diff options
Diffstat (limited to 'src/utils.c')
-rw-r--r-- | src/utils.c | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/src/utils.c b/src/utils.c index 5cdef6b..2247151 100644 --- a/src/utils.c +++ b/src/utils.c @@ -80,6 +80,18 @@ xmalloc(size_t size) return result; } +/* Ditto for realloc */ +void * +xrealloc(void *ptr, size_t size) +{ + void *result = realloc(ptr, size); + if (!result) { + msg(MSG_CRITICAL, "Failed to realloc %zu bytes\n", size); + exit(EXIT_FAILURE); + } + return result; +} + /* Ditto for strdup */ char * xstrdup(const char *s) @@ -143,6 +155,19 @@ write_string(const char *string, FILE *to) xfwrite(string, strlen(string) + 1, to); } +/* Get the value of a hex digit */ +static int +xdigitval(int c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'A' && c <= 'F') + return 10 + c - 'A'; + if (c >= 'a' && c <= 'f') + return 10 + c - 'a'; + return -1; +} + /* Check if a character being put into a URL must be encoded */ static int char_url_mustencode(int c) @@ -192,6 +217,15 @@ write_string_url(const char *string, FILE *to) write_char_url(c, to); } +/* Reads a single char from a file */ +int +read_char(const char **from, const char *max) +{ + if (*from >= max) + return EOF; + return *((*from)++); +} + /* Reads an int from a file, using len bytes, in little-endian order */ uint64_t read_int(const char **from, size_t len, const char *max) @@ -211,6 +245,27 @@ read_int(const char **from, size_t len, const char *max) return result; } +/* Reads an int from a file, stored as an ASCII string, to the first non-digit */ +long +read_int_string(const char **from, const char *max, int base) +{ + long result = 0; + int sign = 1, i; + + if (*from < max && **from == '-') { + sign = -1; + *from += 1; + } + + while (*from < max && (i = xdigitval(**from)) >= 0 && i < base) { + result *= base; + result += i; + *from += 1; + } + + return result * sign; +} + /* Reads a binary string from a file */ char * read_binary_string(const char **from, size_t len, const char *max) @@ -229,6 +284,69 @@ read_binary_string(const char **from, size_t len, const char *max) return result; } +/* Reads binary data from a file, which was stored URL-encoded */ +char * +read_binary_url(const char **pfrom, const char *max, ssize_t *plen) +{ + const char *from; + size_t bufsize, len; + char * buf; + int hi, lo; + + from = *pfrom; + bufsize = 32; + buf = xmalloc(bufsize); + len = 0; + + while (from < max) { + if (len == bufsize) { + bufsize *= 2; + buf = xrealloc(buf, bufsize); + } + + if (*from == '%' && (max - from) >= 3) { + /* URL-encoded char - decode */ + from++; + hi = xdigitval(*from++); + lo = xdigitval(*from++); + if (hi < 0 || lo < 0) { + /* Invalid encoding */ + free(buf); + *pfrom = from; + return NULL; + } + if (hi == 0 && lo == 0 && !plen) { + /* NUL in C string? Stop here */ + break; + } + buf[len++] = (hi << 4) + lo; + } + else if (char_url_mustencode(*from)) { + /* Un-encoded char. Stop here */ + break; + } + else { + buf[len++] = *from++; + } + } + + if (plen) { + /* plen is non-NULL means read binary data - return length */ + *plen = len; + } + else { + /* plen is NULL actually means read C string - NUL terminate */ + if (len == bufsize) { + bufsize *= 2; + buf = xrealloc(buf, bufsize); + } + buf[len++] = '\0'; + } + + *pfrom = from; + return buf; +} + /* Reads a normal C string from a file */ char * read_string(const char **from, const char *max) @@ -236,6 +354,13 @@ read_string(const char **from, const char *max) return read_binary_string(from, strlen(*from) + 1, max); } +/* Reads a normal C string from a file, which was stored URL-encoded */ +char * +read_string_url(const char **from, const char *max) +{ + return read_binary_url(from, max, NULL); +} + /* For group caching */ static struct group *gtable = NULL; |