*.pyc
*.pc
/src/jansson_config.h
+*.exe
+Version 2.4
+===========
+
+Released 2012-09-23
+
+* New features:
+
+ - Add `json_boolean()` macro that returns the JSON true or false
+ value based on its argument (#86).
+
+ - Add `json_load_callback()` that calls a callback function
+ repeatedly to read the JSON input (#57).
+
+ - Add JSON_ESCAPE_SLASH encoding flag to escape all occurences of
+ ``/`` with ``\/``.
+
+* Bug fixes:
+
+ - Check for and reject NaN and Inf values for reals. Encoding these
+ values resulted in invalid JSON.
+
+ - Fix `json_real_set()` to return -1 on error.
+
+* Build:
+
+ - Jansson now builds on Windows with Visual Studio 2010, and
+ includes solution and project files in ``win32/vs2010/``
+ directory.
+
+ - Fix build warnings (#77, #78).
+
+ - Add ``-no-undefined`` to LDFLAGS (#90).
+
+* Tests:
+
+ - Fix the symbol exports test on Linux/PPC64 (#88).
+
+* Documentation:
+
+ - Fix typos (#73, #84).
+
+
+Version 2.3.1
+=============
+
+Released 2012-04-20
+
+* Build issues:
+
+ - Only use ``long long`` if ``strtoll()`` is also available.
+
+* Documentation:
+
+ - Fix the names of library version constants in documentation. (#52)
+
+ - Change the tutorial to use GitHub API v3. (#65)
+
+* Tests:
+
+ - Make some tests locale independent. (#51)
+
+ - Distribute the library exports test in the tarball.
+
+ - Make test run on shells that don't support the ``export FOO=bar``
+ syntax.
+
+
+Version 2.3
+===========
+
+Released 2012-01-27
+
+* New features:
+
+ - `json_unpack()` and friends: Add support for optional object keys
+ with the ``{s?o}`` syntax.
+
+ - Add `json_object_update_existing()` and
+ `json_object_update_missing()`, for updating only existing keys or
+ only adding missing keys to an object. (#37)
+
+ - Add `json_object_foreach()` for more convenient iteration over
+ objects. (#45, #46)
+
+ - When decoding JSON, write the number of bytes that were read from
+ input to ``error.position`` also on success. This is handy with
+ ``JSON_DISABLE_EOF_CHECK``.
+
+ - Add support for decoding any JSON value, not just arrays or
+ objects. The support is enabled with the new ``JSON_DECODE_ANY``
+ flag. Patch by Andrea Marchesini. (#4)
+
+* Bug fixes
+
+ - Avoid problems with object's serial number growing too big. (#40,
+ #41)
+
+ - Decoding functions now return NULL if the first argument is NULL.
+ Patch by Andrea Marchesini.
+
+ - Include ``jansson_config.h.win32`` in the distribution tarball.
+
+ - Remove ``+`` and leading zeros from exponents in the encoder.
+ (#39)
+
+ - Make Jansson build and work on MinGW. (#39, #38)
+
+* Documentation
+
+ - Note that the same JSON values must not be encoded in parallel by
+ separate threads. (#42)
+
+ - Document MinGW support.
+
+
+Version 2.2.1
+=============
+
+Released 2011-10-06
+
+* Bug fixes:
+
+ - Fix real number encoding and decoding under non-C locales. (#32)
+
+ - Fix identifier decoding under non-UTF-8 locales. (#35)
+
+ - `json_load_file()`: Open the input file in binary mode for maximum
+ compatiblity.
+
+* Documentation:
+
+ - Clarify the lifecycle of the result of the ``s`` fromat of
+ `json_unpack()`. (#31)
+
+ - Add some portability info. (#36)
+
+ - Little clarifications here and there.
+
+* Other:
+
+ - Some style fixes, issues detected by static analyzers.
+
+
+Version 2.2
+===========
+
+Released 2011-09-03
+
+* New features:
+
+ - `json_dump_callback()`: Pass the encoder output to a callback
+ function in chunks.
+
+* Bug fixes:
+
+ - `json_string_set()`: Check that target is a string and value is
+ not NULL.
+
+* Other:
+
+ - Documentation typo fixes and clarifications.
+
+
+Version 2.1
+===========
+
+Released 2011-06-10
+
+* New features:
+
+ - `json_loadb()`: Decode a string with a given size, useful if the
+ string is not null terminated.
+
+ - Add ``JSON_ENCODE_ANY`` encoding flag to allow encoding any JSON
+ value. By default, only arrays and objects can be encoded. (#19)
+
+ - Add ``JSON_REJECT_DUPLICATES`` decoding flag to issue a decoding
+ error if any JSON object in the input contins duplicate keys. (#3)
+
+ - Add ``JSON_DISABLE_EOF_CHECK`` decoding flag to stop decoding after a
+ valid JSON input. This allows other data after the JSON data.
+
+* Bug fixes:
+
+ - Fix an additional memory leak when memory allocation fails in
+ `json_object_set()` and friends.
+
+ - Clear errno before calling `strtod()` for better portability. (#27)
+
+* Building:
+
+ - Avoid set-but-not-used warning/error in a test. (#20)
+
+* Other:
+
+ - Minor clarifications to documentation.
+
+
+Version 2.0.1
+=============
+
+Released 2011-03-31
+
+* Bug fixes:
+
+ - Replace a few `malloc()` and `free()` calls with their
+ counterparts that support custom memory management.
+
+ - Fix object key hashing in json_unpack() strict checking mode.
+
+ - Fix the parentheses in ``JANSSON_VERSION_HEX`` macro.
+
+ - Fix `json_object_size()` return value.
+
+ - Fix a few compilation issues.
+
+* Portability:
+
+ - Enhance portability of `va_copy()`.
+
+ - Test framework portability enhancements.
+
+* Documentation:
+
+ - Distribute ``doc/upgrading.rst`` with the source tarball.
+
+ - Build documentation in strict mode in ``make distcheck``.
+
+
Version 2.0
===========
-Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
-EXTRA_DIST = CHANGES LICENSE README.rst jansson.spec
+EXTRA_DIST = CHANGES LICENSE README.rst win32 jansson.spec
+
SUBDIRS = doc src test
# "make distcheck" builds the dvi target, so use it to check that the
$ make check
If the source has been checked out from a Git repository, the
-./configure script has to be generated fist. The easiest way is to use
-autoreconf::
+./configure script has to be generated first. The easiest way is to
+use autoreconf::
$ autoreconf -i
AC_PREREQ([2.60])
-AC_INIT([jansson], [2.0], [petri@digip.org])
+AC_INIT([jansson], [2.4], [petri@digip.org])
AM_INIT_AUTOMAKE([1.10 foreign])
# Checks for libraries.
# Checks for header files.
+AC_CHECK_HEADERS([locale.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_INT32_T
-
AC_TYPE_LONG_LONG_INT
-case $ac_cv_type_long_long_int in
- yes) json_have_long_long=1;;
- *) json_have_long_long=0;;
-esac
-AC_SUBST([json_have_long_long])
AC_C_INLINE
case $ac_cv_c_inline in
AC_SUBST([json_inline])
# Checks for library functions.
+AC_CHECK_FUNCS([strtoll localeconv])
+
+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])
AC_CONFIG_FILES([
jansson.pc
EXTRA_DIST = conf.py apiref.rst changes.rst conformance.rst \
- gettingstarted.rst github_commits.c index.rst tutorial.rst \
- upgrading.rst ext/refcounting.py
+ gettingstarted.rst github_commits.c index.rst portability.rst \
+ tutorial.rst upgrading.rst ext/refcounting.py
SPHINXBUILD = sphinx-build
SPHINXOPTS = -d _build/doctrees $(SPHINXOPTS_EXTRA)
The following preprocessor constants specify the current version of
the library:
-``JANSSON_VERSION_MAJOR``, ``JANSSON_VERSION_MINOR``, ``JANSSON_VERSION_MICRO``
+``JANSSON_MAJOR_VERSION``, ``JANSSON_MINOR_VERSION``, ``JANSSON_MICRO_VERSION``
Integers specifying the major, minor and micro versions,
respectively.
True, False and Null
====================
-These values are implemented as singletons, so each of these functions
-returns the same value each time.
+These three values are implemented as singletons, so the returned
+pointers won't change between invocations of these functions.
.. function:: json_t *json_true(void)
Returns the JSON false value.
+.. function:: json_t *json_boolean(val)
+
+ .. refcounting:: new
+
+ Returns JSON false if ``val`` is zero, and JSON true otherwise.
+ This is a macro, and equivalent to ``val ? json_true() :
+ json_false()``.
+
+ .. versionadded:: 2.4
+
+
.. function:: json_t *json_null(void)
.. refcounting:: new
Removes the element in *array* at position *index*, shifting the
elements after *index* one position towards the start of the array.
- Returns 0 on success and -1 on error.
+ Returns 0 on success and -1 on error. The reference count of the
+ removed value is decremented.
.. function:: int json_array_clear(json_t *array)
Removes all elements from *array*. Returns 0 on sucess and -1 on
- error.
+ error. The reference count of all removed values are decremented.
.. function:: int json_array_extend(json_t *array, json_t *other_array)
.. function:: int json_object_del(json_t *object, const char *key)
Delete *key* from *object* if it exists. Returns 0 on success, or
- -1 if *key* was not found.
-
+ -1 if *key* was not found. The reference count of the removed value
+ is decremented.
.. function:: int json_object_clear(json_t *object)
Remove all elements from *object*. Returns 0 on success and -1 if
- *object* is not a JSON object.
+ *object* is not a JSON object. The reference count of all removed
+ values are decremented.
.. function:: int json_object_update(json_t *object, json_t *other)
Update *object* with the key-value pairs from *other*, overwriting
existing keys. Returns 0 on success or -1 on error.
+.. function:: int json_object_update_existing(json_t *object, json_t *other)
+
+ Like :func:`json_object_update()`, but only the values of existing
+ keys are updated. No new keys are created. Returns 0 on success or
+ -1 on error.
+
+ .. versionadded:: 2.3
+
+.. function:: int json_object_update_missing(json_t *object, json_t *other)
+
+ Like :func:`json_object_update()`, but only new keys are created.
+ The value of any existing key is not changed. Returns 0 on success
+ or -1 on error.
+
+ .. versionadded:: 2.3
+
+The following macro can be used to iterate through all key-value pairs
+in an object.
+
+.. function:: json_object_foreach(object, key, value)
+
+ Iterate over every key-value pair of ``object``, running the block
+ of code that follows each time with the proper values set to
+ variables ``key`` and ``value``, of types :type:`const char *` and
+ :type:`json_t *` respectively. Example::
+
+ /* obj is a JSON object */
+ const char *key;
+ json_t *value;
+
+ json_object_foreach(obj, key, value) {
+ /* block of code that uses key and value */
+ }
+
+ The items are not returned in any particular order.
+
+ This macro expands to an ordinary ``for`` statement upon
+ preprocessing, so its performance is equivalent to that of
+ hand-written iteration code using the object iteration protocol
+ (see below). The main advantage of this macro is that it abstracts
+ away the complexity behind iteration, and makes for shorter, more
+ concise code.
+
+ .. versionadded:: 2.3
-The following functions implement an iteration protocol for objects:
+
+The following functions implement an iteration protocol for objects,
+allowing to iterate through all key-value pairs in an object. The
+items are not returned in any particular order, as this would require
+sorting due to the internal hashtable implementation.
.. function:: void *json_object_iter(json_t *object)
*value*. This is useful when *value* is newly created and not used
after the call.
+.. function:: void *json_object_key_to_iter(const char *key)
+
+ Like :func:`json_object_iter_at()`, but much faster. Only works for
+ values returned by :func:`json_object_iter_key()`. Using other keys
+ will lead to segfaults. This function is used internally to
+ implement :func:`json_object_foreach`.
+
+ .. versionadded:: 2.3
+
The iteration protocol can be used for example as follows::
/* obj is a JSON object */
const char *key;
json_t *value;
+
void *iter = json_object_iter(obj);
while(iter)
{
}
Also note that if the call succeeded (``json != NULL`` in the above
-example), the contents of ``error`` are unspecified.
+example), the contents of ``error`` are generally left unspecified.
+The decoding functions write to the ``position`` member also on
+success. See :ref:`apiref-decoding` for more info.
All functions also accept *NULL* as the :type:`json_error_t` pointer,
in which case no error information is returned to the caller.
========
This sections describes the functions that can be used to encode
-values to JSON. Only objects and arrays can be encoded, since they are
-the only valid "root" values of a JSON text.
+values to JSON. By default, only objects and arrays can be encoded
+directly, since they are the only valid *root* values of a JSON text.
+To encode any JSON value, use the ``JSON_ENCODE_ANY`` flag (see
+below).
By default, the output has no newlines, and spaces are used between
array and object elements for a readable output. This behavior can be
``JSON_INDENT(n)``
Pretty-print the result, using newlines between array and object
items, and indenting with *n* spaces. The valid range for *n* is
- between 0 and 32, other values result in an undefined output. If
- ``JSON_INDENT`` is not used or *n* is 0, no newlines are inserted
- between array and object items.
+ between 0 and 31 (inclusive), other values result in an undefined
+ output. If ``JSON_INDENT`` is not used or *n* is 0, no newlines are
+ inserted between array and object items.
``JSON_COMPACT``
This flag enables a compact representation, i.e. sets the separator
example, decoding a JSON text and then encoding with this flag
preserves the order of object keys.
+``JSON_ENCODE_ANY``
+ Specifying this flag makes it possible to encode any JSON value on
+ its own. Without it, only objects and arrays can be passed as the
+ *root* value to the encoding functions.
+
+ **Note:** Encoding any value may be useful in some scenarios, but
+ it's generally discouraged as it violates strict compatiblity with
+ :rfc:`4627`. If you use this flag, don't expect interoperatibility
+ with other JSON systems.
+
+ .. versionadded:: 2.1
+
+``JSON_ESCAPE_SLASH``
+ Escape the ``/`` characters in strings with ``\/``.
+
+ .. versionadded:: 2.4
+
The following functions perform the actual JSON encoding. The result
is in UTF-8.
*path* already exists, it is overwritten. *flags* is described
above. Returns 0 on success and -1 on error.
+.. type:: json_dump_callback_t
+
+ A typedef for a function that's called by
+ :func:`json_dump_callback()`::
+
+ typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
+
+ *buffer* points to a buffer containing a chunk of output, *size* is
+ the length of the buffer, and *data* is the corresponding
+ :func:`json_dump_callback()` argument passed through.
+
+ On error, the function should return -1 to stop the encoding
+ process. On success, it should return 0.
+
+ .. versionadded:: 2.2
+
+.. function:: int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags)
+
+ Call *callback* repeatedly, passing a chunk of the JSON
+ representation of *root* each time. *flags* is described above.
+ Returns 0 on success and -1 on error.
+
+ .. versionadded:: 2.2
+
.. _apiref-decoding:
specification requires that a JSON text is either a serialized array
or object, and this requirement is also enforced with the following
functions. In other words, the top level value in the JSON text being
-decoded must be either array or object.
+decoded must be either array or object. To decode any JSON value, use
+the ``JSON_DECODE_ANY`` flag (see below).
See :ref:`rfc-conformance` for a discussion on Jansson's conformance
to the JSON specification. It explains many design decisions that
affect especially the behavior of the decoder.
+Each function takes a *flags* parameter that can be used to control
+the behavior of the decoder. Its default value is 0. The following
+macros can be ORed together to obtain *flags*.
+
+``JSON_REJECT_DUPLICATES``
+ Issue a decoding error if any JSON object in the input text
+ contains duplicate keys. Without this flag, the value of the last
+ occurence of each key ends up in the result. Key equivalence is
+ checked byte-by-byte, without special Unicode comparison
+ algorithms.
+
+ .. versionadded:: 2.1
+
+``JSON_DECODE_ANY``
+ By default, the decoder expects an array or object as the input.
+ With this flag enabled, the decoder accepts any valid JSON value.
+
+ **Note:** Decoding any value may be useful in some scenarios, but
+ it's generally discouraged as it violates strict compatiblity with
+ :rfc:`4627`. If you use this flag, don't expect interoperatibility
+ with other JSON systems.
+
+ .. versionadded:: 2.3
+
+``JSON_DISABLE_EOF_CHECK``
+ By default, the decoder expects that its whole input constitutes a
+ valid JSON text, and issues an error if there's extra data after
+ the otherwise valid JSON input. With this flag enabled, the decoder
+ stops after decoding a valid JSON array or object, and thus allows
+ extra data after the JSON text.
+
+ Normally, reading will stop when the last ``]`` or ``}`` in the
+ JSON input is encountered. If both ``JSON_DISABLE_EOF_CHECK`` and
+ ``JSON_DECODE_ANY`` flags are used, the decoder may read one extra
+ UTF-8 code unit (up to 4 bytes of input). For example, decoding
+ ``4true`` correctly decodes the integer 4, but also reads the
+ ``t``. For this reason, if reading multiple consecutive values that
+ are not arrays or objects, they should be separated by at least one
+ whitespace character.
+
+ .. versionadded:: 2.1
+
+Each function also takes an optional :type:`json_error_t` parameter
+that is filled with error information if decoding fails. It's also
+updated on success; the number of bytes of input read is written to
+its ``position`` field. This is especially useful when using
+``JSON_DISABLE_EOF_CHECK`` to read multiple consecutive JSON texts.
+
+.. versionadded:: 2.3
+ Number of bytes of input read is written to the ``position`` field
+ of the :type:`json_error_t` structure.
+
+If no error or position information is needed, you can pass *NULL*.
+
+The following functions perform the actual JSON decoding.
+
.. function:: json_t *json_loads(const char *input, size_t flags, json_error_t *error)
.. refcounting:: new
Decodes the JSON string *input* and returns the array or object it
contains, or *NULL* on error, in which case *error* is filled with
- information about the error. *flags* is currently unused, and
- should be set to 0.
+ information about the error. *flags* is described above.
+
+.. function:: json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error)
+
+ .. refcounting:: new
+
+ Decodes the JSON string *buffer*, whose length is *buflen*, and
+ returns the array or object it contains, or *NULL* on error, in
+ which case *error* is filled with information about the error. This
+ is similar to :func:`json_loads()` except that the string doesn't
+ need to be null-terminated. *flags* is described above.
+
+ .. versionadded:: 2.1
.. function:: json_t *json_loadf(FILE *input, size_t flags, json_error_t *error)
Decodes the JSON text in stream *input* and returns the array or
object it contains, or *NULL* on error, in which case *error* is
- filled with information about the error. *flags* is currently
- unused, and should be set to 0.
+ filled with information about the error. *flags* is described
+ above.
+
+ This function will start reading the input from whatever position
+ the input file was, without attempting to seek first. If an error
+ occurs, the file position will be left indeterminate. On success,
+ the file position will be at EOF, unless ``JSON_DISABLE_EOF_CHECK``
+ flag was used. In this case, the file position will be at the first
+ character after the last ``]`` or ``}`` in the JSON input. This
+ allows calling :func:`json_loadf()` on the same ``FILE`` object
+ multiple times, if the input consists of consecutive JSON texts,
+ possibly separated by whitespace.
.. function:: json_t *json_load_file(const char *path, size_t flags, json_error_t *error)
Decodes the JSON text in file *path* and returns the array or
object it contains, or *NULL* on error, in which case *error* is
- filled with information about the error. *flags* is currently
- unused, and should be set to 0.
+ filled with information about the error. *flags* is described
+ above.
+
+.. type:: json_load_callback_t
+
+ A typedef for a function that's called by
+ :func:`json_load_callback()` to read a chunk of input data::
+
+ typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);
+
+ *buffer* points to a buffer of *buflen* bytes, and *data* is the
+ corresponding :func:`json_load_callback()` argument passed through.
+
+ On error, the function should return ``(size_t)-1`` to abort the
+ decoding process. When there's no data left, it should return 0 to
+ report that the end of input has been reached.
+
+ .. versionadded:: 2.4
+
+.. function:: json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error)
+
+ .. refcounting:: new
+
+ Decodes the JSON text produced by repeated calls to *callback*, and
+ returns the array or object it contains, or *NULL* on error, in
+ which case *error* is filled with information about the error.
+ *data* is passed through to *callback* on each call. *flags* is
+ described above.
+
+ .. versionadded:: 2.4
.. _apiref-pack:
Building Values
===============
-This sectinon describes functions that help to create, or *pack*,
+This section describes functions that help to create, or *pack*,
complex JSON values, especially nested objects and arrays. Value
building is based on a *format string* that is used to tell the
functions about the expected arguments.
For example, the format string ``"i"`` specifies a single integer
value, while the format string ``"[ssb]"`` or the equivalent ``"[s, s,
-b]"`` specifies an array value with two integers and a boolean as its
+b]"`` specifies an array value with two strings and a boolean as its
items::
/* Create the JSON integer 42 */
``o`` (any value) [json_t \*]
Output any given JSON value as-is. If the value is added to an
array or object, the reference to the value passed to ``o`` is
- stealed by the container.
+ stolen by the container.
``O`` (any value) [json_t \*]
Like ``o``, but the argument's reference count is incremented.
fourth, etc. format character represent a value. Any value may be
an object or array, i.e. recursive value building is supported.
+Whitespace, ``:`` and ``,`` are ignored.
+
The following functions compose the value building API:
.. function:: json_t *json_pack(const char *fmt, ...)
json_pack("{}");
/* Build the JSON object {"foo": 42, "bar": 7} */
- json_pack("{sisb}", "foo", 42, "bar", 7);
+ json_pack("{sisi}", "foo", 42, "bar", 7);
/* Like above, ':', ',' and whitespace are ignored */
- json_pack("{s:i, s:b}", "foo", 42, "bar", 7);
+ json_pack("{s:i, s:i}", "foo", 42, "bar", 7);
/* Build the JSON array [[1, 2], {"cool": true}] */
- json_pack("[[i,i],{s:b]]", 1, 2, "cool", 1);
+ json_pack("[[i,i],{s:b}]", 1, 2, "cool", 1);
.. _apiref-unpack:
``s`` (string) [const char \*]
Convert a JSON string to a pointer to a NULL terminated UTF-8
- string.
+ string. The resulting string is extracted by using
+ :func:`json_string_value()` internally, so it exists as long as
+ there are still references to the corresponding JSON string.
``n`` (null)
Expect a JSON null value. Nothing is extracted.
``fmt`` may contain objects and arrays as values, i.e. recursive
value extraction is supporetd.
+ .. versionadded:: 2.3
+ Any ``s`` representing a key may be suffixed with a ``?`` to
+ make the key optional. If the key is not found, nothing is
+ extracted. See below for an example.
+
``!``
This special format character is used to enable the check that
all object and array items are accessed, on a per-value basis. It
or object as the last format character before the closing bracket
or brace.
+Whitespace, ``:`` and ``,`` are ignored.
+
The following functions compose the parsing and validation API:
.. function:: int json_unpack(json_t *root, const char *fmt, ...)
behaviour of the unpacker, see below for the flags. Returns 0 on
success and -1 on failure.
+.. note::
+
+ The first argument of all unpack functions is ``json_t *root``
+ instead of ``const json_t *root``, because the use of ``O`` format
+ character causes the reference count of ``root``, or some value
+ reachable from ``root``, to be increased. Furthermore, the ``o``
+ format character may be used to extract a value as-is, which allows
+ modifying the structure or contents of a value reachable from
+ ``root``.
+
+ If the ``O`` and ``o`` format characters are not used, it's
+ perfectly safe to cast a ``const json_t *`` variable to plain
+ ``json_t *`` when used with these functions.
+
The following unpacking flags are available:
``JSON_STRICT``
json_unpack(root, "[ii!]", &myint1, &myint2);
/* returns -1 for failed validation */
+ /* root is an empty JSON object */
+ int myint = 0, myint2 = 0;
+ json_unpack(root, "{s?i, s?[ii]}",
+ "foo", &myint1,
+ "bar", &myint2, &myint3);
+ /* myint1, myint2 or myint3 is no touched as "foo" and "bar" don't exist */
+
Equality
========
Returns a deep copy of *value*, or *NULL* on error.
+.. _apiref-custom-memory-allocation:
+
Custom Memory Allocation
========================
For more information about the issues of storing sensitive data in
memory, see
http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/protect-secrets.html.
-The page also examplains the :func:`guaranteed_memset()` function used
+The page also explains the :func:`guaranteed_memset()` function used
in the example and gives a sample implementation for it.
# General information about the project.
project = u'Jansson'
-copyright = u'2009-2011, Petri Lehtinen'
+copyright = u'2009-2012, Petri Lehtinen'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
-version = '2.0'
+version = '2.4'
# The full version, including alpha/beta/rc tags.
-release = '2.0'
+release = version
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
***************
JSON is specified in :rfc:`4627`, *"The application/json Media Type
-for JavaScript Object Notation (JSON)"*. This chapter discusses
-Jansson's conformance to this specification.
+for JavaScript Object Notation (JSON)"*.
Character Encoding
==================
All other Unicode codepoints U+0001 through U+10FFFF are allowed.
+Unicode normalization or any other transformation is never performed
+on any strings (string values or object keys). When checking for
+equivalence of strings or object keys, the comparison is performed
+byte by byte between the original UTF-8 representations of the
+strings.
+
Numbers
=======
<description of the json_object function>
- :copyright: Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ :copyright: Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
:license: MIT, see LICENSE for details.
"""
The Jansson source is available at
http://www.digip.org/jansson/releases/.
-Unix-like systems
------------------
+Unix-like systems (including MinGW)
+-----------------------------------
Unpack the source tarball and change to the source directory:
.. _libtool: http://www.gnu.org/software/libtool/
+Windows
+-------
+
+Jansson can be built with Visual Studio 2010 (and probably newer
+versions, too). The solution and project files are in the
+``win32/vs2010/`` directory in the source distribution.
+
+
Other Systems
-------------
-On Windows and other non Unix-like systems, you may be unable to run
-the ``./configure`` script. In this case, follow these steps. All the
-files mentioned can be found in the ``src/`` directory.
+On non Unix-like systems, you may be unable to run the ``./configure``
+script. In this case, follow these steps. All the files mentioned can
+be found in the ``src/`` directory.
-1. Create ``jansson_config.h``. This file has some platform-specific
+1. Create ``jansson_config.h`` (which has some platform-specific
parameters that are normally filled in by the ``./configure``
- script:
-
- - On Windows, rename ``jansson_config.h.win32`` to ``jansson_config.h``.
-
- - On other systems, edit ``jansson_config.h.in``, replacing all
- ``@variable@`` placeholders, and rename the file to
- ``jansson_config.h``.
+ script). Edit ``jansson_config.h.in``, replacing all ``@variable@``
+ placeholders, and rename the file to ``jansson_config.h``.
2. Make ``jansson.h`` and ``jansson_config.h`` available to the
compiler, so that they can be found when compiling programs that
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
#define BUFFER_SIZE (256 * 1024) /* 256 KB */
-#define URL_FORMAT "http://github.com/api/v2/json/commits/list/%s/%s/master"
+#define URL_FORMAT "https://api.github.com/repos/%s/%s/commits"
#define URL_SIZE 256
/* Return the offset of the first newline in text or the length of
json_t *root;
json_error_t error;
- json_t *commits;
if(argc != 3)
{
return 1;
}
- commits = json_object_get(root, "commits");
- if(!json_is_array(commits))
+ if(!json_is_array(root))
{
- fprintf(stderr, "error: commits is not an array\n");
+ fprintf(stderr, "error: root is not an array\n");
return 1;
}
- for(i = 0; i < json_array_size(commits); i++)
+ for(i = 0; i < json_array_size(root); i++)
{
- json_t *commit, *id, *message;
+ json_t *data, *sha, *commit, *message;
const char *message_text;
- commit = json_array_get(commits, i);
- if(!json_is_object(commit))
+ data = json_array_get(root, i);
+ if(!json_is_object(data))
+ {
+ fprintf(stderr, "error: commit data %d is not an object\n", i + 1);
+ return 1;
+ }
+
+ sha = json_object_get(data, "sha");
+ if(!json_is_string(sha))
{
- fprintf(stderr, "error: commit %d is not an object\n", i + 1);
+ fprintf(stderr, "error: commit %d: sha is not a string\n", i + 1);
return 1;
}
- id = json_object_get(commit, "id");
- if(!json_is_string(id))
+ commit = json_object_get(data, "commit");
+ if(!json_is_object(commit))
{
- fprintf(stderr, "error: commit %d: id is not a string\n", i + 1);
+ fprintf(stderr, "error: commit %d: commit is not an object\n", i + 1);
return 1;
}
message_text = json_string_value(message);
printf("%.8s %.*s\n",
- json_string_value(id),
+ json_string_value(sha),
newline_offset(message_text),
message_text);
}
Jansson is licensed under the `MIT license`_; see LICENSE in the
source distribution for details.
+Jansson is used in production and its API is stable. It works on
+numerous platforms, including numerous Unix like systems and Windows.
+It's suitable for use on any system, including desktop, server, and
+small embedded systems.
+
.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php
.. _Jansson: http://www.digip.org/jansson/
upgrading
tutorial
conformance
+ portability
apiref
changes
--- /dev/null
+***********
+Portability
+***********
+
+Thread safety
+-------------
+
+Jansson is thread safe and has no mutable global state. The only
+exception are the memory allocation functions, that should be set at
+most once, and only on program startup. See
+:ref:`apiref-custom-memory-allocation`.
+
+There's no locking performed inside Jansson's code, so a multithreaded
+program must perform its own locking if JSON values are shared by
+multiple threads. Jansson's reference counting semantics may make this
+a bit harder than it seems, as it's possible to have a reference to a
+value that's also stored inside a list or object. Modifying the
+container (adding or removing values) may trigger concurrent access to
+such values, as containers manage the reference count of their
+contained values. Bugs involving concurrent incrementing or
+decrementing of deference counts may be hard to track.
+
+The encoding functions (:func:`json_dumps()` and friends) track
+reference loops by modifying the internal state of objects and arrays.
+For this reason, encoding functions must not be run on the same JSON
+values in two separate threads at the same time. As already noted
+above, be especially careful if two arrays or objects share their
+contained values with another array or object.
+
+If you want to make sure that two JSON value hierarchies do not
+contain shared values, use :func:`json_deep_copy()` to make copies.
+
+Locale
+------
+
+Jansson works fine under any locale.
+
+However, if the host program is multithreaded and uses ``setlocale()``
+to switch the locale in one thread while Jansson is currently encoding
+or decoding JSON data in another thread, the result may be wrong or
+the program may even crash.
+
+Jansson uses locale specific functions for certain string conversions
+in the encoder and decoder, and then converts the locale specific
+values to/from the JSON representation. This fails if the locale
+changes between the string conversion and the locale-to-JSON
+conversion. This can only happen in multithreaded programs that use
+``setlocale()``, because ``setlocale()`` switches the locale for all
+running threads, not only the thread that calls ``setlocale()``.
+
+If your program uses ``setlocale()`` as described above, consider
+using the thread-safe ``uselocale()`` instead.
.. highlight:: c
In this tutorial, we create a program that fetches the latest commits
-of a repository in GitHub_ over the web. One of the response formats
-supported by `GitHub API`_ is JSON, so the result can be parsed using
-Jansson.
+of a repository in GitHub_ over the web. `GitHub API`_ uses JSON, so
+the result can be parsed using Jansson.
To stick to the the scope of this tutorial, we will only cover the the
parts of the program related to handling JSON data. For the best user
the program too many times within a short period of time, the sever
starts to respond with an error.
-.. _GitHub: http://github.com/
-.. _GitHub API: http://develop.github.com/
+.. _GitHub: https://github.com/
+.. _GitHub API: http://developer.github.com/
.. _libcurl: http://curl.haxx.se/
.. _tutorial-github-commits-api:
-The GitHub Commits API
-======================
+The GitHub Repo Commits API
+===========================
-The `GitHub commits API`_ is used by sending HTTP requests to URLs
-starting with ``http://github.com/api/v2/json/commits/``. Our program
-only lists the latest commits, so the rest of the URL is
-``list/USER/REPOSITORY/BRANCH``, where ``USER``, ``REPOSITORY`` and
-``BRANCH`` are the GitHub user ID, the name of the repository, and the
-name of the branch whose commits are to be listed, respectively.
+The `GitHub Repo Commits API`_ is used by sending HTTP requests to
+URLs like ``https://api.github.com/repos/USER/REPOSITORY/commits``,
+where ``USER`` and ``REPOSITORY`` are the GitHub user ID and the name
+of the repository whose commits are to be listed, respectively.
-GitHub responds with a JSON object of the following form:
+GitHub responds with a JSON array of the following form:
.. code-block:: none
- {
- "commits": [
- {
- "id": "<the commit ID>",
+ [
+ {
+ "sha": "<the commit ID>",
+ "commit": {
"message": "<the commit message>",
- <more fields, not important to this tutorial>
+ <more fields, not important to this tutorial...>
},
- {
- "id": "<the commit ID>",
+ <more fields...>
+ },
+ {
+ "sha": "<the commit ID>",
+ "commit": {
"message": "<the commit message>",
- <more fields, not important to this tutorial>
+ <more fields...>
},
- <more commits...>
- ]
- }
+ <more fields...>
+ },
+ <more commits...>
+ ]
In our program, the HTTP request is sent using the following
function::
<github_commits.c>`, as the actual implementation is not important
here.
-.. _GitHub commits API: http://develop.github.com/p/commits.html
+.. _GitHub Repo Commits API: http://developer.github.com/v3/repos/commits/
.. _tutorial-the-program:
Like all the programs using Jansson, we need to include
:file:`jansson.h`.
-The following definitions are used to build the GitHub commits API
-request URL::
+The following definitions are used to build the GitHub API request
+URL::
- #define URL_FORMAT "http://github.com/api/v2/json/commits/list/%s/%s/master"
+ #define URL_FORMAT "https://api.github.com/repos/%s/%s/commits"
#define URL_SIZE 256
The following function is used when formatting the result to find the
The main function follows. In the beginning, we first declare a bunch
of variables and check the command line parameters::
- size_t i;
- char *text;
- char url[URL_SIZE];
+ int main(int argc, char *argv[])
+ {
+ size_t i;
+ char *text;
+ char url[URL_SIZE];
- json_t *root;
- json_error_t error;
- json_t *commits;
+ json_t *root;
+ json_error_t error;
- if(argc != 3)
- {
- fprintf(stderr, "usage: %s USER REPOSITORY\n\n", argv[0]);
- fprintf(stderr, "List commits at USER's REPOSITORY.\n\n");
- return 2;
- }
+ if(argc != 3)
+ {
+ fprintf(stderr, "usage: %s USER REPOSITORY\n\n", argv[0]);
+ fprintf(stderr, "List commits at USER's REPOSITORY.\n\n");
+ return 2;
+ }
Then we build the request URL using the user and repository names
given as command line parameters::
The structure of the response JSON was explained in section
:ref:`tutorial-github-commits-api`.
-First, we'll extract the ``commits`` array from the JSON response::
+We check that the returned value really is an array::
- commits = json_object_get(root, "commits");
- if(!json_is_array(commits))
+ if(!json_is_array(root))
{
- fprintf(stderr, "error: commits is not an array\n");
+ fprintf(stderr, "error: root is not an array\n");
return 1;
}
-This is the array that contains objects describing latest commits in
-the repository. We check that the returned value really is an array.
-If the key ``commits`` doesn't exist, :func:`json_object_get()`
-returns *NULL*, but :func:`json_is_array()` handles this case, too.
-
Then we proceed to loop over all the commits in the array::
- for(i = 0; i < json_array_size(commits); i++)
+ for(i = 0; i < json_array_size(root); i++)
{
- json_t *commit, *id, *message;
+ json_t *data, *sha, *commit, *message;
const char *message_text;
- commit = json_array_get(commits, i);
- if(!json_is_object(commit))
+ data = json_array_get(root, i);
+ if(!json_is_object(data))
{
- fprintf(stderr, "error: commit %d is not an object\n", i + 1);
+ fprintf(stderr, "error: commit data %d is not an object\n", i + 1);
return 1;
}
...
The function :func:`json_array_size()` returns the size of a JSON
array. First, we again declare some variables and then extract the
-i'th element of the ``commits`` array using :func:`json_array_get()`.
+i'th element of the ``root`` array using :func:`json_array_get()`.
We also check that the resulting value is a JSON object.
-Next we'll extract the commit ID and commit message, and check that
-they both are JSON strings::
+Next we'll extract the commit ID (a hexadecimal SHA-1 sum),
+intermediate commit info object, and the commit message from that
+object. We also do proper type checks::
+
+ sha = json_object_get(data, "sha");
+ if(!json_is_string(sha))
+ {
+ fprintf(stderr, "error: commit %d: sha is not a string\n", i + 1);
+ return 1;
+ }
- id = json_object_get(commit, "id");
- if(!json_is_string(id))
+ commit = json_object_get(data, "commit");
+ if(!json_is_object(commit))
{
- fprintf(stderr, "error: commit %d: id is not a string\n", i + 1);
+ fprintf(stderr, "error: commit %d: commit is not an object\n", i + 1);
return 1;
}
Jansson's repository::
$ ./github_commits akheron jansson
- 86dc1d62 Fix indentation
- b67e130f json_dumpf: Document the output shortage on error
- 4cd77771 Enhance handling of circular references
- 79009e62 json_dumps: Close the strbuffer if dumping fails
- 76999799 doc: Fix a small typo in apiref
- 22af193a doc/Makefile.am: Remove *.pyc in clean
- 951d091f Make integer, real and string mutable
- 185e107d Don't use non-portable asprintf()
- ca7703fb Merge branch '1.0'
- 12cd4e8c jansson 1.0.4
- <etc...>
+ 1581f26a Merge branch '2.3'
+ aabfd493 load: Change buffer_pos to be a size_t
+ bd72efbd load: Avoid unexpected behaviour in macro expansion
+ e8fd3e30 Document and tweak json_load_callback()
+ 873eddaf Merge pull request #60 from rogerz/contrib
+ bd2c0c73 Ignore the binary test_load_callback
+ 17a51a4b Merge branch '2.3'
+ 09c39adc Add json_load_callback to the list of exported symbols
+ cbb80baf Merge pull request #57 from rogerz/contrib
+ 040bd7b0 Add json_load_callback()
+ 2637faa4 Make test stripping locale independent
+ <...>
Conclusion
==========
In this tutorial, we implemented a program that fetches the latest
-commits of a GitHub repository using the GitHub commits API. Jansson
-was used to decode the JSON response and to extract the commit data.
+commits of a GitHub repository using the GitHub Repo Commits API.
+Jansson was used to decode the JSON response and to extract the commit
+data.
This tutorial only covered a small part of Jansson. For example, we
did not create or manipulate JSON values at all. Proceed to
+EXTRA_DIST = jansson.def
+
include_HEADERS = jansson.h jansson_config.h
lib_LTLIBRARIES = libjansson.la
pack_unpack.c \
strbuffer.c \
strbuffer.h \
+ strconv.c \
utf.c \
utf.h \
value.c
libjansson_la_LDFLAGS = \
+ -no-undefined \
-export-symbols-regex '^json_' \
- -version-info 4:0:0
+ -version-info 8:0:4
if GCC
# These flags are gcc specific
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
#include <string.h>
#include <assert.h>
-#include <jansson.h>
+#include "jansson.h"
#include "jansson_private.h"
#include "strbuffer.h"
#include "utf.h"
#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)
/* 32 spaces (the maximum indentation size) */
static char whitespace[] = " ";
-static int dump_indent(size_t 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)
{
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;
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;
if(end == pos)
break;
- /* handle \, ", and control codes */
+ /* handle \, /, ", and control codes */
length = 2;
switch(codepoint)
{
case '\n': text = "\\n"; break;
case '\r': text = "\\r"; break;
case '\t': text = "\\t"; break;
+ case '/': text = "\\/"; break;
default:
{
/* codepoint is in BMP */
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, size_t flags, int depth,
- dump_func dump, void *data)
+ json_dump_callback_t dump, void *data)
{
- int ascii = flags & JSON_ENSURE_ASCII ? 1 : 0;
-
switch(json_typeof(json)) {
case JSON_NULL:
return dump("null", 4, data);
size = snprintf(buffer, MAX_INTEGER_STR_LENGTH,
"%" JSON_INTEGER_FORMAT,
json_integer_value(json));
- if(size >= MAX_INTEGER_STR_LENGTH)
+ if(size < 0 || size >= MAX_INTEGER_STR_LENGTH)
return -1;
return dump(buffer, size, data);
{
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:
{
if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER)
{
- const object_key_t **keys;
+ struct object_key *keys;
size_t size, i;
int (*cmp_func)(const void *, const void *);
size = json_object_size(json);
- keys = jsonp_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++;
}
else
cmp_func = object_key_compare_serials;
- qsort(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))
{
{
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))
}
}
-
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 = jsonp_strdup(strbuffer_value(&strbuff));
strbuffer_close(&strbuff);
-
return result;
}
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, size_t 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);
+}
error->position = position;
vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH, msg, ap);
+ error->text[JSON_ERROR_TEXT_LENGTH - 1] = '\0';
}
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* 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 <stdlib.h>
+#include <string.h>
#include <jansson_config.h> /* for JSON_INLINE */
#include "jansson_private.h" /* for container_of() */
#include "hashtable.h"
#define list_to_pair(list_) container_of(list_, pair_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;
12582917, 25165843, 50331653, 100663319, 201326611, 402653189,
805306457, 1610612741
};
-static const size_t num_primes = sizeof(primes) / sizeof(size_t);
static JSON_INLINE size_t num_buckets(hashtable_t *hashtable)
{
static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
- const void *key, size_t hash)
+ const char *key, size_t hash)
{
list_t *list;
pair_t *pair;
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)
/* returns 0 on success, -1 if key was not found */
static int hashtable_do_del(hashtable_t *hashtable,
- const void *key, size_t hash)
+ const char *key, size_t hash)
{
pair_t *pair;
bucket_t *bucket;
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;
{
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);
+ json_decref(pair->value);
jsonp_free(pair);
}
}
}
-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 = jsonp_malloc(sizeof(hashtable_t));
- if(!hashtable)
- return NULL;
-
- if(hashtable_init(hashtable, hash_key, cmp_keys, free_key, free_value))
- {
- jsonp_free(hashtable);
- return NULL;
- }
-
- return hashtable;
-}
-
-void hashtable_destroy(hashtable_t *hashtable)
-{
- hashtable_close(hashtable);
- jsonp_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)
{
size_t i;
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 =
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;
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 = jsonp_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);
return 0;
}
-void *hashtable_get(hashtable_t *hashtable, const void *key)
+void *hashtable_get(hashtable_t *hashtable, const char *key)
{
pair_t *pair;
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);
return pair->value;
}
-int hashtable_del(hashtable_t *hashtable, const void *key)
+int hashtable_del(hashtable_t *hashtable, const char *key)
{
- size_t hash = hashtable->hash_key(key);
+ size_t hash = hash_str(key);
return hashtable_do_del(hashtable, key, hash);
}
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;
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);
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;
}
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
#ifndef HASHTABLE_H
#define HASHTABLE_H
-typedef size_t (*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;
size_t hash;
struct hashtable_list list;
+ json_t *value;
+ size_t serial;
+ char key[1];
};
struct hashtable_bucket {
struct hashtable_bucket *buckets;
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
*
* @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
*
* 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
*
* 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
* 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
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
*
* @iter: The iterator
* @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
--- /dev/null
+LIBRARY "jansson"
+
+EXPORTS
+ json_delete
+ json_true
+ json_false
+ json_null
+ json_string
+ json_string_nocheck
+ json_string_value
+ json_string_set
+ json_string_set_nocheck
+ json_integer
+ json_integer_value
+ json_integer_set
+ json_real
+ json_real_value
+ json_real_set
+ json_number_value
+ json_array
+ json_array_size
+ json_array_get
+ json_array_set_new
+ json_array_append_new
+ json_array_insert_new
+ json_array_remove
+ json_array_clear
+ json_array_extend
+ json_object
+ json_object_size
+ json_object_get
+ json_object_set_new
+ json_object_set_new_nocheck
+ json_object_del
+ json_object_clear
+ json_object_update
+ json_object_update_existing
+ json_object_update_missing
+ json_object_iter
+ json_object_iter_at
+ json_object_iter_next
+ json_object_iter_key
+ json_object_iter_value
+ json_object_iter_set_new
+ json_object_key_to_iter
+ json_dumps
+ json_dumpf
+ json_dump_file
+ json_dump_callback
+ json_loads
+ json_loadb
+ json_loadf
+ json_load_file
+ json_load_callback
+ json_equal
+ json_copy
+ json_deep_copy
+ json_pack
+ json_pack_ex
+ json_vpack_ex
+ json_unpack
+ json_unpack_ex
+ json_vunpack_ex
+ json_set_alloc_funcs
+
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
/* version */
#define JANSSON_MAJOR_VERSION 2
-#define JANSSON_MINOR_VERSION 0
+#define JANSSON_MINOR_VERSION 4
#define JANSSON_MICRO_VERSION 0
/* Micro version is omitted if it's 0 */
-#define JANSSON_VERSION "2.0"
+#define JANSSON_VERSION "2.4"
/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
} json_t;
#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"
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
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))))
+
static JSON_INLINE
int json_object_set(json_t *object, const char *key, json_t *value)
{
json_t *json_deep_copy(json_t *value);
-/* loading, printing */
+/* decoding */
+
+#define JSON_REJECT_DUPLICATES 0x1
+#define JSON_DISABLE_EOF_CHECK 0x2
+#define JSON_DECODE_ANY 0x4
+
+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);
/* custom memory allocation */
/*
- * Copyright (c) 2010-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2010-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
#define JSON_INLINE @json_inline@
#endif
-/* If your compiler supports the `long long` type,
- JSON_INTEGER_IS_LONG_LONG is defined to 1, otherwise to 0. */
+/* 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 @json_have_long_long@
+/* If locale.h and localeconv() are available, define to 1,
+ otherwise to 0. */
+#define JSON_HAVE_LOCALECONV @json_have_localeconv@
+
#endif
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
#include <stddef.h>
#include "jansson.h"
#include "hashtable.h"
+#include "strbuffer.h"
#define container_of(ptr_, type_, member_) \
((type_ *)((char *)ptr_ - offsetof(type_, member_)))
#define json_to_real(json_) container_of(json_, json_real_t, json)
#define json_to_integer(json_) container_of(json_, json_integer_t, json)
-size_t jsonp_hash_key(const void *ptr);
-int jsonp_key_equal(const void *ptr1, const void *ptr2);
-
-typedef struct {
- size_t serial;
- char key[1];
-} object_key_t;
-
-const object_key_t *jsonp_object_iter_fullkey(void *iter);
-
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,
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);
+
/* Wrappers for custom memory functions */
void* jsonp_malloc(size_t size);
void jsonp_free(void *ptr);
char *jsonp_strdup(const char *str);
+/* Windows compatibility */
+#ifdef _WIN32
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+#endif
+
#endif
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#define _GNU_SOURCE
-#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
-#include <jansson.h>
+#include "jansson.h"
#include "jansson_private.h"
#include "strbuffer.h"
#include "utf.h"
#define TOKEN_FALSE 260
#define TOKEN_NULL 261
+/* 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(). */
get_func get;
void *data;
char buffer[5];
- int buffer_pos;
+ size_t buffer_pos;
int state;
int line;
int column, last_column;
{
va_list ap;
char msg_text[JSON_ERROR_TEXT_LENGTH];
+ char msg_with_context[JSON_ERROR_TEXT_LENGTH];
int line = -1, col = -1;
size_t pos = 0;
va_start(ap, msg);
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);
- char msg_with_context[JSON_ERROR_TEXT_LENGTH];
line = lex->stream.line;
col = lex->stream.column;
if(lex->saved_text.length <= 20) {
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(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;
}
}
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);
if(c == 'u') {
c = lex_get_save(lex, error);
for(i = 0; i < 4; i++) {
- if(!isxdigit(c)) {
+ if(!l_isxdigit(c)) {
error_set(error, lex, "invalid escape");
goto out;
}
}
#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
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 {
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);
}
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;
}
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);
/*** 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)
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 != ':') {
jsonp_free(key);
}
lex_scan(lex, error);
- value = parse_value(lex, error);
+ value = parse_value(lex, flags, error);
if(!value) {
jsonp_free(key);
goto 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)
return array;
while(lex->token) {
- json_t *elem = parse_value(lex, error);
+ json_t *elem = parse_value(lex, flags, error);
if(!elem)
goto 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;
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:
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)
{
+ 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;
+ }
}
- return parse_value(lex, error);
+ if(error) {
+ /* Save the position even though there was no error */
+ error->position = lex->stream.position;
+ }
+
+ return result;
}
typedef struct
json_t *result;
string_data_t stream_data;
- (void)flags; /* unused */
+ jsonp_error_init(error, "<string>");
+
+ 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;
- jsonp_error_init(error, "<string>");
+ result = parse_json(&lex, flags, error);
- result = parse_json(&lex, error);
- if(!result)
- goto out;
+ 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_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;
- lex_scan(&lex, error);
- if(lex.token != TOKEN_EOF) {
- error_set(error, &lex, "end of file expected");
- json_decref(result);
- result = NULL;
+ jsonp_error_init(error, "<buffer>");
+
+ if (buffer == NULL) {
+ error_set(error, NULL, "wrong arguments");
+ return NULL;
}
-out:
+ stream_data.data = buffer;
+ stream_data.pos = 0;
+ stream_data.len = buflen;
+
+ if(lex_init(&lex, buffer_get, (void *)&stream_data))
+ return NULL;
+
+ result = parse_json(&lex, flags, error);
+
lex_close(&lex);
return result;
}
lex_t lex;
const char *source;
json_t *result;
- (void)flags; /* unused */
-
- if(lex_init(&lex, (get_func)fgetc, input))
- return NULL;
if(input == stdin)
source = "<stdin>";
jsonp_error_init(error, source);
- result = parse_json(&lex, error);
- if(!result)
- goto out;
-
- 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;
}
jsonp_error_init(error, path);
- fp = fopen(path, "r");
+ if (path == NULL) {
+ error_set(error, NULL, "wrong arguments");
+ return NULL;
+ }
+
+ fp = fopen(path, "rb");
if(!fp)
{
error_set(error, NULL, "unable to open %s: %s",
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, "<callback>");
+
+ 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;
+}
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
- * Copyright (c) 2011 Basile Starynkevitch <basile@starynkevitch.net>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2011-2012 Basile Starynkevitch <basile@starynkevitch.net>
*
* Jansson is free software; you can redistribute it and/or modify it
* under the terms of the MIT license. See LICENSE for details.
#include <stdlib.h>
#include <string.h>
-#include <jansson.h>
+#include "jansson.h"
#include "jansson_private.h"
/* memory function pointers */
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
- * Copyright (c) 2011 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2011-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <string.h>
-#include <jansson.h>
+#include "jansson.h"
#include "jansson_private.h"
#include "utf.h"
*/
hashtable_t key_set;
- if(hashtable_init(&key_set, jsonp_hash_key, jsonp_key_equal, NULL, NULL)) {
+ if(hashtable_init(&key_set)) {
set_error(s, "<internal>", "Out of memory");
return -1;
}
- if(!json_is_object(root)) {
+ if(root && !json_is_object(root)) {
set_error(s, "<validation>", "Expected object, got %s",
type_name(root));
goto out;
while(s->token != '}') {
const char *key;
json_t *value;
+ int opt = 0;
if(strict != 0) {
set_error(s, "<format>", "Expected '}' after '%c', got '%c'",
next_token(s);
- value = json_object_get(root, key);
- if(!value) {
- set_error(s, "<validation>", "Object item not found: %s", key);
- goto out;
+ if(s->token == '?') {
+ opt = 1;
+ next_token(s);
+ }
+
+ if(!root) {
+ /* skipping */
+ value = NULL;
+ }
+ else {
+ value = json_object_get(root, key);
+ if(!value && !opt) {
+ set_error(s, "<validation>", "Object item not found: %s", key);
+ goto out;
+ }
}
if(unpack(s, value, ap))
goto out;
- hashtable_set(&key_set, (void *)key, NULL);
+ hashtable_set(&key_set, key, 0, json_null());
next_token(s);
}
if(strict == 0 && (s->flags & JSON_STRICT))
strict = 1;
- if(strict == 1 && key_set.size != json_object_size(root)) {
+ 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, "<validation>", "%li object item(s) left unpacked", diff);
goto out;
size_t i = 0;
int strict = 0;
- if(!json_is_array(root)) {
+ if(root && !json_is_array(root)) {
set_error(s, "<validation>", "Expected array, got %s", type_name(root));
return -1;
}
return -1;
}
- value = json_array_get(root, i);
- if(!value) {
- set_error(s, "<validation>", "Array index %lu out of range",
- (unsigned long)i);
- return -1;
+ if(!root) {
+ /* skipping */
+ value = NULL;
+ }
+ else {
+ value = json_array_get(root, i);
+ if(!value) {
+ set_error(s, "<validation>", "Array index %lu out of range",
+ (unsigned long)i);
+ return -1;
+ }
}
if(unpack(s, value, ap))
if(strict == 0 && (s->flags & JSON_STRICT))
strict = 1;
- if(strict == 1 && i != json_array_size(root)) {
+ if(root && strict == 1 && i != json_array_size(root)) {
long diff = (long)json_array_size(root) - (long)i;
set_error(s, "<validation>", "%li array item(s) left unpacked", diff);
return -1;
return unpack_array(s, root, ap);
case 's':
- if(!json_is_string(root)) {
+ if(root && !json_is_string(root)) {
set_error(s, "<validation>", "Expected string, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
- const char **str;
+ const char **target;
- str = va_arg(*ap, const char **);
- if(!str) {
+ target = va_arg(*ap, const char **);
+ if(!target) {
set_error(s, "<args>", "NULL string argument");
return -1;
}
- *str = json_string_value(root);
+ if(root)
+ *target = json_string_value(root);
}
return 0;
case 'i':
- if(!json_is_integer(root)) {
+ if(root && !json_is_integer(root)) {
set_error(s, "<validation>", "Expected integer, got %s",
type_name(root));
return -1;
}
- if(!(s->flags & JSON_VALIDATE_ONLY))
- *va_arg(*ap, int*) = json_integer_value(root);
+ 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(!json_is_integer(root)) {
+ if(root && !json_is_integer(root)) {
set_error(s, "<validation>", "Expected integer, got %s",
type_name(root));
return -1;
}
- if(!(s->flags & JSON_VALIDATE_ONLY))
- *va_arg(*ap, json_int_t*) = json_integer_value(root);
+ 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(!json_is_boolean(root)) {
+ if(root && !json_is_boolean(root)) {
set_error(s, "<validation>", "Expected true or false, got %s",
type_name(root));
return -1;
}
- if(!(s->flags & JSON_VALIDATE_ONLY))
- *va_arg(*ap, int*) = json_is_true(root);
+ if(!(s->flags & JSON_VALIDATE_ONLY)) {
+ int *target = va_arg(*ap, int*);
+ if(root)
+ *target = json_is_true(root);
+ }
return 0;
case 'f':
- if(!json_is_real(root)) {
+ if(root && !json_is_real(root)) {
set_error(s, "<validation>", "Expected real, got %s",
type_name(root));
return -1;
}
- if(!(s->flags & JSON_VALIDATE_ONLY))
- *va_arg(*ap, double*) = json_real_value(root);
+ if(!(s->flags & JSON_VALIDATE_ONLY)) {
+ double *target = va_arg(*ap, double*);
+ if(root)
+ *target = json_real_value(root);
+ }
return 0;
case 'F':
- if(!json_is_number(root)) {
+ if(root && !json_is_number(root)) {
set_error(s, "<validation>", "Expected real or integer, got %s",
type_name(root));
return -1;
}
- if(!(s->flags & JSON_VALIDATE_ONLY))
- *va_arg(*ap, double*) = json_number_value(root);
+ if(!(s->flags & JSON_VALIDATE_ONLY)) {
+ double *target = va_arg(*ap, double*);
+ if(root)
+ *target = json_number_value(root);
+ }
return 0;
case 'O':
- if(!(s->flags & JSON_VALIDATE_ONLY))
+ if(root && !(s->flags & JSON_VALIDATE_ONLY))
json_incref(root);
/* Fall through */
case 'o':
- if(!(s->flags & JSON_VALIDATE_ONLY))
- *va_arg(*ap, json_t**) = root;
+ 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(!json_is_null(root)) {
+ if(root && !json_is_null(root)) {
set_error(s, "<validation>", "Expected null, got %s",
type_name(root));
return -1;
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
#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;
void strbuffer_close(strbuffer_t *strbuff)
{
- free(strbuff->value);
+ jsonp_free(strbuff->value);
strbuff->size = 0;
strbuff->length = 0;
strbuff->value = NULL;
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)
{
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);
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
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);
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);
--- /dev/null
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include "jansson_private.h"
+#include "strbuffer.h"
+
+#if JSON_HAVE_LOCALECONV
+#include <locale.h>
+
+/*
+ - 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;
+}
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
+#include <math.h>
-#include <jansson.h>
+#include "jansson.h"
#include "hashtable.h"
#include "jansson_private.h"
#include "utf.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 JSON_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)
-
-size_t jsonp_hash_key(const void *ptr)
-{
- const char *str = ((const object_key_t *)ptr)->key;
-
- size_t hash = 5381;
- size_t c;
-
- while((c = (size_t)*str))
- {
- hash = ((hash << 5) + hash) + c;
- str++;
- }
-
- return hash;
-}
-
-int jsonp_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 = jsonp_malloc(sizeof(json_object_t));
return NULL;
json_init(&object->json, JSON_OBJECT);
- if(hashtable_init(&object->hashtable,
- jsonp_hash_key, jsonp_key_equal,
- jsonp_free, value_decref))
+ if(hashtable_init(&object->hashtable))
{
jsonp_free(object);
return NULL;
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);
- /* offsetof(...) returns the size of object_key_t without the
- last, flexible member. This way, the correct amount is
- allocated. */
- k = jsonp_malloc(offsetof(object_key_t, key) + 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;
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)
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;
- 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;
+}
+
+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;
+
+ json_object_foreach(other, key, value) {
+ if(!json_object_get(object, key))
+ json_object_set_nocheck(object, key, value);
}
return 0;
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)
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)
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;
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)
{
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_new_nocheck(result, key, json_deep_copy(value));
- iter = json_object_iter_next(object, iter);
- }
-
return result;
}
char *dup;
json_string_t *string;
+ if(!json_is_string(json) || !value)
+ return -1;
+
dup = jsonp_strdup(value);
if(!dup)
return -1;
json_t *json_real(double value)
{
- json_real_t *real = jsonp_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);
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;
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
suites/api/test_copy
suites/api/test_cpp
suites/api/test_dump
+suites/api/test_dump_callback
suites/api/test_equal
suites/api/test_load
+suites/api/test_loadb
suites/api/test_memory_funcs
suites/api/test_number
suites/api/test_object
suites/api/test_pack
suites/api/test_simple
suites/api/test_unpack
+suites/api/test_load_callback
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <jansson.h>
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#if _WIN32
+#include <io.h> /* for _setmode() */
+#include <fcntl.h> /* for _O_BINARY */
+#endif
+
+#define l_isspace(c) ((c) == ' ' || (c) == '\n' || (c) == '\r' || (c) == '\t')
+
static int getenv_int(const char *name)
{
char *value, *end;
{
size_t length;
char *result = str;
- while(*result && isspace(*result))
+ while(*result && l_isspace(*result))
result++;
length = strlen(result);
if(length == 0)
return result;
- while(isspace(result[length - 1]))
+ while(l_isspace(result[length - 1]))
result[--length] = '\0';
return result;
json_t *json;
json_error_t error;
+#if HAVE_SETLOCALE
+ setlocale(LC_ALL, "");
+#endif
+
if(argc != 1) {
fprintf(stderr, "usage: %s\n", argv[0]);
return 2;
}
+#ifdef _WIN32
+ /* On Windows, set stdout and stderr to binary mode to avoid
+ outputting DOS line terminators */
+ _setmode(_fileno(stdout), _O_BINARY);
+ _setmode(_fileno(stderr), _O_BINARY);
+#endif
+
indent = getenv_int("JSON_INDENT");
if(indent < 0 || indent > 255) {
fprintf(stderr, "invalid value for JSON_INDENT: %d\n", indent);
[ -z "$STOP" ] && STOP=0
-export suites_srcdir=$top_srcdir/test/suites
-export suites_builddir=suites
-export scriptdir=$top_srcdir/test/scripts
-export logdir=logs
-export bindir=bin
+suites_srcdir=$top_srcdir/test/suites
+suites_builddir=suites
+scriptdir=$top_srcdir/test/scripts
+logdir=logs
+bindir=bin
+export suites_srcdir suites_builddir scriptdir logdir bindir
passed=0
failed=0
-# Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+# Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
+die() {
+ echo "$1" >&2
+ exit 1
+}
+
+[ -n "$1" ] || die "Usage: $0 suite-name"
+[ -n "$bindir" ] || die "Set bindir"
+[ -n "$logdir" ] || die "Set logdir"
+[ -n "$scriptdir" ] || die "Set scriptdir"
+[ -n "$suites_srcdir" ] || die "Set suites_srcdir"
+[ -n "$suites_builddir" ] || die "Set suites_builddir"
+
json_process=$bindir/json_process
suite_name=$1
suite_builddir=$suites_builddir/$suite_name
suite_log=$logdir/$suite_name
-
[ -z "$VERBOSE" ] && VERBOSE=0
[ -z "$STOP" ] && STOP=0
-# Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+# Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
-EXTRA_DIST = run
+EXTRA_DIST = run check-exports
check_PROGRAMS = \
test_array \
test_copy \
test_dump \
+ test_dump_callback \
test_equal \
test_load \
+ test_loadb \
+ test_load_callback \
test_memory_funcs \
test_number \
test_object \
test_array_SOURCES = test_array.c util.h
test_copy_SOURCES = test_copy.c util.h
test_dump_SOURCES = test_dump.c util.h
+test_dump_callback_SOURCES = test_dump_callback.c util.h
test_load_SOURCES = test_load.c util.h
+test_loadb_SOURCES = test_loadb.c util.h
test_memory_funcs_SOURCES = test_memory_funcs.c util.h
test_number_SOURCES = test_number.c util.h
test_object_SOURCES = test_object.c util.h
#!/bin/sh
-
-# This tests checks that the libjansson.so exports the correct
-# symbols.
-
-# The list of symbols that the shared object should export
-sort >$test_log/exports <<EOF
-json_delete
-json_true
-json_false
-json_null
-json_string
-json_string_nocheck
-json_string_value
-json_string_set
-json_string_set_nocheck
-json_integer
-json_integer_value
-json_integer_set
-json_real
-json_real_value
-json_real_set
-json_number_value
-json_array
-json_array_size
-json_array_get
-json_array_set_new
-json_array_append_new
-json_array_insert_new
-json_array_remove
-json_array_clear
-json_array_extend
-json_object
-json_object_size
-json_object_get
-json_object_set_new
-json_object_set_new_nocheck
-json_object_del
-json_object_clear
-json_object_update
-json_object_iter
-json_object_iter_at
-json_object_iter_next
-json_object_iter_key
-json_object_iter_value
-json_object_iter_set_new
-json_dumps
-json_dumpf
-json_dump_file
-json_loads
-json_loadf
-json_load_file
-json_equal
-json_copy
-json_deep_copy
-json_pack
-json_pack_ex
-json_vpack_ex
-json_unpack
-json_unpack_ex
-json_vunpack_ex
-json_set_alloc_funcs
-EOF
-
-# The list of functions are not exported in the library because they
-# are macros or static inline functions. This is only the make the
-# list complete, there are not used by the test.
-sort >$test_log/macros_or_inline <<EOF
-json_typeof
-json_incref
-json_decref
-json_is_object
-json_is_object
-json_is_array
-json_is_string
-json_is_integer
-json_is_real
-json_is_true
-json_is_false
-json_is_null
-json_is_number
-json_is_boolean
-json_array_set
-json_array_append
-json_array_insert
-json_object_set
-json_object_set_nocheck
-EOF
+#
+# This test checks that libjansson.so exports the correct symbols.
+#
SOFILE="../src/.libs/libjansson.so"
+# The list of symbols, which the shared object should export, is read
+# from the def file, which is used in Windows builds
+grep 'json_' $top_srcdir/src/jansson.def \
+ | sed -e 's/ //g' \
+ | sort \
+ >$test_log/exports
+
nm -D $SOFILE >/dev/null >$test_log/symbols 2>/dev/null \
|| exit 77 # Skip if "nm -D" doesn't seem to work
-grep ' T ' $test_log/symbols | cut -d' ' -f3 | sort >$test_log/output
+grep ' [DT] ' $test_log/symbols | cut -d' ' -f3 | sort >$test_log/output
if ! cmp -s $test_log/exports $test_log/output; then
diff -u $test_log/exports $test_log/output >&2
#!/bin/sh
#
-# Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+# Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
}
-int main()
+static void run_tests()
{
test_misc();
test_insert();
test_clear();
test_extend();
test_circular();
-
- return 0;
}
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
json_decref(copy);
}
-int main()
+static void run_tests()
{
test_copy_simple();
test_deep_copy_simple();
test_deep_copy_array();
test_copy_object();
test_deep_copy_object();
- return 0;
}
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
#include <string.h>
#include "util.h"
-int main()
+static void encode_twice()
{
+ /* Encode an empty object/array, add an item, encode again */
+
json_t *json;
char *result;
- /* Encode an empty object/array, add an item, encode again */
-
json = json_object();
result = json_dumps(json, 0);
if(!result || strcmp(result, "{}"))
free(result);
json_decref(json);
+}
+static void circular_references()
+{
/* Construct a JSON object/array with a circular reference:
object: {"a": {"b": {"c": <circular reference to $.a>}}}
Encode it, remove the circular reference and encode again.
*/
+
+ json_t *json;
+ char *result;
+
json = json_object();
json_object_set_new(json, "a", json_object());
json_object_set_new(json_object_get(json, "a"), "b", json_object());
free(result);
json_decref(json);
+}
+
+static void encode_other_than_array_or_object()
+{
+ /* Encoding anything other than array or object should only
+ * succeed if the JSON_ENCODE_ANY flag is used */
+
+ json_t *json;
+ FILE *fp = NULL;
+ char *result;
+
+ json = json_string("foo");
+ if(json_dumps(json, 0) != NULL)
+ fail("json_dumps encoded a string!");
+ if(json_dumpf(json, fp, 0) == 0)
+ fail("json_dumpf encoded a string!");
+
+ result = json_dumps(json, JSON_ENCODE_ANY);
+ if(!result || strcmp(result, "\"foo\"") != 0)
+ fail("json_dumps failed to encode a string with JSON_ENCODE_ANY");
+
+ free(result);
+ json_decref(json);
+
+ json = json_integer(42);
+ if(json_dumps(json, 0) != NULL)
+ fail("json_dumps encoded an integer!");
+ if(json_dumpf(json, fp, 0) == 0)
+ fail("json_dumpf encoded an integer!");
+
+ result = json_dumps(json, JSON_ENCODE_ANY);
+ if(!result || strcmp(result, "42") != 0)
+ fail("json_dumps failed to encode an integer with JSON_ENCODE_ANY");
+
+ free(result);
+ json_decref(json);
+
+
+}
+
+static void escape_slashes()
+{
+ /* Test dump escaping slashes */
+
+ json_t *json;
+ char *result;
+
+ json = json_object();
+ json_object_set_new(json, "url", json_string("https://github.com/akheron/jansson"));
+
+ result = json_dumps(json, 0);
+ if(!result || strcmp(result, "{\"url\": \"https://github.com/akheron/jansson\"}"))
+ fail("json_dumps failed to not escape slashes");
+
+ free(result);
+
+ result = json_dumps(json, JSON_ESCAPE_SLASH);
+ if(!result || strcmp(result, "{\"url\": \"https:\\/\\/github.com\\/akheron\\/jansson\"}"))
+ fail("json_dumps failed to escape slashes");
+
+ free(result);
+ json_decref(json);
+}
- return 0;
+static void run_tests()
+{
+ encode_twice();
+ circular_references();
+ encode_other_than_array_or_object();
+ escape_slashes();
}
--- /dev/null
+/*
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include <jansson.h>
+#include <string.h>
+#include <stdlib.h>
+#include "util.h"
+
+struct my_sink {
+ char *buf;
+ size_t off;
+ size_t cap;
+};
+
+static int my_writer(const char *buffer, size_t len, void *data) {
+ struct my_sink *s = data;
+ if (len > s->cap - s->off) {
+ return -1;
+ }
+ memcpy(s->buf + s->off, buffer, len);
+ s->off += len;
+ return 0;
+}
+
+static void run_tests()
+{
+ struct my_sink s;
+ json_t *json;
+ const char str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]";
+ char *dumped_to_string;
+
+ json = json_loads(str, 0, NULL);
+ if(!json) {
+ fail("json_loads failed");
+ }
+
+ dumped_to_string = json_dumps(json, 0);
+ if (!dumped_to_string) {
+ json_decref(json);
+ fail("json_dumps failed");
+ }
+
+ s.off = 0;
+ s.cap = strlen(dumped_to_string);
+ s.buf = malloc(s.cap);
+ if (!s.buf) {
+ json_decref(json);
+ free(dumped_to_string);
+ fail("malloc failed");
+ }
+
+ if (json_dump_callback(json, my_writer, &s, 0) == -1) {
+ json_decref(json);
+ free(dumped_to_string);
+ free(s.buf);
+ fail("json_dump_callback failed on an exact-length sink buffer");
+ }
+
+ if (strncmp(dumped_to_string, s.buf, s.off) != 0) {
+ json_decref(json);
+ free(dumped_to_string);
+ free(s.buf);
+ fail("json_dump_callback and json_dumps did not produce identical output");
+ }
+
+ s.off = 1;
+ if (json_dump_callback(json, my_writer, &s, 0) != -1) {
+ json_decref(json);
+ free(dumped_to_string);
+ free(s.buf);
+ fail("json_dump_callback succeeded on a short buffer when it should have failed");
+ }
+
+ json_decref(json);
+ free(dumped_to_string);
+ free(s.buf);
+}
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
/* TODO: There's no negative test case here */
}
-int main()
+static void run_tests()
{
test_equal_simple();
test_equal_array();
test_equal_object();
test_equal_complex();
- return 0;
}
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
#include <string.h>
#include "util.h"
-int main()
+static void file_not_found()
{
json_t *json;
json_error_t error;
+ char *pos;
json = json_load_file("/path/to/nonexistent/file.json", 0, &error);
+ if(json)
+ fail("json_load_file returned non-NULL for a nonexistent file");
if(error.line != -1)
fail("json_load_file returned an invalid line number");
- if(strcmp(error.text, "unable to open /path/to/nonexistent/file.json: No such file or directory") != 0)
+
+ /* The error message is locale specific, only check the beginning
+ of the error message. */
+
+ pos = strchr(error.text, ':');
+ if(!pos)
+ fail("json_load_file returne an invalid error message");
+
+ *pos = '\0';
+
+ if(strcmp(error.text, "unable to open /path/to/nonexistent/file.json") != 0)
fail("json_load_file returned an invalid error message");
+}
+
+static void reject_duplicates()
+{
+ json_error_t error;
+
+ if(json_loads("{\"foo\": 1, \"foo\": 2}", JSON_REJECT_DUPLICATES, &error))
+ fail("json_loads did not detect a duplicate key");
+ check_error("duplicate object key near '\"foo\"'", "<string>", 1, 16, 16);
+}
+
+static void disable_eof_check()
+{
+ json_error_t error;
+ json_t *json;
+
+ const char *text = "{\"foo\": 1} garbage";
+
+ if(json_loads(text, 0, &error))
+ fail("json_loads did not detect garbage after JSON text");
+ check_error("end of file expected near 'garbage'", "<string>", 1, 18, 18);
+
+ json = json_loads(text, JSON_DISABLE_EOF_CHECK, &error);
+ if(!json)
+ fail("json_loads failed with JSON_DISABLE_EOF_CHECK");
+
+ json_decref(json);
+}
+
+static void decode_any()
+{
+ json_t *json;
+ json_error_t error;
- return 0;
+ json = json_loads("\"foo\"", JSON_DECODE_ANY, &error);
+ if (!json || !json_is_string(json))
+ fail("json_load decoded any failed - string");
+ json_decref(json);
+
+ json = json_loads("42", JSON_DECODE_ANY, &error);
+ if (!json || !json_is_integer(json))
+ fail("json_load decoded any failed - integer");
+ json_decref(json);
+
+ json = json_loads("true", JSON_DECODE_ANY, &error);
+ if (!json || !json_is_true(json))
+ fail("json_load decoded any failed - boolean");
+ json_decref(json);
+
+ json = json_loads("null", JSON_DECODE_ANY, &error);
+ if (!json || !json_is_null(json))
+ fail("json_load decoded any failed - null");
+ json_decref(json);
+}
+
+static void load_wrong_args()
+{
+ json_t *json;
+ json_error_t error;
+
+ json = json_loads(NULL, 0, &error);
+ if (json)
+ fail("json_loads should return NULL if the first argument is NULL");
+
+ json = json_loadb(NULL, 0, 0, &error);
+ if (json)
+ fail("json_loadb should return NULL if the first argument is NULL");
+
+ json = json_loadf(NULL, 0, &error);
+ if (json)
+ fail("json_loadf should return NULL if the first argument is NULL");
+
+ json = json_load_file(NULL, 0, &error);
+ if (json)
+ fail("json_loadf should return NULL if the first argument is NULL");
+}
+
+static void position()
+{
+ json_t *json;
+ size_t flags = JSON_DISABLE_EOF_CHECK;
+ json_error_t error;
+
+ json = json_loads("{\"foo\": \"bar\"}", 0, &error);
+ if(error.position != 14)
+ fail("json_loads returned a wrong position");
+ json_decref(json);
+
+ json = json_loads("{\"foo\": \"bar\"} baz quux", flags, &error);
+ if(error.position != 14)
+ fail("json_loads returned a wrong position");
+ json_decref(json);
+}
+
+static void run_tests()
+{
+ file_not_found();
+ reject_duplicates();
+ disable_eof_check();
+ decode_any();
+ load_wrong_args();
+ position();
}
--- /dev/null
+/*
+ * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include <jansson.h>
+#include <string.h>
+#include <stdlib.h>
+#include "util.h"
+
+struct my_source {
+ const char *buf;
+ size_t off;
+ size_t cap;
+};
+
+static const char my_str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]";
+
+static size_t greedy_reader(void *buf, size_t buflen, void *arg)
+{
+ struct my_source *s = arg;
+ if (buflen > s->cap - s->off)
+ buflen = s->cap - s->off;
+ if (buflen > 0) {
+ memcpy(buf, s->buf + s->off, buflen);
+ s->off += buflen;
+ return buflen;
+ } else {
+ return 0;
+ }
+}
+
+static void run_tests()
+{
+ struct my_source s;
+ json_t *json;
+ json_error_t error;
+
+ s.off = 0;
+ s.cap = strlen(my_str);
+ s.buf = my_str;
+
+ json = json_load_callback(greedy_reader, &s, 0, &error);
+
+ if (!json)
+ fail("json_load_callback failed on a valid callback");
+ json_decref(json);
+
+ s.off = 0;
+ s.cap = strlen(my_str) - 1;
+ s.buf = my_str;
+
+ json = json_load_callback(greedy_reader, &s, 0, &error);
+ if (json) {
+ json_decref(json);
+ fail("json_load_callback should have failed on an incomplete stream, but it didn't");
+ }
+ if (strcmp(error.source, "<callback>") != 0) {
+ fail("json_load_callback returned an invalid error source");
+ }
+ if (strcmp(error.text, "']' expected near end of file") != 0) {
+ fail("json_load_callback returned an invalid error message for an unclosed top-level array");
+ }
+
+ json = json_load_callback(NULL, NULL, 0, &error);
+ if (json) {
+ json_decref(json);
+ fail("json_load_callback should have failed on NULL load callback, but it didn't");
+ }
+ if (strcmp(error.text, "wrong arguments") != 0) {
+ fail("json_load_callback returned an invalid error message for a NULL load callback");
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include <jansson.h>
+#include <string.h>
+#include "util.h"
+
+static void run_tests()
+{
+ json_t *json;
+ json_error_t error;
+ const char str[] = "[\"A\", {\"B\": \"C\"}, 1, 2, 3]garbage";
+ size_t len = strlen(str) - strlen("garbage");
+
+ json = json_loadb(str, len, 0, &error);
+ if(!json) {
+ fail("json_loadb failed on a valid JSON buffer");
+ }
+ json_decref(json);
+
+ json = json_loadb(str, len - 1, 0, &error);
+ if (json) {
+ json_decref(json);
+ fail("json_loadb should have failed on an incomplete buffer, but it didn't");
+ }
+ if(error.line != 1) {
+ fail("json_loadb returned an invalid line number on fail");
+ }
+ if(strcmp(error.text, "']' expected near end of file") != 0) {
+ fail("json_loadb returned an invalid error message for an unclosed top-level array");
+ }
+}
json_set_alloc_funcs(my_malloc, my_free);
create_and_free_complex_object();
- if(malloc_called != 27 || free_called != 27)
+ if(malloc_called != 20 || free_called != 20)
fail("Custom allocation failed");
}
/* Store the memory area size in the beginning of the block */
void *ptr = malloc(size + 8);
*((size_t *)ptr) = size;
- return ptr + 8;
+ return (char *)ptr + 8;
}
static void secure_free(void *ptr)
{
size_t size;
- ptr -= 8;
+ ptr = (char *)ptr - 8;
size = *((size_t *)ptr);
/*guaranteed_*/memset(ptr, 0, size);
create_and_free_complex_object();
}
-int main()
+static void run_tests()
{
test_simple();
test_secure_funcs();
-
- return 0;
}
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
+#include <math.h>
#include <jansson.h>
#include "util.h"
-int main()
+static void run_tests()
{
json_t *integer, *real;
int i;
json_decref(integer);
json_decref(real);
- return 0;
+#ifdef NAN
+ real = json_real(NAN);
+ if(real != NULL)
+ fail("could construct a real from NaN");
+
+ real = json_real(1.0);
+ if(json_real_set(real, NAN) != -1)
+ fail("could set a real to NaN");
+
+ if(json_real_value(real) != 1.0)
+ fail("real value changed unexpectedly");
+
+ json_decref(real);
+#endif
+
+#ifdef INFINITY
+ real = json_real(INFINITY);
+ if(real != NULL)
+ fail("could construct a real from Inf");
+
+ real = json_real(1.0);
+ if(json_real_set(real, INFINITY) != -1)
+ fail("could set a real to Inf");
+
+ if(json_real_value(real) != 1.0)
+ fail("real value changed unexpectedly");
+
+ json_decref(real);
+#endif
}
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
json_decref(object);
}
+static void test_conditional_updates()
+{
+ json_t *object, *other;
+
+ object = json_pack("{sisi}", "foo", 1, "bar", 2);
+ other = json_pack("{sisi}", "foo", 3, "baz", 4);
+
+ if(json_object_update_existing(object, other))
+ fail("json_object_update_existing failed");
+
+ if(json_object_size(object) != 2)
+ fail("json_object_update_existing added new items");
+
+ if(json_integer_value(json_object_get(object, "foo")) != 3)
+ fail("json_object_update_existing failed to update existing key");
+
+ if(json_integer_value(json_object_get(object, "bar")) != 2)
+ fail("json_object_update_existing updated wrong key");
+
+ json_decref(object);
+
+ object = json_pack("{sisi}", "foo", 1, "bar", 2);
+
+ if(json_object_update_missing(object, other))
+ fail("json_object_update_missing failed");
+
+ if(json_object_size(object) != 3)
+ fail("json_object_update_missing didn't add new items");
+
+ if(json_integer_value(json_object_get(object, "foo")) != 1)
+ fail("json_object_update_missing updated existing key");
+
+ if(json_integer_value(json_object_get(object, "bar")) != 2)
+ fail("json_object_update_missing updated wrong key");
+
+ if(json_integer_value(json_object_get(object, "baz")) != 4)
+ fail("json_object_update_missing didn't add new items");
+
+ json_decref(object);
+ json_decref(other);
+}
+
static void test_circular()
{
json_t *object1, *object2;
json_decref(object);
}
-int main()
+static void test_foreach()
+{
+ const char *key;
+ json_t *object1, *object2, *value;
+
+ object1 = json_pack("{sisisi}", "foo", 1, "bar", 2, "baz", 3);
+ object2 = json_object();
+
+ json_object_foreach(object1, key, value)
+ json_object_set(object2, key, value);
+
+ if(!json_equal(object1, object2))
+ fail("json_object_foreach failed to iterate all key-value pairs");
+
+ json_decref(object1);
+ json_decref(object2);
+}
+
+static void run_tests()
{
test_misc();
test_clear();
test_update();
+ test_conditional_updates();
test_circular();
test_set_nocheck();
test_iterators();
test_preserve_order();
-
- return 0;
+ test_foreach();
}
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
- * Copyright (c) 2010-2011 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2010-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
#include <stdio.h>
#include "util.h"
-int main()
+static void run_tests()
{
json_t *value;
int i;
value = json_pack("b", 1);
if(!json_is_true(value))
fail("json_pack boolean failed");
- if(value->refcount != (ssize_t)-1)
+ if(value->refcount != (size_t)-1)
fail("json_pack boolean refcount failed");
json_decref(value);
value = json_pack("b", 0);
if(!json_is_false(value))
fail("json_pack boolean failed");
- if(value->refcount != (ssize_t)-1)
+ if(value->refcount != (size_t)-1)
fail("json_pack boolean refcount failed");
json_decref(value);
value = json_pack("n");
if(!json_is_null(value))
fail("json_pack null failed");
- if(value->refcount != (ssize_t)-1)
+ if(value->refcount != (size_t)-1)
fail("json_pack null refcount failed");
json_decref(value);
value = json_pack("i", 1);
if(!json_is_integer(value) || json_integer_value(value) != 1)
fail("json_pack integer failed");
- if(value->refcount != (ssize_t)1)
+ if(value->refcount != (size_t)1)
fail("json_pack integer refcount failed");
json_decref(value);
value = json_pack("I", (json_int_t)555555);
if(!json_is_integer(value) || json_integer_value(value) != 555555)
fail("json_pack json_int_t failed");
- if(value->refcount != (ssize_t)1)
+ if(value->refcount != (size_t)1)
fail("json_pack integer refcount failed");
json_decref(value);
value = json_pack("f", 1.0);
if(!json_is_real(value) || json_real_value(value) != 1.0)
fail("json_pack real failed");
- if(value->refcount != (ssize_t)1)
+ if(value->refcount != (size_t)1)
fail("json_pack real refcount failed");
json_decref(value);
value = json_pack("s", "test");
if(!json_is_string(value) || strcmp("test", json_string_value(value)))
fail("json_pack string failed");
- if(value->refcount != (ssize_t)1)
+ if(value->refcount != (size_t)1)
fail("json_pack string refcount failed");
json_decref(value);
value = json_pack("{}", 1.0);
if(!json_is_object(value) || json_object_size(value) != 0)
fail("json_pack empty object failed");
- if(value->refcount != (ssize_t)1)
+ if(value->refcount != (size_t)1)
fail("json_pack empty object refcount failed");
json_decref(value);
value = json_pack("[]", 1.0);
if(!json_is_array(value) || json_array_size(value) != 0)
fail("json_pack empty list failed");
- if(value->refcount != (ssize_t)1)
+ if(value->refcount != (size_t)1)
fail("json_pack empty list failed");
json_decref(value);
value = json_pack("o", json_integer(1));
if(!json_is_integer(value) || json_integer_value(value) != 1)
fail("json_pack object failed");
- if(value->refcount != (ssize_t)1)
+ if(value->refcount != (size_t)1)
fail("json_pack integer refcount failed");
json_decref(value);
value = json_pack("O", json_integer(1));
if(!json_is_integer(value) || json_integer_value(value) != 1)
fail("json_pack object failed");
- if(value->refcount != (ssize_t)2)
+ if(value->refcount != (size_t)2)
fail("json_pack integer refcount failed");
json_decref(value);
json_decref(value);
fail("json_pack array failed");
if(!json_is_array(json_object_get(value, "foo")))
fail("json_pack array failed");
- if(json_object_get(value, "foo")->refcount != (ssize_t)1)
+ if(json_object_get(value, "foo")->refcount != (size_t)1)
fail("json_pack object refcount failed");
json_decref(value);
if(json_pack_ex(&error, 0, "{s:s}", "foo", "\xff\xff"))
fail("json_pack failed to catch invalid UTF-8 in a string");
check_error("Invalid UTF-8 string", "<args>", 1, 4, 4);
-
- return 0;
}
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
#include "util.h"
/* Call the simple functions not covered by other tests of the public API */
-int main()
+static void run_tests()
{
json_t *value;
+ value = json_boolean(1);
+ if(!json_is_true(value))
+ fail("json_boolean(1) failed");
+ json_decref(value);
+
+ value = json_boolean(-123);
+ if(!json_is_true(value))
+ fail("json_boolean(-123) failed");
+ json_decref(value);
+
+ value = json_boolean(0);
+ if(!json_is_false(value))
+ fail("json_boolean(0) failed");
+ json_decref(value);
+
+
value = json_integer(1);
if(json_typeof(value) != JSON_INTEGER)
fail("json_typeof failed");
json_incref(value);
if(value->refcount != (size_t)-1)
fail("refcounting null works incorrectly");
-
- return 0;
}
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
- * Copyright (c) 2010-2011 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2010-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
#include <stdio.h>
#include "util.h"
-int main()
+static void run_tests()
{
json_t *j, *j2;
int i1, i2, i3;
fail("json_unpack simple array failed");
json_decref(j);
+ /* object with many items & strict checking */
+ j = json_pack("{s:i, s:i, s:i}", "a", 1, "b", 2, "c", 3);
+ rv = json_unpack(j, "{s:i, s:i, s:i}", "a", &i1, "b", &i2, "c", &i3);
+ if(rv || i1 != 1 || i2 != 2 || i3 != 3)
+ fail("json_unpack object with many items failed");
+ json_decref(j);
+
/*
* Invalid cases
*/
/* Unpack the same item twice */
j = json_pack("{s:s, s:i}", "foo", "bar", "baz", 42);
if(!json_unpack_ex(j, &error, 0, "{s:s,s:s!}", "foo", &s, "foo", &s))
- fail("json_unpack object with strict validation failed");
+ fail("json_unpack object with strict validation failed");
check_error("1 object item(s) left unpacked", "<validation>", 1, 10, 10);
json_decref(j);
check_error("1 array item(s) left unpacked", "<validation>", 1, 5, 5);
json_decref(j);
- return 0;
+ /* Optional values */
+ j = json_object();
+ i1 = 0;
+ if(json_unpack(j, "{s?i}", "foo", &i1))
+ fail("json_unpack failed for optional key");
+ if(i1 != 0)
+ fail("json_unpack unpacked an optional key");
+ json_decref(j);
+
+ i1 = 0;
+ j = json_pack("{si}", "foo", 42);
+ if(json_unpack(j, "{s?i}", "foo", &i1))
+ fail("json_unpack failed for an optional value");
+ if(i1 != 42)
+ fail("json_unpack failed to unpack an optional value");
+ json_decref(j);
+
+ j = json_object();
+ i1 = i2 = i3 = 0;
+ if(json_unpack(j, "{s?[ii]s?{s{si}}}",
+ "foo", &i1, &i2,
+ "bar", "baz", "quux", &i3))
+ fail("json_unpack failed for complex optional values");
+ if(i1 != 0 || i2 != 0 || i3 != 0)
+ fail("json_unpack unexpectedly unpacked something");
+ json_decref(j);
+
+ j = json_pack("{s{si}}", "foo", "bar", 42);
+ if(json_unpack(j, "{s?{s?i}}", "foo", "bar", &i1))
+ fail("json_unpack failed for complex optional values");
+ if(i1 != 42)
+ fail("json_unpack failed to unpack");
+ json_decref(j);
}
/*
- * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
#ifndef UTIL_H
#define UTIL_H
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <stdio.h>
#include <stdlib.h>
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
#include <jansson.h>
#define failhdr fprintf(stderr, "%s:%s:%d: ", __FILE__, __FUNCTION__, __LINE__)
} \
} while(0)
+
+static void run_tests();
+
+int main() {
+#ifdef HAVE_SETLOCALE
+ setlocale(LC_ALL, "");
+#endif
+ run_tests();
+ return 0;
+}
+
#endif
-export JSON_COMPACT=1
+JSON_COMPACT=1
+export JSON_COMPACT
-export JSON_COMPACT=1
+JSON_COMPACT=1
+export JSON_COMPACT
-export JSON_ENSURE_ASCII=1
+JSON_ENSURE_ASCII=1
+export JSON_ENSURE_ASCII
-export JSON_INDENT=4
+JSON_INDENT=4
+export JSON_INDENT
-export JSON_INDENT=4
-export JSON_COMPACT=1
+JSON_INDENT=4
+JSON_COMPACT=1
+export JSON_INDENT JSON_COMPACT
-export JSON_INDENT=4
-export JSON_COMPACT=1
+JSON_INDENT=4
+JSON_COMPACT=1
+export JSON_INDENT JSON_COMPACT
-export JSON_INDENT=4
+JSON_INDENT=4
+export JSON_INDENT
-export JSON_PRESERVE_ORDER=1
+JSON_PRESERVE_ORDER=1
+export JSON_PRESERVE_ORDER
#!/bin/sh
#
-# Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+# Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
-export JSON_SORT_KEYS=1
+JSON_SORT_KEYS=1
+export JSON_SORT_KEYS
#!/bin/sh
#
-# Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+# Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
#!/bin/sh
#
-# Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+# Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
-[1e+22]
\ No newline at end of file
+[1e22]
\ No newline at end of file
-[1.2299999999999999e+47]
\ No newline at end of file
+[1.2299999999999999e47]
\ No newline at end of file
-[1.23456e+80]
\ No newline at end of file
+[1.23456e80]
\ No newline at end of file
#!/bin/sh
#
-# Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
+# Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
-export JSON_SORT_KEYS=1
+JSON_SORT_KEYS=1
+export JSON_SORT_KEYS
is_test() {
test -d $test_path
/*
- * Copyright (c) 2010-2011 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2010-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
#ifdef __cplusplus
#define JSON_INLINE inline
#else
-#define JSON_INLINE
+#define JSON_INLINE __inline
#endif
-/* If your compiler supports the `long long` type,
- JSON_INTEGER_IS_LONG_LONG is defined to 1, otherwise to 0. */
+/* 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
--- /dev/null
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual C++ Express 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jansson", "jansson.vcxproj", "{76226D20-1972-4789-A595-EDACC7A76DC3}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {76226D20-1972-4789-A595-EDACC7A76DC3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {76226D20-1972-4789-A595-EDACC7A76DC3}.Debug|Win32.Build.0 = Debug|Win32
+ {76226D20-1972-4789-A595-EDACC7A76DC3}.Release|Win32.ActiveCfg = Release|Win32
+ {76226D20-1972-4789-A595-EDACC7A76DC3}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\src\dump.c" />
+ <ClCompile Include="..\..\src\error.c" />
+ <ClCompile Include="..\..\src\hashtable.c" />
+ <ClCompile Include="..\..\src\load.c" />
+ <ClCompile Include="..\..\src\memory.c" />
+ <ClCompile Include="..\..\src\pack_unpack.c" />
+ <ClCompile Include="..\..\src\strbuffer.c" />
+ <ClCompile Include="..\..\src\strconv.c" />
+ <ClCompile Include="..\..\src\utf.c" />
+ <ClCompile Include="..\..\src\value.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\src\hashtable.h" />
+ <ClInclude Include="..\..\src\jansson.h" />
+ <ClInclude Include="..\..\src\jansson_private.h" />
+ <ClInclude Include="..\..\src\strbuffer.h" />
+ <ClInclude Include="..\..\src\utf.h" />
+ <ClInclude Include="..\jansson_config.h" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{76226D20-1972-4789-A595-EDACC7A76DC3}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>jansson_dll</RootNamespace>
+ <ProjectName>jansson</ProjectName>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>Output\$(Configuration)\</OutDir>
+ <IntDir>Build\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>Output\$(Configuration)\</OutDir>
+ <IntDir>Build\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;JANSSON_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>4996</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ModuleDefinitionFile>../../src/jansson.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;JANSSON_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>4996</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <ModuleDefinitionFile>../../src/jansson.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\src\dump.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\error.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\hashtable.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\load.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\memory.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\pack_unpack.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\strbuffer.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\strconv.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\utf.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\value.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\src\hashtable.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\jansson.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\jansson_private.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\strbuffer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\utf.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\jansson_config.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project>
\ No newline at end of file