From e72c6d4785a27c6a9ee1e26542b25dcce81d48fe Mon Sep 17 00:00:00 2001 From: Tanguy Pruvot Date: Sat, 22 Nov 2014 15:10:02 +0100 Subject: [PATCH] Update jansson windows sources to 2.6 There was sometimes problems with float values close to 0 (like 0.001) --- ccminer.vcxproj | 5 + ccminer.vcxproj.filters | 15 + compat/jansson/.gitignore | 4 + compat/jansson/Makefile.am | 38 +- compat/jansson/config.h | 213 ++++++--- compat/jansson/configure.ac | 98 ++++ compat/jansson/dump.c | 144 +++--- compat/jansson/error.c | 63 +++ compat/jansson/hashtable.c | 163 +++---- compat/jansson/hashtable.h | 89 ++-- compat/jansson/jansson.h | 179 ++++++-- compat/jansson/jansson_config.h | 43 ++ compat/jansson/jansson_private.h | 55 ++- compat/jansson/load.c | 570 +++++++++++++++-------- compat/jansson/memory.c | 56 +++ compat/jansson/pack_unpack.c | 762 +++++++++++++++++++++++++++++++ compat/jansson/strbuffer.c | 43 +- compat/jansson/strbuffer.h | 10 +- compat/jansson/strconv.c | 134 ++++++ compat/jansson/utf.c | 2 +- compat/jansson/utf.h | 15 +- compat/jansson/value.c | 328 ++++++------- 22 files changed, 2274 insertions(+), 755 deletions(-) create mode 100644 compat/jansson/.gitignore create mode 100644 compat/jansson/configure.ac create mode 100644 compat/jansson/error.c create mode 100644 compat/jansson/jansson_config.h create mode 100644 compat/jansson/memory.c create mode 100644 compat/jansson/pack_unpack.c create mode 100644 compat/jansson/strconv.c diff --git a/ccminer.vcxproj b/ccminer.vcxproj index 4844f38..be7e66e 100644 --- a/ccminer.vcxproj +++ b/ccminer.vcxproj @@ -225,9 +225,13 @@ + + + + @@ -280,6 +284,7 @@ + diff --git a/ccminer.vcxproj.filters b/ccminer.vcxproj.filters index 83208ff..1035274 100644 --- a/ccminer.vcxproj.filters +++ b/ccminer.vcxproj.filters @@ -201,6 +201,18 @@ Source Files + + Source Files\jansson + + + Source Files\jansson + + + Source Files\jansson + + + Source Files\jansson + @@ -347,6 +359,9 @@ Header Files\compat\nvapi + + Header Files\compat + diff --git a/compat/jansson/.gitignore b/compat/jansson/.gitignore new file mode 100644 index 0000000..55344a1 --- /dev/null +++ b/compat/jansson/.gitignore @@ -0,0 +1,4 @@ +*.h.in +*.h.in~ +libtool +libjansson.a diff --git a/compat/jansson/Makefile.am b/compat/jansson/Makefile.am index ff38e51..e27f05a 100644 --- a/compat/jansson/Makefile.am +++ b/compat/jansson/Makefile.am @@ -1,18 +1,20 @@ - -noinst_LIBRARIES = libjansson.a - -libjansson_a_SOURCES = \ - config.h \ - dump.c \ - hashtable.c \ - hashtable.h \ - jansson.h \ - jansson_private.h \ - load.c \ - strbuffer.c \ - strbuffer.h \ - utf.c \ - utf.h \ - util.h \ - value.c - + +noinst_LIBRARIES = libjansson.a + +libjansson_a_SOURCES = \ + config.h \ + dump.c \ + error.c \ + hashtable.c hashtable.h \ + jansson.h \ + jansson_config.h \ + jansson_private.h \ + load.c \ + memory.c \ + pack_unpack.c \ + strbuffer.c strbuffer.h \ + strconv.c \ + utf.c utf.h \ + util.h \ + value.c + diff --git a/compat/jansson/config.h b/compat/jansson/config.h index f11075a..bbc54b9 100644 --- a/compat/jansson/config.h +++ b/compat/jansson/config.h @@ -1,73 +1,140 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#define LT_OBJDIR ".libs/" - -/* Name of package */ -#define PACKAGE "jansson" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "petri@digip.org" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "jansson" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "jansson 1.3" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "jansson" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "1.3" - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Version number of package */ -#define VERSION "1.3" - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -/* #undef inline */ -#endif - -/* Define to the type of a signed integer type of width exactly 32 bits if - such a type exists and the standard includes do not define it. */ -/* #undef int32_t */ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if gcc's __atomic builtins are available */ +/* #undef HAVE_ATOMIC_BUILTINS */ + +/* Define to 1 if you have the `close' function. */ +#define HAVE_CLOSE 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DLFCN_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ENDIAN_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `getpid' function. */ +#define HAVE_GETPID 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `localeconv' function. */ +#define HAVE_LOCALECONV 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if the system has the type `long long int'. */ +#define HAVE_LONG_LONG_INT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `open' function. */ +#define HAVE_OPEN 1 + +/* Define to 1 if you have the `read' function. */ +#define HAVE_READ 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SCHED_H 1 + +/* Define to 1 if you have the `sched_yield' function. */ +/* #undef HAVE_SCHED_YIELD */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strtoll' function. */ +#define HAVE_STRTOLL 1 + +/* Define to 1 if gcc's __sync builtins are available */ +#define HAVE_SYNC_BUILTINS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Name of package */ +#define PACKAGE "jansson" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "petri@digip.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "jansson" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "jansson 2.6" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "jansson" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "2.6" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if /dev/urandom should be used for seeding the hash function */ +#define USE_URANDOM 1 + +/* Define to 1 if CryptGenRandom should be used for seeding the hash function + */ +#define USE_WINDOWS_CRYPTOAPI 1 + +/* Version number of package */ +#define VERSION "2.6" + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT32_T */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to the type of a signed integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef int32_t */ + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint32_t */ diff --git a/compat/jansson/configure.ac b/compat/jansson/configure.ac new file mode 100644 index 0000000..e7e88a4 --- /dev/null +++ b/compat/jansson/configure.ac @@ -0,0 +1,98 @@ +AC_PREREQ([2.60]) +AC_INIT([jansson], [2.6], [petri@digip.org]) + +AC_CONFIG_MACRO_DIR([m4]) + +AM_INIT_AUTOMAKE([1.10 foreign]) +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_CONFIG_SRCDIR([value.c]) +AC_CONFIG_HEADERS([config.h]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_LIBTOOL +AM_CONDITIONAL([GCC], [test x$GCC = xyes]) + +# Checks for libraries. + +# Checks for header files. +AC_CHECK_HEADERS([endian.h fcntl.h locale.h sched.h unistd.h sys/param.h sys/stat.h sys/time.h sys/types.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_TYPE_INT32_T +AC_TYPE_UINT32_T +AC_TYPE_LONG_LONG_INT + +AC_C_INLINE +case $ac_cv_c_inline in + yes) json_inline=inline;; + no) json_inline=;; + *) json_inline=$ac_cv_c_inline;; +esac +AC_SUBST([json_inline]) + +# Checks for library functions. +AC_CHECK_FUNCS([close getpid gettimeofday localeconv open read sched_yield strtoll]) + +AC_MSG_CHECKING([for gcc __sync builtins]) +have_sync_builtins=no +AC_TRY_LINK( + [], [unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1);], + [have_sync_builtins=yes], +) +if test "x$have_sync_builtins" = "xyes"; then + AC_DEFINE([HAVE_SYNC_BUILTINS], [1], + [Define to 1 if gcc's __sync builtins are available]) +fi +AC_MSG_RESULT([$have_sync_builtins]) + +AC_MSG_CHECKING([for gcc __atomic builtins]) +have_atomic_builtins=no +AC_TRY_LINK( + [], [char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_ACQ_REL); __atomic_load_n(&v, __ATOMIC_ACQUIRE);], + [have_atomic_builtins=yes], +) +if test "x$have_atomic_builtins" = "xyes"; then + AC_DEFINE([HAVE_ATOMIC_BUILTINS], [1], + [Define to 1 if gcc's __atomic builtins are available]) +fi +AC_MSG_RESULT([$have_atomic_builtins]) + +case "$ac_cv_type_long_long_int$ac_cv_func_strtoll" in + yesyes) json_have_long_long=1;; + *) json_have_long_long=0;; +esac +AC_SUBST([json_have_long_long]) + +case "$ac_cv_header_locale_h$ac_cv_func_localeconv" in + yesyes) json_have_localeconv=1;; + *) json_have_localeconv=0;; +esac +AC_SUBST([json_have_localeconv]) + +# Features +AC_ARG_ENABLE([urandom], + [AS_HELP_STRING([--disable-urandom], + [Don't use /dev/urandom to seed the hash function])], + [use_urandom=$enableval], [use_urandom=yes]) + +if test "x$use_urandom" = xyes; then +AC_DEFINE([USE_URANDOM], [1], + [Define to 1 if /dev/urandom should be used for seeding the hash function]) +fi + +AC_ARG_ENABLE([windows-cryptoapi], + [AS_HELP_STRING([--disable-windows-cryptoapi], + [Don't use CryptGenRandom to seed the hash function])], + [use_windows_cryptoapi=$enableval], [use_windows_cryptoapi=yes]) + +if test "x$use_windows_cryptoapi" = xyes; then +AC_DEFINE([USE_WINDOWS_CRYPTOAPI], [1], + [Define to 1 if CryptGenRandom should be used for seeding the hash function]) +fi + +AC_CONFIG_FILES([ + Makefile +]) +AC_OUTPUT diff --git a/compat/jansson/dump.c b/compat/jansson/dump.c index a8c9cc6..45450b1 100644 --- a/compat/jansson/dump.c +++ b/compat/jansson/dump.c @@ -1,17 +1,20 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif + #include #include #include #include -#include +#include "jansson.h" #include "jansson_private.h" #include "strbuffer.h" #include "utf.h" @@ -19,21 +22,17 @@ #define MAX_INTEGER_STR_LENGTH 100 #define MAX_REAL_STR_LENGTH 100 -typedef int (*dump_func)(const char *buffer, int size, void *data); - -struct string -{ - char *buffer; - int length; - int size; +struct object_key { + size_t serial; + const char *key; }; -static int dump_to_strbuffer(const char *buffer, int size, void *data) +static int dump_to_strbuffer(const char *buffer, size_t size, void *data) { return strbuffer_append_bytes((strbuffer_t *)data, buffer, size); } -static int dump_to_file(const char *buffer, int size, void *data) +static int dump_to_file(const char *buffer, size_t size, void *data) { FILE *dest = (FILE *)data; if(fwrite(buffer, size, 1, dest) != 1) @@ -41,10 +40,10 @@ static int dump_to_file(const char *buffer, int size, void *data) return 0; } -/* 256 spaces (the maximum indentation size) */ -static char whitespace[] = " "; +/* 32 spaces (the maximum indentation size) */ +static const char whitespace[] = " "; -static int dump_indent(unsigned long flags, int depth, int space, dump_func dump, void *data) +static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data) { if(JSON_INDENT(flags) > 0) { @@ -66,7 +65,7 @@ static int dump_indent(unsigned long flags, int depth, int space, dump_func dump return 0; } -static int dump_string(const char *str, int ascii, dump_func dump, void *data) +static int dump_string(const char *str, json_dump_callback_t dump, void *data, size_t flags) { const char *pos, *end; int32_t codepoint; @@ -91,8 +90,12 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data) if(codepoint == '\\' || codepoint == '"' || codepoint < 0x20) break; + /* slash */ + if((flags & JSON_ESCAPE_SLASH) && codepoint == '/') + break; + /* non-ASCII */ - if(ascii && codepoint > 0x7F) + if((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F) break; pos = end; @@ -106,7 +109,7 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data) if(end == pos) break; - /* handle \, ", and control codes */ + /* handle \, /, ", and control codes */ length = 2; switch(codepoint) { @@ -117,6 +120,7 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data) case '\n': text = "\\n"; break; case '\r': text = "\\r"; break; case '\t': text = "\\t"; break; + case '/': text = "\\/"; break; default: { /* codepoint is in BMP */ @@ -155,20 +159,23 @@ static int dump_string(const char *str, int ascii, dump_func dump, void *data) static int object_key_compare_keys(const void *key1, const void *key2) { - return strcmp((*(const object_key_t **)key1)->key, - (*(const object_key_t **)key2)->key); + return strcmp(((const struct object_key *)key1)->key, + ((const struct object_key *)key2)->key); } static int object_key_compare_serials(const void *key1, const void *key2) { - return (*(const object_key_t **)key1)->serial - - (*(const object_key_t **)key2)->serial; + size_t a = ((const struct object_key *)key1)->serial; + size_t b = ((const struct object_key *)key2)->serial; + + return a < b ? -1 : a == b ? 0 : 1; } -static int do_dump(const json_t *json, unsigned long flags, int depth, - dump_func dump, void *data) +static int do_dump(const json_t *json, size_t flags, int depth, + json_dump_callback_t dump, void *data) { - int ascii = flags & JSON_ENSURE_ASCII ? 1 : 0; + if(!json) + return -1; switch(json_typeof(json)) { case JSON_NULL: @@ -185,8 +192,10 @@ static int do_dump(const json_t *json, unsigned long flags, int depth, char buffer[MAX_INTEGER_STR_LENGTH]; int size; - size = snprintf(buffer, MAX_INTEGER_STR_LENGTH, "%d", json_integer_value(json)); - if(size >= MAX_INTEGER_STR_LENGTH) + size = snprintf(buffer, MAX_INTEGER_STR_LENGTH, + "%" JSON_INTEGER_FORMAT, + json_integer_value(json)); + if(size < 0 || size >= MAX_INTEGER_STR_LENGTH) return -1; return dump(buffer, size, data); @@ -196,31 +205,17 @@ static int do_dump(const json_t *json, unsigned long flags, int depth, { char buffer[MAX_REAL_STR_LENGTH]; int size; + double value = json_real_value(json); - size = snprintf(buffer, MAX_REAL_STR_LENGTH, "%.17g", - json_real_value(json)); - if(size >= MAX_REAL_STR_LENGTH) + size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value); + if(size < 0) return -1; - /* Make sure there's a dot or 'e' in the output. Otherwise - a real is converted to an integer when decoding */ - if(strchr(buffer, '.') == NULL && - strchr(buffer, 'e') == NULL) - { - if(size + 2 >= MAX_REAL_STR_LENGTH) { - /* No space to append ".0" */ - return -1; - } - buffer[size] = '.'; - buffer[size + 1] = '0'; - size += 2; - } - return dump(buffer, size, data); } case JSON_STRING: - return dump_string(json_string_value(json), ascii, dump, data); + return dump_string(json_string_value(json), dump, data, flags); case JSON_ARRAY: { @@ -306,20 +301,20 @@ static int do_dump(const json_t *json, unsigned long flags, int depth, if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER) { - const object_key_t **keys; - unsigned int size; - unsigned int i; + struct object_key *keys; + size_t size, i; int (*cmp_func)(const void *, const void *); size = json_object_size(json); - keys = malloc(size * sizeof(object_key_t *)); + keys = jsonp_malloc(size * sizeof(struct object_key)); if(!keys) goto object_error; i = 0; while(iter) { - keys[i] = jsonp_object_iter_fullkey(iter); + keys[i].serial = hashtable_iter_serial(iter); + keys[i].key = json_object_iter_key(iter); iter = json_object_iter_next((json_t *)json, iter); i++; } @@ -330,22 +325,22 @@ static int do_dump(const json_t *json, unsigned long flags, int depth, else cmp_func = object_key_compare_serials; - qsort((void*)keys, size, sizeof(object_key_t *), cmp_func); + qsort(keys, size, sizeof(struct object_key), cmp_func); for(i = 0; i < size; i++) { const char *key; json_t *value; - key = keys[i]->key; + key = keys[i].key; value = json_object_get(json, key); assert(value); - dump_string(key, ascii, dump, data); + dump_string(key, dump, data, flags); if(dump(separator, separator_length, data) || do_dump(value, flags, depth + 1, dump, data)) { - free((void*)keys); + jsonp_free(keys); goto object_error; } @@ -354,7 +349,7 @@ static int do_dump(const json_t *json, unsigned long flags, int depth, if(dump(",", 1, data) || dump_indent(flags, depth + 1, 1, dump, data)) { - free((void*)keys); + jsonp_free(keys); goto object_error; } } @@ -362,13 +357,13 @@ static int do_dump(const json_t *json, unsigned long flags, int depth, { if(dump_indent(flags, depth, 0, dump, data)) { - free((void*)keys); + jsonp_free(keys); goto object_error; } } } - free((void*)keys); + jsonp_free(keys); } else { @@ -378,7 +373,7 @@ static int do_dump(const json_t *json, unsigned long flags, int depth, { void *next = json_object_iter_next((json_t *)json, iter); - dump_string(json_object_iter_key(iter), ascii, dump, data); + dump_string(json_object_iter_key(iter), dump, data, flags); if(dump(separator, separator_length, data) || do_dump(json_object_iter_value(iter), flags, depth + 1, dump, data)) @@ -414,38 +409,29 @@ static int do_dump(const json_t *json, unsigned long flags, int depth, } } - -char *json_dumps(const json_t *json, unsigned long flags) +char *json_dumps(const json_t *json, size_t flags) { strbuffer_t strbuff; char *result; - if(!json_is_array(json) && !json_is_object(json)) - return NULL; - if(strbuffer_init(&strbuff)) return NULL; - if(do_dump(json, flags, 0, dump_to_strbuffer, (void *)&strbuff)) { - strbuffer_close(&strbuff); - return NULL; - } + if(json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags)) + result = NULL; + else + result = jsonp_strdup(strbuffer_value(&strbuff)); - result = strdup(strbuffer_value(&strbuff)); strbuffer_close(&strbuff); - return result; } -int json_dumpf(const json_t *json, FILE *output, unsigned long flags) +int json_dumpf(const json_t *json, FILE *output, size_t flags) { - if(!json_is_array(json) && !json_is_object(json)) - return -1; - - return do_dump(json, flags, 0, dump_to_file, (void *)output); + return json_dump_callback(json, dump_to_file, (void *)output, flags); } -int json_dump_file(const json_t *json, const char *path, unsigned long flags) +int json_dump_file(const json_t *json, const char *path, size_t flags) { int result; @@ -458,3 +444,13 @@ int json_dump_file(const json_t *json, const char *path, unsigned long flags) fclose(output); return result; } + +int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags) +{ + if(!(flags & JSON_ENCODE_ANY)) { + if(!json_is_array(json) && !json_is_object(json)) + return -1; + } + + return do_dump(json, flags, 0, callback, data); +} diff --git a/compat/jansson/error.c b/compat/jansson/error.c new file mode 100644 index 0000000..a544a59 --- /dev/null +++ b/compat/jansson/error.c @@ -0,0 +1,63 @@ +#include +#include "jansson_private.h" + +void jsonp_error_init(json_error_t *error, const char *source) +{ + if(error) + { + error->text[0] = '\0'; + error->line = -1; + error->column = -1; + error->position = 0; + if(source) + jsonp_error_set_source(error, source); + else + error->source[0] = '\0'; + } +} + +void jsonp_error_set_source(json_error_t *error, const char *source) +{ + size_t length; + + if(!error || !source) + return; + + length = strlen(source); + if(length < JSON_ERROR_SOURCE_LENGTH) + strcpy(error->source, source); + else { + size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4; + strcpy(error->source, "..."); + strcpy(error->source + 3, source + extra); + } +} + +void jsonp_error_set(json_error_t *error, int line, int column, + size_t position, const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + jsonp_error_vset(error, line, column, position, msg, ap); + va_end(ap); +} + +void jsonp_error_vset(json_error_t *error, int line, int column, + size_t position, const char *msg, va_list ap) +{ + if(!error) + return; + + if(error->text[0] != '\0') { + /* error already set */ + return; + } + + error->line = line; + error->column = column; + error->position = position; + + vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH, msg, ap); + error->text[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; +} diff --git a/compat/jansson/hashtable.c b/compat/jansson/hashtable.c index 791f9ac..a438bbb 100644 --- a/compat/jansson/hashtable.c +++ b/compat/jansson/hashtable.c @@ -1,35 +1,46 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * This library is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ -#include - #include +#include +#include /* for JSON_INLINE */ +#include "jansson_private.h" /* for container_of() */ #include "hashtable.h" -#ifdef WIN32 -#define inline __inline -#endif - typedef struct hashtable_list list_t; typedef struct hashtable_pair pair_t; typedef struct hashtable_bucket bucket_t; -#define container_of(ptr_, type_, member_) \ - ((type_ *)((char *)ptr_ - (size_t)&((type_ *)0)->member_)) - #define list_to_pair(list_) container_of(list_, pair_t, list) -static inline void list_init(list_t *list) +/* From http://www.cse.yorku.ca/~oz/hash.html */ +static size_t hash_str(const void *ptr) +{ + const char *str = (const char *)ptr; + + size_t hash = 5381; + size_t c; + + while((c = (size_t)*str)) + { + hash = ((hash << 5) + hash) + c; + str++; + } + + return hash; +} + +static JSON_INLINE void list_init(list_t *list) { list->next = list; list->prev = list; } -static inline void list_insert(list_t *list, list_t *node) +static JSON_INLINE void list_insert(list_t *list, list_t *node) { node->next = list; node->prev = list->prev; @@ -37,13 +48,13 @@ static inline void list_insert(list_t *list, list_t *node) list->prev = node; } -static inline void list_remove(list_t *list) +static JSON_INLINE void list_remove(list_t *list) { list->prev->next = list->next; list->next->prev = list->prev; } -static inline int bucket_is_empty(hashtable_t *hashtable, bucket_t *bucket) +static JSON_INLINE int bucket_is_empty(hashtable_t *hashtable, bucket_t *bucket) { return bucket->first == &hashtable->list && bucket->first == bucket->last; } @@ -63,22 +74,21 @@ static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket, } } -static unsigned int primes[] = { +static const size_t primes[] = { 5, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 }; -static const unsigned int num_primes = sizeof(primes) / sizeof(unsigned int); -static inline unsigned int num_buckets(hashtable_t *hashtable) +static JSON_INLINE size_t num_buckets(hashtable_t *hashtable) { return primes[hashtable->num_buckets]; } static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, - const void *key, unsigned int hash) + const char *key, size_t hash) { list_t *list; pair_t *pair; @@ -90,7 +100,7 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, while(1) { pair = list_to_pair(list); - if(pair->hash == hash && hashtable->cmp_keys(pair->key, key)) + if(pair->hash == hash && strcmp(pair->key, key) == 0) return pair; if(list == bucket->last) @@ -104,11 +114,11 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, /* returns 0 on success, -1 if key was not found */ static int hashtable_do_del(hashtable_t *hashtable, - const void *key, unsigned int hash) + const char *key, size_t hash) { pair_t *pair; bucket_t *bucket; - unsigned int index; + size_t index; index = hash % num_buckets(hashtable); bucket = &hashtable->buckets[index]; @@ -127,13 +137,9 @@ static int hashtable_do_del(hashtable_t *hashtable, bucket->last = pair->list.prev; list_remove(&pair->list); + json_decref(pair->value); - if(hashtable->free_key) - hashtable->free_key(pair->key); - if(hashtable->free_value) - hashtable->free_value(pair->value); - - free(pair); + jsonp_free(pair); hashtable->size--; return 0; @@ -148,11 +154,8 @@ static void hashtable_do_clear(hashtable_t *hashtable) { next = list->next; pair = list_to_pair(list); - if(hashtable->free_key) - hashtable->free_key(pair->key); - if(hashtable->free_value) - hashtable->free_value(pair->value); - free(pair); + json_decref(pair->value); + jsonp_free(pair); } } @@ -160,14 +163,14 @@ static int hashtable_do_rehash(hashtable_t *hashtable) { list_t *list, *next; pair_t *pair; - unsigned int i, index, new_size; + size_t i, index, new_size; - free(hashtable->buckets); + jsonp_free(hashtable->buckets); hashtable->num_buckets++; new_size = num_buckets(hashtable); - hashtable->buckets = malloc(new_size * sizeof(bucket_t)); + hashtable->buckets = jsonp_malloc(new_size * sizeof(bucket_t)); if(!hashtable->buckets) return -1; @@ -191,47 +194,18 @@ static int hashtable_do_rehash(hashtable_t *hashtable) } -hashtable_t *hashtable_create(key_hash_fn hash_key, key_cmp_fn cmp_keys, - free_fn free_key, free_fn free_value) -{ - hashtable_t *hashtable = malloc(sizeof(hashtable_t)); - if(!hashtable) - return NULL; - - if(hashtable_init(hashtable, hash_key, cmp_keys, free_key, free_value)) - { - free(hashtable); - return NULL; - } - - return hashtable; -} - -void hashtable_destroy(hashtable_t *hashtable) -{ - hashtable_close(hashtable); - free(hashtable); -} - -int hashtable_init(hashtable_t *hashtable, - key_hash_fn hash_key, key_cmp_fn cmp_keys, - free_fn free_key, free_fn free_value) +int hashtable_init(hashtable_t *hashtable) { - unsigned int i; + size_t i; hashtable->size = 0; hashtable->num_buckets = 0; /* index to primes[] */ - hashtable->buckets = malloc(num_buckets(hashtable) * sizeof(bucket_t)); + hashtable->buckets = jsonp_malloc(num_buckets(hashtable) * sizeof(bucket_t)); if(!hashtable->buckets) return -1; list_init(&hashtable->list); - hashtable->hash_key = hash_key; - hashtable->cmp_keys = cmp_keys; - hashtable->free_key = free_key; - hashtable->free_value = free_value; - for(i = 0; i < num_buckets(hashtable); i++) { hashtable->buckets[i].first = hashtable->buckets[i].last = @@ -244,42 +218,45 @@ int hashtable_init(hashtable_t *hashtable, void hashtable_close(hashtable_t *hashtable) { hashtable_do_clear(hashtable); - free(hashtable->buckets); + jsonp_free(hashtable->buckets); } -int hashtable_set(hashtable_t *hashtable, void *key, void *value) +int hashtable_set(hashtable_t *hashtable, + const char *key, size_t serial, + json_t *value) { pair_t *pair; bucket_t *bucket; - unsigned int hash, index; + size_t hash, index; /* rehash if the load ratio exceeds 1 */ if(hashtable->size >= num_buckets(hashtable)) if(hashtable_do_rehash(hashtable)) return -1; - hash = hashtable->hash_key(key); + hash = hash_str(key); index = hash % num_buckets(hashtable); bucket = &hashtable->buckets[index]; pair = hashtable_find_pair(hashtable, bucket, key, hash); if(pair) { - if(hashtable->free_key) - hashtable->free_key(key); - if(hashtable->free_value) - hashtable->free_value(pair->value); + json_decref(pair->value); pair->value = value; } else { - pair = malloc(sizeof(pair_t)); + /* offsetof(...) returns the size of pair_t without the last, + flexible member. This way, the correct amount is + allocated. */ + pair = jsonp_malloc(offsetof(pair_t, key) + strlen(key) + 1); if(!pair) return -1; - pair->key = key; - pair->value = value; pair->hash = hash; + pair->serial = serial; + strcpy(pair->key, key); + pair->value = value; list_init(&pair->list); insert_to_bucket(hashtable, bucket, &pair->list); @@ -289,13 +266,13 @@ int hashtable_set(hashtable_t *hashtable, void *key, void *value) return 0; } -void *hashtable_get(hashtable_t *hashtable, const void *key) +void *hashtable_get(hashtable_t *hashtable, const char *key) { pair_t *pair; - unsigned int hash; + size_t hash; bucket_t *bucket; - hash = hashtable->hash_key(key); + hash = hash_str(key); bucket = &hashtable->buckets[hash % num_buckets(hashtable)]; pair = hashtable_find_pair(hashtable, bucket, key, hash); @@ -305,15 +282,15 @@ void *hashtable_get(hashtable_t *hashtable, const void *key) return pair->value; } -int hashtable_del(hashtable_t *hashtable, const void *key) +int hashtable_del(hashtable_t *hashtable, const char *key) { - unsigned int hash = hashtable->hash_key(key); + size_t hash = hash_str(key); return hashtable_do_del(hashtable, key, hash); } void hashtable_clear(hashtable_t *hashtable) { - unsigned int i; + size_t i; hashtable_do_clear(hashtable); @@ -332,13 +309,13 @@ void *hashtable_iter(hashtable_t *hashtable) return hashtable_iter_next(hashtable, &hashtable->list); } -void *hashtable_iter_at(hashtable_t *hashtable, const void *key) +void *hashtable_iter_at(hashtable_t *hashtable, const char *key) { pair_t *pair; - unsigned int hash; + size_t hash; bucket_t *bucket; - hash = hashtable->hash_key(key); + hash = hash_str(key); bucket = &hashtable->buckets[hash % num_buckets(hashtable)]; pair = hashtable_find_pair(hashtable, bucket, key, hash); @@ -362,18 +339,22 @@ void *hashtable_iter_key(void *iter) return pair->key; } +size_t hashtable_iter_serial(void *iter) +{ + pair_t *pair = list_to_pair((list_t *)iter); + return pair->serial; +} + void *hashtable_iter_value(void *iter) { pair_t *pair = list_to_pair((list_t *)iter); return pair->value; } -void hashtable_iter_set(hashtable_t *hashtable, void *iter, void *value) +void hashtable_iter_set(void *iter, json_t *value) { pair_t *pair = list_to_pair((list_t *)iter); - if(hashtable->free_value) - hashtable->free_value(pair->value); - + json_decref(pair->value); pair->value = value; } diff --git a/compat/jansson/hashtable.h b/compat/jansson/hashtable.h index 52f8549..3c9fdc2 100644 --- a/compat/jansson/hashtable.h +++ b/compat/jansson/hashtable.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * This library is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -8,20 +8,20 @@ #ifndef HASHTABLE_H #define HASHTABLE_H -typedef unsigned int (*key_hash_fn)(const void *key); -typedef int (*key_cmp_fn)(const void *key1, const void *key2); -typedef void (*free_fn)(void *key); - struct hashtable_list { struct hashtable_list *prev; struct hashtable_list *next; }; +/* "pair" may be a bit confusing a name, but think of it as a + key-value pair. In this case, it just encodes some extra data, + too */ struct hashtable_pair { - void *key; - void *value; - unsigned int hash; + size_t hash; struct hashtable_list list; + json_t *value; + size_t serial; + char key[1]; }; struct hashtable_bucket { @@ -30,60 +30,27 @@ struct hashtable_bucket { }; typedef struct hashtable { - unsigned int size; + size_t size; struct hashtable_bucket *buckets; - unsigned int num_buckets; /* index to primes[] */ + size_t num_buckets; /* index to primes[] */ struct hashtable_list list; - - key_hash_fn hash_key; - key_cmp_fn cmp_keys; /* returns non-zero for equal keys */ - free_fn free_key; - free_fn free_value; } hashtable_t; -/** - * hashtable_create - Create a hashtable object - * - * @hash_key: The key hashing function - * @cmp_keys: The key compare function. Returns non-zero for equal and - * zero for unequal unequal keys - * @free_key: If non-NULL, called for a key that is no longer referenced. - * @free_value: If non-NULL, called for a value that is no longer referenced. - * - * Returns a new hashtable object that should be freed with - * hashtable_destroy when it's no longer used, or NULL on failure (out - * of memory). - */ -hashtable_t *hashtable_create(key_hash_fn hash_key, key_cmp_fn cmp_keys, - free_fn free_key, free_fn free_value); -/** - * hashtable_destroy - Destroy a hashtable object - * - * @hashtable: The hashtable - * - * Destroys a hashtable created with hashtable_create(). - */ -void hashtable_destroy(hashtable_t *hashtable); +#define hashtable_key_to_iter(key_) \ + (&(container_of(key_, struct hashtable_pair, key)->list)) /** * hashtable_init - Initialize a hashtable object * * @hashtable: The (statically allocated) hashtable object - * @hash_key: The key hashing function - * @cmp_keys: The key compare function. Returns non-zero for equal and - * zero for unequal unequal keys - * @free_key: If non-NULL, called for a key that is no longer referenced. - * @free_value: If non-NULL, called for a value that is no longer referenced. * * Initializes a statically allocated hashtable object. The object * should be cleared with hashtable_close when it's no longer used. * * Returns 0 on success, -1 on error (out of memory). */ -int hashtable_init(hashtable_t *hashtable, - key_hash_fn hash_key, key_cmp_fn cmp_keys, - free_fn free_key, free_fn free_value); +int hashtable_init(hashtable_t *hashtable); /** * hashtable_close - Release all resources used by a hashtable object @@ -99,20 +66,19 @@ void hashtable_close(hashtable_t *hashtable); * * @hashtable: The hashtable object * @key: The key + * @serial: For addition order of keys * @value: The value * * If a value with the given key already exists, its value is replaced - * with the new value. - * - * Key and value are "stealed" in the sense that hashtable frees them - * automatically when they are no longer used. The freeing is - * accomplished by calling free_key and free_value functions that were - * supplied to hashtable_new. In case one or both of the free - * functions is NULL, the corresponding item is not "stealed". + * with the new value. Value is "stealed" in the sense that hashtable + * doesn't increment its refcount but decreases the refcount when the + * value is no longer needed. * * Returns 0 on success, -1 on failure (out of memory). */ -int hashtable_set(hashtable_t *hashtable, void *key, void *value); +int hashtable_set(hashtable_t *hashtable, + const char *key, size_t serial, + json_t *value); /** * hashtable_get - Get a value associated with a key @@ -122,7 +88,7 @@ int hashtable_set(hashtable_t *hashtable, void *key, void *value); * * Returns value if it is found, or NULL otherwise. */ -void *hashtable_get(hashtable_t *hashtable, const void *key); +void *hashtable_get(hashtable_t *hashtable, const char *key); /** * hashtable_del - Remove a value from the hashtable @@ -132,7 +98,7 @@ void *hashtable_get(hashtable_t *hashtable, const void *key); * * Returns 0 on success, or -1 if the key was not found. */ -int hashtable_del(hashtable_t *hashtable, const void *key); +int hashtable_del(hashtable_t *hashtable, const char *key); /** * hashtable_clear - Clear hashtable @@ -169,7 +135,7 @@ void *hashtable_iter(hashtable_t *hashtable); * Like hashtable_iter() but returns an iterator pointing to a * specific key. */ -void *hashtable_iter_at(hashtable_t *hashtable, const void *key); +void *hashtable_iter_at(hashtable_t *hashtable, const char *key); /** * hashtable_iter_next - Advance an iterator @@ -189,6 +155,13 @@ void *hashtable_iter_next(hashtable_t *hashtable, void *iter); */ void *hashtable_iter_key(void *iter); +/** + * hashtable_iter_serial - Retrieve the serial number pointed to by an iterator + * + * @iter: The iterator + */ +size_t hashtable_iter_serial(void *iter); + /** * hashtable_iter_value - Retrieve the value pointed by an iterator * @@ -202,6 +175,6 @@ void *hashtable_iter_value(void *iter); * @iter: The iterator * @value: The value to set */ -void hashtable_iter_set(hashtable_t *hashtable, void *iter, void *value); +void hashtable_iter_set(void *iter, json_t *value); #endif diff --git a/compat/jansson/jansson.h b/compat/jansson/jansson.h index 781896c..d1de218 100644 --- a/compat/jansson/jansson.h +++ b/compat/jansson/jansson.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -9,23 +9,31 @@ #define JANSSON_H #include +#include /* for size_t */ +#include -#ifdef WIN32 -#define snprintf(...) _snprintf(__VA_ARGS__) -#define strdup(x) _strdup(x) -#endif - -#ifdef WIN32 -#define inline __inline -#endif +#include -#ifndef __cplusplus -#define JSON_INLINE inline -#else -#define JSON_INLINE inline +#ifdef __cplusplus extern "C" { #endif +/* version */ + +#define JANSSON_MAJOR_VERSION 2 +#define JANSSON_MINOR_VERSION 5 +#define JANSSON_MICRO_VERSION 0 + +/* Micro version is omitted if it's 0 */ +#define JANSSON_VERSION "2.5" + +/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this + for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */ +#define JANSSON_VERSION_HEX ((JANSSON_MAJOR_VERSION << 16) | \ + (JANSSON_MINOR_VERSION << 8) | \ + (JANSSON_MICRO_VERSION << 0)) + + /* types */ typedef enum { @@ -39,11 +47,25 @@ typedef enum { JSON_NULL } json_type; -typedef struct { +typedef struct json_t { json_type type; - unsigned long refcount; + size_t refcount; } json_t; +#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ +#if JSON_INTEGER_IS_LONG_LONG +#ifdef _WIN32 +#define JSON_INTEGER_FORMAT "I64d" +#else +#define JSON_INTEGER_FORMAT "lld" +#endif +typedef long long json_int_t; +#else +#define JSON_INTEGER_FORMAT "ld" +typedef long json_int_t; +#endif /* JSON_INTEGER_IS_LONG_LONG */ +#endif + #define json_typeof(json) ((json)->type) #define json_is_object(json) (json && json_typeof(json) == JSON_OBJECT) #define json_is_array(json) (json && json_typeof(json) == JSON_ARRAY) @@ -62,16 +84,17 @@ json_t *json_object(void); json_t *json_array(void); json_t *json_string(const char *value); json_t *json_string_nocheck(const char *value); -json_t *json_integer(int value); +json_t *json_integer(json_int_t value); json_t *json_real(double value); json_t *json_true(void); json_t *json_false(void); +#define json_boolean(val) ((val) ? json_true() : json_false()) json_t *json_null(void); static JSON_INLINE json_t *json_incref(json_t *json) { - if(json && json->refcount != (unsigned int)-1) + if(json && json->refcount != (size_t)-1) ++json->refcount; return json; } @@ -82,27 +105,54 @@ void json_delete(json_t *json); static JSON_INLINE void json_decref(json_t *json) { - if(json && json->refcount != (unsigned int)-1 && --json->refcount == 0) + if(json && json->refcount != (size_t)-1 && --json->refcount == 0) json_delete(json); } +/* error reporting */ + +#define JSON_ERROR_TEXT_LENGTH 160 +#define JSON_ERROR_SOURCE_LENGTH 80 + +typedef struct { + int line; + int column; + int position; + char source[JSON_ERROR_SOURCE_LENGTH]; + char text[JSON_ERROR_TEXT_LENGTH]; +} json_error_t; + + /* getters, setters, manipulation */ -unsigned int json_object_size(const json_t *object); +size_t json_object_size(const json_t *object); json_t *json_object_get(const json_t *object, const char *key); int json_object_set_new(json_t *object, const char *key, json_t *value); int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value); int json_object_del(json_t *object, const char *key); int json_object_clear(json_t *object); int json_object_update(json_t *object, json_t *other); +int json_object_update_existing(json_t *object, json_t *other); +int json_object_update_missing(json_t *object, json_t *other); void *json_object_iter(json_t *object); void *json_object_iter_at(json_t *object, const char *key); +void *json_object_key_to_iter(const char *key); void *json_object_iter_next(json_t *object, void *iter); const char *json_object_iter_key(void *iter); json_t *json_object_iter_value(void *iter); int json_object_iter_set_new(json_t *object, void *iter, json_t *value); +#define json_object_foreach(object, key, value) \ + for(key = json_object_iter_key(json_object_iter(object)); \ + key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ + key = json_object_iter_key(json_object_iter_next(object, json_object_key_to_iter(key)))) + +#define json_array_foreach(array, index, value) \ + for(index = 0; \ + index < json_array_size(array) && (value = json_array_get(array, index)); \ + index++) + static JSON_INLINE int json_object_set(json_t *object, const char *key, json_t *value) { @@ -115,25 +165,25 @@ int json_object_set_nocheck(json_t *object, const char *key, json_t *value) return json_object_set_new_nocheck(object, key, json_incref(value)); } -static inline +static JSON_INLINE int json_object_iter_set(json_t *object, void *iter, json_t *value) { return json_object_iter_set_new(object, iter, json_incref(value)); } -unsigned int json_array_size(const json_t *array); -json_t *json_array_get(const json_t *array, unsigned int index); -int json_array_set_new(json_t *array, unsigned int index, json_t *value); +size_t json_array_size(const json_t *array); +json_t *json_array_get(const json_t *array, size_t index); +int json_array_set_new(json_t *array, size_t index, json_t *value); int json_array_append_new(json_t *array, json_t *value); -int json_array_insert_new(json_t *array, unsigned int index, json_t *value); -int json_array_remove(json_t *array, unsigned int index); +int json_array_insert_new(json_t *array, size_t index, json_t *value); +int json_array_remove(json_t *array, size_t index); int json_array_clear(json_t *array); int json_array_extend(json_t *array, json_t *other); static JSON_INLINE -int json_array_set(json_t *array, unsigned int index, json_t *value) +int json_array_set(json_t *array, size_t ind, json_t *value) { - return json_array_set_new(array, index, json_incref(value)); + return json_array_set_new(array, ind, json_incref(value)); } static JSON_INLINE @@ -143,22 +193,36 @@ int json_array_append(json_t *array, json_t *value) } static JSON_INLINE -int json_array_insert(json_t *array, unsigned int index, json_t *value) +int json_array_insert(json_t *array, size_t ind, json_t *value) { - return json_array_insert_new(array, index, json_incref(value)); + return json_array_insert_new(array, ind, json_incref(value)); } const char *json_string_value(const json_t *string); -int json_integer_value(const json_t *integer); +json_int_t json_integer_value(const json_t *integer); double json_real_value(const json_t *real); double json_number_value(const json_t *json); int json_string_set(json_t *string, const char *value); int json_string_set_nocheck(json_t *string, const char *value); -int json_integer_set(json_t *integer, int value); +int json_integer_set(json_t *integer, json_int_t value); int json_real_set(json_t *real, double value); +/* pack, unpack */ + +json_t *json_pack(const char *fmt, ...); +json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...); +json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap); + +#define JSON_VALIDATE_ONLY 0x1 +#define JSON_STRICT 0x2 + +int json_unpack(json_t *root, const char *fmt, ...); +int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...); +int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, va_list ap); + + /* equality */ int json_equal(json_t *value1, json_t *value2); @@ -167,31 +231,48 @@ int json_equal(json_t *value1, json_t *value2); /* copying */ json_t *json_copy(json_t *value); -json_t *json_deep_copy(json_t *value); +json_t *json_deep_copy(const json_t *value); -/* loading, printing */ +/* decoding */ -#define JSON_ERROR_TEXT_LENGTH 160 +#define JSON_REJECT_DUPLICATES 0x1 +#define JSON_DISABLE_EOF_CHECK 0x2 +#define JSON_DECODE_ANY 0x4 +#define JSON_DECODE_INT_AS_REAL 0x8 -typedef struct { - char text[JSON_ERROR_TEXT_LENGTH]; - int line; -} json_error_t; +typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data); + +json_t *json_loads(const char *input, size_t flags, json_error_t *error); +json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error); +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error); +json_t *json_load_file(const char *path, size_t flags, json_error_t *error); +json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error); + + +/* encoding */ + +#define JSON_INDENT(n) (n & 0x1F) +#define JSON_COMPACT 0x20 +#define JSON_ENSURE_ASCII 0x40 +#define JSON_SORT_KEYS 0x80 +#define JSON_PRESERVE_ORDER 0x100 +#define JSON_ENCODE_ANY 0x200 +#define JSON_ESCAPE_SLASH 0x400 + +typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data); + +char *json_dumps(const json_t *json, size_t flags); +int json_dumpf(const json_t *json, FILE *output, size_t flags); +int json_dump_file(const json_t *json, const char *path, size_t flags); +int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags); -json_t *json_loads(const char *input, json_error_t *error); -json_t *json_loadf(FILE *input, json_error_t *error); -json_t *json_load_file(const char *path, json_error_t *error); +/* custom memory allocation */ -#define JSON_INDENT(n) (n & 0xFF) -#define JSON_COMPACT 0x100 -#define JSON_ENSURE_ASCII 0x200 -#define JSON_SORT_KEYS 0x400 -#define JSON_PRESERVE_ORDER 0x800 +typedef void *(*json_malloc_t)(size_t); +typedef void (*json_free_t)(void *); -char *json_dumps(const json_t *json, unsigned long flags); -int json_dumpf(const json_t *json, FILE *output, unsigned long flags); -int json_dump_file(const json_t *json, const char *path, unsigned long flags); +void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn); #ifdef __cplusplus } diff --git a/compat/jansson/jansson_config.h b/compat/jansson/jansson_config.h new file mode 100644 index 0000000..90ca129 --- /dev/null +++ b/compat/jansson/jansson_config.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010-2013 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The configure script copies this file to jansson_config.h and + * replaces @var@ substitutions by values that fit your system. If you + * cannot run the configure script, you can do the value substitution + * by hand. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ + +#ifdef _MSC_VER +#define inline __inline +#endif + +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE inline +#endif + +/* If your compiler supports the `long long` type and the strtoll() + library function, JSON_INTEGER_IS_LONG_LONG is defined to 1, + otherwise to 0. */ +#define JSON_INTEGER_IS_LONG_LONG 1 + +/* If locale.h and localeconv() are available, define to 1, + otherwise to 0. */ +#define JSON_HAVE_LOCALECONV 1 + +#endif diff --git a/compat/jansson/jansson_private.h b/compat/jansson/jansson_private.h index 3a3ed75..b47d404 100644 --- a/compat/jansson/jansson_private.h +++ b/compat/jansson/jansson_private.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -8,23 +8,40 @@ #ifndef JANSSON_PRIVATE_H #define JANSSON_PRIVATE_H +#include #include "jansson.h" #include "hashtable.h" +#include "strbuffer.h" #define container_of(ptr_, type_, member_) \ - ((type_ *)((char *)ptr_ - (size_t)&((type_ *)0)->member_)) + ((type_ *)((char *)ptr_ - offsetof(type_, member_))) + +/* On some platforms, max() may already be defined */ +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +/* va_copy is a C99 feature. In C89 implementations, it's sometimes + available as __va_copy. If not, memcpy() should do the trick. */ +#ifndef va_copy +#ifdef __va_copy +#define va_copy __va_copy +#else +#define va_copy(a, b) memcpy(&(a), &(b), sizeof(va_list)) +#endif +#endif typedef struct { json_t json; hashtable_t hashtable; - unsigned long serial; + size_t serial; int visited; } json_object_t; typedef struct { json_t json; - unsigned int size; - unsigned int entries; + size_t size; + size_t entries; json_t **table; int visited; } json_array_t; @@ -41,7 +58,7 @@ typedef struct { typedef struct { json_t json; - int value; + json_int_t value; } json_integer_t; #define json_to_object(json_) container_of(json_, json_object_t, json) @@ -50,11 +67,27 @@ typedef struct { #define json_to_real(json_) container_of(json_, json_real_t, json) #define json_to_integer(json_) container_of(json_, json_integer_t, json) -typedef struct { - unsigned long serial; - char key[]; -} object_key_t; +void jsonp_error_init(json_error_t *error, const char *source); +void jsonp_error_set_source(json_error_t *error, const char *source); +void jsonp_error_set(json_error_t *error, int line, int column, + size_t position, const char *msg, ...); +void jsonp_error_vset(json_error_t *error, int line, int column, + size_t position, const char *msg, va_list ap); + +/* Locale independent string<->double conversions */ +int jsonp_strtod(strbuffer_t *strbuffer, double *out); +int jsonp_dtostr(char *buffer, size_t size, double value); -const object_key_t *jsonp_object_iter_fullkey(void *iter); +/* Wrappers for custom memory functions */ +void* jsonp_malloc(size_t size); +void jsonp_free(void *ptr); +char *jsonp_strndup(const char *str, size_t length); +char *jsonp_strdup(const char *str); + +/* Windows compatibility */ +#ifdef _WIN32 +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#endif #endif diff --git a/compat/jansson/load.c b/compat/jansson/load.c index ee56fbe..45e21d0 100644 --- a/compat/jansson/load.c +++ b/compat/jansson/load.c @@ -1,25 +1,30 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ +#ifndef _GNU_SOURCE #define _GNU_SOURCE -#include +#endif + #include #include #include #include #include -#include #include -#include +#include "jansson.h" #include "jansson_private.h" #include "strbuffer.h" #include "utf.h" +#define STREAM_STATE_OK 0 +#define STREAM_STATE_EOF -1 +#define STREAM_STATE_ERROR -2 + #define TOKEN_INVALID -1 #define TOKEN_EOF 0 #define TOKEN_STRING 256 @@ -29,113 +34,136 @@ #define TOKEN_FALSE 260 #define TOKEN_NULL 261 -/* read one byte from stream, return EOF on end of file */ +/* Locale independent versions of isxxx() functions */ +#define l_isupper(c) ('A' <= (c) && (c) <= 'Z') +#define l_islower(c) ('a' <= (c) && (c) <= 'z') +#define l_isalpha(c) (l_isupper(c) || l_islower(c)) +#define l_isdigit(c) ('0' <= (c) && (c) <= '9') +#define l_isxdigit(c) \ + (l_isdigit(c) || ('A' <= (c) && (c) <= 'F') || ('a' <= (c) && (c) <= 'f')) + +/* Read one byte from stream, convert to unsigned char, then int, and + return. return EOF on end of file. This corresponds to the + behaviour of fgetc(). */ typedef int (*get_func)(void *data); -/* return non-zero if end of file has been reached */ -typedef int (*eof_func)(void *data); - typedef struct { get_func get; - eof_func eof; void *data; - int stream_pos; char buffer[5]; - int buffer_pos; + size_t buffer_pos; + int state; + int line; + int column, last_column; + size_t position; } stream_t; - typedef struct { stream_t stream; strbuffer_t saved_text; int token; - int line, column; union { char *string; - int integer; + json_int_t integer; double real; } value; } lex_t; +#define stream_to_lex(stream) container_of(stream, lex_t, stream) -/*** error reporting ***/ -static void error_init(json_error_t *error) -{ - if(error) - { - error->text[0] = '\0'; - error->line = -1; - } -} +/*** error reporting ***/ static void error_set(json_error_t *error, const lex_t *lex, const char *msg, ...) { va_list ap; - char text[JSON_ERROR_TEXT_LENGTH]; + char msg_text[JSON_ERROR_TEXT_LENGTH]; + char msg_with_context[JSON_ERROR_TEXT_LENGTH]; + + int line = -1, col = -1; + size_t pos = 0; + const char *result = msg_text; - if(!error || error->text[0] != '\0') { - /* error already set */ + if(!error) return; - } va_start(ap, msg); - vsnprintf(text, JSON_ERROR_TEXT_LENGTH, msg, ap); + vsnprintf(msg_text, JSON_ERROR_TEXT_LENGTH, msg, ap); + msg_text[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; va_end(ap); if(lex) { const char *saved_text = strbuffer_value(&lex->saved_text); - error->line = lex->line; + + line = lex->stream.line; + col = lex->stream.column; + pos = lex->stream.position; + if(saved_text && saved_text[0]) { if(lex->saved_text.length <= 20) { - snprintf(error->text, JSON_ERROR_TEXT_LENGTH, - "%s near '%s'", text, saved_text); + snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, + "%s near '%s'", msg_text, saved_text); + msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + result = msg_with_context; } - else - snprintf(error->text, JSON_ERROR_TEXT_LENGTH, "%s", text); } else { - snprintf(error->text, JSON_ERROR_TEXT_LENGTH, - "%s near end of file", text); + if(lex->stream.state == STREAM_STATE_ERROR) { + /* No context for UTF-8 decoding errors */ + result = msg_text; + } + else { + snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, + "%s near end of file", msg_text); + msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + result = msg_with_context; + } } } - else - { - error->line = -1; - snprintf(error->text, JSON_ERROR_TEXT_LENGTH, "%s", text); - } + + jsonp_error_set(error, line, col, pos, "%s", result); } /*** lexical analyzer ***/ static void -stream_init(stream_t *stream, get_func get, eof_func eof, void *data) +stream_init(stream_t *stream, get_func get, void *data) { stream->get = get; - stream->eof = eof; stream->data = data; - stream->stream_pos = 0; stream->buffer[0] = '\0'; stream->buffer_pos = 0; + + stream->state = STREAM_STATE_OK; + stream->line = 1; + stream->column = 0; + stream->position = 0; } -static char stream_get(stream_t *stream, json_error_t *error) +static int stream_get(stream_t *stream, json_error_t *error) { - char c; + int c; + + if(stream->state != STREAM_STATE_OK) + return stream->state; if(!stream->buffer[stream->buffer_pos]) { - stream->buffer[0] = stream->get(stream->data); - stream->buffer_pos = 0; + c = stream->get(stream->data); + if(c == EOF) { + stream->state = STREAM_STATE_EOF; + return STREAM_STATE_EOF; + } - c = stream->buffer[0]; + stream->buffer[0] = c; + stream->buffer_pos = 0; - if((unsigned char)c >= 0x80 && c != (char)EOF) + if(0x80 <= c && c <= 0xFF) { /* multi-byte UTF-8 sequence */ int i, count; @@ -152,30 +180,47 @@ static char stream_get(stream_t *stream, json_error_t *error) if(!utf8_check_full(stream->buffer, count, NULL)) goto out; - stream->stream_pos += count; stream->buffer[count] = '\0'; } - else { + else stream->buffer[1] = '\0'; - stream->stream_pos++; - } } - return stream->buffer[stream->buffer_pos++]; + c = stream->buffer[stream->buffer_pos++]; -out: - error_set(error, NULL, "unable to decode byte 0x%x at position %d", - (unsigned char)c, stream->stream_pos); + stream->position++; + if(c == '\n') { + stream->line++; + stream->last_column = stream->column; + stream->column = 0; + } + else if(utf8_check_first(c)) { + /* track the Unicode character column, so increment only if + this is the first character of a UTF-8 sequence */ + stream->column++; + } - stream->buffer[0] = EOF; - stream->buffer[1] = '\0'; - stream->buffer_pos = 1; + return c; - return EOF; +out: + stream->state = STREAM_STATE_ERROR; + error_set(error, stream_to_lex(stream), "unable to decode byte 0x%x", c); + return STREAM_STATE_ERROR; } -static void stream_unget(stream_t *stream, char c) +static void stream_unget(stream_t *stream, int c) { + if(c == STREAM_STATE_EOF || c == STREAM_STATE_ERROR) + return; + + stream->position--; + if(c == '\n') { + stream->line--; + stream->column = stream->last_column; + } + else if(utf8_check_first(c)) + stream->column--; + assert(stream->buffer_pos > 0); stream->buffer_pos--; assert(stream->buffer[stream->buffer_pos] == c); @@ -187,29 +232,41 @@ static int lex_get(lex_t *lex, json_error_t *error) return stream_get(&lex->stream, error); } -static int lex_eof(lex_t *lex) -{ - return lex->stream.eof(lex->stream.data); -} - -static void lex_save(lex_t *lex, char c) +static void lex_save(lex_t *lex, int c) { strbuffer_append_byte(&lex->saved_text, c); } static int lex_get_save(lex_t *lex, json_error_t *error) { - char c = stream_get(&lex->stream, error); - lex_save(lex, c); + int c = stream_get(&lex->stream, error); + if(c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) + lex_save(lex, c); return c; } -static void lex_unget_unsave(lex_t *lex, char c) +static void lex_unget(lex_t *lex, int c) { - char d; stream_unget(&lex->stream, c); - d = strbuffer_pop(&lex->saved_text); - assert(c == d); +} + +static void lex_unget_unsave(lex_t *lex, int c) +{ + if(c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) { + /* Since we treat warnings as errors, when assertions are turned + * off the "d" variable would be set but never used. Which is + * treated as an error by GCC. + */ + #ifndef NDEBUG + char d; + #endif + stream_unget(&lex->stream, c); + #ifndef NDEBUG + d = + #endif + strbuffer_pop(&lex->saved_text); + assert(c == d); + } } static void lex_save_cached(lex_t *lex) @@ -218,6 +275,7 @@ static void lex_save_cached(lex_t *lex) { lex_save(lex, lex->stream.buffer[lex->stream.buffer_pos]); lex->stream.buffer_pos++; + lex->stream.position++; } } @@ -232,11 +290,11 @@ static int32_t decode_unicode_escape(const char *str) for(i = 1; i <= 4; i++) { char c = str[i]; value <<= 4; - if(isdigit(c)) + if(l_isdigit(c)) value += c - '0'; - else if(islower(c)) + else if(l_islower(c)) value += c - 'a' + 10; - else if(isupper(c)) + else if(l_isupper(c)) value += c - 'A' + 10; else assert(0); @@ -247,7 +305,7 @@ static int32_t decode_unicode_escape(const char *str) static void lex_scan_string(lex_t *lex, json_error_t *error) { - char c; + int c; const char *p; char *t; int i; @@ -258,14 +316,15 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) c = lex_get_save(lex, error); while(c != '"') { - if(c == (char)EOF) { - lex_unget_unsave(lex, c); - if(lex_eof(lex)) - error_set(error, lex, "premature end of input"); + if(c == STREAM_STATE_ERROR) + goto out; + + else if(c == STREAM_STATE_EOF) { + error_set(error, lex, "premature end of input"); goto out; } - else if((unsigned char)c <= 0x1F) { + else if(0 <= c && c <= 0x1F) { /* control character */ lex_unget_unsave(lex, c); if(c == '\n') @@ -280,8 +339,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) if(c == 'u') { c = lex_get_save(lex, error); for(i = 0; i < 4; i++) { - if(!isxdigit(c)) { - lex_unget_unsave(lex, c); + if(!l_isxdigit(c)) { error_set(error, lex, "invalid escape"); goto out; } @@ -292,7 +350,6 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) c == 'f' || c == 'n' || c == 'r' || c == 't') c = lex_get_save(lex, error); else { - lex_unget_unsave(lex, c); error_set(error, lex, "invalid escape"); goto out; } @@ -308,7 +365,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) - two \uXXXX escapes (length 12) forming an UTF-16 surrogate pair are converted to 4 bytes */ - lex->value.string = malloc(lex->saved_text.length + 1); + lex->value.string = jsonp_malloc(lex->saved_text.length + 1); if(!lex->value.string) { /* this is not very nice, since TOKEN_INVALID is returned */ goto out; @@ -398,10 +455,22 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) return; out: - free(lex->value.string); + jsonp_free(lex->value.string); } -static int lex_scan_number(lex_t *lex, char c, json_error_t *error) +#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ +#if JSON_INTEGER_IS_LONG_LONG +#ifdef _MSC_VER /* Microsoft Visual Studio */ +#define json_strtoint _strtoi64 +#else +#define json_strtoint strtoll +#endif +#else +#define json_strtoint strtol +#endif +#endif + +static int lex_scan_number(lex_t *lex, int c, json_error_t *error) { const char *saved_text; char *end; @@ -414,52 +483,55 @@ static int lex_scan_number(lex_t *lex, char c, json_error_t *error) if(c == '0') { c = lex_get_save(lex, error); - if(isdigit(c)) { + if(l_isdigit(c)) { lex_unget_unsave(lex, c); goto out; } } - else if(isdigit(c)) { + else if(l_isdigit(c)) { c = lex_get_save(lex, error); - while(isdigit(c)) + while(l_isdigit(c)) c = lex_get_save(lex, error); } else { - lex_unget_unsave(lex, c); - goto out; + lex_unget_unsave(lex, c); + goto out; } if(c != '.' && c != 'E' && c != 'e') { - long value; + json_int_t value; lex_unget_unsave(lex, c); saved_text = strbuffer_value(&lex->saved_text); - value = strtol(saved_text, &end, 10); - assert(end == saved_text + lex->saved_text.length); - if((value == LONG_MAX && errno == ERANGE) || value > INT_MAX) { - error_set(error, lex, "too big integer"); - goto out; - } - else if((value == LONG_MIN && errno == ERANGE) || value < INT_MIN) { - error_set(error, lex, "too big negative integer"); + errno = 0; + value = json_strtoint(saved_text, &end, 10); + if(errno == ERANGE) { + if(value < 0) + error_set(error, lex, "too big negative integer"); + else + error_set(error, lex, "too big integer"); goto out; } + assert(end == saved_text + lex->saved_text.length); + lex->token = TOKEN_INTEGER; - lex->value.integer = (int)value; + lex->value.integer = value; return 0; } if(c == '.') { c = lex_get(lex, error); - if(!isdigit(c)) + if(!l_isdigit(c)) { + lex_unget(lex, c); goto out; + } lex_save(lex, c); c = lex_get_save(lex, error); - while(isdigit(c)) + while(l_isdigit(c)) c = lex_get_save(lex, error); } @@ -468,23 +540,19 @@ static int lex_scan_number(lex_t *lex, char c, json_error_t *error) if(c == '+' || c == '-') c = lex_get_save(lex, error); - if(!isdigit(c)) { + if(!l_isdigit(c)) { lex_unget_unsave(lex, c); goto out; } c = lex_get_save(lex, error); - while(isdigit(c)) + while(l_isdigit(c)) c = lex_get_save(lex, error); } lex_unget_unsave(lex, c); - saved_text = strbuffer_value(&lex->saved_text); - value = strtod(saved_text, &end); - assert(end == saved_text + lex->saved_text.length); - - if(errno == ERANGE && value != 0) { + if(jsonp_strtod(&lex->saved_text, &value)) { error_set(error, lex, "real number overflow"); goto out; } @@ -499,29 +567,26 @@ out: static int lex_scan(lex_t *lex, json_error_t *error) { - char c; + int c; strbuffer_clear(&lex->saved_text); if(lex->token == TOKEN_STRING) { - free(lex->value.string); + jsonp_free(lex->value.string); lex->value.string = NULL; } c = lex_get(lex, error); while(c == ' ' || c == '\t' || c == '\n' || c == '\r') - { - if(c == '\n') - lex->line++; - c = lex_get(lex, error); + + if(c == STREAM_STATE_EOF) { + lex->token = TOKEN_EOF; + goto out; } - if(c == (char)EOF) { - if(lex_eof(lex)) - lex->token = TOKEN_EOF; - else - lex->token = TOKEN_INVALID; + if(c == STREAM_STATE_ERROR) { + lex->token = TOKEN_INVALID; goto out; } @@ -533,17 +598,17 @@ static int lex_scan(lex_t *lex, json_error_t *error) else if(c == '"') lex_scan_string(lex, error); - else if(isdigit(c) || c == '-') { + else if(l_isdigit(c) || c == '-') { if(lex_scan_number(lex, c, error)) goto out; } - else if(isupper(c) || islower(c)) { + else if(l_isalpha(c)) { /* eat up the whole identifier for clearer error messages */ const char *saved_text; c = lex_get_save(lex, error); - while(isupper(c) || islower(c)) + while(l_isalpha(c)) c = lex_get_save(lex, error); lex_unget_unsave(lex, c); @@ -581,31 +646,29 @@ static char *lex_steal_string(lex_t *lex) return result; } -static int lex_init(lex_t *lex, get_func get, eof_func eof, void *data) +static int lex_init(lex_t *lex, get_func get, void *data) { - stream_init(&lex->stream, get, eof, data); + stream_init(&lex->stream, get, data); if(strbuffer_init(&lex->saved_text)) return -1; lex->token = TOKEN_INVALID; - lex->line = 1; - return 0; } static void lex_close(lex_t *lex) { if(lex->token == TOKEN_STRING) - free(lex->value.string); + jsonp_free(lex->value.string); strbuffer_close(&lex->saved_text); } /*** parser ***/ -static json_t *parse_value(lex_t *lex, json_error_t *error); +static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error); -static json_t *parse_object(lex_t *lex, json_error_t *error) +static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) { json_t *object = json_object(); if(!object) @@ -628,28 +691,36 @@ static json_t *parse_object(lex_t *lex, json_error_t *error) if(!key) return NULL; + if(flags & JSON_REJECT_DUPLICATES) { + if(json_object_get(object, key)) { + jsonp_free(key); + error_set(error, lex, "duplicate object key"); + goto error; + } + } + lex_scan(lex, error); if(lex->token != ':') { - free(key); + jsonp_free(key); error_set(error, lex, "':' expected"); goto error; } lex_scan(lex, error); - value = parse_value(lex, error); + value = parse_value(lex, flags, error); if(!value) { - free(key); + jsonp_free(key); goto error; } if(json_object_set_nocheck(object, key, value)) { - free(key); + jsonp_free(key); json_decref(value); goto error; } json_decref(value); - free(key); + jsonp_free(key); lex_scan(lex, error); if(lex->token != ',') @@ -670,7 +741,7 @@ error: return NULL; } -static json_t *parse_array(lex_t *lex, json_error_t *error) +static json_t *parse_array(lex_t *lex, size_t flags, json_error_t *error) { json_t *array = json_array(); if(!array) @@ -681,7 +752,7 @@ static json_t *parse_array(lex_t *lex, json_error_t *error) return array; while(lex->token) { - json_t *elem = parse_value(lex, error); + json_t *elem = parse_value(lex, flags, error); if(!elem) goto error; @@ -710,9 +781,10 @@ error: return NULL; } -static json_t *parse_value(lex_t *lex, json_error_t *error) +static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error) { json_t *json; + double value; switch(lex->token) { case TOKEN_STRING: { @@ -721,7 +793,15 @@ static json_t *parse_value(lex_t *lex, json_error_t *error) } case TOKEN_INTEGER: { - json = json_integer(lex->value.integer); + if (flags & JSON_DECODE_INT_AS_REAL) { + if(jsonp_strtod(&lex->saved_text, &value)) { + error_set(error, lex, "real number overflow"); + return NULL; + } + json = json_real(value); + } else { + json = json_integer(lex->value.integer); + } break; } @@ -743,11 +823,11 @@ static json_t *parse_value(lex_t *lex, json_error_t *error) break; case '{': - json = parse_object(lex, error); + json = parse_object(lex, flags, error); break; case '[': - json = parse_array(lex, error); + json = parse_array(lex, flags, error); break; case TOKEN_INVALID: @@ -765,17 +845,37 @@ static json_t *parse_value(lex_t *lex, json_error_t *error) return json; } -static json_t *parse_json(lex_t *lex, json_error_t *error) +static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error) { - error_init(error); + json_t *result; lex_scan(lex, error); - if(lex->token != '[' && lex->token != '{') { - error_set(error, lex, "'[' or '{' expected"); + if(!(flags & JSON_DECODE_ANY)) { + if(lex->token != '[' && lex->token != '{') { + error_set(error, lex, "'[' or '{' expected"); + return NULL; + } + } + + result = parse_value(lex, flags, error); + if(!result) return NULL; + + if(!(flags & JSON_DISABLE_EOF_CHECK)) { + lex_scan(lex, error); + if(lex->token != TOKEN_EOF) { + error_set(error, lex, "end of file expected"); + json_decref(result); + return NULL; + } + } + + if(error) { + /* Save the position even though there was no error */ + error->position = lex->stream.position; } - return parse_value(lex, error); + return result; } typedef struct @@ -794,77 +894,120 @@ static int string_get(void *data) else { stream->pos++; - return c; + return (unsigned char)c; } } -static int string_eof(void *data) +json_t *json_loads(const char *string, size_t flags, json_error_t *error) { - string_data_t *stream = (string_data_t *)data; - return (stream->data[stream->pos] == '\0'); + lex_t lex; + json_t *result; + string_data_t stream_data; + + jsonp_error_init(error, ""); + + if (string == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; + } + + stream_data.data = string; + stream_data.pos = 0; + + if(lex_init(&lex, string_get, (void *)&stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +typedef struct +{ + const char *data; + size_t len; + size_t pos; +} buffer_data_t; + +static int buffer_get(void *data) +{ + char c; + buffer_data_t *stream = data; + if(stream->pos >= stream->len) + return EOF; + + c = stream->data[stream->pos]; + stream->pos++; + return (unsigned char)c; } -json_t *json_loads(const char *string, json_error_t *error) +json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) { lex_t lex; json_t *result; + buffer_data_t stream_data; - string_data_t stream_data = { - string, - 0 - }; + jsonp_error_init(error, ""); - if(lex_init(&lex, string_get, string_eof, (void *)&stream_data)) + if (buffer == NULL) { + error_set(error, NULL, "wrong arguments"); return NULL; + } - result = parse_json(&lex, error); - if(!result) - goto out; + stream_data.data = buffer; + stream_data.pos = 0; + stream_data.len = buflen; - lex_scan(&lex, error); - if(lex.token != TOKEN_EOF) { - error_set(error, &lex, "end of file expected"); - json_decref(result); - result = NULL; - } + if(lex_init(&lex, buffer_get, (void *)&stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); -out: lex_close(&lex); return result; } -json_t *json_loadf(FILE *input, json_error_t *error) +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) { lex_t lex; + const char *source; json_t *result; - if(lex_init(&lex, (get_func)fgetc, (eof_func)feof, input)) - return NULL; + if(input == stdin) + source = ""; + else + source = ""; - result = parse_json(&lex, error); - if(!result) - goto out; + jsonp_error_init(error, source); - lex_scan(&lex, error); - if(lex.token != TOKEN_EOF) { - error_set(error, &lex, "end of file expected"); - json_decref(result); - result = NULL; + if (input == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; } -out: + if(lex_init(&lex, (get_func)fgetc, input)) + return NULL; + + result = parse_json(&lex, flags, error); + lex_close(&lex); return result; } -json_t *json_load_file(const char *path, json_error_t *error) +json_t *json_load_file(const char *path, size_t flags, json_error_t *error) { json_t *result; FILE *fp; - error_init(error); + jsonp_error_init(error, path); + + if (path == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; + } - fp = fopen(path, "r"); + fp = fopen(path, "rb"); if(!fp) { error_set(error, NULL, "unable to open %s: %s", @@ -872,8 +1015,63 @@ json_t *json_load_file(const char *path, json_error_t *error) return NULL; } - result = json_loadf(fp, error); + result = json_loadf(fp, flags, error); fclose(fp); return result; } + +#define MAX_BUF_LEN 1024 + +typedef struct +{ + char data[MAX_BUF_LEN]; + size_t len; + size_t pos; + json_load_callback_t callback; + void *arg; +} callback_data_t; + +static int callback_get(void *data) +{ + char c; + callback_data_t *stream = data; + + if(stream->pos >= stream->len) { + stream->pos = 0; + stream->len = stream->callback(stream->data, MAX_BUF_LEN, stream->arg); + if(stream->len == 0 || stream->len == (size_t)-1) + return EOF; + } + + c = stream->data[stream->pos]; + stream->pos++; + return (unsigned char)c; +} + +json_t *json_load_callback(json_load_callback_t callback, void *arg, size_t flags, json_error_t *error) +{ + lex_t lex; + json_t *result; + + callback_data_t stream_data; + + memset(&stream_data, 0, sizeof(stream_data)); + stream_data.callback = callback; + stream_data.arg = arg; + + jsonp_error_init(error, ""); + + if (callback == NULL) { + error_set(error, NULL, "wrong arguments"); + return NULL; + } + + if(lex_init(&lex, (get_func)callback_get, &stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} diff --git a/compat/jansson/memory.c b/compat/jansson/memory.c new file mode 100644 index 0000000..eb6cec5 --- /dev/null +++ b/compat/jansson/memory.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * Copyright (c) 2011-2012 Basile Starynkevitch + * + * Jansson is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include + +#include "jansson.h" +#include "jansson_private.h" + +/* memory function pointers */ +static json_malloc_t do_malloc = malloc; +static json_free_t do_free = free; + +void *jsonp_malloc(size_t size) +{ + if(!size) + return NULL; + + return (*do_malloc)(size); +} + +void jsonp_free(void *ptr) +{ + if(!ptr) + return; + + (*do_free)(ptr); +} + +char *jsonp_strdup(const char *str) +{ + char *new_str; + size_t len; + + len = strlen(str); + if(len == (size_t)-1) + return NULL; + + new_str = jsonp_malloc(len + 1); + if(!new_str) + return NULL; + + memcpy(new_str, str, len + 1); + return new_str; +} + +void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn) +{ + do_malloc = malloc_fn; + do_free = free_fn; +} diff --git a/compat/jansson/pack_unpack.c b/compat/jansson/pack_unpack.c new file mode 100644 index 0000000..0d932f7 --- /dev/null +++ b/compat/jansson/pack_unpack.c @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2009-2013 Petri Lehtinen + * Copyright (c) 2011-2012 Graeme Smecher + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include "jansson.h" +#include "jansson_private.h" +#include "utf.h" + +typedef struct { + int line; + int column; + size_t pos; + char token; +} token_t; + +typedef struct { + const char *start; + const char *fmt; + token_t prev_token; + token_t token; + token_t next_token; + json_error_t *error; + size_t flags; + int line; + int column; + size_t pos; +} scanner_t; + +#define token(scanner) ((scanner)->token.token) + +static const char * const type_names[] = { + "object", + "array", + "string", + "integer", + "real", + "true", + "false", + "null" +}; + +#define type_name(x) type_names[json_typeof(x)] + +static const char unpack_value_starters[] = "{[siIbfFOon"; + + +static void scanner_init(scanner_t *s, json_error_t *error, + size_t flags, const char *fmt) +{ + s->error = error; + s->flags = flags; + s->fmt = s->start = fmt; + memset(&s->prev_token, 0, sizeof(token_t)); + memset(&s->token, 0, sizeof(token_t)); + memset(&s->next_token, 0, sizeof(token_t)); + s->line = 1; + s->column = 0; + s->pos = 0; +} + +static void next_token(scanner_t *s) +{ + const char *t; + s->prev_token = s->token; + + if(s->next_token.line) { + s->token = s->next_token; + s->next_token.line = 0; + return; + } + + t = s->fmt; + s->column++; + s->pos++; + + /* skip space and ignored chars */ + while(*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') { + if(*t == '\n') { + s->line++; + s->column = 1; + } + else + s->column++; + + s->pos++; + t++; + } + + s->token.token = *t; + s->token.line = s->line; + s->token.column = s->column; + s->token.pos = s->pos; + + t++; + s->fmt = t; +} + +static void prev_token(scanner_t *s) +{ + s->next_token = s->token; + s->token = s->prev_token; +} + +static void set_error(scanner_t *s, const char *source, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + jsonp_error_vset(s->error, s->token.line, s->token.column, s->token.pos, + fmt, ap); + + jsonp_error_set_source(s->error, source); + + va_end(ap); +} + +static json_t *pack(scanner_t *s, va_list *ap); + + +/* ours will be set to 1 if jsonp_free() must be called for the result + afterwards */ +static char *read_string(scanner_t *s, va_list *ap, + const char *purpose, int *ours) +{ + char t; + strbuffer_t strbuff; + const char *str; + size_t length; + char *result; + + next_token(s); + t = token(s); + prev_token(s); + + if(t != '#' && t != '+') { + /* Optimize the simple case */ + str = va_arg(*ap, const char *); + + if(!str) { + set_error(s, "", "NULL string argument"); + return NULL; + } + + if(!utf8_check_string(str, -1)) { + set_error(s, "", "Invalid UTF-8 %s", purpose); + return NULL; + } + + *ours = 0; + return (char *)str; + } + + strbuffer_init(&strbuff); + + while(1) { + str = va_arg(*ap, const char *); + if(!str) { + set_error(s, "", "NULL string argument"); + strbuffer_close(&strbuff); + return NULL; + } + + next_token(s); + + if(token(s) == '#') { + length = va_arg(*ap, int); + } + else { + prev_token(s); + length = strlen(str); + } + + if(strbuffer_append_bytes(&strbuff, str, length) == -1) { + set_error(s, "", "Out of memory"); + strbuffer_close(&strbuff); + return NULL; + } + + next_token(s); + if(token(s) != '+') { + prev_token(s); + break; + } + } + + result = strbuffer_steal_value(&strbuff); + + if(!utf8_check_string(result, -1)) { + set_error(s, "", "Invalid UTF-8 %s", purpose); + return NULL; + } + + *ours = 1; + return result; +} + +static json_t *pack_object(scanner_t *s, va_list *ap) +{ + json_t *object = json_object(); + next_token(s); + + while(token(s) != '}') { + char *key; + int ours; + json_t *value; + + if(!token(s)) { + set_error(s, "", "Unexpected end of format string"); + goto error; + } + + if(token(s) != 's') { + set_error(s, "", "Expected format 's', got '%c'", token(s)); + goto error; + } + + key = read_string(s, ap, "object key", &ours); + if(!key) + goto error; + + next_token(s); + + value = pack(s, ap); + if(!value) + goto error; + + if(json_object_set_new_nocheck(object, key, value)) { + if(ours) + jsonp_free(key); + + set_error(s, "", "Unable to add key \"%s\"", key); + goto error; + } + + if(ours) + jsonp_free(key); + + next_token(s); + } + + return object; + +error: + json_decref(object); + return NULL; +} + +static json_t *pack_array(scanner_t *s, va_list *ap) +{ + json_t *array = json_array(); + next_token(s); + + while(token(s) != ']') { + json_t *value; + + if(!token(s)) { + set_error(s, "", "Unexpected end of format string"); + goto error; + } + + value = pack(s, ap); + if(!value) + goto error; + + if(json_array_append_new(array, value)) { + set_error(s, "", "Unable to append to array"); + goto error; + } + + next_token(s); + } + return array; + +error: + json_decref(array); + return NULL; +} + +static json_t *pack(scanner_t *s, va_list *ap) +{ + switch(token(s)) { + case '{': + return pack_object(s, ap); + + case '[': + return pack_array(s, ap); + + case 's': { /* string */ + char *str; + int ours; + json_t *result; + + str = read_string(s, ap, "string", &ours); + if(!str) + return NULL; + + result = json_string_nocheck(str); + if(ours) + jsonp_free(str); + + return result; + } + + case 'n': /* null */ + return json_null(); + + case 'b': /* boolean */ + return va_arg(*ap, int) ? json_true() : json_false(); + + case 'i': /* integer from int */ + return json_integer(va_arg(*ap, int)); + + case 'I': /* integer from json_int_t */ + return json_integer(va_arg(*ap, json_int_t)); + + case 'f': /* real */ + return json_real(va_arg(*ap, double)); + + case 'O': /* a json_t object; increments refcount */ + return json_incref(va_arg(*ap, json_t *)); + + case 'o': /* a json_t object; doesn't increment refcount */ + return va_arg(*ap, json_t *); + + default: + set_error(s, "", "Unexpected format character '%c'", + token(s)); + return NULL; + } +} + +static int unpack(scanner_t *s, json_t *root, va_list *ap); + +static int unpack_object(scanner_t *s, json_t *root, va_list *ap) +{ + int ret = -1; + int strict = 0; + + /* Use a set (emulated by a hashtable) to check that all object + keys are accessed. Checking that the correct number of keys + were accessed is not enough, as the same key can be unpacked + multiple times. + */ + hashtable_t key_set; + + if(hashtable_init(&key_set)) { + set_error(s, "", "Out of memory"); + return -1; + } + + if(root && !json_is_object(root)) { + set_error(s, "", "Expected object, got %s", + type_name(root)); + goto out; + } + next_token(s); + + while(token(s) != '}') { + const char *key; + json_t *value; + int opt = 0; + + if(strict != 0) { + set_error(s, "", "Expected '}' after '%c', got '%c'", + (strict == 1 ? '!' : '*'), token(s)); + goto out; + } + + if(!token(s)) { + set_error(s, "", "Unexpected end of format string"); + goto out; + } + + if(token(s) == '!' || token(s) == '*') { + strict = (token(s) == '!' ? 1 : -1); + next_token(s); + continue; + } + + if(token(s) != 's') { + set_error(s, "", "Expected format 's', got '%c'", token(s)); + goto out; + } + + key = va_arg(*ap, const char *); + if(!key) { + set_error(s, "", "NULL object key"); + goto out; + } + + next_token(s); + + if(token(s) == '?') { + opt = 1; + next_token(s); + } + + if(!root) { + /* skipping */ + value = NULL; + } + else { + value = json_object_get(root, key); + if(!value && !opt) { + set_error(s, "", "Object item not found: %s", key); + goto out; + } + } + + if(unpack(s, value, ap)) + goto out; + + hashtable_set(&key_set, key, 0, json_null()); + next_token(s); + } + + if(strict == 0 && (s->flags & JSON_STRICT)) + strict = 1; + + if(root && strict == 1 && key_set.size != json_object_size(root)) { + long diff = (long)json_object_size(root) - (long)key_set.size; + set_error(s, "", "%li object item(s) left unpacked", diff); + goto out; + } + + ret = 0; + +out: + hashtable_close(&key_set); + return ret; +} + +static int unpack_array(scanner_t *s, json_t *root, va_list *ap) +{ + size_t i = 0; + int strict = 0; + + if(root && !json_is_array(root)) { + set_error(s, "", "Expected array, got %s", type_name(root)); + return -1; + } + next_token(s); + + while(token(s) != ']') { + json_t *value; + + if(strict != 0) { + set_error(s, "", "Expected ']' after '%c', got '%c'", + (strict == 1 ? '!' : '*'), + token(s)); + return -1; + } + + if(!token(s)) { + set_error(s, "", "Unexpected end of format string"); + return -1; + } + + if(token(s) == '!' || token(s) == '*') { + strict = (token(s) == '!' ? 1 : -1); + next_token(s); + continue; + } + + if(!strchr(unpack_value_starters, token(s))) { + set_error(s, "", "Unexpected format character '%c'", + token(s)); + return -1; + } + + if(!root) { + /* skipping */ + value = NULL; + } + else { + value = json_array_get(root, i); + if(!value) { + set_error(s, "", "Array index %lu out of range", + (unsigned long)i); + return -1; + } + } + + if(unpack(s, value, ap)) + return -1; + + next_token(s); + i++; + } + + if(strict == 0 && (s->flags & JSON_STRICT)) + strict = 1; + + if(root && strict == 1 && i != json_array_size(root)) { + long diff = (long)json_array_size(root) - (long)i; + set_error(s, "", "%li array item(s) left unpacked", diff); + return -1; + } + + return 0; +} + +static int unpack(scanner_t *s, json_t *root, va_list *ap) +{ + switch(token(s)) + { + case '{': + return unpack_object(s, root, ap); + + case '[': + return unpack_array(s, root, ap); + + case 's': + if(root && !json_is_string(root)) { + set_error(s, "", "Expected string, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + const char **target; + + target = va_arg(*ap, const char **); + if(!target) { + set_error(s, "", "NULL string argument"); + return -1; + } + + if(root) + *target = json_string_value(root); + } + return 0; + + case 'i': + if(root && !json_is_integer(root)) { + set_error(s, "", "Expected integer, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + int *target = va_arg(*ap, int*); + if(root) + *target = (int)json_integer_value(root); + } + + return 0; + + case 'I': + if(root && !json_is_integer(root)) { + set_error(s, "", "Expected integer, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + json_int_t *target = va_arg(*ap, json_int_t*); + if(root) + *target = json_integer_value(root); + } + + return 0; + + case 'b': + if(root && !json_is_boolean(root)) { + set_error(s, "", "Expected true or false, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + int *target = va_arg(*ap, int*); + if(root) + *target = json_is_true(root); + } + + return 0; + + case 'f': + if(root && !json_is_real(root)) { + set_error(s, "", "Expected real, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + double *target = va_arg(*ap, double*); + if(root) + *target = json_real_value(root); + } + + return 0; + + case 'F': + if(root && !json_is_number(root)) { + set_error(s, "", "Expected real or integer, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + double *target = va_arg(*ap, double*); + if(root) + *target = json_number_value(root); + } + + return 0; + + case 'O': + if(root && !(s->flags & JSON_VALIDATE_ONLY)) + json_incref(root); + /* Fall through */ + + case 'o': + if(!(s->flags & JSON_VALIDATE_ONLY)) { + json_t **target = va_arg(*ap, json_t**); + if(root) + *target = root; + } + + return 0; + + case 'n': + /* Never assign, just validate */ + if(root && !json_is_null(root)) { + set_error(s, "", "Expected null, got %s", + type_name(root)); + return -1; + } + return 0; + + default: + set_error(s, "", "Unexpected format character '%c'", + token(s)); + return -1; + } +} + +json_t *json_vpack_ex(json_error_t *error, size_t flags, + const char *fmt, va_list ap) +{ + scanner_t s; + va_list ap_copy; + json_t *value; + + if(!fmt || !*fmt) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, "NULL or empty format string"); + return NULL; + } + jsonp_error_init(error, NULL); + + scanner_init(&s, error, flags, fmt); + next_token(&s); + + va_copy(ap_copy, ap); + value = pack(&s, &ap_copy); + va_end(ap_copy); + + if(!value) + return NULL; + + next_token(&s); + if(token(&s)) { + json_decref(value); + set_error(&s, "", "Garbage after format string"); + return NULL; + } + + return value; +} + +json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) +{ + json_t *value; + va_list ap; + + va_start(ap, fmt); + value = json_vpack_ex(error, flags, fmt, ap); + va_end(ap); + + return value; +} + +json_t *json_pack(const char *fmt, ...) +{ + json_t *value; + va_list ap; + + va_start(ap, fmt); + value = json_vpack_ex(NULL, 0, fmt, ap); + va_end(ap); + + return value; +} + +int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, + const char *fmt, va_list ap) +{ + scanner_t s; + va_list ap_copy; + + if(!root) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, "NULL root value"); + return -1; + } + + if(!fmt || !*fmt) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, "NULL or empty format string"); + return -1; + } + jsonp_error_init(error, NULL); + + scanner_init(&s, error, flags, fmt); + next_token(&s); + + va_copy(ap_copy, ap); + if(unpack(&s, root, &ap_copy)) { + va_end(ap_copy); + return -1; + } + va_end(ap_copy); + + next_token(&s); + if(token(&s)) { + set_error(&s, "", "Garbage after format string"); + return -1; + } + + return 0; +} + +int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = json_vunpack_ex(root, error, flags, fmt, ap); + va_end(ap); + + return ret; +} + +int json_unpack(json_t *root, const char *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = json_vunpack_ex(root, NULL, 0, fmt, ap); + va_end(ap); + + return ret; +} diff --git a/compat/jansson/strbuffer.c b/compat/jansson/strbuffer.c index 0019645..8a51a5a 100644 --- a/compat/jansson/strbuffer.c +++ b/compat/jansson/strbuffer.c @@ -1,25 +1,29 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif + #include #include +#include "jansson_private.h" #include "strbuffer.h" -#include "util.h" #define STRBUFFER_MIN_SIZE 16 #define STRBUFFER_FACTOR 2 +#define STRBUFFER_SIZE_MAX ((size_t)-1) int strbuffer_init(strbuffer_t *strbuff) { strbuff->size = STRBUFFER_MIN_SIZE; strbuff->length = 0; - strbuff->value = malloc(strbuff->size); + strbuff->value = jsonp_malloc(strbuff->size); if(!strbuff->value) return -1; @@ -30,7 +34,9 @@ int strbuffer_init(strbuffer_t *strbuff) void strbuffer_close(strbuffer_t *strbuff) { - free(strbuff->value); + if(strbuff->value) + jsonp_free(strbuff->value); + strbuff->size = 0; strbuff->length = 0; strbuff->value = NULL; @@ -50,7 +56,7 @@ const char *strbuffer_value(const strbuffer_t *strbuff) char *strbuffer_steal_value(strbuffer_t *strbuff) { char *result = strbuff->value; - strbuffer_init(strbuff); + strbuff->value = NULL; return result; } @@ -64,16 +70,31 @@ int strbuffer_append_byte(strbuffer_t *strbuff, char byte) return strbuffer_append_bytes(strbuff, &byte, 1); } -int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, int size) +int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size) { - if(strbuff->length + size >= strbuff->size) + if(size >= strbuff->size - strbuff->length) { - strbuff->size = max(strbuff->size * STRBUFFER_FACTOR, - strbuff->length + size + 1); + size_t new_size; + char *new_value; + + /* avoid integer overflow */ + if (strbuff->size > STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR + || size > STRBUFFER_SIZE_MAX - 1 + || strbuff->length > STRBUFFER_SIZE_MAX - 1 - size) + return -1; + + new_size = max(strbuff->size * STRBUFFER_FACTOR, + strbuff->length + size + 1); - strbuff->value = realloc(strbuff->value, strbuff->size); - if(!strbuff->value) + new_value = jsonp_malloc(new_size); + if(!new_value) return -1; + + memcpy(new_value, strbuff->value, strbuff->length); + + jsonp_free(strbuff->value); + strbuff->value = new_value; + strbuff->size = new_size; } memcpy(strbuff->value + strbuff->length, data, size); diff --git a/compat/jansson/strbuffer.h b/compat/jansson/strbuffer.h index 816594a..b17ea2b 100644 --- a/compat/jansson/strbuffer.h +++ b/compat/jansson/strbuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -10,8 +10,8 @@ typedef struct { char *value; - int length; /* bytes used */ - int size; /* bytes allocated */ + size_t length; /* bytes used */ + size_t size; /* bytes allocated */ } strbuffer_t; int strbuffer_init(strbuffer_t *strbuff); @@ -20,11 +20,13 @@ void strbuffer_close(strbuffer_t *strbuff); void strbuffer_clear(strbuffer_t *strbuff); const char *strbuffer_value(const strbuffer_t *strbuff); + +/* Steal the value and close the strbuffer */ char *strbuffer_steal_value(strbuffer_t *strbuff); int strbuffer_append(strbuffer_t *strbuff, const char *string); int strbuffer_append_byte(strbuffer_t *strbuff, char byte); -int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, int size); +int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size); char strbuffer_pop(strbuffer_t *strbuff); diff --git a/compat/jansson/strconv.c b/compat/jansson/strconv.c new file mode 100644 index 0000000..3e2cb7c --- /dev/null +++ b/compat/jansson/strconv.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include "jansson_private.h" +#include "strbuffer.h" + +/* need config.h to get the correct snprintf */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if JSON_HAVE_LOCALECONV +#include + +/* + - This code assumes that the decimal separator is exactly one + character. + + - If setlocale() is called by another thread between the call to + localeconv() and the call to sprintf() or strtod(), the result may + be wrong. setlocale() is not thread-safe and should not be used + this way. Multi-threaded programs should use uselocale() instead. +*/ + +static void to_locale(strbuffer_t *strbuffer) +{ + const char *point; + char *pos; + + point = localeconv()->decimal_point; + if(*point == '.') { + /* No conversion needed */ + return; + } + + pos = strchr(strbuffer->value, '.'); + if(pos) + *pos = *point; +} + +static void from_locale(char *buffer) +{ + const char *point; + char *pos; + + point = localeconv()->decimal_point; + if(*point == '.') { + /* No conversion needed */ + return; + } + + pos = strchr(buffer, *point); + if(pos) + *pos = '.'; +} +#endif + +int jsonp_strtod(strbuffer_t *strbuffer, double *out) +{ + double value; + char *end; + +#if JSON_HAVE_LOCALECONV + to_locale(strbuffer); +#endif + + errno = 0; + value = strtod(strbuffer->value, &end); + assert(end == strbuffer->value + strbuffer->length); + + if(errno == ERANGE && value != 0) { + /* Overflow */ + return -1; + } + + *out = value; + return 0; +} + +int jsonp_dtostr(char *buffer, size_t size, double value) +{ + int ret; + char *start, *end; + size_t length; + + ret = snprintf(buffer, size, "%.17g", value); + if(ret < 0) + return -1; + + length = (size_t)ret; + if(length >= size) + return -1; + +#if JSON_HAVE_LOCALECONV + from_locale(buffer); +#endif + + /* Make sure there's a dot or 'e' in the output. Otherwise + a real is converted to an integer when decoding */ + if(strchr(buffer, '.') == NULL && + strchr(buffer, 'e') == NULL) + { + if(length + 3 >= size) { + /* No space to append ".0" */ + return -1; + } + buffer[length] = '.'; + buffer[length + 1] = '0'; + buffer[length + 2] = '\0'; + length += 2; + } + + /* Remove leading '+' from positive exponent. Also remove leading + zeros from exponents (added by some printf() implementations) */ + start = strchr(buffer, 'e'); + if(start) { + start++; + end = start + 1; + + if(*start == '-') + start++; + + while(*end == '0') + end++; + + if(end != start) { + memmove(start, end, length - (size_t)(end - buffer)); + length -= (size_t)(end - start); + } + } + + return (int)length; +} diff --git a/compat/jansson/utf.c b/compat/jansson/utf.c index 2b64450..709694d 100644 --- a/compat/jansson/utf.c +++ b/compat/jansson/utf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. diff --git a/compat/jansson/utf.h b/compat/jansson/utf.h index 8e95296..c5af8ed 100644 --- a/compat/jansson/utf.h +++ b/compat/jansson/utf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -8,6 +8,7 @@ #ifndef UTF_H #define UTF_H +#ifdef HAVE_CONFIG_H #include #ifdef HAVE_INTTYPES_H @@ -15,7 +16,17 @@ no need to include stdint.h separately. If inttypes.h doesn't define int32_t, it's defined in config.h. */ #include -#endif +#endif /* HAVE_INTTYPES_H */ + +#else /* !HAVE_CONFIG_H */ +#ifdef _WIN32 +typedef int int32_t; +#else /* !_WIN32 */ +/* Assume a standard environment */ +#include +#endif /* _WIN32 */ + +#endif /* HAVE_CONFIG_H */ int utf8_encode(int codepoint, char *buffer, int *size); diff --git a/compat/jansson/value.c b/compat/jansson/value.c index 591b89e..1e7697c 100644 --- a/compat/jansson/value.c +++ b/compat/jansson/value.c @@ -1,25 +1,33 @@ /* - * Copyright (c) 2009, 2010 Petri Lehtinen + * Copyright (c) 2009-2013 Petri Lehtinen * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif -#include - +#include #include #include +#include -#include +#include "jansson.h" #include "hashtable.h" #include "jansson_private.h" #include "utf.h" -#include "util.h" +/* Work around nonstandard isnan() and isinf() implementations */ +#ifndef isnan +static JSON_INLINE int isnan(double x) { return x != x; } +#endif +#ifndef isinf +static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); } +#endif -static inline void json_init(json_t *json, json_type type) +static JSON_INLINE void json_init(json_t *json, json_type type) { json->type = type; json->refcount = 1; @@ -28,50 +36,16 @@ static inline void json_init(json_t *json, json_type type) /*** object ***/ -/* This macro just returns a pointer that's a few bytes backwards from - string. This makes it possible to pass a pointer to object_key_t - when only the string inside it is used, without actually creating - an object_key_t instance. */ -#define string_to_key(string) container_of(string, object_key_t, key) - -static unsigned int hash_key(const void *ptr) -{ - const char *str = ((const object_key_t *)ptr)->key; - - unsigned int hash = 5381; - unsigned int c; - - while((c = (unsigned int)*str)) - { - hash = ((hash << 5) + hash) + c; - str++; - } - - return hash; -} - -static int key_equal(const void *ptr1, const void *ptr2) -{ - return strcmp(((const object_key_t *)ptr1)->key, - ((const object_key_t *)ptr2)->key) == 0; -} - -static void value_decref(void *value) -{ - json_decref((json_t *)value); -} - json_t *json_object(void) { - json_object_t *object = malloc(sizeof(json_object_t)); + json_object_t *object = jsonp_malloc(sizeof(json_object_t)); if(!object) return NULL; json_init(&object->json, JSON_OBJECT); - if(hashtable_init(&object->hashtable, hash_key, key_equal, - free, value_decref)) + if(hashtable_init(&object->hashtable)) { - free(object); + jsonp_free(object); return NULL; } @@ -84,15 +58,15 @@ json_t *json_object(void) static void json_delete_object(json_object_t *object) { hashtable_close(&object->hashtable); - free(object); + jsonp_free(object); } -unsigned int json_object_size(const json_t *json) +size_t json_object_size(const json_t *json) { json_object_t *object; if(!json_is_object(json)) - return -1; + return 0; object = json_to_object(json); return object->hashtable.size; @@ -106,32 +80,24 @@ json_t *json_object_get(const json_t *json, const char *key) return NULL; object = json_to_object(json); - return hashtable_get(&object->hashtable, string_to_key(key)); + return hashtable_get(&object->hashtable, key); } int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) { json_object_t *object; - object_key_t *k; - if(!key || !value) + if(!value) return -1; - if(!json_is_object(json) || json == value) + if(!key || !json_is_object(json) || json == value) { json_decref(value); return -1; } object = json_to_object(json); - k = malloc(sizeof(object_key_t) + strlen(key) + 1); - if(!k) - return -1; - - k->serial = object->serial++; - strcpy(k->key, key); - - if(hashtable_set(&object->hashtable, k, value)) + if(hashtable_set(&object->hashtable, key, object->serial++, value)) { json_decref(value); return -1; @@ -159,7 +125,7 @@ int json_object_del(json_t *json, const char *key) return -1; object = json_to_object(json); - return hashtable_del(&object->hashtable, string_to_key(key)); + return hashtable_del(&object->hashtable, key); } int json_object_clear(json_t *json) @@ -170,30 +136,56 @@ int json_object_clear(json_t *json) return -1; object = json_to_object(json); + hashtable_clear(&object->hashtable); + object->serial = 0; return 0; } int json_object_update(json_t *object, json_t *other) { - void *iter; + const char *key; + json_t *value; if(!json_is_object(object) || !json_is_object(other)) return -1; - iter = json_object_iter(other); - while(iter) { - const char *key; - json_t *value; - - key = json_object_iter_key(iter); - value = json_object_iter_value(iter); - + json_object_foreach(other, key, value) { if(json_object_set_nocheck(object, key, value)) return -1; + } + + return 0; +} + +int json_object_update_existing(json_t *object, json_t *other) +{ + const char *key; + json_t *value; + + if(!json_is_object(object) || !json_is_object(other)) + return -1; + + json_object_foreach(other, key, value) { + if(json_object_get(object, key)) + json_object_set_nocheck(object, key, value); + } + + return 0; +} + +int json_object_update_missing(json_t *object, json_t *other) +{ + const char *key; + json_t *value; + + if(!json_is_object(object) || !json_is_object(other)) + return -1; - iter = json_object_iter_next(other, iter); + json_object_foreach(other, key, value) { + if(!json_object_get(object, key)) + json_object_set_nocheck(object, key, value); } return 0; @@ -218,7 +210,7 @@ void *json_object_iter_at(json_t *json, const char *key) return NULL; object = json_to_object(json); - return hashtable_iter_at(&object->hashtable, string_to_key(key)); + return hashtable_iter_at(&object->hashtable, key); } void *json_object_iter_next(json_t *json, void *iter) @@ -232,20 +224,12 @@ void *json_object_iter_next(json_t *json, void *iter) return hashtable_iter_next(&object->hashtable, iter); } -const object_key_t *jsonp_object_iter_fullkey(void *iter) -{ - if(!iter) - return NULL; - - return hashtable_iter_key(iter); -} - const char *json_object_iter_key(void *iter) { if(!iter) return NULL; - return jsonp_object_iter_fullkey(iter)->key; + return hashtable_iter_key(iter); } json_t *json_object_iter_value(void *iter) @@ -258,38 +242,34 @@ json_t *json_object_iter_value(void *iter) int json_object_iter_set_new(json_t *json, void *iter, json_t *value) { - json_object_t *object; - if(!json_is_object(json) || !iter || !value) return -1; - object = json_to_object(json); - hashtable_iter_set(&object->hashtable, iter, value); - + hashtable_iter_set(iter, value); return 0; } +void *json_object_key_to_iter(const char *key) +{ + if(!key) + return NULL; + + return hashtable_key_to_iter(key); +} + static int json_object_equal(json_t *object1, json_t *object2) { - void *iter; + const char *key; + json_t *value1, *value2; if(json_object_size(object1) != json_object_size(object2)) return 0; - iter = json_object_iter(object1); - while(iter) - { - const char *key; - json_t *value1, *value2; - - key = json_object_iter_key(iter); - value1 = json_object_iter_value(iter); + json_object_foreach(object1, key, value1) { value2 = json_object_get(object2, key); if(!json_equal(value1, value2)) return 0; - - iter = json_object_iter_next(object1, iter); } return 1; @@ -298,29 +278,21 @@ static int json_object_equal(json_t *object1, json_t *object2) static json_t *json_object_copy(json_t *object) { json_t *result; - void *iter; + + const char *key; + json_t *value; result = json_object(); if(!result) return NULL; - iter = json_object_iter(object); - while(iter) - { - const char *key; - json_t *value; - - key = json_object_iter_key(iter); - value = json_object_iter_value(iter); + json_object_foreach(object, key, value) json_object_set_nocheck(result, key, value); - iter = json_object_iter_next(object, iter); - } - return result; } -static json_t *json_object_deep_copy(json_t *object) +static json_t *json_object_deep_copy(const json_t *object) { json_t *result; void *iter; @@ -329,17 +301,17 @@ static json_t *json_object_deep_copy(json_t *object) if(!result) return NULL; - iter = json_object_iter(object); - while(iter) - { + /* Cannot use json_object_foreach because object has to be cast + non-const */ + iter = json_object_iter((json_t *)object); + while(iter) { const char *key; - json_t *value; - + const json_t *value; key = json_object_iter_key(iter); value = json_object_iter_value(iter); - json_object_set_new_nocheck(result, key, json_deep_copy(value)); - iter = json_object_iter_next(object, iter); + json_object_set_new_nocheck(result, key, json_deep_copy(value)); + iter = json_object_iter_next((json_t *)object, iter); } return result; @@ -350,7 +322,7 @@ static json_t *json_object_deep_copy(json_t *object) json_t *json_array(void) { - json_array_t *array = malloc(sizeof(json_array_t)); + json_array_t *array = jsonp_malloc(sizeof(json_array_t)); if(!array) return NULL; json_init(&array->json, JSON_ARRAY); @@ -358,9 +330,9 @@ json_t *json_array(void) array->entries = 0; array->size = 8; - array->table = malloc(array->size * sizeof(json_t *)); + array->table = jsonp_malloc(array->size * sizeof(json_t *)); if(!array->table) { - free(array); + jsonp_free(array); return NULL; } @@ -371,16 +343,16 @@ json_t *json_array(void) static void json_delete_array(json_array_t *array) { - unsigned int i; + size_t i; for(i = 0; i < array->entries; i++) json_decref(array->table[i]); - free(array->table); - free(array); + jsonp_free(array->table); + jsonp_free(array); } -unsigned int json_array_size(const json_t *json) +size_t json_array_size(const json_t *json) { if(!json_is_array(json)) return 0; @@ -388,7 +360,7 @@ unsigned int json_array_size(const json_t *json) return json_to_array(json)->entries; } -json_t *json_array_get(const json_t *json, unsigned int index) +json_t *json_array_get(const json_t *json, size_t index) { json_array_t *array; if(!json_is_array(json)) @@ -401,7 +373,7 @@ json_t *json_array_get(const json_t *json, unsigned int index) return array->table[index]; } -int json_array_set_new(json_t *json, unsigned int index, json_t *value) +int json_array_set_new(json_t *json, size_t index, json_t *value) { json_array_t *array; @@ -427,24 +399,24 @@ int json_array_set_new(json_t *json, unsigned int index, json_t *value) return 0; } -static void array_move(json_array_t *array, unsigned int dest, - unsigned int src, unsigned int count) +static void array_move(json_array_t *array, size_t dest, + size_t src, size_t count) { memmove(&array->table[dest], &array->table[src], count * sizeof(json_t *)); } -static void array_copy(json_t **dest, unsigned int dpos, - json_t **src, unsigned int spos, - unsigned int count) +static void array_copy(json_t **dest, size_t dpos, + json_t **src, size_t spos, + size_t count) { memcpy(&dest[dpos], &src[spos], count * sizeof(json_t *)); } static json_t **json_array_grow(json_array_t *array, - unsigned int amount, + size_t amount, int copy) { - unsigned int new_size; + size_t new_size; json_t **old_table, **new_table; if(array->entries + amount <= array->size) @@ -453,7 +425,7 @@ static json_t **json_array_grow(json_array_t *array, old_table = array->table; new_size = max(array->size + amount, array->size * 2); - new_table = malloc(new_size * sizeof(json_t *)); + new_table = jsonp_malloc(new_size * sizeof(json_t *)); if(!new_table) return NULL; @@ -462,7 +434,7 @@ static json_t **json_array_grow(json_array_t *array, if(copy) { array_copy(array->table, 0, old_table, 0, array->entries); - free(old_table); + jsonp_free(old_table); return array->table; } @@ -494,7 +466,7 @@ int json_array_append_new(json_t *json, json_t *value) return 0; } -int json_array_insert_new(json_t *json, unsigned int index, json_t *value) +int json_array_insert_new(json_t *json, size_t index, json_t *value) { json_array_t *array; json_t **old_table; @@ -523,7 +495,7 @@ int json_array_insert_new(json_t *json, unsigned int index, json_t *value) array_copy(array->table, 0, old_table, 0, index); array_copy(array->table, index + 1, old_table, index, array->entries - index); - free(old_table); + jsonp_free(old_table); } else array_move(array, index + 1, index, array->entries - index); @@ -534,7 +506,7 @@ int json_array_insert_new(json_t *json, unsigned int index, json_t *value) return 0; } -int json_array_remove(json_t *json, unsigned int index) +int json_array_remove(json_t *json, size_t index) { json_array_t *array; @@ -547,7 +519,10 @@ int json_array_remove(json_t *json, unsigned int index) json_decref(array->table[index]); - array_move(array, index, index + 1, array->entries - index); + /* If we're removing the last element, nothing has to be moved */ + if(index < array->entries - 1) + array_move(array, index, index + 1, array->entries - index - 1); + array->entries--; return 0; @@ -556,7 +531,7 @@ int json_array_remove(json_t *json, unsigned int index) int json_array_clear(json_t *json) { json_array_t *array; - unsigned int i; + size_t i; if(!json_is_array(json)) return -1; @@ -572,7 +547,7 @@ int json_array_clear(json_t *json) int json_array_extend(json_t *json, json_t *other_json) { json_array_t *array, *other; - unsigned int i; + size_t i; if(!json_is_array(json) || !json_is_array(other_json)) return -1; @@ -593,7 +568,7 @@ int json_array_extend(json_t *json, json_t *other_json) static int json_array_equal(json_t *array1, json_t *array2) { - unsigned int i, size; + size_t i, size; size = json_array_size(array1); if(size != json_array_size(array2)) @@ -616,7 +591,7 @@ static int json_array_equal(json_t *array1, json_t *array2) static json_t *json_array_copy(json_t *array) { json_t *result; - unsigned int i; + size_t i; result = json_array(); if(!result) @@ -628,10 +603,10 @@ static json_t *json_array_copy(json_t *array) return result; } -static json_t *json_array_deep_copy(json_t *array) +static json_t *json_array_deep_copy(const json_t *array) { json_t *result; - unsigned int i; + size_t i; result = json_array(); if(!result) @@ -652,14 +627,14 @@ json_t *json_string_nocheck(const char *value) if(!value) return NULL; - string = malloc(sizeof(json_string_t)); + string = jsonp_malloc(sizeof(json_string_t)); if(!string) return NULL; json_init(&string->json, JSON_STRING); - string->value = strdup(value); + string->value = jsonp_strdup(value); if(!string->value) { - free(string); + jsonp_free(string); return NULL; } @@ -687,12 +662,15 @@ int json_string_set_nocheck(json_t *json, const char *value) char *dup; json_string_t *string; - dup = strdup(value); + if(!json_is_string(json) || !value) + return -1; + + dup = jsonp_strdup(value); if(!dup) return -1; string = json_to_string(json); - free(string->value); + jsonp_free(string->value); string->value = dup; return 0; @@ -708,8 +686,8 @@ int json_string_set(json_t *json, const char *value) static void json_delete_string(json_string_t *string) { - free(string->value); - free(string); + jsonp_free(string->value); + jsonp_free(string); } static int json_string_equal(json_t *string1, json_t *string2) @@ -717,7 +695,7 @@ static int json_string_equal(json_t *string1, json_t *string2) return strcmp(json_string_value(string1), json_string_value(string2)) == 0; } -static json_t *json_string_copy(json_t *string) +static json_t *json_string_copy(const json_t *string) { return json_string_nocheck(json_string_value(string)); } @@ -725,9 +703,9 @@ static json_t *json_string_copy(json_t *string) /*** integer ***/ -json_t *json_integer(int value) +json_t *json_integer(json_int_t value) { - json_integer_t *integer = malloc(sizeof(json_integer_t)); + json_integer_t *integer = jsonp_malloc(sizeof(json_integer_t)); if(!integer) return NULL; json_init(&integer->json, JSON_INTEGER); @@ -736,7 +714,7 @@ json_t *json_integer(int value) return &integer->json; } -int json_integer_value(const json_t *json) +json_int_t json_integer_value(const json_t *json) { if(!json_is_integer(json)) return 0; @@ -744,7 +722,7 @@ int json_integer_value(const json_t *json) return json_to_integer(json)->value; } -int json_integer_set(json_t *json, int value) +int json_integer_set(json_t *json, json_int_t value) { if(!json_is_integer(json)) return -1; @@ -756,7 +734,7 @@ int json_integer_set(json_t *json, int value) static void json_delete_integer(json_integer_t *integer) { - free(integer); + jsonp_free(integer); } static int json_integer_equal(json_t *integer1, json_t *integer2) @@ -764,7 +742,7 @@ static int json_integer_equal(json_t *integer1, json_t *integer2) return json_integer_value(integer1) == json_integer_value(integer2); } -static json_t *json_integer_copy(json_t *integer) +static json_t *json_integer_copy(const json_t *integer) { return json_integer(json_integer_value(integer)); } @@ -774,7 +752,12 @@ static json_t *json_integer_copy(json_t *integer) json_t *json_real(double value) { - json_real_t *real = malloc(sizeof(json_real_t)); + json_real_t *real; + + if(isnan(value) || isinf(value)) + return NULL; + + real = jsonp_malloc(sizeof(json_real_t)); if(!real) return NULL; json_init(&real->json, JSON_REAL); @@ -793,8 +776,8 @@ double json_real_value(const json_t *json) int json_real_set(json_t *json, double value) { - if(!json_is_real(json)) - return 0; + if(!json_is_real(json) || isnan(value) || isinf(value)) + return -1; json_to_real(json)->value = value; @@ -803,7 +786,7 @@ int json_real_set(json_t *json, double value) static void json_delete_real(json_real_t *real) { - free(real); + jsonp_free(real); } static int json_real_equal(json_t *real1, json_t *real2) @@ -811,7 +794,7 @@ static int json_real_equal(json_t *real1, json_t *real2) return json_real_value(real1) == json_real_value(real2); } -static json_t *json_real_copy(json_t *real) +static json_t *json_real_copy(const json_t *real) { return json_real(json_real_value(real)); } @@ -822,7 +805,7 @@ static json_t *json_real_copy(json_t *real) double json_number_value(const json_t *json) { if(json_is_integer(json)) - return json_integer_value(json); + return (double)json_integer_value(json); else if(json_is_real(json)) return json_real_value(json); else @@ -834,30 +817,21 @@ double json_number_value(const json_t *json) json_t *json_true(void) { - static json_t the_true = { - JSON_TRUE, - (unsigned int)-1 - }; + static json_t the_true = {JSON_TRUE, (size_t)-1}; return &the_true; } json_t *json_false(void) { - static json_t the_false = { - JSON_FALSE, - (unsigned int)-1 - }; + static json_t the_false = {JSON_FALSE, (size_t)-1}; return &the_false; } json_t *json_null(void) { - static json_t the_null = { - JSON_NULL, - (unsigned int)-1 - }; + static json_t the_null = {JSON_NULL, (size_t)-1}; return &the_null; } @@ -946,7 +920,7 @@ json_t *json_copy(json_t *json) return NULL; } -json_t *json_deep_copy(json_t *json) +json_t *json_deep_copy(const json_t *json) { if(!json) return NULL; @@ -970,7 +944,7 @@ json_t *json_deep_copy(json_t *json) return json_real_copy(json); if(json_is_true(json) || json_is_false(json) || json_is_null(json)) - return json; + return (json_t *)json; return NULL; }