12 #include "../minmax.h"
13 #include "../oslib/strcasestr.h"
14 #include "../oslib/strndup.h"
17 * parse_file() - parses binary file to fill buffer
18 * @beg - string input, extract filename from this
19 * @out - output buffer where parsed number should be put
20 * @out_len - length of the output buffer
21 * @filled - pointer where number of bytes successfully
24 * Returns the end pointer where parsing has been stopped.
25 * In case of parsing error or lack of bytes in output buffer
26 * NULL will be returned.
28 static const char *parse_file(const char *beg, char *out,
35 ssize_t rc, count = 0;
42 end = strchr(beg, '\'');
46 file = strndup(beg, end - beg);
50 fd = open(file, O_RDONLY);
56 rc = read(fd, out, out_len - count);
60 goto err_free_close_out;
66 count = lseek(fd, 0, SEEK_END);
68 goto err_free_close_out;
90 * parse_string() - parses string in double quotes, like "abc"
92 * @out - output buffer where parsed number should be put
93 * @out_len - length of the output buffer
94 * @filled - pointer where number of bytes successfully
97 * Returns the end pointer where parsing has been stopped.
98 * In case of parsing error or lack of bytes in output buffer
99 * NULL will be returned.
101 static const char *parse_string(const char *beg, char *out,
102 unsigned int out_len,
103 unsigned int *filled)
112 end = strchr(beg, '"');
115 if (end - beg > out_len)
119 memcpy(out, beg, end - beg);
127 * parse_number() - parses numbers
128 * @beg - string input
129 * @out - output buffer where parsed number should be put
130 * @out_len - length of the output buffer
131 * @filled - pointer where number of bytes successfully
134 * Supports decimals in the range [INT_MIN, INT_MAX] and
135 * hexidecimals of any size, which should be started with
138 * Returns the end pointer where parsing has been stopped.
139 * In case of parsing error or lack of bytes in output buffer
140 * NULL will be returned.
142 static const char *parse_number(const char *beg, char *out,
143 unsigned int out_len,
144 unsigned int *filled)
155 sscanf(beg, "0%*[xX]%*[0-9a-fA-F]%n", &num);
157 /* Here we are trying to parse decimal */
162 _end = strcasestr(beg, "0x");
166 lval = strntol(beg, num, &_end, 10);
168 lval = strtol(beg, &_end, 10);
169 if (beg == _end || lval > INT_MAX || lval < INT_MIN)
179 val = (unsigned int)lval;
180 for (; val && out_len; out_len--, i++, val >>= 8)
189 /* Catch up 0x prefix */
193 /* Look back, handle this combined string: 0xff0x14 */
194 if (beg[num] && !strncasecmp(&beg[num - 1], "0x", 2))
199 for (i = 0; num && out_len;
200 out_len--, i++, num -= 2, beg += 2) {
203 fmt = (num & 1 ? "%1hhx" : "%2hhx");
205 sscanf(beg, fmt, &out[i]);
221 * parse_format() - parses formats, like %o, etc
223 * @out - output buffer where space for format should be reserved
224 * @parsed - number of bytes which were already parsed so far
225 * @out_len - length of the output buffer
226 * @fmt_desc - format descriptor array, what we expect to find
227 * @fmt - format array, the output
228 * @fmt_sz - size of format array
230 * This function tries to find formats, e.g.:
231 * %o - offset of the block
233 * In case of successful parsing it fills the format param
234 * with proper offset and the size of the expected value, which
235 * should be pasted into buffer using the format 'func' callback.
237 * Returns the end pointer where parsing has been stopped.
238 * In case of parsing error or lack of bytes in output buffer
239 * NULL will be returned.
241 static const char *parse_format(const char *in, char *out, unsigned int parsed,
242 unsigned int out_len, unsigned int *filled,
243 const struct pattern_fmt_desc *fmt_desc,
244 struct pattern_fmt *fmt, unsigned int fmt_sz)
247 struct pattern_fmt *f = NULL;
248 unsigned int len = 0;
250 if (!out_len || !fmt_desc || !fmt || !fmt_sz)
255 for (i = 0; fmt_desc[i].fmt; i++) {
256 const struct pattern_fmt_desc *desc;
259 len = strlen(desc->fmt);
260 if (0 == strncmp(in, desc->fmt, len)) {
270 if (f->desc->len > out_len)
274 memset(out, '\0', f->desc->len);
275 *filled = f->desc->len;
281 * parse_and_fill_pattern() - Parses combined input, which consists of strings,
282 * numbers and pattern formats.
284 * @in_len - size of the input string
285 * @out - output buffer where parsed result will be put, may be NULL
286 * in which case this function just calculates the required
287 * length of the buffer
288 * @out_len - lengths of the output buffer
289 * @fmt_desc - array of pattern format descriptors [input]
290 * @fmt - array of pattern formats [output]
291 * @fmt_sz - pointer where the size of pattern formats array stored [input],
292 * after successful parsing this pointer will contain the number
293 * of parsed formats if any [output].
296 * bytes sequence in double quotes, e.g. "123".
297 * NOTE: there is no way to escape quote, so "123\"abc" does not work.
300 * hexadecimal - sequence of hex bytes starting from 0x or 0X prefix,
301 * e.g. 0xff12ceff1100ff
302 * decimal - decimal number in range [INT_MIN, INT_MAX]
305 * %o - offset of block, reserved 8 bytes.
307 * Explicit examples of combined string:
309 * in="abcd" in=-1024 in=66 in=0xFF0X1
310 * out=61 62 63 64 out=00 fc ff ff out=42 out=ff 01
313 * in=%o in="123"0xFFeeCC
314 * out=00 00 00 00 00 00 00 00 out=31 32 33 ff ec cc
318 * out=f6 ff ff ff ab 31 00 00 00 00 00 00 00 00 32
322 * out=00 00 00 00 00 00 00 00 de ad be ef 00 00 00 00 00 00 00 00
325 * in=0xfefefefefefefefefefefefefefefefefefefefefe
326 * out=fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
328 * Returns number of bytes filled or err < 0 in case of failure.
330 static int parse_and_fill_pattern(const char *in, unsigned int in_len,
331 char *out, unsigned int out_len,
332 const struct pattern_fmt_desc *fmt_desc,
333 struct pattern_fmt *fmt,
334 unsigned int *fmt_sz_out)
336 const char *beg, *end, *out_beg = out;
337 unsigned int total = 0, fmt_rem = 0;
339 if (!in || !in_len || !out_len)
342 fmt_rem = *fmt_sz_out;
354 end = parse_file(beg, out, out_len, &filled);
357 end = parse_string(beg, out, out_len, &filled);
360 end = parse_format(beg, out, out - out_beg, out_len,
361 &filled, fmt_desc, fmt, fmt_rem);
365 end = parse_number(beg, out, out_len, &filled);
378 assert(end - beg <= in_len);
383 assert(filled <= out_len);
391 *fmt_sz_out -= fmt_rem;
396 * parse_and_fill_pattern_alloc() - Parses combined input, which consists of
397 * strings, numbers and pattern formats and
398 * allocates a buffer for the result.
401 * @in_len - size of the input string
402 * @out - pointer to the output buffer pointer, this will be set to the newly
403 * allocated pattern buffer which must be freed by the caller
404 * @fmt_desc - array of pattern format descriptors [input]
405 * @fmt - array of pattern formats [output]
406 * @fmt_sz - pointer where the size of pattern formats array stored [input],
407 * after successful parsing this pointer will contain the number
408 * of parsed formats if any [output].
410 * See documentation on parse_and_fill_pattern() above for a description
411 * of the functionality.
413 * Returns number of bytes filled or err < 0 in case of failure.
415 int parse_and_fill_pattern_alloc(const char *in, unsigned int in_len,
416 char **out, const struct pattern_fmt_desc *fmt_desc,
417 struct pattern_fmt *fmt, unsigned int *fmt_sz_out)
421 count = parse_and_fill_pattern(in, in_len, NULL, MAX_PATTERN_SIZE,
422 fmt_desc, fmt, fmt_sz_out);
426 *out = malloc(count);
427 count = parse_and_fill_pattern(in, in_len, *out, count, fmt_desc,
438 * dup_pattern() - Duplicates part of the pattern all over the buffer.
440 * Returns 0 in case of success or errno < 0 in case of failure.
442 static int dup_pattern(char *out, unsigned int out_len, unsigned int pattern_len)
444 unsigned int left, len, off;
446 if (out_len <= pattern_len)
451 left = (out_len - off);
452 len = min(left, off);
454 /* Duplicate leftover */
456 memcpy(out + off, out, len);
459 len = min(left, off);
466 * cpy_pattern() - Copies pattern to the buffer.
468 * Function copies pattern along the whole buffer.
470 * Returns 0 in case of success or errno < 0 in case of failure.
472 int cpy_pattern(const char *pattern, unsigned int pattern_len,
473 char *out, unsigned int out_len)
477 if (!pattern || !pattern_len || !out || !out_len)
481 len = min(pattern_len, out_len);
482 memcpy(out, pattern, len);
484 /* Spread filled chunk all over the buffer */
485 return dup_pattern(out, out_len, pattern_len);
489 * cmp_pattern() - Compares pattern and buffer.
491 * For the sake of performance this function avoids any loops.
492 * Firstly it tries to compare the buffer itself, checking that
493 * buffer consists of repeating patterns along the buffer size.
495 * If the difference is not found then the function tries to compare
496 * buffer and pattern.
498 * Returns 0 in case of success or errno < 0 in case of failure.
500 int cmp_pattern(const char *pattern, unsigned int pattern_size,
501 unsigned int off, const char *buf, unsigned int len)
506 /* Find the difference in buffer */
507 if (len > pattern_size) {
508 rc = memcmp(buf, buf + pattern_size, len - pattern_size);
512 /* Compare second part of the pattern with buffer */
514 size = min(len, pattern_size - off);
515 rc = memcmp(buf, pattern + off, size);
521 /* Compare first part of the pattern or the whole pattern
524 size = min(len, (off ? off : pattern_size));
525 rc = memcmp(buf, pattern, size);
534 * paste_format_inplace() - Pastes parsed formats to the pattern.
536 * This function pastes formats to the pattern. If @fmt_sz is 0
537 * function does nothing and pattern buffer is left untouched.
539 * Returns 0 in case of success or errno < 0 in case of failure.
541 int paste_format_inplace(char *pattern, unsigned int pattern_len,
542 struct pattern_fmt *fmt, unsigned int fmt_sz,
548 if (!pattern || !pattern_len || !fmt)
551 /* Paste formats for first pattern chunk */
552 for (i = 0; i < fmt_sz; i++) {
553 struct pattern_fmt *f;
556 if (pattern_len <= f->off)
558 len = min(pattern_len - f->off, f->desc->len);
559 rc = f->desc->paste(pattern + f->off, len, priv);
568 * paste_format() - Pastes parsed formats to the buffer.
570 * This function copies pattern to the buffer, pastes format
571 * into it and then duplicates pattern all over the buffer size.
573 * Returns 0 in case of success or errno < 0 in case of failure.
575 int paste_format(const char *pattern, unsigned int pattern_len,
576 struct pattern_fmt *fmt, unsigned int fmt_sz,
577 char *out, unsigned int out_len, void *priv)
582 if (!pattern || !pattern_len || !out || !out_len)
586 len = min(pattern_len, out_len);
587 memcpy(out, pattern, len);
589 rc = paste_format_inplace(out, len, fmt, fmt_sz, priv);
593 /* Spread filled chunk all over the buffer */
594 return dup_pattern(out, out_len, pattern_len);