/*
 * This file is auto-generated, do not modify!
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

#include "config.h"

#include <glib.h>

#include "fu-uf2-struct.h"
#include "fu-byte-array.h"
#include "fu-bytes.h"
#include "fu-mem-private.h"
#include "fu-string.h"

#ifdef G_LOG_DOMAIN
  #undef G_LOG_DOMAIN
#endif
#define G_LOG_DOMAIN "FuStruct"

/**
 * fu_uf2_firmware_block_flags_to_string:
 * @val: value, e.g. %FU_UF2_FIRMWARE_BLOCK_FLAG_NOFLASH
 *
 * Converts an enumerated value to a string.
 *
 * Returns: identifier string
 **/
static const gchar *
fu_uf2_firmware_block_flags_to_string(FuUf2FirmwareBlockFlags val)
{
    if (val == FU_UF2_FIRMWARE_BLOCK_FLAG_NONE)
        return "none";
    if (val == FU_UF2_FIRMWARE_BLOCK_FLAG_NOFLASH)
        return "noflash";
    if (val == FU_UF2_FIRMWARE_BLOCK_FLAG_IS_CONTAINER)
        return "is-container";
    if (val == FU_UF2_FIRMWARE_BLOCK_FLAG_HAS_FAMILY)
        return "has-family";
    if (val == FU_UF2_FIRMWARE_BLOCK_FLAG_HAS_MD5)
        return "has-md5";
    if (val == FU_UF2_FIRMWARE_BLOCK_FLAG_HAS_EXTENSION_TAG)
        return "has-extension-tag";
    return NULL;
}

/**
 * fu_uf2_firmware_tag_to_string:
 * @val: value, e.g. %FU_UF2_FIRMWARE_TAG_DESCRIPTION
 *
 * Converts an enumerated value to a string.
 *
 * Returns: identifier string
 **/
const gchar *
fu_uf2_firmware_tag_to_string(FuUf2FirmwareTag val)
{
    if (val == FU_UF2_FIRMWARE_TAG_VERSION)
        return "version";
    if (val == FU_UF2_FIRMWARE_TAG_DESCRIPTION)
        return "description";
    if (val == FU_UF2_FIRMWARE_TAG_PAGE_SZ)
        return "page-sz";
    if (val == FU_UF2_FIRMWARE_TAG_SHA2)
        return "sha2";
    if (val == FU_UF2_FIRMWARE_TAG_DEVICE_ID)
        return "device-id";
    return NULL;
}
/**
 * fu_struct_uf2_extension_ref: (skip):
 **/
FuStructUf2Extension *
fu_struct_uf2_extension_ref(FuStructUf2Extension *st)
{
    g_return_val_if_fail(st != NULL, NULL);
    st->refcount++;
    return st;
}
/**
 * fu_struct_uf2_extension_unref: (skip):
 **/
void
fu_struct_uf2_extension_unref(FuStructUf2Extension *st)
{
    g_return_if_fail(st != NULL);
    if (st->refcount == 0) {
        g_critical("FuStructUf2Extension refcount already zero");
        return;
    }
    if (--st->refcount > 0)
        return;
    if (st->buf != NULL)
        g_byte_array_unref(st->buf);
    g_free(st);
}
/**
 * fu_struct_uf2_extension_new_internal: (skip):
 **/
static FuStructUf2Extension *
fu_struct_uf2_extension_new_internal(void)
{
    FuStructUf2Extension *st = g_new0(FuStructUf2Extension, 1);
    st->refcount = 1;
    return st;
}

/* getters */
/**
 * fu_struct_uf2_extension_get_size: (skip):
 **/
guint8
fu_struct_uf2_extension_get_size(const FuStructUf2Extension *st)
{
    g_return_val_if_fail(st != NULL, 0x0);
    return st->buf->data[0];
}
/**
 * fu_struct_uf2_extension_get_tag: (skip):
 **/
