[PATCH v1 3/4] corelib: refactor Lua image attribute parsing

9 views
Skip to first unread message

He Yong

unread,
Apr 17, 2026, 12:44:34 PM (5 days ago) Apr 17
to swup...@googlegroups.com
Lua image parsing currently relies on repeated key comparisons across
string, bool, and number handlers. This duplicates logic, scatters
field assignments, and makes new attributes error-prone to add.

Switch to table-driven key dispatch with dedicated setter helpers,
reuse common setter macros for bounded copies and typed assignments,
and keep conversion code centralized for better consistency and
maintainability.

Signed-off-by: He Yong <hyy...@163.com>
---
corelib/lua_interface.c | 218 ++++++++++++++++++++++++----------------
1 file changed, 131 insertions(+), 87 deletions(-)

diff --git a/corelib/lua_interface.c b/corelib/lua_interface.c
index 6543dff7..63703075 100644
--- a/corelib/lua_interface.c
+++ b/corelib/lua_interface.c
@@ -267,116 +267,157 @@ int run_lua_script(lua_State *L, const char *script, bool load, const char *func
return ret;
}

+typedef void (*lua_img_string_handler_fn)(struct img_type *img, const char *value);
+typedef void (*lua_img_bool_handler_fn)(struct img_type *img, bool val);
+typedef void (*lua_img_number_handler_fn)(struct img_type *img, double val);
+
+struct lua_img_string_handler_entry {
+ const char *key;
+ lua_img_string_handler_fn handler;
+};
+
+struct lua_img_bool_handler_entry {
+ const char *key;
+ lua_img_bool_handler_fn handler;
+};
+
+struct lua_img_number_handler_entry {
+ const char *key;
+ lua_img_number_handler_fn handler;
+};
+
+static void lua_set_compressed_string(struct img_type *img, const char *value)
+{
+ if (compressed_string_to_type(value, &img->compressed) < 0) {
+ ERROR("compressed argument: '%s' invalid", value);
+ img->compressed = COMPRESSED_FALSE;
+ }
+}
+
+DEFINE_IMG_STRLCPY_SETTER(lua_set_name, id.name)
+DEFINE_IMG_STRLCPY_SETTER(lua_set_version, id.version)
+DEFINE_IMG_STRLCPY_SETTER(lua_set_filename, fname)
+DEFINE_IMG_STRLCPY_SETTER(lua_set_volume, volname)
+DEFINE_IMG_STRLCPY_SETTER(lua_set_type, type)
+DEFINE_IMG_STRLCPY_SETTER(lua_set_device, device)
+DEFINE_IMG_STRLCPY_SETTER(lua_set_mtdname, mtdname)
+DEFINE_IMG_STRLCPY_SETTER(lua_set_path, path)
+DEFINE_IMG_STRLCPY_SETTER(lua_set_data, type_data)
+DEFINE_IMG_STRLCPY_SETTER(lua_set_filesystem, filesystem)
+DEFINE_IMG_STRLCPY_SETTER(lua_set_ivt, ivt_ascii)
+DEFINE_IMG_STRLCPY_SETTER(lua_set_aes_key, aes_ascii)
+
+static void lua_set_sha256(struct img_type *img, const char *value)
+{
+ ascii_to_hash(img->sha256, value);
+}
+
+static void lua_set_offset_string(struct img_type *img, const char *value)
+{
+ char seek_str[MAX_SEEK_STRING_SIZE];
+
+ strlcpy(seek_str, value, sizeof(seek_str));
+ /* convert the offset handling multiplicative suffixes */
+ errno = 0;
+ img->seek = ustrtoull(seek_str, NULL, 0);
+ if (errno) {
+ ERROR("offset argument: ustrtoull failed");
+ }
+}
+
+static const struct lua_img_string_handler_entry lua_string_handlers[] = {
+ { "compressed", lua_set_compressed_string },
+ { "name", lua_set_name },
+ { "version", lua_set_version },
+ { "filename", lua_set_filename },
+ { "volume", lua_set_volume },
+ { "type", lua_set_type },
+ { "device", lua_set_device },
+ { "mtdname", lua_set_mtdname },
+ { "path", lua_set_path },
+ { "data", lua_set_data },
+ { "filesystem", lua_set_filesystem },
+ { "sha256", lua_set_sha256 },
+ { "ivt", lua_set_ivt },
+ { "aes-key", lua_set_aes_key },
+ { "offset", lua_set_offset_string },
+};
+
/**
* @brief convert an image description struct to a lua table
*
* @param L [inout] the Lua stack
* @param software [in] the software struct
*/
-
static void lua_string_to_img(struct img_type *img, const char *key,
const char *value)
{
- const char offset[] = "offset";
- char seek_str[MAX_SEEK_STRING_SIZE];
+ size_t i;

- if (!strcmp(key, "compressed")) {
- if (!strcmp(value, "zlib")) {
- img->compressed = COMPRESSED_ZLIB;
- } else if (!strcmp(value, "xz")) {
- img->compressed = COMPRESSED_XZ;
- } else if (!strcmp(value, "zstd")) {
- img->compressed = COMPRESSED_ZSTD;
- } else {
- ERROR("compressed argument: '%s' invalid", value);
- img->compressed = COMPRESSED_FALSE;
- }
- }
- if (!strcmp(key, "name")) {
- strncpy(img->id.name, value,
- sizeof(img->id.name));
- }
- if (!strcmp(key, "version")) {
- strncpy(img->id.version, value,
- sizeof(img->id.version));
- }
- if (!strcmp(key, "filename")) {
- strncpy(img->fname, value,
- sizeof(img->fname));
- }
- if (!strcmp(key, "volume"))
- strncpy(img->volname, value,
- sizeof(img->volname));
- if (!strcmp(key, "type"))
- strncpy(img->type, value,
- sizeof(img->type));
- if (!strcmp(key, "device"))
- strncpy(img->device, value,
- sizeof(img->device));
- if (!strcmp(key, "mtdname"))
- strncpy(img->mtdname, value,
- sizeof(img->mtdname));
- if (!strcmp(key, "path"))
- strncpy(img->path, value,
- sizeof(img->path));
- if (!strcmp(key, "data"))
- strncpy(img->type_data, value,
- sizeof(img->type_data));
- if (!strcmp(key, "filesystem"))
- strncpy(img->filesystem, value,
- sizeof(img->filesystem));
- if (!strcmp(key, "sha256"))
- ascii_to_hash(img->sha256, value);
- if (!strcmp(key, "ivt"))
- strncpy(img->ivt_ascii, value,
- sizeof(img->ivt_ascii));
- if (!strcmp(key, "aes-key"))
- strncpy(img->aes_ascii, value,
- sizeof(img->aes_ascii));
- if (!strncmp(key, offset, sizeof(offset))) {
- strncpy(seek_str, value,
- sizeof(seek_str));
- /* convert the offset handling multiplicative suffixes */
- img->seek = ustrtoull(seek_str, NULL, 0);
- if (errno){
- ERROR("offset argument: ustrtoull failed");
+ for (i = 0; i < ARRAY_SIZE(lua_string_handlers); i++) {
+ if (!strcmp(key, lua_string_handlers[i].key)) {
+ lua_string_handlers[i].handler(img, value);
+ return;
}
}
}

+DEFINE_IMG_BOOL_SETTER(lua_set_compressed_bool, compressed)
+DEFINE_IMG_BOOL_SETTER(lua_set_installed_directly, install_directly)
+DEFINE_IMG_BOOL_SETTER(lua_set_install_if_different, id.install_if_different)
+DEFINE_IMG_BOOL_SETTER(lua_set_install_if_higher, id.install_if_higher)
+DEFINE_IMG_BOOL_SETTER(lua_set_encrypted, is_encrypted)
+DEFINE_IMG_BOOL_SETTER(lua_set_partition, is_partitioner)
+DEFINE_IMG_BOOL_SETTER(lua_set_script, is_script)
+DEFINE_IMG_BOOL_SETTER(lua_set_preserve_attributes, preserve_attributes)
+
+static const struct lua_img_bool_handler_entry lua_bool_handlers[] = {
+ { "compressed", lua_set_compressed_bool },
+ { "installed_directly", lua_set_installed_directly },
+ { "install_if_different", lua_set_install_if_different },
+ { "install_if_higher", lua_set_install_if_higher },
+ { "encrypted", lua_set_encrypted },
+ { "partition", lua_set_partition },
+ { "script", lua_set_script },
+ { "preserve_attributes", lua_set_preserve_attributes },
+};

static void lua_bool_to_img(struct img_type *img, const char *key,
bool val)
{
- if (!strcmp(key, "compressed"))
- img->compressed = (bool)val;
- if (!strcmp(key, "installed_directly"))
- img->install_directly = (bool)val;
- if (!strcmp(key, "install_if_different"))
- img->id.install_if_different = (bool)val;
- if (!strcmp(key, "install_if_higher"))
- img->id.install_if_higher = (bool)val;
- if (!strcmp(key, "encrypted"))
- img->is_encrypted = (bool)val;
- if (!strcmp(key, "partition"))
- img->is_partitioner = (bool)val;
- if (!strcmp(key, "script"))
- img->is_script = (bool)val;
- if (!strcmp(key, "preserve_attributes"))
- img->preserve_attributes = (bool)val;
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(lua_bool_handlers); i++) {
+ if (!strcmp(key, lua_bool_handlers[i].key)) {
+ lua_bool_handlers[i].handler(img, val);
+ return;
+ }
+ }
}

+DEFINE_IMG_NUMBER_SETTER(lua_set_offset_number, seek, unsigned long long)
+DEFINE_IMG_NUMBER_SETTER(lua_set_size, size, long long)
+DEFINE_IMG_NUMBER_SETTER(lua_set_checksum, checksum, unsigned int)
+DEFINE_IMG_NUMBER_SETTER(lua_set_skip, skip, unsigned int)
+
+static const struct lua_img_number_handler_entry lua_number_handlers[] = {
+ { "offset", lua_set_offset_number },
+ { "size", lua_set_size },
+ { "checksum", lua_set_checksum },
+ { "skip", lua_set_skip },
+};
+
static void lua_number_to_img(struct img_type *img, const char *key,
double val)
{
- if (!strcmp(key, "offset"))
- img->seek = (unsigned long long)val;
- if (!strcmp(key, "size"))
- img->size = (long long)val;
- if (!strcmp(key, "checksum"))
- img->checksum = (unsigned int)val;
- if (!strcmp(key, "skip"))
- img->skip = (unsigned int)val;
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(lua_number_handlers); i++) {
+ if (!strcmp(key, lua_number_handlers[i].key)) {
+ lua_number_handlers[i].handler(img, val);
+ return;
+ }
+ }
}

