API Reference
The cjsonx API is designed to be minimalistic, safe, and intuitive. It uses opaque 16-byte handles (cjsonx_val_t) to interact with the underlying DOM arena, ensuring type safety and preventing use-after-free errors.
Core Types
cjsonx_doc_t
The main document container. It holds the flat DOM arena, the structural tape, and the original JSON string.
typedef struct {
bool is_valid; // True if parsing succeeded
cjsonx_error_t error; // Error code if parsing failed
size_t error_offset; // Byte offset of the syntax error
cjsonx_val_t root; // The root value handle
// ... internal fields ...
} cjsonx_doc_t;
cjsonx_val_t
A lightweight 16-byte handle representing a JSON node (Object, Array, String, Number, Boolean, or Null). Passed by value.
typedef struct {
const cjsonx_doc_t* doc;
uint32_t node_idx;
} cjsonx_val_t;
cjsonx_type_t
Enumeration of possible JSON types.
typedef enum {
CJSONX_NULL = 0,
CJSONX_BOOL,
CJSONX_NUMBER,
CJSONX_STRING,
CJSONX_ARRAY,
CJSONX_OBJECT
} cjsonx_type_t;
Parsing & Memory Management
cjsonx_parse
cjsonx_doc_t* cjsonx_parse(const char* json, size_t length);
Parses a JSON string.
json: The UTF-8 JSON payload. Does not need to be null-terminated.length: The byte length of the payload.- Returns: A dynamically allocated document. Returns
NULLifmallocfails internally. You must checkdoc->is_validto ensure syntax correctness.
cjsonx_parse_with_buffer (Zero-Allocation Mode)
cjsonx_doc_t* cjsonx_parse_with_buffer(const char* json, size_t length, void* buffer, size_t buffer_size);
Parses a JSON string using entirely user-provided memory. This avoids malloc entirely, making it perfect for embedded systems or RTOS environments.
buffer: A static byte array or memory pool.buffer_size: The size of the buffer. If parsing exhausts this size, the parser fails withCJSONX_ERROR_OOM.
cjsonx_doc_free
void cjsonx_doc_free(cjsonx_doc_t* doc);
Frees the entire document and its internal arenas. Any cjsonx_val_t handles associated with this document become invalid.
DOM Access
cjsonx_get_type
cjsonx_type_t cjsonx_get_type(cjsonx_val_t val);
Returns the type of the value. If the handle is invalid or null, returns CJSONX_NULL.
cjsonx_get
cjsonx_val_t cjsonx_get(cjsonx_val_t obj, const char* key);
Retrieves a child value from a JSON Object by its string key.
- Returns a null handle if the key is not found, or if
objis not an Object.
cjsonx_get_index
cjsonx_val_t cjsonx_get_index(cjsonx_val_t arr, size_t index);
Retrieves a child value from a JSON Array by its zero-based index.
- Returns a null handle if the index is out of bounds, or if
arris not an Array.
Value Retrieval
cjsonx_str
const char* cjsonx_str(cjsonx_val_t val);
Retrieves the string pointer.
Warning: cjsonx is a zero-copy parser. The returned string points directly into the original JSON payload and is not null-terminated. You must use cjsonx_str_len to read it safely.
cjsonx_str_len
size_t cjsonx_str_len(cjsonx_val_t val);
Returns the exact byte length of the string.
cjsonx_num
double cjsonx_num(cjsonx_val_t val);
Retrieves the 64-bit double precision representation of a JSON number.
cjsonx_int
int64_t cjsonx_int(cjsonx_val_t val);
Retrieves the numerical value as a strict 64-bit integer. Useful for parsing large IDs.
cjsonx_bool
bool cjsonx_bool(cjsonx_val_t val);
Returns true or false for boolean nodes.
cjsonx_size
size_t cjsonx_size(cjsonx_val_t val);
Returns the number of elements inside an Array or the number of key-value pairs inside an Object.
cjsonx_is_null
bool cjsonx_is_null(cjsonx_val_t val);
Returns true if the value is explicitly a JSON null, or if the handle itself is invalid/empty.
Iteration
cjsonx_iter_t
A lightweight iterator struct for walking through Arrays and Objects.
typedef struct {
cjsonx_val_t key; // Populated if iterating an Object
cjsonx_val_t value; // The child value (Array element or Object value)
bool is_object;
bool valid;
// ... internal fields ...
} cjsonx_iter_t;
cjsonx_iter_init & cjsonx_iter_next
cjsonx_iter_t cjsonx_iter_init(cjsonx_val_t val);
bool cjsonx_iter_next(cjsonx_iter_t* iter);
Creates an iterator for an Array or Object and advances it.
Example: Iterating an Array
cjsonx_iter_t it = cjsonx_iter_init(my_array);
while (cjsonx_iter_next(&it)) {
double n = cjsonx_num(it.value);
}
Example: Iterating an Object
cjsonx_iter_t it = cjsonx_iter_init(my_object);
while (cjsonx_iter_next(&it)) {
printf("Key: %s\n", cjsonx_str(it.key));
}
Error Handling
cjsonx_error_string
const char* cjsonx_error_string(cjsonx_error_t err);
Converts a cjsonx_error_t enum into a human-readable string (e.g., "Invalid structural character", "Unterminated string").
Builder API & Stringification
cjsonx allows you to create and mutate JSON documents dynamically, and convert them back into JSON strings.
Creating Values
| Function | Signature | Description |
|---|---|---|
cjsonx_create_null |
cjsonx_val_t cjsonx_create_null(cjsonx_doc_t* doc) |
Creates a null node in the document. |
cjsonx_create_bool |
cjsonx_val_t cjsonx_create_bool(cjsonx_doc_t* doc, bool val) |
Creates a boolean node. |
cjsonx_create_number |
cjsonx_val_t cjsonx_create_number(cjsonx_doc_t* doc, double val) |
Creates a number node. |
cjsonx_create_string |
cjsonx_val_t cjsonx_create_string(cjsonx_doc_t* doc, const char* str) |
Creates a string node. The string is copied into the document arena. |
cjsonx_create_object |
cjsonx_val_t cjsonx_create_object(cjsonx_doc_t* doc) |
Creates an empty JSON Object. |
cjsonx_create_array |
cjsonx_val_t cjsonx_create_array(cjsonx_doc_t* doc) |
Creates an empty JSON Array. |
Mutating Structures
| Function | Signature | Description |
|---|---|---|
cjsonx_object_set |
bool cjsonx_object_set(cjsonx_val_t obj, const char* key, cjsonx_val_t val) |
Inserts or appends a key-value pair into an Object. |
cjsonx_array_push |
bool cjsonx_array_push(cjsonx_val_t arr, cjsonx_val_t val) |
Appends a value to the end of an Array. |
cjsonx_object_remove |
bool cjsonx_object_remove(cjsonx_val_t obj, const char* key) |
Removes a key-value pair from an Object. |
cjsonx_array_remove |
bool cjsonx_array_remove(cjsonx_val_t arr, size_t index) |
Removes a value at the given index from an Array. |
Stringification
| Function | Signature | Description |
|---|---|---|
cjsonx_stringify |
char* cjsonx_stringify(cjsonx_doc_t* doc) |
Converts the entire document into a minified, null-terminated JSON string. The returned string is malloc'd and must be freed by the caller. |
cjsonx_stringify_format |
char* cjsonx_stringify_format(cjsonx_doc_t* doc, int indent) |
Same as stringify, but pretty-prints the JSON with indent spaces per level. |
JSON Pointer (RFC 6901)
You can query deeply nested JSON structures using a single path string.
| Function | Signature | Description |
|---|---|---|
cjsonx_pointer_get |
cjsonx_val_t cjsonx_pointer_get(cjsonx_val_t root, const char* path) |
Retrieves a node using a JSON Pointer path (e.g. "/user/profile/age"). Returns a null handle if the path is invalid or not found. Properly unescapes ~1 to / and ~0 to ~. |
Custom Allocator Injection
For strict memory environments (e.g., game engines, custom OS kernels), you can override the standard <stdlib.h> allocation functions using cjsonx_parse_ex.
cjsonx_allocator_t
typedef struct {
void* (*malloc_fn)(size_t size, void* user_data);
void* (*realloc_fn)(void* ptr, size_t size, void* user_data);
void (*free_fn)(void* ptr, void* user_data);
void* user_data;
} cjsonx_allocator_t;
| Function | Signature | Description |
|---|---|---|
cjsonx_parse_ex |
cjsonx_doc_t* cjsonx_parse_ex(const char* json, size_t len, cjsonx_allocator_t* alloc) |
Parses the JSON document using the provided allocator functions. If alloc is NULL, it falls back to standard malloc and free. |
Cloning and Patching
cjsonx_clone_val
cjsonx_val_t cjsonx_clone_val(cjsonx_doc_t* dest_doc, cjsonx_val_t src_val);
Recursively clones a value node and all of its children into the destination document's arena. Returns the cloned node handle.
cjsonx_merge_patch
cjsonx_val_t cjsonx_merge_patch(cjsonx_val_t target, cjsonx_val_t patch);
Applies a JSON Merge Patch (RFC 7396) to a target node. Returns the modified node handle.
File I/O Utilities
cjsonx_read_file & cjsonx_read_file_ex
cjsonx_doc_t* cjsonx_read_file(const char* path);
cjsonx_doc_t* cjsonx_read_file_ex(const char* path, cjsonx_allocator_t* alloc);
Reads the JSON file from the filesystem path and parses it. Returns the parsed document handle, or NULL if opening/reading fails.
cjsonx_write_file & cjsonx_write_file_format
bool cjsonx_write_file(const char* path, cjsonx_doc_t* doc);
bool cjsonx_write_file_format(const char* path, cjsonx_doc_t* doc, int indent);
Serializes the document into a JSON file at the specified path. Returns true on success, or false on file writing failure.
Limits & Warnings
- 16MB Node Size Limit: The 16-byte DOM node packs its type and length field into a single
uint32_t(8 bits for type, 24 bits for length). This limits the maximum length of any single string or serialized container to16,777,215bytes. - O(N) Array Push Complexity: Pushing an element to an array via
cjsonx_array_pushtraverses the list of siblings to find the end. Building large arrays sequentially through push operations results in O(N^2) complexity. - Stringify Depth Guard: To prevent stack overflows on deeply nested JSON inputs during serialization,
cjsonx_stringifyandcjsonx_stringify_formatenforce a nesting depth limit of 512 (CJSONX_MAX_DEPTH).