From d8e48a60b0a9a2b025078bf6b38e360e0ec7e23b Mon Sep 17 00:00:00 2001 From: Jan200101 Date: Wed, 29 Jun 2022 18:36:22 +0200 Subject: properly accept character escaping in VDF files --- src/vdf/tests/files/registry.vdf | 28 +++---------- src/vdf/vdf.c | 88 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 85 insertions(+), 31 deletions(-) diff --git a/src/vdf/tests/files/registry.vdf b/src/vdf/tests/files/registry.vdf index 0e400bf..60bdfaf 100644 --- a/src/vdf/tests/files/registry.vdf +++ b/src/vdf/tests/files/registry.vdf @@ -11,34 +11,16 @@ "empty" { } - "slash-test" - { - "key\"string" "value\"string" - } "steamglobal" { "language" "english" } - "Apps" + "escape_test" { - "10090" - { - "installed" "1" - "Updating" "0" - "Running" "0" - } - "1245040" - { - "installed" "1" - "Updating" "0" - "Running" "0" - } - "287700" - { - "installed" "1" - "Updating" "0" - "Running" "0" - } + "double\"quote" "ab\"cd" + "tab\tulator" "ab\tcd" + "new\nline" "ab\ncd" + "back\\slash" "ab\\cd" } } } diff --git a/src/vdf/vdf.c b/src/vdf/vdf.c index 10c3ed1..fc43e8c 100644 --- a/src/vdf/vdf.c +++ b/src/vdf/vdf.c @@ -18,6 +18,77 @@ #define FMT_UNKNOWN_CHAR "Encountered Unknown Character %c (%li)\n" +static char* local_strndup_escape(const char* s, size_t n) +{ + if (!s) + return NULL; + + char* retval = malloc(n + 1); + strncpy(retval, s, n); + retval[n] = '\0'; + + char* head = retval; + char* tail = retval + n; + + while (*head) + { + if (*head == CHAR_BACKSLASH) + { + switch (head[1]) + { + case 'n': + memmove(head, head+1, (size_t)(tail-head)); + *head = CHAR_NEWLINE; + break; + + case 't': + memmove(head, head+1, (size_t)(tail-head)); + *head = CHAR_TAB; + break; + + case CHAR_BACKSLASH: + case CHAR_DOUBLE_QUOTE: + memmove(head, head+1, (size_t)(tail-head)); + break; + } + } + ++head; + } + + return retval; +} + +static void puts_escaped(const char* s) +{ + while (*s) + { + switch(*s) + { + case CHAR_DOUBLE_QUOTE: + printf("\\\""); + break; + + case CHAR_TAB: + printf("\\t"); + break; + + case CHAR_NEWLINE: + printf("\\n"); + break; + + case CHAR_BACKSLASH: + printf("\\\\"); + break; + + default: + printf("%c", *s); + break; + } + + ++s; + } +} + struct vdf_object* vdf_parse_buffer(const char* buffer, size_t size) { if (!buffer) @@ -80,10 +151,8 @@ struct vdf_object* vdf_parse_buffer(const char* buffer, size_t size) break; case VDF_TYPE_STRING: - o->data.data_string.str = malloc(len+1); o->data.data_string.len = len; - strncpy(o->data.data_string.str, buf, len); - o->data.data_string.str[len] = '\0'; + o->data.data_string.str = local_strndup_escape(buf, len); break; default: @@ -111,9 +180,7 @@ struct vdf_object* vdf_parse_buffer(const char* buffer, size_t size) else { size_t len = tail - buf; - o->key = malloc(len+1); - strncpy(o->key, buf, len); - o->key[len] = '\0'; + o->key = local_strndup_escape(buf, len); buf = NULL; } break; @@ -259,7 +326,10 @@ static void vdf_print_object_indent(struct vdf_object* o, int l) for (int k = 0; k < l; ++k) printf("%s", spacing); - printf("\"%s\"", o->key); + printf("\""); + puts_escaped(o->key); + printf("\""); + switch (o->type) { case VDF_TYPE_ARRAY: @@ -280,7 +350,9 @@ static void vdf_print_object_indent(struct vdf_object* o, int l) break; case VDF_TYPE_STRING: - printf("\t\t\"%s\"\n", o->data.data_string.str); + printf("\t\t\""); + puts_escaped(o->data.data_string.str); + printf("\"\n"); break; default: -- cgit v1.2.3