static int l_copy2file(lua_State *L)
@@ -541,6 +582,9 @@ static void update_table(lua_State* L, struct img_type *img)
case COMPRESSED_ZSTD:
LUA_PUSH_IMG_STRING_VALUE(img, "compressed", "zstd");
break;
+ case COMPRESSED_LZ4:
+ LUA_PUSH_IMG_STRING_VALUE(img, "compressed", "lz4");
+ break;
default:
LUA_PUSH_IMG_BOOL(img, "compressed", compressed);
break;
--
2.43.0

He Yong

unread,
Apr 17, 2026, 12:44:34 PM (5 days ago) Apr 17
to swup...@googlegroups.com
Enable lz4 artifacts end-to-end by wiring parser mappings, runtime
decompression pipeline, build flags, and docs so compressed="lz4"
works like existing codecs.

Signed-off-by: He Yong <hyy...@163.com>
---
Kconfig | 8 +++
Makefile.deps | 4 ++
Makefile.flags | 4 ++
ci/setup.sh | 1 +
core/cpio_utils.c | 101 +++++++++++++++++++++++++++++++++-
core/util.c | 1 +
doc/source/sw-description.rst | 2 +-
doc/source/swupdate.rst | 2 +-
handlers/swupdate.lua | 2 +-
include/util.h | 1 +
10 files changed, 120 insertions(+), 6 deletions(-)

