Skip to content
master
Switch branches/tags
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

jsonic

JSON parser for C.

Including and Compiling

Including

#include "jsonic.h"

Compiling

GNU Compiler Collection (GCC)
cd /path/to/jsonic
make
cd /path/to/your/project
gcc -o example.exe example.c /path/to/jsonic/jsonic.o -I /path/to/jsonic

Reading JSON

Jsonic Node

Every JSON result is a jsonic_node_t object in jsonic.

typedef struct jsonic_node jsonic_node_t;
struct jsonic_node {
    char* key;
    char* val;
    jsonic_node_type_t type;
    unsigned int len;
    unsigned int pos;
    ...
};

You will use structure members: type, key, val, len and pos for reading JSON.

val is useable for string, number, boolean and null types. val is a NULL Terminated String and you can get length of string via len for string values. pos is useable for getting iteration position for arrays/objects.

key is useable NULL Terminated String for Key=>Value iteration results.

String Values

String values come as NULL Terminated String in val and you can check them with node->type == JSONIC_STRING.

Number Values

Number values come as NULL Terminated String in val and you can check them with node->type == JSONIC_NUMBER.

Boolean Values

Boolean values come as NULL Terminated String in val. val maybe "1" or "0" for boolean values and you can check them with node->type == JSONIC_BOOLEAN.

Null Values

Null values come as NULL Terminated String in val as "0" and you can check them with node->type == JSONIC_NULL.

Result Length

len is useable for string, number, boolean and null types and does not give length of an array. You can use jsonic_array_length() or jsonic_array_length_from() for getting an array's length.

Iteration Position

node->pos is useable for objects and arrays both. It gives current index of current iterated array item or object key&value. Also you can use it for not found result nodes.

JSON Types

enum JSONIC_NODE_TYPES {
    JSONIC_NONE,
    JSONIC_OBJECT,
    JSONIC_ARRAY,
    JSONIC_STRING,
    JSONIC_NUMBER,
    JSONIC_BOOLEAN,
    JSONIC_NULL
};
typedef enum JSONIC_NODE_TYPES jsonic_node_type_t;

Not Found Results

You will get a node with type JSONIC_NONE for not found results and of course you need freeing it.

Checking Length for Not Found Results

You can check how many items itered at total including searching the not found result node with node->pos.

Examples
jsonic_node_t* not_exists_key = jsonic_object_get(json_string, root, "not_exists_key");
printf("Count: %d\n\n", not_exists_key->pos); // not_exists_key->pos+1 is how many items itered.
jsonic_node_t* an_exists_key = jsonic_object_get(json_string, root, "an_exists_key");
jsonic_node_t* not_exists_key = jsonic_object_iter(json_string, root, an_exists_key, "not_exists_key");

// not_exists_key->pos+1 is how many items itered at total including an_exists_key.
printf("Count: %d\n\n", not_exists_key->pos);
jsonic_node_t* not_exists_item = jsonic_array_get(json_string, array, 100);
printf("Count: %d\n\n", not_exists_item->pos); // not_exists_item->pos+1 is how many items itered.
jsonic_node_t* not_exists_item = jsonic_array_iter(json_string, array, exists_item, 100);
printf("Count: %d\n\n", not_exists_item->pos); // not_exists_item->pos+1 is how many items itered at total.

Functions

There are various functions in Jsonic for walking and iterating on JSON.

jsonic_from_file()

char* jsonic_from_file(char* fname);

jsonic_free()

void jsonic_free(jsonic_node_t** node);

Example:

jsonic_node_t* members = jsonic_object_get(json_string, jsonic_get_root(json_string), "members");
...
jsonic_free(&members); // free'd and members is set to NULL

jsonic_free_addr()

void jsonic_free_addr(jsonic_node_t* node);

jsonic_get_root()

jsonic_node_t* jsonic_get_root(char* json_str);
Checking Root
jsonic_node_t* root = jsonic_get_root(json_string);

if (root->type == JSONIC_NONE) {
    printf("JSON root is none.\n");
} else if (root->type == JSONIC_OBJECT) {
    printf("JSON root is an object.\n");
} else if (root->type == JSONIC_ARRAY) {
    printf("JSON root is an array.\n");
} else if (root->type == JSONIC_STRING) {
    printf("JSON root is a string.\n");
} else if (root->type == JSONIC_NUMBER) {
    printf("JSON root is a number.\n");
} else if (root->type == JSONIC_BOOLEAN) {
    printf("JSON root is a boolean.\n");
} else if (root->type == JSONIC_NULL) {
    printf("JSON root is null.\n");
}