FuUf2FirmwareTag
fu_struct_uf2_extension_get_tag(const FuStructUf2Extension *st)
{
    g_return_val_if_fail(st != NULL, 0x0);
    return fu_memread_uint24(st->buf->data + 1, G_LITTLE_ENDIAN);
}

/* setters */
/**
 * fu_struct_uf2_extension_set_size: (skip):
 **/
void
fu_struct_uf2_extension_set_size(FuStructUf2Extension *st, guint8 value)
{
    g_return_if_fail(st != NULL);
    st->buf->data[0] = value;
}
/**
 * fu_struct_uf2_extension_set_tag: (skip):
 **/
void
fu_struct_uf2_extension_set_tag(FuStructUf2Extension *st, FuUf2FirmwareTag value)
{
    g_return_if_fail(st != NULL);
    fu_memwrite_uint24(st->buf->data + 1, value, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_extension_new: (skip):
 **/
FuStructUf2Extension *
fu_struct_uf2_extension_new(void)
{
    FuStructUf2Extension *st = fu_struct_uf2_extension_new_internal();
    st->buf = g_byte_array_sized_new(4);
    fu_byte_array_set_size(st->buf, 4, 0x0);
    return st;
}
/**
 * fu_struct_uf2_extension_to_string: (skip):
 **/
static gchar *
fu_struct_uf2_extension_to_string(const FuStructUf2Extension *st)
{
    g_autoptr(GString) str = g_string_new("FuStructUf2Extension:\n");
    g_return_val_if_fail(st != NULL, NULL);
    g_string_append_printf(str, "  size: 0x%x\n",
                           (guint) fu_struct_uf2_extension_get_size(st));
    {
        const gchar *tmp = fu_uf2_firmware_tag_to_string(fu_struct_uf2_extension_get_tag(st));
        if (tmp != NULL) {
            g_string_append_printf(str, "  tag: 0x%x [%s]\n", (guint) fu_struct_uf2_extension_get_tag(st), tmp);
        } else {
            g_string_append_printf(str, "  tag: 0x%x\n", (guint) fu_struct_uf2_extension_get_tag(st));
        }
    }
    if (str->len > 0)
        g_string_set_size(str, str->len - 1);
    return g_string_free(g_steal_pointer(&str), FALSE);
}
static gboolean
fu_struct_uf2_extension_validate_internal(FuStructUf2Extension *st, GError **error)
{
    g_return_val_if_fail(st != NULL, FALSE);
    return TRUE;
}
static gboolean
fu_struct_uf2_extension_parse_internal(FuStructUf2Extension *st, GError **error)
{
    if (g_log_get_debug_enabled()) {
        g_autofree gchar *str = fu_struct_uf2_extension_to_string(st);
        g_debug("%s", str);
    }
    if (!fu_struct_uf2_extension_validate_internal(st, error))
        return FALSE;
    return TRUE;
}

/**
 * fu_struct_uf2_extension_parse: (skip):
 **/
FuStructUf2Extension *
fu_struct_uf2_extension_parse(const guint8 *buf, gsize bufsz, gsize offset, GError **error)
{
    g_autoptr(FuStructUf2Extension) st = fu_struct_uf2_extension_new_internal();
    g_return_val_if_fail(buf != NULL, NULL);
    g_return_val_if_fail(error == NULL || *error == NULL, NULL);
    if (!fu_memchk_read(bufsz, offset, 4, error)) {
        g_prefix_error_literal(error, "invalid struct FuStructUf2Extension: ");
        return NULL;
    }
    st->buf = g_byte_array_new();
    g_byte_array_append(st->buf, buf + offset, 4);
    if (!fu_struct_uf2_extension_parse_internal(st, error))
        return NULL;
    return g_steal_pointer(&st);
}
/**
 * fu_struct_uf2_ref: (skip):
 **/
FuStructUf2 *
fu_struct_uf2_ref(FuStructUf2 *st)
{
    g_return_val_if_fail(st != NULL, NULL);
    st->refcount++;
    return st;
}
/**
 * fu_struct_uf2_unref: (skip):
 **/
void
fu_struct_uf2_unref(FuStructUf2 *st)
{
    g_return_if_fail(st != NULL);
    if (st->refcount == 0) {
        g_critical("FuStructUf2 refcount already zero");
        return;
    }
    if (--st->refcount > 0)
        return;
    if (st->buf != NULL)
        g_byte_array_unref(st->buf);
    g_free(st);
}
/**
 * fu_struct_uf2_new_internal: (skip):
 **/
static FuStructUf2 *
fu_struct_uf2_new_internal(void)
{
    FuStructUf2 *st = g_new0(FuStructUf2, 1);
    st->refcount = 1;
    return st;
}

/* getters */
/**
 * fu_struct_uf2_get_magic0: (skip):
 **/
static guint32
fu_struct_uf2_get_magic0(const FuStructUf2 *st)
{
    g_return_val_if_fail(st != NULL, 0x0);
    return fu_memread_uint32(st->buf->data + 0, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_get_magic1: (skip):
 **/
static guint32
fu_struct_uf2_get_magic1(const FuStructUf2 *st)
{
    g_return_val_if_fail(st != NULL, 0x0);
    return fu_memread_uint32(st->buf->data + 4, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_get_flags: (skip):
 **/
FuUf2FirmwareBlockFlags
fu_struct_uf2_get_flags(const FuStructUf2 *st)
{
    g_return_val_if_fail(st != NULL, 0x0);
    return fu_memread_uint32(st->buf->data + 8, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_get_target_addr: (skip):
 **/
guint32
fu_struct_uf2_get_target_addr(const FuStructUf2 *st)
{
    g_return_val_if_fail(st != NULL, 0x0);
    return fu_memread_uint32(st->buf->data + 12, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_get_payload_size: (skip):
 **/
guint32
fu_struct_uf2_get_payload_size(const FuStructUf2 *st)
{
    g_return_val_if_fail(st != NULL, 0x0);
    return fu_memread_uint32(st->buf->data + 16, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_get_block_no: (skip):
 **/
guint32
fu_struct_uf2_get_block_no(const FuStructUf2 *st)
{
    g_return_val_if_fail(st != NULL, 0x0);
    return fu_memread_uint32(st->buf->data + 20, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_get_num_blocks: (skip):
 **/
guint32
fu_struct_uf2_get_num_blocks(const FuStructUf2 *st)
{
    g_return_val_if_fail(st != NULL, 0x0);
    return fu_memread_uint32(st->buf->data + 24, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_get_family_id: (skip):
 **/
guint32
fu_struct_uf2_get_family_id(const FuStructUf2 *st)
{
    g_return_val_if_fail(st != NULL, 0x0);
    return fu_memread_uint32(st->buf->data + 28, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_get_data: (skip):
 **/
const guint8 *
fu_struct_uf2_get_data(const FuStructUf2 *st, gsize *bufsz)
{
    g_return_val_if_fail(st != NULL, NULL);
    if (bufsz != NULL)
        *bufsz = 476;
    return st->buf->data + 32;
}
/**
 * fu_struct_uf2_get_magic_end: (skip):
 **/
static guint32
fu_struct_uf2_get_magic_end(const FuStructUf2 *st)
{
    g_return_val_if_fail(st != NULL, 0x0);
    return fu_memread_uint32(st->buf->data + 508, G_LITTLE_ENDIAN);
}

/* setters */
/**
 * fu_struct_uf2_set_magic0: (skip):
 **/
static void
fu_struct_uf2_set_magic0(FuStructUf2 *st, guint32 value)
{
    g_return_if_fail(st != NULL);
    fu_memwrite_uint32(st->buf->data + 0, value, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_set_magic1: (skip):
 **/
static void
fu_struct_uf2_set_magic1(FuStructUf2 *st, guint32 value)
{
    g_return_if_fail(st != NULL);
    fu_memwrite_uint32(st->buf->data + 4, value, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_set_flags: (skip):
 **/
void
fu_struct_uf2_set_flags(FuStructUf2 *st, FuUf2FirmwareBlockFlags value)
{
    g_return_if_fail(st != NULL);
    fu_memwrite_uint32(st->buf->data + 8, value, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_set_target_addr: (skip):
 **/
void
fu_struct_uf2_set_target_addr(FuStructUf2 *st, guint32 value)
{
    g_return_if_fail(st != NULL);
    fu_memwrite_uint32(st->buf->data + 12, value, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_set_payload_size: (skip):
 **/
void
fu_struct_uf2_set_payload_size(FuStructUf2 *st, guint32 value)
{
    g_return_if_fail(st != NULL);
    fu_memwrite_uint32(st->buf->data + 16, value, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_set_block_no: (skip):
 **/
void
fu_struct_uf2_set_block_no(FuStructUf2 *st, guint32 value)
{
    g_return_if_fail(st != NULL);
    fu_memwrite_uint32(st->buf->data + 20, value, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_set_num_blocks: (skip):
 **/
void
fu_struct_uf2_set_num_blocks(FuStructUf2 *st, guint32 value)
{
    g_return_if_fail(st != NULL);
    fu_memwrite_uint32(st->buf->data + 24, value, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_set_family_id: (skip):
 **/
void
fu_struct_uf2_set_family_id(FuStructUf2 *st, guint32 value)
{
    g_return_if_fail(st != NULL);
    fu_memwrite_uint32(st->buf->data + 28, value, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_set_data: (skip):
 **/
gboolean
fu_struct_uf2_set_data(FuStructUf2 *st, const guint8 *buf, gsize bufsz, GError **error)
{
    g_return_val_if_fail(st != NULL, FALSE);
    g_return_val_if_fail(buf != NULL, FALSE);
    g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
    return fu_memcpy_safe(st->buf->data, st->buf->len, 32, buf, bufsz, 0x0, bufsz, error);
}
/**
 * fu_struct_uf2_set_magic_end: (skip):
 **/
static void
fu_struct_uf2_set_magic_end(FuStructUf2 *st, guint32 value)
{
    g_return_if_fail(st != NULL);
    fu_memwrite_uint32(st->buf->data + 508, value, G_LITTLE_ENDIAN);
}
/**
 * fu_struct_uf2_new: (skip):
 **/
FuStructUf2 *
fu_struct_uf2_new(void)
{
    FuStructUf2 *st = fu_struct_uf2_new_internal();
    st->buf = g_byte_array_sized_new(512);
    fu_byte_array_set_size(st->buf, 512, 0x0);
    fu_struct_uf2_set_magic0(st, 0x0A324655);
    fu_struct_uf2_set_magic1(st, 0x9E5D5157);
    fu_struct_uf2_set_magic_end(st, 0x0AB16F30);
    return st;
}
/**
 * fu_struct_uf2_to_string: (skip):
 **/
static gchar *
fu_struct_uf2_to_string(const FuStructUf2 *st)
{
    g_autoptr(GString) str = g_string_new("FuStructUf2:\n");
    g_return_val_if_fail(st != NULL, NULL);
    g_string_append_printf(str, "  magic0: 0x%x\n",
                           (guint) fu_struct_uf2_get_magic0(st));
    g_string_append_printf(str, "  magic1: 0x%x\n",
                           (guint) fu_struct_uf2_get_magic1(st));
    {
        const gchar *tmp = fu_uf2_firmware_block_flags_to_string(fu_struct_uf2_get_flags(st));
        if (tmp != NULL) {
            g_string_append_printf(str, "  flags: 0x%x [%s]\n", (guint) fu_struct_uf2_get_flags(st), tmp);
        } else {
            g_string_append_printf(str, "  flags: 0x%x\n", (guint) fu_struct_uf2_get_flags(st));
        }
    }
    g_string_append_printf(str, "  target_addr: 0x%x\n",
                           (guint) fu_struct_uf2_get_target_addr(st));
    g_string_append_printf(str, "  payload_size: 0x%x\n",
                           (guint) fu_struct_uf2_get_payload_size(st));
    g_string_append_printf(str, "  block_no: 0x%x\n",
                           (guint) fu_struct_uf2_get_block_no(st));
    g_string_append_printf(str, "  num_blocks: 0x%x\n",
                           (guint) fu_struct_uf2_get_num_blocks(st));
    g_string_append_printf(str, "  family_id: 0x%x\n",
                           (guint) fu_struct_uf2_get_family_id(st));
    {
        gsize bufsz = 0;
        const guint8 *buf = fu_struct_uf2_get_data(st, &bufsz);
        g_autoptr(GString) tmp = g_string_new(NULL);
        for (gsize i = 0; i < bufsz; i++)
            g_string_append_printf(tmp, "%02X", buf[i]);
        g_string_append_printf(str, "  data: 0x%s\n", tmp->str);
    }
    g_string_append_printf(str, "  magic_end: 0x%x\n",
                           (guint) fu_struct_uf2_get_magic_end(st));
    if (str->len > 0)
        g_string_set_size(str, str->len - 1);
    return g_string_free(g_steal_pointer(&str), FALSE);
}
static gboolean
fu_struct_uf2_validate_internal(FuStructUf2 *st, GError **error)
{
    g_return_val_if_fail(st != NULL, FALSE);
    if (fu_struct_uf2_get_magic0(st) != 0x0A324655) {
        g_set_error(error,
                    FWUPD_ERROR,
                    FWUPD_ERROR_INVALID_DATA,
                    "constant FuStructUf2.magic0 was not valid, "
                    "expected 0x%x and got 0x%x",
                    (guint) 0x0A324655,
                    (guint) fu_struct_uf2_get_magic0(st));
        return FALSE;
    }
    if (fu_struct_uf2_get_magic1(st) != 0x9E5D5157) {
        g_set_error(error,
                    FWUPD_ERROR,
                    FWUPD_ERROR_INVALID_DATA,
                    "constant FuStructUf2.magic1 was not valid, "
                    "expected 0x%x and got 0x%x",
                    (guint) 0x9E5D5157,
                    (guint) fu_struct_uf2_get_magic1(st));
        return FALSE;
    }
    if (fu_struct_uf2_get_magic_end(st) != 0x0AB16F30) {
        g_set_error(error,
                    FWUPD_ERROR,
                    FWUPD_ERROR_INVALID_DATA,
                    "constant FuStructUf2.magic_end was not valid, "
                    "expected 0x%x and got 0x%x",
                    (guint) 0x0AB16F30,
                    (guint) fu_struct_uf2_get_magic_end(st));
        return FALSE;
    }
    return TRUE;
}
static gboolean
fu_struct_uf2_parse_internal(FuStructUf2 *st, GError **error)
{
    if (g_log_get_debug_enabled()) {
        g_autofree gchar *str = fu_struct_uf2_to_string(st);
        g_debug("%s", str);
    }
    if (!fu_struct_uf2_validate_internal(st, error))
        return FALSE;
    return TRUE;
}

/**
 * fu_struct_uf2_parse: (skip):
 **/
FuStructUf2 *
fu_struct_uf2_parse(const guint8 *buf, gsize bufsz, gsize offset, GError **error)
{
    g_autoptr(FuStructUf2) st = fu_struct_uf2_new_internal();
    g_return_val_if_fail(buf != NULL, NULL);
    g_return_val_if_fail(error == NULL || *error == NULL, NULL);
    if (!fu_memchk_read(bufsz, offset, 512, error)) {
        g_prefix_error_literal(error, "invalid struct FuStructUf2: ");
        return NULL;
    }
    st->buf = g_byte_array_new();
    g_byte_array_append(st->buf, buf + offset, 512);
    if (!fu_struct_uf2_parse_internal(st, error))
        return NULL;
    return g_steal_pointer(&st);
}
