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.
40 /// Value can be either a number with minimum and maximum value limit, or
41 /// a string-id map mapping a list of possible string values to integers.
43 /// When parsing both option and value succeed, a filter-specific function
44 /// is called, which should update the given value to filter-specific
45 /// options structure.
47 /// \param str String containing the options from the command line
48 /// \param opts Filter-specific option map
49 /// \param set Filter-specific function to update filter_options
50 /// \param filter_options Pointer to filter-specific options structure
52 /// \return Returns only if no errors occur.
55 parse_options(const char *str, const option_map *opts,
56 void (*set)(void *filter_options,
57 uint32_t key, uint64_t value),
60 if (str == NULL || str[0] == '\0')
63 char *s = xstrdup(str);
67 char *split = strchr(name, ',');
71 char *value = strchr(name, '=');
75 if (value == NULL || value[0] == '\0')
76 message_fatal(_("%s: Options must be `name=value' "
77 "pairs separated with commas"), str);
79 // Look for the option name from the option map.
81 for (size_t i = 0; opts[i].name != NULL; ++i) {
82 if (strcmp(name, opts[i].name) != 0)
85 if (opts[i].map == NULL) {
86 // value is an integer.
87 const uint64_t v = str_to_uint64(name, value,
88 opts[i].min, opts[i].max);
89 set(filter_options, i, v);
91 // value is a string which we should map
94 for (j = 0; opts[i].map[j].name != NULL; ++j) {
95 if (strcmp(opts[i].map[j].name, value)
100 if (opts[i].map[j].name == NULL)
101 message_fatal(_("%s: Invalid option "
104 set(filter_options, i, opts[i].map[j].id);
112 message_fatal(_("%s: Invalid option name"), name);
137 set_subblock(void *options, uint32_t key, uint64_t value)
139 lzma_options_subblock *opt = options;
143 opt->subblock_data_size = value;
151 opt->alignment = value;
157 extern lzma_options_subblock *
158 options_subblock(const char *str)
160 static const option_map opts[] = {
161 { "size", NULL, LZMA_SUBBLOCK_DATA_SIZE_MIN,
162 LZMA_SUBBLOCK_DATA_SIZE_MAX },
163 { "rle", NULL, LZMA_SUBBLOCK_RLE_OFF,
164 LZMA_SUBBLOCK_RLE_MAX },
165 { "align",NULL, LZMA_SUBBLOCK_ALIGNMENT_MIN,
166 LZMA_SUBBLOCK_ALIGNMENT_MAX },
170 lzma_options_subblock *options
171 = xmalloc(sizeof(lzma_options_subblock));
172 *options = (lzma_options_subblock){
173 .allow_subfilters = false,
174 .alignment = LZMA_SUBBLOCK_ALIGNMENT_DEFAULT,
175 .subblock_data_size = LZMA_SUBBLOCK_DATA_SIZE_DEFAULT,
176 .rle = LZMA_SUBBLOCK_RLE_OFF,
179 parse_options(str, opts, &set_subblock, options);
195 set_delta(void *options, uint32_t key, uint64_t value)
197 lzma_options_delta *opt = options;
206 extern lzma_options_delta *
207 options_delta(const char *str)
209 static const option_map opts[] = {
210 { "dist", NULL, LZMA_DELTA_DIST_MIN,
211 LZMA_DELTA_DIST_MAX },
215 lzma_options_delta *options = xmalloc(sizeof(lzma_options_delta));
216 *options = (lzma_options_delta){
217 // It's hard to give a useful default for this.
218 .type = LZMA_DELTA_TYPE_BYTE,
219 .dist = LZMA_DELTA_DIST_MIN,
222 parse_options(str, opts, &set_delta, options);
238 set_bcj(void *options, uint32_t key, uint64_t value)
240 lzma_options_bcj *opt = options;
242 case OPT_START_OFFSET:
243 opt->start_offset = value;
249 extern lzma_options_bcj *
250 options_bcj(const char *str)
252 static const option_map opts[] = {
253 { "start", NULL, 0, UINT32_MAX },
257 lzma_options_bcj *options = xmalloc(sizeof(lzma_options_bcj));
258 *options = (lzma_options_bcj){
262 parse_options(str, opts, &set_bcj, options);
286 set_lzma(void *options, uint32_t key, uint64_t value)
288 lzma_options_lzma *opt = options;
292 if (lzma_lzma_preset(options, (uint32_t)(value)))
293 message_fatal("LZMA1/LZMA2 preset %u is not supported",
294 (unsigned int)(value));
298 opt->dict_size = value;
318 opt->nice_len = value;
332 extern lzma_options_lzma *
333 options_lzma(const char *str)
335 static const name_id_map modes[] = {
336 { "fast", LZMA_MODE_FAST },
337 { "normal", LZMA_MODE_NORMAL },
341 static const name_id_map mfs[] = {
342 { "hc3", LZMA_MF_HC3 },
343 { "hc4", LZMA_MF_HC4 },
344 { "bt2", LZMA_MF_BT2 },
345 { "bt3", LZMA_MF_BT3 },
346 { "bt4", LZMA_MF_BT4 },
350 static const option_map opts[] = {
351 { "preset", NULL, 0, 9 },
352 { "dict", NULL, LZMA_DICT_SIZE_MIN,
353 (UINT32_C(1) << 30) + (UINT32_C(1) << 29) },
354 { "lc", NULL, LZMA_LCLP_MIN, LZMA_LCLP_MAX },
355 { "lp", NULL, LZMA_LCLP_MIN, LZMA_LCLP_MAX },
356 { "pb", NULL, LZMA_PB_MIN, LZMA_PB_MAX },
357 { "mode", modes, 0, 0 },
358 { "nice", NULL, 2, 273 },
360 { "depth", NULL, 0, UINT32_MAX },
364 // TODO There should be a way to take some preset as the base for
366 lzma_options_lzma *options = xmalloc(sizeof(lzma_options_lzma));
367 *options = (lzma_options_lzma){
368 .dict_size = LZMA_DICT_SIZE_DEFAULT,
370 .preset_dict_size = 0,
371 .lc = LZMA_LC_DEFAULT,
372 .lp = LZMA_LP_DEFAULT,
373 .pb = LZMA_PB_DEFAULT,
375 .mode = LZMA_MODE_NORMAL,
381 parse_options(str, opts, &set_lzma, options);
383 if (options->lc + options->lp > LZMA_LCLP_MAX)
384 message_fatal(_("The sum of lc and lp must be at "
387 const uint32_t nice_len_min = options->mf & 0x0F;
388 if (options->nice_len < nice_len_min)
389 message_fatal(_("The selected match finder requires at "
390 "least nice=%" PRIu32), nice_len_min);