Skip to content

Repository files navigation

TinyJSON

CILicense: MITVersion

A lightweight and lightning-fast C++ JSON & JSON5 parser designed for high performance and minimal footprint.

  • Zero-dependency: Easy to integrate into any C++ project.
  • Atomic file saving: Guarantees data integrity by using a temporary file before overwriting.
  • Minimal memory overhead: Ideal for resource-constrained environments.
  • High-performance parsing: Benchmarked for speed against other leading parsers.
  • Simple API: Intuitive and easy to use.

Contents

Supported JSON

See more in the specifications document.

JSON5 Support

TinyJSON is a fully compliant JSON5 parser. JSON5 is a superset of JSON that makes it easier for humans to write and maintain.

Key differences between JSON5 and standard JSON

  • Objects: Keys can be unquoted identifiers (e.g., {name: "value"}) or single-quoted. Trailing commas are allowed.
  • Arrays: Trailing commas are allowed.
  • Strings: Can be single-quoted ('hello'). Can span multiple lines by escaping newlines. Support for additional escapes like \v, \0, \xHH, and \u{HHHHH}.
  • Numbers: Can be hexadecimal (0x123). Can have leading or trailing decimal points (.5, 5.). Support for NaN and Infinity. Can start with an explicit plus sign (+42).
  • Comments: Support for single-line (//) and multi-line (/* ... */) comments.
  • Whitespace: Support for additional Unicode whitespace characters.

Parsing JSON5 Example

To parse JSON5, you must set the specification flag in parse_options.

#include"TinyJSON.h"
#include<iostream>usingnamespaceTinyJSON;intmain() {
constchar* json5_text = R"( { // A comment unquoted: 'single quoted string', hex: 0xFF, array: [1, 2, 3,], // trailing comma nested: { val: .5 // leading decimal } })";
parse_options options;
options.specification = parse_options::json5_1_0_0;
options.throw_exception = true;
try {
auto* tj = TJ::parse(json5_text, options);
if (tj) {
auto* obj = dynamic_cast<TJValueObject*>(tj);
std::cout << "Hex value: " << obj->get_number<int>("hex") << std::endl;
delete tj;
}
} catch (const TJParseException& e) {
std::cerr << "Parse error: " << e.what() << std::endl;
}
return0;
}

Data types

JSONc++/TinyJSON
objectTJValueObject
arrayTJValueArray
stringTJValueString
numberTJValueNumber (long long, long double, exponent)
trueTJValueBoolean (true)
falseTJValueBoolean (false)
nullTJValueNull (nullptr)

Simple examples

Version Control

We follow Semantic Versioning 2.0.0, semver.org

  • MAJOR version when you make incompatible API changes
  • MINOR version when you add functionality in a backward compatible manner
  • PATCH version when you make backward compatible bug fixes

The version is set in the TinyJSON.h file.

staticconstshortTJ_VERSION_MAJOR = 0;
staticconstshortTJ_VERSION_MINOR = 2;
staticconstshortTJ_VERSION_PATCH = 7;
staticconstcharTJ_VERSION_STRING[] = "0.2.7";

Simple Value Access

TinyJSON provides a convenient operator[] for object member access and a templated as<T>() method for casting values.

auto* tj = TJ::parse(R"({"a": {"b": 10}})");
if (tj) {
// Access nested members directlyint value = (*tj)["a"]["b"].as<int>(); // 10// Handling missing keys (behavior depends on parse_options::throw_exception)// If throw_exception is false (default), it returns a null valueif ((*tj)["missing"].is_null()) {
// ...
}
delete tj;
}

Options

