fwupd/libfwupdplugin/fu-firmware-image.c
Richard Hughes 47862828e1 trivial: Allow setting an ID of NULL for the FuFirmwareImage
There's no reason to prevent NULL, and doing so means the caller has to check
before setting the value. Only one subclassed type was actually doing this...
2020-01-16 11:24:55 -06:00

372 lines
8.8 KiB
C

/*
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#define G_LOG_DOMAIN "FuFirmware"
#include "config.h"
#include "fu-common.h"
#include "fu-firmware-image-private.h"
/**
* SECTION:fu-firmware_image
* @short_description: a firmware_image file
*
* An object that represents a firmware_image file.
*/
typedef struct {
gchar *id;
GBytes *bytes;
guint64 addr;
guint64 idx;
gchar *version;
} FuFirmwareImagePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (FuFirmwareImage, fu_firmware_image, G_TYPE_OBJECT)
#define GET_PRIVATE(o) (fu_firmware_image_get_instance_private (o))
/**
* fu_firmware_image_get_version:
* @self: A #FuFirmwareImage
*
* Gets an optional version that represents the firmware image.
*
* Returns: a string, or %NULL
*
* Since: 1.3.4
**/
const gchar *
fu_firmware_image_get_version (FuFirmwareImage *self)
{
FuFirmwareImagePrivate *priv = GET_PRIVATE (self);
g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), NULL);
return priv->version;
}
/**
* fu_firmware_image_set_version:
* @self: A #FuFirmwareImage
* @version: (nullable): A string version, or %NULL
*
* Sets an optional version that represents the firmware image.
*
* Since: 1.3.4
**/
void
fu_firmware_image_set_version (FuFirmwareImage *self, const gchar *version)
{
FuFirmwareImagePrivate *priv = GET_PRIVATE (self);
g_return_if_fail (FU_IS_FIRMWARE_IMAGE (self));
g_free (priv->version);
priv->version = g_strdup (version);
}
/**
* fu_firmware_image_set_id:
* @self: a #FuPlugin
* @id: (nullable): image ID, e.g. "config"
*
* Since: 1.3.1
**/
void
fu_firmware_image_set_id (FuFirmwareImage *self, const gchar *id)
{
FuFirmwareImagePrivate *priv = GET_PRIVATE (self);
g_return_if_fail (FU_IS_FIRMWARE_IMAGE (self));
g_free (priv->id);
priv->id = g_strdup (id);
}
/**
* fu_firmware_image_get_id:
* @self: a #FuPlugin
*
* Gets the image ID, typically set at construction.
*
* Returns: image ID, e.g. "config"
*
* Since: 1.3.1
**/
const gchar *
fu_firmware_image_get_id (FuFirmwareImage *self)
{
FuFirmwareImagePrivate *priv = GET_PRIVATE (self);
g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), NULL);
return priv->id;
}
/**
* fu_firmware_image_set_addr:
* @self: a #FuPlugin
* @addr: integer
*
* Sets the base address of the image.
*
* Since: 1.3.1
**/
void
fu_firmware_image_set_addr (FuFirmwareImage *self, guint64 addr)
{
FuFirmwareImagePrivate *priv = GET_PRIVATE (self);
g_return_if_fail (FU_IS_FIRMWARE_IMAGE (self));
priv->addr = addr;
}
/**
* fu_firmware_image_get_addr:
* @self: a #FuPlugin
*
* Gets the base address of the image.
*
* Returns: integer
*
* Since: 1.3.1
**/
guint64
fu_firmware_image_get_addr (FuFirmwareImage *self)
{
FuFirmwareImagePrivate *priv = GET_PRIVATE (self);
g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), G_MAXUINT64);
return priv->addr;
}
/**
* fu_firmware_image_set_idx:
* @self: a #FuPlugin
* @idx: integer
*
* Sets the index of the image which is used for ordering.
*
* Since: 1.3.1
**/
void
fu_firmware_image_set_idx (FuFirmwareImage *self, guint64 idx)
{
FuFirmwareImagePrivate *priv = GET_PRIVATE (self);
g_return_if_fail (FU_IS_FIRMWARE_IMAGE (self));
priv->idx = idx;
}
/**
* fu_firmware_image_get_idx:
* @self: a #FuPlugin
*
* Gets the index of the image which is used for ordering.
*
* Returns: integer
*
* Since: 1.3.1
**/
guint64
fu_firmware_image_get_idx (FuFirmwareImage *self)
{
FuFirmwareImagePrivate *priv = GET_PRIVATE (self);
g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), G_MAXUINT64);
return priv->idx;
}
/**
* fu_firmware_image_set_bytes:
* @self: a #FuPlugin
* @bytes: A #GBytes
*
* Sets the contents of the image if not created with fu_firmware_image_new().
*
* Since: 1.3.1
**/
void
fu_firmware_image_set_bytes (FuFirmwareImage *self, GBytes *bytes)
{
FuFirmwareImagePrivate *priv = GET_PRIVATE (self);
g_return_if_fail (FU_IS_FIRMWARE_IMAGE (self));
g_return_if_fail (bytes != NULL);
g_return_if_fail (priv->bytes == NULL);
priv->bytes = g_bytes_ref (bytes);
}
/**
* fu_firmware_image_write:
* @self: a #FuPlugin
* @error: A #GError, or %NULL
*
* Writes the image, which will try to call a superclassed ->write() function.
*
* By default (and in most cases) this just provides the value set by the
* fu_firmware_image_set_bytes() function.
*
* Returns: (transfer full): a #GBytes of the bytes, or %NULL if the bytes is not set
*
* Since: 1.3.3
**/
GBytes *
fu_firmware_image_write (FuFirmwareImage *self, GError **error)
{
FuFirmwareImageClass *klass = FU_FIRMWARE_IMAGE_GET_CLASS (self);
FuFirmwareImagePrivate *priv = GET_PRIVATE (self);
g_return_val_if_fail (FU_IS_FIRMWARE_IMAGE (self), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
/* optional vfunc */
if (klass->write != NULL)
return klass->write (self, error);
/* fall back to what was set manually */
if (priv->bytes == NULL) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_FOUND,
"no bytes found in firmware bytes %s", priv->id);
return NULL;
}
return g_bytes_ref (priv->bytes);
}
/**
* fu_firmware_image_write_chunk:
* @self: a #FuFirmwareImage
* @address: an address greater than dfu_element_get_address()
* @chunk_sz_max: the size of the new chunk
* @error: a #GError, or %NULL
*
* Gets a block of data from the image. If the contents of the image is
* smaller than the requested chunk size then the #GBytes will be smaller
* than @chunk_sz_max. Use fu_common_bytes_pad() if padding is required.
*
* If the @address is larger than the size of the image then an error is returned.
*
* Return value: (transfer full): a #GBytes, or %NULL
*
* Since: 1.3.1
**/
GBytes *
fu_firmware_image_write_chunk (FuFirmwareImage *self,
guint64 address,
guint64 chunk_sz_max,
GError **error)
{
FuFirmwareImagePrivate *priv = GET_PRIVATE (self);
gsize chunk_left;
guint64 offset;
/* check address requested is larger than base address */
if (address < priv->addr) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"requested address 0x%x less than base address 0x%x",
(guint) address, (guint) priv->addr);
return NULL;
}
/* offset into data */
offset = address - priv->addr;
if (offset > g_bytes_get_size (priv->bytes)) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_FOUND,
"offset 0x%x larger than data size 0x%x",
(guint) offset,
(guint) g_bytes_get_size (priv->bytes));
return NULL;
}
/* if we have less data than requested */
chunk_left = g_bytes_get_size (priv->bytes) - offset;
if (chunk_sz_max > chunk_left)
return g_bytes_new_from_bytes (priv->bytes, offset, chunk_left);
/* check chunk */
return g_bytes_new_from_bytes (priv->bytes, offset, chunk_sz_max);
}
void
fu_firmware_image_add_string (FuFirmwareImage *self, guint idt, GString *str)
{
FuFirmwareImagePrivate *priv = GET_PRIVATE (self);
FuFirmwareImageClass *klass = FU_FIRMWARE_IMAGE_GET_CLASS (self);
fu_common_string_append_kv (str, idt, G_OBJECT_TYPE_NAME (self), NULL);
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->addr != 0x0)
fu_common_string_append_kx (str, idt, "Address", priv->addr);
if (priv->version != NULL)
fu_common_string_append_kv (str, 0, "Version", priv->version);
if (priv->bytes != NULL) {
fu_common_string_append_kx (str, idt, "Data",
g_bytes_get_size (priv->bytes));
}
/* vfunc */
if (klass->to_string != NULL)
klass->to_string (self, idt, str);
}
/**
* fu_firmware_image_to_string:
* @self: A #FuFirmwareImage
*
* This allows us to easily print the object.
*
* Returns: a string value, or %NULL for invalid.
*
* Since: 1.3.1
**/
gchar *
fu_firmware_image_to_string (FuFirmwareImage *self)
{
GString *str = g_string_new (NULL);
fu_firmware_image_add_string (self, 0, str);
return g_string_free (str, FALSE);
}
static void
fu_firmware_image_init (FuFirmwareImage *self)
{
}
static void
fu_firmware_image_finalize (GObject *object)
{
FuFirmwareImage *self = FU_FIRMWARE_IMAGE (object);
FuFirmwareImagePrivate *priv = GET_PRIVATE (self);
g_free (priv->id);
g_free (priv->version);
if (priv->bytes != NULL)
g_bytes_unref (priv->bytes);
G_OBJECT_CLASS (fu_firmware_image_parent_class)->finalize (object);
}
static void
fu_firmware_image_class_init (FuFirmwareImageClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = fu_firmware_image_finalize;
}
/**
* fu_firmware_image_new:
* @bytes: Optional #GBytes
*
* Creates an empty firmware_image object.
*
* Returns: a #FuFirmwareImage
*
* Since: 1.3.1
**/
FuFirmwareImage *
fu_firmware_image_new (GBytes *bytes)
{
FuFirmwareImage *self = g_object_new (FU_TYPE_FIRMWARE_IMAGE, NULL);
if (bytes != NULL)
fu_firmware_image_set_bytes (self, bytes);
return self;
}