diff options
-rw-r--r-- | lib/common/comp_opt.c | 243 |
1 files changed, 89 insertions, 154 deletions
diff --git a/lib/common/comp_opt.c b/lib/common/comp_opt.c index 5be4466..f77ac20 100644 --- a/lib/common/comp_opt.c +++ b/lib/common/comp_opt.c @@ -42,6 +42,16 @@ static const flag_t lz4_flags[] = { { "hc", SQFS_COMP_FLAG_LZ4_HC }, }; +static const struct { + const flag_t *flags; + size_t count; +} comp_flags[SQFS_COMP_MAX + 1] = { + [SQFS_COMP_GZIP] = { gzip_flags, sizeof(gzip_flags) / sizeof(flag_t) }, + [SQFS_COMP_XZ] = { xz_flags, sizeof(xz_flags) / sizeof(flag_t) }, + [SQFS_COMP_LZMA] = { lzma_flags, sizeof(lzma_flags) / sizeof(flag_t) }, + [SQFS_COMP_LZ4] = { lz4_flags, sizeof(lz4_flags) / sizeof(flag_t) }, +}; + static const char *lzo_algs[] = { [SQFS_LZO1X_1] = "lzo1x_1", [SQFS_LZO1X_1_11] = "lzo1x_1_11", @@ -50,10 +60,10 @@ static const char *lzo_algs[] = { [SQFS_LZO1X_999] = "lzo1x_999", }; -static int set_flag(sqfs_compressor_config_t *cfg, const char *name, - const flag_t *flags, size_t num_flags) +static int set_flag(sqfs_compressor_config_t *cfg, const char *name) { - size_t i; + const flag_t *flags = comp_flags[cfg->id].flags; + size_t i, num_flags = comp_flags[cfg->id].count; for (i = 0; i < num_flags; ++i) { if (strcmp(flags[i].name, name) == 0) { @@ -87,6 +97,7 @@ enum { OPT_LC, OPT_LP, OPT_PB, + OPT_COUNT, }; static char *const token[] = { [OPT_WINDOW] = (char *)"window", @@ -99,14 +110,54 @@ static char *const token[] = { NULL }; +static int opt_available[SQFS_COMP_MAX + 1] = { + [SQFS_COMP_GZIP] = (1 << OPT_WINDOW) | (1 << OPT_LEVEL), + [SQFS_COMP_XZ] = (1 << OPT_LEVEL) | (1 << OPT_DICT) | (1 << OPT_LC) | + (1 << OPT_LP) | (1 << OPT_PB), + [SQFS_COMP_LZMA] = (1 << OPT_LEVEL) | (1 << OPT_DICT) | (1 << OPT_LC) | + (1 << OPT_LP) | (1 << OPT_PB), + [SQFS_COMP_ZSTD] = (1 << OPT_LEVEL), + [SQFS_COMP_LZO] = (1 << OPT_LEVEL) | (1 << OPT_ALG), +}; + +static const struct { + int min; + int max; +} value_range[SQFS_COMP_MAX + 1][OPT_COUNT] = { + [SQFS_COMP_GZIP] = { + [OPT_LEVEL] = { SQFS_GZIP_MIN_LEVEL, SQFS_GZIP_MAX_LEVEL }, + [OPT_WINDOW] = { SQFS_GZIP_MIN_WINDOW, SQFS_GZIP_MAX_WINDOW }, + }, + [SQFS_COMP_XZ] = { + [OPT_LEVEL] = { SQFS_XZ_MIN_LEVEL, SQFS_XZ_MAX_LEVEL }, + [OPT_DICT] = { SQFS_XZ_MIN_DICT_SIZE, SQFS_XZ_MAX_DICT_SIZE }, + [OPT_LC] = { SQFS_XZ_MIN_LC, SQFS_XZ_MAX_LC }, + [OPT_LP] = { SQFS_XZ_MIN_LP, SQFS_XZ_MAX_LP }, + [OPT_PB] = { SQFS_XZ_MIN_PB, SQFS_XZ_MAX_PB }, + }, + [SQFS_COMP_LZMA] = { + [OPT_LEVEL] = { SQFS_LZMA_MIN_LEVEL, SQFS_LZMA_MAX_LEVEL }, + [OPT_DICT] = { SQFS_LZMA_MIN_DICT_SIZE, + SQFS_LZMA_MAX_DICT_SIZE }, + [OPT_LC] = { SQFS_LZMA_MIN_LC, SQFS_LZMA_MAX_LC }, + [OPT_LP] = { SQFS_LZMA_MIN_LP, SQFS_LZMA_MAX_LP }, + [OPT_PB] = { SQFS_LZMA_MIN_PB, SQFS_LZMA_MAX_PB }, + }, + [SQFS_COMP_ZSTD] = { + [OPT_LEVEL] = { SQFS_ZSTD_MIN_LEVEL, SQFS_ZSTD_MAX_LEVEL }, + }, + [SQFS_COMP_LZO] = { + [OPT_LEVEL] = { SQFS_LZO_MIN_LEVEL, SQFS_LZO_MAX_LEVEL }, + }, +}; + int compressor_cfg_init_options(sqfs_compressor_config_t *cfg, SQFS_COMPRESSOR id, size_t block_size, char *options) { - size_t num_flags = 0, min_level = 0, max_level = 0, level, dict_size; - const flag_t *flags = NULL; char *subopts, *value; - int i, opt; + int opt, ival; + size_t szval; if (sqfs_compressor_config_init(cfg, id, block_size, 0)) return -1; @@ -114,151 +165,51 @@ int compressor_cfg_init_options(sqfs_compressor_config_t *cfg, if (options == NULL) return 0; - switch (cfg->id) { - case SQFS_COMP_GZIP: - min_level = SQFS_GZIP_MIN_LEVEL; - max_level = SQFS_GZIP_MAX_LEVEL; - flags = gzip_flags; - num_flags = sizeof(gzip_flags) / sizeof(gzip_flags[0]); - break; - case SQFS_COMP_LZO: - min_level = SQFS_LZO_MIN_LEVEL; - max_level = SQFS_LZO_MAX_LEVEL; - break; - case SQFS_COMP_ZSTD: - min_level = SQFS_ZSTD_MIN_LEVEL; - max_level = SQFS_ZSTD_MAX_LEVEL; - break; - case SQFS_COMP_XZ: - min_level = SQFS_XZ_MIN_LEVEL; - max_level = SQFS_XZ_MAX_LEVEL; - flags = xz_flags; - num_flags = sizeof(xz_flags) / sizeof(xz_flags[0]); - break; - case SQFS_COMP_LZMA: - min_level = SQFS_LZMA_MIN_LEVEL; - max_level = SQFS_LZMA_MAX_LEVEL; - flags = lzma_flags; - num_flags = sizeof(lzma_flags) / sizeof(lzma_flags[0]); - break; - case SQFS_COMP_LZ4: - flags = lz4_flags; - num_flags = sizeof(lz4_flags) / sizeof(lz4_flags[0]); - break; - default: - break; - } - subopts = options; while (*subopts != '\0') { opt = getsubopt(&subopts, token, &value); - switch (opt) { - case OPT_WINDOW: - if (cfg->id != SQFS_COMP_GZIP) + if (opt < 0) { + if (set_flag(cfg, value)) goto fail_opt; + continue; + } - if (value == NULL) - goto fail_value; - - for (i = 0; isdigit(value[i]); ++i) - ; - - if (i < 1 || i > 3 || value[i] != '\0') - goto fail_window; - - cfg->opt.gzip.window_size = atoi(value); - - if (cfg->opt.gzip.window_size < SQFS_GZIP_MIN_WINDOW || - cfg->opt.gzip.window_size > SQFS_GZIP_MAX_WINDOW) - goto fail_window; - break; - case OPT_LEVEL: - if (value == NULL) - goto fail_value; - - for (i = 0; isdigit(value[i]) && i < 3; ++i) - ; - - if (i < 1 || i > 3 || value[i] != '\0') - goto fail_level; - - level = atoi(value); - if (level < min_level || level > max_level) - goto fail_level; + if (!(opt_available[cfg->id] & (1 << opt))) + goto fail_opt; - cfg->level = level; - break; - case OPT_ALG: - if (cfg->id != SQFS_COMP_LZO) - goto fail_opt; - - if (value == NULL) - goto fail_value; + if (value == NULL) + goto fail_value; + if (opt == OPT_ALG) { if (find_lzo_alg(cfg, value)) goto fail_lzo_alg; - break; - case OPT_DICT: - if (cfg->id != SQFS_COMP_XZ && - cfg->id != SQFS_COMP_LZMA) { - goto fail_opt; - } - - if (value == NULL) - goto fail_value; + continue; + } + if (opt == OPT_DICT) { if (parse_size("Parsing LZMA dictionary size", - &dict_size, value, cfg->block_size)) { + &szval, value, cfg->block_size)) { return -1; } + ival = szval; + } else { + ival = strtol(value, NULL, 10); + } - cfg->opt.xz.dict_size = dict_size; - break; - case OPT_LC: - if (cfg->id != SQFS_COMP_XZ && - cfg->id != SQFS_COMP_LZMA) { - goto fail_opt; - } - - if (value == NULL) - goto fail_value; - - cfg->opt.xz.lc = strtol(value, NULL, 10); - if (cfg->opt.xz.lc > SQFS_XZ_MAX_LC) - goto fail_lc; - break; - case OPT_LP: - if (cfg->id != SQFS_COMP_XZ && - cfg->id != SQFS_COMP_LZMA) { - goto fail_opt; - } - - if (value == NULL) - goto fail_value; - - cfg->opt.xz.lp = strtol(value, NULL, 10); - if (cfg->opt.xz.lp > SQFS_XZ_MAX_LP) - goto fail_lp; - break; - case OPT_PB: - if (cfg->id != SQFS_COMP_XZ && - cfg->id != SQFS_COMP_LZMA) { - goto fail_opt; - } - - if (value == NULL) - goto fail_value; + if (ival < value_range[cfg->id][opt].min) + goto fail_range; + if (ival > value_range[cfg->id][opt].max) + goto fail_range; - cfg->opt.xz.pb = strtol(value, NULL, 10); - if (cfg->opt.xz.lp > SQFS_XZ_MAX_PB) - goto fail_pb; - break; - default: - if (set_flag(cfg, value, flags, num_flags)) - goto fail_opt; - break; + switch (opt) { + case OPT_LEVEL: cfg->level = ival; break; + case OPT_LC: cfg->opt.xz.lc = ival; break; + case OPT_LP: cfg->opt.xz.lp = ival; break; + case OPT_PB: cfg->opt.xz.pb = ival; break; + case OPT_WINDOW: cfg->opt.gzip.window_size = ival; break; + case OPT_DICT: cfg->opt.xz.dict_size = ival; break; } } @@ -271,29 +222,13 @@ int compressor_cfg_init_options(sqfs_compressor_config_t *cfg, fail_sum_lp_lc: fputs("Sum of XZ lc + lp must not exceed 4.\n", stderr); return -1; -fail_lp: - fprintf(stderr, - "XZ literal position bits (lp) must be between %d and %d.\n", - SQFS_XZ_MIN_LP, SQFS_XZ_MAX_LP); - return -1; -fail_lc: - fprintf(stderr, "XZ literal context (lc) must be between %d and %d.\n", - SQFS_XZ_MIN_LC, SQFS_XZ_MAX_LC); - return -1; -fail_pb: - fprintf(stderr, "XZ position bits (bp) must be between %d and %d.\n", - SQFS_XZ_MIN_PB, SQFS_XZ_MAX_PB); - return -1; fail_lzo_alg: fprintf(stderr, "Unknown lzo variant '%s'.\n", value); return -1; -fail_window: - fputs("Window size must be a number between 8 and 15.\n", stderr); - return -1; -fail_level: - fprintf(stderr, - "Compression level must be a number between " PRI_SZ " and " - PRI_SZ ".\n", min_level, max_level); +fail_range: + fprintf(stderr, "`%s` must be a number between %d and %d.\n", + token[opt], value_range[cfg->id][opt].min, + value_range[cfg->id][opt].max); return -1; fail_opt: fprintf(stderr, "Unknown compressor option '%s'.\n", value); |