Parse Options

  • Depth: (max_depth:64) You can set how deep you want to allow the parsing to go.
  • Throw: (throw_exception:false) If you want to throw exceptions or simply return null.
  • Strict: (strict:false) If true, getter methods (like get_boolean, get_string, etc.) will throw an exception if the key is not found or the type is incorrect. If false, they will return a default value (e.g., 0, "", false).
  • Specification: (specification:parse_options::rfc8259) What specs will the parser be following/enforcing.
    • rfc4627
    • rfc7159
    • rfc8259
    • json5_1_0_0
  • Callback: (callback_function:std::function<void(message_type, const TJCHAR*)>) Callback function called where there is an error, warning etc. NB: The Callback function is called even if Throw is false.
    • If a getter method (try_get_string, get_*(..), or get<>(..)) is called on a key that does not exist in a TJValueObject, a warning message indicating the missing key (e.g. "The key 'missing' was not found!") is passed to the callback function.
    • trace
    • debug
    • info
    • warning
    • error
    • fatal

For example ...

TinyJSON::parse_options options = {};
options.throw_exception = true;
options.max_depth = 10;
options.Callback = [&](TinyJSON::parse_options::message_type message_type, constTJCHAR* exception_message) {
// something, something ...
};
try
{
auto blah = TinyJSON::TJ::parse("[0123]", options)
...
}
catch(TinyJSON::TJParseException ex)
{
ex.what(); // Numbers cannot have leading zeros
}

Write Options

  • Throw: (throw_exception:false) If you want to throw exceptions or simply return false.
  • write_formatting: (write_formatting::indented) The formatting we want to write the file with.
    • none
    • indented
  • Byte order mark: (byte_order_mark:none)
    • none
    • uft8

For example ...

TinyJSON::write_options options = {};
options.throw_exception = true;
options.write_formatting = TinyJSON::formatting::minify;
try
{
...
// get JSON somewhere or create it.
...
if( TinyJSON::TJ::write_file("file.json", *json, options))
{
// all good
}
...
}
catch(TinyJSON::TJParseException ex)
{
ex.what(); // what?
}

Exceptions

Parsing Exception

The parsing exception is TinyJSON::TJParseException and can be made optional in the TinyJSON::parse_options flag.

 TinyJSON::parse_options options = {};
options.throw_exception = true;
try
{
auto blah = TinyJSON::TJ::parse("[0123]", options)
...
}
catch(TinyJSON::TJParseException ex)
{
ex.what(); // Numbers cannot have leading zeros
}

Write Exception

The parsing exception is TinyJSON::TJParseException and can be made optional in the TinyJSON::parse_options flag.

 TinyJSON::write_options options = {};
options.throw_exception = true;
options.write_formatting = TinyJSON::formatting::minify;
try
{
auto json = TinyJSON::TJ::parse( "{ \"Hello\" : \"World\" }" );
TinyJSON::TJ::write_file("file.json", *json, options)
...
}
catch(TinyJSON::TJWriteException ex)
{
ex.what(); // some write error
}

Check if JSON is valid

You can simply call the TinyJSON::TJ::is_valid(...) method

if(TinyJSON::TJ::is_valid("[123,456]"))
{
// do this
}
else
{
// do that
}

Read a JSON file

To read a JSON file you simply need to call the static method parse_file, the extention does not have to be .json

auto json = TinyJSON::TJ::parse_file( "myfile.json" );
...
delete json;

This will then return an object that you can inspect as per normal.

Read a JSON string

To read a JSON string you simply need to call the static method parse

auto json = TinyJSON::TJ::parse( "{ \"Hello\" : \"World\" }" );
...
delete json;

This will then return an object that you can inspect.

 ...
auto value = json->try_get_string("Hello"); // "World"auto no_value = json->try_get_string("Life"); // null
...

You can also use literals

usingnamespaceTinyJSON;
...
auto json = "[12,13,14]"_tj;
// use it.
...
delete json;
...

Or just use the string directly

You can convert the json to 'pretty' indented json

#defineTJ_INCLUDE_STD_STRING1
#include"TinyJSON.h"usingnamespaceTinyJSON;
...
// output a pretty JSON
std::cout << "[12,13,14]"_tj_indent;
...

