...
This section describes how to use the library.
Online Resources
https://www.json.org/json-en.htm– - Formal description of JSON syntax.
...
https://github.com/cesanta/mjso– - Original mjson source project; Please refer to the documentation in this guide regarding the parser since many of the interfaces have been enhanced or modified.
String Escaping
The C language requires that certain characters are escaped in literal strings. For example, a double quote " contained within a literal string must be preceded with a backslash:"\"hello world\"" in memory would be "hello world". When interpreting the C language examples in the following sections implementors should keep in mind C escaping rules.
...
Another, common problem that causes syntax problems arises when using Microsoft Word. By default, Microsoft Word uses "Smart Quotes". These quotes do not have the same binary encoding as the standard ASCII double quote and will cause JSON syntax errors. This document was written with Smart Quotes disabled. Implementors may wisely choose to disable Smart Quotes under the Auto Correct options especially if using Microsoft Word to document equipment specific JSON elements.
Library Limitations
The JSON library has several limitations as enumerated in this section.
Unicode character sets are not supported. The library will not encode Unicode characters and it will not decode Unicode characters. If this is a requirement for an application, then the data should be encoded as a Base64 or ASCII Hexadecimal string. The library does and will encode and decode certain single byte characters as Unicode data to allow for proper string escaping.
The library allows for specifying hierarchical element paths delimited by a period symbol. If an element name includes a period, which is technically permittable under JSON syntax rules, then the path description will not be able to find the requested element. Implementors should not use the period symbol in their JSON element names.
Unit Test
After porting the JSON library to the target platform it is strongly recommended that MJSON_UNIT_TEST be defined and the MJUnitTest() function be invoked to verify that the library is behaving as expected. It is not necessary to compile in and invoke the unit test in production code.
The units test also provides implementors useful examples of how to properly use the JSON library.
Generation
MJPrintf() is the primary function used to generate JSON. It behaves in a similar way to the standard library function snprintf().
Code Block | ||
---|---|---|
| ||
int32_t MJPrintf(MJBuffer_t *mb, const int8_t *fmt, . |
...
..); |
The return value is always the number of bytes written to mb.
mb parameter
mb contains a pointer to a buffer where the JSON is printed. The structure also contains the size of the buffer, and the current length of the JSON string.
Code Block | ||
---|---|---|
| ||
typedef struct MJBuffer { |
...
int8_t* ptr; |
...
int32_t s ize; |
...
int32_t len; |
...
} MJBuffe r_t; |
The JSON library will never overrun the buffer, and it always ensures NULL termination of the JSON string.
fmt parameter
fmt is just like the format specifier in printf(), except there is a different set of allowed formatters.
...
These types of errors are likely to be the number one source of problems in applications using the CWL, so implementors beware!
...
%Q – Quoted and Escaped String
%Q takes a matching int8_t * in the argument list. It prints a quoted and escaped string to mb.
Generally, when printing strings implementors should use %Q instead of %s. The reason is that %Q will escape certain characters that can appear within a string that would otherwise cause the JSON to be invalid.
Code Block | ||
---|---|---|
| ||
uint8_t buf[1 00]; |
...
MJBuffer_t mb; |
...
mb.ptr = buf; |
...
mb.size = sizeof(buf); |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%Q}", "name", "value"); |
...
/* mb.ptr == {"name":"value"}\0 */ |
...
/* mb.len == 16 */ |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%Q}", "name", "B\x12""C"); |
...
/* mb.ptr == {"name":"B\u0012C"}\0 */ |
...
/* mb.len == 19 */ |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%Q}", "name", "B\"C"); |
...
/* mb.ptr == {"name":"B\"C"}\0 */ |
...
/* mb.len == 15 */ |
...
...
...
%.*Q – Length Limited Quoted and Escaped String
%.*Q takes a matching int and int8_t * in the argument list. It behaves like %Q except that it limits the length of the string to value of the passed uint32_t.
Code Block | ||
---|---|---|
| ||
uint8_t buf[100]; |
...
MJBuffer_t mb; |
...
mb.ptr = buf; |
...
mb.size = sizeof(buf); |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%.*Q}", "name", (int) 3, "value"); |
...
/* mb.ptr == {"name":"val"}\0 */ |
...
/* mb.len == 14 */ |
...
...
%d and %ld – Signed Integer
%d takes a matching int in the argument list. It behaves like the standard printf() %d formatter and allows only numbers in an int16_t range to be printed. Unlike %d used in printf(), the behavior of %d will not differ between 16 and 32-bit platforms. When using %d the argument must either be of type int or be cast as such otherwise the variable argument list will be pushed improperly, leading to invalid behaviors or a crash.
...
Unlike the standard printf() %d and %ld, they do not permit any decorators such as flags, width, precision, or length.
Code Block | ||
---|---|---|
| ||
uint8_t buf[100]; |
...
MJBuffer_t mb; |
...
mb.ptr = buf; |
...
mb.size = sizeof(buf); |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%ld}", "count", (int32_t) 2147483647); |
...
/* mb.ptr == {"count":2147483647}\0 */ |
...
/* mb.len == 20 */ |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%ld}", "count", (int32_t) -2147483647); |
...
/* mb.ptr == {"count":-2147483647}\0 */ |
...
/* mb.len == 21 */ |
...
...
%u and %lu – Unsigned Integer
%u takes a matching unsigned int in the argument list. It behaves like the standard printf() %u formatter but allows only numbers in an uint16_t range to be printed. Unlike %u used in printf(), the behavior of %u will not differ between 16 and 32-bit platforms. When using %u the argument must either be of type unsigned int or be cast as such otherwise the variable argument list will be pushed improperly, leading to invalid behaviors or a crash.
...
Unlike the standard printf() %u and %lu, they do not permit any decorators such as flags, width, precision, or length.
Code Block | ||
---|---|---|
| ||
uint8_t buf[100]; |
...
MJBuffer_t mb; |
...
mb.ptr = buf; |
...
mb.size = sizeof(buf); |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%lu}", "count", (uint32_t) 4294967295); |
...
/* mb.ptr == {"count":4294967295}\0 */ |
...
/* mb.len == 20 */ |
...
...
%B - Boolean
%B takes a matching Boolean expression as an int in the argument list. It will print true or false to the buffer.
Code Block | ||
---|---|---|
| ||
uint8_t buf[100]; |
...
MJBuffer_t mb; |
...
mb.ptr = buf; |
...
mb.size = sizeof(buf); |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%B}", "state", (int) (1 == 1)); |
...
/* mb.ptr == {"state":true}\0 */ |
...
/* mb.len == 14 */ |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%B}", "state", (int) (1 == 0)) |
...
/* mb.ptr == {"state":false}\0 */ |
...
/* mb.len == 15 */ |
...
...
%s – Literal String
%s takes a matching int8_t * in the argument list. It behaves like the standard printf() %s formatter and prints a string to the output buffer.
...
Care must be taken when using %s since it will not properly escape control characters that would otherwise cause the JSON to be invalid.
Code Block | ||
---|---|---|
| ||
uint8_t buf[100]; |
...
MJBuffer_t mb; |
...
mb.ptr = buf; |
...
mb.size = sizeof(buf); |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:\"%s\"}", "name", "value"); |
...
/* mb.ptr == {"name":"value"}\0 */ |
...
/* mb.len == 16 */ |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:\"%s\"}", "name", "B\x12""C"); |
...
/* mb.ptr == {"name":"B<Ctrl-R>C"}\0 NOT VALID JSON! */ |
...
/* mb.len == 13 */ |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%s}", "name", "B\"C"); |
...
/* mb.ptr == {"name":"B"C"}\0 NOT VALID JSON! */ |
...
/* mb.len == 14 */ |
...
%.*s – Length Limited Literal String
%.*s takes a matching int and int8_t * in the argument list. It behaves like the standard printf() %s formatter and prints a string to the output buffer where the int limits the total length of the string.
...
Care must be taken when using %.*s since it will not properly escape control characters that would otherwise cause the JSON to be invalid.
Code Block | ||
---|---|---|
| ||
uint8_t buf[100]; |
...
MJBuffer_t mb; |
...
mb.ptr = buf; |
...
mb.size = sizeof(buf); |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:\"%s\"}", "name", (int) 3, "value"); |
...
/* mb.ptr == {"name":"val"}\0 */ |
...
/* mb.len == 14 */ |
...
%g – Shortest Floating Point Number Representation
%g takes a matching double in the argument list. It behaves like the standard printf() %g formatter and prints the shortest representation of the double to the buffer.
Unlike the standard printf() %g, it does not permit any decorators such as flags, width, precision, or length.
Code Block | ||
---|---|---|
| ||
uint8_t buf[100]; |
...
MJBuffer_t mb; |
...
mb.ptr = buf; |
...
mb.size = sizeof(buf); |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%g}", "temp", 1987636523.889); |
...
/* mb.ptr == {"temp":1.98764e+09}\0 */ |
...
/* mb.len == 20 */ |
...
...
%f – Floating Point Number
%f takes a matching double in the argument list. It behaves like the standard printf() %f formatter and prints the double value to the buffer.
Unlike the standard printf() %f, it does not permit any decorators such as flags, width, precision, or length.
Code Block | ||
---|---|---|
| ||
uint8_t buf[100]; |
...
MJBuffer_t mb; |
...
mb.ptr = buf; |
...
mb.size = sizeof(buf); |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%f}", "temp", -1987636523.0); |
...
/* mb.ptr == {"temp":-1987636523.000000}\0 */ |
...
/* mb.len == 27 */ |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%f}", "temp", 1987636523.88912); |
...
/* mb.ptr == {"temp":1987636523.889120}\0 */ |
...
/* mb.len == 26 */ |
...
%.[0-9]f – Floating Point Number with Specific Precision
%.[0-9]f takes a matching double in the argument list. It behaves like the standard printf() %f formatter and prints the double value to the buffer with a precision between 0 and 9.
Unlike the standard printf() %f, it does not permit any other decorators such as flags, width, or length.
Code Block | ||
---|---|---|
| ||
uint8_t buf[100]; |
...
MJBuffer_t mb; |
...
mb.ptr = buf; |
...
mb.size = sizeof(buf); |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%.3f}", "temp", 1987636523.88912); |
...
/* mb.ptr == {"temp":1987636523.889}\0 */ |
...
/* mb.len == 23 */ |
...
...
%V and %v – Quoted and Unquoted Base64 Encoding
%V takes a matching int and uint8_t * expression in the argument list. It will print the Base64 encoded representation of the number of bytes specified by the int from the binary data specified by the uint8_t * in a quoted string.
...
The CWL substitutes the pipe character | for the standard forward slash character / when encoding and decoding Base64 strings. This is done to eliminate the required JSON escaping of the forward slash within the JSON string. This makes the length of the Base64 encoding more predictable and results in less memory consumption.
Code Block | ||
---|---|---|
| ||
uint8_t buf[100]; |
...
MJBuffer_t mb; |
...
mb.ptr = buf; |
...
mb.size = sizeof(buf); |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%V}", "bincfg", (int) 8, "\x01\x02\x03\x44\x55\xCD\xEF\xB8"); |
...
/* mb.ptr == {"bincfg":"AQIDRFXN77g="}\0 */ |
...
/* mb.len == 25 */ |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:\"%v\"}", "bincfg", (int) 8, "\x01\x02\x03\x44\x55\xCD\xEF\xB8"); |
...
/* mb.ptr == {"bincfg":"AQIDRFXN77g="}\0 */ |
...
/* mb.len == 25 */ |
...
%H and %h – Quoted and Unquoted ASCII Hexadecimal Encoding
%H takes a matching int and uint8_t * expression in the argument list. It will print the ASCII hexadecimal encoded representation of the number of bytes specified by the int from the binary data specified by the uint8_t * in a quoted string.
...
Typically, this is used for binary data that is not voluminous and contains an obvious meaning, such as a MAC address or a status bitmask.
Code Block | ||
---|---|---|
| ||
uint8_t buf[100]; |
...
MJBuffer_t mb; |
...
mb.ptr = buf; |
...
mb.size = sizeof(buf); |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%H}", "mac", (int) 8, "\x01\x02\x03\x44\x55\xCD\xEF\xB8"); |
...
/* mb.ptr == {"bincfg":"0102034455CDEFB8"}\0 */ |
...
/* mb.len == 29 */ |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:\"%h\"}", "mac", (int) 8, "\x01\x02\x03\x44\x55\xCD\xEF\xB8"); |
...
/* mb.ptr == {"bincfg":"0102034455CDEFB8"}\0 */ |
...
/* mb.len == 29 */ |
...
%M – Generic Printer Function
%M takes a matching MJPrintFn_t * and zero or more additional expressions in the argument list. This function will be invoked to print a complex value to the buffer.int32_t
Code Block | ||
---|---|---|
| ||
int32_t m_printer_1(MJBuffer_t *mb, va_list *ap) { |
...
return MJPrintf(mb, "{%Q:%d,%Q:%Q}", "DD", (int) -1, "EE", "fg!"); |
...
} |
...
int32_t m_printer_2(MJBuffer_t *mb, va_list *ap) { |
...
int value = va_arg(*ap, int); |
...
int8_t *str = va_arg(*ap, int8_t *); |
...
return MJPrintf(mb, "{%Q:%d,%Q:%Q}", "DD", value, "EE", str); |
...
} |
...
uint8_t buf[100]; |
...
MJBuffer_t mb; |
...
mb.ptr = buf; |
...
mb.size = sizeof(buf); |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%M}", "a", m_printer_1); |
...
/* mb.ptr == {"a":{"DD":-1,"EE":"fg!"}}\0 */ |
...
/* mb.len == 26 */ |
...
mb.len = 0; |
...
MJPrintf(&mb, "{%Q:%M,%Q:%Q}", "a", m_printer_2, (int) -42, "hello", "d", "e"); |
...
/* mb.ptr == {"a":{"DD":-42,"EE":"hello"},"d":"e"}\0 */ |
...
/* mb.len == 37 */ |
For each optional expression after the MJPrintFn_t * the function must call va_arg() to pull the additional arguments off the list using the correct types and order. Failure to do so will typically cause a program to crash since the format specifier and variable argument list will become unsynchronized.
...
%A – Array Printer Function
%A works exactly as %M except that it will encapsulate the output of the invoked function between opening and closing square array brackets.
...
%O – Object Printer Function
%A works exactly as %M except that it will encapsulate the output of the invoked function between opening and closing curly object brackets.
...
Decoding
The JSON library has an extensive set of functions to properly parse JSON messages.
Home brew, ad-hoc parsing should not be attempted since such code will invariably not account for all of the subtleties of JSON syntax and will certainly lead to bugs and improper operation.
...
s, len, path - Common Arguments
There are several arguments common to the decoding functions. These arguments are defined here.
...
For example, take the JSON string:
Code Block | ||
---|---|---|
| ||
{"a":{"DD":-42,"EE":"hello"},"d":["e","f"]} |
The value of $ is the object {"a":{"DD":-42,"EE":"hello"},"d":["e","f"]}
The value of $.a is the object {"DD":-42,"EE":"hello"}
The value of $.a.DD is the number -42.
The value of $.d is the array ["e","f"]
The value of $.d[1] is string "f".
While any of the functions that accept a path will permit array notation, it is recommended to use the MJGetArrayElement() function since it simplifies application code when accessing array elements.
...
MJIsValid()
bool MJIsValid(const int8_t* s, int32_t len);
This function returns true when s is a valid JSON string, else it returns false.
Code Block | ||
---|---|---|
| ||
int8_t valid[] = "{\"a\":{\"DD\":-42,\"EE\":\"hi\"},\"d\":[\"e\",\"f\"]}"; |
...
int8_t invalid[] = "{\"a\":{\"DD\":-42,\"EE\":\"hi\"},\"d\":[\"e\",\"f\"]"; |
...
/* Returns true */ |
...
if (MJIsValid(valid, strlen(valid)) == true) |
...
{ |
...
/* JSON is valid */ |
...
}
} /* Returns false, missing closing } */ |
...
if (MJIsValid(invalid, strlen(invalid)) == false) |
...
{ |
...
/* JSON is invalid */ |
...
} |
...
...
MJFind()
MJToken_t MJFind(const int8_t* s, int32_t len, const int8_t* path, const int8_t** tokptr, int32_t* toklen);
...
Possible return values are:
MJSON_TOK_INVALID /* Element not found */
MJSON_TOK_STRING /* String, ASCII hexadecimal, or Base64 */
MJSON_TOK_NUMBER /* Number, double or integer */
MJSON_TOK_TRUE /* Boolean true */
MJSON_TOK_FALSE /* Boolean false */
MJSON_TOK_NULL /* null */
MJSON_TOK_ARRAY /* Array [] */
MJSON_TOK_OBJECT /* Object {} */
Code Block | ||
---|---|---|
| ||
int8_t s[] = "{\"a\":{\"DD\":-42,\"EE\":\"hi\"},\"d\":[\"e\",\"f\"]}"; |
...
/* Returns MJSON_TOK_NUMBER */ |
...
if (MJFind(s, strlen(s), "$.a.DD", NULL, NULL) == MJSON_TOK_NUMBER) |
...
{ |
...
/* The value is present and is a number */ |
...
}
} /* Returns MJSON_TOK_STRING */ |
...
if (MJFind(s, strlen(s), "$.a.EE", NULL, NULL) == MJSON_TOK_STRING) |
...
{ |
...
/* The value is present and is a string */ |
...
}
} /* Returns MJSON_TOK_INVALID */ |
...
if (MJFind(s, strlen(s), "$.temp", NULL, NULL) == MJSON_TOK_STRING) |
...
{ |
...
/* This clause will not execute */ |
...
} |
...
else |
...
{ |
...
/* temp does not exist or its value is not a string */ |
...
} |
...
|
...
MJGetBase64()
int32_t MJGetBase64(const int8_t *s, int32_t len, const int8_t *path, int8_t *to, int32_t n);
This function decodes up to n bytes of a quoted Base64 string into to. If successful it returns the actual number of data bytes written into to. Or a negative number on a failure, usually because the to buffer is too small, in which case to will not contain a valid decoding and must not be used by the caller. This function writes binary data not a string into to, therefore NULL termination is not ensured unless the NULL termination character is part of the Base64 encoded string.
Code Block | ||
---|---|---|
| ||
int8_t s[] = "{\"data\":\"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=\"}"; |
...
int8_t buf[52]; |
...
int32_t len; |
...
/* Returns 26, buf == "abcdefghijklmnopqrstuvwxyz" no NULL terminator */ |
...
len = MJGetBase64(s, strlen(s), "$.data", buf, sizeof(buf)); |
...
if (len > 0) |
...
{ |
...
/* buf contains len bytes of decoded binary data */ |
...
} |
...
...
MJGetDouble()
int32_t MJGetDouble(const int8_t* s, int32_t len, const int8_t* path, double* v);
This function converts a floating-point number into a double and stores it to the memory pointed to by v. It returns sizeof(double) on success, any other return value indicates an unsuccessful conversion and the memory pointed to by v will not be updated and must not be used by the caller.
Code Block | ||
---|---|---|
| ||
int8_t s[] = "{\"f\":-1.99E-10}"; |
...
double v; |
...
/* Returns sizeof(double), v contains the floating-point value encoded in the JSON */ |
...
if (MJGetDouble(s, strlen(s), "$.f", &v) == sizeof(double)) |
...
{ |
...
/* v contains the floating-point value of -1.99E-10 */ |
...
} |
...
...
MJGetInteger()
Code Block | ||
---|---|---|
| ||
int32_t MJGetInteger(const int8_t* s, int32_t len, const int8_t* path, int32_t* v); |
This function converts the number in the JSON string element into a 32-bit signed integer. If the type of the element is not known to contain a 32-bit signed integer then MJGetDouble() should be used instead because it can represent a larger set of numbers. On success, the function will return sizeof(int32_t), otherwise the value pointed to by v must not be used by the caller.
Code Block | ||
---|---|---|
| ||
int8_t s[] = {\"i\":-1998776544}"; |
...
int32_t v; |
...
/* Returns sizeof(int32_t), v == -1998776544 */ |
...
if (MJGetInteger(s, strlen(s), "$.i", &v) == sizeof(int32_t)) |
...
{ |
...
/* v == -1998776544 */ |
...
} |
...
...
MJGetUInteger()
Code Block | ||
---|---|---|
| ||
int32_t MJGetUInteger(const int8_t* s, int32_t len, const int8_t* path, uint32_t* v); |
This function converts the number in the JSON string element into a 32-bit unsigned integer. If the type of the element is not known to contain a 32-bit unsigned integer then MJGetDouble() should be used instead because it can represent a larger set of numbers. On success, the function will return sizeof(uint32_t), otherwise the value pointed to by v must not be used by the caller.int8_t
Code Block | ||
---|---|---|
| ||
int8_t s[] = {\"i\":1998776544}"; |
...
uint32_t v; |
...
/* Returns sizeof(uint32_t), v == 1998776544 */ |
...
if (MJGetUInteger(s, strlen(s), "$.i", &v) == sizeof(uint32_t)) |
...
{ |
...
/* v == 1998776544 */ |
...
} |
...
...
MJGetBool()
Code Block | ||
---|---|---|
| ||
int32_t MJGetBool(const int8_t *s, int32_t len, const int8_t *path, bool *v); |
This function converts a JSON Boolean into a C language Boolean. On success it returns sizeof(bool) and the memory pointed to by v will contain the Boolean value of the element, any other return value is a failure and the value pointed to by v must not be used by the caller.
Code Block | ||
---|---|---|
| ||
int8_t st[] = "{\"b\":true}"; |
...
int8_t sf[] = "{\"b\":true}"; |
...
bool v; |
...
/* Returns sizeof(bool), v == 1 */ |
...
if (MJGetBool(st, strlen(st), "$.b", &v) == sizeof(bool)) |
...
{ |
...
/* v == 1 */ |
...
}
} /* Returns sizeof(bool), v == 0 */ |
...
if (MJGetBool(sf, strlen(sf), "$.b", &v) == sizeof(bool)) |
...
{ |
...
/* v == 0 */ |
...
} |
...
...
MJGetString()
Code Block | ||
---|---|---|
| ||
int32_t MJGetString(const int8_t *s, int32_t len, const int8_t *path, int8_t *to, int32_t n); |
This function returns an unescaped NULL terminated C language string into to up to n bytes in length. On success it returns the actual length of the string not including the NULL terminator. An empty string "" will return a length of zero. On failure, typically when to is not large enough to hold the unescaped string and NULL termination, it returns a negative number and the memory pointed to by to must not be used by the caller.
Code Block | ||
---|---|---|
| ||
int8_t s[] = "{\"str\":\"hello world\"}"; |
...
int8_t to[20]; |
...
int32_t len; |
...
/* Returns 11, to == "hello world\x00" */ |
...
len = MJGetString(s, strlen(s), "$.str", to, sizeof(to)); |
...
if (len >= 0) |
...
{ |
...
/* to == "hello world\x00" */ |
...
} |
...
...
MJGetHex()
Code Block | ||
---|---|---|
| ||
int32_t MJGetHex(const int8_t* s, int32_t len, const int8_t* path, int8_t* to, int32_t n, bool reverse); |
This function decodes an ASCII hexadecimal string into binary data and stores up to n bytes into to. The binary data may be returned in reverse order from the string encoding by passing true for the reverse parameter. On success the function returns the actual number of binary data bytes decoded. On failure, typically when to is not large enough to hold the decoded binary value of the string, a negative number is returned, and the caller must not use the data pointed to by to.
Code Block | ||
---|---|---|
| ||
int8_t s[] = "{\"mac\":\"112233C1556677F8\"}"; |
...
int8_t to[8]; |
...
int32_t len; |
...
/* Returns 8, to == \x11\x22\x33\xC1\x55\x66\x77\xF8 */ |
...
len = MJGetHex(s, strlen(s), "$.mac", to, sizeof(to), false); |
...
if (len > 0) |
...
{ |
...
/* to == \x11\x22\x33\xC1\x55\x66\x77\xF8 */ |
...
}
} /* Returns 8, to == \xF8\x77\x66\x55\xC1\x33\x22\x11 */ |
...
len = MJGetHex(s, strlen(s), "$.mac", to, sizeof(to), true); |
...
if (len > 0) |
...
{ |
...
/* to == \xF8\x77\x66\x55\xC1\x33\x22\x11 */ |
...
} |
...
MJGetArrayElement()
Code Block | ||
---|---|---|
| ||
MJGetArrayElement(const int8_t* s, int32_t len, const int8_t* path, MJDataType_t type, void* data, int32_t n, ...); |
This function makes it easier to extract the values of array elements even when they are multidimensionally nested. type declares the data type of the passed data buffer pointer that has a size of n, and is one of the following enumerated values:
MJSON_DATATYPE_HEX, MJSON_DATATYPE_HEX_REV, MJSON_DATATYPE_STRING, MJSON_DATATYPE_DOUBLE, MJSON_DATATYPE_INTEGER, MJSON_DATATYPE_UINTEGER, MJSON_DATATYPE_BASE64
After the n parameter is a list of zero or more numbers of type int that are the associated zero-indexed array indices specified in path. To indicate a variable index value in path use a %d format specifier.
The return value is equivalent to directly calling the associated primitive functions MJGetBase64(), MJGetDouble(), MJGetInteger(), MJGetUInteger(), MJGetBool(), MJGetString(), and MJGetHex() functions.
Code Block | ||
---|---|---|
| ||
int8_t s[] = "{\"a\":[[1,2,3],[4,5,6],[7,8,9]]}"; |
...
int32_t data; |
...
int i, j; |
...
/* Returns sizeof(int32_t), data == 4 */ |
...
if (MJGetArrayElement(s, strlen(s), "$a[%d][%d]", MJSON_DATATYPE_INTEGER, &data, sizeof(data), 1, 0) == sizeof(int32_t)) |
...
{ |
...
/* data == 4 */ |
...
}
} /* Returns sizeof(int32_t), data == 9 */ |
...
if (MJGetArrayElement(s, strlen(s), "$a[%d][%d]", MJSON_DATATYPE_INTEGER, &data, sizeof(data), 2, 2) == sizeof(int32_t)) |
...
{ |
...
/* data == 9 */ |
...
} |
...
/* Implements a loop that will print out all the 2-dimensional array |
...
values without knowing the number of array elements in advance */ |
...
j = -1; |
...
for (i = 0; j != 0; i++) |
...
{ |
...
for (j = 0;; j++) |
...
{ |
...
if (MJGetArrayElement(s, strlen(s), "$.a[%d][%d]", |
...
MJSON_DATATYPE_INTEGER, &data, |
...
sizeof(data), i, j) == sizeof(int32_t)) |
...
{ |
...
printf("a[%d][%d] = %d\r\n", i, j, data); |
...
} |
...
else break; |
...
} |
...
} |
...
MJParse()
Code Block | ||
---|---|---|
| ||
int32_t MJParse(const int8_t* s, int32_t len, mjson_cb_t cb, void* ud); |
This function provides access to the low level JSON parser that is used internally by the functions previously described. It is primarily used when the name of an element can vary which makes specifying a path parameter difficult or impossible.
...