diff --git a/Kconfig b/Kconfig
index 2cf68eb8..8b6139de 100644
--- a/Kconfig
+++ b/Kconfig
@@ -85,6 +85,10 @@ config HAVE_ZSTD
bool
option env="HAVE_ZSTD"

+config HAVE_LZ4
+ bool
+ option env="HAVE_LZ4"
+
config HAVE_LIBSSL
bool
option env="HAVE_LIBSSL"
@@ -421,6 +425,10 @@ config ZSTD
bool "Zstd compression support"
depends on HAVE_ZSTD

+config LZ4
+ bool "LZ4 compression support"
+ depends on HAVE_LZ4
+
comment "Parsers"
source "parser/Kconfig"

diff --git a/Makefile.deps b/Makefile.deps
index c759f687..35f1bd6b 100644
--- a/Makefile.deps
+++ b/Makefile.deps
@@ -66,6 +66,10 @@ ifeq ($(HAVE_ZSTD),)
export HAVE_ZSTD = y
endif

+ifeq ($(HAVE_LZ4),)
+export HAVE_LZ4 = y
+endif
+
ifeq ($(HAVE_LIBEXT2FS),)
export HAVE_LIBEXT2FS = y
endif
diff --git a/Makefile.flags b/Makefile.flags
index 40dd3b66..267d74ab 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -197,6 +197,10 @@ ifeq ($(CONFIG_ZSTD),y)
LDLIBS += zstd
endif

