Optimized JSON in C (OjC), as the name implies, was written to provide performant JSON handling. The primary focus is for applications that need the maximum performance when reading large JSON document from a file or socket. Functions for building, formatting, and writing JSON are also part of the library.
There are a number of options for parsing JSON to address a variety of use cases but in all cases an attempt was made to keep the API as easy to use as possible. The code itself is fairly direct in regard to implementing the algorithms selected in an attempt to make it easy to read and follow. At least that was goal. It is up to the reader to make that judgement though.
Since the code is Open Source most of the types and structs are exposed. There is no reason to hide them when someone can just look at the code and modify it anyway. An object model is used for functions and structures. At the core is the ojVal struct that represents the elements of a JSON document. Generally functions start with the name of the type they are associated with such as oj_build_object() for a function that uses an ojBuilder type. The ojVal is the exception as it is the code so functions such as oj_double_get() forgo the oj_val prefix that might be expected.
In the interest of keeping OjC is as flexible as possible, OjC can not only read from files but also from any file descriptor whether it represents a file, socket, or some other stream. There are no restrictions on how multiple JSON documents appear in the stream other than each document must be valid JSON and only white space is allowed between JSON documents. Formatted or indented JSON is accepted as well as compact JSON that is on one line. Callback APIs are used when parsing streams containing multiple JSON documents.
Found in the examples/validate directory.
Parse a JSON string and return an JSON element as an ojVal. ojVal is the type used to represent JSON element in the OjC library.
Parse a JSON string using callbacks on each element. For every element the push callback is made. The pop callback is called when an array or object close is encountered. This approach is similar to the XML SAX parsers or the Ruby Oj SCP parser and Oj::ScHandler. It can be more efficient if there is no need to build a full JSON structure in memory. It is also useful when parsing a string that contains multiple JSON documents.
Parse a JSON string using callbacks on each document. For every document the callback is invoked. This is an effective way to iterate over multiple documents in a string.
The callback function's return value indicates to the parser what whould be done after the callback. If the document (val) is no longer needed then OJ_DESTROY is returned. If the parsing should be stopped then OJ_STOP is returned. To both stop and cleanup the two values are ORed together (OJ_DESTROY | OJ_STOP).
Parse a JSON string using callbacks on each document. For every document the callback is invoked but invoked in a thread separate from the parser. This is an effective way to iterate over multiple documents in a string where significant processing time is spent on each document. There is some overhead using the caller so it is best used when there is some processing of the documents involved.
The callback function's return value indicates to the parser what whould be done after the callback. If the document (val) is no longer needed then OJ_DESTROY is returned. If the parsing should be stopped then OJ_STOP is returned. To both stop and cleanup the two values are ORed together (OJ_DESTROY | OJ_STOP).
Parse a JSON file and return an JSON element as an ojVal. ojVal is the type used to represent JSON element in the OjCz library.
The input file, sample.json has the following content although and JSON file should be fine.
Parse a JSON file using callbacks on each element. For every element the push callback is made. The pop callback is called when an array or object close is encountered. This approach is similar to the XML SAX parsers or the Ruby Oj SCP parser and Oj::ScHandler. It can be more efficient if there is no need to build a full JSON structure in memory. It is also useful when parsing a file that contains multiple JSON documents.
The input file, sample.json has the following content although and JSON file should be fine.
Parse a JSON file using callbacks on each document. For every document the callback is invoked. This is an effective way to iterate over multiple documents in a file.
The callback function's return value indicates to the parser what whould be done after the callback. If the document (val) is no longer needed then OJ_DESTROY is returned. If the parsing should be stopped then OJ_STOP is returned. To both stop and cleanup the two values are ORed together (OJ_DESTROY | OJ_STOP).
The input file, sample.json has the following content although and JSON file should be fine.
Parse a JSON file using callbacks on each document. For every document the callback is invoked but invoked in a thread separate from the parser. This is an effective way to iterate over multiple documents in a file where significant processing time is spent on each document. There is some overhead using the caller so it is best used when there is some processing of the documents involved.
The callback function's return value indicates to the parser what whould be done after the callback. If the document (val) is no longer needed then OJ_DESTROY is returned. If the parsing should be stopped then OJ_STOP is returned. To both stop and cleanup the two values are ORed together (OJ_DESTROY | OJ_STOP).
The input file, sample.json has the following content although and JSON file should be fine.
This example demonstrates the use of the ojBuilder to construct a JSON document as well as writing the document to a file as indented JSON.
This enum is for the return values of the ojParseCallback functions.
OJ_CONTINUE | Indicates parsing should continue. |
OJ_STOP | Indicates parsing should stop. |
OJ_DESTROY | Indicates the ojVal argument to the callback should be freed. This value can be OR-ed with either OJ_CONTINUE or OJ_STOP. |
Used to indicate how object members are stored in a value.
OJ_OBJ_RAW | Members are stores as a simple list. |
OJ_OBJ_HASH | Members are store in a fixed size hash. |
Functions that can fail take an ojErr argument. If an error occurs the fields of the ojErr are set. The ojErr.code is set to either one of the errors in errno.h or to one of the ojStatus enum values.
OJ_OK | No error, Okay |
OJ_ERR_MEMORY | A memory error |
OJ_ERR_PARSE | A parse error |
OJ_ERR_READ | A read error |
OJ_ERR_WRITE | A write error |
OJ_ERR_OVERFLOW | An overflow error |
OJ_ERR_ARG | An argument error |
OJ_ERR_TOO_MANY | Too many of something error |
OJ_ERR_TYPE | A type error |
OJ_ERR_KEY | A key error |
OJ_ABORT | An indication that parsing should stop |
OJ_ERR_LAST | Maximum enum value |
Used to identify ojVal types.
OJ_NONE | Type not set |
OJ_NULL | Value is a JSON null |
OJ_TRUE | Value is a JSON true |
OJ_FALSE | Value is a JSON false |
OJ_INT | Value is a int64_t |
OJ_DECIMAL | Value is a long double |
OJ_BIG | Value is a bignum stored as a string (const char*) |
OJ_STRING | Value is a string (const char*) |
OJ_OBJECT | Value is a JSON object |
OJ_ARRAY | Value is a JSON array |
Used for building strings as well as writing to files. The buffer starts out with a fixed size base and appends to that until more space is needed. If more space is needed it is allocated. If fronting for a file then the buffer is written and the tail is reset.
char* | head | Always points to the string being built |
char* | end | Marks the end of the buffer |
char* | tail | The current or next position to write to |
int | fd | fiel descriptor to write to is not 0 |
bool | realloc_ok | A flag indicating reallocation is okay. Set to false if used for reading only. |
ojStatus | err | Error indicator |
char | base[4096] | Built in buffer |
Used for building ojVal JSON documents. A stack based approach is used making use of the ojVal.next field.
ojVal | top | Top of the document |
ojVal | stack | The stack |
struct _ojErr | err | Place to store errors |
Struct used internally by the ojCaller.
ojVal | val | Value for callbacks |
struct _ojReuser | reuser | Used to return values to the pool |
atomic_flag | busy | Concurrent use protection |
Used for concurrent callbacks. The fields in the struct should not be modified directly. The correct use of the caller when parsing is to first call the oj_caller_start() and then finish up with oj_caller_wait() after the parser is called.
struct _ojCall | queue[256] | Callback queue |
pthread_t | thread | Thread invoking the callback |
ojParseCallback | cb | The callback |
void* | ctx | The callback context |
ojCall | end | The end of the queue |
ojCall | tail | Last slot for the callback thread |
atomic_flag | starting | Concurrent protection flag |
volatile bool | done | Indicator that callbacks are complete |
Struct to store error information.
int | code | Error code (ojStatus) |
int | line | Line in document the error occured on if applicable |
int | col | Column in document the error occured on if applicable |
char | msg[256] | Message describing the error |
List representation. It is also used for the object raw mode.
struct _ojVal* | head | Head of the list |
struct _ojVal* | tail | Tail or last member in the list |
All numbers are stores in this struct. The ojVal.type determines which members are set. Several of the members are only used during parsing and can be ignored.
long double | dub | Decimal value |
int64_t | fixnum | Integer values or all digits when parsing |
uint32_t | len | Length of the string representation |
int16_t | div | Divisor when parsing |
int16_t | exp | Exponent when parsing |
uint8_t | shift | Shift of fixnum to get the decimal value |
bool | neg | If true the number is negative |
bool | exp_neg | If true the exponent is negative |
bool | calc | Indicator that the parts have been used to calculate the fixnum or double value |
char | raw[88] | String version of the number |
ojS4k | s4k | String version of the number if too long for the raw field |
size_t | cap | Capacity of string representation if too long for the s4k field |
char* | ptr | String representation if too long for the s4k field |
The type for callback functions when using the callback parsers.
The type for the push function with the push-pop parsers.
The type for the pop function with the push-pop parsers.
The struct used for collecting and efficiently returning ojVal instances back to the pool. The fields are used internally only.
ojVal | head | Head of the ojVals to be returned |
ojVal | tail | Tail of the ojVals to be returned |
ojVal | dig | ojVals that need addition free calls. |
Blocks used for strings and bignums that are too large to fit directly into a ojVal. These are used internally.
union _ojS4k* | next | Linked list link |
char | str[4096] | Space for the string |
Used to store strings. There are three locations for the string data depending on the string length. Shorter strings are stored in the raw member. The next level up is the s4k member. If the string is larger than a ojS4k then the ptr member is used to store the string.
int | len | Length of raw or ptr excluding terminating null |
char | raw[120] | Storage for shorter string |
ojS4k | s4k | Storage for larger strings |
size_t | cap | Capacity of extra large strings |
char* | ptr | Storage for extra large strings |
Each element of a JSON document is represented by the ojVal struct.
struct _ojVal* | next | Linked list next pointer |
struct _ojVal* | free | Free list next pointer |
struct _ojStr | key | Key of the member if a member of an object |
uint32_t | kh | Hash of the key|
uint8_t | type | Type of the value (ojType) |
uint8_t | mod | Modifier of the type (objects only) |
struct _ojStr | str | String value |
struct _ojList | list | List and raw object value |
struct _ojVal* | hash[16] | Object value when a hash |
struct _ojNum | num | Numeric value |
Thread safe flag. It should be set when using the library from multiple threads.
Appends a member to an array. It can also be used to set an object entry if the member key is set.
ojErr | err | Used for error reporting. |
ojVal | val | Array or object to append to. |
ojVal | member | Member to append. |
Create a new array ojVal.
ojErr | err | Used for error reporting. |
Return the first member of a list. If not a list or the list is empty NULL is returned.
ojVal | val | The array to get the first member from. |
Return the last member of a list. If not a list or the list is empty NULL is returned.
ojVal | val | The list to get the last member from. |
Return the nth member of a list. If not a list or there is no nth element NULL is returned.
ojVal | val | The list to get the nth member from. |
int | n | The member offset (n) in the list to return. |
Create a new bignum ojVal.
ojErr | err | Used for error reporting. |
const char* | s | String representation of a big number. |
size_t | len | Length of the string. |
Return the bignum string.
ojVal | val | Value to get the string from. |
Set the value of a ojVal to a bignum.
ojErr | err | Used for error reporting. |
ojVal | val | Value to set. |
const char* | s | Bignum string. |
size_t | len | String length. |
Create a new boolean ojVal.
ojErr | err | Used for error reporting. |
bool | b | Boolean value for the new ojVal. |
Set the value of a ojVal to a boolean.
ojVal | val | ojVal to set the value of. |
bool | b | Boolean value for the ojVal. |
Marshal a ojVal into a ojBuf indented with the specified indentation and stating depth.
ojBuf | buf | Buffer to fill. |
ojVal | val | Value to marshal. |
int | indent | Identation of generated string. |
int | depth | Initial depth of the indentation. |
Push an array onto the build stack of a ojBuilder and return the state of the builder error code.
ojBuilder | b | Builder to push the new value to. |
const char* | key | Key for the value being pushed if parent is an object. |
Push a bignum string onto the build stack or append to the most recent object or array on the stack a ojBuilder and return the state of the builder error code.
ojBuilder | b | Builder to push the new value to. |
const char* | key | Key for the value being pushed if parent is an object. |
const char* | big | The bignum string to push. |
size_t | len | Length of the bignum string. |
Push a boolean onto the build stack or append to the most recent object or array on the stack a ojBuilder and return the state of the builder error code.
ojBuilder | b | Builder to push the new value to. |
const char* | key | Key for the value being pushed if parent is an object. |
bool | boo | Value to push to the stack. |
Push a long double onto the build stack or append to the most recent object or array on the stack a ojBuilder and return the state of the builder error code.
ojBuilder | b | Builder to push the new value to. |
const char* | key | Key for the value being pushed if parent is an object. |
long double | d | Value to push to the stack. |
Push an int64_t onto the build stack or append to the most recent object or array on the stack a ojBuilder and return the state of the builder error code.
ojBuilder | b | Builder to push the new value to. |
const char* | key | Key for the value being pushed if parent is an object. |
int64_t | i | Value to push on the stack. |
Push a null onto the build stack or append to the most recent object or array on the stack a ojBuilder and return the state of the builder error code.
ojBuilder | b | Builder to push the new value to. |
const char* | key | Key for the value being pushed if parent is an object. |
Push an object onto the build stack of a ojBuilder and return the state of the builder error code.
ojBuilder | b | Builder to push the new value to. |
const char* | key | Key for the value being pushed if parent is an object. |
Pop a value from the builder stack. This has the effect of closing the most recent object or array.
ojBuilder | b | Builder to pop a value from. |
Continue popping a value from the builder stack until the stack is empty. This has the effect of closing all remaining objects and arrays.
ojBuilder | b | Builder to pop values from. |
Push a string onto the build stack or append to the most recent object or array on the stack a ojBuilder and return the state of the builder error code.
ojBuilder | b | Builder to push the new value to. |
const char* | key | Key for the value being pushed if parent is an object. |
const char* | s | String to push onto the stack. |
size_t | len | Length of the string to push. |
Shutdown a ojCaller which stops the callback thread. Any remaining callbacks are discarded.
ojCaller | caller | The caller to shutdown. |
Starts a ojCaller so that is is ready when call parser is invoked with it as an argument.
ojErr | err | Used for error reporting. |
ojCaller | caller | Caller to start. |
ojParseCallback | cb | Callback function for calls. |
void* | ctx | Context for the callback function. |
Wait for a ojCaller to finish processing pending callbacks.
ojCaller | caller | Caller to wait on. |
Cleans up memory used by the library. It should be called before exiting an application if checking for memory leaks.
Returns a ojVal to the memory pool. A reuse pool is used to improve performance.
ojVal | val | The ojVal to return to the pool. |
Create a new double numeric ojVal.
ojErr | err | Used for error reporting. |
long double | dub | The value to set in the new ojVal. |
Return the long double value of a ojVal. If the ojVal is not a double then 0.0 is returned.
Set the value of a ojVal to a long double.
ojVal | val | The ojVal set the provided value on. |
long double | dub | The value to set the ojVal to. |
Iterate over all members of an array or object.
ojVal | val | Array or object ojVal to iterate over. |
bool (*)(ojVal, void*) | cb | Callback to be invoked for each member of the array or object. |
void* | ctx | Context to provide to each callback invocation. |
Initialize a ojErr struct.
ojErr | err | ojVal to initialize. |
Fill a buffer with a ojVal marshalled into JSON.
ojErr | err | Used for error reporting. |
ojVal | val | ojVal to marshal into JSON. |
int | indent | Indentation to use for formatting the JSON. |
char* | buf | Buffer to fill with JSON. |
int | max | Maximum size of encoded JSON. |
Write a ojVal to a file encoded as JSON.
ojErr | err | Used for error reporting. |
ojVal | val | ojVal to encode. |
int | indent | Indentation to use for formatting the JSON. |
const char* | filepath | Filename to write to. |
Create a new integer numeric ojVal.
ojErr | err | Used for error reporting. |
int64_t | fixnum | TBD. |
Return the int64_t value of a ojVal. If the ojVal is not a int then 0 is returned.
ojVal | val | ojVal to get the value from. |
Set the value of a ojVal to a int64_t.
ojVal | val | ojVal to set the value of. |
int64_t | fixnum | The value to set the ojVal to. |
Return the key of a ojVal.
ojVal | val | The ojVal to get the key from. |
Set the key of a ojVal.
ojErr | err | Used for error reporting. |
ojVal | val | ojVal to set the key of. |
const char* | key | Key to set the ojVal to. |
size_t | len | Length of the key. |
Create a new null ojVal.
ojErr | err | Used for error reporting. |
Set the value of a ojVal to null.
ojVal | val | ojVal to set to a null value. |
Create a new object ojVal.
ojErr | err | Used for error reporting. |
Find the member of the object that has a matching key if the ojVal is an object. The mode is not changed.
ojVal | val | Object to get a value from. |
const char* | key | Key to match. |
int | len | Length of the key. |
Get the member of the object that has a matching key if the ojVal is an object. The mode is set to OJ_OBJ_HASH.
ojVal | val | Object to get a value from. |
const char* | key | Key to match. |
int | len | Length of the key. |
Set a member of the object associated with the provided key.
ojErr | err | Used for error reporting. |
ojVal | val | Object to set the member of. |
const char* | key | Key for the member. |
ojVal | member | Member to be set associated with the key. |
Parse JSON read from a file descriptor. Only one JSON document should be in the stream. The caller is responsible for freeing the returned value with oj_destroy() or by using the reuser if provided.
ojErr | err | Used for error reporting. |
int | fd | Stream parse. |
ojReuser | reuser | Optional reused for freeing the returned value. |
Parse multiple JSON documents from a file descriptor using callback through the provided caller.
ojErr | err | Used for error reporting. |
int | fd | Stream to read from. |
ojCaller | caller | Caller for invoking callbacks. |
Parse multiple JSON documents from a file descriptor using a callback function.
ojErr | err | Used for error reporting. |
int | fd | Stream to read from. |
ojParseCallback | cb | Callback function. |
void* | ctx | Context for the callback. |
Parse JSON read from a file. Only one JSON document should be in the file. The caller is responsible for freeing the returned value with oj_destroy() or by using the reuser if provided.
ojErr | err | Used for error reporting. |
const char* | filename | File to parse. |
ojReuser | reuser | Optional reused for freeing the returned value. |
Parse multiple JSON documents from a file using callback through the provided caller.
ojErr | err | Used for error reporting. |
int | filename | File to read from. |
ojCaller | caller | Caller for invoking callbacks. |
Parse multiple JSON documents from a file using callback through the provided callback function.
ojErr | err | Used for error reporting. |
const char* | filename | File to parse. |
ojParseCallback | cb | Callback function. |
void* | ctx | Context for the callback. |
pp Parse JSON string. Only one JSON document should be in the string. The caller is responsible for freeing the returned value with oj_destroy() or by using the reuser if provided.
ojErr | err | Used for error reporting. |
const char* | json | String to parse. |
ojReuser | reuser | Optional reused for freeing the returned value. |
Parse multiple JSON documents from a string using callback through the provided caller.
ojErr | err | Used for error reporting. |
const char* | json | String to parse. |
ojCaller | caller | Caller for invoking callbacks. |
Parse multiple JSON documents from a string using callback through the provided callback function.
ojErr | err | Used for error reporting. |
const char* | json | String to parse. |
ojParseCallback | cb | Callback function. |
void* | ctx | Context for the callback. |
Parse a JSON string pointed to by the json pointer. Only one document is parsed and then the json argument is set to point to just after the parsed string. The caller is responsible for freeing the returned value with oj_destroy() or by using the reuser if provided.
ojErr | err | Used for error reporting. |
const char** | json | Pointer to a string to parse. |
ojReuser | reuser | Optional reused for freeing the returned value. |
Parse multiple JSON documents from a file descriptor using callbacks for pushing values when they are first encountered and popping when array or objects are closed.
ojErr | err | Used for error reporting. |
int | fd | Stream to parse. |
ojPushFunc | push | Push callback. |
ojPopFunc | pop | Pop callback. |
void* | ctx | Context for both callbacks. |
Parse multiple JSON documents from a file using callbacks for pushing values when they are first encountered and popping when array or objects are closed.
ojErr | err | Used for error reporting. |
const char* | filepath | File to parse. |
ojPushFunc | push | Push callback. |
ojPopFunc | pop | Pop callback. |
void* | ctx | Context for both callbacks. |
Parse multiple JSON documents from a string using callbacks for pushing values when they are first encountered and popping when array or objects are closed.
ojErr | err | Used for error reporting. |
const char* | json | String to parse. |
ojPushFunc | push | Push callback. |
ojPopFunc | pop | Pop callback. |
void* | ctx | Context for both callbacks. |
Return ojVal instance collected during parsing.
ojReuser | reuser | Reuser that collected ojVal instances. |
Return a string representation of the ojStatus provided.
ojStatus | code | ojStatus to return a string from. |
Create a new string ojVal.
ojErr | err | Used for error reporting. |
const char* | s | String value for the new ojVal. |
size_t | len | Length of string. |
Return the string value of a ojVal. If the ojVal is not a string then NULL is returned.
ojVal | val | ojVal to get the value from. |
Set the value of a ojVal to a string.
ojErr | err | Used for error reporting. |
ojVal | val | ojVal to set the value on. |
int64_t | s | The value to set the ojVal to. |
size_t | len | Length of string. |
Return a JSON string represented by the ojVal provided. The returned JSON string should be freed when no longer needed.
ojVal | val | ojVal to encode. |
int | indent | Indentation for the JSON string. |
Return a string representation of the provided type.
ojType | type | Type to return a string represenation of. |
Create a new blank ojVal.
Validate a JSON string.
ojErr | err | Used for error reporting. |
const char* | json | JSON string to validate. |
Return the OjC version.
Write a ojVal to a stream in JSON format.
ojErr | err | Used for error reporting. |
ojVal | val | ojVal to encode. |
int | indent | Indentation for the JSON output. |
int | fd | Stream to write to. |