# JSON Library

JSON is a data interchange format that can be used to transmit data objects as human readable text. The innovaphone apps use JSON for all websocket protocols. This library can be used to encode and decode JSON in C++.

# File information

File | common/ilib/json.h
Overview
Classes | json_io
Defines | JSON_TYPE_OBJECT JSON_TYPE_ARRAY JSON_TYPE_VALUE JSON_TYPE_CONTENT_PACKET JSON_TYPE_ANY JSON_FLAG_QUOTED JSON_FLAG_INCOMPLETE JSON_FLAG_COMPLETE JSON_ID_ROOT JSON_ID_NONE
Examples | Encoding Decoding

# Overview

For information about the JSON structure and semantic, please refer to the RFC8259 article.
This current article explains the concepts of the JSON library by innovaphone

This library requires you to follow a specific order when adding properties to a JSON document. The document can be visualized as a tree structure, with each level representing either an object or an array. To add properties to an object, you must first add the object to the current level of the tree. Then, add all the properties to the object before moving to the next level. It's not possible to add another property to the same level as the object until all the properties have been added to the object.

Most code explaination will be refering to this JSON Object

    {
        "name": "John Doe",
        "age": 30,
        "interests": [
            "programming",
            "tv series",
            "cooking"
        ],
        "address": {
            "street": "123 Street",
            "city": "City of New State",
            "state": "New State"
        },
        "email": "john.doe@aol.com"
    }

The json_io class can be used for encoding and decoding JSON messages to or from a char buffer.

Each element has a unique numeric ID `word base`.
`JSON_ID_ROOT` represents the top level element. It can be no or a single element. Often the root is an object that holds all the other data. Normally json_io can be used as a stack variable.
A typical encoding flow looks like this:

    char message[512];
    json_io json(message);
    word base = json.add_object(JSON_ID_ROOT, 0);
    // add elements
    json.encode();

Decoding is usually done like this:

    json_io json(message);
    json.decode();
    word base = recv.get_object(JSON_ID_ROOT, 0);
    // read elements

There are two different methods for traversing the JSON structure:
Inside objects the elements are referenced by their name.

    // adding elements
    json.add_string(base, "name", "John Doe");
    // reading elements
    const char * name = json.get_string(base, "name");

Inside arrays the elements are enumerated.

    // adding elements
    json.add_string(base, 0, "programming");
    json.add_string(base, 0, "tv series");
    json.add_string(base, 0, "cooking");
    // reading elements
    word last = 0;
    do {
        const char * interest = json.get_string(base, last);
    }
    while (last != JSON_ID_NONE);

Some add functions need an additional buffer for storing the values temporarily. Those buffers are called `char * & tmp` in the interface. Note that the buffer pointer reference is increased when adding an element.

    char temp[128];
    char * t = temp;
    json.add_attrib_printf(base, "name", t, "%s %s", "John", "Doe");
    json.add_unsigned(base, "age", 30, t);

### Chunked decoding

Sometimes JSON objects exceed the limits of json_io, so that they cannot be decoded completely in one step. In this case chuncked decoding can be used. Chunked decoding works if on some level of the JSON object a list exists, either as array or as object, which each element of this list not exceeding the limits.

Please check the JSON chunked decoding tutorial for more information.

# Classes

