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;
}