string_conversion.c 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330
  1. // SPDX-License-Identifier: 0BSD
  2. ///////////////////////////////////////////////////////////////////////////////
  3. //
  4. /// \file string_conversion.c
  5. /// \brief Conversion of strings to filter chain and vice versa
  6. //
  7. // Author: Lasse Collin
  8. //
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include "filter_common.h"
  11. /////////////////////
  12. // String building //
  13. /////////////////////
  14. /// How much memory to allocate for strings. For now, no realloc is used
  15. /// so this needs to be big enough even though there of course is
  16. /// an overflow check still.
  17. ///
  18. /// FIXME? Using a fixed size is wasteful if the application doesn't free
  19. /// the string fairly quickly but this can be improved later if needed.
  20. #define STR_ALLOC_SIZE 800
  21. typedef struct {
  22. char *buf;
  23. size_t pos;
  24. } lzma_str;
  25. static lzma_ret
  26. str_init(lzma_str *str, const lzma_allocator *allocator)
  27. {
  28. str->buf = lzma_alloc(STR_ALLOC_SIZE, allocator);
  29. if (str->buf == NULL)
  30. return LZMA_MEM_ERROR;
  31. str->pos = 0;
  32. return LZMA_OK;
  33. }
  34. static void
  35. str_free(lzma_str *str, const lzma_allocator *allocator)
  36. {
  37. lzma_free(str->buf, allocator);
  38. return;
  39. }
  40. static bool
  41. str_is_full(const lzma_str *str)
  42. {
  43. return str->pos == STR_ALLOC_SIZE - 1;
  44. }
  45. static lzma_ret
  46. str_finish(char **dest, lzma_str *str, const lzma_allocator *allocator)
  47. {
  48. if (str_is_full(str)) {
  49. // The preallocated buffer was too small.
  50. // This shouldn't happen as STR_ALLOC_SIZE should
  51. // be adjusted if new filters are added.
  52. lzma_free(str->buf, allocator);
  53. *dest = NULL;
  54. assert(0);
  55. return LZMA_PROG_ERROR;
  56. }
  57. str->buf[str->pos] = '\0';
  58. *dest = str->buf;
  59. return LZMA_OK;
  60. }
  61. static void
  62. str_append_str(lzma_str *str, const char *s)
  63. {
  64. const size_t len = strlen(s);
  65. const size_t limit = STR_ALLOC_SIZE - 1 - str->pos;
  66. const size_t copy_size = my_min(len, limit);
  67. memcpy(str->buf + str->pos, s, copy_size);
  68. str->pos += copy_size;
  69. return;
  70. }
  71. static void
  72. str_append_u32(lzma_str *str, uint32_t v, bool use_byte_suffix)
  73. {
  74. if (v == 0) {
  75. str_append_str(str, "0");
  76. } else {
  77. // NOTE: Don't use plain "B" because xz and the parser in this
  78. // file don't support it and at glance it may look like 8
  79. // (there cannot be a space before the suffix).
  80. static const char suffixes[4][4] = { "", "KiB", "MiB", "GiB" };
  81. size_t suf = 0;
  82. if (use_byte_suffix) {
  83. while ((v & 1023) == 0
  84. && suf < ARRAY_SIZE(suffixes) - 1) {
  85. v >>= 10;
  86. ++suf;
  87. }
  88. }
  89. // UINT32_MAX in base 10 would need 10 + 1 bytes. Remember
  90. // that initializing to "" initializes all elements to
  91. // zero so '\0'-termination gets handled by this.
  92. char buf[16] = "";
  93. size_t pos = sizeof(buf) - 1;
  94. do {
  95. buf[--pos] = '0' + (v % 10);
  96. v /= 10;
  97. } while (v != 0);
  98. str_append_str(str, buf + pos);
  99. str_append_str(str, suffixes[suf]);
  100. }
  101. return;
  102. }
  103. //////////////////////////////////////////////
  104. // Parsing and stringification declarations //
  105. //////////////////////////////////////////////
  106. /// Maximum length for filter and option names.
  107. /// 11 chars + terminating '\0' + sizeof(uint32_t) = 16 bytes
  108. #define NAME_LEN_MAX 11
  109. /// For option_map.flags: Use .u.map to do convert the input value
  110. /// to an integer. Without this flag, .u.range.{min,max} are used
  111. /// as the allowed range for the integer.
  112. #define OPTMAP_USE_NAME_VALUE_MAP 0x01
  113. /// For option_map.flags: Allow KiB/MiB/GiB in input string and use them in
  114. /// the stringified output if the value is an exact multiple of these.
  115. /// This is used e.g. for LZMA1/2 dictionary size.
  116. #define OPTMAP_USE_BYTE_SUFFIX 0x02
  117. /// For option_map.flags: If the integer value is zero then this option
  118. /// won't be included in the stringified output. It's used e.g. for
  119. /// BCJ filter start offset which usually is zero.
  120. #define OPTMAP_NO_STRFY_ZERO 0x04
  121. /// Possible values for option_map.type. Since OPTMAP_TYPE_UINT32 is 0,
  122. /// it doesn't need to be specified in the initializers as it is
  123. /// the implicit value.
  124. enum {
  125. OPTMAP_TYPE_UINT32,
  126. OPTMAP_TYPE_LZMA_MODE,
  127. OPTMAP_TYPE_LZMA_MATCH_FINDER,
  128. OPTMAP_TYPE_LZMA_PRESET,
  129. };
  130. /// This is for mapping string values in options to integers.
  131. /// The last element of an array must have "" as the name.
  132. /// It's used e.g. for match finder names in LZMA1/2.
  133. typedef struct {
  134. const char name[NAME_LEN_MAX + 1];
  135. const uint32_t value;
  136. } name_value_map;
  137. /// Each filter that has options needs an array of option_map structures.
  138. /// The array doesn't need to be terminated as the functions take the
  139. /// length of the array as an argument.
  140. ///
  141. /// When converting a string to filter options structure, option values
  142. /// will be handled in a few different ways:
  143. ///
  144. /// (1) If .type equals OPTMAP_TYPE_LZMA_PRESET then LZMA1/2 preset string
  145. /// is handled specially.
  146. ///
  147. /// (2) If .flags has OPTMAP_USE_NAME_VALUE_MAP set then the string is
  148. /// converted to an integer using the name_value_map pointed by .u.map.
  149. /// The last element in .u.map must have .name = "" as the terminator.
  150. ///
  151. /// (3) Otherwise the string is treated as a non-negative unsigned decimal
  152. /// integer which must be in the range set in .u.range. If .flags has
  153. /// OPTMAP_USE_BYTE_SUFFIX then KiB, MiB, and GiB suffixes are allowed.
  154. ///
  155. /// The integer value from (2) or (3) is then stored to filter_options
  156. /// at the offset specified in .offset using the type specified in .type
  157. /// (default is uint32_t).
  158. ///
  159. /// Stringifying a filter is done by processing a given number of options
  160. /// in order from the beginning of an option_map array. The integer is
  161. /// read from filter_options at .offset using the type from .type.
  162. ///
  163. /// If the integer is zero and .flags has OPTMAP_NO_STRFY_ZERO then the
  164. /// option is skipped.
  165. ///
  166. /// If .flags has OPTMAP_USE_NAME_VALUE_MAP set then .u.map will be used
  167. /// to convert the option to a string. If the map doesn't contain a string
  168. /// for the integer value then "UNKNOWN" is used.
  169. ///
  170. /// If .flags doesn't have OPTMAP_USE_NAME_VALUE_MAP set then the integer is
  171. /// converted to a decimal value. If OPTMAP_USE_BYTE_SUFFIX is used then KiB,
  172. /// MiB, or GiB suffix is used if the value is an exact multiple of these.
  173. /// Plain "B" suffix is never used.
  174. typedef struct {
  175. char name[NAME_LEN_MAX + 1];
  176. uint8_t type;
  177. uint8_t flags;
  178. uint16_t offset;
  179. union {
  180. struct {
  181. uint32_t min;
  182. uint32_t max;
  183. } range;
  184. const name_value_map *map;
  185. } u;
  186. } option_map;
  187. static const char *parse_options(const char **const str, const char *str_end,
  188. void *filter_options,
  189. const option_map *const optmap, const size_t optmap_size);
  190. /////////
  191. // BCJ //
  192. /////////
  193. #if defined(HAVE_ENCODER_X86) \
  194. || defined(HAVE_DECODER_X86) \
  195. || defined(HAVE_ENCODER_ARM) \
  196. || defined(HAVE_DECODER_ARM) \
  197. || defined(HAVE_ENCODER_ARMTHUMB) \
  198. || defined(HAVE_DECODER_ARMTHUMB) \
  199. || defined(HAVE_ENCODER_ARM64) \
  200. || defined(HAVE_DECODER_ARM64) \
  201. || defined(HAVE_ENCODER_POWERPC) \
  202. || defined(HAVE_DECODER_POWERPC) \
  203. || defined(HAVE_ENCODER_IA64) \
  204. || defined(HAVE_DECODER_IA64) \
  205. || defined(HAVE_ENCODER_SPARC) \
  206. || defined(HAVE_DECODER_SPARC) \
  207. || defined(HAVE_ENCODER_RISCV) \
  208. || defined(HAVE_DECODER_RISCV)
  209. static const option_map bcj_optmap[] = {
  210. {
  211. .name = "start",
  212. .flags = OPTMAP_NO_STRFY_ZERO | OPTMAP_USE_BYTE_SUFFIX,
  213. .offset = offsetof(lzma_options_bcj, start_offset),
  214. .u.range.min = 0,
  215. .u.range.max = UINT32_MAX,
  216. }
  217. };
  218. static const char *
  219. parse_bcj(const char **const str, const char *str_end, void *filter_options)
  220. {
  221. // filter_options was zeroed on allocation and that is enough
  222. // for the default value.
  223. return parse_options(str, str_end, filter_options,
  224. bcj_optmap, ARRAY_SIZE(bcj_optmap));
  225. }
  226. #endif
  227. ///////////
  228. // Delta //
  229. ///////////
  230. #if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
  231. static const option_map delta_optmap[] = {
  232. {
  233. .name = "dist",
  234. .offset = offsetof(lzma_options_delta, dist),
  235. .u.range.min = LZMA_DELTA_DIST_MIN,
  236. .u.range.max = LZMA_DELTA_DIST_MAX,
  237. }
  238. };
  239. static const char *
  240. parse_delta(const char **const str, const char *str_end, void *filter_options)
  241. {
  242. lzma_options_delta *opts = filter_options;
  243. opts->type = LZMA_DELTA_TYPE_BYTE;
  244. opts->dist = LZMA_DELTA_DIST_MIN;
  245. return parse_options(str, str_end, filter_options,
  246. delta_optmap, ARRAY_SIZE(delta_optmap));
  247. }
  248. #endif
  249. ///////////////////
  250. // LZMA1 & LZMA2 //
  251. ///////////////////
  252. /// Help string for presets
  253. #define LZMA12_PRESET_STR "0-9[e]"
  254. static const char *
  255. parse_lzma12_preset(const char **const str, const char *str_end,
  256. uint32_t *preset)
  257. {
  258. assert(*str < str_end);
  259. *preset = (uint32_t)(**str - '0');
  260. // NOTE: Remember to update LZMA12_PRESET_STR if this is modified!
  261. while (++*str < str_end) {
  262. switch (**str) {
  263. case 'e':
  264. *preset |= LZMA_PRESET_EXTREME;
  265. break;
  266. default:
  267. return "Unsupported preset flag";
  268. }
  269. }
  270. return NULL;
  271. }
  272. static const char *
  273. set_lzma12_preset(const char **const str, const char *str_end,
  274. void *filter_options)
  275. {
  276. uint32_t preset;
  277. const char *errmsg = parse_lzma12_preset(str, str_end, &preset);
  278. if (errmsg != NULL)
  279. return errmsg;
  280. lzma_options_lzma *opts = filter_options;
  281. if (lzma_lzma_preset(opts, preset))
  282. return "Unsupported preset";
  283. return NULL;
  284. }
  285. static const name_value_map lzma12_mode_map[] = {
  286. { "fast", LZMA_MODE_FAST },
  287. { "normal", LZMA_MODE_NORMAL },
  288. { "", 0 }
  289. };
  290. static const name_value_map lzma12_mf_map[] = {
  291. { "hc3", LZMA_MF_HC3 },
  292. { "hc4", LZMA_MF_HC4 },
  293. { "bt2", LZMA_MF_BT2 },
  294. { "bt3", LZMA_MF_BT3 },
  295. { "bt4", LZMA_MF_BT4 },
  296. { "", 0 }
  297. };
  298. static const option_map lzma12_optmap[] = {
  299. {
  300. .name = "preset",
  301. .type = OPTMAP_TYPE_LZMA_PRESET,
  302. }, {
  303. .name = "dict",
  304. .flags = OPTMAP_USE_BYTE_SUFFIX,
  305. .offset = offsetof(lzma_options_lzma, dict_size),
  306. .u.range.min = LZMA_DICT_SIZE_MIN,
  307. // FIXME? The max is really max for encoding but decoding
  308. // would allow 4 GiB - 1 B.
  309. .u.range.max = (UINT32_C(1) << 30) + (UINT32_C(1) << 29),
  310. }, {
  311. .name = "lc",
  312. .offset = offsetof(lzma_options_lzma, lc),
  313. .u.range.min = LZMA_LCLP_MIN,
  314. .u.range.max = LZMA_LCLP_MAX,
  315. }, {
  316. .name = "lp",
  317. .offset = offsetof(lzma_options_lzma, lp),
  318. .u.range.min = LZMA_LCLP_MIN,
  319. .u.range.max = LZMA_LCLP_MAX,
  320. }, {
  321. .name = "pb",
  322. .offset = offsetof(lzma_options_lzma, pb),
  323. .u.range.min = LZMA_PB_MIN,
  324. .u.range.max = LZMA_PB_MAX,
  325. }, {
  326. .name = "mode",
  327. .type = OPTMAP_TYPE_LZMA_MODE,
  328. .flags = OPTMAP_USE_NAME_VALUE_MAP,
  329. .offset = offsetof(lzma_options_lzma, mode),
  330. .u.map = lzma12_mode_map,
  331. }, {
  332. .name = "nice",
  333. .offset = offsetof(lzma_options_lzma, nice_len),
  334. .u.range.min = 2,
  335. .u.range.max = 273,
  336. }, {
  337. .name = "mf",
  338. .type = OPTMAP_TYPE_LZMA_MATCH_FINDER,
  339. .flags = OPTMAP_USE_NAME_VALUE_MAP,
  340. .offset = offsetof(lzma_options_lzma, mf),
  341. .u.map = lzma12_mf_map,
  342. }, {
  343. .name = "depth",
  344. .offset = offsetof(lzma_options_lzma, depth),
  345. .u.range.min = 0,
  346. .u.range.max = UINT32_MAX,
  347. }
  348. };
  349. static const char *
  350. parse_lzma12(const char **const str, const char *str_end, void *filter_options)
  351. {
  352. lzma_options_lzma *opts = filter_options;
  353. // It cannot fail.
  354. const bool preset_ret = lzma_lzma_preset(opts, LZMA_PRESET_DEFAULT);
  355. assert(!preset_ret);
  356. (void)preset_ret;
  357. const char *errmsg = parse_options(str, str_end, filter_options,
  358. lzma12_optmap, ARRAY_SIZE(lzma12_optmap));
  359. if (errmsg != NULL)
  360. return errmsg;
  361. if (opts->lc + opts->lp > LZMA_LCLP_MAX)
  362. return "The sum of lc and lp must not exceed 4";
  363. return NULL;
  364. }
  365. /////////////////////////////////////////
  366. // Generic parsing and stringification //
  367. /////////////////////////////////////////
  368. static const struct {
  369. /// Name of the filter
  370. char name[NAME_LEN_MAX + 1];
  371. /// For lzma_str_to_filters:
  372. /// Size of the filter-specific options structure.
  373. uint32_t opts_size;
  374. /// Filter ID
  375. lzma_vli id;
  376. /// For lzma_str_to_filters:
  377. /// Function to parse the filter-specific options. The filter_options
  378. /// will already have been allocated using lzma_alloc_zero().
  379. const char *(*parse)(const char **str, const char *str_end,
  380. void *filter_options);
  381. /// For lzma_str_from_filters:
  382. /// If the flag LZMA_STR_ENCODER is used then the first
  383. /// strfy_encoder elements of optmap are stringified.
  384. /// With LZMA_STR_DECODER strfy_decoder is used.
  385. /// Currently encoders use all options that decoders do but if
  386. /// that changes then this needs to be changed too, for example,
  387. /// add a new OPTMAP flag to skip printing some decoder-only options.
  388. const option_map *optmap;
  389. uint8_t strfy_encoder;
  390. uint8_t strfy_decoder;
  391. /// For lzma_str_from_filters:
  392. /// If true, lzma_filter.options is allowed to be NULL. In that case,
  393. /// only the filter name is printed without any options.
  394. bool allow_null;
  395. } filter_name_map[] = {
  396. #if defined (HAVE_ENCODER_LZMA1) || defined(HAVE_DECODER_LZMA1)
  397. { "lzma1", sizeof(lzma_options_lzma), LZMA_FILTER_LZMA1,
  398. &parse_lzma12, lzma12_optmap, 9, 5, false },
  399. #endif
  400. #if defined(HAVE_ENCODER_LZMA2) || defined(HAVE_DECODER_LZMA2)
  401. { "lzma2", sizeof(lzma_options_lzma), LZMA_FILTER_LZMA2,
  402. &parse_lzma12, lzma12_optmap, 9, 2, false },
  403. #endif
  404. #if defined(HAVE_ENCODER_X86) || defined(HAVE_DECODER_X86)
  405. { "x86", sizeof(lzma_options_bcj), LZMA_FILTER_X86,
  406. &parse_bcj, bcj_optmap, 1, 1, true },
  407. #endif
  408. #if defined(HAVE_ENCODER_ARM) || defined(HAVE_DECODER_ARM)
  409. { "arm", sizeof(lzma_options_bcj), LZMA_FILTER_ARM,
  410. &parse_bcj, bcj_optmap, 1, 1, true },
  411. #endif
  412. #if defined(HAVE_ENCODER_ARMTHUMB) || defined(HAVE_DECODER_ARMTHUMB)
  413. { "armthumb", sizeof(lzma_options_bcj), LZMA_FILTER_ARMTHUMB,
  414. &parse_bcj, bcj_optmap, 1, 1, true },
  415. #endif
  416. #if defined(HAVE_ENCODER_ARM64) || defined(HAVE_DECODER_ARM64)
  417. { "arm64", sizeof(lzma_options_bcj), LZMA_FILTER_ARM64,
  418. &parse_bcj, bcj_optmap, 1, 1, true },
  419. #endif
  420. #if defined(HAVE_ENCODER_RISCV) || defined(HAVE_DECODER_RISCV)
  421. { "riscv", sizeof(lzma_options_bcj), LZMA_FILTER_RISCV,
  422. &parse_bcj, bcj_optmap, 1, 1, true },
  423. #endif
  424. #if defined(HAVE_ENCODER_POWERPC) || defined(HAVE_DECODER_POWERPC)
  425. { "powerpc", sizeof(lzma_options_bcj), LZMA_FILTER_POWERPC,
  426. &parse_bcj, bcj_optmap, 1, 1, true },
  427. #endif
  428. #if defined(HAVE_ENCODER_IA64) || defined(HAVE_DECODER_IA64)
  429. { "ia64", sizeof(lzma_options_bcj), LZMA_FILTER_IA64,
  430. &parse_bcj, bcj_optmap, 1, 1, true },
  431. #endif
  432. #if defined(HAVE_ENCODER_SPARC) || defined(HAVE_DECODER_SPARC)
  433. { "sparc", sizeof(lzma_options_bcj), LZMA_FILTER_SPARC,
  434. &parse_bcj, bcj_optmap, 1, 1, true },
  435. #endif
  436. #if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
  437. { "delta", sizeof(lzma_options_delta), LZMA_FILTER_DELTA,
  438. &parse_delta, delta_optmap, 1, 1, false },
  439. #endif
  440. };
  441. /// Decodes options from a string for one filter (name1=value1,name2=value2).
  442. /// Caller must have allocated memory for filter_options already and set
  443. /// the initial default values. This is called from the filter-specific
  444. /// parse_* functions.
  445. ///
  446. /// The input string starts at *str and the address in str_end is the first
  447. /// char that is not part of the string anymore. So no '\0' terminator is
  448. /// used. *str is advanced every time something has been decoded successfully.
  449. static const char *
  450. parse_options(const char **const str, const char *str_end,
  451. void *filter_options,
  452. const option_map *const optmap, const size_t optmap_size)
  453. {
  454. while (*str < str_end && **str != '\0') {
  455. // Each option is of the form name=value.
  456. // Commas (',') separate options. Extra commas are ignored.
  457. // Ignoring extra commas makes it simpler if an optional
  458. // option stored in a shell variable which can be empty.
  459. if (**str == ',') {
  460. ++*str;
  461. continue;
  462. }
  463. // Find where the next name=value ends.
  464. const size_t str_len = (size_t)(str_end - *str);
  465. const char *name_eq_value_end = memchr(*str, ',', str_len);
  466. if (name_eq_value_end == NULL)
  467. name_eq_value_end = str_end;
  468. const char *equals_sign = memchr(*str, '=',
  469. (size_t)(name_eq_value_end - *str));
  470. // Fail if the '=' wasn't found or the option name is missing
  471. // (the first char is '=').
  472. if (equals_sign == NULL || **str == '=')
  473. return "Options must be 'name=value' pairs separated "
  474. "with commas";
  475. // Reject a too long option name so that the memcmp()
  476. // in the loop below won't read past the end of the
  477. // string in optmap[i].name.
  478. const size_t name_len = (size_t)(equals_sign - *str);
  479. if (name_len > NAME_LEN_MAX)
  480. return "Unknown option name";
  481. // Find the option name from optmap[].
  482. size_t i = 0;
  483. while (true) {
  484. if (i == optmap_size)
  485. return "Unknown option name";
  486. if (memcmp(*str, optmap[i].name, name_len) == 0
  487. && optmap[i].name[name_len] == '\0')
  488. break;
  489. ++i;
  490. }
  491. // The input string is good at least until the start of
  492. // the option value.
  493. *str = equals_sign + 1;
  494. // The code assumes that the option value isn't an empty
  495. // string so check it here.
  496. const size_t value_len = (size_t)(name_eq_value_end - *str);
  497. if (value_len == 0)
  498. return "Option value cannot be empty";
  499. // LZMA1/2 preset has its own parsing function.
  500. if (optmap[i].type == OPTMAP_TYPE_LZMA_PRESET) {
  501. const char *errmsg = set_lzma12_preset(str,
  502. name_eq_value_end, filter_options);
  503. if (errmsg != NULL)
  504. return errmsg;
  505. continue;
  506. }
  507. // It's an integer value.
  508. uint32_t v;
  509. if (optmap[i].flags & OPTMAP_USE_NAME_VALUE_MAP) {
  510. // The integer is picked from a string-to-integer map.
  511. //
  512. // Reject a too long value string so that the memcmp()
  513. // in the loop below won't read past the end of the
  514. // string in optmap[i].u.map[j].name.
  515. if (value_len > NAME_LEN_MAX)
  516. return "Invalid option value";
  517. const name_value_map *map = optmap[i].u.map;
  518. size_t j = 0;
  519. while (true) {
  520. // The array is terminated with an empty name.
  521. if (map[j].name[0] == '\0')
  522. return "Invalid option value";
  523. if (memcmp(*str, map[j].name, value_len) == 0
  524. && map[j].name[value_len]
  525. == '\0') {
  526. v = map[j].value;
  527. break;
  528. }
  529. ++j;
  530. }
  531. } else if (**str < '0' || **str > '9') {
  532. // Note that "max" isn't supported while it is
  533. // supported in xz. It's not useful here.
  534. return "Value is not a non-negative decimal integer";
  535. } else {
  536. // strtoul() has locale-specific behavior so it cannot
  537. // be relied on to get reproducible results since we
  538. // cannot change the locate in a thread-safe library.
  539. // It also needs '\0'-termination.
  540. //
  541. // Use a temporary pointer so that *str will point
  542. // to the beginning of the value string in case
  543. // an error occurs.
  544. const char *p = *str;
  545. v = 0;
  546. do {
  547. if (v > UINT32_MAX / 10)
  548. return "Value out of range";
  549. v *= 10;
  550. const uint32_t add = (uint32_t)(*p - '0');
  551. if (UINT32_MAX - add < v)
  552. return "Value out of range";
  553. v += add;
  554. ++p;
  555. } while (p < name_eq_value_end
  556. && *p >= '0' && *p <= '9');
  557. if (p < name_eq_value_end) {
  558. // Remember this position so that it can be
  559. // used for error messages that are
  560. // specifically about the suffix. (Out of
  561. // range values are about the whole value
  562. // and those error messages point to the
  563. // beginning of the number part,
  564. // not to the suffix.)
  565. const char *multiplier_start = p;
  566. // If multiplier suffix shouldn't be used
  567. // then don't allow them even if the value
  568. // would stay within limits. This is a somewhat
  569. // unnecessary check but it rejects silly
  570. // things like lzma2:pb=0MiB which xz allows.
  571. if ((optmap[i].flags & OPTMAP_USE_BYTE_SUFFIX)
  572. == 0) {
  573. *str = multiplier_start;
  574. return "This option does not support "
  575. "any integer suffixes";
  576. }
  577. uint32_t shift;
  578. switch (*p) {
  579. case 'k':
  580. case 'K':
  581. shift = 10;
  582. break;
  583. case 'm':
  584. case 'M':
  585. shift = 20;
  586. break;
  587. case 'g':
  588. case 'G':
  589. shift = 30;
  590. break;
  591. default:
  592. *str = multiplier_start;
  593. return "Invalid multiplier suffix "
  594. "(KiB, MiB, or GiB)";
  595. }
  596. ++p;
  597. // Allow "M", "Mi", "MB", "MiB" and the same
  598. // for the other five characters from the
  599. // switch-statement above. All are handled
  600. // as base-2 (perhaps a mistake, perhaps not).
  601. // Note that 'i' and 'B' are case sensitive.
  602. if (p < name_eq_value_end && *p == 'i')
  603. ++p;
  604. if (p < name_eq_value_end && *p == 'B')
  605. ++p;
  606. // Now we must have no chars remaining.
  607. if (p < name_eq_value_end) {
  608. *str = multiplier_start;
  609. return "Invalid multiplier suffix "
  610. "(KiB, MiB, or GiB)";
  611. }
  612. if (v > (UINT32_MAX >> shift))
  613. return "Value out of range";
  614. v <<= shift;
  615. }
  616. if (v < optmap[i].u.range.min
  617. || v > optmap[i].u.range.max)
  618. return "Value out of range";
  619. }
  620. // Set the value in filter_options. Enums are handled
  621. // specially since the underlying type isn't the same
  622. // as uint32_t on all systems.
  623. void *ptr = (char *)filter_options + optmap[i].offset;
  624. switch (optmap[i].type) {
  625. case OPTMAP_TYPE_LZMA_MODE:
  626. *(lzma_mode *)ptr = (lzma_mode)v;
  627. break;
  628. case OPTMAP_TYPE_LZMA_MATCH_FINDER:
  629. *(lzma_match_finder *)ptr = (lzma_match_finder)v;
  630. break;
  631. default:
  632. *(uint32_t *)ptr = v;
  633. break;
  634. }
  635. // This option has been successfully handled.
  636. *str = name_eq_value_end;
  637. }
  638. // No errors.
  639. return NULL;
  640. }
  641. /// Finds the name of the filter at the beginning of the string and
  642. /// calls filter_name_map[i].parse() to decode the filter-specific options.
  643. /// The caller must have set str_end so that exactly one filter and its
  644. /// options are present without any trailing characters.
  645. static const char *
  646. parse_filter(const char **const str, const char *str_end, lzma_filter *filter,
  647. const lzma_allocator *allocator, bool only_xz)
  648. {
  649. // Search for a colon or equals sign that would separate the filter
  650. // name from filter options. If neither is found, then the input
  651. // string only contains a filter name and there are no options.
  652. //
  653. // First assume that a colon or equals sign won't be found:
  654. const char *name_end = str_end;
  655. const char *opts_start = str_end;
  656. for (const char *p = *str; p < str_end; ++p) {
  657. if (*p == ':' || *p == '=') {
  658. name_end = p;
  659. // Filter options (name1=value1,name2=value2,...)
  660. // begin after the colon or equals sign.
  661. opts_start = p + 1;
  662. break;
  663. }
  664. }
  665. // Reject a too long filter name so that the memcmp()
  666. // in the loop below won't read past the end of the
  667. // string in filter_name_map[i].name.
  668. const size_t name_len = (size_t)(name_end - *str);
  669. if (name_len > NAME_LEN_MAX)
  670. return "Unknown filter name";
  671. for (size_t i = 0; i < ARRAY_SIZE(filter_name_map); ++i) {
  672. if (memcmp(*str, filter_name_map[i].name, name_len) == 0
  673. && filter_name_map[i].name[name_len] == '\0') {
  674. if (only_xz && filter_name_map[i].id
  675. >= LZMA_FILTER_RESERVED_START)
  676. return "This filter cannot be used in "
  677. "the .xz format";
  678. // Allocate the filter-specific options and
  679. // initialize the memory with zeros.
  680. void *options = lzma_alloc_zero(
  681. filter_name_map[i].opts_size,
  682. allocator);
  683. if (options == NULL)
  684. return "Memory allocation failed";
  685. // Filter name was found so the input string is good
  686. // at least this far.
  687. *str = opts_start;
  688. const char *errmsg = filter_name_map[i].parse(
  689. str, str_end, options);
  690. if (errmsg != NULL) {
  691. lzma_free(options, allocator);
  692. return errmsg;
  693. }
  694. // *filter is modified only when parsing is successful.
  695. filter->id = filter_name_map[i].id;
  696. filter->options = options;
  697. return NULL;
  698. }
  699. }
  700. return "Unknown filter name";
  701. }
  702. /// Converts the string to a filter chain (array of lzma_filter structures).
  703. ///
  704. /// *str is advanced every time something has been decoded successfully.
  705. /// This way the caller knows where in the string a possible error occurred.
  706. static const char *
  707. str_to_filters(const char **const str, lzma_filter *filters, uint32_t flags,
  708. const lzma_allocator *allocator)
  709. {
  710. const char *errmsg;
  711. // Skip leading spaces.
  712. while (**str == ' ')
  713. ++*str;
  714. if (**str == '\0')
  715. return "Empty string is not allowed, "
  716. "try \"6\" if a default value is needed";
  717. // Detect the type of the string.
  718. //
  719. // A string beginning with a digit or a string beginning with
  720. // one dash and a digit are treated as presets. Trailing spaces
  721. // will be ignored too (leading spaces were already ignored above).
  722. //
  723. // For example, "6", "7 ", "-9e", or " -3 " are treated as presets.
  724. // Strings like "-" or "- " aren't preset.
  725. #define MY_IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
  726. if (MY_IS_DIGIT(**str) || (**str == '-' && MY_IS_DIGIT((*str)[1]))) {
  727. if (**str == '-')
  728. ++*str;
  729. // Ignore trailing spaces.
  730. const size_t str_len = strlen(*str);
  731. const char *str_end = memchr(*str, ' ', str_len);
  732. if (str_end != NULL) {
  733. // There is at least one trailing space. Check that
  734. // there are no chars other than spaces.
  735. for (size_t i = 1; str_end[i] != '\0'; ++i)
  736. if (str_end[i] != ' ')
  737. return "Unsupported preset";
  738. } else {
  739. // There are no trailing spaces. Use the whole string.
  740. str_end = *str + str_len;
  741. }
  742. uint32_t preset;
  743. errmsg = parse_lzma12_preset(str, str_end, &preset);
  744. if (errmsg != NULL)
  745. return errmsg;
  746. lzma_options_lzma *opts = lzma_alloc(sizeof(*opts), allocator);
  747. if (opts == NULL)
  748. return "Memory allocation failed";
  749. if (lzma_lzma_preset(opts, preset)) {
  750. lzma_free(opts, allocator);
  751. return "Unsupported preset";
  752. }
  753. filters[0].id = LZMA_FILTER_LZMA2;
  754. filters[0].options = opts;
  755. filters[1].id = LZMA_VLI_UNKNOWN;
  756. filters[1].options = NULL;
  757. return NULL;
  758. }
  759. // Not a preset so it must be a filter chain.
  760. //
  761. // If LZMA_STR_ALL_FILTERS isn't used we allow only filters that
  762. // can be used in .xz.
  763. const bool only_xz = (flags & LZMA_STR_ALL_FILTERS) == 0;
  764. // Use a temporary array so that we don't modify the caller-supplied
  765. // one until we know that no errors occurred.
  766. lzma_filter temp_filters[LZMA_FILTERS_MAX + 1];
  767. size_t i = 0;
  768. do {
  769. if (i == LZMA_FILTERS_MAX) {
  770. errmsg = "The maximum number of filters is four";
  771. goto error;
  772. }
  773. // Skip "--" if present.
  774. if ((*str)[0] == '-' && (*str)[1] == '-')
  775. *str += 2;
  776. // Locate the end of "filter:name1=value1,name2=value2",
  777. // stopping at the first "--" or a single space.
  778. const char *filter_end = *str;
  779. while (filter_end[0] != '\0') {
  780. if ((filter_end[0] == '-' && filter_end[1] == '-')
  781. || filter_end[0] == ' ')
  782. break;
  783. ++filter_end;
  784. }
  785. // Inputs that have "--" at the end or "-- " in the middle
  786. // will result in an empty filter name.
  787. if (filter_end == *str) {
  788. errmsg = "Filter name is missing";
  789. goto error;
  790. }
  791. errmsg = parse_filter(str, filter_end, &temp_filters[i],
  792. allocator, only_xz);
  793. if (errmsg != NULL)
  794. goto error;
  795. // Skip trailing spaces.
  796. while (**str == ' ')
  797. ++*str;
  798. ++i;
  799. } while (**str != '\0');
  800. // Seems to be good, terminate the array so that
  801. // basic validation can be done.
  802. temp_filters[i].id = LZMA_VLI_UNKNOWN;
  803. temp_filters[i].options = NULL;
  804. // Do basic validation if the application didn't prohibit it.
  805. if ((flags & LZMA_STR_NO_VALIDATION) == 0) {
  806. size_t dummy;
  807. const lzma_ret ret = lzma_validate_chain(temp_filters, &dummy);
  808. assert(ret == LZMA_OK || ret == LZMA_OPTIONS_ERROR);
  809. if (ret != LZMA_OK) {
  810. errmsg = "Invalid filter chain "
  811. "('lzma2' missing at the end?)";
  812. goto error;
  813. }
  814. }
  815. // All good. Copy the filters to the application supplied array.
  816. memcpy(filters, temp_filters, (i + 1) * sizeof(lzma_filter));
  817. return NULL;
  818. error:
  819. // Free the filter options that were successfully decoded.
  820. while (i-- > 0)
  821. lzma_free(temp_filters[i].options, allocator);
  822. return errmsg;
  823. }
  824. extern LZMA_API(const char *)
  825. lzma_str_to_filters(const char *str, int *error_pos, lzma_filter *filters,
  826. uint32_t flags, const lzma_allocator *allocator)
  827. {
  828. if (str == NULL || filters == NULL)
  829. return "Unexpected NULL pointer argument(s) "
  830. "to lzma_str_to_filters()";
  831. // Validate the flags.
  832. const uint32_t supported_flags
  833. = LZMA_STR_ALL_FILTERS
  834. | LZMA_STR_NO_VALIDATION;
  835. if (flags & ~supported_flags)
  836. return "Unsupported flags to lzma_str_to_filters()";
  837. const char *used = str;
  838. const char *errmsg = str_to_filters(&used, filters, flags, allocator);
  839. if (error_pos != NULL) {
  840. const size_t n = (size_t)(used - str);
  841. *error_pos = n > INT_MAX ? INT_MAX : (int)n;
  842. }
  843. return errmsg;
  844. }
  845. /// Converts options of one filter to a string.
  846. ///
  847. /// The caller must have already put the filter name in the destination
  848. /// string. Since it is possible that no options will be needed, the caller
  849. /// won't have put a delimiter character (':' or '=') in the string yet.
  850. /// We will add it if at least one option will be added to the string.
  851. static void
  852. strfy_filter(lzma_str *dest, const char *delimiter,
  853. const option_map *optmap, size_t optmap_count,
  854. const void *filter_options)
  855. {
  856. for (size_t i = 0; i < optmap_count; ++i) {
  857. // No attempt is made to reverse LZMA1/2 preset.
  858. if (optmap[i].type == OPTMAP_TYPE_LZMA_PRESET)
  859. continue;
  860. // All options have integer values, some just are mapped
  861. // to a string with a name_value_map. LZMA1/2 preset
  862. // isn't reversed back to preset=PRESET form.
  863. uint32_t v;
  864. const void *ptr
  865. = (const char *)filter_options + optmap[i].offset;
  866. switch (optmap[i].type) {
  867. case OPTMAP_TYPE_LZMA_MODE:
  868. v = *(const lzma_mode *)ptr;
  869. break;
  870. case OPTMAP_TYPE_LZMA_MATCH_FINDER:
  871. v = *(const lzma_match_finder *)ptr;
  872. break;
  873. default:
  874. v = *(const uint32_t *)ptr;
  875. break;
  876. }
  877. // Skip this if this option should be omitted from
  878. // the string when the value is zero.
  879. if (v == 0 && (optmap[i].flags & OPTMAP_NO_STRFY_ZERO))
  880. continue;
  881. // Before the first option we add whatever delimiter
  882. // the caller gave us. For later options a comma is used.
  883. str_append_str(dest, delimiter);
  884. delimiter = ",";
  885. // Add the option name and equals sign.
  886. str_append_str(dest, optmap[i].name);
  887. str_append_str(dest, "=");
  888. if (optmap[i].flags & OPTMAP_USE_NAME_VALUE_MAP) {
  889. const name_value_map *map = optmap[i].u.map;
  890. size_t j = 0;
  891. while (true) {
  892. if (map[j].name[0] == '\0') {
  893. str_append_str(dest, "UNKNOWN");
  894. break;
  895. }
  896. if (map[j].value == v) {
  897. str_append_str(dest, map[j].name);
  898. break;
  899. }
  900. ++j;
  901. }
  902. } else {
  903. str_append_u32(dest, v,
  904. optmap[i].flags & OPTMAP_USE_BYTE_SUFFIX);
  905. }
  906. }
  907. return;
  908. }
  909. extern LZMA_API(lzma_ret)
  910. lzma_str_from_filters(char **output_str, const lzma_filter *filters,
  911. uint32_t flags, const lzma_allocator *allocator)
  912. {
  913. // On error *output_str is always set to NULL.
  914. // Do it as the very first step.
  915. if (output_str == NULL)
  916. return LZMA_PROG_ERROR;
  917. *output_str = NULL;
  918. if (filters == NULL)
  919. return LZMA_PROG_ERROR;
  920. // Validate the flags.
  921. const uint32_t supported_flags
  922. = LZMA_STR_ENCODER
  923. | LZMA_STR_DECODER
  924. | LZMA_STR_GETOPT_LONG
  925. | LZMA_STR_NO_SPACES;
  926. if (flags & ~supported_flags)
  927. return LZMA_OPTIONS_ERROR;
  928. // There must be at least one filter.
  929. if (filters[0].id == LZMA_VLI_UNKNOWN)
  930. return LZMA_OPTIONS_ERROR;
  931. // Allocate memory for the output string.
  932. lzma_str dest;
  933. return_if_error(str_init(&dest, allocator));
  934. const bool show_opts = (flags & (LZMA_STR_ENCODER | LZMA_STR_DECODER));
  935. const char *opt_delim = (flags & LZMA_STR_GETOPT_LONG) ? "=" : ":";
  936. for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
  937. // If we reach LZMA_FILTERS_MAX, then the filters array
  938. // is too large since the ID cannot be LZMA_VLI_UNKNOWN here.
  939. if (i == LZMA_FILTERS_MAX) {
  940. str_free(&dest, allocator);
  941. return LZMA_OPTIONS_ERROR;
  942. }
  943. // Don't add a space between filters if the caller
  944. // doesn't want them.
  945. if (i > 0 && !(flags & LZMA_STR_NO_SPACES))
  946. str_append_str(&dest, " ");
  947. // Use dashes for xz getopt_long() compatible syntax but also
  948. // use dashes to separate filters when spaces weren't wanted.
  949. if ((flags & LZMA_STR_GETOPT_LONG)
  950. || (i > 0 && (flags & LZMA_STR_NO_SPACES)))
  951. str_append_str(&dest, "--");
  952. size_t j = 0;
  953. while (true) {
  954. if (j == ARRAY_SIZE(filter_name_map)) {
  955. // Filter ID in filters[i].id isn't supported.
  956. str_free(&dest, allocator);
  957. return LZMA_OPTIONS_ERROR;
  958. }
  959. if (filter_name_map[j].id == filters[i].id) {
  960. // Add the filter name.
  961. str_append_str(&dest, filter_name_map[j].name);
  962. // If only the filter names were wanted then
  963. // skip to the next filter. In this case
  964. // .options is ignored and may be NULL even
  965. // when the filter doesn't allow NULL options.
  966. if (!show_opts)
  967. break;
  968. if (filters[i].options == NULL) {
  969. if (!filter_name_map[j].allow_null) {
  970. // Filter-specific options
  971. // are missing but with
  972. // this filter the options
  973. // structure is mandatory.
  974. str_free(&dest, allocator);
  975. return LZMA_OPTIONS_ERROR;
  976. }
  977. // .options is allowed to be NULL.
  978. // There is no need to add any
  979. // options to the string.
  980. break;
  981. }
  982. // Options structure is available. Add
  983. // the filter options to the string.
  984. const size_t optmap_count
  985. = (flags & LZMA_STR_ENCODER)
  986. ? filter_name_map[j].strfy_encoder
  987. : filter_name_map[j].strfy_decoder;
  988. strfy_filter(&dest, opt_delim,
  989. filter_name_map[j].optmap,
  990. optmap_count,
  991. filters[i].options);
  992. break;
  993. }
  994. ++j;
  995. }
  996. }
  997. return str_finish(output_str, &dest, allocator);
  998. }
  999. extern LZMA_API(lzma_ret)
  1000. lzma_str_list_filters(char **output_str, lzma_vli filter_id, uint32_t flags,
  1001. const lzma_allocator *allocator)
  1002. {
  1003. // On error *output_str is always set to NULL.
  1004. // Do it as the very first step.
  1005. if (output_str == NULL)
  1006. return LZMA_PROG_ERROR;
  1007. *output_str = NULL;
  1008. // Validate the flags.
  1009. const uint32_t supported_flags
  1010. = LZMA_STR_ALL_FILTERS
  1011. | LZMA_STR_ENCODER
  1012. | LZMA_STR_DECODER
  1013. | LZMA_STR_GETOPT_LONG;
  1014. if (flags & ~supported_flags)
  1015. return LZMA_OPTIONS_ERROR;
  1016. // Allocate memory for the output string.
  1017. lzma_str dest;
  1018. return_if_error(str_init(&dest, allocator));
  1019. // If only listing the filter names then separate them with spaces.
  1020. // Otherwise use newlines.
  1021. const bool show_opts = (flags & (LZMA_STR_ENCODER | LZMA_STR_DECODER));
  1022. const char *filter_delim = show_opts ? "\n" : " ";
  1023. const char *opt_delim = (flags & LZMA_STR_GETOPT_LONG) ? "=" : ":";
  1024. bool first_filter_printed = false;
  1025. for (size_t i = 0; i < ARRAY_SIZE(filter_name_map); ++i) {
  1026. // If we are printing only one filter then skip others.
  1027. if (filter_id != LZMA_VLI_UNKNOWN
  1028. && filter_id != filter_name_map[i].id)
  1029. continue;
  1030. // If we are printing only .xz filters then skip the others.
  1031. if (filter_name_map[i].id >= LZMA_FILTER_RESERVED_START
  1032. && (flags & LZMA_STR_ALL_FILTERS) == 0
  1033. && filter_id == LZMA_VLI_UNKNOWN)
  1034. continue;
  1035. // Add a new line if this isn't the first filter being
  1036. // written to the string.
  1037. if (first_filter_printed)
  1038. str_append_str(&dest, filter_delim);
  1039. first_filter_printed = true;
  1040. if (flags & LZMA_STR_GETOPT_LONG)
  1041. str_append_str(&dest, "--");
  1042. str_append_str(&dest, filter_name_map[i].name);
  1043. // If only the filter names were wanted then continue
  1044. // to the next filter.
  1045. if (!show_opts)
  1046. continue;
  1047. const option_map *optmap = filter_name_map[i].optmap;
  1048. const char *d = opt_delim;
  1049. const size_t end = (flags & LZMA_STR_ENCODER)
  1050. ? filter_name_map[i].strfy_encoder
  1051. : filter_name_map[i].strfy_decoder;
  1052. for (size_t j = 0; j < end; ++j) {
  1053. // The first option is delimited from the filter
  1054. // name using "=" or ":" and the rest of the options
  1055. // are separated with ",".
  1056. str_append_str(&dest, d);
  1057. d = ",";
  1058. // optname=<possible_values>
  1059. str_append_str(&dest, optmap[j].name);
  1060. str_append_str(&dest, "=<");
  1061. if (optmap[j].type == OPTMAP_TYPE_LZMA_PRESET) {
  1062. // LZMA1/2 preset has its custom help string.
  1063. str_append_str(&dest, LZMA12_PRESET_STR);
  1064. } else if (optmap[j].flags
  1065. & OPTMAP_USE_NAME_VALUE_MAP) {
  1066. // Separate the possible option values by "|".
  1067. const name_value_map *m = optmap[j].u.map;
  1068. for (size_t k = 0; m[k].name[0] != '\0'; ++k) {
  1069. if (k > 0)
  1070. str_append_str(&dest, "|");
  1071. str_append_str(&dest, m[k].name);
  1072. }
  1073. } else {
  1074. // Integer range is shown as min-max.
  1075. const bool use_byte_suffix = optmap[j].flags
  1076. & OPTMAP_USE_BYTE_SUFFIX;
  1077. str_append_u32(&dest, optmap[j].u.range.min,
  1078. use_byte_suffix);
  1079. str_append_str(&dest, "-");
  1080. str_append_u32(&dest, optmap[j].u.range.max,
  1081. use_byte_suffix);
  1082. }
  1083. str_append_str(&dest, ">");
  1084. }
  1085. }
  1086. // If no filters were added to the string then it must be because
  1087. // the caller provided an unsupported Filter ID.
  1088. if (!first_filter_printed) {
  1089. str_free(&dest, allocator);
  1090. return LZMA_OPTIONS_ERROR;
  1091. }
  1092. return str_finish(output_str, &dest, allocator);
  1093. }