|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- #include <assert.h>
- #include <ctype.h>
- #include <errno.h>
- #include <inttypes.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include "benc.h"
-
- #define benc_safeset(out, val) if ((out) != NULL) *(out) = (val)
-
- static const char *benc_validate_aux(const char *p, const char *end);
-
- int
- benc_validate(const char *p, size_t len)
- {
- const char *end = p + len - 1;
-
- if (len <= 0)
- return EINVAL;
-
- return benc_validate_aux(p, end) == end ? 0 : EINVAL;
- }
-
- static const char *
- benc_validate_aux(const char *p, const char *end)
- {
- size_t d = 0;
- switch (*p) {
- case 'd':
- d = 1;
- case 'l':
- for (p++; p <= end && *p != 'e'; p++) {
- if (d != 0) {
- if (d % 2 == 1 && !isdigit(*p))
- return NULL;
- else
- d++;
- }
- if ((p = benc_validate_aux(p, end)) == NULL)
- return NULL;
- }
- if (p > end || (d != 0 && d % 2 != 1))
- return NULL;
- break;
- case 'i':
- p++;
- if (p > end)
- return NULL;
- if (*p == '-')
- p++;
- if (p > end || !isdigit(*p))
- return NULL;
- p++;
- while (p <= end && isdigit(*p))
- p++;
- if (p > end || *p != 'e')
- return NULL;
- break;
- default:
- if (isdigit(*p)) {
- size_t len = 0;
- while (p <= end && isdigit(*p)) {
- len *= 10;
- len += *p - '0';
- p++;
- }
- if (p <= end && *p == ':' && p + len <= end)
- p += len;
- else
- return NULL;
- }
- else
- return NULL;
- break;
- }
- return p;
- }
-
- size_t
- benc_length(const char *p)
- {
- size_t blen;
- const char *next;
-
- switch (*p) {
- case 'd':
- case 'l':
- blen = 2; // [l|d]...e
- next = benc_first(p);
- while (*next != 'e') {
- size_t len = benc_length(next);
- blen += len;
- next += len;
- }
- return blen;
- case 'i':
- for (next = p + 1; *next != 'e'; next++)
- ;
- return next - p + 1;
- default:
- assert(benc_str(p, &next, &blen, NULL) == 0);
- return next - p + blen;
- }
- }
-
- size_t
- benc_nelems(const char *p)
- {
- size_t nelems = 0;
- for (p = benc_first(p); p != NULL; p = benc_next(p))
- nelems++;
- return nelems;
- }
-
- const char *
- benc_first(const char *p)
- {
- assert(benc_islst(p));
- return *(p + 1) == 'e' ? NULL : p + 1;
- }
-
- const char *
- benc_next(const char *p)
- {
- size_t blen = benc_length(p);
- return *(p + blen) == 'e' ? NULL : p + blen;
- }
-
- int
- benc_str(const char *p, const char **out, size_t *len, const char**next)
- {
- size_t blen = 0;
- assert(isdigit(*p));
- blen = *p - '0';
- p++;
- while (isdigit(*p)) {
- blen *= 10;
- blen += *p - '0';
- p++;
- }
- assert(*p == ':');
- benc_safeset(len, blen);
- benc_safeset(out, p + 1);
- benc_safeset(next, *(p + blen + 1) == 'e' ? NULL : p + blen + 1);
- return 0;
- }
-
- int
- benc_strz(const char *p, char **out, size_t *len, const char **next)
- {
- int err;
- size_t blen;
- const char *bstr;
-
- if ((err = benc_str(p, &bstr, &blen, next)) == 0) {
- if ((*out = malloc(blen + 1)) != NULL) {
- memcpy(*out, bstr, blen);
- (*out)[blen] = '\0';
- benc_safeset(len, blen);
- } else
- err = ENOMEM;
- }
- return err;
- }
-
- int
- benc_stra(const char *p, char **out, size_t *len, const char **next)
- {
- int err;
- size_t blen;
- const char *bstr;
-
- if ((err = benc_str(p, &bstr, &blen, next)) == 0) {
- if ((*out = malloc(blen)) != NULL) {
- memcpy(*out, bstr, blen);
- benc_safeset(len, blen);
- } else
- err = ENOMEM;
- }
- return err;
- }
-
- int
- benc_int64(const char *p, int64_t *out, const char **next)
- {
- int sign = 1;
- int64_t res = 0;
-
- assert(*p == 'i');
- p++;
- if (*p == '-') {
- sign = -1;
- p++;
- }
- assert(isdigit(*p));
- res += sign * (*p - '0');
- p++;
- while (isdigit(*p)) {
- res *= sign * 10;
- res += sign * (*p - '0');
- p++;
- }
- assert(*p == 'e');
- benc_safeset(out, res);
- benc_safeset(next, *(p + 1) == 'e' ? NULL : p + 1);
-
- return 0;
- }
-
- int
- benc_uint32(const char *p, uint32_t *out, const char **next)
- {
- int err;
- int64_t res;
- if ((err = benc_int64(p, &res, next)) == 0) {
- if (res >= 0 && res <= 0xffffffffUL)
- *out = (uint32_t)res;
- else
- err = EINVAL;
- }
- return err;
- }
-
- int
- benc_dget_any(const char *p, const char *key, const char **val)
- {
- int res;
- size_t len, blen;
- const char *bstr;
-
- assert(benc_isdct(p));
-
- len = strlen(key);
-
- p = benc_first(p);
- while (p != NULL) {
- if ((res = benc_str(p, &bstr, &blen, &p)) != 0)
- return res;
-
- res = strncmp(bstr, key, blen);
- if (res == 0 && len == blen) {
- *val = p;
- return 0;
- } else if (res <= 0) {
- p = benc_next(p);
- } else
- return ENOENT;
- }
- return ENOENT;
- }
-
- int
- benc_dget_lst(const char *p, const char *key, const char **val)
- {
- int err;
- if ((err = benc_dget_any(p, key, val)) == 0)
- if (!benc_islst(*val))
- err = EINVAL;
- return err;
- }
-
- int
- benc_dget_dct(const char *p, const char *key, const char **val)
- {
- int err;
- if ((err = benc_dget_any(p, key, val)) == 0)
- if (!benc_isdct(*val))
- err = EINVAL;
- return err;
- }
-
- int
- benc_dget_str(const char *p, const char *key, const char **val, size_t *len)
- {
- int err;
- const char *sp;
- if ((err = benc_dget_any(p, key, &sp)) == 0)
- err = benc_isstr(sp) ? benc_str(sp, val, len, NULL) : EINVAL;
- return err;
- }
-
- int
- benc_dget_stra(const char *p, const char *key, char **val, size_t *len)
- {
- int err;
- const char *sp;
- if ((err = benc_dget_any(p, key, &sp)) == 0)
- err = benc_isstr(sp) ? benc_stra(sp, val, len, NULL) : EINVAL;
- return err;
- }
-
- int
- benc_dget_strz(const char *p, const char *key, char **val, size_t *len)
- {
- int err;
- const char *sp;
- if ((err = benc_dget_any(p, key, &sp)) == 0)
- err = benc_isstr(sp) ? benc_strz(sp, val, len, NULL) : EINVAL;
- return err;
- }
-
- int
- benc_dget_int64(const char *p, const char *key, int64_t *val)
- {
- int err;
- const char *ip;
- if ((err = benc_dget_any(p, key, &ip)) == 0)
- err = benc_isint(ip) ? benc_int64(ip, val, NULL) : EINVAL;
- return err;
- }
-
- int
- benc_dget_uint32(const char *p, const char *key, uint32_t *val)
- {
- int err;
- const char *ip;
- if ((err = benc_dget_any(p, key, &ip)) == 0)
- err = benc_isint(ip) ? benc_uint32(ip, val, NULL) : EINVAL;
- return err;
- }
-
- int
- benc_islst(const char *p)
- {
- return *p == 'l' || *p == 'd';
- }
-
- int
- benc_isdct(const char *p)
- {
- return *p == 'd';
- }
-
- int
- benc_isint(const char *p)
- {
- return *p == 'i';
- }
-
- int
- benc_isstr(const char *p)
- {
- return isdigit(*p);
- }
|