Or minify code.

#defineTJ_INCLUDE_STD_STRING1
#include"TinyJSON.h"usingnamespaceTinyJSON;
...
// output a pretty JSON
std::cout << "[12 , 13 , 14]"_tj_minify;
...

Search an object by key

There are 2 ways to find a key, case sensitive or insensitive, (the default is case sensitive).

You can load the json either by parsing or creating it manually.

auto object = new TinyJSON::TJValueObject();
object->set_string("a", "Hello");
object->set_string("b", "World");
object->set_string("c", "Bye");
...
// search for somethingauto case_sensitive = object->try_get_value("Hello");
auto case_insensitive = object->try_get_value("HelLO", false); // all good as we don't care about case.auto case_insensitive_not_found = object->try_get_value("HelLO"); // = null as the search was case sensitive
...
delete object;

Check if key exists

You can use has_key to check if an object contains a specific key.

auto json = TinyJSON::TJ::parse(R"({"a": 42})");
auto jobject = dynamic_cast<TinyJSON::TJValueObject*>(json);
if (jobject->has_key("a")) {
// do something
}
// Case insensitive checkbool exists = jobject->has_key("A", false); // returns true

How to create a JSON value?

auto object = new TinyJSON::TJValueObject();
object->set_string("a", "Hello");
object->set_string("b", "World");
object->set_string("c", "Bye");
object->set_boolean("d", true);
object->set_float("e", 42.15);
auto dump = object->dump();
/* { "a": "Hello", "b": "World", "c": "Bye", "d": true, "e": 42.15 }*/

You can also remove a value

Write a JSON string

auto object = new TinyJSON::TJValueObject();
object->set_string("a", "Hello");
object->set_string("b", "World");
object->set_string("c", "Bye");
object->set_boolean("d", true);
object->pop("b");
auto dump = object->dump();
/* { "a": "Hello", "b": "World", "c": "Bye", "d": true }*/

To write a JSON string you simply need to call the method write_file on the JSON object returned.

auto json = TinyJSON::TJ::parse( "{ \"Hello\" : \"World\" }" );
if( TinyJSON::TJ::write_file("file.json", *json))
{
// all good
}
else
{
// something broke
}
delete json;

UTF-8 DOM

Regardless if you are parsing a file or parsing a string, TinyJSON will parse the file for UTF-8 DOM if there is one.

Using a JSON string

While you can dump a string to (re)write a json string you might want to use it directly in your code.

auto json = TinyJSON::TJ::parse( R"("This is a test \" with a quote")" );
auto actual_string = json->dump_string(); /* This is a test " with a quote*/delete json;

The formatting types are

 TinyJSON::formatting::indented
TinyJSON::formatting::minify

Objects

Each objects are read into TJValue* classes of type TJValueObject.

auto json = TinyJSON::TJ::parse( "{ \"Hello\" : \"World\" }" );
auto value = json->try_get_string("Hello"); // "World"auto no_value = json->try_get_string("Life"); // nulldelete json;

or

auto json = TinyJSON::TJ::parse( "{ \"Hello\" : \"World\" }" );
auto value = json->get_string("Hello"); // "World"auto no_value = json->get_string("Life"); // ""delete json;

Adding values to an object

You can dynamically create a new object and then add a named values to it.

auto object = new TinyJSON::TJValueObject();
object->set_number("a", 42);
object->set_float("b", 0.005);
object->set_null("c");
...
delete json;

Arrays

Each arrays are read into TJValue* classes of type TJValueArray. Then each items in the array are also TJValue* of type string, number and so on.

auto json = TinyJSON::TJ::parse( "[ 12, 14, 16 ]" );
auto array_of_values = dynamic_cast<TinyJSON::TJValueArray*>(json);
auto number_of_items = array_of_values->get_number_of_items(); // 3auto value1 = array_of_values->at(0); //14auto value2 = array_of_values->at(2); //16auto value3 = array_of_values->at(5); // nulldelete json;