jsonic_object_get()

jsonic_node_t* jsonic_object_get(char* json_str, jsonic_node_t* current, char* key);
Get an Object Key

Get a key from JSON root:

jsonic_object_get(json_string, jsonic_get_root(json_string), "someKey");

or find an existing node:

jsonic_object_get(json_string, some_object, "someKey");

jsonic_array_get()

jsonic_node_t* jsonic_array_get(char* json_str, jsonic_node_t* current, int index);
Get an Element of Array

Get an array element from JSON Array root:

jsonic_array_get(json_string, jsonic_get_root(json_string), 5);

or find an existing node:

jsonic_array_get(json_string, some_array, 5);
Inline Usage

If you are using these functions as inline, application will have memory leaks and it will be non-memory-safe, so you may get SIGSEGV!

extern jsonic_node_t* jsonic_get_root(char* json_str);
extern jsonic_node_t* jsonic_object_get(char* json_str, jsonic_node_t* current, char* key);
extern jsonic_node_t* jsonic_object_iter(char* json_str, jsonic_node_t* current, jsonic_node_t* from, char* key);
extern jsonic_node_t* jsonic_object_iter_free(char* json_str, jsonic_node_t* current, jsonic_node_t* from, char* key);
extern jsonic_node_t* jsonic_object_iter_kv(char* json_str, jsonic_node_t* current, jsonic_node_t* from);
extern jsonic_node_t* jsonic_object_iter_kv_free(char* json_str, jsonic_node_t* current, jsonic_node_t* from);
extern jsonic_node_t* jsonic_array_get(char* json_str, jsonic_node_t* current, int index);
extern jsonic_node_t* jsonic_array_iter(char* json_str, jsonic_node_t* current, jsonic_node_t* node, int index);
extern jsonic_node_t* jsonic_array_iter_free(char* json_str, jsonic_node_t* current, jsonic_node_t* node, int index);
Example

Non-memory-safe usage:

printf("Squad: %s\n", jsonic_object_get(json_string, jsonic_get_root(json_string), "squadName")->val);

This is memory-safe usage:

jsonic_node_t* root = jsonic_get_root(json_string);
jsonic_node_t* name = jsonic_object_get(json_string, root, "squadName");

if (name != NULL) {
    if (name->type == JSONIC_STRING) {
        printf("Squad: %s\n", name->val);
    }

    jsonic_free(&name);
}

jsonic_free(&root);

jsonic_array_length()

int jsonic_array_length(char* json_str, jsonic_node_t* array);

jsonic_array_length_from()

int jsonic_array_length_from(char* json_str, jsonic_node_t* array, jsonic_node_t* from);

jsonic_array_iter()

jsonic_node_t* jsonic_array_iter(char* json_str, jsonic_node_t* current, jsonic_node_t* node, int index);

Useable for iterating arrays. Starts reading from given node in current, so index parameter must start from 0, it will start reading from given node.

jsonic_array_iter_free()

jsonic_node_t* jsonic_array_iter_free(char* json_str, jsonic_node_t* current, jsonic_node_t* node, int index);

Same as jsonic_array_iter() but frees given jsonic object (node).

Iterating Arrays

You can use jsonic_array_iter() or jsonic_array_iter_free().

jsonic_node_t* power = NULL;
for (;;) {
    power = jsonic_array_iter_free(json_string, powers, power, 0);
    if (power->type == JSONIC_NONE) break;
}

Notice: Using jsonic_array_iter() instead of jsonic_array_iter_free() would be non-memory safe for most of times.

jsonic_object_iter()

jsonic_node_t* jsonic_object_iter(char* json_str, jsonic_node_t* current, jsonic_node_t* from, char* key);

Useable for getting a key's value with more performance. It starts reading from given node in current.

Notice: You must be sure your key is located after given node in JSON.

jsonic_object_iter_free()

jsonic_node_t* jsonic_object_iter_free(char* json_str, jsonic_node_t* current, jsonic_node_t* from, char* key);

Same as jsonic_object_iter() but frees given jsonic object (from).

