NAME
Json
—
A fully-featured JSON API.
SYNOPSIS
#include
<Json.h>
JsonType
JsonValueType
(JsonValue
*);
JsonValue *
JsonValueObject
(HashMap
*);
HashMap *
JsonValueAsObject
(JsonValue
*);
JsonValue *
JsonValueArray
(Array
*);
Array *
JsonValueAsArray
();
JsonValue *
JsonValueString
(char
*);
char *
JsonValueAsString
(JsonValue
*);
JsonValue *
JsonValueInteger
(long);
long
JsonValueAsInteger
(JsonValue
*);
JsonValue *
JsonValueFloat
(double);
double
JsonValueAsFloat
(JsonValue
*);
JsonValue *
JsonValueBoolean
(int);
int
JsonValueAsBoolean
(JsonValue
*);
JsonValue *
JsonValueNull
(void);
void
JsonValueFree
(JsonValue
*);
void
JsonFree
(HashMap
*);
void
JsonEncodeString
(const
char *, FILE
*);
void
JsonEncodeValue
(JsonValue
*, FILE *);
int
JsonEncode
(HashMap
*, FILE *);
HashMap *
JsonDecode
(FILE
*);
JsonValue *
JsonGet
(HashMap
*, size_t,
...);
JsonValue *
JsonSet
(HashMap
*, size_t,
...);
DESCRIPTION
Json
is a fully-featured JSON API for C
using Array(3) and
HashMap(3) that can parse JSON, and serialize an in-memory structure
to JSON. It builds on the foundation set up by those APIs because that's all
JSON really is, just maps and arrays. Json
also
provides a structure for encapsulating an arbitrary value and identifying
its type, making it easy for a program to work with JSON data.
Json
is very strict and tries to adhere as closely
as possible to the proper defintion of JSON. It will fail on syntax errors
of any kind, which is fine for a Matrix homeserver because we can just
return M_BAD_JSON if anything here fails, but it may not be suitable for
other purposes.
This JSON implementation focuses primarily on serialization and deserialization to and from streams. It does not provide facilities for handling JSON strings; it only writes JSON to output streams, and reads them from input streams. If course, you can use the POSIX fmemopen(3) and open_memstream(3) if you want to deal with JSON strings, but JSON is intended to be an exchange format. Data should be converted to JSON right before it is leaving the program, and converted from JSON as soon as it is coming in.
The Json
header defines the following
enumeration for identifying types of values:
typedef enum JsonType { JSON_NULL, /* Maps to C NULL */ JSON_OBJECT, /* Maps to a HashMap of JsonValues */ JSON_ARRAY, /* Maps to an Array of JsonValues */ JSON_STRING, /* Maps to a NULL-terminated C string */ JSON_INTEGER, /* Maps to a C long */ JSON_FLOAT, /* Maps to a C double */ JSON_BOOLEAN /* Maps to a C boolean, 1 or 0 */ } JsonType;
A JsonValue encapsulates all the possible types that
can be stored in JSON. It is an opaque structure that can be managed
entirely by the functions defined in this API. It is important to note that
in the case of objects, arrays, and strings, this structure only stores
pointers to the allocated data, it doesn't store the data itself, but the
data IS freed when using
JsonFree
().
Objects are represented as hash maps consisting entirely of JsonValue structures, and arrays are represented as arrays consisting entirely of JsonValue structures. When generating a JSON object, any attempt to stuff a value into a hash map or array without encoding it as a JsonValue first will result in undefined behavior.
JsonValueType
()
determines the type of a given JsonValue.
The
JsonValue*
()
functions wrap their input in a JsonValue that represents the given value.
The
JsonValueAs*
()
functions do the opposite; they unwrap a JsonValue and return the actual
usable value itself. They all closely resemble each other and they all
behave the same way, so to save on time and effort, they're not explicitly
documented individually. If something is unclear about how these functions
work, consult the source code, and feel free to write the documentation
yourself for clarification. Otherwise, reach out to the official Matrix
rooms, and someone should be able to help you.
JsonValueNull
()
is a special case that represents a JSON null. Because
Array(3) and
HashMap(3) do not accept NULL values, this function should be used to
represent NULL in JSON. Even though a small amount of memory is allocated
just to point to NULL, this keeps the APIs clean.
JsonValueFree
()
frees the memory being used by a JSON value. Note that this will recursively
free all Arrays, HashMaps, and other JsonValues that are reachable from the
given value. It also invokes
Free
()
(documented in Memory) on
all strings, so make sure passed string pointers point to strings on the
heap, not the stack. This will be the case for all strings returned by
JsonDecode
(), but if you are manually creating JSON
objects and stitching them together, you should be aware that calling this
function on a value that contains a pointer to a stack string will result in
undefined behavior.
JsonFree
()
recursively frees a JSON object, iterating over all the values and freeing
them using JsonValueFree
().
JsonEncodeString
()
encodes the given string in such a way that it can be embedded in a JSON
stream. This entails:
- Escaping quotes, backslashes, and other special characters using their backslash escape.
- Encoding bytes that are not UTF-8 using escapes.
- Wrapping the entire string in double quotes.
This function is provided via the public
Json
API so that it is accessible to custom JSON
encoders, such as
CanonicalJson(3). This will typically be used for encoding
JSON keys; for encoding values, just use
JsonEncodeValue
().
JsonEncodeValue
()
serializes a JsonValue as it would appear in JSON output. This is a
recursive function that also encodes all child values reachable from the
given value. This function is exposed via the public
Json
API so that it is accessible to custom JSON
encoders. Normal users that are not writing custom encoders should in most
cases just use JsonEncode
() to encode an entire
object.
JsonEncode
()
encodes a JSON object as minimized JSON and writes it to the given output
stream. This function is recursive; it will serialize everything accessible
from the passed object.
JsonDecode
()
does the opposite; it reads from a JSON stream and decodes it into a hash
map of JsonValues.
JsonSet
()
and
JsonGet
()
are convenience functions that allow the caller to retrieve and manipulate
arbitrarily deep keys within a JSON object. They take a root JSON object,
the number of levels deep to go, and then that number of keys as a varargs
list. All keys must have objects as values, with the exception of the last
one, which is the one being retrieved or set.
JsonSet
() will create any intermediate objects as
necessary to set the proper key.
RETURN VALUES
JsonValueType
() returns a JsonType,
documented above, that tells what the given value actually is, or JSON_NULL
if the passed value is NULL. Note that even a fully valid JsonValue may
actually be of type JSON_NULL, so this function should not be used to
determine whether or not a given value is valid.
The JsonValue*
() functions return a
JsonValue that holds a pointer to the passed value, or NULL if there was an
error allocating memory. The JsonValueAs*
()
functions return the actual value represented by the given JsonValue so that
it can be manipulated by the program, or NULL if no value was provided, or
the value is not of the correct type expected by the function.
JsonEncode
() returns whether or not the
encoding operation was successful. This function will fail if any passed
parameters are NULL, otherwise it will assume all pointers are valid and
return a success value.
JsonDecode
() returns a hash map of
JsonValues that can be manipulated by this API, or NULL if there was an
error parsing the JSON.
JsonGet
() returns a JsonValue, or NULL if
the requested key is not set in the object.
JsonGet
() returns the previous value of the provided
key, or NULL if there was no previous value.