Skip to content

Latest commit

 

History

History
346 lines (230 loc) · 10.2 KB

File metadata and controls

346 lines (230 loc) · 10.2 KB

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 NULL if malloc fails internally. You must check doc->is_valid to 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 with CJSONX_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 obj is 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 arr is 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 to 16,777,215 bytes.
  • O(N) Array Push Complexity: Pushing an element to an array via cjsonx_array_push traverses 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_stringify and cjsonx_stringify_format enforce a nesting depth limit of 512 (CJSONX_MAX_DEPTH).