14 #include "../minmax.h"
15 #include "../oslib/strcasestr.h"
16 #include "../oslib/strndup.h"
19 * parse_file() - parses binary file to fill buffer
20 * @beg - string input, extract filename from this
21 * @out - output buffer where parsed number should be put
22 * @out_len - length of the output buffer
23 * @filled - pointer where number of bytes successfully
26 * Returns the end pointer where parsing has been stopped.
27 * In case of parsing error or lack of bytes in output buffer
28 * NULL will be returned.
30 static const char *parse_file(const char *beg, char *out,
44 end = strchr(beg, '\'');
48 file = strndup(beg, end - beg);
52 fd = open(file, O_RDONLY);
56 count = read(fd, out, out_len);
58 goto err_free_close_out;
77 * parse_string() - parses string in double quotes, like "abc"
79 * @out - output buffer where parsed number should be put
80 * @out_len - length of the output buffer
81 * @filled - pointer where number of bytes successfully
84 * Returns the end pointer where parsing has been stopped.
85 * In case of parsing error or lack of bytes in output buffer
86 * NULL will be returned.
88 static const char *parse_string(const char *beg, char *out,
99 end = strchr(beg, '"');
102 if (end - beg > out_len)
105 memcpy(out, beg, end - beg);
113 * parse_number() - parses numbers
114 * @beg - string input
115 * @out - output buffer where parsed number should be put
116 * @out_len - length of the output buffer
117 * @filled - pointer where number of bytes successfully
120 * Supports decimals in the range [INT_MIN, INT_MAX] and
121 * hexidecimals of any size, which should be started with
124 * Returns the end pointer where parsing has been stopped.
125 * In case of parsing error or lack of bytes in output buffer
126 * NULL will be returned.
128 static const char *parse_number(const char *beg, char *out,
129 unsigned int out_len,
130 unsigned int *filled)
141 sscanf(beg, "0%*[xX]%*[0-9a-fA-F]%n", &num);
143 /* Here we are trying to parse decimal */
148 _end = strcasestr(beg, "0x");
152 lval = strntol(beg, num, &_end, 10);
154 lval = strtol(beg, &_end, 10);
155 if (beg == _end || lval > INT_MAX || lval < INT_MIN)
164 val = (unsigned int)lval;
165 for (; val && out_len; out_len--, i++, val >>= 8)
173 /* Catch up 0x prefix */
177 /* Look back, handle this combined string: 0xff0x14 */
178 if (beg[num] && !strncasecmp(&beg[num - 1], "0x", 2))
183 for (i = 0; num && out_len;
184 out_len--, i++, num -= 2, beg += 2) {
187 fmt = (num & 1 ? "%1hhx" : "%2hhx");
188 sscanf(beg, fmt, &out[i]);
204 * parse_format() - parses formats, like %o, etc
206 * @out - output buffer where space for format should be reserved
207 * @parsed - number of bytes which were already parsed so far
208 * @out_len - length of the output buffer
209 * @fmt_desc - format descritor array, what we expect to find
210 * @fmt_desc_sz - size of the format descritor array
211 * @fmt - format array, the output
212 * @fmt_sz - size of format array
214 * This function tries to find formats, e.g.:
215 * %o - offset of the block
217 * In case of successfull parsing it fills the format param
218 * with proper offset and the size of the expected value, which
219 * should be pasted into buffer using the format 'func' callback.
221 * Returns the end pointer where parsing has been stopped.
222 * In case of parsing error or lack of bytes in output buffer
223 * NULL will be returned.
225 static const char *parse_format(const char *in, char *out, unsigned int parsed,
226 unsigned int out_len, unsigned int *filled,
227 const struct pattern_fmt_desc *fmt_desc,
228 unsigned int fmt_desc_sz,
229 struct pattern_fmt *fmt, unsigned int fmt_sz)
232 struct pattern_fmt *f = NULL;
233 unsigned int len = 0;
235 if (!out_len || !fmt_desc || !fmt_desc_sz || !fmt || !fmt_sz)
240 for (i = 0; i < fmt_desc_sz; i++) {
241 const struct pattern_fmt_desc *desc;
244 len = strlen(desc->fmt);
245 if (0 == strncmp(in, desc->fmt, len)) {
255 if (f->desc->len > out_len)
258 memset(out, '\0', f->desc->len);
259 *filled = f->desc->len;
265 * parse_and_fill_pattern() - Parses combined input, which consists of strings,
266 * numbers and pattern formats.
268 * @in_len - size of the input string
269 * @out - output buffer where parsed result will be put
270 * @out_len - lengths of the output buffer
271 * @fmt_desc - array of pattern format descriptors [input]
272 * @fmt_desc_sz - size of the format descriptor array
273 * @fmt - array of pattern formats [output]
274 * @fmt_sz - pointer where the size of pattern formats array stored [input],
275 * after successfull parsing this pointer will contain the number
276 * of parsed formats if any [output].
279 * bytes sequence in double quotes, e.g. "123".
280 * NOTE: there is no way to escape quote, so "123\"abc" does not work.
283 * hexidecimal - sequence of hex bytes starting from 0x or 0X prefix,
284 * e.g. 0xff12ceff1100ff
285 * decimal - decimal number in range [INT_MIN, INT_MAX]
288 * %o - offset of block, reserved 8 bytes.
290 * Explicit examples of combined string:
292 * in="abcd" in=-1024 in=66 in=0xFF0X1
293 * out=61 62 63 64 out=00 fc ff ff out=42 out=ff 01
296 * in=%o in="123"0xFFeeCC
297 * out=00 00 00 00 00 00 00 00 out=31 32 33 ff ec cc
301 * out=f6 ff ff ff ab 31 00 00 00 00 00 00 00 00 32
305 * out=00 00 00 00 00 00 00 00 de ad be ef 00 00 00 00 00 00 00 00
308 * in=0xfefefefefefefefefefefefefefefefefefefefefe
309 * out=fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
311 * Returns number of bytes filled or err < 0 in case of failure.
313 int parse_and_fill_pattern(const char *in, unsigned int in_len,
314 char *out, unsigned int out_len,
315 const struct pattern_fmt_desc *fmt_desc,
316 unsigned int fmt_desc_sz,
317 struct pattern_fmt *fmt,
318 unsigned int *fmt_sz_out)
320 const char *beg, *end, *out_beg = out;
321 unsigned int total = 0, fmt_rem = 0;
323 if (!in || !in_len || !out || !out_len)
326 fmt_rem = *fmt_sz_out;
338 end = parse_file(beg, out, out_len, &filled);
341 end = parse_string(beg, out, out_len, &filled);
344 end = parse_format(beg, out, out - out_beg, out_len,
345 &filled, fmt_desc, fmt_desc_sz,
350 end = parse_number(beg, out, out_len, &filled);
363 assert(end - beg <= in_len);
368 assert(filled <= out_len);
376 *fmt_sz_out -= fmt_rem;
381 * dup_pattern() - Duplicates part of the pattern all over the buffer.
383 * Returns 0 in case of success or errno < 0 in case of failure.
385 static int dup_pattern(char *out, unsigned int out_len, unsigned int pattern_len)
387 unsigned int left, len, off;
389 if (out_len <= pattern_len)
394 left = (out_len - off);
395 len = min(left, off);
397 /* Duplicate leftover */
399 memcpy(out + off, out, len);
402 len = min(left, off);
409 * cpy_pattern() - Copies pattern to the buffer.
411 * Function copies pattern along the whole buffer.
413 * Returns 0 in case of success or errno < 0 in case of failure.
415 int cpy_pattern(const char *pattern, unsigned int pattern_len,
416 char *out, unsigned int out_len)
420 if (!pattern || !pattern_len || !out || !out_len)
424 len = min(pattern_len, out_len);
425 memcpy(out, pattern, len);
427 /* Spread filled chunk all over the buffer */
428 return dup_pattern(out, out_len, pattern_len);
432 * cmp_pattern() - Compares pattern and buffer.
434 * For the sake of performance this function avoids any loops.
435 * Firstly it tries to compare the buffer itself, checking that
436 * buffer consists of repeating patterns along the buffer size.
438 * If the difference is not found then the function tries to compare
439 * buffer and pattern.
441 * Returns 0 in case of success or errno < 0 in case of failure.
443 int cmp_pattern(const char *pattern, unsigned int pattern_size,
444 unsigned int off, const char *buf, unsigned int len)
449 /* Find the difference in buffer */
450 if (len > pattern_size) {
451 rc = memcmp(buf, buf + pattern_size, len - pattern_size);
455 /* Compare second part of the pattern with buffer */
457 size = min(len, pattern_size - off);
458 rc = memcmp(buf, pattern + off, size);
464 /* Compare first part of the pattern or the whole pattern
467 size = min(len, (off ? off : pattern_size));
468 rc = memcmp(buf, pattern, size);
477 * paste_format_inplace() - Pastes parsed formats to the pattern.
479 * This function pastes formats to the pattern. If @fmt_sz is 0
480 * function does nothing and pattern buffer is left untouched.
482 * Returns 0 in case of success or errno < 0 in case of failure.
484 int paste_format_inplace(char *pattern, unsigned int pattern_len,
485 struct pattern_fmt *fmt, unsigned int fmt_sz,
491 if (!pattern || !pattern_len || !fmt)
494 /* Paste formats for first pattern chunk */
495 for (i = 0; i < fmt_sz; i++) {
496 struct pattern_fmt *f;
499 if (pattern_len <= f->off)
501 len = min(pattern_len - f->off, f->desc->len);
502 rc = f->desc->paste(pattern + f->off, len, priv);
511 * paste_format() - Pastes parsed formats to the buffer.
513 * This function copies pattern to the buffer, pastes format
514 * into it and then duplicates pattern all over the buffer size.
516 * Returns 0 in case of success or errno < 0 in case of failure.
518 int paste_format(const char *pattern, unsigned int pattern_len,
519 struct pattern_fmt *fmt, unsigned int fmt_sz,
520 char *out, unsigned int out_len, void *priv)
525 if (!pattern || !pattern_len || !out || !out_len)
529 len = min(pattern_len, out_len);
530 memcpy(out, pattern, len);
532 rc = paste_format_inplace(out, len, fmt, fmt_sz, priv);
536 /* Spread filled chunk all over the buffer */
537 return dup_pattern(out, out_len, pattern_len);