## json_io

        class json_io {
        public:

        json_io(char * buffer);

        void reset();
        bool decode();
        dword encode();
        dword encode(word handle, char * buffer);
        void write(word current, char * & p, word incomplete = 0xffff);
        void dump();

        word add(byte type, byte flags, word base, const char* name, const char* info, dword len = 0xffffffff);
        word add_object(word base, const char * name);
        word add_array(word base, const char * name);
        void add_string(word base, const char * name, const char * value, dword len=0xffffffff);
        void add_string(word base, const char * name, const word * value, dword len, char * & tmp);
        void add_string(word base, const char * name, const word * value, char * & tmp) { add_string(base, name, value, 0xffffffff, tmp); };
        void add_replace_string(word base, const char * name, const char * value, dword len=0xffffffff);
        void add_int(word base, const char * name, int c, char * & tmp);
        void add_unsigned(word base, const char * name, dword c, char * & tmp);
        void add_long64(word base, const char * name, long64 c, char * & tmp);
        void add_ulong64(word base, const char * name, ulong64 c, char * & tmp);
        void add_bool(word base, const char * name, bool value);
        void add_null(word base, const char * name);
        void add_double(word base, const char * name, double c, char *& tmp, byte decimalPlaces = 6);

        void add_printf(word base, const char * name, char * & tmp, const char * format, ...);
        void add_printfv(word base, const char * name, char * & tmp, const char * format, va_list ap);
        void add_hexstring(word base, const char * name, const byte * hex, word hex_len, char * & tmp);
        void add_json(word base, const char * name, const char * value, dword len=0xffffffff);

        char* get_buffer()
        void set_buffer(char* buffer)

        word get_object(word base, const char * name);
        word get_object(word base, word & last);
        word get_array(word base, const char * name);
        word get_array(word base, word & last);
        const char * get_string(word base, const char * name, bool * present=0);
        const char * get_string(word base, word & last, bool * present=0);
        int get_int(word base, const char * name, bool * present=0);
        int get_int(word base, word & last, bool * present=0);
        dword get_unsigned(word base, const char * name, bool * present=0);
        dword get_unsigned(word base, word & last, bool * present=0);
        long64 get_long64(word base, const char * name, bool * present = 0);
        long64 get_long64(word base, word & last, bool * present = 0);
        ulong64 get_ulong64(word base, const char * name, bool * present = 0);
        ulong64 get_ulong64(word base, word & last, bool * present = 0);
        bool get_bool(word base, const char * name, bool * present=0);
        bool get_bool(word base, word & last, bool * present=0);
        bool get_bool_int(word base, const char * name, int & iret, byte * present=0);
        double get_double(word base, const char * name, bool * present = 0);
        double get_double(word base, word & last, bool * present = 0);

        byte get_flags(word handle);
        word get_next(word base, word last, byte & type, byte & flags, const char * & name, const char * & info);
        word get_index();
        const char * get_name(word handle);
        const char * get_info(word handle);
        word get_count(word handle);
        const char* get_value(word base, byte flags, const char* name, bool * present=0);
        const char* get_value(word base, byte flags, word& last, bool * present=0);

        void trace(class debug_printf * dbg, word base, word level = 0);
        word to_url(word base, char * b, word l, const char * prefix = 0, bool cont = false);

        char * last;
        char * name_last;
        char * incomplete;
        unsigned max_item;

        };

### Public functions

json_io(constructor)
  Initializes the json_io structure.

  #### Parameters

  char * buffer | The buffer for the message.

  #### Remarks

  The buffer is mandatory for decoding. For encoding it is optional but if it's null a buffer must be passed to the encode function. Make sure it is big enough to contain the whole message. Note that the buffer will be modified for both encoding and decoding.
reset
  Resets the internal state of the json_io structure. All added or parsed elements will be cleared from the internal state.
decode
  Decodes the buffer overloaded to the constructor, as JSON.

  #### Return value

  bool | 1 if decoding was successful, 0 if not

encode
  Encodes the data structure into a null-terminated JSON string and writes it to the buffer specified with the constructor.

  #### Return value

  dword | The size of the encoded message.

encode (overloaded)
  Encodes a subtree of the data structure into a null-terminated JSON string and writes it to the specified buffer.

  #### Parameters

  word handle | The ID of the root element of the subtree.
  char * buffer | The buffer for the message.

  #### Return value

  dword | The size of the encoded message.

write
  This function is used internally but it can also be used to encode the data structure to a JSON string in several chunks.

  #### Parameters

  word current | The ID of the start element. Use 0 for complete data.
  char *& p | The output buffer.
  word incomplete | The incomplete argument can be used to write only the incomplete data so that new received data can be appended to the buffer an decoding started again. The incomplete argument should be the handle of the descriptor of the array, with potential incomplete elements.

dump
  This function can be used to print the JSON string in a preset format:

  base=<unique numeric identifier, pointer to base address>

  count=<length of property value>

  flags=<flags of elements>

      json.dump();
      OUTPUT:
      base=65535 count=11 flags=0 OBJECT=(NULL)/(NULL)
      base=0 count=8 flags=1 VALUE=name/John Doe
      base=0 count=2 flags=0 VALUE=age/30
      base=0 count=3 flags=0 ARRAY=interests/(NULL)
      base=3 count=11 flags=1 VALUE=(NULL)/programming
      base=3 count=9 flags=1 VALUE=(NULL)/tv series
      base=3 count=7 flags=1 VALUE=(NULL)/cooking
      base=0 count=3 flags=0 OBJECT=address/(NULL)
      base=7 count=10 flags=1 VALUE=street/123 Street
      base=7 count=17 flags=1 VALUE=city/City of New State
      base=7 count=9 flags=1 VALUE=state/New State
      base=0 count=16 flags=1 VALUE=email/john.doe@aol.com

