json-build is a zero-allocation JSON serializer written in ANSI C. Its tokenizer counterpart can be found at jsmn-find.
- compatible with C89
- no dependencies
- no dynamic memory allocation
Download json-build.h, include it, done.
#include "json-build.h"
...
jsonb b;
char buf[1024];
jsonb_init(&b);
jsonb_object(&b, buf, sizeof(buf));
{
jsonb_key(&b, buf, sizeof(buf), "foo", strlen("foo"));
jsonb_array(&b, buf, sizeof(buf));
{
jsonb_number(&b, buf, sizeof(buf), 1);
jsonb_string(&b, buf, sizeof(buf), "hi", 2);
jsonb_bool(&b, buf, sizeof(buf), 0);
jsonb_null(&b, buf, sizeof(buf));
jsonb_array_pop(&b, buf, sizeof(buf));
}
jsonb_object_pop(&b, buf, sizeof(buf));
}
printf("JSON: %s", buf); // JSON: {"foo":[1,"hi",false,null]}For dynamic buffer management, json-build provides _auto counterparts for all serializer functions.
These functions will automatically reallocate the buffer when more space is needed:
#include "json-build.h"
#include <stdlib.h>
...
jsonb b;
char *buf = malloc(64); // Initial small buffer
size_t bufsize = 64;
jsonb_init(&b);
jsonb_object_auto(&b, &buf, &bufsize); // Note: passing pointers to buffer and size
{
jsonb_key_auto(&b, &buf, &bufsize, "foo", strlen("foo"));
jsonb_array_auto(&b, &buf, &bufsize);
{
jsonb_number_auto(&b, &buf, &bufsize, 1);
jsonb_string_auto(&b, &buf, &bufsize, "hi", 2);
jsonb_bool_auto(&b, &buf, &bufsize, 0);
jsonb_null_auto(&b, &buf, &bufsize);
jsonb_array_pop_auto(&b, &buf, &bufsize);
}
jsonb_object_pop_auto(&b, &buf, &bufsize);
}
printf("JSON: %s (buffer size: %zu)\n", buf, bufsize);
free(buf);IMPORTANT: Do not mix regular and _auto functions on the same buffer. Always use either the regular functions with a fixed-size buffer or the _auto functions with a dynamically allocated buffer throughout your code.
Since json-build is a single-header, header-only library, for more complex use
cases you might need to define additional macros. #define JSONB_STATIChides all
json-build API symbols by making them static. Also, if you want to include json-build.h
for multiple C files, to avoid duplication of symbols you may define JSONB_HEADER macro.
/* In every .c file that uses json-build include only declarations: */
#define JSONB_HEADER
#include "json-build.h"
/* Additionally, create one json-build.c file for json-build implementation: */
#include "json-build.h"jsonb_init()- initialize a jsonb handlejsonb_reset()- reset the buffer's position tracker for streaming purposesjsonb_object()- push an object to the builder stackjsonb_object_pop()- pop an object from the builder stackjsonb_key()- push an object key field to the builder stackjsonb_array()- push an array to the builder stackjsonb_array_pop()- pop an array from the builder stackjsonb_token()- push a raw token to the builder stackjsonb_bool()- push a boolean token to the builder stackjsonb_null()- push a null token to the builder stackjsonb_string()- push a string token to the builder stackjsonb_number()- push a number token to the builder stack
The following are the possible return codes for the builder functions:
JSONB_OK- operation was a success, user can proceed with the next operationJSONB_END- operation was a success, JSON is complete and expects no more operationsJSONB_ERROR_NOMEM- buffer is not large enough, or_autofunction couldn't reallocateJSONB_ERROR_INPUT- user action don't match expected next tokenJSONB_ERROR_STACK- user action would lead to out of boundaries access, increaseJSONB_MAX_DEPTH!JSONB_ERROR_OVERFLOW- automatic buffer increase would lead to an overflow, only use with_autofunctions
Its worth mentioning that all JSONB_ERROR_ prefixed codes are negative.
If you get JSONB_ERROR_NOMEM you can either:
- re-allocate a larger buffer and call the builder function once more
- call
jsonb_reset()to reset the buffer's position tracker and call the builder function once more (useful for streaming with a fixed sized buffer!)
This software is distributed under MIT license, so feel free to integrate it in your commercial products.