Adding values to an arrays

You can dynamically create a new array and then add string, numbers and so on.

auto json = new TinyJSON::TJValueArray();
json->add_boolean(true);
json->add_boolean(false);
json->add_number(42);
...
delete json;

Removing values from an array

You can remove an item at a certain position using remove_at(index).

auto json = new TinyJSON::TJValueArray();
json->add_string("Hello");
json->add_string("Tiny");
json->add_string("World");
// Remove "Tiny" at index 1
json->remove_at(1);
...
delete json;

Data type

Each TJValue* item can be of different type

Assuming the array below with multiple items, you can query the type of each TJValue* and do something accordingly.

auto json = TinyJSON::TJ::parse( "[ ... ]" );
auto array_of_values = dynamic_cast<TinyJSON::TJValueArray*>(json);
auto value = array_of_values->at(0);
if(value->is_object()) { /**/}
if(value->is_array()) { /**/}
if(value->is_string()) { /**/}
if(value->is_number()) { /**/}
if(value->is_true()) { /**/}
if(value->is_false()) { /**/}
if(value->is_null()) { /**/}
delete json;

Iterate values

auto json = TinyJSON::TJ::parse(R"( 1, 2, 3 ])");
for (auto& a : *json)
{
// do stuff
}
delete json;
...

NB: You can technically everything...

auto json = TinyJSON::TJ::parse("2.5");
for (auto& a : *json)
{
// do stuff
}
...
delete json;

Get values

Generic Get values

The generic get<...>( ... ) method provides a convenient way to retrieve values of various types directly.

For TJValueObject (key-based):

auto json = TinyJSON::TJ::parse(R"({"a": 42, "b": "hello", "c": true})");
auto obj = dynamic_cast<TJValueObject*>(json);
int a = obj->get<int>("a"); // 42
std::string b = obj->get<std::string>("b"); // "hello"bool c = obj->get<bool>("c"); // true

Get values with default

The get_or<...>(key, default_value) method allows you to specify a default value if the key is not found or the type is incorrect.

auto json = TinyJSON::TJ::parse(R"({"a": 42})");
auto obj = dynamic_cast<TJValueObject*>(json);
int a = obj->get_or<int>("a", 0); // 42int b = obj->get_or<int>("b", 100); // 100 (key not found)
std::string c = obj->get_or<std::string>("c", "default"); // "default"

For any TJValue* (direct value):

auto val = obj->try_get_value("a");
int a = val->get<int>(); // 42

The generic get also supports std::vector for arrays of numbers or floats:

auto json = TinyJSON::TJ::parse(R"({"ints": [1, 2, 3], "floats": [1.1, 2.2]})");
auto obj = dynamic_cast<TJValueObject*>(json);
```cpp
auto ints = obj->get<std::vector<int>>("ints");
auto doubles = obj->get<std::vector<double>>("floats");

Strict Get values

Getter methods on TJValue (or through TJValueObject keys) can be used to retrieve specific types. By default, these methods are non-strict and return default values if the type is incorrect. By setting strict: true in parse_options, these methods will throw a TJParseException instead. If a key is not found when calling try_get_string, get_*(..), or get<>(..), a warning callback is triggered with a message indicating the key that was not found (e.g. "The key 'missing' was not found!") if a callback function is registered in parse_options.

  • get_number()
  • get_float()
  • get_string()
  • get_boolean()
  • get_numbers()
  • get_floats()
TinyJSON::parse_options options;
options.strict = true;
options.throw_exception = true;
auto json = TinyJSON::TJ::parse(R"( { "a": true, "b": 123 })", options
);
auto jobject = dynamic_cast<TinyJSON::TJValueObject*>(json);
auto valuea = jobject->get_boolean("a"); // returns truetry {
auto valueb = jobject->get_string("b"); // THROW! "b" is a number, not a string
} catch (const TinyJSON::TJParseException& e) {
// Handle error
}

Set values

Generic Set values

The generic set<...>( ... ) method provides a convenient way to set values of various types directly.

For TJValueObject (key-based):

TinyJSON::TJValueObject obj;
obj.set("a", 42); // set int
obj.set("b", "hello"); // set string
obj.set("c", true); // set boolean
obj.set("d", 3.14); // set double

The generic set also supports std::string and std::vector for arrays of numbers or floats:

TinyJSON::TJValueObject obj;
std::string val = "hello";
obj.set("b", val); // set std::string
std::vector<int> ints = {1, 2, 3};
obj.set("ints", ints); // set std::vector<int>

Strict Set values

You can also use specific set methods:

  • set_number(key, value)
  • set_float(key, value)
  • set_string(key, value)
  • set_boolean(key, value)
  • set_null(key)
TinyJSON::TJValueObject obj;
obj.set_number("a", 42);
obj.set_string("b", "hello");
obj.set_boolean("c", true);
obj.set_null("d");

Getting Started

TinyJSON is designed to be as simple to integrate as possible.

1. Simple Drop-in

You can simply copy src/TinyJSON.h and src/TinyJSON.cpp directly into your project.

2. CMake add_subdirectory

Clone the repository into your project (e.g., in a third_party/ directory) and add it to your CMakeLists.txt:

add_subdirectory(third_party/TinyJSON)
target_link_libraries(your_targetPUBLICTinyJSON)

3. CMake FetchContent

You can automatically download and build TinyJSON using CMake's FetchContent:

include(FetchContent)
FetchContent_Declare(
TinyJSON
GIT_REPOSITORY https://github.com/FFMG/TinyJSON.git
GIT_TAG v0.2.2 # or main
)
FetchContent_MakeAvailable(TinyJSON)
target_link_libraries(your_targetPUBLICTinyJSON)

Quick Start Example

Here is the absolute minimum code needed to parse a JSON string and read a value:

#include"TinyJSON.h"
#include<iostream>intmain() {
// 1. Parse a stringauto json = TinyJSON::TJ::parse(R"({"name": "TinyJSON", "fast": true})");
// 2. Read valuesauto obj = dynamic_cast<TinyJSON::TJValueObject*>(json);
if (obj) {
std::cout << "Library: " << obj->get_string("name") << std::endl;
std::cout << "Fast? " << (obj->get_boolean("fast") ? "Yes" : "No") << std::endl;
}
// 3. Clean updelete json;
return0;
}

Building and testing the project

  • Clone this repository
  • init the submodules git submodule --init --recursive

Data Range

Numbers

The whole number ranges are +9223372036854775807 and -9223372036854775806

TODO

  • Make sure that all the code follow our own coding standards.
  • [] Update comments
  • Finish documentation how to use the code.
  • [] Run/Create some benchmark tests, make sure they are up to date.
  • Arrays
  • Objects
  • Values
  • More tests!
  • Add version number (started at version 0.0.1)
  • Copyright
  • Add 2 kinds of error handling, either throw or return an error structure.
  • [] While we do not care about size, (on paper), it would be nice to implement limits in the code.
    • depth
    • [] string
    • [] numbers
  • Automated build
  • Run on linux/gcc/g++ or something other than visual studio. g++ -std=c++11 -Wall -Wextra -Werror -O3 src/tinyJSON.cpp -o a.exe
  • We need to add copy and move constructors to TJValue and the derived classes.
  • [] Add Macro(s) explanation like TJ_INCLUDE_STD_STRING for example.
  • Add support for JSON5 https://json5.org 📄 https://github.com/json5/json5

Supported CPP

The supported versions of c++ are c++ 11 and later.

About

TinyJSON: A high-performance, zero-dependency C++11 library for RFC 8259 and JSON5. Engineered for speed and minimal memory footprint.

Topics

Resources

Contributing

Security policy

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages