JSON(3) Library Functions Manual JSON(3)

JsonA fully-featured JSON API.

#include <Json.h>

JsonValueType(JsonValue *);

JsonValue *
JsonValueObject(HashMap *);

HashMap *
JsonValueAsObject(JsonValue *);

JsonValue *
JsonValueArray(Array *);

Array *

JsonValue *
JsonValueString(char *);

char *
JsonValueAsString(JsonValue *);

JsonValue *

JsonValueAsInteger(JsonValue *);

JsonValue *

JsonValueAsFloat(JsonValue *);

JsonValue *

JsonValueAsBoolean(JsonValue *);

JsonValue *

JsonValueFree(JsonValue *);

JsonFree(HashMap *);

JsonEncodeString(const char *, FILE *);

JsonEncodeValue(JsonValue *, FILE *);

JsonEncode(HashMap *, FILE *);

HashMap *
JsonDecode(FILE *);

JsonValue *
JsonGet(HashMap *, size_t, ...);

JsonValue *
JsonSet(HashMap *, size_t, ...);

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 ().

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.

() determines the type of a given JsonValue.

The () functions wrap their input in a JsonValue that represents the given value. The () 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.

() 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.

() 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 () (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.

() recursively frees a JSON object, iterating over all the values and freeing them using JsonValueFree().

() encodes the given string in such a way that it can be embedded in a JSON stream. This entails:

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 ().

() 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.

() 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. () does the opposite; it reads from a JSON stream and decodes it into a hash map of JsonValues.

() and () 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.

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.

HashMap(3), Array(3)

March 6, 2023 Telodendria Project