telodendria/man/man3/Json.3

264 lines
8.5 KiB
Groff

.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