summaryrefslogtreecommitdiff
path: root/src/utils.c
diff options
context:
space:
mode:
authorAdam Spragg <adam@spra.gg>2022-05-17 17:31:48 +0100
committerAdam Spragg <adam@spra.gg>2022-05-18 17:19:47 +0100
commit260fc47f01ef64368721ec93de4cbd988357b32b (patch)
tree551213a3f0ecdff66f525cf4b0a59c349ee898dd /src/utils.c
parentb3c08670f56d7c5ee85dffa1a2faa5e03d2df5a1 (diff)
Add ability to read Format 1 metadata files
Diffstat (limited to 'src/utils.c')
-rw-r--r--src/utils.c125
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;