+ifeq ($(CONFIG_LZ4),y)
+LDLIBS += lz4
+endif
+
ifeq ($(CONFIG_DISKPART),y)
LDLIBS += fdisk
endif
diff --git a/ci/setup.sh b/ci/setup.sh
index 863b1c42..82aca63a 100755
--- a/ci/setup.sh
+++ b/ci/setup.sh
@@ -51,6 +51,7 @@ $_SUDO apt-get -qq update && apt-get install --yes --no-install-recommends \
liburiparser-dev \
libwebsockets-dev \
liblzma-dev \
+ liblz4-dev \
libwolfssl-dev \
libzstd-dev \
make \
diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index cb291d3b..4a8b2964 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -22,6 +22,9 @@
#ifdef CONFIG_ZSTD
#include <zstd.h>
#endif
+#ifdef CONFIG_LZ4
+#include <lz4frame.h>
+#endif

#include "generated/autoconf.h"
#include "cpiohdr.h"
@@ -341,7 +344,7 @@ static int decrypt_step(void *state, void *buffer, size_t size)
return 0;
}

-#if defined(CONFIG_GUNZIP) || defined(CONFIG_ZSTD) || defined(CONFIG_XZ)
+#if defined(CONFIG_GUNZIP) || defined(CONFIG_ZSTD) || defined(CONFIG_XZ) || defined(CONFIG_LZ4)
typedef int (*DecompressStep)(void *state, void *buffer, size_t size);