add
  The function creates a new JSON element based on the provided parameters and adds it to the JSON structure under the specified base.

  #### Parameters

  byte type | The type of JSON element to be added
  wordflags | Additional flags that can be used to modify the behavior of the added element, such as JSON_FLAG_QUOTED, which indicates that the value should be quoted.
  wordbase | A reference point in the JSON object hierarchy where the new element should be added.
  const char*name | The name of the JSON element to be added. This is applicable for objects and values.
  const char*info (optional) | The length of the info parameter, if applicable. If not provided, the default value is 0xffffffff.

  #### Return value

  word | The ID of the added object, representing the reference to the newly added JSON element in the structure. Can be used to add elements to the object.

  #### Remarks

  If the object shall be added to root level, use JSON_ID_ROOT as the base.
add_object
  Adds an object to the structure.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the new element should be added.
  const char * name | The name of the object. Only used when the object is inside another object. Set to 0 otherwise.

  #### Return value

  word | The ID of the added object. Can be used to add elements to the object.

  #### Remarks

  If the object shall be added to root level, use JSON_ID_ROOT as the base.
add_array
  Adds an array to the structure.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the new element should be added.
  const char * name | The name of the array. Only used when the array is inside an object. Set to 0 otherwise.

  #### Return value

  word | The ID of the added array. Can be used to add elements to the array.

  #### Remarks

  If the array shall be added to root level, use JSON_ID_ROOT as the base.
add_string (overloaded)
  Adds an UTF-8 string to the structure.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the new element should be added.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  const char * value | The value of the element. If value is 0 the element is not added.
  dword len | The number of bytes in the value buffer. Only needed if value is not null-terminated.

add_string (overloaded)
  Adds a string with 16-bit character representation to the structure.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the new element should be added.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  const word * value | The value of the element. If value is 0 the element is not added.
  dword len | The number of bytes in the value buffer. Only needed if value is not null-terminated.

add_replace_string
  Adds or replaces an existing UTF-8 string inside an object.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the new element should be added.
  const char * name | The name of the element (mandatory).
  const char * value | The value of the element.
  dword len | The number of bytes in the value buffer. Only needed if value is not null-terminated.

  #### Remarks

  The function is only implemented for strings inside objects.
add_int
  Adds a 32-bit signed integer to the structure.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the new element should be added.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  int c | The value of the element.
  char * & tmp | The temporary buffer to store the value until it's encoded.

add_unsigned
  Adds a 32-bit unsigned integer to the structure.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the new element should be added.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  unsigned c | The value of the element.
  char * & tmp | The temporary buffer to store the value until it's encoded.

add_long64
  Adds a 64-bit signed integer to the structure.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the new element should be added.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  long64 c | The value of the element.
  char * & tmp | The temporary buffer to store the value until it's encoded.

add_ulong64
  Adds an 64-bit unsigned integer to the structure.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the new element should be added.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  ulong64 c | The value of the element.
  char * & tmp | The temporary buffer to store the value until it's encoded.

add_bool
  Adds a boolean to the structure.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the new element should be added.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  bool value | The value of the element.

add_null
  Adds a null value to the structure.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the new element should be added.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.

add_double
  Adds a double value to the structure.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the new element should be added.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  double c | The value of the element.
  char * & tmp | The temporary buffer to store the value until it's encoded.
  byte decimalPlaces = 6 | The decimal places after the period.

add_printf
  Does an sprintf to a temporary buffer and adds the resulting string to the structure.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the new element should be added.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  char * & tmp | The temporary buffer to store the value until it's encoded.
  const char * format | A standard sprintf format string.
  ... | Additional parameters to be used by sprintf as defined in the format string.

add_printfv
  Does an sprintf to a temporary buffer and adds the resulting string to the structure. Uses va_list datatype for passing the arguments.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the new element should be added.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  char * & tmp | The temporary buffer to store the value until it's encoded.
  const char * format | A standard sprintf format string.
  va_list ap | Additional parameters declared as va_list to be used by sprintf as defined in the format string.

