.Dd $Mdocdate: March 12 2023 $ .Dt JSON 3 .Os Telodendria Project .Sh NAME .Nm Json .Nd A fully-featured JSON API. .Sh SYNOPSIS .In Json.h .Ft JsonType .Fn JsonValueType "JsonValue *" .Ft JsonValue * .Fn JsonValueObject "HashMap *" .Ft HashMap * .Fn JsonValueAsObject "JsonValue *" .Ft JsonValue * .Fn JsonValueArray "Array *" .Ft Array * .Fn JsonValueAsArray " .Ft JsonValue * .Fn JsonValueString "char *" .Ft char * .Fn JsonValueAsString "JsonValue *" .Ft JsonValue * .Fn JsonValueInteger "long" .Ft long .Fn JsonValueAsInteger "JsonValue *" .Ft JsonValue * .Fn JsonValueFloat "double" .Ft double .Fn JsonValueAsFloat "JsonValue *" .Ft JsonValue * .Fn JsonValueBoolean "int" .Ft int .Fn JsonValueAsBoolean "JsonValue *" .Ft JsonValue * .Fn JsonValueNull "void" .Ft void .Fn JsonValueFree "JsonValue *" .Ft void .Fn JsonFree "HashMap *" .Ft void .Fn JsonEncodeString "const char *" "FILE *" .Ft void .Fn JsonEncodeValue "JsonValue *" "FILE *" "int" .Ft int .Fn JsonEncode "HashMap *" "FILE *" "int" .Ft HashMap * .Fn JsonDecode "FILE *" .Ft JsonValue * .Fn JsonGet "HashMap *" "size_t" "..." .Ft JsonValue * .Fn JsonSet "HashMap *" "size_t" "..." .Sh DESCRIPTION .Nm is a fully-featured JSON API for C using .Xr Array 3 and .Xr 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. .Nm also provides a structure for encapsulating an arbitrary value and identifying its type, making it easy for a program to work with JSON data. .Nm 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. .Pp 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 .Xr fmemopen 3 and .Xr 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. .Pp The .Nm header defines the following enumeration for identifying types of values: .Bd -literal -offset indent 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; .Ed .Pp 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 .Fn JsonFree . .Pp 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. .Pp .Fn JsonValueType determines the type of a given JsonValue. .Pp The .Fn JsonValue* functions wrap their input in a JsonValue that represents the given value. The .Fn 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. .Pp .Fn JsonValueNull is a special case that represents a JSON null. Because .Xr Array 3 and .Xr 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. .Pp .Fn 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 .Fn Free (documented in .Xr 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 .Fn 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. .Pp .Fn JsonFree recursively frees a JSON object, iterating over all the values and freeing them using .Fn JsonValueFree . .Pp .Fn JsonEncodeString encodes the given string in such a way that it can be embedded in a JSON stream. This entails: .Bl -bullet -offset indent .It Escaping quotes, backslashes, and other special characters using their backslash escape. .It Encoding bytes that are not UTF-8 using escapes. .It Wrapping the entire string in double quotes. .El .Pp This function is provided via the public .Nm API so that it is accessible to custom JSON encoders, such as .Xr CanonicalJson 3 . This will typically be used for encoding JSON keys; for encoding values, just use .Fn JsonEncodeValue . .Pp .Fn 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 .Nm API so that it is accessible to custom JSON encoders. Normal users that are not writing custom encoders should in most cases just use .Fn JsonEncode to encode an entire object. The third parameter is an integer that represents the indent level of the value to be printed, or a negative number if pretty-printing should be disabled, and JSON should be printed as minimized as possible. If you want to pretty-print a JSON object, set this to .Va JSON_PRETTY . To get the minified output, set it to .Va JSON_DEFAULT . .Pp .Fn 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. The third integer parameter has the same behavior asa described above. .Pp .Fn JsonDecode does the opposite of .Fn JsonEncode ; it reads from a JSON stream and decodes it into a hash map of JsonValues. .Pp .Fn JsonSet and .Fn 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. .Fn JsonSet will create any intermediate objects as necessary to set the proper key. .Sh RETURN VALUES .Pp .Fn 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. .Pp The .Fn JsonValue* functions return a JsonValue that holds a pointer to the passed value, or NULL if there was an error allocating memory. The .Fn 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. .Pp .Fn 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. .Pp .Fn JsonDecode returns a hash map of JsonValues that can be manipulated by this API, or NULL if there was an error parsing the JSON. .Pp .Fn JsonGet returns a JsonValue, or NULL if the requested key is not set in the object. .Fn JsonGet returns the previous value of the provided key, or NULL if there was no previous value. .Sh SEE ALSO .Xr HashMap 3 , .Xr Array 3