aboutsummaryrefslogtreecommitdiff
path: root/lib/sqfs/src/comp/compressor.c
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-01-31 11:21:30 +0100
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-01-31 13:51:49 +0100
commitcdccc69c62579b0c13b35fad0728079652b8f3c9 (patch)
tree9fa54c710f73c5e08a9c8466e7a712eb63ee07ac /lib/sqfs/src/comp/compressor.c
parent2182129c8f359c4fa1390eaba7a65b595ccd4182 (diff)
Move library source into src sub-directory
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/sqfs/src/comp/compressor.c')
-rw-r--r--lib/sqfs/src/comp/compressor.c218
1 files changed, 218 insertions, 0 deletions
diff --git a/lib/sqfs/src/comp/compressor.c b/lib/sqfs/src/comp/compressor.c
new file mode 100644
index 0000000..4c4d73c
--- /dev/null
+++ b/lib/sqfs/src/comp/compressor.c
@@ -0,0 +1,218 @@
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/*
+ * compressor.c
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#define SQFS_BUILDING_DLL
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "internal.h"
+
+typedef int (*compressor_fun_t)(const sqfs_compressor_config_t *cfg,
+ sqfs_compressor_t **out);
+
+static compressor_fun_t compressors[SQFS_COMP_MAX + 1] = {
+#ifdef WITH_GZIP
+ [SQFS_COMP_GZIP] = gzip_compressor_create,
+#endif
+#ifdef WITH_XZ
+ [SQFS_COMP_XZ] = xz_compressor_create,
+ [SQFS_COMP_LZMA] = lzma_compressor_create,
+#endif
+#ifdef WITH_LZ4
+ [SQFS_COMP_LZ4] = lz4_compressor_create,
+#endif
+#ifdef WITH_ZSTD
+ [SQFS_COMP_ZSTD] = zstd_compressor_create,
+#endif
+};
+
+static const char *names[] = {
+ [SQFS_COMP_GZIP] = "gzip",
+ [SQFS_COMP_LZMA] = "lzma",
+ [SQFS_COMP_LZO] = "lzo",
+ [SQFS_COMP_XZ] = "xz",
+ [SQFS_COMP_LZ4] = "lz4",
+ [SQFS_COMP_ZSTD] = "zstd",
+};
+
+int sqfs_generic_write_options(sqfs_file_t *file, const void *data, size_t size)
+{
+ sqfs_u8 buffer[64];
+ sqfs_u16 header;
+ int ret;
+
+ /* XXX: options for all known compressors should fit into this */
+ if (size >= (sizeof(buffer) - sizeof(header)))
+ return SQFS_ERROR_INTERNAL;
+
+ header = htole16(0x8000 | size);
+ memcpy(buffer, &header, sizeof(header));
+ memcpy(buffer + sizeof(header), data, size);
+
+ ret = file->write_at(file, sizeof(sqfs_super_t),
+ buffer, sizeof(header) + size);
+ if (ret)
+ return ret;
+
+ return sizeof(header) + size;
+}
+
+int sqfs_generic_read_options(sqfs_file_t *file, void *data, size_t size)
+{
+ sqfs_u8 buffer[64];
+ sqfs_u16 header;
+ int ret;
+
+ /* XXX: options for all known compressors should fit into this */
+ if (size >= (sizeof(buffer) - sizeof(header)))
+ return SQFS_ERROR_INTERNAL;
+
+ ret = file->read_at(file, sizeof(sqfs_super_t),
+ buffer, sizeof(header) + size);
+ if (ret)
+ return ret;
+
+ memcpy(&header, buffer, sizeof(header));
+
+ if (le16toh(header) != (0x8000 | size))
+ return SQFS_ERROR_CORRUPTED;
+
+ memcpy(data, buffer + 2, size);
+ return 0;
+}
+
+int sqfs_compressor_create(const sqfs_compressor_config_t *cfg,
+ sqfs_compressor_t **out)
+{
+ sqfs_u8 padd0[sizeof(cfg->opt)];
+ int ret;
+
+ *out = NULL;
+
+ /* check compressor ID */
+ if (cfg == NULL)
+ return SQFS_ERROR_ARG_INVALID;
+
+ if (cfg->id < SQFS_COMP_MIN || cfg->id > SQFS_COMP_MAX)
+ return SQFS_ERROR_UNSUPPORTED;
+
+ if (compressors[cfg->id] == NULL)
+ return SQFS_ERROR_UNSUPPORTED;
+
+ /* make sure the padding bytes are cleared, so we could theoretically
+ turn them into option fields in the future and remain compatible */
+ memset(padd0, 0, sizeof(padd0));
+
+ switch (cfg->id) {
+ case SQFS_COMP_XZ:
+ ret = memcmp(cfg->opt.xz.padd0, padd0,
+ sizeof(cfg->opt.xz.padd0));
+ break;
+ case SQFS_COMP_LZMA:
+ ret = memcmp(cfg->opt.lzma.padd0, padd0,
+ sizeof(cfg->opt.lzma.padd0));
+ break;
+ case SQFS_COMP_LZO:
+ ret = memcmp(cfg->opt.lzo.padd0, padd0,
+ sizeof(cfg->opt.lzo.padd0));
+ break;
+ case SQFS_COMP_GZIP:
+ ret = memcmp(cfg->opt.gzip.padd0, padd0,
+ sizeof(cfg->opt.gzip.padd0));
+ break;
+ default:
+ ret = memcmp(cfg->opt.padd0, padd0, sizeof(cfg->opt.padd0));
+ break;
+ }
+
+ if (ret != 0)
+ return SQFS_ERROR_ARG_INVALID;
+
+ return compressors[cfg->id](cfg, out);
+}
+
+const char *sqfs_compressor_name_from_id(SQFS_COMPRESSOR id)
+{
+ if (id < 0 || (size_t)id >= sizeof(names) / sizeof(names[0]))
+ return NULL;
+
+ return names[id];
+}
+
+int sqfs_compressor_id_from_name(const char *name)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof(names) / sizeof(names[0]); ++i) {
+ if (names[i] != NULL && strcmp(names[i], name) == 0)
+ return i;
+ }
+
+ return SQFS_ERROR_UNSUPPORTED;
+}
+
+int sqfs_compressor_config_init(sqfs_compressor_config_t *cfg,
+ SQFS_COMPRESSOR id,
+ size_t block_size, sqfs_u16 flags)
+{
+ sqfs_u32 flag_mask = SQFS_COMP_FLAG_GENERIC_ALL;
+
+ memset(cfg, 0, sizeof(*cfg));
+
+ switch (id) {
+ case SQFS_COMP_GZIP:
+ flag_mask |= SQFS_COMP_FLAG_GZIP_ALL;
+ cfg->level = SQFS_GZIP_DEFAULT_LEVEL;
+ cfg->opt.gzip.window_size = SQFS_GZIP_DEFAULT_WINDOW;
+ break;
+ case SQFS_COMP_LZO:
+ cfg->opt.lzo.algorithm = SQFS_LZO_DEFAULT_ALG;
+ cfg->level = SQFS_LZO_DEFAULT_LEVEL;
+ break;
+ case SQFS_COMP_ZSTD:
+ cfg->level = SQFS_ZSTD_DEFAULT_LEVEL;
+ break;
+ case SQFS_COMP_XZ:
+ flag_mask |= SQFS_COMP_FLAG_XZ_ALL;
+ cfg->level = SQFS_XZ_DEFAULT_LEVEL;
+ cfg->opt.xz.dict_size = block_size;
+ cfg->opt.xz.lc = SQFS_XZ_DEFAULT_LC;
+ cfg->opt.xz.lp = SQFS_XZ_DEFAULT_LP;
+ cfg->opt.xz.pb = SQFS_XZ_DEFAULT_PB;
+
+ if (block_size < SQFS_XZ_MIN_DICT_SIZE)
+ cfg->opt.xz.dict_size = SQFS_XZ_MIN_DICT_SIZE;
+ break;
+ case SQFS_COMP_LZMA:
+ flag_mask |= SQFS_COMP_FLAG_LZMA_ALL;
+ cfg->level = SQFS_LZMA_DEFAULT_LEVEL;
+ cfg->opt.lzma.dict_size = block_size;
+ cfg->opt.lzma.lc = SQFS_LZMA_DEFAULT_LC;
+ cfg->opt.lzma.lp = SQFS_LZMA_DEFAULT_LP;
+ cfg->opt.lzma.pb = SQFS_LZMA_DEFAULT_PB;
+
+ if (block_size < SQFS_LZMA_MIN_DICT_SIZE)
+ cfg->opt.lzma.dict_size = SQFS_LZMA_MIN_DICT_SIZE;
+ break;
+ case SQFS_COMP_LZ4:
+ flag_mask |= SQFS_COMP_FLAG_LZ4_ALL;
+ break;
+ default:
+ return SQFS_ERROR_UNSUPPORTED;
+ }
+
+ if (flags & ~flag_mask) {
+ memset(cfg, 0, sizeof(*cfg));
+ return SQFS_ERROR_UNSUPPORTED;
+ }
+
+ cfg->id = id;
+ cfg->flags = flags;
+ cfg->block_size = block_size;
+ return 0;
+}