add_hexstring
  Converts a binary buffer to a hex string and adds it to the structure, encoded as a JSON string.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the new element should be added.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  const byte * hex | Arbitrary binary data.
  word hex_len | The number of bytes in the hex buffer.
  char * & tmp | The temporary buffer to store the value until it's encoded.

add_json
  Adds a raw JSON string to the structure. The string must have valid encoding. It will not be escaped by the library.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the new element should be added.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  const char * value | The JSON string to be added.
  dword len | The number of bytes in value. Only needed if value is not null-terminated.

get_object (overloaded)
  Gets an object by name.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.

  #### Return value

  word | The ID of the object or JSON_ID_NONE if it's not found.

get_object (overloaded)
  Gets the next object from an array.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  word & last | A word reference that must have the value 0 for the first call. The value will be updated by the function call for each subsequent call. If the value is JSON_ID_NONE the end of the array is reached.

  #### Return value

  word | The ID of the object or JSON_ID_NONE if there are no more objects in the array.

get_array (overloaded)
  Gets an array by name.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.

  #### Return value

  word | The ID of the array or JSON_ID_NONE if it's not found.

get_array (overloaded)
  Gets the next array from an array.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  word & last | A word reference that must have the value 0 for the first call. The value will be updated by the function call for each subsequent call. If the value is JSON_ID_NONE the end of the array is reached.

  #### Return value

  word | The ID of the array or JSON_ID_NONE if there are no more objects in the array.

get_string (overloaded)
  Gets a string by name.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.

  #### Return value

  const char * | The value of the string or 0 if it's not found.

get_string (overloaded)
  Gets the next string from an array.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  word & last | A word reference that must have the value 0 for the first call. The value will be updated by the function call for each subsequent call. If the value is JSON_ID_NONE the end of the array is reached.

  #### Return value

  const char * | The value of the string or 0 if there are no more objects in the array.

get_int (overloaded)
  Gets a 32-bit signed integer by name.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  bool * present | If specified, the value will be set to true if the element existed. false otherwise.

  #### Return value

  int | The value of the element or 0 if it's not found.

get_int (overloaded)
  Gets the next 32-bit signed integer from an array.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  word & last | A word reference that must have the value 0 for the first call. The value will be updated by the function call for each subsequent call. If the value is JSON_ID_NONE the end of the array is reached.
  bool * present | If specified, the value will be set to true if the element existed. false otherwise.

  #### Return value

  int | The value of the element or 0 if there are no more objects in the array.

get_unsigned (overloaded)
  Gets a 32-bit unsigned integer by name.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  bool * present | If specified, the value will be set to true if the element existed. false otherwise.

  #### Return value

  dword | The value of the element or 0 if it's not found.

get_unsigned (overloaded)
  Gets the next 32-bit unsigned integer from an array.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  word & last | A word reference that must have the value 0 for the first call. The value will be updated by the function call for each subsequent call. If the value is JSON_ID_NONE the end of the array is reached.
  bool * present | If specified, the value will be set to true if the element existed. false otherwise.

  #### Return value

  dword | The value of the element or 0 if there are no more objects in the array.

get_long64 (overloaded)
  Gets a 64-bit signed integer by name.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  bool * present | If specified, the value will be set to true if the element existed. false otherwise.

  #### Return value

  long64 | The value of the element or 0 if it's not found.

get_long64 (overloaded)
  Gets the next 64-bit signed integer from an array.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  word & last | A word reference that must have the value 0 for the first call. The value will be updated by the function call for each subsequent call. If the value is JSON_ID_NONE the end of the array is reached.
  bool * present | If specified, the value will be set to true if the element existed. false otherwise.

  #### Return value

  long64 | The value of the element or 0 if there are no more objects in the array.

get_ulong64 (overloaded)
  Gets a 64-bit unsigned integer by name.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  bool * present | If specified, the value will be set to true if the element existed. false otherwise.

  #### Return value

  ulong64 | The value of the element or 0 if it's not found.

get_ulong64 (overloaded)
  Gets the next 64-bit unsigned integer from an array.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  word & last | A word reference that must have the value 0 for the first call. The value will be updated by the function call for each subsequent call. If the value is JSON_ID_NONE the end of the array is reached.
  bool * present | If specified, the value will be set to true if the element existed. false otherwise.

  #### Return value

  ulong64 | The value of the element or 0 if there are no more objects in the array.

get_bool (overloaded)
  Gets a boolean by name.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  bool * present | If specified, the value will be set to true if the element existed. false otherwise.

  #### Return value

  bool | The value of the element or false if it's not found.

