src/cx/json.h

changeset 937
10123f4d5618
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cx/json.h	Sat Oct 19 17:25:11 2024 +0200
@@ -0,0 +1,299 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2024 Mike Becker, Olaf Wintermann All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * \file json.h
+ * \brief Interface for parsing data from JSON files.
+ * \author Mike Becker
+ * \author Olaf Wintermann
+ * \copyright 2-Clause BSD License
+ */
+
+#ifndef UCX_JSON_H
+#define UCX_JSON_H
+
+#include "common.h"
+#include "string.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum cx_json_token_type {
+    CX_JSON_NO_TOKEN,
+    CX_JSON_TOKEN_ERROR,
+    CX_JSON_TOKEN_BEGIN_ARRAY,
+    CX_JSON_TOKEN_BEGIN_OBJECT,
+    CX_JSON_TOKEN_END_ARRAY,
+    CX_JSON_TOKEN_END_OBJECT,
+    CX_JSON_TOKEN_NAME_SEPARATOR,
+    CX_JSON_TOKEN_VALUE_SEPARATOR,
+    CX_JSON_TOKEN_STRING,
+    CX_JSON_TOKEN_INTEGER,
+    CX_JSON_TOKEN_NUMBER,
+    CX_JSON_TOKEN_LITERAL,
+    CX_JSON_TOKEN_SPACE
+};
+
+enum cx_json_value_type {
+    CX_JSON_NOTHING, // this allows us to always return non-NULL values
+    CX_JSON_OBJECT,
+    CX_JSON_ARRAY,
+    CX_JSON_STRING,
+    CX_JSON_INTEGER, // TODO: the spec does not know integer types
+    CX_JSON_NUMBER,
+    CX_JSON_LITERAL
+};
+
+enum cx_json_literal_type {
+    CX_JSON_NULL,
+    CX_JSON_TRUE,
+    CX_JSON_FALSE
+};
+
+enum cx_json_reader_type {
+    CX_JSON_READER_OBJECT_BEGIN,
+    CX_JSON_READER_OBJECT_END,
+    CX_JSON_READER_ARRAY_BEGIN,
+    CX_JSON_READER_ARRAY_END,
+    CX_JSON_READER_STRING,
+    CX_JSON_READER_INTEGER,
+    CX_JSON_READER_NUMBER,
+    CX_JSON_READER_LITERAL
+};
+
+typedef enum cx_json_token_type CxJsonTokenType;
+typedef enum cx_json_value_type CxJsonValueType;
+typedef enum cx_json_literal_type CxJsonLiteralType;
+typedef enum cx_json_reader_type CxJsonReaderType;
+
+typedef struct cx_json_s CxJson;
+typedef struct cx_json_token_s CxJsonToken;
+
+typedef struct cx_json_value_s CxJsonValue;
+
+typedef struct cx_json_array_s CxJsonArray;
+typedef struct cx_json_object_s CxJsonObject;
+typedef struct cx_mutstr_s CxJsonString;
+typedef struct cx_json_integer_s CxJsonInteger;
+typedef struct cx_json_number_s CxJsonNumber;
+typedef struct cx_json_literal_s CxJsonLiteral;
+
+typedef struct cx_json_obj_value_s CxJsonObjValue;
+
+struct cx_json_token_s {
+    CxJsonTokenType tokentype;
+    const char *content;
+    size_t length;
+    size_t alloc;
+};
+
+struct cx_json_s {
+    const char *buffer;
+    size_t size;
+    size_t pos;
+
+    CxJsonToken uncompleted;
+    int tokenizer_escape;
+
+    int *states;
+    int nstates;
+    int states_alloc;
+
+    CxJsonToken reader_token;
+    CxJsonReaderType reader_type;
+    int value_ready;
+    char *value_name;
+    size_t value_name_len;
+    char *value_str;
+    size_t value_str_len;
+    int64_t value_int;
+    double value_double;
+
+    CxJsonValue **readvalue_stack;
+    int readvalue_nelm;
+    int readvalue_alloc;
+    CxJsonValue *read_value;
+    int readvalue_initialized;
+
+    int reader_array_alloc;
+
+    int error;
+};
+
+struct cx_json_array_s {
+    CxJsonValue **array;
+    size_t alloc;
+    size_t size;
+};
+
+struct cx_json_object_s {
+    CxJsonObjValue *values;
+    size_t alloc;
+    size_t size;
+};
+
+struct cx_json_obj_value_s {
+    char *name;
+    CxJsonValue *value;
+};
+
+// TODO: remove single member structs
+
+struct cx_json_integer_s {
+    int64_t value;
+};
+
+struct cx_json_number_s {
+    double value;
+};
+
+struct cx_json_literal_s {
+    CxJsonLiteralType literal;
+};
+
+struct cx_json_value_s {
+    CxJsonValueType type;
+    union {
+        CxJsonArray array;
+        CxJsonObject object;
+        CxJsonString string;
+        CxJsonInteger integer;
+        CxJsonNumber number;
+        CxJsonLiteral literal;
+    } value;
+};
+
+// TODO: add support for CxAllocator
+
+__attribute__((__nonnull__))
+void cxJsonInit(CxJson *json);
+
+__attribute__((__nonnull__))
+void cxJsonDestroy(CxJson *json);
+
+__attribute__((__nonnull__))
+void cxJsonFill(CxJson *json, const char *buf, size_t len);
+
+// TODO: discuss if it is intentional that cxJsonNext() will usually parse an entire file in one go
+__attribute__((__nonnull__))
+int cxJsonNext(CxJson *json, CxJsonValue **value);
+
+void cxJsonValueFree(CxJsonValue *value);
+
+__attribute__((__nonnull__))
+static inline bool cxJsonIsObject(CxJsonValue *value) {
+    return value->type == CX_JSON_OBJECT;
+}
+
+__attribute__((__nonnull__))
+static inline bool cxJsonIsArray(CxJsonValue *value) {
+    return value->type == CX_JSON_ARRAY;
+}
+
+__attribute__((__nonnull__))
+static inline bool cxJsonIsString(CxJsonValue *value) {
+    return value->type == CX_JSON_STRING;
+}
+
+__attribute__((__nonnull__))
+static inline bool cxJsonIsNumber(CxJsonValue *value) {
+    // TODO: this is not good, because an integer is also a number
+    return value->type == CX_JSON_NUMBER;
+}
+
+__attribute__((__nonnull__))
+static inline bool cxJsonIsInteger(CxJsonValue *value) {
+    return value->type == CX_JSON_INTEGER;
+}
+
+__attribute__((__nonnull__))
+static inline bool cxJsonIsLiteral(CxJsonValue *value) {
+    return value->type == CX_JSON_LITERAL;
+}
+
+__attribute__((__nonnull__))
+static inline bool cxJsonIsBool(CxJsonValue *value) {
+    return cxJsonIsLiteral(value) && value->value.literal.literal != CX_JSON_NULL;
+}
+
+__attribute__((__nonnull__))
+static inline bool cxJsonIsTrue(CxJsonValue *value) {
+    return cxJsonIsLiteral(value) && value->value.literal.literal == CX_JSON_TRUE;
+}
+
+__attribute__((__nonnull__))
+static inline bool cxJsonIsFalse(CxJsonValue *value) {
+    return cxJsonIsLiteral(value) && value->value.literal.literal == CX_JSON_FALSE;
+}
+
+__attribute__((__nonnull__))
+static inline bool cxJsonIsNull(CxJsonValue *value) {
+    return cxJsonIsLiteral(value) && value->value.literal.literal == CX_JSON_NULL;
+}
+
+__attribute__((__nonnull__))
+static inline cxmutstr cxJsonAsString(CxJsonValue *value) {
+    // TODO: do we need a separate method to return this directly as cxstring?
+    return value->value.string;
+}
+
+__attribute__((__nonnull__))
+static inline double cxJsonAsDouble(CxJsonValue *value) {
+    return value->value.number.value;
+}
+
+__attribute__((__nonnull__))
+static inline int64_t cxJsonAsInteger(CxJsonValue *value) {
+    return value->value.integer.value;
+}
+
+__attribute__((__nonnull__))
+static inline bool cxJsonAsBool(CxJsonValue *value) {
+    return value->value.literal.literal == CX_JSON_TRUE;
+}
+
+__attribute__((__nonnull__))
+static inline size_t cxJsonArrSize(CxJsonValue *value) {
+    return value->value.array.size;
+}
+
+__attribute__((__nonnull__, __returns_nonnull__))
+CxJsonValue *cxJsonArrGet(CxJsonValue *value, size_t index);
+
+// TODO: add cxJsonArrIter()
+
+// TODO: implement cxJsonObjGet as a _Generic with support for cxstring
+__attribute__((__nonnull__, __returns_nonnull__))
+CxJsonValue *cxJsonObjGet(CxJsonValue *value, const char* name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UCX_JSON_H */
+

mercurial