jsonic_object_iter_kv()

jsonic_node_t* kv = jsonic_object_iter_kv(json_string, current, from);

Useable for object iteration as key: value pairs in current starting from from.

jsonic_object_iter_kv_free()

jsonic_node_t* kv = jsonic_object_iter_kv_free(json_string, current, from);

Same as jsonic_object_iter_kv() but frees given jsonic object (from).

Iterating Objects with a Key

You can use jsonic_object_iter() or jsonic_object_iter_free().

jsonic_node_t* node = jsonic_object_iter(json_string, something, previousNode, "someKey");
Iterating Objects as Key: Value Pairs

You can use jsonic_object_iter_kv() or jsonic_object_iter_kv_free().

jsonic_node_t* key = NULL;
for (;;) {
    key = jsonic_object_iter_kv_free(json_string, keys, key);
    if (key->type == JSONIC_NONE) break;
    
    if ((key->type == JSONIC_STRING) || (key->type == JSONIC_NUMBER)) {
        printf("%s => %s\n", key->key, key->val);
    }
}

Compile and Run Examples

You can compile and run examples in examples/ directory:

cd examples/heroes
make

and run on Windows:

heroes.exe

on Linux:

./heroes.exe

Example

An example for reading JSON data

char* json_string = jsonic_from_file("heroes.json");

jsonic_node_t* root = jsonic_get_root(json_string);

jsonic_node_t* members = jsonic_object_get(json_string, root, "members");
jsonic_node_t* member = jsonic_array_get(json_string, members, 1);
jsonic_node_t* powers = jsonic_object_get(json_string, member, "powers");

// inline usage: non-free'd nodes and non-safe pointers!..
// using jsonic_object_get() is poor way because of reading it from start of json each time!
// use jsonic_object_iter() or jsonic_object_iter_free() instead of jsonic_object_get().
printf("Squad: %s\n", jsonic_object_get(json_string, root, "squadName")->val);
printf("Active: %s\n", jsonic_object_get(json_string, root, "active")->val);
printf("Formed: %s\n", jsonic_object_get(json_string, root, "formed")->val);
printf("Name: %s\n", jsonic_object_get(json_string, member, "name")->val);
printf("Age: %s\n", jsonic_object_get(json_string, member, "age")->val);
printf("Powers (%d total):\n", jsonic_array_length(json_string, powers));

jsonic_node_t* power = NULL;
for (;;) {
    power = jsonic_array_iter_free(json_string, powers, power, 0);
    if (power->type == JSONIC_NONE) break;
    
    if (power->type == JSONIC_STRING) {
        printf(
            "\t%s (pos: %d, from len: %d)\n",
            power->val,
            power->pos,
            jsonic_array_length_from(json_string, powers, power)
        );
    }
}

jsonic_free(&members);
jsonic_free(&member);
jsonic_free(&powers);
jsonic_free(&root);
free(json_string);

Example JSON (heroes.json):

{
    "squadName": "Super hero squad",
    "homeTown": "Metro City",
    "formed": 2016,
    "secretBase": "Super tower",
    "active": true,
    "members": [
    {
        "name": "Molecule Man",
        "age": 29,
        "secretIdentity": "Dan Jukes",
        "powers": [
            "Radiation resistance",
            "Turning tiny",
            "Radiation blast"
        ]
    },
    {
        "name": "Madame Uppercut",
        "age": 39,
        "secretIdentity": "Jane Wilson",
        "powers": [
            "Million tonne punch",
            "Damage resistance",
            "Superhuman reflexes"
        ]
    },
    {
        "name": "Eternal Flame",
        "age": 1000000,
        "secretIdentity": "Unknown",
        "powers": [
            "Immortality",
            "Heat Immunity",
            "Inferno",
            "Teleportation",
            "Interdimensional travel"
        ]
    }
    ]
}

JSON Type Checking

You must check JSON node for jsonic_object_get() or jsonic_array_get() from it. Otherwise you will get some absurd data. (e.g. Trying get a key's value from an array.)

Syntax Checking

This library does not check JSON syntax, so you may get SIGSEGV or maybe infinite loops for corrupt JSONs. Likewise in some cases of corrupt JSONs, it would work as properly.

Performance

There are some example JSONs and reading examples in examples/ folder for profiling the performance.

License

MIT