get_bool (overloaded)
  Gets the next boolean from an array.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  word & last | A word reference that must have the value 0 for the first call. The value will be updated by the function call for each subsequent call. If the value is JSON_ID_NONE the end of the array is reached.
  bool * present | If specified, the value will be set to true if the element existed. false otherwise.

  #### Return value

  bool | The value of the element or false if there are no more objects in the array.

get_bool_int (overloaded)
  Gets a boolean or integer by name.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  int & iret | Returns the integer value
  bool * present | If specified, the value will be set to 1 if the element existed and is bool, 2 if the value existed and is integer. Set to 0 otherwise

  #### Return value

  bool | The value of the element or false if it's not found.

get_double (overloaded)
  Gets a double value by name.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  const char * name | The name of the element. Only used when it's is inside an object. Set to 0 otherwise.
  bool * present | If specified, the value will be set to true if the element existed. false otherwise.

  #### Return value

  double | The value of the element or 0 if it's not found.

get_double (overloaded)
  Gets the next double value from an array.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  word & last | A word reference that must have the value 0 for the first call. The value will be updated by the function call for each subsequent call. If the value is JSON_ID_NONE the end of the array is reached.
  bool * present | If specified, the value will be set to true if the element existed. false otherwise.

  #### Return value

  double | The value of the element or 0 if there are no more objects in the array.

get_flags (overloaded)
  Gets the flags of an given element

  #### Parameters

  word handle | The ID of the element.

  #### Return value

  double | The flags. The only relevant flag is JSON_FLAG_INCOMPLETE. It indicates that the element using chunked decoding is not yet complete and should not be processed.

to_url
  Helper function to encode the structure not as JSON but as URL arguments.

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  char * b | The output buffer.
  word l | The size of the output buffer.
  const char * prefix | Prefix to be used for the single elements. For elements nested within arrays or objects another prefix of the name of the array/object is added. The prefixes are sepearted by '.'
  bool cont | true indicates that the arguments are to be added to other arguments. This means a '&' is put at the beginning

  #### Return value

  word | The number of bytes that have been written to the output buffer.

get_index
  Gets the total number of variables in the object, including the root element.

  #### Return value

  word | The total number of variables.

get_name
  Gets the string value of the passed argument.

  #### Parameters

  word handle | Typically represents the key of the JSON-property and serves as a unique identifier for the corresponding structure or substructure.

  #### Return value

  const char* | The key name.

get_info
  Gets the value from the JSON key-value pair.

  #### Parameters

  word handle | Typically represents the key of the JSON-property and serves as a unique identifier for the corresponding structure or substructure.

  #### Return value

  const char* | The value of the corresponding key in a JSON key-value pair, if value is nonexistent NULL is returned

get_count
  Gets the length of info.

  #### Return value

  word | The count of info.

get_next
  Gets the next JSON element

  #### Parameters

  word base | A reference point in the JSON object hierarchy where the element should be searched.
  word last | A word reference that must have the value 0 for the first call. The value will be updated by the function call for each subsequent call. If the value is JSON_ID_NONE the end of the array is reached.
  byte& type | The expected type of the next element. If the type of upcoming element does not match, that element will be ignored.
  byte& flags | A flag indicating the expected data type of the value to be extracted (e.g., 0x01 for a string value).
  const char* name | Pointer to buffer, in which the next elements name(key) will be saved.
  const char* info | Pointer to buffer, in which the next elements string info will be saved.

  #### Return value

  word | The id of the next JSON element.

get_value
  The function searches the JSON string for a value that matches the specified flags and position in the hierarchy. If found, it returns a pointer to a constant character array representing the extracted value.

  #### Parameters

  word base | A reference point in the JSON object hierarchy from where the search for the value should begin.
  byte& flags | A flag indicating the expected data type of the value to be extracted (e.g., 0x01 for a string value).
  const char* name | The function searches the JSON string for a value that matches the specified name and flags, and is present within the object hierarchy starting from the given base.
  bool* (optional) name | A pointer to a boolean variable that can be used to store whether the value was found in the JSON string or not.

  #### Return value

  const char* | If found, it returns a pointer to a constant character array representing the extracted value.

