diff --git a/data/bash-completion/fwupdtool.in b/data/bash-completion/fwupdtool.in index 55c01b86b..d57d7e364 100644 --- a/data/bash-completion/fwupdtool.in +++ b/data/bash-completion/fwupdtool.in @@ -6,6 +6,7 @@ _fwupdtool_cmd_list=( 'esp-unmount' 'firmware-build' 'firmware-convert' + 'firmware-export' 'firmware-extract' 'firmware-parse' 'get-updates' diff --git a/libfwupdplugin/fu-chunk-private.h b/libfwupdplugin/fu-chunk-private.h index 6216aaf5d..21e645e16 100644 --- a/libfwupdplugin/fu-chunk-private.h +++ b/libfwupdplugin/fu-chunk-private.h @@ -9,10 +9,11 @@ #include #include "fu-chunk.h" +#include "fu-firmware.h" -void fu_chunk_add_string (FuChunk *self, - guint idt, - GString *str); +void fu_chunk_export (FuChunk *self, + FuFirmwareExportFlags flags, + XbBuilderNode *bn); gboolean fu_chunk_build (FuChunk *self, XbNode *n, GError **error); diff --git a/libfwupdplugin/fu-chunk.c b/libfwupdplugin/fu-chunk.c index 2d27b7294..8de70f7a4 100644 --- a/libfwupdplugin/fu-chunk.c +++ b/libfwupdplugin/fu-chunk.c @@ -292,19 +292,23 @@ fu_chunk_bytes_new (GBytes *bytes) } void -fu_chunk_add_string (FuChunk *self, guint idt, GString *str) +fu_chunk_export (FuChunk *self, FuFirmwareExportFlags flags, XbBuilderNode *bn) { - fu_common_string_append_kv (str, idt, G_OBJECT_TYPE_NAME (self), NULL); - fu_common_string_append_kx (str, idt + 1, "Index", self->idx); - fu_common_string_append_kx (str, idt + 1, "Page", self->page); - fu_common_string_append_kx (str, idt + 1, "Address", self->address); + fu_xmlb_builder_insert_kx (bn, "idx", self->idx); + fu_xmlb_builder_insert_kx (bn, "page", self->page); + fu_xmlb_builder_insert_kx (bn, "addr", self->address); if (self->data != NULL) { g_autofree gchar *datastr = NULL; - datastr = fu_common_strsafe ((const gchar *) self->data, MIN (self->data_sz, 16)); - if (datastr != NULL) - fu_common_string_append_kv (str, idt + 1, "Data", datastr); + g_autofree gchar *dataszstr = g_strdup_printf ("0x%x", (guint) self->data_sz); + if (flags & FU_FIRMWARE_EXPORT_FLAG_ASCII_DATA) { + datastr = fu_common_strsafe ((const gchar *) self->data, MIN (self->data_sz, 16)); + } else { + datastr = g_base64_encode (self->data, self->data_sz); + } + xb_builder_node_insert_text (bn, "data", datastr, + "size", dataszstr, + NULL); } - fu_common_string_append_kx (str, idt + 1, "DataSz", self->data_sz); } /** @@ -320,9 +324,15 @@ fu_chunk_add_string (FuChunk *self, guint idt, GString *str) gchar * fu_chunk_to_string (FuChunk *self) { - GString *str = g_string_new (NULL); - fu_chunk_add_string (self, 0, str); - return g_string_free (str, FALSE); + g_autoptr(XbBuilderNode) bn = xb_builder_node_new ("chunk"); + fu_chunk_export (self, FU_FIRMWARE_EXPORT_FLAG_ASCII_DATA, bn); + return xb_builder_node_export (bn, + XB_NODE_EXPORT_FLAG_FORMAT_MULTILINE | +#if LIBXMLB_CHECK_VERSION(0,2,2) + XB_NODE_EXPORT_FLAG_COLLAPSE_EMPTY | +#endif + XB_NODE_EXPORT_FLAG_FORMAT_INDENT, + NULL); } /** @@ -338,15 +348,19 @@ fu_chunk_to_string (FuChunk *self) gchar * fu_chunk_array_to_string (GPtrArray *chunks) { - GString *str = g_string_new (NULL); + g_autoptr(XbBuilderNode) bn = xb_builder_node_new ("chunks"); for (guint i = 0; i < chunks->len; i++) { FuChunk *chk = g_ptr_array_index (chunks, i); - g_autofree gchar *tmp = fu_chunk_to_string (chk); - g_string_append_printf (str, "%s\n", tmp); + g_autoptr(XbBuilderNode) bc = xb_builder_node_insert (bn, "chunk", NULL); + fu_chunk_export (chk, FU_FIRMWARE_EXPORT_FLAG_ASCII_DATA, bc); } - if (str->len > 0) - g_string_truncate (str, str->len - 1); - return g_string_free (str, FALSE); + return xb_builder_node_export (bn, + XB_NODE_EXPORT_FLAG_FORMAT_MULTILINE | +#if LIBXMLB_CHECK_VERSION(0,2,2) + XB_NODE_EXPORT_FLAG_COLLAPSE_EMPTY | +#endif + XB_NODE_EXPORT_FLAG_FORMAT_INDENT, + NULL); } /** diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 81a1ecabd..511605b02 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -3276,3 +3276,59 @@ fu_common_align_up (gsize value, guint8 alignment) /* success */ return value_new; } + +/** + * fu_xmlb_builder_insert_kv: + * @bn: #JsonBuilder + * @key: string key + * @value: string value + * + * Convenience function to add an XML node with a string value. If @value is %NULL + * then no member is added. + * + * Since: 1.6.0 + **/ +void +fu_xmlb_builder_insert_kv (XbBuilderNode *bn, const gchar *key, const gchar *value) +{ + if (value == NULL) + return; + xb_builder_node_insert_text (bn, key, value, NULL); +} + +/** + * fu_xmlb_builder_insert_kx: + * @bn: #JsonBuilder + * @key: string key + * @value: integer value + * + * Convenience function to add an XML node with a integer value. If @value is 0 + * then no member is added. + * + * Since: 1.6.0 + **/ +void +fu_xmlb_builder_insert_kx (XbBuilderNode *bn, const gchar *key, guint64 value) +{ + g_autofree gchar *value_hex = NULL; + if (value == 0) + return; + value_hex = g_strdup_printf ("0x%x", (guint) value); + xb_builder_node_insert_text (bn, key, value_hex, NULL); +} + +/** + * fu_xmlb_builder_insert_kb: + * @bn: #JsonBuilder + * @key: string key + * @value: boolean value + * + * Convenience function to add an XML node with a boolean value. + * + * Since: 1.6.0 + **/ +void +fu_xmlb_builder_insert_kb (XbBuilderNode *bn, const gchar *key, gboolean value) +{ + xb_builder_node_insert_text (bn, key, value ? "true" : "false", NULL); +} diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index 272c8edff..f541ec77e 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include "fu-volume.h" @@ -363,3 +364,13 @@ guint32 fu_common_crc32_full (const guint8 *buf, gchar *fu_common_uri_get_scheme (const gchar *uri); gsize fu_common_align_up (gsize value, guint8 alignment); + +void fu_xmlb_builder_insert_kv (XbBuilderNode *bn, + const gchar *key, + const gchar *value); +void fu_xmlb_builder_insert_kx (XbBuilderNode *bn, + const gchar *key, + guint64 value); +void fu_xmlb_builder_insert_kb (XbBuilderNode *bn, + const gchar *key, + gboolean value); diff --git a/libfwupdplugin/fu-dfu-firmware.c b/libfwupdplugin/fu-dfu-firmware.c index 0be2bf84a..40e767356 100644 --- a/libfwupdplugin/fu-dfu-firmware.c +++ b/libfwupdplugin/fu-dfu-firmware.c @@ -34,14 +34,16 @@ G_DEFINE_TYPE_WITH_PRIVATE (FuDfuFirmware, fu_dfu_firmware, FU_TYPE_FIRMWARE) #define GET_PRIVATE(o) (fu_dfu_firmware_get_instance_private (o)) static void -fu_dfu_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_dfu_firmware_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuDfuFirmware *self = FU_DFU_FIRMWARE (firmware); FuDfuFirmwarePrivate *priv = GET_PRIVATE (self); - fu_common_string_append_kx (str, idt, "Vid", priv->vid); - fu_common_string_append_kx (str, idt, "Pid", priv->pid); - fu_common_string_append_kx (str, idt, "Release", priv->release); - fu_common_string_append_kx (str, idt, "DfuVersion", priv->dfu_version); + fu_xmlb_builder_insert_kx (bn, "vendor", priv->vid); + fu_xmlb_builder_insert_kx (bn, "product", priv->pid); + fu_xmlb_builder_insert_kx (bn, "release", priv->release); + fu_xmlb_builder_insert_kx (bn, "dfu_version", priv->dfu_version); } /* private */ @@ -387,7 +389,7 @@ static void fu_dfu_firmware_class_init (FuDfuFirmwareClass *klass) { FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); - klass_firmware->to_string = fu_dfu_firmware_to_string; + klass_firmware->export = fu_dfu_firmware_export; klass_firmware->parse = fu_dfu_firmware_parse; klass_firmware->write = fu_dfu_firmware_write; klass_firmware->build = fu_dfu_firmware_build; diff --git a/libfwupdplugin/fu-firmware.c b/libfwupdplugin/fu-firmware.c index 1a6a625e2..7722c4d22 100644 --- a/libfwupdplugin/fu-firmware.c +++ b/libfwupdplugin/fu-firmware.c @@ -608,6 +608,7 @@ fu_firmware_get_checksum (FuFirmware *self, { FuFirmwarePrivate *priv = GET_PRIVATE (self); FuFirmwareClass *klass = FU_FIRMWARE_GET_CLASS (self); + g_autoptr(GBytes) blob = NULL; g_return_val_if_fail (FU_IS_FIRMWARE (self), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); @@ -617,15 +618,14 @@ fu_firmware_get_checksum (FuFirmware *self, return klass->get_checksum (self, csum_kind, error); /* internal data */ - if (priv->bytes == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_FOUND, - "no bytes found in firmware bytes %s", - priv->id); + if (priv->bytes != NULL) + return g_compute_checksum_for_bytes (csum_kind, priv->bytes); + + /* write */ + blob = fu_firmware_write (self, error); + if (blob == NULL) return NULL; - } - return g_compute_checksum_for_bytes (csum_kind, priv->bytes); + return g_compute_checksum_for_bytes (csum_kind, blob); } /** @@ -890,6 +890,84 @@ fu_firmware_build (FuFirmware *self, XbNode *n, GError **error) return TRUE; } +/** + * fu_firmware_build_from_xml: + * @self: A #FuFirmware + * @xml: XML text + * @error: A #GError, or %NULL + * + * Builds a firmware from an XML manifest. The manifest would typically have the + * following form: + * + * |[ + * + * + * 1.2.3 + * + * 7.8.9 + * stage1 + * 0x01 + * stage1.bin + * + * + * stage2 + * + * + * + * ape + * 0x7 + * aGVsbG8gd29ybGQ= + * + * + * ]| + * + * This would be used in a build-system to merge images from generated files: + * `fwupdtool firmware-build fw.builder.xml test.fw` + * + * Static binary content can be specified in the `/` section and + * is encoded as base64 text if not empty. + * + * Additionally, extra nodes can be included under nested `` objects + * which can be parsed by the subclassed objects. You should verify the + * subclassed object `FuFirmware->build` vfunc for the specific additional + * options supported. + * + * Plugins should manually g_type_ensure() subclassed image objects if not + * constructed as part of the plugin fu_plugin_init() or fu_plugin_setup() + * functions. + * + * Returns: %TRUE for success + * + * Since: 1.6.0 + **/ +gboolean +fu_firmware_build_from_xml (FuFirmware *self, const gchar *xml, GError **error) +{ + g_autoptr(XbBuilder) builder = xb_builder_new (); + g_autoptr(XbBuilderSource) source = xb_builder_source_new (); + g_autoptr(XbNode) n = NULL; + g_autoptr(XbSilo) silo = NULL; + + /* parse XML */ + if (!xb_builder_source_load_xml (source, xml, + XB_BUILDER_SOURCE_FLAG_NONE, + error)) { + g_prefix_error (error, "could not parse XML: "); + return FALSE; + } + xb_builder_import_source (builder, source); + silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_NONE, + NULL, error); + if (silo == NULL) + return FALSE; + + /* create FuFirmware of specific GType */ + n = xb_silo_query_first (silo, "firmware", error); + if (n == NULL) + return FALSE; + return fu_firmware_build (self, n, error); +} + /** * fu_firmware_parse_file: * @self: A #FuFirmware @@ -1363,14 +1441,30 @@ fu_firmware_get_image_by_idx_bytes (FuFirmware *self, guint64 idx, GError **erro return fu_firmware_write (img, error); } -static void -fu_firmware_add_string (FuFirmware *self, guint idt, GString *str) +/** + * fu_firmware_export: + * @self: A #FuFirmware + * @flags: #FuFirmwareExportFlags, e.g. %FU_FIRMWARE_EXPORT_FLAG_INCLUDE_DEBUG + * @bn: A #XbBuilderNode + * + * This allows us to build an XML object for the nested firmware. + * + * Since: 1.6.0 + **/ +void +fu_firmware_export (FuFirmware *self, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuFirmwareClass *klass = FU_FIRMWARE_GET_CLASS (self); FuFirmwarePrivate *priv = GET_PRIVATE (self); + const gchar *gtypestr = G_OBJECT_TYPE_NAME (self); + + /* object */ + if (g_strcmp0 (gtypestr, "FuFirmware") != 0) + xb_builder_node_set_attr (bn, "gtype", gtypestr); /* subclassed type */ - fu_common_string_append_kv (str, idt, G_OBJECT_TYPE_NAME (self), NULL); if (priv->flags != FU_FIRMWARE_FLAG_NONE) { g_autoptr(GString) tmp = g_string_new (""); for (guint i = 0; i < 64; i++) { @@ -1381,51 +1475,84 @@ fu_firmware_add_string (FuFirmware *self, guint idt, GString *str) } if (tmp->len > 0) g_string_truncate (tmp, tmp->len - 1); - fu_common_string_append_kv (str, idt, "Flags", tmp->str); + fu_xmlb_builder_insert_kv (bn, "flags", tmp->str); } - if (priv->id != NULL) - fu_common_string_append_kv (str, idt, "ID", priv->id); - if (priv->idx != 0x0) - fu_common_string_append_kx (str, idt, "Index", priv->idx); - if (priv->version != NULL) - fu_common_string_append_kv (str, idt, "Version", priv->version); - if (priv->version_raw != 0x0) - fu_common_string_append_kx (str, idt, "VersionRaw", priv->version_raw); - if (priv->addr != 0x0) - fu_common_string_append_kx (str, idt, "Address", priv->addr); - if (priv->offset != 0x0) - fu_common_string_append_kx (str, idt, "Offset", priv->offset); - if (priv->size != 0x0) - fu_common_string_append_kx (str, idt, "Size", priv->size); - if (priv->filename != NULL) - fu_common_string_append_kv (str, idt, "Filename", priv->filename); + fu_xmlb_builder_insert_kv (bn, "id", priv->id); + fu_xmlb_builder_insert_kx (bn, "idx", priv->idx); + fu_xmlb_builder_insert_kv (bn, "version", priv->version); + fu_xmlb_builder_insert_kx (bn, "version_raw", priv->version_raw); + fu_xmlb_builder_insert_kx (bn, "addr", priv->addr); + fu_xmlb_builder_insert_kx (bn, "offset", priv->offset); + fu_xmlb_builder_insert_kx (bn, "size", priv->size); + fu_xmlb_builder_insert_kv (bn, "filename", priv->filename); if (priv->bytes != NULL) { - fu_common_string_append_kx (str, idt, "Data", - g_bytes_get_size (priv->bytes)); - } - if (priv->alignment != 0x0) { - fu_common_string_append_kx (str, idt, "Alignment", - (guint64) 1 << priv->alignment); + gsize bufsz = 0; + const guint8 *buf = g_bytes_get_data (priv->bytes, &bufsz); + g_autofree gchar *datastr = NULL; + g_autofree gchar *dataszstr = g_strdup_printf ("0x%x", (guint) bufsz); + if (flags & FU_FIRMWARE_EXPORT_FLAG_ASCII_DATA) { + datastr = fu_common_strsafe ((const gchar *) buf, MIN (bufsz, 16)); + } else { + datastr = g_base64_encode (buf, bufsz); + } + xb_builder_node_insert_text (bn, "data", datastr, + "size", dataszstr, + NULL); } + fu_xmlb_builder_insert_kx (bn, "alignment", priv->alignment); - /* add chunks */ - if (priv->chunks != NULL) { + /* chunks */ + if (priv->chunks != NULL && priv->chunks->len > 0) { + g_autoptr(XbBuilderNode) bp = xb_builder_node_insert (bn, "chunks", NULL); for (guint i = 0; i < priv->chunks->len; i++) { FuChunk *chk = g_ptr_array_index (priv->chunks, i); - fu_chunk_add_string (chk, 1, str); + g_autoptr(XbBuilderNode) bc = xb_builder_node_insert (bp, "chunk", NULL); + fu_chunk_export (chk, flags, bc); } } /* vfunc */ - if (klass->to_string != NULL) - klass->to_string (self, idt, str); + if (klass->export != NULL) + klass->export (self, flags, bn); - for (guint i = 0; i < priv->images->len; i++) { - FuFirmware *img = g_ptr_array_index (priv->images, i); - fu_firmware_add_string (img, idt + 1, str); + /* children */ + if (priv->images->len > 0) { + for (guint i = 0; i < priv->images->len; i++) { + FuFirmware *img = g_ptr_array_index (priv->images, i); + g_autoptr(XbBuilderNode) bc = xb_builder_node_insert (bn, "firmware", NULL); + fu_firmware_export (img, flags, bc); + } } } +/** + * fu_firmware_export_to_xml: + * @self: A #FuFirmware + * @flags: #FuFirmwareExportFlags, e.g. %FU_FIRMWARE_EXPORT_FLAG_INCLUDE_DEBUG + * @error: (nullable): a #GError or %NULL + * + * This allows us to build an XML object for the nested firmware. + * + * Returns: a string value, or %NULL for invalid. + * + * Since: 1.6.0 + **/ +gchar * +fu_firmware_export_to_xml (FuFirmware *self, + FuFirmwareExportFlags flags, + GError **error) +{ + g_autoptr(XbBuilderNode) bn = xb_builder_node_new ("firmware"); + fu_firmware_export (self, flags, bn); + return xb_builder_node_export (bn, + XB_NODE_EXPORT_FLAG_FORMAT_MULTILINE | +#if LIBXMLB_CHECK_VERSION(0,2,2) + XB_NODE_EXPORT_FLAG_COLLAPSE_EMPTY | +#endif + XB_NODE_EXPORT_FLAG_FORMAT_INDENT, + error); +} + /** * fu_firmware_to_string: * @self: A #FuFirmware @@ -1439,9 +1566,15 @@ fu_firmware_add_string (FuFirmware *self, guint idt, GString *str) gchar * fu_firmware_to_string (FuFirmware *self) { - GString *str = g_string_new (NULL); - fu_firmware_add_string (self, 0, str); - return g_string_free (str, FALSE); + g_autoptr(XbBuilderNode) bn = xb_builder_node_new ("firmware"); + fu_firmware_export (self, FU_FIRMWARE_EXPORT_FLAG_INCLUDE_DEBUG, bn); + return xb_builder_node_export (bn, + XB_NODE_EXPORT_FLAG_FORMAT_MULTILINE | +#if LIBXMLB_CHECK_VERSION(0,2,2) + XB_NODE_EXPORT_FLAG_COLLAPSE_EMPTY | +#endif + XB_NODE_EXPORT_FLAG_FORMAT_INDENT, + NULL); } static void diff --git a/libfwupdplugin/fu-firmware.h b/libfwupdplugin/fu-firmware.h index 5f81f324d..1e5767fb4 100644 --- a/libfwupdplugin/fu-firmware.h +++ b/libfwupdplugin/fu-firmware.h @@ -16,6 +16,19 @@ #define FU_TYPE_FIRMWARE (fu_firmware_get_type ()) G_DECLARE_DERIVABLE_TYPE (FuFirmware, fu_firmware, FU, FIRMWARE, GObject) +/** + * FuFirmwareExportFlags: + * @FU_FIRMWARE_EXPORT_FLAG_NONE: No flags set + * @FU_FIRMWARE_EXPORT_FLAG_INCLUDE_DEBUG: Include debug information when exporting + * @FU_FIRMWARE_EXPORT_FLAG_ASCII_DATA: Write the data as UTF-8 strings + * + * The firmware export flags. + **/ +#define FU_FIRMWARE_EXPORT_FLAG_NONE (0u) /* Since: 1.6.0 */ +#define FU_FIRMWARE_EXPORT_FLAG_INCLUDE_DEBUG (1u << 0) /* Since: 1.6.0 */ +#define FU_FIRMWARE_EXPORT_FLAG_ASCII_DATA (1u << 1) /* Since: 1.6.0 */ +typedef guint64 FuFirmwareExportFlags; + struct _FuFirmwareClass { GObjectClass parent_class; @@ -29,9 +42,9 @@ struct _FuFirmwareClass GBytes *(*write) (FuFirmware *self, GError **error) G_GNUC_WARN_UNUSED_RESULT; - void (*to_string) (FuFirmware *self, - guint indent, - GString *str); + void (*export) (FuFirmware *self, + FuFirmwareExportFlags flags, + XbBuilderNode *bn); gboolean (*tokenize) (FuFirmware *self, GBytes *fw, FwupdInstallFlags flags, @@ -66,9 +79,9 @@ struct _FuFirmwareClass #define FU_FIRMWARE_FLAG_HAS_VID_PID (1u << 3) /* Since: 1.5.6 */ typedef guint64 FuFirmwareFlags; -#define FU_FIRMWARE_ID_PAYLOAD "payload" +#define FU_FIRMWARE_ID_PAYLOAD "payload" #define FU_FIRMWARE_ID_SIGNATURE "signature" -#define FU_FIRMWARE_ID_HEADER "header" +#define FU_FIRMWARE_ID_HEADER "header" const gchar *fu_firmware_flag_to_string (FuFirmwareFlags flag); FuFirmwareFlags fu_firmware_flag_from_string (const gchar *flag); @@ -80,6 +93,12 @@ FuFirmware *fu_firmware_new_from_gtypes (GBytes *fw, GError **error, ...); gchar *fu_firmware_to_string (FuFirmware *self); +void fu_firmware_export (FuFirmware *self, + FuFirmwareExportFlags flags, + XbBuilderNode *bn); +gchar *fu_firmware_export_to_xml (FuFirmware *self, + FuFirmwareExportFlags flags, + GError **error); const gchar *fu_firmware_get_version (FuFirmware *self); void fu_firmware_set_version (FuFirmware *self, const gchar *version); @@ -129,6 +148,10 @@ gboolean fu_firmware_build (FuFirmware *self, XbNode *n, GError **error) G_GNUC_WARN_UNUSED_RESULT; +gboolean fu_firmware_build_from_xml (FuFirmware *self, + const gchar *xml, + GError **error) + G_GNUC_WARN_UNUSED_RESULT; gboolean fu_firmware_parse (FuFirmware *self, GBytes *fw, FwupdInstallFlags flags, diff --git a/libfwupdplugin/fu-fmap-firmware.c b/libfwupdplugin/fu-fmap-firmware.c index bdca6cbc7..e7bc6f61d 100644 --- a/libfwupdplugin/fu-fmap-firmware.c +++ b/libfwupdplugin/fu-fmap-firmware.c @@ -54,13 +54,14 @@ fu_fmap_firmware_find_offset (FuFmapFirmware *self, } static void -fu_fmap_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_fmap_firmware_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuFmapFirmware *self = FU_FMAP_FIRMWARE (firmware); FuFmapFirmwarePrivate *priv = GET_PRIVATE (self); - if (priv->offset > 0) - fu_common_string_append_kx (str, idt, "Offset", priv->offset); - fu_common_string_append_kx (str, idt, "Base", priv->base); + fu_xmlb_builder_insert_kx (bn, "offset", priv->offset); + fu_xmlb_builder_insert_kx (bn, "base", priv->base); } static gboolean @@ -260,7 +261,7 @@ static void fu_fmap_firmware_class_init (FuFmapFirmwareClass *klass) { FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); - klass_firmware->to_string = fu_fmap_firmware_to_string; + klass_firmware->export = fu_fmap_firmware_export; klass_firmware->parse = fu_fmap_firmware_parse; klass_firmware->write = fu_fmap_firmware_write; klass_firmware->build = fu_fmap_firmware_build; diff --git a/libfwupdplugin/fu-self-test.c b/libfwupdplugin/fu-self-test.c index 63ce53de8..02e22a256 100644 --- a/libfwupdplugin/fu-self-test.c +++ b/libfwupdplugin/fu-self-test.c @@ -1320,117 +1320,98 @@ fu_chunk_func (void) chunked3 = fu_chunk_array_new ((const guint8 *) "123456", 6, 0x0, 3, 3); chunked3_str = fu_chunk_array_to_string (chunked3); - g_assert_cmpstr (chunked3_str, ==, "FuChunk:\n" - " Index: 0x0\n" - " Page: 0x0\n" - " Address: 0x0\n" - " Data: 123\n" - " DataSz: 0x3\n" - "\n" - "FuChunk:\n" - " Index: 0x1\n" - " Page: 0x1\n" - " Address: 0x0\n" - " Data: 456\n" - " DataSz: 0x3\n"); + g_assert_cmpstr (chunked3_str, ==, + "\n" + " \n" + " 123\n" + " \n" + " \n" + " 0x1\n" + " 0x1\n" + " 456\n" + " \n" + "\n"); chunked4 = fu_chunk_array_new ((const guint8 *) "123456", 6, 0x4, 4, 4); chunked4_str = fu_chunk_array_to_string (chunked4); - g_assert_cmpstr (chunked4_str, ==, "FuChunk:\n" - " Index: 0x0\n" - " Page: 0x1\n" - " Address: 0x0\n" - " Data: 1234\n" - " DataSz: 0x4\n" - "\n" - "FuChunk:\n" - " Index: 0x1\n" - " Page: 0x2\n" - " Address: 0x0\n" - " Data: 56\n" - " DataSz: 0x2\n"); + g_assert_cmpstr (chunked4_str, ==, + "\n" + " \n" + " 0x1\n" + " 1234\n" + " \n" + " \n" + " 0x1\n" + " 0x2\n" + " 56\n" + " \n" + "\n"); chunked1 = fu_chunk_array_new ((const guint8 *) "0123456789abcdef", 16, 0x0, 10, 4); chunked1_str = fu_chunk_array_to_string (chunked1); - g_assert_cmpstr (chunked1_str, ==, "FuChunk:\n" - " Index: 0x0\n" - " Page: 0x0\n" - " Address: 0x0\n" - " Data: 0123\n" - " DataSz: 0x4\n" - "\n" - "FuChunk:\n" - " Index: 0x1\n" - " Page: 0x0\n" - " Address: 0x4\n" - " Data: 4567\n" - " DataSz: 0x4\n" - "\n" - "FuChunk:\n" - " Index: 0x2\n" - " Page: 0x0\n" - " Address: 0x8\n" - " Data: 89\n" - " DataSz: 0x2\n" - "\n" - "FuChunk:\n" - " Index: 0x3\n" - " Page: 0x1\n" - " Address: 0x0\n" - " Data: abcd\n" - " DataSz: 0x4\n" - "\n" - "FuChunk:\n" - " Index: 0x4\n" - " Page: 0x1\n" - " Address: 0x4\n" - " Data: ef\n" - " DataSz: 0x2\n"); - + g_assert_cmpstr (chunked1_str, ==, + "\n" + " \n" + " 0123\n" + " \n" + " \n" + " 0x1\n" + " 0x4\n" + " 4567\n" + " \n" + " \n" + " 0x2\n" + " 0x8\n" + " 89\n" + " \n" + " \n" + " 0x3\n" + " 0x1\n" + " abcd\n" + " \n" + " \n" + " 0x4\n" + " 0x1\n" + " 0x4\n" + " ef\n" + " \n" + "\n"); chunked2 = fu_chunk_array_new ((const guint8 *) "XXXXXXYYYYYYZZZZZZ", 18, 0x0, 6, 4); chunked2_str = fu_chunk_array_to_string (chunked2); g_print ("\n%s", chunked2_str); - g_assert_cmpstr (chunked2_str, ==, "FuChunk:\n" - " Index: 0x0\n" - " Page: 0x0\n" - " Address: 0x0\n" - " Data: XXXX\n" - " DataSz: 0x4\n" - "\n" - "FuChunk:\n" - " Index: 0x1\n" - " Page: 0x0\n" - " Address: 0x4\n" - " Data: XX\n" - " DataSz: 0x2\n" - "\n" - "FuChunk:\n" - " Index: 0x2\n" - " Page: 0x1\n" - " Address: 0x0\n" - " Data: YYYY\n" - " DataSz: 0x4\n" - "\n" - "FuChunk:\n" - " Index: 0x3\n" - " Page: 0x1\n" - " Address: 0x4\n" - " Data: YY\n" - " DataSz: 0x2\n" - "\n" - "FuChunk:\n" - " Index: 0x4\n" - " Page: 0x2\n" - " Address: 0x0\n" - " Data: ZZZZ\n" - " DataSz: 0x4\n" - "\n" - "FuChunk:\n" - " Index: 0x5\n" - " Page: 0x2\n" - " Address: 0x4\n" - " Data: ZZ\n" - " DataSz: 0x2\n"); + g_assert_cmpstr (chunked2_str, ==, + "\n" + " \n" + " XXXX\n" + " \n" + " \n" + " 0x1\n" + " 0x4\n" + " XX\n" + " \n" + " \n" + " 0x2\n" + " 0x1\n" + " YYYY\n" + " \n" + " \n" + " 0x3\n" + " 0x1\n" + " 0x4\n" + " YY\n" + " \n" + " \n" + " 0x4\n" + " 0x2\n" + " ZZZZ\n" + " \n" + " \n" + " 0x5\n" + " 0x2\n" + " 0x4\n" + " ZZ\n" + " \n" + "\n"); } static void @@ -2134,16 +2115,20 @@ fu_firmware_func (void) g_assert_cmpstr (fu_firmware_get_id (img_idx), ==, "secondary"); str = fu_firmware_to_string (firmware); - g_assert_cmpstr (str, ==, "FuFirmware:\n" - " FuFirmware:\n" - " ID: primary\n" - " Index: 0xd\n" - " Address: 0x200\n" - " Filename: BIOS.bin\n" - " FuFirmware:\n" - " ID: secondary\n" - " Index: 0x17\n" - " Address: 0x400\n"); + g_assert_cmpstr (str, ==, + "\n" + " \n" + " primary\n" + " 0xd\n" + " 0x200\n" + " BIOS.bin\n" + " \n" + " \n" + " secondary\n" + " 0x17\n" + " 0x400\n" + " \n" + "\n"); ret = fu_firmware_remove_image_by_idx (firmware, 0xd, &error); g_assert_no_error (error); @@ -2464,6 +2449,147 @@ fu_security_attrs_hsi_func (void) g_assert_cmpstr (hsi8, ==, expected_hsi8); g_clear_object (&attr); } +static void +fu_firmware_dfuse_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_dfuse_firmware_new (); + g_autoptr(FuFirmware) firmware2 = fu_dfuse_firmware_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/dfuse.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "c1ff429f0e381c8fe8e1b2ee41a5a9a79e2f2ff7"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} +static void +fu_firmware_srec_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_srec_firmware_new (); + g_autoptr(FuFirmware) firmware2 = fu_srec_firmware_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/srec.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} +static void +fu_firmware_ihex_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_ihex_firmware_new (); + g_autoptr(FuFirmware) firmware2 = fu_ihex_firmware_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/ihex.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "a8d74f767f3fc992b413e5ba801cedc80a4cf013"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} +static void +fu_firmware_fmap_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_fmap_firmware_new (); + g_autoptr(FuFirmware) firmware2 = fu_fmap_firmware_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/fmap.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "a0b9ffc10a586d217edf9e9bae7c1fe7c564ea01"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} int main (int argc, char **argv) @@ -2520,13 +2646,17 @@ main (int argc, char **argv) g_test_add_func ("/fwupd/firmware{dedupe}", fu_firmware_dedupe_func); g_test_add_func ("/fwupd/firmware{build}", fu_firmware_build_func); g_test_add_func ("/fwupd/firmware{ihex}", fu_firmware_ihex_func); + g_test_add_func ("/fwupd/firmware{ihex-xml}", fu_firmware_ihex_xml_func); g_test_add_func ("/fwupd/firmware{ihex-offset}", fu_firmware_ihex_offset_func); g_test_add_func ("/fwupd/firmware{ihex-signed}", fu_firmware_ihex_signed_func); g_test_add_func ("/fwupd/firmware{srec-tokenization}", fu_firmware_srec_tokenization_func); g_test_add_func ("/fwupd/firmware{srec}", fu_firmware_srec_func); + g_test_add_func ("/fwupd/firmware{srec-xml}", fu_firmware_srec_xml_func); g_test_add_func ("/fwupd/firmware{dfu}", fu_firmware_dfu_func); g_test_add_func ("/fwupd/firmware{dfuse}", fu_firmware_dfuse_func); + g_test_add_func ("/fwupd/firmware{dfuse-xml}", fu_firmware_dfuse_xml_func); g_test_add_func ("/fwupd/firmware{fmap}", fu_firmware_fmap_func); + g_test_add_func ("/fwupd/firmware{fmap-xml}", fu_firmware_fmap_xml_func); g_test_add_func ("/fwupd/firmware{gtypes}", fu_firmware_new_from_gtypes_func); g_test_add_func ("/fwupd/archive{invalid}", fu_archive_invalid_func); g_test_add_func ("/fwupd/archive{cab}", fu_archive_cab_func); diff --git a/libfwupdplugin/fu-smbios.c b/libfwupdplugin/fu-smbios.c index 576a2c3b2..ac5f63585 100644 --- a/libfwupdplugin/fu-smbios.c +++ b/libfwupdplugin/fu-smbios.c @@ -479,19 +479,24 @@ fu_smbios_setup (FuSmbios *self, GError **error) } static void -fu_smbios_to_string_internal (FuFirmware *firmware, guint idt, GString *str) +fu_smbios_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuSmbios *self = FU_SMBIOS (firmware); + for (guint i = 0; i < self->items->len; i++) { FuSmbiosItem *item = g_ptr_array_index (self->items, i); - fu_common_string_append_kx (str, idt + 0, "Type", item->type); - fu_common_string_append_kx (str, idt + 1, "Length", item->buf->len); - fu_common_string_append_kx (str, idt + 1, "Handle", item->handle); + g_autoptr(XbBuilderNode) bc = xb_builder_node_insert (bn, "item", NULL); + fu_xmlb_builder_insert_kx (bc, "type", item->type); + fu_xmlb_builder_insert_kx (bc, "length", item->buf->len); + fu_xmlb_builder_insert_kx (bc, "handle", item->handle); for (guint j = 0; j < item->strings->len; j++) { const gchar *tmp = g_ptr_array_index (item->strings, j); - g_autofree gchar *title = g_strdup_printf ("String[%02u]", j); + g_autofree gchar *title = g_strdup_printf ("%02u", j); g_autofree gchar *value = fu_common_strsafe (tmp, 20); - fu_common_string_append_kv (str, idt + 2, title, value); + xb_builder_node_insert_text (bc, "string", value, + "idx", title, NULL); } } } @@ -689,7 +694,7 @@ fu_smbios_class_init (FuSmbiosClass *klass) FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); object_class->finalize = fu_smbios_finalize; klass_firmware->parse = fu_smbios_parse; - klass_firmware->to_string = fu_smbios_to_string_internal; + klass_firmware->export = fu_smbios_export; } static void diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 5b26f296f..74174974f 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -761,6 +761,9 @@ LIBFWUPDPLUGIN_1.6.0 { fu_byte_array_set_size_full; fu_common_align_up; fu_firmware_add_chunk; + fu_firmware_build_from_xml; + fu_firmware_export; + fu_firmware_export_to_xml; fu_firmware_get_addr; fu_firmware_get_alignment; fu_firmware_get_bytes; @@ -780,5 +783,8 @@ LIBFWUPDPLUGIN_1.6.0 { fu_firmware_set_offset; fu_firmware_set_size; fu_firmware_write_chunk; + fu_xmlb_builder_insert_kb; + fu_xmlb_builder_insert_kv; + fu_xmlb_builder_insert_kx; local: *; } LIBFWUPDPLUGIN_1.5.8; diff --git a/meson.build b/meson.build index a036e217d..394751f38 100644 --- a/meson.build +++ b/meson.build @@ -471,6 +471,7 @@ conf.set_quoted('FWUPD_DATADIR', datadir) conf.set_quoted('FWUPD_LOCALSTATEDIR', localstatedir) conf.set_quoted('FWUPD_SYSCONFDIR', sysconfdir) conf.set_quoted('FWUPD_LOCALEDIR', localedir) +conf.set_quoted('FWUPD_FUZZINGSRCDIR', join_paths(meson.source_root(), 'src', 'fuzzing')) if build_standalone if host_machine.system() == 'windows' diff --git a/plugins/bcm57xx/fu-bcm57xx-dict-image.c b/plugins/bcm57xx/fu-bcm57xx-dict-image.c index 55d393804..119319a66 100644 --- a/plugins/bcm57xx/fu-bcm57xx-dict-image.c +++ b/plugins/bcm57xx/fu-bcm57xx-dict-image.c @@ -20,17 +20,19 @@ struct _FuBcm57xxDictImage { G_DEFINE_TYPE (FuBcm57xxDictImage, fu_bcm57xx_dict_image, FU_TYPE_FIRMWARE) static void -fu_bcm57xx_dict_image_to_string (FuFirmware *image, guint idt, GString *str) +fu_bcm57xx_dict_image_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { - FuBcm57xxDictImage *self = FU_BCM57XX_DICT_IMAGE (image); + FuBcm57xxDictImage *self = FU_BCM57XX_DICT_IMAGE (firmware); if (self->target != 0xff) - fu_common_string_append_kx (str, idt, "Target", self->target); + fu_xmlb_builder_insert_kx (bn, "target", self->target); if (self->kind != 0xff) - fu_common_string_append_kx (str, idt, "Kind", self->kind); + fu_xmlb_builder_insert_kx (bn, "kind", self->kind); } static gboolean -fu_bcm57xx_dict_image_parse (FuFirmware *image, +fu_bcm57xx_dict_image_parse (FuFirmware *firmware, GBytes *fw, guint64 addr_start, guint64 addr_end, @@ -47,12 +49,12 @@ fu_bcm57xx_dict_image_parse (FuFirmware *image, error); if (fw_nocrc == NULL) return FALSE; - fu_firmware_set_bytes (image, fw_nocrc); + fu_firmware_set_bytes (firmware, fw_nocrc); return TRUE; } static GBytes * -fu_bcm57xx_dict_image_write (FuFirmware *image, GError **error) +fu_bcm57xx_dict_image_write (FuFirmware *firmware, GError **error) { const guint8 *buf; gsize bufsz = 0; @@ -61,7 +63,7 @@ fu_bcm57xx_dict_image_write (FuFirmware *image, GError **error) g_autoptr(GBytes) fw_nocrc = NULL; /* get the CRC-less data */ - fw_nocrc = fu_firmware_get_bytes (image, error); + fw_nocrc = fu_firmware_get_bytes (firmware, error); if (fw_nocrc == NULL) return NULL; @@ -77,9 +79,9 @@ fu_bcm57xx_dict_image_write (FuFirmware *image, GError **error) } static gboolean -fu_bcm57xx_dict_image_build (FuFirmware *image, XbNode *n, GError **error) +fu_bcm57xx_dict_image_build (FuFirmware *firmware, XbNode *n, GError **error) { - FuBcm57xxDictImage *self = FU_BCM57XX_DICT_IMAGE (image); + FuBcm57xxDictImage *self = FU_BCM57XX_DICT_IMAGE (firmware); guint64 tmp; /* two simple properties */ @@ -167,7 +169,7 @@ fu_bcm57xx_dict_image_class_init (FuBcm57xxDictImageClass *klass) klass_image->parse = fu_bcm57xx_dict_image_parse; klass_image->write = fu_bcm57xx_dict_image_write; klass_image->build = fu_bcm57xx_dict_image_build; - klass_image->to_string = fu_bcm57xx_dict_image_to_string; + klass_image->export = fu_bcm57xx_dict_image_export; } FuFirmware * diff --git a/plugins/bcm57xx/fu-bcm57xx-firmware.c b/plugins/bcm57xx/fu-bcm57xx-firmware.c index 6e66f7a1f..693970c95 100644 --- a/plugins/bcm57xx/fu-bcm57xx-firmware.c +++ b/plugins/bcm57xx/fu-bcm57xx-firmware.c @@ -35,13 +35,17 @@ G_DEFINE_TYPE (FuBcm57xxFirmware, fu_bcm57xx_firmware, FU_TYPE_FIRMWARE) #define BCM_CODE_DIRECTORY_ADDR_APE 0x07 static void -fu_bcm57xx_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_bcm57xx_firmware_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuBcm57xxFirmware *self = FU_BCM57XX_FIRMWARE (firmware); - fu_common_string_append_kx (str, idt, "Vendor", self->vendor); - fu_common_string_append_kx (str, idt, "Model", self->model); - fu_common_string_append_kb (str, idt, "IsBackup", self->is_backup); - fu_common_string_append_kx (str, idt, "PhysAddr", self->phys_addr); + fu_xmlb_builder_insert_kx (bn, "vendor", self->vendor); + fu_xmlb_builder_insert_kx (bn, "model", self->model); + if (flags & FU_FIRMWARE_EXPORT_FLAG_INCLUDE_DEBUG) { + fu_xmlb_builder_insert_kb (bn, "is_backup", self->is_backup); + fu_xmlb_builder_insert_kx (bn, "phys_addr", self->phys_addr); + } } static gboolean @@ -589,7 +593,7 @@ fu_bcm57xx_firmware_class_init (FuBcm57xxFirmwareClass *klass) { FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); klass_firmware->parse = fu_bcm57xx_firmware_parse; - klass_firmware->to_string = fu_bcm57xx_firmware_to_string; + klass_firmware->export = fu_bcm57xx_firmware_export; klass_firmware->write = fu_bcm57xx_firmware_write; klass_firmware->build = fu_bcm57xx_firmware_build; } diff --git a/plugins/bcm57xx/fu-self-test.c b/plugins/bcm57xx/fu-self-test.c index ceaf77168..87b199f6e 100644 --- a/plugins/bcm57xx/fu-self-test.c +++ b/plugins/bcm57xx/fu-self-test.c @@ -11,7 +11,10 @@ #include "fu-common.h" #include "fu-bcm57xx-common.h" +#include "fu-bcm57xx-dict-image.h" #include "fu-bcm57xx-firmware.h" +#include "fu-bcm57xx-stage1-image.h" +#include "fu-bcm57xx-stage2-image.h" static void fu_bcm57xx_create_verbuf (guint8 *bufver, const gchar *version) @@ -88,15 +91,55 @@ fu_bcm57xx_firmware_talos_func (void) g_assert_true (ret); } +static void +fu_bcm57xx_firmware_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_bcm57xx_firmware_new (); + g_autoptr(FuFirmware) firmware2 = fu_bcm57xx_firmware_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/bcm57xx.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "a3ac108905c37857cf48612b707c1c72c582f914"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} + int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); + g_type_ensure (FU_TYPE_BCM57XX_STAGE1_IMAGE); + g_type_ensure (FU_TYPE_BCM57XX_STAGE2_IMAGE); + g_type_ensure (FU_TYPE_BCM57XX_DICT_IMAGE); /* only critical and error are fatal */ g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); /* tests go here */ + g_test_add_func ("/fwupd/bcm57xx/firmware{xml}", fu_bcm57xx_firmware_xml_func); g_test_add_func ("/fwupd/bcm57xx/firmware{talos}", fu_bcm57xx_firmware_talos_func); g_test_add_func ("/fwupd/bcm57xx/common{veritem}", fu_bcm57xx_common_veritem_func); return g_test_run (); diff --git a/plugins/ccgx/fu-ccgx-dmc-firmware.c b/plugins/ccgx/fu-ccgx-dmc-firmware.c index 08dcf7582..274cb612a 100644 --- a/plugins/ccgx/fu-ccgx-dmc-firmware.c +++ b/plugins/ccgx/fu-ccgx-dmc-firmware.c @@ -75,11 +75,15 @@ fu_ccgx_dmc_firmware_get_fw_data_size (FuCcgxDmcFirmware *self) } static void -fu_ccgx_dmc_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_ccgx_dmc_firmware_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuCcgxDmcFirmware *self = FU_CCGX_DMC_FIRMWARE (firmware); - fu_common_string_append_kx (str, idt, "FwDataSize", self->fw_data_size); - fu_common_string_append_ku (str, idt, "ImageRecords", self->image_records->len); + if (flags & FU_FIRMWARE_EXPORT_FLAG_INCLUDE_DEBUG) { + fu_xmlb_builder_insert_kx (bn, "fw_data_size", self->fw_data_size); + fu_xmlb_builder_insert_kx (bn, "image_records", self->image_records->len); + } } static gboolean @@ -466,7 +470,7 @@ fu_ccgx_dmc_firmware_class_init (FuCcgxDmcFirmwareClass *klass) object_class->finalize = fu_ccgx_dmc_firmware_finalize; klass_firmware->parse = fu_ccgx_dmc_firmware_parse; klass_firmware->write = fu_ccgx_dmc_firmware_write; - klass_firmware->to_string = fu_ccgx_dmc_firmware_to_string; + klass_firmware->export = fu_ccgx_dmc_firmware_export; } FuFirmware * diff --git a/plugins/ccgx/fu-ccgx-firmware.c b/plugins/ccgx/fu-ccgx-firmware.c index 4f72b1cc0..7654971ae 100644 --- a/plugins/ccgx/fu-ccgx-firmware.c +++ b/plugins/ccgx/fu-ccgx-firmware.c @@ -58,14 +58,18 @@ fu_ccgx_firmware_get_fw_mode (FuCcgxFirmware *self) } static void -fu_ccgx_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_ccgx_firmware_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuCcgxFirmware *self = FU_CCGX_FIRMWARE (firmware); - fu_common_string_append_kx (str, idt, "AppType", self->app_type); - fu_common_string_append_kx (str, idt, "SiliconId", self->silicon_id); - fu_common_string_append_ku (str, idt, "Records", self->records->len); - fu_common_string_append_kv (str, idt, "FWMode", - fu_ccgx_fw_mode_to_string (self->fw_mode)); + fu_xmlb_builder_insert_kx (bn, "silicon_id", self->silicon_id); + if (flags & FU_FIRMWARE_EXPORT_FLAG_INCLUDE_DEBUG) { + fu_xmlb_builder_insert_kx (bn, "app_type", self->app_type); + fu_xmlb_builder_insert_kx (bn, "records", self->records->len); + fu_xmlb_builder_insert_kv (bn, "fw_mode", + fu_ccgx_fw_mode_to_string (self->fw_mode)); + } } static void @@ -467,7 +471,7 @@ fu_ccgx_firmware_class_init (FuCcgxFirmwareClass *klass) klass_firmware->parse = fu_ccgx_firmware_parse; klass_firmware->write = fu_ccgx_firmware_write; klass_firmware->build = fu_ccgx_firmware_build; - klass_firmware->to_string = fu_ccgx_firmware_to_string; + klass_firmware->export = fu_ccgx_firmware_export; } FuFirmware * diff --git a/plugins/ccgx/fu-self-test.c b/plugins/ccgx/fu-self-test.c new file mode 100644 index 000000000..877f7f64a --- /dev/null +++ b/plugins/ccgx/fu-self-test.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-ccgx-firmware.h" +#include "fu-ccgx-dmc-firmware.h" + +static void +fu_ccgx_firmware_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_ccgx_firmware_new (); + g_autoptr(FuFirmware) firmware2 = fu_ccgx_firmware_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/ccgx.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} + +static void +fu_ccgx_dmc_firmware_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_ccgx_dmc_firmware_new (); + g_autoptr(FuFirmware) firmware2 = fu_ccgx_dmc_firmware_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/ccgx-dmc.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + + /* tests go here */ + g_test_add_func ("/ccgx/firmware{xml}", fu_ccgx_firmware_xml_func); + g_test_add_func ("/ccgx-dmc/firmware{xml}", fu_ccgx_dmc_firmware_xml_func); + return g_test_run (); +} diff --git a/plugins/ccgx/meson.build b/plugins/ccgx/meson.build index bbceb7671..5ea832006 100644 --- a/plugins/ccgx/meson.build +++ b/plugins/ccgx/meson.build @@ -39,3 +39,32 @@ shared_module('fu_plugin_ccgx', ], ) endif + +if get_option('tests') + e = executable( + 'ccgx-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-ccgx-common.c', + 'fu-ccgx-firmware.c', + 'fu-ccgx-dmc-common.c', + 'fu-ccgx-dmc-firmware.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + install : true, + install_dir : installed_test_bindir, + ) + test('ccgx-self-test', e) +endif diff --git a/plugins/elantp/fu-elantp-firmware.c b/plugins/elantp/fu-elantp-firmware.c index d12c6f5b7..136076b92 100644 --- a/plugins/elantp/fu-elantp-firmware.c +++ b/plugins/elantp/fu-elantp-firmware.c @@ -39,11 +39,13 @@ fu_elantp_firmware_get_iap_addr (FuElantpFirmware *self) } static void -fu_elantp_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_elantp_firmware_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuElantpFirmware *self = FU_ELANTP_FIRMWARE (firmware); - fu_common_string_append_kx (str, idt, "IapAddr", self->iap_addr); - fu_common_string_append_kx (str, idt, "ModuleId", self->module_id); + fu_xmlb_builder_insert_kx (bn, "iap_addr", self->iap_addr); + fu_xmlb_builder_insert_kx (bn, "module_id", self->module_id); } static gboolean @@ -185,7 +187,7 @@ fu_elantp_firmware_class_init (FuElantpFirmwareClass *klass) klass_firmware->parse = fu_elantp_firmware_parse; klass_firmware->build = fu_elantp_firmware_build; klass_firmware->write = fu_elantp_firmware_write; - klass_firmware->to_string = fu_elantp_firmware_to_string; + klass_firmware->export = fu_elantp_firmware_export; } FuFirmware * diff --git a/plugins/elantp/fu-self-test.c b/plugins/elantp/fu-self-test.c new file mode 100644 index 000000000..0f8cfedb9 --- /dev/null +++ b/plugins/elantp/fu-self-test.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-elantp-firmware.h" + +static void +fu_elantp_firmware_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_elantp_firmware_new (); + g_autoptr(FuFirmware) firmware2 = fu_elantp_firmware_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/elantp.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + + /* tests go here */ + g_test_add_func ("/elantp/firmware{xml}", fu_elantp_firmware_xml_func); + return g_test_run (); +} diff --git a/plugins/elantp/meson.build b/plugins/elantp/meson.build index be0403c32..120e69292 100644 --- a/plugins/elantp/meson.build +++ b/plugins/elantp/meson.build @@ -36,3 +36,29 @@ shared_module('fu_plugin_elantp', ], ) endif + +if get_option('tests') + e = executable( + 'elantp-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-elantp-firmware.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + install : true, + install_dir : installed_test_bindir, + ) + test('elantp-self-test', e) +endif diff --git a/plugins/fresco-pd/fu-fresco-pd-firmware.c b/plugins/fresco-pd/fu-fresco-pd-firmware.c index 302db833d..85fac84b9 100644 --- a/plugins/fresco-pd/fu-fresco-pd-firmware.c +++ b/plugins/fresco-pd/fu-fresco-pd-firmware.c @@ -24,10 +24,12 @@ fu_fresco_pd_firmware_get_customer_id (FuFrescoPdFirmware *self) } static void -fu_fresco_pd_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_fresco_pd_firmware_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuFrescoPdFirmware *self = FU_FRESCO_PD_FIRMWARE (firmware); - fu_common_string_append_ku (str, idt, "CustomerID", self->customer_id); + fu_xmlb_builder_insert_kx (bn, "customer_id", self->customer_id); } static gboolean @@ -70,7 +72,7 @@ fu_fresco_pd_firmware_class_init (FuFrescoPdFirmwareClass *klass) { FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); klass_firmware->parse = fu_fresco_pd_firmware_parse; - klass_firmware->to_string = fu_fresco_pd_firmware_to_string; + klass_firmware->export = fu_fresco_pd_firmware_export; } FuFirmware * diff --git a/plugins/pixart-rf/fu-pxi-firmware.c b/plugins/pixart-rf/fu-pxi-firmware.c index b7bc8082d..ffe68e89b 100644 --- a/plugins/pixart-rf/fu-pxi-firmware.c +++ b/plugins/pixart-rf/fu-pxi-firmware.c @@ -28,10 +28,12 @@ fu_pxi_firmware_get_model_name (FuPxiFirmware *self) } static void -fu_pxi_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_pxi_firmware_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuPxiFirmware *self = FU_PXI_FIRMWARE (firmware); - fu_common_string_append_kv (str, idt, "ModelName", self->model_name); + fu_xmlb_builder_insert_kv (bn, "model_name", self->model_name); } static gboolean @@ -206,7 +208,7 @@ fu_pxi_firmware_class_init (FuPxiFirmwareClass *klass) klass_firmware->parse = fu_pxi_firmware_parse; klass_firmware->build = fu_pxi_firmware_build; klass_firmware->write = fu_pxi_firmware_write; - klass_firmware->to_string = fu_pxi_firmware_to_string; + klass_firmware->export = fu_pxi_firmware_export; } FuFirmware * diff --git a/plugins/pixart-rf/fu-self-test.c b/plugins/pixart-rf/fu-self-test.c new file mode 100644 index 000000000..7c1b4e6b3 --- /dev/null +++ b/plugins/pixart-rf/fu-self-test.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-pxi-firmware.h" + +static void +fu_pxi_firmware_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_pxi_firmware_new (); + g_autoptr(FuFirmware) firmware2 = fu_pxi_firmware_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/pixart.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + + /* tests go here */ + g_test_add_func ("/pxi/firmware{xml}", fu_pxi_firmware_xml_func); + return g_test_run (); +} diff --git a/plugins/pixart-rf/meson.build b/plugins/pixart-rf/meson.build index ce2e6f6d5..5d9267cbc 100644 --- a/plugins/pixart-rf/meson.build +++ b/plugins/pixart-rf/meson.build @@ -29,3 +29,29 @@ shared_module('fu_plugin_pixart_rf', ], ) endif + +if get_option('tests') + e = executable( + 'pxi-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-pxi-firmware.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + install : true, + install_dir : installed_test_bindir, + ) + test('pxi-self-test', e) +endif diff --git a/plugins/spi/fu-efi-firmware-file.c b/plugins/spi/fu-efi-firmware-file.c index a50ed7395..2d611d441 100644 --- a/plugins/spi/fu-efi-firmware-file.c +++ b/plugins/spi/fu-efi-firmware-file.c @@ -96,22 +96,20 @@ fu_efi_firmware_file_type_to_string (guint8 type) } static void -fu_efi_firmware_file_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_efi_firmware_file_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuEfiFirmwareFile *self = FU_EFI_FIRMWARE_FILE (firmware); FuEfiFirmwareFilePrivate *priv = GET_PRIVATE (self); - const gchar *type_name = fu_efi_firmware_file_type_to_string (priv->type); - const gchar *guid_name = fu_efi_guid_to_name (fu_firmware_get_id (firmware)); - if (guid_name != NULL) - fu_common_string_append_kv (str, idt, "Name", guid_name); - if (priv->attrib != 0x0) - fu_common_string_append_kx (str, idt, "Attrib", priv->attrib); - if (type_name != NULL) { - g_autofree gchar *tmp = g_strdup_printf ("%s [0x%02x]", type_name, priv->type); - fu_common_string_append_kv (str, idt, "Type", tmp); - } else { - fu_common_string_append_kx (str, idt, "Type", priv->type); + fu_xmlb_builder_insert_kx (bn, "attrib", priv->attrib); + fu_xmlb_builder_insert_kx (bn, "type", priv->type); + if (flags & FU_FIRMWARE_EXPORT_FLAG_INCLUDE_DEBUG) { + fu_xmlb_builder_insert_kv (bn, "name", + fu_efi_guid_to_name (fu_firmware_get_id (firmware))); + fu_xmlb_builder_insert_kv (bn, "type_name", + fu_efi_firmware_file_type_to_string (priv->type)); } } @@ -367,7 +365,7 @@ fu_efi_firmware_file_class_init (FuEfiFirmwareFileClass *klass) klass_firmware->parse = fu_efi_firmware_file_parse; klass_firmware->write = fu_efi_firmware_file_write; klass_firmware->build = fu_efi_firmware_file_build; - klass_firmware->to_string = fu_efi_firmware_file_to_string; + klass_firmware->export = fu_efi_firmware_file_export; } /** diff --git a/plugins/spi/fu-efi-firmware-section.c b/plugins/spi/fu-efi-firmware-section.c index 0de892e4d..f41ab2411 100644 --- a/plugins/spi/fu-efi-firmware-section.c +++ b/plugins/spi/fu-efi-firmware-section.c @@ -82,21 +82,20 @@ fu_efi_firmware_section_type_to_string (guint8 type) } static void -fu_efi_firmware_section_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_efi_firmware_section_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuEfiFirmwareSection *self = FU_EFI_FIRMWARE_SECTION (firmware); FuEfiFirmwareSectionPrivate *priv = GET_PRIVATE (self); - const gchar *type_name = fu_efi_firmware_section_type_to_string (priv->type); - const gchar *guid_name = fu_efi_guid_to_name (fu_firmware_get_id (firmware)); - if (type_name != NULL) { - g_autofree gchar *tmp = g_strdup_printf ("%s [0x%02x]", type_name, priv->type); - fu_common_string_append_kv (str, idt, "Type", tmp); - } else { - fu_common_string_append_kx (str, idt, "Type", priv->type); + fu_xmlb_builder_insert_kx (bn, "type", priv->type); + if (flags & FU_FIRMWARE_EXPORT_FLAG_INCLUDE_DEBUG) { + fu_xmlb_builder_insert_kv (bn, "name", + fu_efi_guid_to_name (fu_firmware_get_id (firmware))); + fu_xmlb_builder_insert_kv (bn, "type_name", + fu_efi_firmware_section_type_to_string (priv->type)); } - if (guid_name != NULL) - fu_common_string_append_kv (str, idt, "Name", guid_name); } static gboolean @@ -263,7 +262,7 @@ fu_efi_firmware_section_class_init (FuEfiFirmwareSectionClass *klass) klass_firmware->parse = fu_efi_firmware_section_parse; klass_firmware->write = fu_efi_firmware_section_write; klass_firmware->build = fu_efi_firmware_section_build; - klass_firmware->to_string = fu_efi_firmware_section_to_string; + klass_firmware->export = fu_efi_firmware_section_export; } /** diff --git a/plugins/spi/fu-efi-firmware-volume.c b/plugins/spi/fu-efi-firmware-volume.c index 7c8090348..666e6c7d0 100644 --- a/plugins/spi/fu-efi-firmware-volume.c +++ b/plugins/spi/fu-efi-firmware-volume.c @@ -44,14 +44,17 @@ G_DEFINE_TYPE_WITH_PRIVATE (FuEfiFirmwareVolume, fu_efi_firmware_volume, FU_TYPE #define FU_EFI_FIRMWARE_VOLUME_SIZE 0x40 static void -fu_ifd_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_ifd_firmware_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuEfiFirmwareVolume *self = FU_EFI_FIRMWARE_VOLUME (firmware); FuEfiFirmwareVolumePrivate *priv = GET_PRIVATE (self); - const gchar *guid_name = fu_efi_guid_to_name (fu_firmware_get_id (firmware)); - if (guid_name != NULL) - fu_common_string_append_kv (str, idt, "Name", guid_name); - fu_common_string_append_kx (str, idt, "Attrs", priv->attrs); + fu_xmlb_builder_insert_kx (bn, "attrs", priv->attrs); + if (flags & FU_FIRMWARE_EXPORT_FLAG_INCLUDE_DEBUG) { + fu_xmlb_builder_insert_kv (bn, "name", + fu_efi_guid_to_name (fu_firmware_get_id (firmware))); + } } static gboolean @@ -356,7 +359,7 @@ fu_efi_firmware_volume_class_init (FuEfiFirmwareVolumeClass *klass) FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); klass_firmware->parse = fu_efi_firmware_volume_parse; klass_firmware->write = fu_efi_firmware_volume_write; - klass_firmware->to_string = fu_ifd_firmware_to_string; + klass_firmware->export = fu_ifd_firmware_export; } /** diff --git a/plugins/spi/fu-ifd-bios.c b/plugins/spi/fu-ifd-bios.c index 8618c10c2..470ca4f8e 100644 --- a/plugins/spi/fu-ifd-bios.c +++ b/plugins/spi/fu-ifd-bios.c @@ -80,30 +80,6 @@ fu_ifd_bios_parse (FuFirmware *firmware, return TRUE; } -static GBytes * -fu_ifd_bios_write (FuFirmware *firmware, GError **error) -{ - g_autoptr(GByteArray) buf = g_byte_array_new (); - g_autoptr(GPtrArray) images = fu_firmware_get_images (firmware); - - /* add each volume */ - for (guint i = 0; i < images->len; i++) { - FuFirmware *img = g_ptr_array_index (images, i); - g_autoptr(GBytes) bytes = fu_firmware_write (img, error); - if (bytes == NULL) - return NULL; - fu_byte_array_append_bytes (buf, bytes); - } - - /* align up */ - fu_byte_array_set_size (buf, - fu_common_align_up (buf->len, - fu_firmware_get_alignment (firmware))); - - /* success */ - return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); -} - static void fu_ifd_bios_init (FuIfdBios *self) { @@ -115,7 +91,6 @@ fu_ifd_bios_class_init (FuIfdBiosClass *klass) { FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); klass_firmware->parse = fu_ifd_bios_parse; - klass_firmware->write = fu_ifd_bios_write; } /** diff --git a/plugins/spi/fu-ifd-firmware.c b/plugins/spi/fu-ifd-firmware.c index 0d02a3bfc..4817fbd7a 100644 --- a/plugins/spi/fu-ifd-firmware.c +++ b/plugins/spi/fu-ifd-firmware.c @@ -61,43 +61,38 @@ G_DEFINE_TYPE_WITH_PRIVATE (FuIfdFirmware, fu_ifd_firmware, FU_TYPE_FIRMWARE) #define FU_IFD_FREG_LIMIT(freg) ((((freg) >> 4) & 0x07FFF000) | 0x00000FFF) static void -fu_ifd_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_ifd_firmware_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuIfdFirmware *self = FU_IFD_FIRMWARE (firmware); FuIfdFirmwarePrivate *priv = GET_PRIVATE (self); - fu_common_string_append_kx (str, idt, "DescriptorMap0", - priv->descriptor_map0); - fu_common_string_append_kx (str, idt, "DescriptorMap1", - priv->descriptor_map1); - fu_common_string_append_kx (str, idt, "DescriptorMap2", - priv->descriptor_map2); - fu_common_string_append_ku (str, idt, "NumRegions", - priv->num_regions); - fu_common_string_append_ku (str, idt, "NumComponents", - priv->num_components + 1); - fu_common_string_append_kx (str, idt, "FlashRegionBaseAddr", - priv->flash_region_base_addr); - fu_common_string_append_kx (str, idt, "FlashComponentBaseAddr", - priv->flash_component_base_addr); - fu_common_string_append_kx (str, idt, "FlashMasterBaseAddr", - priv->flash_master_base_addr); + fu_xmlb_builder_insert_kx (bn, "descriptor_map0", priv->descriptor_map0); + fu_xmlb_builder_insert_kx (bn, "descriptor_map1", priv->descriptor_map1); + fu_xmlb_builder_insert_kx (bn, "descriptor_map2", priv->descriptor_map2); + fu_xmlb_builder_insert_kx (bn, "num_regions", priv->num_regions); + fu_xmlb_builder_insert_kx (bn, "num_components", priv->num_components + 1); + fu_xmlb_builder_insert_kx (bn, "flash_region_base_addr", priv->flash_region_base_addr); + fu_xmlb_builder_insert_kx (bn, "flash_component_base_addr", priv->flash_component_base_addr); + fu_xmlb_builder_insert_kx (bn, "flash_master_base_addr", priv->flash_master_base_addr); for (guint i = 1; i < 3; i++) { g_autofree gchar *title = g_strdup_printf ("FlashMaster%x", i + 1); - fu_common_string_append_kx (str, idt, title, - priv->flash_master[i]); + fu_xmlb_builder_insert_kx (bn, title, priv->flash_master[i]); } - fu_common_string_append_kx (str, idt, "FlashIchStrapBaseAddr", - priv->flash_ich_strap_base_addr); - fu_common_string_append_kx (str, idt, "FlashMchStrapBaseAddr", - priv->flash_mch_strap_base_addr); - fu_common_string_append_kx (str, idt, "ComponentsRcd", - priv->components_rcd); - fu_common_string_append_kx (str, idt, "IllegalJedec", priv->illegal_jedec); - fu_common_string_append_kx (str, idt, "IllegalJedec1", priv->illegal_jedec1); - if (priv->flash_descriptor_regs != NULL) { - for (guint i = 0; i < priv->num_regions; i++) { - g_autofree gchar *title = g_strdup_printf ("FlashDescriptorReg%x", i); - fu_common_string_append_kx (str, idt, title, priv->flash_descriptor_regs[i]); + fu_xmlb_builder_insert_kx (bn, "flash_ich_strap_base_addr", + priv->flash_ich_strap_base_addr); + fu_xmlb_builder_insert_kx (bn, "flash_mch_strap_base_addr", + priv->flash_mch_strap_base_addr); + fu_xmlb_builder_insert_kx (bn, "components_rcd", + priv->components_rcd); + fu_xmlb_builder_insert_kx (bn, "illegal_jedec", priv->illegal_jedec); + fu_xmlb_builder_insert_kx (bn, "illegal_jedec1", priv->illegal_jedec1); + if (flags & FU_FIRMWARE_EXPORT_FLAG_INCLUDE_DEBUG) { + if (priv->flash_descriptor_regs != NULL) { + for (guint i = 0; i < priv->num_regions; i++) { + g_autofree gchar *title = g_strdup_printf ("flash_descriptor_reg%x", i); + fu_xmlb_builder_insert_kx (bn, title, priv->flash_descriptor_regs[i]); + } } } } @@ -474,7 +469,7 @@ fu_ifd_firmware_class_init (FuIfdFirmwareClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); object_class->finalize = fu_ifd_firmware_finalize; - klass_firmware->to_string = fu_ifd_firmware_to_string; + klass_firmware->export = fu_ifd_firmware_export; klass_firmware->parse = fu_ifd_firmware_parse; klass_firmware->write = fu_ifd_firmware_write; klass_firmware->build = fu_ifd_firmware_build; diff --git a/plugins/spi/fu-ifd-image.c b/plugins/spi/fu-ifd-image.c index f980ff0d9..bf9b012fc 100644 --- a/plugins/spi/fu-ifd-image.c +++ b/plugins/spi/fu-ifd-image.c @@ -18,17 +18,19 @@ G_DEFINE_TYPE_WITH_PRIVATE (FuIfdImage, fu_ifd_image, FU_TYPE_FIRMWARE) #define GET_PRIVATE(o) (fu_ifd_image_get_instance_private (o)) static void -fu_ifd_image_to_string (FuFirmware *image, guint idt, GString *str) +fu_ifd_image_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { - FuIfdImage *self = FU_IFD_IMAGE (image); + FuIfdImage *self = FU_IFD_IMAGE (firmware); FuIfdImagePrivate *priv = GET_PRIVATE (self); for (guint i = 0; i < FU_IFD_REGION_MAX; i++) { - g_autofree gchar *title = NULL; if (priv->access[i] == FU_IFD_ACCESS_NONE) continue; - title = g_strdup_printf ("Access[%s]", fu_ifd_region_to_string (i)); - fu_common_string_append_kv (str, idt, title, - fu_ifd_access_to_string (priv->access[i])); + xb_builder_node_insert_text (bn, "access", + fu_ifd_access_to_string (priv->access[i]), + "region", fu_ifd_region_to_string (i), + NULL); } } @@ -71,19 +73,32 @@ static GBytes * fu_ifd_image_write (FuFirmware *firmware, GError **error) { g_autoptr(GByteArray) buf = g_byte_array_new (); - g_autoptr(GBytes) bytes = NULL; + g_autoptr(GPtrArray) images = fu_firmware_get_images (firmware); - /* simple payload */ - bytes = fu_firmware_get_bytes (firmware, error); - if (bytes == NULL) - return NULL; - fu_byte_array_append_bytes (buf, bytes); + /* add each volume */ + if (images->len > 0) { + for (guint i = 0; i < images->len; i++) { + FuFirmware *img = g_ptr_array_index (images, i); + g_autoptr(GBytes) bytes = fu_firmware_write (img, error); + if (bytes == NULL) + return NULL; + fu_byte_array_append_bytes (buf, bytes); + } + } else { + g_autoptr(GBytes) bytes = NULL; + bytes = fu_firmware_get_bytes (firmware, error); + if (bytes == NULL) + return NULL; + fu_byte_array_append_bytes (buf, bytes); + } /* align up */ - fu_byte_array_set_size (buf, - fu_common_align_up (g_bytes_get_size (bytes), - fu_firmware_get_alignment (firmware))); + fu_byte_array_set_size (buf, fu_common_align_up (buf->len, + fu_firmware_get_alignment (firmware))); + + /* success */ return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); + } static void @@ -96,7 +111,7 @@ static void fu_ifd_image_class_init (FuIfdImageClass *klass) { FuFirmwareClass *klass_image = FU_FIRMWARE_CLASS (klass); - klass_image->to_string = fu_ifd_image_to_string; + klass_image->export = fu_ifd_image_export; klass_image->write = fu_ifd_image_write; } diff --git a/plugins/spi/fu-self-test.c b/plugins/spi/fu-self-test.c new file mode 100644 index 000000000..9de510c77 --- /dev/null +++ b/plugins/spi/fu-self-test.c @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-efi-firmware-file.h" +#include "fu-efi-firmware-filesystem.h" +#include "fu-efi-firmware-section.h" +#include "fu-efi-firmware-volume.h" +#include "fu-ifd-bios.h" +#include "fu-ifd-image.h" + +static void +fu_efi_firmware_section_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_efi_firmware_section_new (); + g_autoptr(FuFirmware) firmware2 = fu_efi_firmware_section_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/efi-firmware-section.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} + +static void +fu_efi_firmware_file_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_efi_firmware_file_new (); + g_autoptr(FuFirmware) firmware2 = fu_efi_firmware_file_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/efi-firmware-file.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "fb0f4b276b3672d2dbcf3fe543ddd743f02c7fe0"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} + +static void +fu_efi_firmware_filesystem_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_efi_firmware_filesystem_new (); + g_autoptr(FuFirmware) firmware2 = fu_efi_firmware_filesystem_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/efi-firmware-filesystem.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "d6fbadc1c303a3b4eede9db7fb0ddb353efffc86"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} + +static void +fu_efi_firmware_volume_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_efi_firmware_volume_new (); + g_autoptr(FuFirmware) firmware2 = fu_efi_firmware_volume_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/efi-firmware-volume.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} + +static void +fu_ifd_image_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_ifd_image_new (); + g_autoptr(FuFirmware) firmware2 = fu_ifd_image_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/ifd.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "49e18145664a6910ba86b5e6ce74e40efd76c963"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_type_ensure (FU_TYPE_IFD_BIOS); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + + /* tests go here */ + g_test_add_func ("/efi/firmware-section{xml}", fu_efi_firmware_section_xml_func); + g_test_add_func ("/efi/firmware-file{xml}", fu_efi_firmware_file_xml_func); + g_test_add_func ("/efi/firmware-filesystem{xml}", fu_efi_firmware_filesystem_xml_func); + g_test_add_func ("/efi/firmware-volume{xml}", fu_efi_firmware_volume_xml_func); + g_test_add_func ("/ifd/image{xml}", fu_ifd_image_xml_func); + return g_test_run (); +} diff --git a/plugins/spi/meson.build b/plugins/spi/meson.build index d4db6267a..0f85af722 100644 --- a/plugins/spi/meson.build +++ b/plugins/spi/meson.build @@ -34,3 +34,39 @@ shared_module('fu_plugin_spi', ], ) endif + +if get_option('tests') and get_option('lzma') + e = executable( + 'spi-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-efi-common.c', + 'fu-efi-firmware-common.c', + 'fu-efi-firmware-file.c', + 'fu-efi-firmware-filesystem.c', + 'fu-efi-firmware-section.c', + 'fu-efi-firmware-volume.c', + 'fu-ifd-bios.c', + 'fu-ifd-common.c', + 'fu-ifd-firmware.c', + 'fu-ifd-image.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + lzma, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + install : true, + install_dir : installed_test_bindir, + ) + test('spi-self-test', e) +endif diff --git a/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-firmware.c b/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-firmware.c index f85c22f4b..47553f8fa 100644 --- a/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-firmware.c +++ b/plugins/synaptics-cxaudio/fu-synaptics-cxaudio-firmware.c @@ -44,17 +44,19 @@ fu_synaptics_cxaudio_firmware_get_layout_version (FuSynapticsCxaudioFirmware *se } static void -fu_synaptics_cxaudio_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_synaptics_cxaudio_firmware_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuSynapticsCxaudioFirmware *self = FU_SYNAPTICS_CXAUDIO_FIRMWARE (firmware); - fu_common_string_append_kx (str, idt, "FileKind", self->file_kind); - fu_common_string_append_kx (str, idt, "DeviceKind", self->device_kind); - fu_common_string_append_kx (str, idt, "LayoutSignature", self->cinfo.LayoutSignature); - fu_common_string_append_kx (str, idt, "LayoutVersion", self->cinfo.LayoutVersion); + fu_xmlb_builder_insert_kx (bn, "file_kind", self->file_kind); + fu_xmlb_builder_insert_kx (bn, "device_kind", self->device_kind); + fu_xmlb_builder_insert_kx (bn, "layout_signature", self->cinfo.LayoutSignature); + fu_xmlb_builder_insert_kx (bn, "layout_version", self->cinfo.LayoutVersion); if (self->cinfo.LayoutVersion >= 1) { - fu_common_string_append_kx (str, idt, "VendorID", self->cinfo.VendorID); - fu_common_string_append_kx (str, idt, "ProductID", self->cinfo.ProductID); - fu_common_string_append_kx (str, idt, "RevisionID", self->cinfo.RevisionID); + fu_xmlb_builder_insert_kx (bn, "vid", self->cinfo.VendorID); + fu_xmlb_builder_insert_kx (bn, "pid", self->cinfo.ProductID); + fu_xmlb_builder_insert_kx (bn, "rev", self->cinfo.RevisionID); } } @@ -294,7 +296,7 @@ fu_synaptics_cxaudio_firmware_class_init (FuSynapticsCxaudioFirmwareClass *klass { FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); klass_firmware->parse = fu_synaptics_cxaudio_firmware_parse; - klass_firmware->to_string = fu_synaptics_cxaudio_firmware_to_string; + klass_firmware->export = fu_synaptics_cxaudio_firmware_export; } FuFirmware * diff --git a/plugins/synaptics-mst/fu-self-test.c b/plugins/synaptics-mst/fu-self-test.c index 0ed1f4220..946656dd9 100644 --- a/plugins/synaptics-mst/fu-self-test.c +++ b/plugins/synaptics-mst/fu-self-test.c @@ -10,6 +10,8 @@ #include #include +#include "fu-synaptics-mst-firmware.h" + #include "fu-plugin-private.h" static void @@ -129,6 +131,42 @@ fu_plugin_synaptics_mst_tb16_func (void) g_assert_cmpint (devices->len, ==, 2); } +static void +fu_synaptics_mst_firmware_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_synaptics_mst_firmware_new (); + g_autoptr(FuFirmware) firmware2 = fu_synaptics_mst_firmware_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/synaptics-mst.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "bfcdf3e6ca6cef45543bfbb57509c92aec9a39fb"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} + int main (int argc, char **argv) { @@ -142,5 +180,7 @@ main (int argc, char **argv) /* tests go here */ g_test_add_func ("/fwupd/plugin/synaptics_mst{none}", fu_plugin_synaptics_mst_none_func); g_test_add_func ("/fwupd/plugin/synaptics_mst{tb16}", fu_plugin_synaptics_mst_tb16_func); + g_test_add_func ("/fwupd/plugin/synaptics_mst/firmware{xml}", fu_synaptics_mst_firmware_xml_func); + return g_test_run (); } diff --git a/plugins/synaptics-mst/fu-synaptics-mst-firmware.c b/plugins/synaptics-mst/fu-synaptics-mst-firmware.c index 3d35f84cb..436b5de75 100644 --- a/plugins/synaptics-mst/fu-synaptics-mst-firmware.c +++ b/plugins/synaptics-mst/fu-synaptics-mst-firmware.c @@ -26,10 +26,12 @@ fu_synaptics_mst_firmware_get_board_id (FuSynapticsMstFirmware *self) } static void -fu_synaptics_mst_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_synaptics_mst_firmware_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuSynapticsMstFirmware *self = FU_SYNAPTICS_MST_FIRMWARE (firmware); - fu_common_string_append_kx (str, idt, "BoardId", self->board_id); + fu_xmlb_builder_insert_kx (bn, "board_id", self->board_id); } static gboolean @@ -75,6 +77,21 @@ fu_synaptics_mst_firmware_write (FuFirmware *firmware, GError **error) return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); } +static gboolean +fu_synaptics_rmi_firmware_build (FuFirmware *firmware, XbNode *n, GError **error) +{ + FuSynapticsMstFirmware *self = FU_SYNAPTICS_MST_FIRMWARE (firmware); + guint64 tmp; + + /* optional properties */ + tmp = xb_node_query_text_as_uint (n, "board_id", NULL); + if (tmp != G_MAXUINT64) + self->board_id = tmp; + + /* success */ + return TRUE; +} + static void fu_synaptics_mst_firmware_init (FuSynapticsMstFirmware *self) { @@ -85,8 +102,9 @@ fu_synaptics_mst_firmware_class_init (FuSynapticsMstFirmwareClass *klass) { FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); klass_firmware->parse = fu_synaptics_mst_firmware_parse; - klass_firmware->to_string = fu_synaptics_mst_firmware_to_string; + klass_firmware->export = fu_synaptics_mst_firmware_export; klass_firmware->write = fu_synaptics_mst_firmware_write; + klass_firmware->build = fu_synaptics_rmi_firmware_build; } FuFirmware * diff --git a/plugins/synaptics-prometheus/fu-self-test.c b/plugins/synaptics-prometheus/fu-self-test.c index 67fe99bf1..8bd9c8970 100644 --- a/plugins/synaptics-prometheus/fu-self-test.c +++ b/plugins/synaptics-prometheus/fu-self-test.c @@ -78,11 +78,48 @@ fu_test_synaprom_firmware_func (void) g_assert_cmpint (buf[1], ==, 'H'); } +static void +fu_synaprom_firmware_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_synaprom_firmware_new (); + g_autoptr(FuFirmware) firmware2 = fu_synaprom_firmware_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/synaprom.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} + int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); g_test_add_func ("/synaprom/firmware", fu_test_synaprom_firmware_func); + g_test_add_func ("/synaprom/firmware{xml}", fu_synaprom_firmware_xml_func); return g_test_run (); } diff --git a/plugins/synaptics-prometheus/fu-synaprom-firmware.c b/plugins/synaptics-prometheus/fu-synaprom-firmware.c index 5a5e2e3ac..fad1b9bc9 100644 --- a/plugins/synaptics-prometheus/fu-synaprom-firmware.c +++ b/plugins/synaptics-prometheus/fu-synaprom-firmware.c @@ -51,10 +51,12 @@ fu_synaprom_firmware_tag_to_string (guint16 tag) } static void -fu_synaprom_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_synaprom_firmware_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuSynapromFirmware *self = FU_SYNAPROM_FIRMWARE (firmware); - fu_common_string_append_kx (str, idt, "ProductId", self->product_id); + fu_xmlb_builder_insert_kx (bn, "product_id", self->product_id); } static gboolean @@ -220,7 +222,7 @@ fu_synaprom_firmware_class_init (FuSynapromFirmwareClass *klass) FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); klass_firmware->parse = fu_synaprom_firmware_parse; klass_firmware->write = fu_synaprom_firmware_write; - klass_firmware->to_string = fu_synaprom_firmware_to_string; + klass_firmware->export = fu_synaprom_firmware_export; klass_firmware->build = fu_synaprom_firmware_build; } diff --git a/plugins/synaptics-rmi/fu-self-test.c b/plugins/synaptics-rmi/fu-self-test.c new file mode 100644 index 000000000..ee64f3474 --- /dev/null +++ b/plugins/synaptics-rmi/fu-self-test.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-common.h" +#include "fu-synaptics-rmi-firmware.h" + +static void +fu_synaptics_rmi_firmware_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_synaptics_rmi_firmware_new (); + g_autoptr(FuFirmware) firmware2 = fu_synaptics_rmi_firmware_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/synaptics-rmi.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + + /* tests go here */ + g_test_add_func ("/synaptics-rmi/firmware{xml}", fu_synaptics_rmi_firmware_xml_func); + return g_test_run (); +} diff --git a/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c b/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c index 32261c3c1..6257efab2 100644 --- a/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c +++ b/plugins/synaptics-rmi/fu-synaptics-rmi-firmware.c @@ -166,18 +166,23 @@ fu_synaptics_rmi_firmware_add_image (FuFirmware *firmware, const gchar *id, } static void -fu_synaptics_rmi_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_synaptics_rmi_firmware_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuSynapticsRmiFirmware *self = FU_SYNAPTICS_RMI_FIRMWARE (firmware); - fu_common_string_append_kx (str, idt, "Kind", self->kind); - fu_common_string_append_kv (str, idt, "ProductId", self->product_id); - fu_common_string_append_kx (str, idt, "BootloaderVersion", self->bootloader_version); - fu_common_string_append_kx (str, idt, "IO", self->io); - fu_common_string_append_kx (str, idt, "Checksum", self->checksum); - fu_common_string_append_kx (str, idt, "BuildId", self->build_id); - fu_common_string_append_kx (str, idt, "PackageId", self->package_id); - fu_common_string_append_kx (str, idt, "ProductInfo", self->product_info); - fu_common_string_append_kx (str, idt, "SigSize", self->sig_size); + fu_xmlb_builder_insert_kx (bn, "kind", self->kind); + fu_xmlb_builder_insert_kv (bn, "product_id", self->product_id); + if (flags & FU_FIRMWARE_EXPORT_FLAG_INCLUDE_DEBUG) { + fu_xmlb_builder_insert_kx (bn, "bootloader_version", + self->bootloader_version); + fu_xmlb_builder_insert_kx (bn, "io", self->io); + fu_xmlb_builder_insert_kx (bn, "checksum", self->checksum); + fu_xmlb_builder_insert_kx (bn, "build_id", self->build_id); + fu_xmlb_builder_insert_kx (bn, "package_id", self->package_id); + fu_xmlb_builder_insert_kx (bn, "product_info", self->product_info); + fu_xmlb_builder_insert_kx (bn, "sig_size", self->sig_size); + } } static gboolean @@ -693,7 +698,7 @@ fu_synaptics_rmi_firmware_class_init (FuSynapticsRmiFirmwareClass *klass) FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); object_class->finalize = fu_synaptics_rmi_firmware_finalize; klass_firmware->parse = fu_synaptics_rmi_firmware_parse; - klass_firmware->to_string = fu_synaptics_rmi_firmware_to_string; + klass_firmware->export = fu_synaptics_rmi_firmware_export; klass_firmware->build = fu_synaptics_rmi_firmware_build; klass_firmware->write = fu_synaptics_rmi_firmware_write; } diff --git a/plugins/synaptics-rmi/meson.build b/plugins/synaptics-rmi/meson.build index 9f02f98d2..acbb6b929 100644 --- a/plugins/synaptics-rmi/meson.build +++ b/plugins/synaptics-rmi/meson.build @@ -39,3 +39,31 @@ shared_module('fu_plugin_synaptics_rmi', ], ) endif + +if get_option('tests') + e = executable( + 'synaptics-rmi-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-synaptics-rmi-common.c', + 'fu-synaptics-rmi-firmware.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + gnutls, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + install : true, + install_dir : installed_test_bindir, + ) + test('synaptics-rmi-self-test', e) +endif diff --git a/plugins/thunderbolt/fu-thunderbolt-firmware.c b/plugins/thunderbolt/fu-thunderbolt-firmware.c index 4785f6fea..3b0818877 100644 --- a/plugins/thunderbolt/fu-thunderbolt-firmware.c +++ b/plugins/thunderbolt/fu-thunderbolt-firmware.c @@ -127,25 +127,28 @@ fu_thunderbolt_firmware_family_to_string (FuThunderboltFamily family) } static void -fu_thunderbolt_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_thunderbolt_firmware_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuThunderboltFirmware *self = FU_THUNDERBOLT_FIRMWARE (firmware); FuThunderboltFirmwarePrivate *priv = GET_PRIVATE (self); + g_autoptr(XbBuilderNode) bc = NULL; - fu_common_string_append_kv (str, idt, "Family", - fu_thunderbolt_firmware_family_to_string (priv->family)); - fu_common_string_append_kb (str, idt, "IsHost", priv->is_host); - fu_common_string_append_kb (str, idt, "IsNative", priv->is_native); - fu_common_string_append_kx (str, idt, "DeviceId", priv->device_id); - fu_common_string_append_kx (str, idt, "VendorId", priv->vendor_id); - fu_common_string_append_kx (str, idt, "ModelId", priv->model_id); - fu_common_string_append_kx (str, idt, "FlashSize", priv->flash_size); - fu_common_string_append_kx (str, idt, "Generation", priv->gen); - fu_common_string_append_kx (str, idt, "Ports", priv->ports); - fu_common_string_append_kb (str, idt, "HasPd", priv->has_pd); + fu_xmlb_builder_insert_kv (bn, "family", + fu_thunderbolt_firmware_family_to_string (priv->family)); + fu_xmlb_builder_insert_kb (bn, "is_host", priv->is_host); + fu_xmlb_builder_insert_kb (bn, "is_native", priv->is_native); + fu_xmlb_builder_insert_kx (bn, "device_id", priv->device_id); + fu_xmlb_builder_insert_kx (bn, "vendor_id", priv->vendor_id); + fu_xmlb_builder_insert_kx (bn, "model_id", priv->model_id); + fu_xmlb_builder_insert_kx (bn, "flash_size", priv->flash_size); + fu_xmlb_builder_insert_kx (bn, "generation", priv->gen); + fu_xmlb_builder_insert_kx (bn, "ports", priv->ports); + fu_xmlb_builder_insert_kb (bn, "has_pd", priv->has_pd); for (guint i = 0; i < _SECTION_LAST; i++) { - g_autofree gchar *title = g_strdup_printf ("Section%u", i); - fu_common_string_append_kx (str, idt, title, priv->sections[i]); + g_autofree gchar *tmp = g_strdup_printf ("%x", priv->sections[i]); + xb_builder_node_insert_text (bn, "section", tmp, NULL); } } @@ -555,7 +558,7 @@ fu_thunderbolt_firmware_class_init (FuThunderboltFirmwareClass *klass) { FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); klass_firmware->parse = fu_thunderbolt_firmware_parse; - klass_firmware->to_string = fu_thunderbolt_firmware_to_string; + klass_firmware->export = fu_thunderbolt_firmware_export; } FuThunderboltFirmware * diff --git a/plugins/vli/fu-vli-pd-firmware.c b/plugins/vli/fu-vli-pd-firmware.c index f4f36dc74..5be6e9596 100644 --- a/plugins/vli/fu-vli-pd-firmware.c +++ b/plugins/vli/fu-vli-pd-firmware.c @@ -54,15 +54,15 @@ fu_vli_pd_firmware_validate_header (FuVliPdFirmware *self) } static void -fu_vli_pd_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_vli_pd_firmware_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuVliPdFirmware *self = FU_VLI_PD_FIRMWARE (firmware); - fu_common_string_append_kv (str, idt, "DeviceKind", - fu_vli_common_device_kind_to_string (self->device_kind)); - fu_common_string_append_kx (str, idt, "VID", - fu_vli_pd_firmware_get_vid (self)); - fu_common_string_append_kx (str, idt, "PID", - fu_vli_pd_firmware_get_pid (self)); + fu_xmlb_builder_insert_kv (bn, "device_kind", + fu_vli_common_device_kind_to_string (self->device_kind)); + fu_xmlb_builder_insert_kx (bn, "vid", fu_vli_pd_firmware_get_vid (self)); + fu_xmlb_builder_insert_kx (bn, "pid", fu_vli_pd_firmware_get_pid (self)); } static gboolean @@ -167,7 +167,7 @@ fu_vli_pd_firmware_class_init (FuVliPdFirmwareClass *klass) { FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); klass_firmware->parse = fu_vli_pd_firmware_parse; - klass_firmware->to_string = fu_vli_pd_firmware_to_string; + klass_firmware->export = fu_vli_pd_firmware_export; } FuFirmware * diff --git a/plugins/vli/fu-vli-usbhub-common.c b/plugins/vli/fu-vli-usbhub-common.c index c574cdf7b..09bb4f1ec 100644 --- a/plugins/vli/fu-vli-usbhub-common.c +++ b/plugins/vli/fu-vli-usbhub-common.c @@ -16,29 +16,45 @@ fu_vli_usbhub_header_crc8 (FuVliUsbhubHeader *hdr) } void -fu_vli_usbhub_header_to_string (FuVliUsbhubHeader *hdr, guint idt, GString *str) +fu_vli_usbhub_header_export (FuVliUsbhubHeader *hdr, XbBuilderNode *bn) { - fu_common_string_append_kx (str, idt, "DevId", GUINT16_FROM_BE(hdr->dev_id)); - fu_common_string_append_kx (str, idt, "Variant", hdr->variant); + fu_xmlb_builder_insert_kx (bn, "dev_id", GUINT16_FROM_BE(hdr->dev_id)); + fu_xmlb_builder_insert_kx (bn, "variant", hdr->variant); if (hdr->usb2_fw_sz > 0) { - fu_common_string_append_kx (str, idt, "Usb2FwAddr", - GUINT16_FROM_BE(hdr->usb2_fw_addr)); - fu_common_string_append_kx (str, idt, "Usb2FwSz", - GUINT16_FROM_BE(hdr->usb2_fw_sz)); + fu_xmlb_builder_insert_kx (bn, "usb2_fw_addr", + GUINT16_FROM_BE(hdr->usb2_fw_addr)); + fu_xmlb_builder_insert_kx (bn, "usb2_fw_sz", + GUINT16_FROM_BE(hdr->usb2_fw_sz)); } - fu_common_string_append_kx (str, idt, "Usb3FwAddr", - ((guint32) hdr->usb3_fw_addr_high) << 16 | - GUINT16_FROM_BE(hdr->usb3_fw_addr)); - fu_common_string_append_kx (str, idt, "Usb3FwSz", - GUINT16_FROM_BE(hdr->usb3_fw_sz)); + fu_xmlb_builder_insert_kx (bn, "usb3_fw_addr", + ((guint32) hdr->usb3_fw_addr_high) << 16 | + GUINT16_FROM_BE(hdr->usb3_fw_addr)); + fu_xmlb_builder_insert_kx (bn, "usb3_fw_sz", + GUINT16_FROM_BE(hdr->usb3_fw_sz)); if (hdr->prev_ptr != VLI_USBHUB_FLASHMAP_IDX_INVALID) { - fu_common_string_append_kx (str, idt, "PrevPtr", - VLI_USBHUB_FLASHMAP_IDX_TO_ADDR(hdr->prev_ptr)); + fu_xmlb_builder_insert_kx (bn, "prev_ptr", + VLI_USBHUB_FLASHMAP_IDX_TO_ADDR(hdr->prev_ptr)); } if (hdr->next_ptr != VLI_USBHUB_FLASHMAP_IDX_INVALID) { - fu_common_string_append_kx (str, idt, "NextPtr", - VLI_USBHUB_FLASHMAP_IDX_TO_ADDR(hdr->next_ptr)); + fu_xmlb_builder_insert_kx (bn, "next_ptr", + VLI_USBHUB_FLASHMAP_IDX_TO_ADDR(hdr->next_ptr)); } - fu_common_string_append_kb (str, idt, "ChecksumOK", - hdr->checksum == fu_vli_usbhub_header_crc8 (hdr)); + fu_xmlb_builder_insert_kb (bn, "checksum_ok", + hdr->checksum == fu_vli_usbhub_header_crc8 (hdr)); +} + +void +fu_vli_usbhub_header_to_string (FuVliUsbhubHeader *hdr, guint idt, GString *str) +{ + g_autoptr(XbBuilderNode) bn = xb_builder_node_new ("header"); + g_autofree gchar *xml = NULL; + fu_vli_usbhub_header_export (hdr, bn); + xml = xb_builder_node_export (bn, + XB_NODE_EXPORT_FLAG_FORMAT_MULTILINE | +#if LIBXMLB_CHECK_VERSION(0,2,2) + XB_NODE_EXPORT_FLAG_COLLAPSE_EMPTY | +#endif + XB_NODE_EXPORT_FLAG_FORMAT_INDENT, + NULL); + fu_common_string_append_kv (str, idt, "xml", xml); } diff --git a/plugins/vli/fu-vli-usbhub-common.h b/plugins/vli/fu-vli-usbhub-common.h index ba580c772..2c68291f9 100644 --- a/plugins/vli/fu-vli-usbhub-common.h +++ b/plugins/vli/fu-vli-usbhub-common.h @@ -63,3 +63,5 @@ guint8 fu_vli_usbhub_header_crc8 (FuVliUsbhubHeader *hdr); void fu_vli_usbhub_header_to_string (FuVliUsbhubHeader *hdr, guint idt, GString *str); +void fu_vli_usbhub_header_export (FuVliUsbhubHeader *hdr, + XbBuilderNode *bn); diff --git a/plugins/vli/fu-vli-usbhub-firmware.c b/plugins/vli/fu-vli-usbhub-firmware.c index cd77413cb..6cf1332e2 100644 --- a/plugins/vli/fu-vli-usbhub-firmware.c +++ b/plugins/vli/fu-vli-usbhub-firmware.c @@ -34,12 +34,14 @@ fu_vli_usbhub_firmware_get_device_id (FuVliUsbhubFirmware *self) } static void -fu_vli_usbhub_firmware_to_string (FuFirmware *firmware, guint idt, GString *str) +fu_vli_usbhub_firmware_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) { FuVliUsbhubFirmware *self = FU_VLI_USBHUB_FIRMWARE (firmware); - fu_common_string_append_kv (str, idt, "DeviceKind", - fu_vli_common_device_kind_to_string (self->device_kind)); - fu_vli_usbhub_header_to_string (&self->hdr, idt, str); + fu_xmlb_builder_insert_kv (bn, "device_kind", + fu_vli_common_device_kind_to_string (self->device_kind)); + fu_vli_usbhub_header_export (&self->hdr, bn); } static gboolean @@ -213,7 +215,7 @@ fu_vli_usbhub_firmware_class_init (FuVliUsbhubFirmwareClass *klass) { FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); klass_firmware->parse = fu_vli_usbhub_firmware_parse; - klass_firmware->to_string = fu_vli_usbhub_firmware_to_string; + klass_firmware->export = fu_vli_usbhub_firmware_export; } FuFirmware * diff --git a/plugins/wacom-usb/fu-self-test.c b/plugins/wacom-usb/fu-self-test.c index 482d544ab..433252b98 100644 --- a/plugins/wacom-usb/fu-self-test.c +++ b/plugins/wacom-usb/fu-self-test.c @@ -10,6 +10,7 @@ #include #include "fu-common.h" +#include "fu-srec-firmware.h" #include "fu-wac-common.h" #include "fu-wac-firmware.h" @@ -52,11 +53,47 @@ fu_wac_firmware_parse_func (void) g_bytes_get_data (blob_block, NULL), g_bytes_get_size (blob_block)); } +static void +fu_wac_firmware_xml_func (void) +{ + gboolean ret; + g_autofree gchar *csum1 = NULL; + g_autofree gchar *csum2 = NULL; + g_autofree gchar *xml_out = NULL; + g_autofree gchar *xml_src = NULL; + g_autoptr(FuFirmware) firmware1 = fu_wac_firmware_new (); + g_autoptr(FuFirmware) firmware2 = fu_wac_firmware_new (); + g_autoptr(GError) error = NULL; + + /* build and write */ + ret = g_file_get_contents (FWUPD_FUZZINGSRCDIR "/wacom.builder.xml", + &xml_src, NULL, &error); + g_assert_no_error (error); + g_assert_true (ret); + ret = fu_firmware_build_from_xml (firmware1, xml_src, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum1 = fu_firmware_get_checksum (firmware1, G_CHECKSUM_SHA1, &error); + g_assert_no_error (error); + g_assert_cmpstr (csum1, ==, "bd734911430831127a7bba4664e212a56a2821bc"); + + /* ensure we can round-trip */ + xml_out = fu_firmware_export_to_xml (firmware1, + FU_FIRMWARE_EXPORT_FLAG_NONE, + &error); + g_assert_no_error (error); + ret = fu_firmware_build_from_xml (firmware2, xml_out, &error); + g_assert_no_error (error); + g_assert_true (ret); + csum2 = fu_firmware_get_checksum (firmware2, G_CHECKSUM_SHA1, &error); + g_assert_cmpstr (csum1, ==, csum2); +} int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); + g_type_ensure (FU_TYPE_SREC_FIRMWARE); /* only critical and error are fatal */ g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); @@ -66,6 +103,7 @@ main (int argc, char **argv) /* tests go here */ g_test_add_func ("/wac/firmware{parse}", fu_wac_firmware_parse_func); + g_test_add_func ("/wac/firmware{xml}", fu_wac_firmware_xml_func); return g_test_run (); } diff --git a/src/fu-tool.c b/src/fu-tool.c index 70b2f692a..1109afc50 100644 --- a/src/fu-tool.c +++ b/src/fu-tool.c @@ -1939,6 +1939,62 @@ fu_util_firmware_parse (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } +static gboolean +fu_util_firmware_export (FuUtilPrivate *priv, gchar **values, GError **error) +{ + FuFirmwareExportFlags flags = FU_FIRMWARE_EXPORT_FLAG_NONE; + GType gtype; + g_autoptr(GBytes) blob = NULL; + g_autoptr(FuFirmware) firmware = NULL; + g_autofree gchar *firmware_type = NULL; + g_autofree gchar *str = NULL; + + /* check args */ + if (g_strv_length (values) == 0 || g_strv_length (values) > 2) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments: filename required"); + return FALSE; + } + + if (g_strv_length (values) == 2) + firmware_type = g_strdup (values[1]); + + /* load file */ + blob = fu_common_get_contents_bytes (values[0], error); + if (blob == NULL) + return FALSE; + + /* load engine */ + if (!fu_engine_load (priv->engine, FU_ENGINE_LOAD_FLAG_READONLY, error)) + return FALSE; + + /* find the GType to use */ + if (firmware_type == NULL) + firmware_type = fu_util_prompt_for_firmware_type (priv, error); + if (firmware_type == NULL) + return FALSE; + gtype = fu_engine_get_firmware_gtype_by_id (priv->engine, firmware_type); + if (gtype == G_TYPE_INVALID) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "GType %s not supported", firmware_type); + return FALSE; + } + firmware = g_object_new (gtype, NULL); + if (!fu_firmware_parse (firmware, blob, priv->flags, error)) + return FALSE; + if (priv->show_all) + flags |= FU_FIRMWARE_EXPORT_FLAG_INCLUDE_DEBUG; + str = fu_firmware_export_to_xml (firmware, flags, error); + if (str == NULL) + return FALSE; + g_print ("%s", str); + return TRUE; +} + static gboolean fu_util_firmware_extract (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -3010,6 +3066,13 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Parse and show details about a firmware file"), fu_util_firmware_parse); + fu_util_cmd_array_add (cmd_array, + "firmware-export", + /* TRANSLATORS: command argument: uppercase, spaces->dashes */ + _("FILENAME [FIRMWARE-TYPE]"), + /* TRANSLATORS: command description */ + _("Export a firmware file structure to XML"), + fu_util_firmware_export); fu_util_cmd_array_add (cmd_array, "firmware-extract", /* TRANSLATORS: command argument: uppercase, spaces->dashes */ diff --git a/src/fuzzing/efi-firmware-file.builder.xml b/src/fuzzing/efi-firmware-file.builder.xml new file mode 100644 index 000000000..962ee68ed --- /dev/null +++ b/src/fuzzing/efi-firmware-file.builder.xml @@ -0,0 +1,7 @@ + + ced4eac6-49f3-4c12-a597-fc8c33447691 + 0x0B + + aGVsbG8gd29ybGQ= + + diff --git a/src/fuzzing/efi-firmware-section.builder.xml b/src/fuzzing/efi-firmware-section.builder.xml new file mode 100644 index 000000000..e179e18a7 --- /dev/null +++ b/src/fuzzing/efi-firmware-section.builder.xml @@ -0,0 +1,5 @@ + + 0x02 + ced4eac6-49f3-4c12-a597-fc8c33447691 + aGVsbG8gd29ybGQ= + diff --git a/src/fuzzing/firmware/efi-file.bin b/src/fuzzing/firmware/efi-file.bin new file mode 100644 index 000000000..309f97748 Binary files /dev/null and b/src/fuzzing/firmware/efi-file.bin differ diff --git a/src/fuzzing/synaptics-rmi.builder.xml b/src/fuzzing/synaptics-rmi.builder.xml new file mode 100644 index 000000000..3b0aea721 --- /dev/null +++ b/src/fuzzing/synaptics-rmi.builder.xml @@ -0,0 +1,4 @@ + + 0x42 + aGVsbG8gd29ybGQ= +