Json For Embedded Systems (JFES)

Related tags

JSON jfes
Overview

JFES

Based on the jsmn project.

Json For Embedded Systems (JFES) is a minimalistic json engine written in plain C. It can be easily integrated into the code for embedded systems.

Features

  • compatible with C99
  • no dependencies (I'm serious!)
  • highly portable
  • you can use it as a json parser only
  • incremental single-pass parsing

API

Initializing

Before use you need to initialize the jfes_config_t object.

/** JFES config structure. */
typedef struct jfes_config {
    jfes_malloc_t           jfes_malloc;        /**< Memory allocation function. */
    jfes_free_t             jfes_free;          /**< Memory deallocation function. */
} jfes_config_t;

Below you can see the prototypes of the memory management functions:

/** Memory allocator function type. */
typedef void *(__cdecl *jfes_malloc_t)(jfes_size_t);

/** Memory deallocator function type. */
typedef void (__cdecl *jfes_free_t)(void*);

As you can see, these functions have the same prototype as the C standard library functions.

So, you can initialize JFES configuration with the following code:

#include <stdlib.h>

/* ...some useful stuff... */

jfes_config_t config;

config.jfes_malloc = malloc;
config.jfes_free = free;

But, if you need to use your own memory management functions, you can use them.

Parser (optional)

If you just need to parse a *.json file without allocating any values (like jsmn), you can parse a json string and separate it into tokens. In this case, you only need to use two functions below:

/**
    JFES parser initialization.
    \param[out]     parser              Pointer to the jfes_parser_t object.
    \param[in]      config              JFES configuration.
    \return         jfes_success if everything is OK.
*/
jfes_status_t jfes_init_parser(jfes_parser_t *parser, jfes_config_t *config);

/******************************************************************/

/**
    Run JSON parser. It parses a JSON data string into and
    array of tokens, each describing a single JSON object.
    \param[in]      parser              Pointer to the jfes_parser_t object.
    \param[in]      json                JSON data string.
    \param[in]      length              JSON data length.
    \param[out]     tokens              Tokens array to fill.
    \param[in, out] max_tokens_count    Maximal count of tokens in tokens array.
                                        Will contain tokens count.
    \return         jfes_success if everything is OK.
*/
jfes_status_t jfes_parse_tokens(jfes_parser_t *parser, const char *json,
    jfes_size_t length, jfes_token_t *tokens, jfes_size_t *max_tokens_count);

You can see a parsing example below.

Loading *.json into value

You can load any json data into jfes_value_t.

/** JSON value structure. */
struct jfes_value {
    jfes_value_type_t       type;               /**< JSON value type. */
    jfes_value_data_t       data;               /**< Value data. */
};

Value type (jfes_value_type_t) can be one of the following:

  • jfes_type_boolean
  • jfes_type_integer
  • jfes_type_double
  • jfes_type_string
  • jfes_type_array
  • jfes_type_object

And jfes_value_data_t is:

/** JFES value data union. */
typedef union jfes_value_data {
    int                     bool_val;           /**< Boolean JSON value. */

    int                     int_val;            /**< Integer JSON value. */
    double                  double_val;         /**< Double JSON value. */
    jfes_string_t           string_val;         /**< String JSON value. */

    jfes_array_t            *array_val;         /**< Array JSON value. */
    jfes_object_t           *object_val;        /**< Object JSON value. */
} jfes_value_data_t;

You can easily load a json string into the value by using the following code:

jfes_config_t config;
config.jfes_malloc = malloc;
config.jfes_free = free;

jfes_value_t value;
jfes_parse_to_value(&config, json_data, json_size, &value);
/* Do something with value */
jfes_free_value(&config, &value);

That's all!

Value modification

You can modify or create jfes_value_t with any of these functions:

jfes_value_t *jfes_create_boolean_value(jfes_config_t *config, int value);
jfes_value_t *jfes_create_integer_value(jfes_config_t *config, int value);
jfes_value_t *jfes_create_double_value(jfes_config_t *config, double value);
jfes_value_t *jfes_create_string_value(jfes_config_t *config, const char *value, jfes_size_t length);
jfes_value_t *jfes_create_array_value(jfes_config_t *config);
jfes_value_t *jfes_create_object_value(jfes_config_t *config);

jfes_value_t *jfes_get_child(jfes_value_t *value, const char *key, jfes_size_t key_length);
jfes_object_map_t *jfes_get_mapped_child(jfes_value_t *value, const char *key, jfes_size_t key_length);

jfes_status_t jfes_place_to_array(jfes_config_t *config, jfes_value_t *value, jfes_value_t *item);
jfes_status_t jfes_place_to_array_at(jfes_config_t *config, jfes_value_t *value, jfes_value_t *item, jfes_size_t place_at);
jfes_status_t jfes_remove_from_array(jfes_config_t *config, jfes_value_t *value, jfes_size_t index);

jfes_status_t jfes_set_object_property(jfes_config_t *config, jfes_value_t *value, jfes_value_t *item, const char *key, jfes_size_t key_length);
jfes_status_t jfes_remove_object_property(jfes_config_t *config, jfes_value_t *value, const char *key, jfes_size_t key_length);

Serializing to json string

You can serialize any jfes_value_t to string with one line (actually, three lines, but two of them are for help):

char dump[1024];
jfes_size_t dump_size = 1024;
jfes_value_to_string(&value, beauty_dump, &dump_size, 1);
beauty_dump[dump_size] = '\0';  /* If you need null-terminated string. */

dump_size will store the dump size. If you pass the fourth argument as 1, the dump will be beautified. And if 0, the dump will be ugly.

Examples

You can find examples here.

Licence

The MIT License (MIT)
See full text.

Comments
  • jfes_integer_to_string: static buffer

    jfes_integer_to_string: static buffer

    I don't like the idea of using a static buffer and returning a pointer to its contents. This results in the possibility of data corruption when jfes_integer_to_string() is called multiple times. Why don't allocate the memory dynamically?

    char *jfes_integer_to_string(int value) {
        static char buf[JFES_MAX_DIGITS + 3];
        char *p = &buf[0] + JFES_MAX_DIGITS + 2;
        ...
        return p;
    }
    
    opened by f2404 6
  • Confusing function names

    Confusing function names

    The description and the function name combination is confusing - I'd expect jfes_is_null() to return non-zero value if null, and zero otherwise. But, according to the description, the name should be more like jfes_is_not_null().

    /**
        Analyzes input string on the subject of whether it is null.
        \param[in]      data                Input string.
        \param[in]      length              Optional. Length of the input string.
                                            You can pass 0, if string is zero-terminated.
        \return         Zero, if input string not null. Otherwise anything.
    */
    static int jfes_is_null(const char *data, jfes_size_t length) {
    

    Same for

    static int jfes_is_boolean(const char *data, jfes_size_t length)
    
    opened by f2404 5
  • jfes.c issues part 2

    jfes.c issues part 2

    1. return jfes_memcmp(data, "null", 4) == 0; Better use strlen("null") instead of magic numbers.
    2. jfes_is_integer(): a. what about hexadecimal integers? b. why are you casting '0' and '9' from char to int? data[i] is char.
    3. jfes_is_double(): a. same question about casting; b. you don't need to use "else if" if the if block ends with "continue".
    4. jfes_string_to_integer() and jfes_string_to_double() just ignore non-number characters in input - is this the intended behavior?
    5. char *jfes_boolean_to_string(int value) { static char *true_value = "true"; static char *false_value = "false"; return value ? true_value : false_value; } Just 'return value ? "true" : "false";' Maybe it's worth to have defines for "true" and "false" to use them in such functions.
    opened by f2404 5
  • Enum and struct names overridden

    Enum and struct names overridden

    Some of the enum values are overridden by the struct names in jfes.h:

        jfes_string             = 0x05,             /**< String token type. */
        jfes_array              = 0x06,             /**< Array token type. */
        jfes_object             = 0x07,             /**< Object token type. */
    

    and

    typedef struct jfes_string {
    typedef struct jfes_array {
    typedef struct jfes_object {
    

    Suggest renaming them, e.g.

    typedef struct _jfes_string_t {
    ...
    } jfes_string_t;
    
    opened by f2404 4
  • Meson support for

    Meson support for "jfes".

    Hello 😀.

    I would like to provide support for Meson build system for the jfes library. If you're interested check out their site and documentation.

    Meson also has a dependency tool that downloads dependencies from third party venders like you. Developers using Meson would probably like to use a "[wrap-git]" file.

    opened by squidfarts 1
  • JFES_MAX_DIGITS question

    JFES_MAX_DIGITS question

    #define JFES_MAX_DIGITS                 64
    char *jfes_integer_to_string(int value) {
        static char buf[JFES_MAX_DIGITS + 1];
        return jfes_integer_to_string_r(value, &buf[0], JFES_MAX_DIGITS);
    }
    

    Why is the buffer so long? 11 chars (+1 for zero) would be enough for int.

    opened by f2404 1
  • Verify config->jfes_malloc and config->jfes_free against NULL

    Verify config->jfes_malloc and config->jfes_free against NULL

    Need to verify that config->jfes_malloc() or config->jfes_free() function pointers are not NULL before calling them. E.g. if (config->jfes_malloc) str->data = (char*)config->jfes_malloc(str->size);

    opened by f2404 1
  • jfes.c issues part 1

    jfes.c issues part 1

    1. You need to verify the pointers against NULL before dereferencing them in jfes_memcmp() and jfes_memcpy().
    2. static const void jfes_memcpy(const void *dst, const void *src, jfes_size_t count) *dst should not be const; return void should not be const as well.
    3. jfes_allocate_string(): what if malloc() fails? still returning success?
    4. I guess, pointers to jfes_malloc, jfes_free, jfes_memcpy functions should be verified against NULL before being called.
    5. jfes_is_null(const char *data, jfes_size_t length), jfes_is_boolean(const char *data, jfes_size_t length) Why do you need length parameter here? Better calculate data length within the function.
    enhancement 
    opened by f2404 1
  • main.c issues

    main.c issues

    1. int set_file_content(const char *filename, char *content, long content_size): a. signed content_size does not make sense; suggest using unsigned value; b. fwrite declaration: size_t fwrite( const void * ptrvoid, size_t size, size_t count, FILE * filestream) you have mixed up the 2nd and the 3rd parameters in your code; c. suggest using "const char *content"; d. suggest returning the return value of fwrite() call.
    2. int get_file_content(const char *filename, char *content, long *max_content_size): a. same as above - suggest using unsigned max_content_size; b. what's the point of this assignment? long fsize = ftell(f); long read_size = fsize; c. fread() parameters are also mixed up; d. you can write the fread() call return value into *max_content_size.
    enhancement 
    opened by f2404 1
  • SIGSEGV on freeing json value

    SIGSEGV on freeing json value

    http://mittorn.tk/clean2.json

    jfes_parse_to_value(&config, file, len, &root);
    jfes_free_value(&config, &root);
    
    Program received signal SIGSEGV, Segmentation fault.
    0x000055555557345a in jfes_free_value (config=0x7ffffff7cdd0, value=0x603000029f80) at jfes.c:1276
    1276                    jfes_value_t *item = value->data.array_val->items[i];
    (gdb) bt
    #0  0x000055555557345a in jfes_free_value (config=0x7ffffff7cdd0, value=0x603000029f80) at jfes.c:1276
    #1  0x0000555555573a4c in jfes_free_value (config=0x7ffffff7cdd0, value=0x60300002a040) at jfes.c:1293
    #2  0x0000555555573a4c in jfes_free_value (config=0x7ffffff7cdd0, value=0x60300002a1c0) at jfes.c:1293
    #3  0x0000555555573a4c in jfes_free_value (config=0x7ffffff7cdd0, value=0x60300002a310) at jfes.c:1293
    #4  0x0000555555573483 in jfes_free_value (config=0x7ffffff7cdd0, value=0x60300002a340) at jfes.c:1277
    #5  0x0000555555573a4c in jfes_free_value (config=0x7ffffff7cdd0, value=0x7ffffff7ce10) at jfes.c:1293
    
    opened by mittorn 1
  • This line should be modified

    This line should be modified

    https://github.com/lumimies18/jfes/blob/d4fb6b04b5792231236532ffc95fdb27439656d5/jfes.c#L1225 Hi, thank for your useful library, I found a bug in this line, you should replace "1024" with "length" so it uses the desired memory, if you use this library in RTOS and the task has low heap size it will return memory error.

    opened by amirparto1 0
  • Memleaks found

    Memleaks found

    jfes_value_t * json = jfes_create_object_value(&json_config);
      jfes_value_t * val = jfes_create_double_value(&json_config, value);
      jfes_status_t res = jfes_set_object_property(&json_config, json, val, "state", 5);
    
      if (res != jfes_success)
        return 0;
    
      jfes_value_to_string(json, output, &size, 0);
      
      output[size] = '\0';
      
      jfes_free_value(&json_config, json);
      
      struct mallinfo heapInf;
      heapInf=mallinfo();
      LOG_W("uordblks: 0x%X", heapInf.uordblks);
    

    This code has a memleak

    opened by MikhailNatalenko 1
  • Serious double serialisation bug

    Serious double serialisation bug

    There is a problem with jfes_double_to_string_r function. When you split fractional_value from real value, you forget about zeros. So 0.0007123132 turns to 0.7 after serialisation

    opened by MikhailNatalenko 0
Releases(v0.1.1-alpha.1)
  • v0.1.1-alpha.1(Oct 24, 2015)

    • Added parsing of hexadecimal and octal integers.
    • Added checks in the event of lack of memory.
    • Changed some arguments to optional.
    • Little code improvements and fixed some little bugs.
    Source code(tar.gz)
    Source code(zip)
  • v0.1.0-alpha.1(Oct 23, 2015)

    Features:

    • Parsing json format into tokens.
    • Creating jfes_value_t object from json string.
    • Modification jfes_value_t object as you want.
    • Saving jfes_value_t object to memory in text (beautiful or ugly).
    Source code(tar.gz)
    Source code(zip)
Owner
Eremin Dmitrii
Senior Software Developer
Eremin Dmitrii
A C++, header-only library for constructing JSON and JSON-like data formats, with JSON Pointer, JSON Patch, JSON Schema, JSONPath, JMESPath, CSV, MessagePack, CBOR, BSON, UBJSON

JSONCONS jsoncons is a C++, header-only library for constructing JSON and JSON-like data formats such as CBOR. For each supported data format, it enab

Daniel Parker 547 Jan 4, 2023
JSON parser and generator for C/C++ with scanf/printf like interface. Targeting embedded systems.

JSON parser and emitter for C/C++ Features ISO C and ISO C++ compliant portable code Very small footprint No dependencies json_scanf() scans a string

Cesanta Software 637 Dec 30, 2022
📟 JSON library for Arduino and embedded C++. Simple and efficient.

ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things). Features JSON deserialization Optionally decodes UTF-16 escape sequences t

Benoît Blanchon 6k Jan 3, 2023
json-cpp is a C++11 JSON serialization library.

JSON parser and generator for C++ Version 0.1 alpha json-cpp is a C++11 JSON serialization library. Example #include <json-cpp.hpp> struct Foo {

Anatoly Scheglov 7 Oct 30, 2022
This is a JSON C++ library. It can write and read JSON files with ease and speed.

Json Box JSON (JavaScript Object Notation) is a lightweight data-interchange format. Json Box is a C++ library used to read and write JSON with ease a

Anhero inc. 110 Dec 4, 2022
A convenience C++ wrapper library for JSON-Glib providing friendly syntactic sugar for parsing JSON

This library is a wrapper for the json-glib library that aims to provide the user with a trivial alternative API to the API provided by the base json-

Rob J Meijer 17 Oct 19, 2022
json-build is a zero-allocation JSON serializer compatible with C89

json-build is a zero-allocation JSON serializer compatible with C89. It is inspired by jsmn, a minimalistic JSON tokenizer.

Lucas Müller 31 Nov 16, 2022
Ultralightweight JSON parser in ANSI C

cJSON Ultralightweight JSON parser in ANSI C. Table of contents License Usage Welcome to cJSON Building Copying the source CMake Makefile Vcpkg Includ

Dave Gamble 8.3k Jan 4, 2023
C library for encoding, decoding and manipulating JSON data

Jansson README Jansson is a C library for encoding, decoding and manipulating JSON data. Its main features and design principles are: Simple and intui

Petri Lehtinen 2.7k Dec 31, 2022
JSON & BSON parser/writer

jbson is a library for building & iterating BSON data, and JSON documents in C++14. \tableofcontents Features # {#features} Header only. Boost license

Chris Manning 40 Sep 14, 2022
A very sane (header only) C++14 JSON library

JeayeSON - a very sane C++14 JSON library JeayeSON was designed out of frustration that there aren't many template-based approaches to handling JSON i

Jeaye Wilkerson 128 Nov 28, 2022
Jsmn is a world fastest JSON parser/tokenizer. This is the official repo replacing the old one at Bitbucket

JSMN jsmn (pronounced like 'jasmine') is a minimalistic JSON parser in C. It can be easily integrated into resource-limited or embedded projects. You

Serge Zaitsev 3.2k Jan 9, 2023
JSON for Modern C++

Design goals Sponsors Integration CMake Package Managers Pkg-config Examples JSON as first-class data type Serialization / Deserialization STL-like ac

Niels Lohmann 33.2k Jan 4, 2023
A JSON parser in C++

JSON++ Introduction JSON++ is a light-weight JSON parser, writer and reader written in C++. JSON++ can also convert JSON documents into lossless XML d

Hong Jiang 498 Dec 28, 2022
🗄️ single header json parser for C and C++

??️ json.h A simple single header solution to parsing JSON in C and C++. JSON is parsed into a read-only, single allocation buffer. The current suppor

Neil Henning 544 Jan 7, 2023
A C++ library for interacting with JSON.

JsonCpp JSON is a lightweight data-interchange format. It can represent numbers, strings, ordered sequences of values, and collections of name/value p

null 6.9k Dec 31, 2022
Very low footprint JSON parser written in portable ANSI C

Very low footprint JSON parser written in portable ANSI C. BSD licensed with no dependencies (i.e. just drop the C file into your project) Never recur

James McLaughlin 1.2k Jan 5, 2023
A tiny JSON library for C++11.

json11 json11 is a tiny JSON library for C++11, providing JSON parsing and serialization. The core object provided by the library is json11::Json. A J

Dropbox 2.4k Dec 31, 2022
A killer modern C++ library for interacting with JSON.

JSON Voorhees Yet another JSON library for C++. This one touts new C++11 features for developer-friendliness, an extremely slow-speed parser and no de

Travis Gockel 124 Oct 26, 2022