get_value
  The function searches the JSON string for a value that matches the specified flags and position in the hierarchy. If found, it returns a pointer to a constant character array representing the extracted value.

  #### Parameters

  word base | A reference point in the JSON object hierarchy from where the search for the value should begin.
  byte& flags | A flag indicating the expected data type of the value to be extracted (e.g., 0x01 for a string value).
  word last | A word reference that must have the value 0 for the first call. The value will be updated by the function call for each subsequent call. If the value is JSON_ID_NONE the end of the array is reached.
  bool* (optional) name | A pointer to a boolean variable that can be used to store whether the value was found in the JSON string or not.

  #### Return value

  const char* | If found, it returns a pointer to a constant character array representing the extracted value.

get_buffer
  Gets the buffer of the current JSON object.

  #### Return value

  char* | The buffer of the object.

set_buffer
  Sets the buffer of the current JSON object.

  #### Parameters

  char* buffer | The buffer to be set.

trace
  Prints the base JSON object in the self implemented form inside iprintf function.

  #### Parameters

  class debug_printf *dbg | A pointer to the object of the class debug_printf in which the iprintf function should be implemented
  wordbase | A reference point in the JSON object hierarchy.
  word level (optional) | A word reference that sets the verbose level of the trace.

# Variables

char *last
  A pointer to the last character encountered during JSON parsing or processing.
char *name_last
  A pointer to the last character of the name of a JSON object or value.
char *incomplete
  A pointer to an incomplete JSON element (e.g., an object or array) that is still open and waiting for further elements or values, reference to JSON_FLAG_INCOMPLETE.
unsigend max_item
  The maximum number of items, reference to JSON_MAX_ITEM.

# Data types

## Defines

JSON_MAX_ITEM | Represents the maximum number of items.
JSON_TYPE_OBJECT | Represents a JSON object.
JSON_TYPE_ARRAY | Represents a JSON array.
JSON_TYPE_VALUE | Represents a JSON value.
JSON_TYPE_CONTENT_PACKET | Represents a content packet in the JSON structure.custom data type that might be used by specific applications or libraries to store additional information or metadata related to the JSON structure.
JSON_TYPE_ANY | Represents any JSON element type.
JSON_FLAG_QUOTED | This flag indicates that a JSON value should be treated as a quoted string..
JSON_FLAG_INCOMPLETE | This flag indicates that a JSON element, such as an object or an array, is not yet complete and may have more elements or values added to it in the future.
JSON_FLAG_COMPLETE | This flag indicates that a JSON element, such as an object or an array, is complete and no more elements or values will be added to it.
JSON_ID_ROOT | Represents the top-level element.
JSON_ID_NONE | Used if an element is not found.

# Code Examples

The following examples demonstrate the library on the following JSON structure.

    {
        "name": "John Doe",
        "age": 30,
        "interests": [
            "programming",
            "tv series",
            "cooking"
        ],
        "address": {
            "street": "123 Street",
            "city": "City of New State",
            "state": "New State"
        },
        "email": "john.doe@aol.com"
    }

## Encoding

    char message[512];
    char temp[64];
    json_io json(message);
    char* t = temp;
    word base = json.add_object(JSON_ID_ROOT, 0);
    json.add_string(base, "name", "John Doe");
    json.add_unsigned(base, "age", 30, t);

    word interests = json.add_array(base, "interests");
    json.add_string(interests, nullptr, "programming");
    json.add_string(interests, nullptr, "tv series");
    json.add_string(interests, nullptr, "cooking");

    word address = json.add_object(base, "address");
    json.add_string(address, "street", "123 Street");
    json.add_string(address, "city", "City of New State");
    json.add_string(address, "state", "New State");

    json.add_string(base, "email", "john.doe@aol.com");

    json.add_string(interests, nullptr, "fishing"); // this will have no effect, cause "interests" handle is not valid any more

    json.encode();

## Decoding

    json_io json(message);
    json.decode();

    word base = json.get_object(JSON_ID_ROOT, 0);
    const char* name = json.get_string(base, "name");
    dword age = json.get_unsigned(base, "age");

    const char* interest_values[4];
    word interest_count = 0;
    word interests = json.get_array(base, "interests");
    word last = 0;

    while (last != JSON_ID_NONE && interest_count < 4) {
        const char* value = json.get_string(interests, last);
        if (value) {
            interest_values[interest_count++] = value;
        }
    }

    word address = json.get_object(base, "address");
    const char* street = json.get_string(address, "street");
    const char* city = json.get_string(address, "city");
    const char* state = json.get_string(address, "state");

    const char* email = json.get_string(base, "email");