/* SPDX-License-Identifier: LGPL-3.0-or-later */ /* * lz4.c * * Copyright (C) 2019 David Oberhollenzer */ #define SQFS_BUILDING_DLL #include "config.h" #include #include #include #include #include #include "internal.h" typedef struct { sqfs_compressor_t base; bool high_compression; } lz4_compressor_t; typedef struct { uint32_t version; uint32_t flags; } lz4_options; #define LZ4LEGACY 1 static int lz4_write_options(sqfs_compressor_t *base, sqfs_file_t *file) { lz4_compressor_t *lz4 = (lz4_compressor_t *)base; lz4_options opt = { .version = htole32(LZ4LEGACY), .flags = htole32(lz4->high_compression ? SQFS_COMP_FLAG_LZ4_HC : 0), }; return sqfs_generic_write_options(file, &opt, sizeof(opt)); } static int lz4_read_options(sqfs_compressor_t *base, sqfs_file_t *file) { lz4_options opt; int ret; (void)base; ret = sqfs_generic_read_options(file, &opt, sizeof(opt)); if (ret) return ret; opt.version = le32toh(opt.version); opt.flags = le32toh(opt.flags); if (opt.version != LZ4LEGACY) return SQFS_ERROR_UNSUPPORTED; return 0; } static ssize_t lz4_comp_block(sqfs_compressor_t *base, const uint8_t *in, size_t size, uint8_t *out, size_t outsize) { lz4_compressor_t *lz4 = (lz4_compressor_t *)base; int ret; if (lz4->high_compression) { ret = LZ4_compress_HC((void *)in, (void *)out, size, outsize, LZ4HC_CLEVEL_MAX); } else { ret = LZ4_compress_default((void *)in, (void *)out, size, outsize); } if (ret < 0) return SQFS_ERROR_COMRPESSOR; return ret; } static ssize_t lz4_uncomp_block(sqfs_compressor_t *base, const uint8_t *in, size_t size, uint8_t *out, size_t outsize) { int ret; (void)base; ret = LZ4_decompress_safe((void *)in, (void *)out, size, outsize); if (ret < 0) return SQFS_ERROR_COMRPESSOR; return ret; } static sqfs_compressor_t *lz4_create_copy(sqfs_compressor_t *cmp) { lz4_compressor_t *lz4 = malloc(sizeof(*lz4)); if (lz4 == NULL) return NULL; memcpy(lz4, cmp, sizeof(*lz4)); return (sqfs_compressor_t *)lz4; } static void lz4_destroy(sqfs_compressor_t *base) { free(base); } sqfs_compressor_t *lz4_compressor_create(const sqfs_compressor_config_t *cfg) { sqfs_compressor_t *base; lz4_compressor_t *lz4; if (cfg->flags & ~(SQFS_COMP_FLAG_LZ4_ALL | SQFS_COMP_FLAG_GENERIC_ALL)) { return NULL; } lz4 = calloc(1, sizeof(*lz4)); base = (sqfs_compressor_t *)lz4; if (lz4 == NULL) return NULL; lz4->high_compression = (cfg->flags & SQFS_COMP_FLAG_LZ4_HC) != 0; base->destroy = lz4_destroy; base->do_block = (cfg->flags & SQFS_COMP_FLAG_UNCOMPRESS) ? lz4_uncomp_block : lz4_comp_block; base->write_options = lz4_write_options; base->read_options = lz4_read_options; base->create_copy = lz4_create_copy; return base; }