From a93baa212f3c7b57a08cb9084d38994290195d78 Mon Sep 17 00:00:00 2001 From: Jan200101 Date: Sun, 26 Jun 2022 21:39:17 +0200 Subject: add vdf library --- src/CMakeLists.txt | 2 + src/vdf/CMakeLists.txt | 11 ++ src/vdf/vdf.c | 347 +++++++++++++++++++++++++++++++++++++++++++++++++ src/vdf/vdf.h | 75 +++++++++++ 4 files changed, 435 insertions(+) create mode 100644 src/vdf/CMakeLists.txt create mode 100644 src/vdf/vdf.c create mode 100644 src/vdf/vdf.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c48af2d..1e11530 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,6 +2,7 @@ find_package(Libcurl REQUIRED) find_package(JsonC REQUIRED) add_subdirectory(hash) +add_subdirectory(vdf) set(CFLAGS -Wall -Wextra -pedantic @@ -34,6 +35,7 @@ target_include_directories(tvn PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(tvn LINK_PUBLIC ${LIBCURL_LIBRARIES}) target_link_libraries(tvn LINK_PUBLIC ${JSONC_LIBRARIES}) target_link_libraries(tvn LINK_PUBLIC md5) +target_link_libraries(tvn LINK_PUBLIC vdf) if(BUILD_CLI) add_subdirectory(cli) diff --git a/src/vdf/CMakeLists.txt b/src/vdf/CMakeLists.txt new file mode 100644 index 0000000..a3a4387 --- /dev/null +++ b/src/vdf/CMakeLists.txt @@ -0,0 +1,11 @@ + +list(APPEND + VDF_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/vdf.h + ${CMAKE_CURRENT_SOURCE_DIR}/vdf.c +) + +add_library(vdf STATIC ${VDF_SOURCES}) +target_compile_options(vdf PUBLIC ${CFLAGS}) + +target_include_directories(vdf PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/src/vdf/vdf.c b/src/vdf/vdf.c new file mode 100644 index 0000000..160577f --- /dev/null +++ b/src/vdf/vdf.c @@ -0,0 +1,347 @@ +#include +#include +#include +#include +#include +#include + +#include "vdf.h" + +#define CHAR_SPACE ' ' +#define CHAR_TAB '\t' +#define CHAR_NEWLINE '\n' +#define CHAR_DOUBLE_QUOTE '"' +#define CHAR_OPEN_CURLY_BRACKET '{' +#define CHAR_CLOSED_CURLY_BRACKET '}' +#define CHAR_FRONTSLASH '/' +#define CHAR_BACKSLASH '\\' + +#define FMT_UNKNOWN_CHAR "Encountered Unknown Character %c (%li)\n" + + +struct vdf_object* vdf_parse_buffer(const char* buffer, size_t size) +{ + if (!buffer) + return NULL; + + struct vdf_object* root_object = malloc(sizeof(struct vdf_object)); + root_object->key = NULL; + root_object->parent = NULL; + root_object->type = VDF_TYPE_NONE; + + struct vdf_object* o = root_object; + + const char* head = buffer; + const char* tail = head; + + const char* end = buffer + size; + + const char* buf = NULL; + + while (end > tail) + { + switch (*tail) + { + case CHAR_DOUBLE_QUOTE: + if (!buf) + { + buf = tail+1; + } + else if (o->key) + { + size_t len = tail - buf; + size_t digits = 0; + size_t chars = 0; + + for (size_t i = 0; i < len; ++i) + { + if (isdigit(buf[i])) + digits++; + + if (isalpha(buf[i])) + chars++; + } + + if (len && digits == len) + { + o->type = VDF_TYPE_INT; + } + else if (len > 6 && len < 9 && (chars+digits) == len-1 && buf[0] == '#') + { + // TODO + //o->type = VDF_TYPE_COLOR; + o->type = VDF_TYPE_STRING; + } + else + { + o->type = VDF_TYPE_STRING; + } + + switch (o->type) + { + case VDF_TYPE_INT: + o->data.data_int = strtol(buf, NULL, 10); + 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'; + break; + + default: + assert(0); + break; + } + + buf = NULL; + + if (o->parent && o->parent->type == VDF_TYPE_ARRAY) + { + o = o->parent; + assert(o->type == VDF_TYPE_ARRAY); + + o->data.data_array.len++; + o->data.data_array.data_value = realloc(o->data.data_array.data_value, (sizeof(void*)) * (o->data.data_array.len + 1)); + o->data.data_array.data_value[o->data.data_array.len] = malloc(sizeof(struct vdf_object)), + o->data.data_array.data_value[o->data.data_array.len]->parent = o; + + o = o->data.data_array.data_value[o->data.data_array.len]; + o->key = NULL; + o->type = VDF_TYPE_NONE; + } + } + else + { + size_t len = tail - buf; + o->key = strndup(buf, len); + buf = NULL; + } + break; + + case CHAR_OPEN_CURLY_BRACKET: + assert(!buf); + assert(o->type == VDF_TYPE_NONE); + + if (o->parent && o->parent->type == VDF_TYPE_ARRAY) + o->parent->data.data_array.len++; + + o->type = VDF_TYPE_ARRAY; + o->data.data_array.len = 0; + o->data.data_array.data_value = malloc((sizeof(void*)) * (o->data.data_array.len + 1)); + o->data.data_array.data_value[o->data.data_array.len] = malloc(sizeof(struct vdf_object)), + o->data.data_array.data_value[o->data.data_array.len]->parent = o; + + o = o->data.data_array.data_value[o->data.data_array.len]; + o->key = NULL; + o->type = VDF_TYPE_NONE; + break; + + case CHAR_CLOSED_CURLY_BRACKET: + assert(!buf); + + o = o->parent; + assert(o); + if (o->parent) + { + o = o->parent; + assert(o->type == VDF_TYPE_ARRAY); + + o->data.data_array.data_value = realloc(o->data.data_array.data_value, (sizeof(void*)) * (o->data.data_array.len + 1)); + o->data.data_array.data_value[o->data.data_array.len] = malloc(sizeof(struct vdf_object)), + o->data.data_array.data_value[o->data.data_array.len]->parent = o; + + o = o->data.data_array.data_value[o->data.data_array.len]; + o->key = NULL; + o->type = VDF_TYPE_NONE; + } + + break; + + case CHAR_FRONTSLASH: + if (!buf) + while (*tail != '\0' && *tail != CHAR_NEWLINE) + ++tail; + + break; + + default: + case CHAR_NEWLINE: + case CHAR_SPACE: + case CHAR_TAB: + break; + } + ++tail; + } + return root_object; +} + +struct vdf_object* vdf_parse_file(const char* path) +{ + struct vdf_object* o = NULL; + if (!path) + return o; + + FILE* fd = fopen(path, "r"); + if (!fd) + return o; + + fseek(fd, 0L, SEEK_END); + size_t file_size = ftell(fd); + rewind(fd); + + if (file_size) + { + char* buffer = malloc(file_size); + fread(buffer, sizeof(*buffer), file_size, fd); + + o = vdf_parse_buffer(buffer, file_size); + free(buffer); + } + + fclose(fd); + + return o; +} + + +size_t vdf_object_get_array_length(struct vdf_object* o) +{ + assert(o); + assert(o->type == VDF_TYPE_ARRAY); + + return o->data.data_array.len; +} + +struct vdf_object* vdf_object_index_array(struct vdf_object* o, size_t index) +{ + assert(o); + assert(o->type == VDF_TYPE_ARRAY); + assert(o->data.data_array.len > index); + + return o->data.data_array.data_value[index]; +} + +struct vdf_object* vdf_object_index_array_str(struct vdf_object* o, char* str) +{ + assert(o); + assert(str); + assert(o->type == VDF_TYPE_ARRAY); + + for (size_t i = 0; i < o->data.data_array.len; ++i) + { + struct vdf_object* k = o->data.data_array.data_value[i]; + if (!strcmp(k->key, str)) + return k; + } + return NULL; +} + +const char* vdf_object_get_string(struct vdf_object* o) +{ + assert(o->type == VDF_TYPE_STRING); + + return o->data.data_string.str; +} + +int vdf_object_get_int(struct vdf_object* o) +{ + assert(o->type == VDF_TYPE_INT); + + return o->data.data_int; +} + +static void vdf_print_object_indent(struct vdf_object* o, int l) +{ + if (!o) + return; + + char* spacing = "\t"; + + for (int k = 0; k < l; ++k) + printf("%s", spacing); + + printf("\"%s\"", o->key); + switch (o->type) + { + case VDF_TYPE_ARRAY: + puts(""); + for (int k = 0; k < l; ++k) + printf("%s", spacing); + puts("{"); + for (size_t i = 0; i < o->data.data_array.len; ++i) + vdf_print_object_indent(o->data.data_array.data_value[i], l+1); + + for (int k = 0; k < l; ++k) + printf("%s", spacing); + puts("}"); + break; + + default: + case VDF_TYPE_NONE: + case VDF_TYPE_FLOAT: + case VDF_TYPE_PTR: // ? + case VDF_TYPE_COLOR: + assert(0); + break; + + case VDF_TYPE_INT: + printf("\t\t\"%i\"\n", o->data.data_int); + break; + + case VDF_TYPE_STRING: + printf("\t\t\"%s\"\n", o->data.data_string.str); + break; + + case VDF_TYPE_WSTRING: + assert(0); + break; + + } +} + +void vdf_print_object(struct vdf_object* o) +{ + vdf_print_object_indent(o, 0); +} + +void vdf_free_object(struct vdf_object* o) +{ + if (!o) + return; + + switch (o->type) + { + case VDF_TYPE_ARRAY: + for (size_t i = 0; i <= o->data.data_array.len; ++i) + { + vdf_free_object(o->data.data_array.data_value[i]); + } + free(o->data.data_array.data_value); + break; + + default: + case VDF_TYPE_NONE: + case VDF_TYPE_INT: + case VDF_TYPE_FLOAT: + case VDF_TYPE_PTR: // ? + case VDF_TYPE_COLOR: + break; + + case VDF_TYPE_STRING: + if (o->data.data_string.str) + free(o->data.data_string.str); + break; + + case VDF_TYPE_WSTRING: + if (o->data.data_wstring.str) + free(o->data.data_wstring.str); + break; + + } + + if (o->key) + free(o->key); + free(o); +} diff --git a/src/vdf/vdf.h b/src/vdf/vdf.h new file mode 100644 index 0000000..d9755da --- /dev/null +++ b/src/vdf/vdf.h @@ -0,0 +1,75 @@ +#ifndef VDF_H +#define VDF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +enum vdf_data_type +{ + VDF_TYPE_NONE, + VDF_TYPE_ARRAY, + VDF_TYPE_STRING, + VDF_TYPE_INT, + VDF_TYPE_FLOAT, + VDF_TYPE_PTR, + VDF_TYPE_WSTRING, + VDF_TYPE_COLOR +}; + +struct vdf_object; + +union vdf_data { + struct { + struct vdf_object** data_value; + size_t len; + } data_array; + + struct { + char* str; + size_t len; + } data_string; + + int data_int; + float data_float; + + void* data_ptr; // TYPE? + + struct { + wchar_t* str; + size_t len; + } data_wstring; + + uint32_t color; // RGBA +}; + +struct vdf_object +{ + char* key; + struct vdf_object* parent; + + enum vdf_data_type type; + union vdf_data data; +}; + +struct vdf_object* vdf_parse_file(const char* path); + +size_t vdf_object_get_array_length(struct vdf_object* o); +struct vdf_object* vdf_object_index_array(struct vdf_object* o, size_t index); +struct vdf_object* vdf_object_index_array_str(struct vdf_object* o, char* str); + +const char* vdf_object_get_string(struct vdf_object* o); + +int vdf_object_get_int(struct vdf_object* o); + +void vdf_print_object(struct vdf_object* o); +void vdf_free_object(struct vdf_object* o); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file -- cgit v1.2.3