diff options
Diffstat (limited to 'src/blob.c')
-rw-r--r-- | src/blob.c | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/src/blob.c b/src/blob.c new file mode 100644 index 0000000..1604308 --- /dev/null +++ b/src/blob.c @@ -0,0 +1,426 @@ +#include <time.h> +#include <ctype.h> +#include <string.h> + +#include "blob.h" + +/* RFC 3986 section 2.3 Unreserved Characters (January 2005) */ +#define CTYPE_UNRESERVED 1 + +static const char *xd = "0123456789abcdefghijklmnopqrstuvwxyz"; + +static const unsigned char chartype[128] = { + ['a'] = CTYPE_UNRESERVED, + ['b'] = CTYPE_UNRESERVED, + ['c'] = CTYPE_UNRESERVED, + ['d'] = CTYPE_UNRESERVED, + ['e'] = CTYPE_UNRESERVED, + ['f'] = CTYPE_UNRESERVED, + ['g'] = CTYPE_UNRESERVED, + ['h'] = CTYPE_UNRESERVED, + ['i'] = CTYPE_UNRESERVED, + ['j'] = CTYPE_UNRESERVED, + ['k'] = CTYPE_UNRESERVED, + ['l'] = CTYPE_UNRESERVED, + ['m'] = CTYPE_UNRESERVED, + ['n'] = CTYPE_UNRESERVED, + ['o'] = CTYPE_UNRESERVED, + ['p'] = CTYPE_UNRESERVED, + ['q'] = CTYPE_UNRESERVED, + ['r'] = CTYPE_UNRESERVED, + ['s'] = CTYPE_UNRESERVED, + ['t'] = CTYPE_UNRESERVED, + ['u'] = CTYPE_UNRESERVED, + ['v'] = CTYPE_UNRESERVED, + ['w'] = CTYPE_UNRESERVED, + ['x'] = CTYPE_UNRESERVED, + ['y'] = CTYPE_UNRESERVED, + ['z'] = CTYPE_UNRESERVED, + ['A'] = CTYPE_UNRESERVED, + ['B'] = CTYPE_UNRESERVED, + ['C'] = CTYPE_UNRESERVED, + ['D'] = CTYPE_UNRESERVED, + ['E'] = CTYPE_UNRESERVED, + ['F'] = CTYPE_UNRESERVED, + ['G'] = CTYPE_UNRESERVED, + ['H'] = CTYPE_UNRESERVED, + ['I'] = CTYPE_UNRESERVED, + ['J'] = CTYPE_UNRESERVED, + ['K'] = CTYPE_UNRESERVED, + ['L'] = CTYPE_UNRESERVED, + ['M'] = CTYPE_UNRESERVED, + ['N'] = CTYPE_UNRESERVED, + ['O'] = CTYPE_UNRESERVED, + ['P'] = CTYPE_UNRESERVED, + ['Q'] = CTYPE_UNRESERVED, + ['R'] = CTYPE_UNRESERVED, + ['S'] = CTYPE_UNRESERVED, + ['T'] = CTYPE_UNRESERVED, + ['U'] = CTYPE_UNRESERVED, + ['V'] = CTYPE_UNRESERVED, + ['W'] = CTYPE_UNRESERVED, + ['X'] = CTYPE_UNRESERVED, + ['Y'] = CTYPE_UNRESERVED, + ['Z'] = CTYPE_UNRESERVED, + + ['0'] = CTYPE_UNRESERVED, + ['1'] = CTYPE_UNRESERVED, + ['2'] = CTYPE_UNRESERVED, + ['3'] = CTYPE_UNRESERVED, + ['4'] = CTYPE_UNRESERVED, + ['5'] = CTYPE_UNRESERVED, + ['6'] = CTYPE_UNRESERVED, + ['7'] = CTYPE_UNRESERVED, + ['8'] = CTYPE_UNRESERVED, + ['9'] = CTYPE_UNRESERVED, + + ['-'] = CTYPE_UNRESERVED, + ['_'] = CTYPE_UNRESERVED, + ['.'] = CTYPE_UNRESERVED, + ['~'] = CTYPE_UNRESERVED, +}; + +static inline int dx(int c) +{ + if (likely(c >= '0' && c <= '9')) + return c - '0'; + if (likely(c >= 'a' && c <= 'f')) + return c - 'a' + 0xa; + if (c >= 'A' && c <= 'F') + return c - 'A' + 0xa; + return -1; +} + +char *blob_cstr_dup(blob_t b) +{ + char *p; + + if (blob_is_null(b)) + return NULL; + + p = malloc(b.len+1); + if (p != NULL) { + memcpy(p, b.ptr, b.len); + p[b.len] = 0; + } + return p; +} + +blob_t blob_dup(blob_t b) +{ + blob_t p; + + if (blob_is_null(b)) + return BLOB_NULL; + + p.ptr = malloc(b.len); + if (p.ptr != NULL) { + memcpy(p.ptr, b.ptr, b.len); + p.len = b.len; + } else { + p.len = 0; + } + return p; +} + +int blob_cmp(blob_t a, blob_t b) +{ + if (a.len != b.len) + return a.len - b.len; + return memcmp(a.ptr, b.ptr, a.len); +} + +unsigned long blob_inet_addr(blob_t b) +{ + unsigned long ip = 0; + int i; + + for (i = 0; i < 3; i++) { + ip += blob_pull_uint(&b, 10); + ip <<= 8; + if (!blob_pull_matching(&b, BLOB_STR("."))) + return 0; + } + ip += blob_pull_uint(&b, 10); + if (b.len != 0) + return 0; + return htonl(ip); +} + + +blob_t blob_pushed(blob_t buffer, blob_t left) +{ + if (buffer.ptr + buffer.len != left.ptr + left.len) + return BLOB_NULL; + return BLOB_PTR_LEN(buffer.ptr, left.ptr - buffer.ptr); +} + +void blob_push(blob_t *b, blob_t d) +{ + if (b->len >= d.len) { + memcpy(b->ptr, d.ptr, d.len); + b->ptr += d.len; + b->len -= d.len; + } else { + *b = BLOB_NULL; + } +} + +void blob_push_lower(blob_t *b, blob_t d) +{ + int i; + + if (b->len < d.len) { + *b = BLOB_NULL; + return; + } + for (i = 0; i < d.len; i++) + b->ptr[i] = tolower(d.ptr[i]); + b->ptr += d.len; + b->len -= d.len; +} + +void blob_push_byte(blob_t *b, unsigned char byte) +{ + if (b->len) { + b->ptr[0] = byte; + b->ptr ++; + b->len --; + } else { + *b = BLOB_NULL; + } +} + +void blob_push_uint(blob_t *to, unsigned int value, int radix) +{ + char buf[64]; + char *ptr = &buf[sizeof(buf)-1]; + + if (value == 0) { + blob_push_byte(to, '0'); + return; + } + + while (value != 0) { + *(ptr--) = xd[value % radix]; + value /= radix; + } + + blob_push(to, BLOB_PTR_PTR(ptr+1, &buf[sizeof(buf)-1])); +} + +void blob_push_ctime(blob_t *to, time_t t) +{ + char buf[128]; + blob_t b; + + ctime_r(&t, buf); + b = BLOB_STRLEN(buf); + b.len--; + blob_push(to, b); +} + +void blob_push_hexdump(blob_t *to, blob_t binary) +{ + char *d; + int i; + + if (blob_is_null(*to)) + return; + + if (to->len < binary.len * 2) { + *to = BLOB_NULL; + return; + } + + for (i = 0, d = to->ptr; i < binary.len; i++) { + *(d++) = xd[(binary.ptr[i] >> 4) & 0xf]; + *(d++) = xd[binary.ptr[i] & 0xf]; + } + to->ptr = d; + to->len -= binary.len * 2; +} + +void blob_push_urldecode(blob_t *to, blob_t url) +{ + blob_t b, orig = *to; + + do { + blob_pull_matching(&url, BLOB_STR("/")); + b = blob_pull_cspn(&url, BLOB_STR("/")); + if (blob_is_null(b) || blob_cmp(b, BLOB_STR(".")) == 0) { + /* skip '.' or two consecutive / */ + } else if (blob_cmp(b, BLOB_STR("..")) == 0) { + /* go up one path component */ + blob_shrink_tail(to, blob_pushed(orig, b), '/'); + } else { + /* copy decoded; FIXME decode percent encoding */ + blob_push_byte(to, '/'); + blob_push(to, b); + } + } while (!blob_is_null(url)); +} + +void blob_push_urlencode(blob_t *to, blob_t url) +{ + unsigned char c; + int i; + + for (i = 0; i < url.len; i++) { + c = url.ptr[i]; + + if (c <= 127 && (chartype[c] & CTYPE_UNRESERVED)) { + blob_push_byte(to, c); + } else { + blob_push_byte(to, '%'); + blob_push_uint(to, c, 16); + } + } +} + +blob_t blob_pull(blob_t *b, int len) +{ + blob_t r; + + if (b->len >= len) { + r = BLOB_PTR_LEN(b->ptr, len); + b->ptr += len; + b->len -= len; + return r; + } + *b = BLOB_NULL; + return BLOB_NULL; +} + +void blob_pull_skip(blob_t *b, int len) +{ + if (b->len >= len) { + b->ptr += len; + b->len -= len; + } else { + *b = BLOB_NULL; + } +} + +int blob_pull_matching(blob_t *b, blob_t e) +{ + if (b->len < e.len) + return 0; + if (memcmp(b->ptr, e.ptr, e.len) != 0) + return 0; + b->ptr += e.len; + b->len -= e.len; + return 1; +} + +unsigned int blob_pull_uint(blob_t *b, int radix) +{ + unsigned int val; + int ch; + + val = 0; + while (b->len && b->ptr[0] != 0) { + ch = dx(b->ptr[0]); + if (ch < 0 || ch >= radix) + break; + val *= radix; + val += ch; + + b->ptr++; + b->len--; + } + + return val; +} + +blob_t blob_pull_spn(blob_t *b, const blob_t reject) +{ + blob_t t = *b; + int i; + + for (i = 0; i < t.len; i++) { + if (memchr(reject.ptr, t.ptr[i], reject.len) == NULL) { + *b = BLOB_PTR_LEN(t.ptr + i, t.len - i); + return BLOB_PTR_LEN(t.ptr, i); + } + } + + *b = BLOB_NULL; + return t; +} + +blob_t blob_pull_cspn(blob_t *b, const blob_t reject) +{ + blob_t t = *b; + int i; + + for (i = 0; i < t.len; i++) { + if (memchr(reject.ptr, t.ptr[i], reject.len) != NULL) { + *b = BLOB_PTR_LEN(t.ptr + i, t.len - i); + return BLOB_PTR_LEN(t.ptr, i); + } + } + + *b = BLOB_NULL; + return t; +} + +blob_t blob_expand_head(blob_t *b, blob_t limits, unsigned char sep) +{ + blob_t t = *b; + blob_t r; + + if (t.ptr < limits.ptr || t.ptr+t.len > limits.ptr+limits.len) + return BLOB_NULL; + while (t.ptr > limits.ptr && t.ptr[-1] == sep) + t.ptr--, t.len++; + + r.ptr = t.ptr; + r.len = 0; + while (t.ptr > limits.ptr && t.ptr[-1] != sep) { + t.ptr--, t.len++; + r.ptr--, r.len++; + } + *b = t; + return r; +} + +blob_t blob_expand_tail(blob_t *b, blob_t limits, unsigned char sep) +{ + blob_t t = *b; + blob_t r; + + if (t.ptr < limits.ptr || t.ptr+t.len > limits.ptr+limits.len) + return BLOB_NULL; + while (t.ptr + t.len < limits.ptr + limits.len && t.ptr[t.len] == sep) + t.len++; + + r.ptr = t.ptr + t.len; + r.len = 0; + while (t.ptr + t.len < limits.ptr + limits.len && t.ptr[t.len] != sep) { + t.len++; + r.len++; + } + *b = t; + return r; +} + +blob_t blob_shrink_tail(blob_t *b, blob_t limits, unsigned char sep) +{ + blob_t t = *b; + blob_t r; + + if (t.ptr <= limits.ptr || t.ptr+t.len > limits.ptr+limits.len) + return BLOB_NULL; + while (t.len && t.ptr[t.len-1] == sep) + t.len--; + + r.ptr = t.ptr; + r.len = 0; + while (t.len && t.ptr[t.len-1] != sep) { + t.len--; + r.ptr--, r.len++; + } + *b = t; + return r; +} |