1 ///////////////////////////////////////////////////////////////////////////////
4 /// \brief Parser for filter-specific options
6 // Author: Lasse Collin
8 // This file has been put into the public domain.
9 // You can do whatever you want with this file.
11 ///////////////////////////////////////////////////////////////////////////////
28 const name_id_map *map;
34 /// Parses option=value pairs that are separated with colons, semicolons,
35 /// or commas: opt=val:opt=val;opt=val,opt=val
37 /// Each option is a string, that is converted to an integer using the
38 /// index where the option string is in the array.
41 /// - a string-id map mapping a list of possible string values to integers
42 /// (opts[i].map != NULL, opts[i].min and opts[i].max are ignored);
43 /// - a number with minimum and maximum value limit
44 /// (opts[i].map == NULL && opts[i].min != UINT64_MAX);
45 /// - a string that will be parsed by the filter-specific code
46 /// (opts[i].map == NULL && opts[i].min == UINT64_MAX, opts[i].max ignored)
48 /// When parsing both option and value succeed, a filter-specific function
49 /// is called, which should update the given value to filter-specific
50 /// options structure.
52 /// \param str String containing the options from the command line
53 /// \param opts Filter-specific option map
54 /// \param set Filter-specific function to update filter_options
55 /// \param filter_options Pointer to filter-specific options structure
57 /// \return Returns only if no errors occur.
60 parse_options(const char *str, const option_map *opts,
61 void (*set)(void *filter_options,
62 uint32_t key, uint64_t value, const char *valuestr),
65 if (str == NULL || str[0] == '\0')
68 char *s = xstrdup(str);
71 while (*name != '\0') {
77 char *split = strchr(name, ',');
81 char *value = strchr(name, '=');
85 if (value == NULL || value[0] == '\0')
86 message_fatal(_("%s: Options must be `name=value' "
87 "pairs separated with commas"), str);
89 // Look for the option name from the option map.
91 for (size_t i = 0; opts[i].name != NULL; ++i) {
92 if (strcmp(name, opts[i].name) != 0)
95 if (opts[i].map != NULL) {
96 // value is a string which we should map
99 for (j = 0; opts[i].map[j].name != NULL; ++j) {
100 if (strcmp(opts[i].map[j].name, value)
105 if (opts[i].map[j].name == NULL)
106 message_fatal(_("%s: Invalid option "
109 set(filter_options, i, opts[i].map[j].id,
112 } else if (opts[i].min == UINT64_MAX) {
113 // value is a special string that will be
115 set(filter_options, i, 0, value);
118 // value is an integer.
119 const uint64_t v = str_to_uint64(name, value,
120 opts[i].min, opts[i].max);
121 set(filter_options, i, v, value);
129 message_fatal(_("%s: Invalid option name"), name);
154 set_subblock(void *options, uint32_t key, uint64_t value,
155 const char *valuestr lzma_attribute((unused)))
157 lzma_options_subblock *opt = options;
161 opt->subblock_data_size = value;
169 opt->alignment = value;
175 extern lzma_options_subblock *
176 options_subblock(const char *str)
178 static const option_map opts[] = {
179 { "size", NULL, LZMA_SUBBLOCK_DATA_SIZE_MIN,
180 LZMA_SUBBLOCK_DATA_SIZE_MAX },
181 { "rle", NULL, LZMA_SUBBLOCK_RLE_OFF,
182 LZMA_SUBBLOCK_RLE_MAX },
183 { "align",NULL, LZMA_SUBBLOCK_ALIGNMENT_MIN,
184 LZMA_SUBBLOCK_ALIGNMENT_MAX },
188 lzma_options_subblock *options
189 = xmalloc(sizeof(lzma_options_subblock));
190 *options = (lzma_options_subblock){
191 .allow_subfilters = false,
192 .alignment = LZMA_SUBBLOCK_ALIGNMENT_DEFAULT,
193 .subblock_data_size = LZMA_SUBBLOCK_DATA_SIZE_DEFAULT,
194 .rle = LZMA_SUBBLOCK_RLE_OFF,
197 parse_options(str, opts, &set_subblock, options);
213 set_delta(void *options, uint32_t key, uint64_t value,
214 const char *valuestr lzma_attribute((unused)))
216 lzma_options_delta *opt = options;
225 extern lzma_options_delta *
226 options_delta(const char *str)
228 static const option_map opts[] = {
229 { "dist", NULL, LZMA_DELTA_DIST_MIN,
230 LZMA_DELTA_DIST_MAX },
234 lzma_options_delta *options = xmalloc(sizeof(lzma_options_delta));
235 *options = (lzma_options_delta){
236 // It's hard to give a useful default for this.
237 .type = LZMA_DELTA_TYPE_BYTE,
238 .dist = LZMA_DELTA_DIST_MIN,
241 parse_options(str, opts, &set_delta, options);
257 set_bcj(void *options, uint32_t key, uint64_t value,
258 const char *valuestr lzma_attribute((unused)))
260 lzma_options_bcj *opt = options;
262 case OPT_START_OFFSET:
263 opt->start_offset = value;
269 extern lzma_options_bcj *
270 options_bcj(const char *str)
272 static const option_map opts[] = {
273 { "start", NULL, 0, UINT32_MAX },
277 lzma_options_bcj *options = xmalloc(sizeof(lzma_options_bcj));
278 *options = (lzma_options_bcj){
282 parse_options(str, opts, &set_bcj, options);
305 static void lzma_attribute((noreturn))
306 error_lzma_preset(const char *valuestr)
308 message_fatal(_("Unsupported LZMA1/LZMA2 preset: %s"), valuestr);
313 set_lzma(void *options, uint32_t key, uint64_t value, const char *valuestr)
315 lzma_options_lzma *opt = options;
319 if (valuestr[0] < '0' || valuestr[0] > '9')
320 error_lzma_preset(valuestr);
322 uint32_t preset = valuestr[0] - '0';
324 // Currently only "e" is supported as a modifier,
325 // so keep this simple for now.
326 if (valuestr[1] != '\0') {
327 if (valuestr[1] == 'e')
328 preset |= LZMA_PRESET_EXTREME;
330 error_lzma_preset(valuestr);
332 if (valuestr[2] != '\0')
333 error_lzma_preset(valuestr);
336 if (lzma_lzma_preset(options, preset))
337 error_lzma_preset(valuestr);
343 opt->dict_size = value;
363 opt->nice_len = value;
377 extern lzma_options_lzma *
378 options_lzma(const char *str)
380 static const name_id_map modes[] = {
381 { "fast", LZMA_MODE_FAST },
382 { "normal", LZMA_MODE_NORMAL },
386 static const name_id_map mfs[] = {
387 { "hc3", LZMA_MF_HC3 },
388 { "hc4", LZMA_MF_HC4 },
389 { "bt2", LZMA_MF_BT2 },
390 { "bt3", LZMA_MF_BT3 },
391 { "bt4", LZMA_MF_BT4 },
395 static const option_map opts[] = {
396 { "preset", NULL, UINT64_MAX, 0 },
397 { "dict", NULL, LZMA_DICT_SIZE_MIN,
398 (UINT32_C(1) << 30) + (UINT32_C(1) << 29) },
399 { "lc", NULL, LZMA_LCLP_MIN, LZMA_LCLP_MAX },
400 { "lp", NULL, LZMA_LCLP_MIN, LZMA_LCLP_MAX },
401 { "pb", NULL, LZMA_PB_MIN, LZMA_PB_MAX },
402 { "mode", modes, 0, 0 },
403 { "nice", NULL, 2, 273 },
405 { "depth", NULL, 0, UINT32_MAX },
409 lzma_options_lzma *options = xmalloc(sizeof(lzma_options_lzma));
410 *options = (lzma_options_lzma){
411 .dict_size = LZMA_DICT_SIZE_DEFAULT,
413 .preset_dict_size = 0,
414 .lc = LZMA_LC_DEFAULT,
415 .lp = LZMA_LP_DEFAULT,
416 .pb = LZMA_PB_DEFAULT,
418 .mode = LZMA_MODE_NORMAL,
424 parse_options(str, opts, &set_lzma, options);
426 if (options->lc + options->lp > LZMA_LCLP_MAX)
427 message_fatal(_("The sum of lc and lp must be at "
430 const uint32_t nice_len_min = options->mf & 0x0F;
431 if (options->nice_len < nice_len_min)
432 message_fatal(_("The selected match finder requires at "
433 "least nice=%" PRIu32), nice_len_min);