diff --git a/configure.ac b/configure.ac index bd84123..43a0f2a 100644 --- a/configure.ac +++ b/configure.ac @@ -16,6 +16,26 @@ PKGPATH=$($PKG_CONFIG --variable pc_path pkg-config) AC_PROG_CXX AC_PROG_CC +JSONC_CFLAGS="" +JSONC_LDADD="" +JSONC_LDFLAGS="" +JANSSON_CFLAGS="" +JANSSON_LDADD="" +JANSSON_LDFLAGS="" +CJSON_CFLAGS="" +CJSON_LDADD="" +CJSON_LDFLAGS="" +JSONCPP_CFLAGS="" +JSONCPP_LDADD="" +JSONCPP_LDFLAGS="" +SIMDJSON_CFLAGS="" +SIMDJSON_LDADD="" +SIMDJSON_LDFLAGS="" +YYJSON_CFLAGS="" +YYJSON_LDADD="" +YYJSON_LDFLAGS="" +GLAZE_CFLAGS="" + # Verbose output AC_ARG_ENABLE(verbose-output, AS_HELP_STRING([--enable-verbose-output], @@ -164,6 +184,253 @@ fi AM_CONDITIONAL([HAVE_NLOHMANNJSON], [test "x$enable_nlohmannjson" = "xyes"]) #dnl End check for nlohmannjson +dnl Check if we want to use json-c or not +AC_MSG_CHECKING([whether to use json-c]) +AC_ARG_WITH( + [jsonc], + [AS_HELP_STRING([--with-jsonc], [Enable json-c (default is enabled if exists)])], + [case "$withval" in + yes) wantjsonc=yes ;; + no) wantjsonc=no; AC_DEFINE([HAVE_JSONC], [0], [Mark that user does not want json-c]) ;; + *) AC_MSG_ERROR([Invalid value for --with-feature: $withval]) ;; + esac], + [wantjsonc="notset"] +) + +if test "$wantjsonc" != "no"; then + PKG_CHECK_MODULES([JSONC], [json-c], [ + JSONC_CFLAGS="$JSONC_CFLAGS" + JSONC_LDADD="$JSONC_LIBS" + AC_DEFINE([HAVE_JSONC], [1], [Mark that system has json-c]) + ], [ + AC_MSG_ERROR([json-c was requested but not found via pkg-config. Install json-c or disable with --with-jsonc=no]) + ]) +fi + +dnl Check if we want to use jansson or not +AC_MSG_CHECKING([whether to use jansson]) +AC_ARG_WITH( + [jansson], + [AS_HELP_STRING([--with-jansson], [Enable jansson (default is enabled if exists)])], + [case "$withval" in + yes) wantjansson=yes ;; + no) wantjansson=no; AC_DEFINE([HAVE_JANSSON], [0], [Mark that user does not want jansson]) ;; + *) AC_MSG_ERROR([Invalid value for --with-feature: $withval]) ;; + esac], + [wantjansson="notset"] +) + +if test "$wantjansson" != "no"; then + PKG_CHECK_MODULES([JANSSON], [jansson], [ + JANSSON_CFLAGS="$JANSSON_CFLAGS" + JANSSON_LDADD="$JANSSON_LIBS" + AC_DEFINE([HAVE_JANSSON], [1], [Mark that system has jansson]) + ], [ + AC_MSG_ERROR([jansson was requested but not found via pkg-config. Install jansson or disable with --with-jansson=no]) + ]) +fi + +dnl Check if we want to use cJSON or not +AC_MSG_CHECKING([whether to use cJSON]) +AC_ARG_WITH( + [cjson], + [AS_HELP_STRING([--with-cjson], [Enable cJSON (default is enabled if exists)])], + [case "$withval" in + yes) wantcjson=yes ;; + no) wantcjson=no; AC_DEFINE([HAVE_CJSON], [0], [Mark that user does not want cJSON]) ;; + *) AC_MSG_ERROR([Invalid value for --with-feature: $withval]) ;; + esac], + [wantcjson="notset"] +) + +if test "$wantcjson" != "no"; then + PKG_CHECK_MODULES([CJSON], [libcjson], [ + CJSON_CFLAGS="$CJSON_CFLAGS" + CJSON_LDADD="$CJSON_LIBS" + AC_DEFINE([HAVE_CJSON], [1], [Mark that system has cJSON]) + ], [ + AC_MSG_ERROR([cJSON was requested but not found via pkg-config as libcjson. Install libcjson or disable with --with-cjson=no]) + ]) +fi + +dnl Check if we want to use jsoncpp or not +AC_MSG_CHECKING([whether to use jsoncpp]) +AC_ARG_WITH( + [jsoncpp], + [AS_HELP_STRING([--with-jsoncpp], [Enable jsoncpp (default is enabled if exists)])], + [case "$withval" in + yes) wantjsoncpp=yes ;; + no) wantjsoncpp=no; AC_DEFINE([HAVE_JSONCPP], [0], [Mark that user does not want JsonCpp]) ;; + *) AC_MSG_ERROR([Invalid value for --with-feature: $withval]) ;; + esac], + [wantjsoncpp="notset"] +) + +if test "$wantjsoncpp" != "no"; then + PKG_CHECK_MODULES([JSONCPP], [jsoncpp], [ + JSONCPP_CFLAGS="$JSONCPP_CFLAGS" + JSONCPP_LDADD="$JSONCPP_LIBS" + AC_DEFINE([HAVE_JSONCPP], [1], [Mark that system has JsonCpp]) + ], [ + AC_LANG_PUSH([C++]) + jsoncpp_header="no" + AC_CHECK_HEADERS([json/json.h], [jsoncpp_header="json/json.h"]) + if test "$jsoncpp_header" = "no"; then + AC_CHECK_HEADERS([jsoncpp/json/json.h], [ + jsoncpp_header="jsoncpp/json/json.h" + JSONCPP_CFLAGS="-I/usr/include/jsoncpp" + ]) + fi + if test "$jsoncpp_header" = "no"; then + AC_MSG_ERROR([JsonCpp header not found (tried json/json.h and jsoncpp/json/json.h). Install jsoncpp development headers or disable with --with-jsoncpp=no]) + fi + old_LIBS="$LIBS" + LIBS="$LIBS -ljsoncpp" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[#include <$jsoncpp_header>]], [[Json::Value root; return root.isNull() ? 0 : 1;]])], + [ + JSONCPP_LDADD="-ljsoncpp" + AC_DEFINE([HAVE_JSONCPP], [1], [Mark that system has JsonCpp]) + ], + [AC_MSG_ERROR([JsonCpp library not found. Install libjsoncpp or disable with --with-jsoncpp=no])] + ) + LIBS="$old_LIBS" + AC_LANG_POP([C++]) + ]) +fi + + + +dnl Check if we want to use simdjson or not +AC_MSG_CHECKING([whether to use simdjson]) +AC_ARG_WITH( + [simdjson], + [AS_HELP_STRING([--with-simdjson], [Enable simdjson (default is enabled if exists)])], + [case "$withval" in + yes) wantsimdjson=yes ;; + no) wantsimdjson=no; AC_DEFINE([HAVE_SIMDJSON], [0], [Mark that user does not want simdjson]) ;; + *) AC_MSG_ERROR([Invalid value for --with-feature: $withval]) ;; + esac], + [wantsimdjson="notset"] +) + +if test "$wantsimdjson" != "no"; then + PKG_CHECK_MODULES([SIMDJSON], [simdjson], [ + SIMDJSON_CFLAGS="$SIMDJSON_CFLAGS" + SIMDJSON_LDADD="$SIMDJSON_LIBS" + AC_DEFINE([HAVE_SIMDJSON], [1], [Mark that system has simdjson]) + ], [ + AC_LANG_PUSH([C++]) + AC_CHECK_HEADERS([simdjson.h], [], + [AC_MSG_ERROR([simdjson.h not found. Install simdjson headers or disable with --with-simdjson=no])] + ) + old_LIBS="$LIBS" + LIBS="$LIBS -lsimdjson" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[#include ]], [[simdjson::ondemand::parser parser; return 0;]])], + [ + SIMDJSON_LDADD="-lsimdjson" + AC_DEFINE([HAVE_SIMDJSON], [1], [Mark that system has simdjson]) + ], + [AC_MSG_ERROR([simdjson library not found. Install libsimdjson or disable with --with-simdjson=no])] + ) + LIBS="$old_LIBS" + AC_LANG_POP([C++]) + ]) +fi + +dnl Check if we want to use yyjson or not +AC_MSG_CHECKING([whether to use yyjson]) +AC_ARG_WITH( + [yyjson], + [AS_HELP_STRING([--with-yyjson], [Enable yyjson (default is enabled if exists)])], + [case "$withval" in + yes) wantyyjson=yes ;; + no) wantyyjson=no; AC_DEFINE([HAVE_YYJSON], [0], [Mark that user does not want yyjson]) ;; + *) AC_MSG_ERROR([Invalid value for --with-feature: $withval]) ;; + esac], + [wantyyjson="notset"] +) + +if test "$wantyyjson" != "no"; then + PKG_CHECK_MODULES([YYJSON], [yyjson], [ + YYJSON_CFLAGS="$YYJSON_CFLAGS" + YYJSON_LDADD="$YYJSON_LIBS" + AC_DEFINE([HAVE_YYJSON], [1], [Mark that system has yyjson]) + ], [ + AC_MSG_ERROR([yyjson was requested but not found via pkg-config. Install yyjson or disable with --with-yyjson=no]) + ]) +fi + +dnl Check if we want to use glaze or not +AC_MSG_CHECKING([whether to use glaze]) +AC_ARG_WITH( + [glaze], + [AS_HELP_STRING([--with-glaze], [Enable glaze (default is enabled if exists)])], + [case "$withval" in + yes) wantglaze=yes ;; + no) wantglaze=no; AC_DEFINE([HAVE_GLAZE], [0], [Mark that user does not want glaze]) ;; + *) AC_MSG_ERROR([Invalid value for --with-feature: $withval]) ;; + esac], + [wantglaze="notset"] +) + +if test "$wantglaze" != "no"; then + AC_LANG_PUSH([C++]) + AC_MSG_CHECKING([for usable glaze/glaze.hpp with C++ compiler]) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#include ]], [[return 0;]])], + [AC_MSG_RESULT([yes])], + [ + AC_MSG_RESULT([no]) + AC_MSG_ERROR([glaze/glaze.hpp not found or not compilable with C++. Install glaze headers or disable with --with-glaze=no]) + ] + ) + AC_LANG_POP([C++]) + AC_DEFINE([HAVE_GLAZE], [1], [Mark that system has glaze]) +fi + +dnl Check if we want to use jsoncons or not +AC_MSG_CHECKING([whether to use jsoncons]) +AC_ARG_WITH( + [jsoncons], + [AS_HELP_STRING([--with-jsoncons], [Enable jsoncons (default is enabled if exists)])], + [case "$withval" in + yes) wantjsoncons=yes ;; + no) wantjsoncons=no; AC_DEFINE([HAVE_JSONCONS], [0], [Mark that user does not want jsoncons]) ;; + *) AC_MSG_ERROR([Invalid value for --with-feature: $withval]) ;; + esac], + [wantjsoncons="notset"] +) + +if test "$wantjsoncons" != "no"; then + AC_LANG_PUSH([C++]) + AC_CHECK_HEADERS([jsoncons/json.hpp], [], + [AC_MSG_ERROR([jsoncons/json.hpp not found. Install jsoncons headers or disable with --with-jsoncons=no])] + ) + AC_LANG_POP([C++]) + AC_DEFINE([HAVE_JSONCONS], [1], [Mark that system has jsoncons]) +fi + +AC_SUBST(JSONC_CFLAGS) +AC_SUBST(JSONC_LDADD) +AC_SUBST(JSONC_LDFLAGS) +AC_SUBST(JANSSON_CFLAGS) +AC_SUBST(JANSSON_LDADD) +AC_SUBST(JANSSON_LDFLAGS) +AC_SUBST(CJSON_CFLAGS) +AC_SUBST(CJSON_LDADD) +AC_SUBST(CJSON_LDFLAGS) +AC_SUBST(JSONCPP_CFLAGS) +AC_SUBST(JSONCPP_LDADD) +AC_SUBST(JSONCPP_LDFLAGS) +AC_SUBST(SIMDJSON_CFLAGS) +AC_SUBST(SIMDJSON_LDADD) +AC_SUBST(SIMDJSON_LDFLAGS) +AC_SUBST(YYJSON_CFLAGS) +AC_SUBST(YYJSON_LDADD) +AC_SUBST(YYJSON_LDFLAGS) +AC_SUBST(GLAZE_CFLAGS) AC_ARG_WITH( [file-buffer-size], diff --git a/src/Makefile.am b/src/Makefile.am index 6a819ab..e83fe8b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,9 +1,11 @@ AM_CXXFLAGS = -Wall -g -O0 -std=c++17 -fPIC AM_CFLAGS = -Wall -g -O0 -AM_LDFLAGS= $(YAJL_LDFLAGS) +AM_LDFLAGS= $(YAJL_LDFLAGS) $(JSONC_LDFLAGS) $(JANSSON_LDFLAGS) $(CJSON_LDFLAGS) $(JSONCPP_LDFLAGS) $(SIMDJSON_LDFLAGS) $(YYJSON_LDFLAGS) bin_PROGRAMS = jsonbench -jsonbench_SOURCES = yajlparser.c rjparser.cpp nlparser.cpp jsonbench.c -jsonbench_CFLAGS = $(AM_CFLAGS) $(YAJL_CFLAGS) -jsonbench_LDADD = $(YAJL_LDADD) +jsonbench_SOURCES = yajlparser.c rjparser.cpp nlparser.cpp jsoncparser.c janssonparser.c cjsonparser.c jsoncppparser.cpp jsonconsparser.cpp simdjsonparser.cpp yyjsonparser.c glazeparser.cpp jsonbench.c +jsonbench_CPPFLAGS = $(YAJL_CFLAGS) $(JSONC_CFLAGS) $(JANSSON_CFLAGS) $(CJSON_CFLAGS) $(JSONCPP_CFLAGS) $(SIMDJSON_CFLAGS) $(YYJSON_CFLAGS) $(GLAZE_CFLAGS) +jsonbench_CFLAGS = $(AM_CFLAGS) +jsonbench_CXXFLAGS = $(AM_CXXFLAGS) +jsonbench_LDADD = $(YAJL_LDADD) $(JSONC_LDADD) $(JANSSON_LDADD) $(CJSON_LDADD) $(JSONCPP_LDADD) $(SIMDJSON_LDADD) $(YYJSON_LDADD) diff --git a/src/cjsonparser.c b/src/cjsonparser.c new file mode 100644 index 0000000..32a21d6 --- /dev/null +++ b/src/cjsonparser.c @@ -0,0 +1,125 @@ +#include "cjsonparser.h" + +#if HAVE_CJSON + +#include +#include +#include +#include +#include + +struct cjson_parser { + int silence; +}; + +static int read_whole_file(const char *filename, char **content, long *length, char **error_msg) { + FILE *fp = fopen(filename, "rb"); + if (fp == NULL) { + *error_msg = strdup("Unable to open JSON file"); + return 1; + } + + if (fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + *error_msg = strdup("Unable to seek JSON file"); + return 1; + } + + long len = ftell(fp); + if (len < 0) { + fclose(fp); + *error_msg = strdup("Unable to measure JSON file"); + return 1; + } + rewind(fp); + + char *buffer = (char *)malloc((size_t)len + 1U); + if (buffer == NULL) { + fclose(fp); + *error_msg = strdup("Unable to allocate JSON buffer"); + return 1; + } + + size_t read_len = fread(buffer, 1, (size_t)len, fp); + fclose(fp); + if (read_len != (size_t)len) { + free(buffer); + *error_msg = strdup("Unable to read entire JSON file"); + return 1; + } + + buffer[len] = '\0'; + *content = buffer; + *length = len; + return 0; +} + +int cjson_json_init(cjson_parser **parser, char **error_msg) { + assert(parser != NULL); + assert(error_msg != NULL); + + *parser = (cjson_parser *)calloc(1, sizeof(cjson_parser)); + if (*parser == NULL) { + *error_msg = strdup("Unable to allocate cJSON parser"); + return 1; + } + + *error_msg = NULL; + return 0; +} + +int cjson_parse_file(cjson_parser *parser, const char *filename, char **error_msg) { + (void)parser; + if (filename == NULL || error_msg == NULL) { + return -1; + } + + char *content = NULL; + long length = 0; + int rc = read_whole_file(filename, &content, &length, error_msg); + if (rc != 0) { + return 2; + } + + cJSON *root = cJSON_Parse(content); + free(content); + + if (root == NULL) { + const char *cjson_error = cJSON_GetErrorPtr(); + if (cjson_error != NULL) { + *error_msg = strdup(cjson_error); + } else { + *error_msg = strdup("cJSON_Parse failed"); + } + return 2; + } + + cJSON_Delete(root); + return 0; +} + +int cjson_set_max_depth(cjson_parser *parser, double max_depth) { + (void)parser; + (void)max_depth; + return 0; +} + +int cjson_set_max_arg_num(cjson_parser *parser, double max_arg_num) { + (void)parser; + (void)max_arg_num; + return 0; +} + +int cjson_set_silence(cjson_parser *parser, int silence) { + if (parser != NULL) { + parser->silence = silence; + } + return 0; +} + +int cjson_json_cleanup(cjson_parser *parser) { + free(parser); + return 0; +} + +#endif diff --git a/src/cjsonparser.h b/src/cjsonparser.h new file mode 100644 index 0000000..5530fac --- /dev/null +++ b/src/cjsonparser.h @@ -0,0 +1,19 @@ +#ifndef CJSON_PARSER_H +#define CJSON_PARSER_H + +#include "../config.h" + +#if HAVE_CJSON + +typedef struct cjson_parser cjson_parser; + +int cjson_json_init(cjson_parser **parser, char **error_msg); +int cjson_parse_file(cjson_parser *parser, const char *filename, char **error_msg); +int cjson_set_max_depth(cjson_parser *parser, double max_depth); +int cjson_set_max_arg_num(cjson_parser *parser, double max_arg_num); +int cjson_set_silence(cjson_parser *parser, int silence); +int cjson_json_cleanup(cjson_parser *parser); + +#endif + +#endif diff --git a/src/glazeparser.cpp b/src/glazeparser.cpp new file mode 100644 index 0000000..0ca4399 --- /dev/null +++ b/src/glazeparser.cpp @@ -0,0 +1,83 @@ +#include "glazeparser.h" + +#if HAVE_GLAZE + +#include +#include +#include +#include +#include +#include + +struct glaze_parser { + int silence; +}; + +extern "C" int glaze_json_init(glaze_parser **parser, char **error_msg) { + if (parser == nullptr || error_msg == nullptr) { + return -1; + } + + try { + *parser = new glaze_parser{}; + } catch (const std::bad_alloc&) { + *parser = nullptr; + *error_msg = strdup("Unable to allocate glaze parser"); + return 1; + } + + *error_msg = nullptr; + return 0; +} + +extern "C" int glaze_parse_file(glaze_parser *parser, const char *filename, char **error_msg) { + (void)parser; + if (filename == nullptr || error_msg == nullptr) { + return -1; + } + + std::ifstream input(filename); + if (!input.is_open()) { + *error_msg = strdup("Unable to open JSON file"); + return 2; + } + + std::ostringstream oss; + oss << input.rdbuf(); + std::string content = oss.str(); + + glz::json_t doc; + const auto ec = glz::read_json(doc, content); + if (ec) { + *error_msg = strdup("glz::read_json failed"); + return 2; + } + + return 0; +} + +extern "C" int glaze_set_max_depth(glaze_parser *parser, double max_depth) { + (void)parser; + (void)max_depth; + return 0; +} + +extern "C" int glaze_set_max_arg_num(glaze_parser *parser, double max_arg_num) { + (void)parser; + (void)max_arg_num; + return 0; +} + +extern "C" int glaze_set_silence(glaze_parser *parser, int silence) { + if (parser != nullptr) { + parser->silence = silence; + } + return 0; +} + +extern "C" int glaze_json_cleanup(glaze_parser *parser) { + delete parser; + return 0; +} + +#endif diff --git a/src/glazeparser.h b/src/glazeparser.h new file mode 100644 index 0000000..756c4ad --- /dev/null +++ b/src/glazeparser.h @@ -0,0 +1,27 @@ +#ifndef GLAZE_PARSER_H +#define GLAZE_PARSER_H + +#include "../config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if HAVE_GLAZE + +typedef struct glaze_parser glaze_parser; + +int glaze_json_init(glaze_parser **parser, char **error_msg); +int glaze_parse_file(glaze_parser *parser, const char *filename, char **error_msg); +int glaze_set_max_depth(glaze_parser *parser, double max_depth); +int glaze_set_max_arg_num(glaze_parser *parser, double max_arg_num); +int glaze_set_silence(glaze_parser *parser, int silence); +int glaze_json_cleanup(glaze_parser *parser); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/janssonparser.c b/src/janssonparser.c new file mode 100644 index 0000000..e14d9af --- /dev/null +++ b/src/janssonparser.c @@ -0,0 +1,69 @@ +#include "janssonparser.h" + +#if HAVE_JANSSON + +#include +#include +#include +#include + +struct jansson_parser { + int silence; +}; + +int jansson_json_init(jansson_parser **parser, char **error_msg) { + assert(parser != NULL); + assert(error_msg != NULL); + + *parser = (jansson_parser *)calloc(1, sizeof(jansson_parser)); + if (*parser == NULL) { + *error_msg = strdup("Unable to allocate Jansson parser"); + return 1; + } + + *error_msg = NULL; + return 0; +} + +int jansson_parse_file(jansson_parser *parser, const char *filename, char **error_msg) { + (void)parser; + if (filename == NULL || error_msg == NULL) { + return -1; + } + + json_error_t jerror; + json_t *root = json_load_file(filename, 0, &jerror); + if (root == NULL) { + *error_msg = strdup(jerror.text); + return 2; + } + + json_decref(root); + return 0; +} + +int jansson_set_max_depth(jansson_parser *parser, double max_depth) { + (void)parser; + (void)max_depth; + return 0; +} + +int jansson_set_max_arg_num(jansson_parser *parser, double max_arg_num) { + (void)parser; + (void)max_arg_num; + return 0; +} + +int jansson_set_silence(jansson_parser *parser, int silence) { + if (parser != NULL) { + parser->silence = silence; + } + return 0; +} + +int jansson_json_cleanup(jansson_parser *parser) { + free(parser); + return 0; +} + +#endif diff --git a/src/janssonparser.h b/src/janssonparser.h new file mode 100644 index 0000000..2e326c9 --- /dev/null +++ b/src/janssonparser.h @@ -0,0 +1,19 @@ +#ifndef JANSSON_PARSER_H +#define JANSSON_PARSER_H + +#include "../config.h" + +#if HAVE_JANSSON + +typedef struct jansson_parser jansson_parser; + +int jansson_json_init(jansson_parser **parser, char **error_msg); +int jansson_parse_file(jansson_parser *parser, const char *filename, char **error_msg); +int jansson_set_max_depth(jansson_parser *parser, double max_depth); +int jansson_set_max_arg_num(jansson_parser *parser, double max_arg_num); +int jansson_set_silence(jansson_parser *parser, int silence); +int jansson_json_cleanup(jansson_parser *parser); + +#endif + +#endif diff --git a/src/jsonbench.c b/src/jsonbench.c index 0ab500e..37131eb 100644 --- a/src/jsonbench.c +++ b/src/jsonbench.c @@ -3,6 +3,14 @@ #include "yajlparser.h" #include "rjparser.h" #include "nlparser.h" +#include "jsoncparser.h" +#include "janssonparser.h" +#include "cjsonparser.h" +#include "jsoncppparser.h" +#include "jsonconsparser.h" +#include "simdjsonparser.h" +#include "yyjsonparser.h" +#include "glazeparser.h" #include #include #include @@ -32,7 +40,7 @@ static inline void timespec_diff(const struct timespec *a, const struct timespec } } -static char available_engines[10][20] = {""}; +static char available_engines[16][20] = {""}; static int engine_count = 0; static void showhelp(void) { @@ -99,16 +107,40 @@ int main(int argc, char ** argv) { int silence = 0; struct timespec ts_before, ts_after, ts_diff; -#ifdef HAVE_YAJL +#if HAVE_YAJL strcpy(available_engines[engine_count++], "YAJL"); #endif -#ifdef HAVE_RAPIDJSON +#if HAVE_RAPIDJSON strcpy(available_engines[engine_count++], "RAPIDJSON"); #endif -#ifdef HAVE_NLOHMANNJSON +#if HAVE_NLOHMANNJSON strcpy(available_engines[engine_count++], "NLOHMANNJSON"); +#endif +#if HAVE_JSONC +strcpy(available_engines[engine_count++], "JSONC"); +#endif +#if HAVE_JANSSON +strcpy(available_engines[engine_count++], "JANSSON"); +#endif +#if HAVE_CJSON +strcpy(available_engines[engine_count++], "CJSON"); +#endif +#if HAVE_JSONCPP +strcpy(available_engines[engine_count++], "JSONCPP"); +#endif +#if HAVE_JSONCONS +strcpy(available_engines[engine_count++], "JSONCONS"); +#endif +#if HAVE_SIMDJSON +strcpy(available_engines[engine_count++], "SIMDJSON"); +#endif +#if HAVE_YYJSON +strcpy(available_engines[engine_count++], "YYJSON"); +#endif +#if HAVE_GLAZE +strcpy(available_engines[engine_count++], "GLAZE"); #endif while ((c = getopt(argc, argv, "he:a:d:s")) != -1) { @@ -122,9 +154,10 @@ strcpy(available_engines[engine_count++], "NLOHMANNJSON"); fprintf(stderr, "Memory allocation error\n"); return EXIT_FAILURE; } - int i = 0; + int i = engine_count; for(int e = 0; e < engine_count; e++) { if (strcmp(jsonengine, available_engines[e]) == 0) { + i = e; break; } } @@ -170,17 +203,62 @@ strcpy(available_engines[engine_count++], "NLOHMANNJSON"); return EXIT_FAILURE; } - int rc = read_file(jsonfile, data); - if (rc == 0) { - printf("Zero character read from file\n"); - return EXIT_FAILURE; + int file_based_parser = 0; +#if HAVE_JSONC + if (strcmp(jsonengine, "JSONC") == 0) { + file_based_parser = 1; } - else if (rc < 0) { - printf("Error reading file\n"); - return EXIT_FAILURE; +#endif +#if HAVE_JANSSON + if (strcmp(jsonengine, "JANSSON") == 0) { + file_based_parser = 1; } - else { - length = rc; +#endif +#if HAVE_CJSON + if (strcmp(jsonengine, "CJSON") == 0) { + file_based_parser = 1; + } +#endif +#if HAVE_JSONCPP + if (strcmp(jsonengine, "JSONCPP") == 0) { + file_based_parser = 1; + } +#endif +#if HAVE_JSONCONS + if (strcmp(jsonengine, "JSONCONS") == 0) { + file_based_parser = 1; + } +#endif +#if HAVE_SIMDJSON + if (strcmp(jsonengine, "SIMDJSON") == 0) { + file_based_parser = 1; + } +#endif +#if HAVE_YYJSON + if (strcmp(jsonengine, "YYJSON") == 0) { + file_based_parser = 1; + } +#endif +#if HAVE_GLAZE + if (strcmp(jsonengine, "GLAZE") == 0) { + file_based_parser = 1; + } +#endif + + int rc = 0; + if (!file_based_parser) { + rc = read_file(jsonfile, data); + if (rc == 0) { + printf("Zero character read from file\n"); + return EXIT_FAILURE; + } + else if (rc < 0) { + printf("Error reading file\n"); + return EXIT_FAILURE; + } + else { + length = rc; + } } #if HAVE_YAJL if (strcmp(jsonengine, "YAJL") == 0) { @@ -272,6 +350,198 @@ strcpy(available_engines[engine_count++], "NLOHMANNJSON"); } } +#endif +#if HAVE_JSONC + if (strcmp(jsonengine, "JSONC") == 0) { + jsonc_parser *json = NULL; + jsonc_json_init(&json, &error_msg); + jsonc_set_max_depth(json, depth_limit); + jsonc_set_max_arg_num(json, arg_limit); + jsonc_set_silence(json, silence); + + clock_gettime(CLOCK_REALTIME, &ts_before); + rc = jsonc_parse_file(json, jsonfile, &error_msg); + if (rc != 0) { + fprintf(stderr, "Parse failed with code %d\n", rc); + fprintf(stderr, "Error: %s\n", error_msg); + free(error_msg); + return 3; + } + clock_gettime(CLOCK_REALTIME, &ts_after); + ts_diff.tv_sec = 0; + ts_diff.tv_nsec = 0; + timespec_diff(&ts_after, &ts_before, &ts_diff); + jsonc_json_cleanup(json); + printf("\nTime: %ld.%09ld sec\n\n", (long)ts_diff.tv_sec, ts_diff.tv_nsec); + } +#endif +#if HAVE_JANSSON + if (strcmp(jsonengine, "JANSSON") == 0) { + jansson_parser *json = NULL; + jansson_json_init(&json, &error_msg); + jansson_set_max_depth(json, depth_limit); + jansson_set_max_arg_num(json, arg_limit); + jansson_set_silence(json, silence); + + clock_gettime(CLOCK_REALTIME, &ts_before); + rc = jansson_parse_file(json, jsonfile, &error_msg); + if (rc != 0) { + fprintf(stderr, "Parse failed with code %d\n", rc); + fprintf(stderr, "Error: %s\n", error_msg); + free(error_msg); + return 3; + } + clock_gettime(CLOCK_REALTIME, &ts_after); + ts_diff.tv_sec = 0; + ts_diff.tv_nsec = 0; + timespec_diff(&ts_after, &ts_before, &ts_diff); + jansson_json_cleanup(json); + printf("\nTime: %ld.%09ld sec\n\n", (long)ts_diff.tv_sec, ts_diff.tv_nsec); + } +#endif +#if HAVE_CJSON + if (strcmp(jsonengine, "CJSON") == 0) { + cjson_parser *json = NULL; + cjson_json_init(&json, &error_msg); + cjson_set_max_depth(json, depth_limit); + cjson_set_max_arg_num(json, arg_limit); + cjson_set_silence(json, silence); + + clock_gettime(CLOCK_REALTIME, &ts_before); + rc = cjson_parse_file(json, jsonfile, &error_msg); + if (rc != 0) { + fprintf(stderr, "Parse failed with code %d\n", rc); + fprintf(stderr, "Error: %s\n", error_msg); + free(error_msg); + return 3; + } + clock_gettime(CLOCK_REALTIME, &ts_after); + ts_diff.tv_sec = 0; + ts_diff.tv_nsec = 0; + timespec_diff(&ts_after, &ts_before, &ts_diff); + cjson_json_cleanup(json); + printf("\nTime: %ld.%09ld sec\n\n", (long)ts_diff.tv_sec, ts_diff.tv_nsec); + } +#endif +#if HAVE_JSONCPP + if (strcmp(jsonengine, "JSONCPP") == 0) { + jsoncpp_parser *json = NULL; + jsoncpp_json_init(&json, &error_msg); + jsoncpp_set_max_depth(json, depth_limit); + jsoncpp_set_max_arg_num(json, arg_limit); + jsoncpp_set_silence(json, silence); + + clock_gettime(CLOCK_REALTIME, &ts_before); + rc = jsoncpp_parse_file(json, jsonfile, &error_msg); + if (rc != 0) { + fprintf(stderr, "Parse failed with code %d\n", rc); + fprintf(stderr, "Error: %s\n", error_msg); + free(error_msg); + return 3; + } + clock_gettime(CLOCK_REALTIME, &ts_after); + ts_diff.tv_sec = 0; + ts_diff.tv_nsec = 0; + timespec_diff(&ts_after, &ts_before, &ts_diff); + jsoncpp_json_cleanup(json); + printf("\nTime: %ld.%09ld sec\n\n", (long)ts_diff.tv_sec, ts_diff.tv_nsec); + } +#endif +#if HAVE_JSONCONS + if (strcmp(jsonengine, "JSONCONS") == 0) { + jsoncons_parser *json = NULL; + jsoncons_json_init(&json, &error_msg); + jsoncons_set_max_depth(json, depth_limit); + jsoncons_set_max_arg_num(json, arg_limit); + jsoncons_set_silence(json, silence); + + clock_gettime(CLOCK_REALTIME, &ts_before); + rc = jsoncons_parse_file(json, jsonfile, &error_msg); + if (rc != 0) { + fprintf(stderr, "Parse failed with code %d\n", rc); + fprintf(stderr, "Error: %s\n", error_msg); + free(error_msg); + return 3; + } + clock_gettime(CLOCK_REALTIME, &ts_after); + ts_diff.tv_sec = 0; + ts_diff.tv_nsec = 0; + timespec_diff(&ts_after, &ts_before, &ts_diff); + jsoncons_json_cleanup(json); + printf("\nTime: %ld.%09ld sec\n\n", (long)ts_diff.tv_sec, ts_diff.tv_nsec); + } +#endif +#if HAVE_SIMDJSON + if (strcmp(jsonengine, "SIMDJSON") == 0) { + simdjson_parser *json = NULL; + simdjson_json_init(&json, &error_msg); + simdjson_set_max_depth(json, depth_limit); + simdjson_set_max_arg_num(json, arg_limit); + simdjson_set_silence(json, silence); + + clock_gettime(CLOCK_REALTIME, &ts_before); + rc = simdjson_parse_file(json, jsonfile, &error_msg); + if (rc != 0) { + fprintf(stderr, "Parse failed with code %d\n", rc); + fprintf(stderr, "Error: %s\n", error_msg); + free(error_msg); + return 3; + } + clock_gettime(CLOCK_REALTIME, &ts_after); + ts_diff.tv_sec = 0; + ts_diff.tv_nsec = 0; + timespec_diff(&ts_after, &ts_before, &ts_diff); + simdjson_json_cleanup(json); + printf("\nTime: %ld.%09ld sec\n\n", (long)ts_diff.tv_sec, ts_diff.tv_nsec); + } +#endif +#if HAVE_YYJSON + if (strcmp(jsonengine, "YYJSON") == 0) { + yyjson_parser *json = NULL; + yyjson_json_init(&json, &error_msg); + yyjson_set_max_depth(json, depth_limit); + yyjson_set_max_arg_num(json, arg_limit); + yyjson_set_silence(json, silence); + + clock_gettime(CLOCK_REALTIME, &ts_before); + rc = yyjson_parse_file(json, jsonfile, &error_msg); + if (rc != 0) { + fprintf(stderr, "Parse failed with code %d\n", rc); + fprintf(stderr, "Error: %s\n", error_msg); + free(error_msg); + return 3; + } + clock_gettime(CLOCK_REALTIME, &ts_after); + ts_diff.tv_sec = 0; + ts_diff.tv_nsec = 0; + timespec_diff(&ts_after, &ts_before, &ts_diff); + yyjson_json_cleanup(json); + printf("\nTime: %ld.%09ld sec\n\n", (long)ts_diff.tv_sec, ts_diff.tv_nsec); + } +#endif +#if HAVE_GLAZE + if (strcmp(jsonengine, "GLAZE") == 0) { + glaze_parser *json = NULL; + glaze_json_init(&json, &error_msg); + glaze_set_max_depth(json, depth_limit); + glaze_set_max_arg_num(json, arg_limit); + glaze_set_silence(json, silence); + + clock_gettime(CLOCK_REALTIME, &ts_before); + rc = glaze_parse_file(json, jsonfile, &error_msg); + if (rc != 0) { + fprintf(stderr, "Parse failed with code %d\n", rc); + fprintf(stderr, "Error: %s\n", error_msg); + free(error_msg); + return 3; + } + clock_gettime(CLOCK_REALTIME, &ts_after); + ts_diff.tv_sec = 0; + ts_diff.tv_nsec = 0; + timespec_diff(&ts_after, &ts_before, &ts_diff); + glaze_json_cleanup(json); + printf("\nTime: %ld.%09ld sec\n\n", (long)ts_diff.tv_sec, ts_diff.tv_nsec); + } #endif free(jsonengine); } diff --git a/src/jsonconsparser.cpp b/src/jsonconsparser.cpp new file mode 100644 index 0000000..512d971 --- /dev/null +++ b/src/jsonconsparser.cpp @@ -0,0 +1,83 @@ +#include "jsonconsparser.h" + +#if HAVE_JSONCONS + +#include +#include +#include +#include +#include +#include + +struct jsoncons_parser { + int silence; +}; + +extern "C" int jsoncons_json_init(jsoncons_parser **parser, char **error_msg) { + if (parser == nullptr || error_msg == nullptr) { + return -1; + } + + try { + *parser = new jsoncons_parser{}; + } catch (const std::bad_alloc&) { + *parser = nullptr; + *error_msg = strdup("Unable to allocate jsoncons parser"); + return 1; + } + + *error_msg = nullptr; + return 0; +} + +extern "C" int jsoncons_parse_file(jsoncons_parser *parser, const char *filename, char **error_msg) { + (void)parser; + if (filename == nullptr || error_msg == nullptr) { + return -1; + } + + std::ifstream input(filename); + if (!input.is_open()) { + *error_msg = strdup("Unable to open JSON file"); + return 2; + } + + std::ostringstream oss; + oss << input.rdbuf(); + + try { + auto parsed = jsoncons::json::parse(oss.str()); + (void)parsed; + } catch (const std::exception &e) { + *error_msg = strdup(e.what()); + return 2; + } + + return 0; +} + +extern "C" int jsoncons_set_max_depth(jsoncons_parser *parser, double max_depth) { + (void)parser; + (void)max_depth; + return 0; +} + +extern "C" int jsoncons_set_max_arg_num(jsoncons_parser *parser, double max_arg_num) { + (void)parser; + (void)max_arg_num; + return 0; +} + +extern "C" int jsoncons_set_silence(jsoncons_parser *parser, int silence) { + if (parser != nullptr) { + parser->silence = silence; + } + return 0; +} + +extern "C" int jsoncons_json_cleanup(jsoncons_parser *parser) { + delete parser; + return 0; +} + +#endif diff --git a/src/jsonconsparser.h b/src/jsonconsparser.h new file mode 100644 index 0000000..b497901 --- /dev/null +++ b/src/jsonconsparser.h @@ -0,0 +1,27 @@ +#ifndef JSONCONS_PARSER_H +#define JSONCONS_PARSER_H + +#include "../config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if HAVE_JSONCONS + +typedef struct jsoncons_parser jsoncons_parser; + +int jsoncons_json_init(jsoncons_parser **parser, char **error_msg); +int jsoncons_parse_file(jsoncons_parser *parser, const char *filename, char **error_msg); +int jsoncons_set_max_depth(jsoncons_parser *parser, double max_depth); +int jsoncons_set_max_arg_num(jsoncons_parser *parser, double max_arg_num); +int jsoncons_set_silence(jsoncons_parser *parser, int silence); +int jsoncons_json_cleanup(jsoncons_parser *parser); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/jsoncparser.c b/src/jsoncparser.c new file mode 100644 index 0000000..544718c --- /dev/null +++ b/src/jsoncparser.c @@ -0,0 +1,69 @@ +#include "jsoncparser.h" + +#if HAVE_JSONC + +#include +#include +#include +#include +#include + +struct jsonc_parser { + int silence; +}; + +int jsonc_json_init(jsonc_parser **parser, char **error_msg) { + assert(parser != NULL); + assert(error_msg != NULL); + + *parser = (jsonc_parser *)calloc(1, sizeof(jsonc_parser)); + if (*parser == NULL) { + *error_msg = strdup("Unable to allocate JSON-C parser"); + return 1; + } + + *error_msg = NULL; + return 0; +} + +int jsonc_parse_file(jsonc_parser *parser, const char *filename, char **error_msg) { + (void)parser; + if (filename == NULL || error_msg == NULL) { + return -1; + } + + struct json_object *root = json_object_from_file(filename); + if (root == NULL) { + *error_msg = strdup("json_object_from_file failed"); + return 2; + } + + json_object_put(root); + return 0; +} + +int jsonc_set_max_depth(jsonc_parser *parser, double max_depth) { + (void)parser; + (void)max_depth; + return 0; +} + +int jsonc_set_max_arg_num(jsonc_parser *parser, double max_arg_num) { + (void)parser; + (void)max_arg_num; + return 0; +} + +int jsonc_set_silence(jsonc_parser *parser, int silence) { + if (parser != NULL) { + parser->silence = silence; + } + return 0; +} + +int jsonc_json_cleanup(jsonc_parser *parser) { + free(parser); + return 0; +} + +#endif diff --git a/src/jsoncparser.h b/src/jsoncparser.h new file mode 100644 index 0000000..58a874b --- /dev/null +++ b/src/jsoncparser.h @@ -0,0 +1,19 @@ +#ifndef JSONC_PARSER_H +#define JSONC_PARSER_H + +#include "../config.h" + +#if HAVE_JSONC + +typedef struct jsonc_parser jsonc_parser; + +int jsonc_json_init(jsonc_parser **parser, char **error_msg); +int jsonc_parse_file(jsonc_parser *parser, const char *filename, char **error_msg); +int jsonc_set_max_depth(jsonc_parser *parser, double max_depth); +int jsonc_set_max_arg_num(jsonc_parser *parser, double max_arg_num); +int jsonc_set_silence(jsonc_parser *parser, int silence); +int jsonc_json_cleanup(jsonc_parser *parser); + +#endif + +#endif diff --git a/src/jsoncppparser.cpp b/src/jsoncppparser.cpp new file mode 100644 index 0000000..d8651d6 --- /dev/null +++ b/src/jsoncppparser.cpp @@ -0,0 +1,80 @@ +#include "jsoncppparser.h" + +#if HAVE_JSONCPP + +#include +#include +#include +#include +#include + +struct jsoncpp_parser { + int silence; +}; + +extern "C" int jsoncpp_json_init(jsoncpp_parser **parser, char **error_msg) { + if (parser == nullptr || error_msg == nullptr) { + return -1; + } + + try { + *parser = new jsoncpp_parser{}; + } catch (const std::bad_alloc&) { + *parser = nullptr; + *error_msg = strdup("Unable to allocate JsonCpp parser"); + return 1; + } + + *error_msg = nullptr; + return 0; +} + +extern "C" int jsoncpp_parse_file(jsoncpp_parser *parser, const char *filename, char **error_msg) { + (void)parser; + if (filename == nullptr || error_msg == nullptr) { + return -1; + } + + std::ifstream input(filename); + if (!input.is_open()) { + *error_msg = strdup("Unable to open JSON file"); + return 2; + } + + Json::CharReaderBuilder builder; + Json::Value root; + std::string errs; + const bool ok = Json::parseFromStream(builder, input, &root, &errs); + if (!ok) { + *error_msg = strdup(errs.c_str()); + return 2; + } + + return 0; +} + +extern "C" int jsoncpp_set_max_depth(jsoncpp_parser *parser, double max_depth) { + (void)parser; + (void)max_depth; + return 0; +} + +extern "C" int jsoncpp_set_max_arg_num(jsoncpp_parser *parser, double max_arg_num) { + (void)parser; + (void)max_arg_num; + return 0; +} + +extern "C" int jsoncpp_set_silence(jsoncpp_parser *parser, int silence) { + if (parser != nullptr) { + parser->silence = silence; + } + return 0; +} + +extern "C" int jsoncpp_json_cleanup(jsoncpp_parser *parser) { + delete parser; + return 0; +} + +#endif diff --git a/src/jsoncppparser.h b/src/jsoncppparser.h new file mode 100644 index 0000000..9cb5ba8 --- /dev/null +++ b/src/jsoncppparser.h @@ -0,0 +1,27 @@ +#ifndef JSONCPP_PARSER_H +#define JSONCPP_PARSER_H + +#include "../config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if HAVE_JSONCPP + +typedef struct jsoncpp_parser jsoncpp_parser; + +int jsoncpp_json_init(jsoncpp_parser **parser, char **error_msg); +int jsoncpp_parse_file(jsoncpp_parser *parser, const char *filename, char **error_msg); +int jsoncpp_set_max_depth(jsoncpp_parser *parser, double max_depth); +int jsoncpp_set_max_arg_num(jsoncpp_parser *parser, double max_arg_num); +int jsoncpp_set_silence(jsoncpp_parser *parser, int silence); +int jsoncpp_json_cleanup(jsoncpp_parser *parser); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/simdjsonparser.cpp b/src/simdjsonparser.cpp new file mode 100644 index 0000000..e73fef1 --- /dev/null +++ b/src/simdjsonparser.cpp @@ -0,0 +1,154 @@ +#include "simdjsonparser.h" + +#if HAVE_SIMDJSON + +#include +#include +#include + +struct simdjson_parser { + int silence; + simdjson::ondemand::parser parser; +}; + +static int consume_value(simdjson::ondemand::value value) { + simdjson::ondemand::json_type type; + auto type_result = value.type(); + if (type_result.error()) { + return 1; + } + type = type_result.value_unsafe(); + + switch (type) { + case simdjson::ondemand::json_type::object: { + auto obj_result = value.get_object(); + if (obj_result.error()) { + return 1; + } + auto obj = obj_result.value_unsafe(); + for (auto field_result : obj) { + if (field_result.error()) { + return 1; + } + auto field = field_result.value_unsafe(); + auto key_result = field.unescaped_key(false); + if (key_result.error()) { + return 1; + } + auto child = field.value(); + int rc = consume_value(child); + if (rc != 0) { + return rc; + } + } + return 0; + } + case simdjson::ondemand::json_type::array: { + auto arr_result = value.get_array(); + if (arr_result.error()) { + return 1; + } + auto arr = arr_result.value_unsafe(); + for (auto elem_result : arr) { + if (elem_result.error()) { + return 1; + } + auto elem = elem_result.value_unsafe(); + int rc = consume_value(elem); + if (rc != 0) { + return rc; + } + } + return 0; + } + case simdjson::ondemand::json_type::number: { + auto number_result = value.get_number(); + return number_result.error() ? 1 : 0; + } + case simdjson::ondemand::json_type::string: { + auto str_result = value.get_string(); + return str_result.error() ? 1 : 0; + } + case simdjson::ondemand::json_type::boolean: { + auto bool_result = value.get_bool(); + return bool_result.error() ? 1 : 0; + } + case simdjson::ondemand::json_type::null: { + auto null_result = value.is_null(); + return null_result.error() ? 1 : 0; + } + } + + return 1; +} + +extern "C" int simdjson_json_init(simdjson_parser **parser, char **error_msg) { + if (parser == nullptr || error_msg == nullptr) { + return -1; + } + + try { + *parser = new simdjson_parser{}; + } catch (const std::bad_alloc&) { + *parser = nullptr; + *error_msg = strdup("Unable to allocate simdjson parser"); + return 1; + } + + *error_msg = nullptr; + return 0; +} + +extern "C" int simdjson_parse_file(simdjson_parser *parser, const char *filename, char **error_msg) { + if (parser == nullptr || filename == nullptr || error_msg == nullptr) { + return -1; + } + + auto json_result = simdjson::padded_string::load(filename); + if (json_result.error()) { + *error_msg = strdup(simdjson::error_message(json_result.error())); + return 2; + } + + auto &json = json_result.value_unsafe(); + auto doc_result = parser->parser.iterate(json); + if (doc_result.error()) { + *error_msg = strdup(simdjson::error_message(doc_result.error())); + return 2; + } + + auto &doc = doc_result.value_unsafe(); + int rc = consume_value(doc); + if (rc != 0) { + *error_msg = strdup("simdjson parse/iteration failed"); + return 2; + } + + return 0; +} + +extern "C" int simdjson_set_max_depth(simdjson_parser *parser, double max_depth) { + (void)parser; + (void)max_depth; + return 0; +} + +extern "C" int simdjson_set_max_arg_num(simdjson_parser *parser, double max_arg_num) { + (void)parser; + (void)max_arg_num; + return 0; +} + +extern "C" int simdjson_set_silence(simdjson_parser *parser, int silence) { + if (parser != nullptr) { + parser->silence = silence; + } + return 0; +} + +extern "C" int simdjson_json_cleanup(simdjson_parser *parser) { + delete parser; + return 0; +} + +#endif diff --git a/src/simdjsonparser.h b/src/simdjsonparser.h new file mode 100644 index 0000000..d772446 --- /dev/null +++ b/src/simdjsonparser.h @@ -0,0 +1,27 @@ +#ifndef SIMDJSON_PARSER_H +#define SIMDJSON_PARSER_H + +#include "../config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if HAVE_SIMDJSON + +typedef struct simdjson_parser simdjson_parser; + +int simdjson_json_init(simdjson_parser **parser, char **error_msg); +int simdjson_parse_file(simdjson_parser *parser, const char *filename, char **error_msg); +int simdjson_set_max_depth(simdjson_parser *parser, double max_depth); +int simdjson_set_max_arg_num(simdjson_parser *parser, double max_arg_num); +int simdjson_set_silence(simdjson_parser *parser, int silence); +int simdjson_json_cleanup(simdjson_parser *parser); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/yyjsonparser.c b/src/yyjsonparser.c new file mode 100644 index 0000000..b43de06 --- /dev/null +++ b/src/yyjsonparser.c @@ -0,0 +1,120 @@ +#include "yyjsonparser.h" + +#if HAVE_YYJSON + +#include +#include +#include +#include +#include + +struct yyjson_parser { + int silence; +}; + +static int read_whole_file(const char *filename, char **content, size_t *length, char **error_msg) { + FILE *fp = fopen(filename, "rb"); + if (fp == NULL) { + *error_msg = strdup("Unable to open JSON file"); + return 1; + } + + if (fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + *error_msg = strdup("Unable to seek JSON file"); + return 1; + } + + long len = ftell(fp); + if (len < 0) { + fclose(fp); + *error_msg = strdup("Unable to measure JSON file"); + return 1; + } + rewind(fp); + + char *buffer = (char *)malloc((size_t)len + 1U); + if (buffer == NULL) { + fclose(fp); + *error_msg = strdup("Unable to allocate JSON buffer"); + return 1; + } + + size_t read_len = fread(buffer, 1, (size_t)len, fp); + fclose(fp); + if (read_len != (size_t)len) { + free(buffer); + *error_msg = strdup("Unable to read entire JSON file"); + return 1; + } + + buffer[len] = '\0'; + *content = buffer; + *length = (size_t)len; + return 0; +} + +int yyjson_json_init(yyjson_parser **parser, char **error_msg) { + assert(parser != NULL); + assert(error_msg != NULL); + + *parser = (yyjson_parser *)calloc(1, sizeof(yyjson_parser)); + if (*parser == NULL) { + *error_msg = strdup("Unable to allocate yyjson parser"); + return 1; + } + + *error_msg = NULL; + return 0; +} + +int yyjson_parse_file(yyjson_parser *parser, const char *filename, char **error_msg) { + (void)parser; + if (filename == NULL || error_msg == NULL) { + return -1; + } + + char *content = NULL; + size_t length = 0; + int rc = read_whole_file(filename, &content, &length, error_msg); + if (rc != 0) { + return 2; + } + + yyjson_doc *doc = yyjson_read(content, length, 0); + free(content); + + if (doc == NULL) { + *error_msg = strdup("yyjson_read failed"); + return 2; + } + + yyjson_doc_free(doc); + return 0; +} + +int yyjson_set_max_depth(yyjson_parser *parser, double max_depth) { + (void)parser; + (void)max_depth; + return 0; +} + +int yyjson_set_max_arg_num(yyjson_parser *parser, double max_arg_num) { + (void)parser; + (void)max_arg_num; + return 0; +} + +int yyjson_set_silence(yyjson_parser *parser, int silence) { + if (parser != NULL) { + parser->silence = silence; + } + return 0; +} + +int yyjson_json_cleanup(yyjson_parser *parser) { + free(parser); + return 0; +} + +#endif diff --git a/src/yyjsonparser.h b/src/yyjsonparser.h new file mode 100644 index 0000000..c873a45 --- /dev/null +++ b/src/yyjsonparser.h @@ -0,0 +1,19 @@ +#ifndef YYJSON_PARSER_H +#define YYJSON_PARSER_H + +#include "../config.h" + +#if HAVE_YYJSON + +typedef struct yyjson_parser yyjson_parser; + +int yyjson_json_init(yyjson_parser **parser, char **error_msg); +int yyjson_parse_file(yyjson_parser *parser, const char *filename, char **error_msg); +int yyjson_set_max_depth(yyjson_parser *parser, double max_depth); +int yyjson_set_max_arg_num(yyjson_parser *parser, double max_arg_num); +int yyjson_set_silence(yyjson_parser *parser, int silence); +int yyjson_json_cleanup(yyjson_parser *parser); + +#endif + +#endif