struct DecompressState {
@@ -494,6 +497,70 @@ static int zstd_step(void* state, void* buffer, size_t size)

#endif

+#ifdef CONFIG_LZ4
+
+struct Lz4State {
+ LZ4F_decompressionContext_t dctx;
+ const uint8_t *input_src;
+ size_t input_size;
+ size_t input_pos;
+};
+
+static int lz4_step(void *state, void *buffer, size_t size)
+{
+ struct DecompressState *ds = (struct DecompressState *)state;
+ struct Lz4State *s = (struct Lz4State *)ds->impl_state;
+ size_t decompress_ret = 0;
+ size_t produced = 0;
+ int ret;
+
+ do {
+ if (s->input_pos == s->input_size) {
+ ret = ds->upstream_step(ds->upstream_state, ds->input, sizeof ds->input);
+ if (ret < 0) {
+ return ret;
+ } else if (ret == 0) {
+ ds->eof = true;
+ break;
+ }
+ s->input_src = ds->input;
+ s->input_size = ret;
+ s->input_pos = 0;
+ }
+
+ size_t out_len = size - produced;
+ size_t in_len = s->input_size - s->input_pos;
+ size_t old_produced = produced;
+ size_t old_in_pos = s->input_pos;
+
+ decompress_ret = LZ4F_decompress(s->dctx,
+ (uint8_t *)buffer + produced, &out_len,
+ s->input_src + s->input_pos, &in_len,
+ NULL);
+ if (LZ4F_isError(decompress_ret)) {
+ ERROR("LZ4F_decompress failed: %s", LZ4F_getErrorName(decompress_ret));
+ return -1;
+ }
+
+ produced += out_len;
+ s->input_pos += in_len;
+
+ if (old_produced == produced && old_in_pos == s->input_pos) {
+ ERROR("LZ4F_decompress made no progress");
+ return -1;
+ }
+
+ if (decompress_ret == 0) {
+ ds->eof = true;
+ break;
+ }
+ } while (produced == 0 && !ds->eof);
+
+ return produced;
+}
+
+#endif
+
static int hash_compare(void *dgst, unsigned char *hash)
{
/*
@@ -554,7 +621,7 @@ int copyfile(struct swupdate_copy *args)
.outlen = 0, .eof = false
};

-#if defined(CONFIG_GUNZIP) || defined(CONFIG_ZSTD) || defined(CONFIG_XZ)
+#if defined(CONFIG_GUNZIP) || defined(CONFIG_ZSTD) || defined(CONFIG_XZ) || defined(CONFIG_LZ4)
struct DecompressState decompress_state = {
.upstream_step = NULL, .upstream_state = NULL,
.impl_state = NULL
@@ -583,6 +650,14 @@ int copyfile(struct swupdate_copy *args)
.input_view = { NULL, 0, 0 },
};
#endif
+#ifdef CONFIG_LZ4
+ struct Lz4State lz4_state = {
+ .dctx = NULL,
+ .input_src = NULL,
+ .input_size = 0,
+ .input_pos = 0,
+ };
+#endif
#endif

/*
@@ -690,6 +765,21 @@ int copyfile(struct swupdate_copy *args)
decompress_step = &zstd_step;
decompress_state.impl_state = &zstd_state;
} else
+#endif
+#ifdef CONFIG_LZ4
+ if (args->compressed == COMPRESSED_LZ4) {
+ size_t create_ret;
+
+ create_ret = LZ4F_createDecompressionContext(&lz4_state.dctx, LZ4F_VERSION);
+ if (LZ4F_isError(create_ret)) {
+ ERROR("LZ4F_createDecompressionContext failed: %s",
+ LZ4F_getErrorName(create_ret));
+ ret = -EFAULT;
+ goto copyfile_exit;
+ }
+ decompress_step = &lz4_step;
+ decompress_state.impl_state = &lz4_state;
+ } else
#endif
{
TRACE("Requested decompression method (%d) is not configured!", args->compressed);
@@ -724,7 +814,7 @@ int copyfile(struct swupdate_copy *args)
state = &decrypt_state;
}

-#if defined(CONFIG_GUNZIP) || defined(CONFIG_ZSTD) || defined(CONFIG_XZ)
+#if defined(CONFIG_GUNZIP) || defined(CONFIG_ZSTD) || defined(CONFIG_XZ) || defined(CONFIG_LZ4)
if (args->compressed) {
decompress_state.upstream_step = step;
decompress_state.upstream_state = state;
@@ -806,6 +896,11 @@ copyfile_exit:
ZSTD_freeDStream(zstd_state.dctx);
}
#endif
+#ifdef CONFIG_LZ4
+ if (lz4_state.dctx != NULL) {
+ LZ4F_freeDecompressionContext(lz4_state.dctx);
+ }
+#endif

return ret;
}
diff --git a/core/util.c b/core/util.c
index 89046f3c..efc41f84 100644
--- a/core/util.c
+++ b/core/util.c
@@ -83,6 +83,7 @@ static const struct {
{ "zlib", COMPRESSED_ZLIB },
{ "xz", COMPRESSED_XZ },
{ "zstd", COMPRESSED_ZSTD },
+ { "lz4", COMPRESSED_LZ4 },
};

int compressed_string_to_type(const char *s, int *out_type)
diff --git a/doc/source/sw-description.rst b/doc/source/sw-description.rst
index b09333fc..2c1e0017 100644
--- a/doc/source/sw-description.rst
+++ b/doc/source/sw-description.rst
@@ -1491,7 +1491,7 @@ There are 4 main sections inside sw-description:
| | | | before being installed. the value |
| | | | denotes the compression type. |
| | | | currently supported values are "xz", |
- | | | | "zlib" and "zstd". |
+ | | | | "zlib", "zstd" and "lz4". |
+-------------+----------+------------+---------------------------------------+
| compressed | bool (dep| images | Deprecated. Use the string form. true |
| | recated) | files | is equal to 'compressed = "zlib"'. |
diff --git a/doc/source/swupdate.rst b/doc/source/swupdate.rst
index 84a8f21b..62681c2a 100644
--- a/doc/source/swupdate.rst
+++ b/doc/source/swupdate.rst
@@ -57,7 +57,7 @@ General Overview
SWUpdate can recreate UBI volumes, resizing them and
copying the new software.

-- support for compressed images, using the xz, zlib and zstd library.
+- support for compressed images, using the xz, zlib, zstd and lz4 library.
tarball (tgz file) are supported.

- support for partitioned USB-pen or unpartitioned (mainly
diff --git a/handlers/swupdate.lua b/handlers/swupdate.lua
index aaba4774..e4bda3fa 100644
--- a/handlers/swupdate.lua
+++ b/handlers/swupdate.lua
@@ -273,7 +273,7 @@ swupdate.register_handler = function(name, funcptr, mask) end
--- @field size number Artifact size
--- @field checksum number Computed checksum
--- @field skip number `skip_t` enum number as in `include/swupdate.h`
---- @field compressed string `zlib` or `zstd` (boolean value is deprecated)
+--- @field compressed string `zlib`, `xz`, `zstd` or `lz4` (boolean value is deprecated)
--- @field properties table Properties Table equivalent as specified in `sw-description`
--- @field sha256 string sha256 hash of the image, file, or script
local img_type = {
diff --git a/include/util.h b/include/util.h
index dcd0604c..5c7e1363 100644
--- a/include/util.h
+++ b/include/util.h
@@ -64,6 +64,7 @@ enum compression_type {
COMPRESSED_ZLIB,
COMPRESSED_XZ,
COMPRESSED_ZSTD,
+ COMPRESSED_LZ4,
};

typedef int (*writeimage) (void *out, const void *buf, size_t len);
--
2.43.0

He Yong

unread,
Apr 17, 2026, 12:44:34 PM (5 days ago) Apr 17
to swup...@googlegroups.com
Hi,

this series improves maintainability in image attribute parsing and adds
end-to-end LZ4 decompression support.

The first three patches remove duplicated key-parsing logic in parser and
Lua paths by introducing shared helpers and table-driven dispatch. This
keeps compressed type conversion centralized and makes future attribute
extensions easier and less error-prone.

The last patch adds LZ4 support in Kconfig/build flags, parser mappings,
runtime decompression, Lua helper mapping, and related documentation.

Comments and reviews are welcome.

Thanks,
He Yong

He Yong (4):
util: add compressed-string parser and img setter macros
parser: refactor stream attribute parsing
corelib: refactor Lua image attribute parsing
compress: add lz4 decompression support

Kconfig | 8 ++
Makefile.deps | 4 +
Makefile.flags | 4 +
ci/setup.sh | 1 +
core/cpio_utils.c | 101 +++++++++++++++-
core/util.c | 23 ++++
corelib/lua_interface.c | 218 ++++++++++++++++++++--------------
doc/source/sw-description.rst | 2 +-
doc/source/swupdate.rst | 2 +-
handlers/swupdate.lua | 2 +-
include/util.h | 19 +++
parser/parse_external.c | 175 ++++++++++++++++-----------
parser/parser.c | 11 +-
13 files changed, 400 insertions(+), 170 deletions(-)

--
2.43.0

He Yong

unread,
Apr 17, 2026, 12:44:34 PM (5 days ago) Apr 17
to swup...@googlegroups.com
Lua image parsing currently relies on repeated key comparisons across
string, bool, and number handlers. This duplicates logic, scatters
field assignments, and makes new attributes error-prone to add.

Switch to table-driven key dispatch with dedicated setter helpers,
reuse common setter macros for bounded copies and typed assignments,
and keep conversion code centralized for better consistency and
maintainability.

Signed-off-by: He Yong <hyy...@163.com>
---

He Yong

unread,
Apr 17, 2026, 12:44:34 PM (5 days ago) Apr 17
to swup...@googlegroups.com

He Yong

unread,
Apr 17, 2026, 12:44:34 PM (5 days ago) Apr 17
to swup...@googlegroups.com
External parser currently uses a long chain of key comparisons and
duplicates compressed type mapping in multiple places. This makes
attribute handling harder to maintain and easier to drift.

Replace the if-chain with a key-to-handler dispatch table, introduce
small dedicated setters for each attribute, and reuse
compressed_string_to_type() in both external and common parsing paths
to keep compression conversion logic centralized.

Signed-off-by: He Yong <hyy...@163.com>
---
parser/parse_external.c | 175 ++++++++++++++++++++++++----------------
parser/parser.c | 11 +--
2 files changed, 109 insertions(+), 77 deletions(-)

diff --git a/parser/parse_external.c b/parser/parse_external.c
index d67bcca0..e63058f2 100644
--- a/parser/parse_external.c
+++ b/parser/parse_external.c
@@ -28,82 +28,117 @@
#define LUA_PARSER (CONFIG_EXTPARSERNAME)
#endif

-static void sw_append_stream(struct img_type *img, const char *key,
- const char *value)
+typedef void (*stream_handler_fn)(struct img_type *img, const char *value);
+
+struct stream_handler_entry {
+ const char *key;
+ stream_handler_fn handler;
+};
+
+DEFINE_IMG_STRLCPY_SETTER(sw_set_type, type)
+DEFINE_IMG_STRLCPY_SETTER(sw_set_name, id.name)
+DEFINE_IMG_STRLCPY_SETTER(sw_set_version, id.version)
+DEFINE_IMG_STRLCPY_SETTER(sw_set_mtdname, mtdname)
+DEFINE_IMG_STRLCPY_SETTER(sw_set_filesystem, filesystem)
+DEFINE_IMG_STRLCPY_SETTER(sw_set_volume, volname)
+DEFINE_IMG_STRLCPY_SETTER(sw_set_device, device)
+DEFINE_IMG_STRLCPY_SETTER(sw_set_path, path)
+
+static void sw_set_filename(struct img_type *img, const char *value)
+{
+ strlcpy(img->fname, value, sizeof(img->fname));
+ img->skip = SKIP_NONE;
+}
+
+static void sw_set_offset(struct img_type *img, const char *value)
{
- const char offset[] = "offset";
char seek_str[MAX_SEEK_STRING_SIZE];

- if (!strcmp(key, "type"))
- strlcpy(img->type, value,
- sizeof(img->type));
- if (!strcmp(key, "filename")) {
- strlcpy(img->fname, value,
- sizeof(img->fname));
- img->skip = SKIP_NONE;
+ strlcpy(seek_str, value, sizeof(seek_str));
+ /* convert the offset handling multiplicative suffixes */
+ img->seek = ustrtoull(seek_str, NULL, 0);
+ if (errno) {
+ ERROR("offset argument: ustrtoull failed");
}
- if (!strcmp(key, "name")) {
- strlcpy(img->id.name, value,
- sizeof(img->id.name));
- }
- if (!strcmp(key, "version")) {
- strlcpy(img->id.version, value,
- sizeof(img->id.version));
- }
- if (!strcmp(key, "mtdname") || !strcmp(key, "dest"))
- strlcpy(img->mtdname, value,
- sizeof(img->mtdname));
- if (!strcmp(key, "filesystem"))
- strlcpy(img->filesystem, value,
- sizeof(img->filesystem));
- if (!strcmp(key, "volume"))
- strlcpy(img->volname, value,
- sizeof(img->volname));
- if (!strcmp(key, "device_id"))
- strlcpy(img->device, value,
- sizeof(img->device));
- if (!strcmp(key, "device"))
- strlcpy(img->device, value,
- sizeof(img->device));
- if (!strncmp(key, offset, sizeof(offset))) {
- strlcpy(seek_str, value,
- sizeof(seek_str));
- /* convert the offset handling multiplicative suffixes */
- img->seek = ustrtoull(seek_str, NULL, 0);
- if (errno){
- ERROR("offset argument: ustrtoull failed");
- }
+}
+
+static void sw_set_script(struct img_type *img, const char *value)
+{
+ (void)value;
+ img->is_script = 1;
+}
+
+static void sw_set_sha256(struct img_type *img, const char *value)
+{
+ ascii_to_hash(img->sha256, value);
+}
+
+static void sw_set_encrypted(struct img_type *img, const char *value)
+{
+ (void)value;
+ img->is_encrypted = true;
+}
+
+static void sw_set_compressed(struct img_type *img, const char *value)
+{
+ if (value == NULL || compressed_string_to_type(value, &img->compressed) < 0) {
+ img->compressed = COMPRESSED_TRUE;
}
- if (!strcmp(key, "script"))
- img->is_script = 1;
- if (!strcmp(key, "path"))
- strlcpy(img->path, value,
- sizeof(img->path));
- if (!strcmp(key, "sha256"))
- ascii_to_hash(img->sha256, value);
- if (!strcmp(key, "encrypted"))
- img->is_encrypted = true;
- if (!strcmp(key, "compressed")) {
- if (value != NULL) {
- if (!strcmp(value, "zlib")) {
- img->compressed = COMPRESSED_ZLIB;
- } else if (!strcmp(value, "xz")) {
- img->compressed = COMPRESSED_XZ;
- } else if (!strcmp(value, "zstd")) {
- img->compressed = COMPRESSED_ZSTD;
- } else {
- img->compressed = COMPRESSED_TRUE;
- }
- } else {
- img->compressed = COMPRESSED_TRUE;
- }
+
+}
+
+static void sw_set_install_directly(struct img_type *img, const char *value)
+{
+ (void)value;
+ img->install_directly = 1;
+}
+
+static void sw_set_install_if_different(struct img_type *img, const char *value)
+{
+ (void)value;
+ img->id.install_if_different = 1;
+}
+
+static void sw_set_install_if_higher(struct img_type *img, const char *value)
+{
+ (void)value;
+ img->id.install_if_higher = 1;
+}
+
+static const struct stream_handler_entry handlers[] = {
+ { "type", sw_set_type },
+ { "filename", sw_set_filename },
+ { "name", sw_set_name },
+ { "version", sw_set_version },
+ { "mtdname", sw_set_mtdname },
+ { "dest", sw_set_mtdname },
+ { "filesystem", sw_set_filesystem },
+ { "volume", sw_set_volume },
+ { "device_id", sw_set_device },
+ { "device", sw_set_device },
+ { "offset", sw_set_offset },
+ { "script", sw_set_script },
+ { "path", sw_set_path },
+ { "sha256", sw_set_sha256 },
+ { "encrypted", sw_set_encrypted },
+ { "compressed", sw_set_compressed },
+ { "installed-directly", sw_set_install_directly },
+ { "install-if-different", sw_set_install_if_different },
+ { "install-if-higher", sw_set_install_if_higher },
+};
+
+static void sw_append_stream(struct img_type *img, const char *key,
+ const char *value)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof(handlers) / sizeof(handlers[0]); i++) {
+ if (strcmp(key, handlers[i].key))
+ continue;
+
+ handlers[i].handler(img, value);
+ return;
}
- if (!strcmp(key, "installed-directly"))
- img->install_directly = 1;
- if (!strcmp(key, "install-if-different"))
- img->id.install_if_different = 1;
- if (!strcmp(key, "install-if-higher"))
- img->id.install_if_higher = 1;
}

int parse_external(struct swupdate_cfg *software, const char *filename,
diff --git a/parser/parser.c b/parser/parser.c
index ea2dfef4..4613e032 100644
--- a/parser/parser.c
+++ b/parser/parser.c
@@ -503,16 +503,13 @@ static int parse_common_attributes(parsertype p, void *elem, struct img_type *im
}

if ((compressed = get_field_string(p, elem, "compressed")) != NULL) {
- if (!strcmp(compressed, "zlib")) {
- image->compressed = COMPRESSED_ZLIB;
- } else if (!strcmp(compressed, "xz")) {
- image->compressed = COMPRESSED_XZ;
- } else if (!strcmp(compressed, "zstd")) {
- image->compressed = COMPRESSED_ZSTD;
- } else {
+ int ctype;
+
+ if (compressed_string_to_type(compressed, &ctype) < 0) {
ERROR("compressed argument: '%s' unknown", compressed);
return -1;
}
+ image->compressed = ctype;
} else {
bool img_compressed = false;
GET_FIELD_BOOL(p, elem, "compressed", &img_compressed);
--
2.43.0

He Yong

unread,
Apr 17, 2026, 12:44:35 PM (5 days ago) Apr 17
to swup...@googlegroups.com
Add a shared helper to convert compressed strings to internal type values,
and introduce reusable image setter macros used by parser and Lua mapping code.

Signed-off-by: He Yong <hyy...@163.com>
---
core/util.c | 22 ++++++++++++++++++++++
include/util.h | 18 ++++++++++++++++++
2 files changed, 40 insertions(+)

diff --git a/core/util.c b/core/util.c
index 3f62e070..89046f3c 100644
--- a/core/util.c
+++ b/core/util.c
@@ -76,6 +76,28 @@ int ascii_to_bin(unsigned char *dest, size_t dstlen, const char *src)
return 0;
}

+static const struct {
+ const char *name;
+ int type;
+} compressed_by_name[] = {
+ { "zlib", COMPRESSED_ZLIB },
+ { "xz", COMPRESSED_XZ },
+ { "zstd", COMPRESSED_ZSTD },
+};
+
+int compressed_string_to_type(const char *s, int *out_type)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(compressed_by_name); i++) {
+ if (!strcmp(s, compressed_by_name[i].name)) {
+ *out_type = compressed_by_name[i].type;
+ return 0;
+ }
+ }
+ return -1;
+}
+
static int countargc(char *args, char **argv)
{
int count = 0;
diff --git a/include/util.h b/include/util.h
index d4874f64..dcd0604c 100644
--- a/include/util.h
+++ b/include/util.h
@@ -184,6 +184,23 @@ void notifier_set_color(int level, char *col);
p = strdup(v); \
} while (0)

+#define DEFINE_IMG_STRLCPY_SETTER(_name, _field) \
+static void _name(struct img_type *img, const char *value) \
+{ \
+ strlcpy(img->_field, value, sizeof(img->_field)); \
+}
+
+#define DEFINE_IMG_BOOL_SETTER(_name, _field) \
+static void _name(struct img_type *img, bool val) \
+{ \
+ img->_field = (bool)val; \
+}
+
+#define DEFINE_IMG_NUMBER_SETTER(_name, _field, _type) \
+static void _name(struct img_type *img, double val) \
+{ \
+ img->_field = (_type)val; \
+}

#define IS_STR_EQUAL(s,s1) (s && s1 && !strcmp(s,s1))
#define UNUSED __attribute__((__unused__))
@@ -197,6 +214,7 @@ int ascii_to_bin(unsigned char *dest, size_t dstlen, const char *src);
void hash_to_ascii(const unsigned char *hash, char *s);
int IsValidHash(const unsigned char *hash);
bool is_hex_str(const char *ascii);
+int compressed_string_to_type(const char *s, int *out_type);

#ifndef typeof
#define typeof __typeof__
--
2.43.0

Reply all
Reply to author
Forward
0 new messages