cerialize is a lightweight, single-header JSON deserializer written in C. It provides a simple API for parsing JSON strings into C data structures, with robust error handling and support for core JSON types.

Features

  • Single-header library — just include cerialize.h in your project
  • Supports core JSON types — Object, String, Number, Boolean, Null, List (Array)
  • Strict error handling — detailed error messages for invalid input
  • Test suite included — comprehensive tests for all supported types

Getting Started

Copy include/cerialize/cerialize.h into your project, or reference it directly:

#include "cerialize/cerialize.h"

Usage Example

const char* json_str = "{\"key\": \"value\", \"num\": 42, \"flag\": true, \"missing\": null}";
json result = deserialize_json(json_str, strlen(json_str));
if (result.failure) {
    printf("Parse error: %s\n", result.error_text);
    json_free(&result);  // Clean up even on failure
    return 1;
} else {
    // Access result.root (json_object)
    // See Data Types section below
}

// Always free memory when done
json_free(&result);

Data Types

Main Types

  • json_type: Enum for type discrimination — JSON_OBJECT, JSON_STRING, JSON_NUMBER, JSON_BOOL, JSON_NULL, JSON_LIST
  • json_value: Union holding the actual value
    • string: char*
    • number: float
    • boolean: bool_t (char, TRUE/FALSE)
    • is_null: bool_t
    • nodes: Array of json_node (for objects and lists)
    • node_count: Number of nodes (for objects and lists)
  • json_node: Represents a key-value pair in an object, or an element in a list
    • For objects: key is set, value is the value
    • For lists: key is NULL, value is the element value
  • json_object: Main parsed value with type and value fields
  • json: Top-level result with root, error_text, and failure fields

Traversing an Object

if (result.root.type == JSON_OBJECT) {
    for (cereal_size_t i = 0; i < result.root.value.node_count; ++i) {
        json_node node = result.root.value.nodes[i];
        printf("Key: %s\n", node.key);
        // Check node.value type and access accordingly
    }
}

Traversing a List

if (result.root.type == JSON_LIST) {
    for (cereal_size_t i = 0; i < result.root.value.node_count; ++i) {
        json_node node = result.root.value.nodes[i];
        // node.key will be NULL
        // node.value holds the element value
    }
}

Supported JSON Types

  • String: Must be enclosed in quotes ("example"). Newlines inside strings are not allowed.
  • Number: Supports integers, floats, and exponents. Strict format checking.
  • Boolean: Only accepts true or false (case-sensitive). 1 and 0 are rejected.
  • Null: Only accepts null (case-sensitive).
  • Object: Key-value pairs, keys must be strings.
  • List (Array): Elements separated by commas, supports mixed types. Trailing commas are allowed and ignored. Empty lists are supported.

Memory Management

Important: Always call json_free() to prevent memory leaks.

Functions

  • json_free(json* j): Frees all memory associated with a JSON structure
  • json_object_free(json_object* obj): Frees memory for individual JSON objects (used internally)

Memory Management Features

  • Recursive cleanup: Automatically frees nested objects, arrays, and strings
  • NULL safety: Safe to call on NULL pointers
  • Double-free protection: Safe to call multiple times on the same structure
  • Complete reset: Resets the structure after freeing

Error Handling Example

json result = deserialize_json(json_string, strlen(json_string));
if (result.failure) {
    printf("Error: %s\n", result.error_text);
    json_free(&result);  // Free even on failure
    return 1;
}
// Normal processing...
json_free(&result);

Complex Structures Example

// Even deeply nested structures are cleaned up with one call
const char* complex = "{\"users\":[{\"name\":\"John\",\"data\":{\"age\":30}}]}";
json result = deserialize_json(complex, strlen(complex));
// Use the result...
json_free(&result);  // Frees everything recursively

Compilation & Running Tests

Build (CMake)

rm -rf build
mkdir -p build
cd build
cmake ..
make
cd ..

Run Tests

./run_tests.sh

Or run the test binary directly:

./build/tests

Manual Compilation (Optional)

gcc -std=c99 -Wall -Wextra -Iinclude -Itest/helpers -Itest/cases -o build/tests test/tests.c test/helpers/test_output_helper.c -g
./build/tests

Error Handling

All parsing errors are reported via the error_text field in the json struct. Common errors include:

  • Missing or mismatched quotes
  • Invalid number format
  • Unexpected characters
  • Multiple values where only one is allowed

License

This project is licensed under the MIT License. You are free to use, modify, and distribute this software with attribution.