Init
This commit is contained in:
commit
4d4ee8bcb4
|
|
@ -0,0 +1,10 @@
|
|||
//
|
||||
// Created by cfif on 26.10.22.
|
||||
//
|
||||
|
||||
#ifndef ARTERY_PROJECT_CVT_H
|
||||
#define ARTERY_PROJECT_CVT_H
|
||||
|
||||
char *fromFloat(char *bufFloat, float *value);
|
||||
|
||||
#endif //ARTERY_PROJECT_CVT_H
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
This file is Copyright (c) 2020, 2021 by Rene Kita
|
||||
*/
|
||||
|
||||
#ifndef RKTA_MTOJSON_H
|
||||
#define RKTA_MTOJSON_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
enum json_to_type {
|
||||
t_to_primitive,
|
||||
t_to_array,
|
||||
t_to_boolean,
|
||||
t_to_hex,
|
||||
t_to_hex_u8,
|
||||
t_to_hex_u16,
|
||||
t_to_hex_u32,
|
||||
t_to_hex_u64,
|
||||
t_to_int,
|
||||
t_to_int8_t,
|
||||
t_to_int16_t,
|
||||
t_to_int32_t,
|
||||
t_to_int64_t,
|
||||
t_to_long,
|
||||
t_to_longlong,
|
||||
t_to_null,
|
||||
t_to_object,
|
||||
t_to_string,
|
||||
t_to_uint,
|
||||
t_to_uint8_t,
|
||||
t_to_uint16_t,
|
||||
t_to_uint32_t,
|
||||
t_to_uint64_t,
|
||||
t_to_ulong,
|
||||
t_to_ulonglong,
|
||||
t_to_value,
|
||||
t_to_float,
|
||||
};
|
||||
|
||||
struct to_json {
|
||||
const char *name;
|
||||
const void *value;
|
||||
const uint8_t *lenStr;
|
||||
const size_t *count; // Number of elements in a C array
|
||||
size_t len;
|
||||
enum json_to_type stype; // Type of the struct
|
||||
enum json_to_type vtype; // Type of '.value'
|
||||
};
|
||||
|
||||
/* Returns the length of the generated JSON text or 0 in case of an error. */
|
||||
size_t json_generate(char *out, const struct to_json *tjs, size_t len);
|
||||
#endif
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
|
||||
/*
|
||||
|
||||
<https://github.com/rafagafe/tiny-json>
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2016-2018 Rafa Garcia <rafagarcia77@gmail.com>.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _TINY_JSON_H_
|
||||
#define _TINY_JSON_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define json_containerOf( ptr, type, member ) \
|
||||
((type*)( (char*)ptr - offsetof( type, member ) ))
|
||||
|
||||
/** @defgroup tinyJson Tiny JSON parser.
|
||||
* @{ */
|
||||
|
||||
/** Enumeration of codes of supported JSON properties types. */
|
||||
typedef enum {
|
||||
JSON_OBJ, JSON_ARRAY, JSON_TEXT, JSON_BOOLEAN,
|
||||
JSON_INTEGER, JSON_REAL, JSON_NULL
|
||||
} jsonType_t;
|
||||
|
||||
/** Structure to handle JSON properties. */
|
||||
typedef struct json_s {
|
||||
struct json_s* sibling;
|
||||
char const* name;
|
||||
union {
|
||||
char const* value;
|
||||
struct {
|
||||
struct json_s* child;
|
||||
struct json_s* last_child;
|
||||
} c;
|
||||
} u;
|
||||
jsonType_t type;
|
||||
} json_t;
|
||||
|
||||
/** Parse a string to get a json.
|
||||
* @param str String pointer with a JSON object. It will be modified.
|
||||
* @param mem Array of json properties to allocate.
|
||||
* @param qty Number of elements of mem.
|
||||
* @retval Null pointer if any was wrong in the parse process.
|
||||
* @retval If the parser process was successfully a valid handler of a json.
|
||||
* This property is always unnamed and its type is JSON_OBJ. */
|
||||
json_t const* json_create( char* str, json_t mem[], unsigned int qty );
|
||||
|
||||
/** Get the name of a json property.
|
||||
* @param json A valid handler of a json property.
|
||||
* @retval Pointer to null-terminated if property has name.
|
||||
* @retval Null pointer if the property is unnamed. */
|
||||
static inline char const* json_getName( json_t const* json ) {
|
||||
return json->name;
|
||||
}
|
||||
|
||||
/** Get the value of a json property.
|
||||
* The type of property cannot be JSON_OBJ or JSON_ARRAY.
|
||||
* @param property A valid handler of a json property.
|
||||
* @return Pointer to null-terminated string with the value. */
|
||||
static inline char const* json_getValue( json_t const* property ) {
|
||||
return property->u.value;
|
||||
}
|
||||
|
||||
/** Get the type of a json property.
|
||||
* @param json A valid handler of a json property.
|
||||
* @return The code of type.*/
|
||||
static inline jsonType_t json_getType( json_t const* json ) {
|
||||
return json->type;
|
||||
}
|
||||
|
||||
/** Get the next sibling of a JSON property that is within a JSON object or array.
|
||||
* @param json A valid handler of a json property.
|
||||
* @retval The handler of the next sibling if found.
|
||||
* @retval Null pointer if the json property is the last one. */
|
||||
static inline json_t const* json_getSibling( json_t const* json ) {
|
||||
return json->sibling;
|
||||
}
|
||||
|
||||
/** Search a property by its name in a JSON object.
|
||||
* @param obj A valid handler of a json object. Its type must be JSON_OBJ.
|
||||
* @param property The name of property to get.
|
||||
* @retval The handler of the json property if found.
|
||||
* @retval Null pointer if not found. */
|
||||
json_t const* json_getProperty( json_t const* obj, char const* property );
|
||||
|
||||
|
||||
/** Search a property by its name in a JSON object and return its value.
|
||||
* @param obj A valid handler of a json object. Its type must be JSON_OBJ.
|
||||
* @param property The name of property to get.
|
||||
* @retval If found a pointer to null-terminated string with the value.
|
||||
* @retval Null pointer if not found or it is an array or an object. */
|
||||
char const* json_getPropertyValue( json_t const* obj, char const* property );
|
||||
|
||||
/** Get the first property of a JSON object or array.
|
||||
* @param json A valid handler of a json property.
|
||||
* Its type must be JSON_OBJ or JSON_ARRAY.
|
||||
* @retval The handler of the first property if there is.
|
||||
* @retval Null pointer if the json object has not properties. */
|
||||
static inline json_t const* json_getChild( json_t const* json ) {
|
||||
return json->u.c.child;
|
||||
}
|
||||
|
||||
/** Get the value of a json boolean property.
|
||||
* @param property A valid handler of a json object. Its type must be JSON_BOOLEAN.
|
||||
* @return The value stdbool. */
|
||||
static inline bool json_getBoolean( json_t const* property ) {
|
||||
return *property->u.value == 't';
|
||||
}
|
||||
|
||||
/** Get the value of a json integer property.
|
||||
* @param property A valid handler of a json object. Its type must be JSON_INTEGER.
|
||||
* @return The value stdint. */
|
||||
static inline int64_t json_getInteger( json_t const* property ) {
|
||||
return strtoll( property->u.value,(char**)NULL, 10);
|
||||
}
|
||||
|
||||
/** Get the value of a json real property.
|
||||
* @param property A valid handler of a json object. Its type must be JSON_REAL.
|
||||
* @return The value. */
|
||||
static inline double json_getReal( json_t const* property ) {
|
||||
return strtod( property->u.value,(char**)NULL );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Structure to handle a heap of JSON properties. */
|
||||
typedef struct jsonPool_s jsonPool_t;
|
||||
struct jsonPool_s {
|
||||
json_t* (*init)( jsonPool_t* pool );
|
||||
json_t* (*alloc)( jsonPool_t* pool );
|
||||
};
|
||||
|
||||
/** Parse a string to get a json.
|
||||
* @param str String pointer with a JSON object. It will be modified.
|
||||
* @param pool Custom json pool pointer.
|
||||
* @retval Null pointer if any was wrong in the parse process.
|
||||
* @retval If the parser process was successfully a valid handler of a json.
|
||||
* This property is always unnamed and its type is JSON_OBJ. */
|
||||
json_t const* json_createWithPool( char* str, jsonPool_t* pool );
|
||||
|
||||
/** @ } */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TINY_JSON_H_ */
|
||||
|
|
@ -0,0 +1,317 @@
|
|||
//
|
||||
// Created by cfif on 26.10.22.
|
||||
//
|
||||
#include <math.h>
|
||||
|
||||
static unsigned char *
|
||||
cvtround (double fract, int *exp, unsigned char *start, unsigned char *end, unsigned char ch,
|
||||
unsigned char *negp)
|
||||
{
|
||||
double tmp;
|
||||
|
||||
if (fract) {
|
||||
modf (fract * 10, &tmp);
|
||||
} else {
|
||||
tmp = ch - '0';
|
||||
}
|
||||
if (tmp > 4) {
|
||||
for (;; --end) {
|
||||
if (*end == '.') {
|
||||
--end;
|
||||
}
|
||||
if (++*end <= '9') {
|
||||
break;
|
||||
}
|
||||
*end = '0';
|
||||
if (end == start) {
|
||||
if (exp) { /* e/E; increment exponent */
|
||||
*end = '1';
|
||||
++*exp;
|
||||
} else { /* f; add extra digit */
|
||||
*--end = '1';
|
||||
--start;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (*negp) {
|
||||
/*
|
||||
* ``"%.3f", (double)-0.0004'' gives you a negative 0.
|
||||
*/
|
||||
for (;; --end) {
|
||||
if (*end == '.') {
|
||||
--end;
|
||||
}
|
||||
if (*end != '0') {
|
||||
break;
|
||||
}
|
||||
if (end == start) {
|
||||
*negp = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
exponent (unsigned char *p, int exp, unsigned char fmtch)
|
||||
{
|
||||
unsigned char expbuf [8], *t;
|
||||
|
||||
*p++ = fmtch;
|
||||
if (exp < 0) {
|
||||
exp = -exp;
|
||||
*p++ = '-';
|
||||
} else {
|
||||
*p++ = '+';
|
||||
}
|
||||
t = expbuf + sizeof(expbuf);
|
||||
if (exp > 9) {
|
||||
do {
|
||||
*--t = exp % 10 + '0';
|
||||
} while ((exp /= 10) > 9);
|
||||
*--t = exp + '0';
|
||||
for (; t < expbuf + sizeof(expbuf); *p++ = *t++)
|
||||
continue;
|
||||
} else {
|
||||
*p++ = '0';
|
||||
*p++ = exp + '0';
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cvt (double number, int prec, int sharpflag, unsigned char *negp, unsigned char fmtch,
|
||||
unsigned char *startp, unsigned char *endp)
|
||||
{
|
||||
unsigned char *p, *t;
|
||||
double fract;
|
||||
int dotrim, expcnt, gformat;
|
||||
double integer, tmp;
|
||||
|
||||
expcnt = 0;
|
||||
dotrim = expcnt = gformat = 0;
|
||||
fract = modf (number, &integer);
|
||||
|
||||
/*
|
||||
* get an extra slot for rounding
|
||||
*/
|
||||
t = ++startp;
|
||||
|
||||
/*
|
||||
* get integer portion of number; put into the end of the buffer; the
|
||||
* .01 is added for modf (356.0 / 10, &integer) returning .59999999...
|
||||
*/
|
||||
for (p = endp - 1; integer; ++expcnt) {
|
||||
tmp = modf (integer / 10, &integer);
|
||||
*p-- = (int) ((tmp + .01) * 10) + '0';
|
||||
}
|
||||
switch (fmtch) {
|
||||
case 'f':
|
||||
/* reverse integer into beginning of buffer */
|
||||
if (expcnt) {
|
||||
for (; ++p < endp; *t++ = *p);
|
||||
} else {
|
||||
*t++ = '0';
|
||||
}
|
||||
|
||||
/*
|
||||
* if precision required or alternate flag set, add in a
|
||||
* decimal point.
|
||||
*/
|
||||
if (prec || sharpflag) {
|
||||
*t++ = '.';
|
||||
}
|
||||
|
||||
/*
|
||||
* if requires more precision and some fraction left
|
||||
*/
|
||||
if (fract) {
|
||||
if (prec) {
|
||||
do {
|
||||
fract = modf (fract * 10, &tmp);
|
||||
*t++ = (int)tmp + '0';
|
||||
} while (--prec && fract);
|
||||
}
|
||||
if (fract) {
|
||||
startp = cvtround (fract, 0, startp,
|
||||
t - 1, '0', negp);
|
||||
}
|
||||
}
|
||||
for (; prec--; *t++ = '0');
|
||||
break;
|
||||
case 'e':
|
||||
case 'E':
|
||||
eformat: if (expcnt) {
|
||||
*t++ = *++p;
|
||||
if (prec || sharpflag) {
|
||||
*t++ = '.';
|
||||
}
|
||||
|
||||
/*
|
||||
* if requires more precision and some integer left
|
||||
*/
|
||||
for (; prec && ++p < endp; --prec) {
|
||||
*t++ = *p;
|
||||
}
|
||||
|
||||
/*
|
||||
* if done precision and more of the integer component,
|
||||
* round using it; adjust fract so we don't re-round
|
||||
* later.
|
||||
*/
|
||||
if (! prec && ++p < endp) {
|
||||
fract = 0;
|
||||
startp = cvtround (0, &expcnt, startp,
|
||||
t - 1, *p, negp);
|
||||
}
|
||||
/*
|
||||
* adjust expcnt for digit in front of decimal
|
||||
*/
|
||||
--expcnt;
|
||||
}
|
||||
/*
|
||||
* until first fractional digit, decrement exponent
|
||||
*/
|
||||
else if (fract) {
|
||||
/*
|
||||
* adjust expcnt for digit in front of decimal
|
||||
*/
|
||||
for (expcnt = -1;; --expcnt) {
|
||||
fract = modf (fract * 10, &tmp);
|
||||
if (tmp) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*t++ = (int)tmp + '0';
|
||||
if (prec || sharpflag) {
|
||||
*t++ = '.';
|
||||
}
|
||||
} else {
|
||||
*t++ = '0';
|
||||
if (prec || sharpflag) {
|
||||
*t++ = '.';
|
||||
}
|
||||
}
|
||||
/*
|
||||
* if requires more precision and some fraction left
|
||||
*/
|
||||
if (fract) {
|
||||
if (prec) {
|
||||
do {
|
||||
fract = modf (fract * 10, &tmp);
|
||||
*t++ = (int)tmp + '0';
|
||||
} while (--prec && fract);
|
||||
}
|
||||
if (fract) {
|
||||
startp = cvtround (fract, &expcnt, startp,
|
||||
t - 1, '0', negp);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* if requires more precision
|
||||
*/
|
||||
for (; prec--; *t++ = '0');
|
||||
|
||||
/*
|
||||
* unless alternate flag, trim any g/G format trailing 0's
|
||||
*/
|
||||
if (gformat && ! sharpflag) {
|
||||
while (t > startp && *--t == '0');
|
||||
if (*t == '.') {
|
||||
--t;
|
||||
}
|
||||
++t;
|
||||
}
|
||||
t = exponent (t, expcnt, fmtch);
|
||||
break;
|
||||
case 'g':
|
||||
case 'G':
|
||||
/*
|
||||
* a precision of 0 is treated as a precision of 1
|
||||
*/
|
||||
if (!prec) {
|
||||
++prec;
|
||||
}
|
||||
|
||||
/*
|
||||
* ``The style used depends on the value converted; style e
|
||||
* will be used only if the exponent resulting from the
|
||||
* conversion is less than -4 or greater than the precision.''
|
||||
* -- ANSI X3J11
|
||||
*/
|
||||
if (expcnt > prec || (! expcnt && fract && fract < .0001)) {
|
||||
/*
|
||||
* g/G format counts "significant digits, not digits of
|
||||
* precision; for the e/E format, this just causes an
|
||||
* off-by-one problem, i.e. g/G considers the digit
|
||||
* before the decimal point significant and e/E doesn't
|
||||
* count it as precision.
|
||||
*/
|
||||
--prec;
|
||||
fmtch -= 2; /* G->E, g->e */
|
||||
gformat = 1;
|
||||
goto eformat;
|
||||
}
|
||||
/*
|
||||
* reverse integer into beginning of buffer,
|
||||
* note, decrement precision
|
||||
*/
|
||||
if (expcnt) {
|
||||
for (; ++p < endp; *t++ = *p, --prec);
|
||||
} else {
|
||||
*t++ = '0';
|
||||
}
|
||||
/*
|
||||
* if precision required or alternate flag set, add in a
|
||||
* decimal point. If no digits yet, add in leading 0.
|
||||
*/
|
||||
if (prec || sharpflag) {
|
||||
dotrim = 1;
|
||||
*t++ = '.';
|
||||
} else {
|
||||
dotrim = 0;
|
||||
}
|
||||
/*
|
||||
* if requires more precision and some fraction left
|
||||
*/
|
||||
while (prec && fract) {
|
||||
fract = modf (fract * 10, &tmp);
|
||||
*t++ = (int)tmp + '0';
|
||||
prec--;
|
||||
}
|
||||
if (fract) {
|
||||
startp = cvtround (fract, 0, startp, t - 1, '0', negp);
|
||||
}
|
||||
/*
|
||||
* alternate format, adds 0's for precision, else trim 0's
|
||||
*/
|
||||
if (sharpflag) {
|
||||
for (; prec--; *t++ = '0');
|
||||
} else if (dotrim) {
|
||||
while (t > startp && *--t == '0');
|
||||
if (*t != '.') {
|
||||
++t;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(t - startp);
|
||||
}
|
||||
|
||||
char *fromFloat(char *bufFloat, float *value) {
|
||||
int flag = 0;
|
||||
|
||||
if (*value < 0) {
|
||||
flag = 1;
|
||||
*value *= -1;
|
||||
}
|
||||
|
||||
cvt(*value, 6, 1, bufFloat, 'f',&bufFloat[0], &bufFloat[24]);
|
||||
if (flag) {
|
||||
bufFloat[0] = '-';
|
||||
} else {
|
||||
bufFloat[0] = ' ';
|
||||
}
|
||||
return bufFloat;
|
||||
}
|
||||
|
|
@ -0,0 +1,759 @@
|
|||
/*
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
This file is Copyright (c) 2020, 2021 by Rene Kita
|
||||
*/
|
||||
|
||||
#include "mtojson.h"
|
||||
#include "cvt.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
static char* gen_array(char *, const void *);
|
||||
static char* gen_boolean(char *, const void *);
|
||||
static char* gen_c_array(char *, const void *);
|
||||
static char* gen_hex(char *, const void *);
|
||||
static char* gen_hex_u8(char *, const void *);
|
||||
static char* gen_hex_u16(char *, const void *);
|
||||
static char* gen_hex_u32(char *, const void *);
|
||||
static char* gen_hex_u64(char *, const void *);
|
||||
static char* gen_int(char *, const void *);
|
||||
static char* gen_int8_t(char *, const void *);
|
||||
static char* gen_int16_t(char *, const void *);
|
||||
static char* gen_int32_t(char *, const void *);
|
||||
static char* gen_int64_t(char *, const void *);
|
||||
static char* gen_long(char *, const void *);
|
||||
static char* gen_longlong(char *, const void *);
|
||||
static char* gen_null(char *, const void *);
|
||||
static char* gen_object(char *, const void *);
|
||||
static char* gen_primitive(char *, const void *);
|
||||
static char* gen_string(char *, const void *);
|
||||
static char* gen_uint(char *, const void *);
|
||||
static char* gen_uint8_t(char *, const void *);
|
||||
static char* gen_uint16_t(char *, const void *);
|
||||
static char* gen_uint32_t(char *, const void *);
|
||||
static char* gen_uint64_t(char *, const void *);
|
||||
static char* gen_ulong(char *, const void *);
|
||||
static char* gen_ulonglong(char *, const void *);
|
||||
static char* gen_value(char *, const void *);
|
||||
static char* gen_float(char *, const void *);
|
||||
|
||||
static char* (* const gen_functions[])(char *, const void *) = {
|
||||
gen_primitive,
|
||||
gen_array,
|
||||
gen_boolean,
|
||||
gen_hex,
|
||||
gen_hex_u8,
|
||||
gen_hex_u16,
|
||||
gen_hex_u32,
|
||||
gen_hex_u64,
|
||||
gen_int,
|
||||
gen_int8_t,
|
||||
gen_int16_t,
|
||||
gen_int32_t,
|
||||
gen_int64_t,
|
||||
gen_long,
|
||||
gen_longlong,
|
||||
gen_null,
|
||||
gen_object,
|
||||
gen_string,
|
||||
gen_uint,
|
||||
gen_uint8_t,
|
||||
gen_uint16_t,
|
||||
gen_uint32_t,
|
||||
gen_uint64_t,
|
||||
gen_ulong,
|
||||
gen_ulonglong,
|
||||
gen_value,
|
||||
gen_float
|
||||
};
|
||||
|
||||
static char* strcpy_val(char *out, const char *val, size_t len);
|
||||
extern char bufFloat[20];
|
||||
|
||||
static char*
|
||||
gen_float(char *out, const void *val)
|
||||
{
|
||||
char bufFloat[32];
|
||||
memset(bufFloat, 0, sizeof(bufFloat));
|
||||
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
fromFloat(bufFloat, val);
|
||||
|
||||
return strcpy_val(out, &bufFloat[0], strlen(bufFloat));
|
||||
}
|
||||
|
||||
static size_t remaining_length;
|
||||
|
||||
static int
|
||||
reduce_rem_len(size_t len)
|
||||
{
|
||||
if (remaining_length < len)
|
||||
return 0;
|
||||
remaining_length -= len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char*
|
||||
strcpy_val(char *out, const char *val, size_t len)
|
||||
{
|
||||
if (!reduce_rem_len(len))
|
||||
return NULL;
|
||||
memcpy(out, val, len);
|
||||
return out + len;
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_null(char *out, const void *val)
|
||||
{
|
||||
(void)val;
|
||||
return strcpy_val(out, "null", 4);
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_boolean(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
if (*(_Bool*)val)
|
||||
return strcpy_val(out, "true", 4);
|
||||
else
|
||||
return strcpy_val(out, "false", 5);
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_string(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
if (!reduce_rem_len(2)) // 2 -> ""
|
||||
return NULL;
|
||||
|
||||
char chars_to_escape[] = "\"\\";
|
||||
const char *begin = (const char*)val;
|
||||
const char *end = begin + strlen(begin);
|
||||
|
||||
*out++ = '"';
|
||||
char *esc;
|
||||
do {
|
||||
esc = NULL;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
char *tmp;
|
||||
if ((tmp = strchr(begin, chars_to_escape[i]))) {
|
||||
if (!esc)
|
||||
esc = tmp;
|
||||
else
|
||||
esc = esc < tmp ? esc : tmp;
|
||||
}
|
||||
}
|
||||
|
||||
size_t len = esc ? (size_t)(esc - begin) : (size_t)(end - begin);
|
||||
|
||||
if (!(out = strcpy_val(out, begin, len)))
|
||||
return NULL;
|
||||
|
||||
if (esc) {
|
||||
char s[2];
|
||||
s[0] = '\\';
|
||||
s[1] = *esc;
|
||||
if (!(out = strcpy_val(out, s, 2)))
|
||||
return NULL;
|
||||
begin = esc + 1;
|
||||
}
|
||||
|
||||
} while (esc && *begin);
|
||||
|
||||
*out++ = '"';
|
||||
return out;
|
||||
}
|
||||
|
||||
static char*
|
||||
utoa(char *dst, unsigned n, unsigned base)
|
||||
{
|
||||
char *s = dst;
|
||||
char *e;
|
||||
|
||||
for (unsigned m = n; m >= base; m /= base)
|
||||
s++;
|
||||
e = s + 1;
|
||||
|
||||
size_t len = (size_t)(e - dst);
|
||||
if (!reduce_rem_len(len))
|
||||
return NULL;
|
||||
|
||||
for ( ; s >= dst; s--, n /= base)
|
||||
*s = "0123456789ABCDEF"[n % base];
|
||||
return e;
|
||||
}
|
||||
|
||||
static char*
|
||||
ultoa(char *dst, unsigned long n, unsigned base)
|
||||
{
|
||||
char *s = dst;
|
||||
char *e;
|
||||
|
||||
for (unsigned long m = n; m >= base; m /= base)
|
||||
s++;
|
||||
e = s + 1;
|
||||
|
||||
size_t len = (size_t)(e - dst);
|
||||
if (!reduce_rem_len(len))
|
||||
return NULL;
|
||||
|
||||
for ( ; s >= dst; s--, n /= base)
|
||||
*s = "0123456789ABCDEF"[n % base];
|
||||
return e;
|
||||
}
|
||||
|
||||
static char*
|
||||
ulltoa(char *dst, unsigned long long n, unsigned base)
|
||||
{
|
||||
char *s = dst;
|
||||
char *e;
|
||||
|
||||
for (unsigned long long m = n; m >= base; m /= base)
|
||||
s++;
|
||||
e = s + 1;
|
||||
|
||||
size_t len = (size_t)(e - dst);
|
||||
if (!reduce_rem_len(len))
|
||||
return NULL;
|
||||
|
||||
for ( ; s >= dst; s--, n /= base)
|
||||
*s = "0123456789ABCDEF"[n % base];
|
||||
return e;
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_hex(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
if (!reduce_rem_len(2)) // 2 -> ""
|
||||
return NULL;
|
||||
|
||||
*out++ = '"';
|
||||
if (!(out = utoa(out, *(unsigned*)val, 16)))
|
||||
return NULL;
|
||||
*out++ = '"';
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_hex_u8(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
if (!reduce_rem_len(2)) // 2 -> ""
|
||||
return NULL;
|
||||
|
||||
*out++ = '"';
|
||||
if (!(out = utoa(out, *(uint8_t*)val, 16)))
|
||||
return NULL;
|
||||
*out++ = '"';
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_hex_u16(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
if (!reduce_rem_len(2)) // 2 -> ""
|
||||
return NULL;
|
||||
|
||||
*out++ = '"';
|
||||
if (!(out = utoa(out, *(uint16_t*)val, 16)))
|
||||
return NULL;
|
||||
*out++ = '"';
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_hex_u32(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
if (!reduce_rem_len(2)) // 2 -> ""
|
||||
return NULL;
|
||||
|
||||
*out++ = '"';
|
||||
if (!(out = ultoa(out, *(uint32_t*)val, 16)))
|
||||
return NULL;
|
||||
*out++ = '"';
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_hex_u64(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
if (!reduce_rem_len(2)) // 2 -> ""
|
||||
return NULL;
|
||||
|
||||
*out++ = '"';
|
||||
if (!(out = ulltoa(out, *(uint64_t*)val, 16)))
|
||||
return NULL;
|
||||
*out++ = '"';
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_int(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
int n = *(int*)val;
|
||||
unsigned u = (unsigned)n;
|
||||
if (n < 0){
|
||||
if (!reduce_rem_len(1))
|
||||
return NULL;
|
||||
*out++ = '-';
|
||||
u = -(unsigned)n;
|
||||
}
|
||||
|
||||
if (!(out = utoa(out, u, 10)))
|
||||
return NULL;
|
||||
return out;
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_int8_t(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
int n = *(int8_t*)val;
|
||||
unsigned u = (unsigned)n;
|
||||
if (n < 0){
|
||||
if (!reduce_rem_len(1))
|
||||
return NULL;
|
||||
*out++ = '-';
|
||||
u = -(unsigned)n;
|
||||
}
|
||||
|
||||
if (!(out = utoa(out, u, 10)))
|
||||
return NULL;
|
||||
return out;
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_int16_t(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
int n = *(int16_t*)val;
|
||||
unsigned u = (unsigned)n;
|
||||
if (n < 0){
|
||||
if (!reduce_rem_len(1))
|
||||
return NULL;
|
||||
*out++ = '-';
|
||||
u = -(unsigned)n;
|
||||
}
|
||||
|
||||
if (!(out = utoa(out, u, 10)))
|
||||
return NULL;
|
||||
return out;
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_int32_t(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
int n = *(int*)val;
|
||||
unsigned u = (unsigned)n;
|
||||
if (n < 0){
|
||||
if (!reduce_rem_len(1))
|
||||
return NULL;
|
||||
*out++ = '-';
|
||||
u = -(unsigned)n;
|
||||
}
|
||||
|
||||
if (!(out = utoa(out, u, 10)))
|
||||
return NULL;
|
||||
return out;
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_int64_t(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
int64_t n = *(int64_t*)val;
|
||||
uint64_t u = (uint64_t)n;
|
||||
if (n < 0){
|
||||
if (!reduce_rem_len(1))
|
||||
return NULL;
|
||||
*out++ = '-';
|
||||
u = -(uint64_t)n;
|
||||
}
|
||||
|
||||
if (!(out = ulltoa(out, u, 10)))
|
||||
return NULL;
|
||||
return out;
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_uint(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
return utoa(out, *(unsigned*)val, 10);
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_uint8_t(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
return utoa(out, *(uint8_t*)val, 10);
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_uint16_t(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
return utoa(out, *(uint16_t*)val, 10);
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_uint32_t(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
return ultoa(out, *(uint32_t*)val, 10);
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_uint64_t(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
return ulltoa(out, *(uint64_t*)val, 10);
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_long(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
long n = *(long*)val;
|
||||
unsigned long u = (unsigned long)n;
|
||||
if (n < 0){
|
||||
if (!reduce_rem_len(1))
|
||||
return NULL;
|
||||
*out++ = '-';
|
||||
u = -(unsigned long)n;
|
||||
}
|
||||
|
||||
if (!(out = ultoa(out, u, 10)))
|
||||
return NULL;
|
||||
return out;
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_longlong(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
long long n = *(long long*)val;
|
||||
unsigned long long u = (unsigned long long)n;
|
||||
if (n < 0){
|
||||
if (!reduce_rem_len(1))
|
||||
return NULL;
|
||||
*out++ = '-';
|
||||
u = -(unsigned long long)n;
|
||||
}
|
||||
|
||||
if (!(out = ulltoa(out, u, 10)))
|
||||
return NULL;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
static char*
|
||||
gen_ulong(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
return ultoa(out, *(unsigned long*)val, 10);
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_ulonglong(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
return ulltoa(out, *(unsigned long long*)val, 10);
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_value(char *out, const void *val)
|
||||
{
|
||||
return strcpy_val(out, (const char*)val, strlen((const char*)val));
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_c_array(char *out, const void *val)
|
||||
{
|
||||
const struct to_json *tjs = (const struct to_json*)val;
|
||||
if (!reduce_rem_len(2)) // 2 -> []
|
||||
return NULL;
|
||||
|
||||
*out++ = '[';
|
||||
if (*tjs->count == 0){
|
||||
*out++ = ']';
|
||||
return out;
|
||||
}
|
||||
|
||||
size_t incr = 0;
|
||||
char* (*func)(char *, const void *) = gen_functions[tjs->vtype];
|
||||
switch (tjs->vtype) {
|
||||
case t_to_boolean:
|
||||
incr = sizeof(_Bool);
|
||||
break;
|
||||
|
||||
case t_to_int:
|
||||
incr = sizeof(int);
|
||||
break;
|
||||
|
||||
case t_to_int8_t:
|
||||
incr = sizeof(int8_t);
|
||||
break;
|
||||
|
||||
case t_to_int16_t:
|
||||
incr = sizeof(int16_t);
|
||||
break;
|
||||
|
||||
case t_to_int32_t:
|
||||
incr = sizeof(int32_t);
|
||||
break;
|
||||
|
||||
case t_to_float:
|
||||
incr = sizeof(float);
|
||||
break;
|
||||
|
||||
case t_to_int64_t:
|
||||
incr = sizeof(int64_t);
|
||||
break;
|
||||
|
||||
case t_to_long:
|
||||
incr = sizeof(unsigned long);
|
||||
break;
|
||||
|
||||
case t_to_longlong:
|
||||
incr = sizeof(unsigned long long);
|
||||
break;
|
||||
|
||||
case t_to_object:
|
||||
incr = sizeof(struct to_json);
|
||||
break;
|
||||
|
||||
case t_to_hex:
|
||||
case t_to_uint:
|
||||
incr = sizeof(unsigned);
|
||||
break;
|
||||
|
||||
case t_to_hex_u8:
|
||||
case t_to_uint8_t:
|
||||
incr = sizeof(uint8_t);
|
||||
break;
|
||||
|
||||
case t_to_hex_u16:
|
||||
case t_to_uint16_t:
|
||||
incr = sizeof(uint16_t);
|
||||
break;
|
||||
|
||||
case t_to_hex_u32:
|
||||
case t_to_uint32_t:
|
||||
incr = sizeof(uint32_t);
|
||||
break;
|
||||
|
||||
case t_to_hex_u64:
|
||||
case t_to_uint64_t:
|
||||
incr = sizeof(uint64_t);
|
||||
break;
|
||||
|
||||
case t_to_ulong:
|
||||
incr = sizeof(unsigned long);
|
||||
break;
|
||||
|
||||
case t_to_ulonglong:
|
||||
incr = sizeof(unsigned long long);
|
||||
break;
|
||||
|
||||
case t_to_array:
|
||||
case t_to_null:
|
||||
case t_to_primitive:
|
||||
case t_to_string:
|
||||
case t_to_value:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *p = tjs->value;
|
||||
for (size_t i = 0; i < *tjs->count - 1; i++){
|
||||
if (!(out = (*func)(out, p)))
|
||||
return NULL;
|
||||
if (!reduce_rem_len(1))
|
||||
return NULL;
|
||||
*out++ = ',';
|
||||
|
||||
p += incr;
|
||||
}
|
||||
|
||||
if (!(out = (*func)(out, p)))
|
||||
return NULL;
|
||||
|
||||
*out++ = ']';
|
||||
return out;
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_array(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
const struct to_json *tjs = (const struct to_json*)val;
|
||||
if (!reduce_rem_len(2)) // 2 -> []
|
||||
return NULL;
|
||||
|
||||
*out++ = '[';
|
||||
while (tjs->value){
|
||||
if (tjs->count)
|
||||
out = gen_c_array(out, tjs);
|
||||
else
|
||||
out = gen_functions[tjs->vtype](out, tjs->value);
|
||||
if (!out)
|
||||
return NULL;
|
||||
tjs++;
|
||||
if (tjs->value){
|
||||
if (!reduce_rem_len(1))
|
||||
return NULL;
|
||||
*out++ = ',';
|
||||
}
|
||||
}
|
||||
*out++ = ']';
|
||||
return out;
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_object(char *out, const void *val)
|
||||
{
|
||||
if (!val)
|
||||
return gen_null(out, val);
|
||||
|
||||
const struct to_json *tjs = (const struct to_json*)val;
|
||||
|
||||
if (!reduce_rem_len(2)) // 2 -> {}
|
||||
return NULL;
|
||||
|
||||
*out++ = '{';
|
||||
while (tjs->name){
|
||||
const char *name = tjs->name;
|
||||
size_t len = strlen(name) ;
|
||||
if (!reduce_rem_len(len + 3)) // 3 -> "":
|
||||
return NULL;
|
||||
|
||||
*out++ = '"';
|
||||
memcpy(out, name, len);
|
||||
out += len;
|
||||
*out++ = '"';
|
||||
*out++ = ':';
|
||||
|
||||
if (tjs->count)
|
||||
out = gen_c_array(out, tjs);
|
||||
else
|
||||
out = gen_functions[tjs->vtype](out, tjs->value);
|
||||
|
||||
if (!out)
|
||||
return NULL;
|
||||
|
||||
tjs++;
|
||||
if (tjs->name){
|
||||
if (!reduce_rem_len(1))
|
||||
return NULL;
|
||||
*out++ = ',';
|
||||
}
|
||||
}
|
||||
|
||||
*out++ = '}';
|
||||
return out;
|
||||
}
|
||||
|
||||
static char*
|
||||
gen_primitive(char *out, const void *to_json)
|
||||
{
|
||||
const struct to_json *tjs = (const struct to_json *)to_json;
|
||||
if (tjs->count)
|
||||
return gen_c_array(out, tjs);
|
||||
|
||||
return gen_functions[tjs->vtype](out, tjs->value);
|
||||
}
|
||||
|
||||
size_t
|
||||
json_generate(char *out, const struct to_json *tjs, size_t len)
|
||||
{
|
||||
const char *start = out;
|
||||
|
||||
remaining_length = len;
|
||||
if (!reduce_rem_len(1)) // \0
|
||||
return 0;
|
||||
|
||||
switch (tjs->stype) {
|
||||
case t_to_array:
|
||||
out = gen_array(out, tjs);
|
||||
break;
|
||||
case t_to_object:
|
||||
out = gen_object(out, tjs);
|
||||
break;
|
||||
case t_to_primitive:
|
||||
out = gen_primitive(out, tjs);
|
||||
break;
|
||||
/* These are not valid ctypes */
|
||||
case t_to_boolean:
|
||||
case t_to_int:
|
||||
case t_to_null:
|
||||
case t_to_string:
|
||||
case t_to_uint:
|
||||
case t_to_value:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!out)
|
||||
return 0;
|
||||
|
||||
*out = '\0';
|
||||
return (size_t)(out - start);
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
//
|
||||
// Created by cfif on 27.10.22.
|
||||
//
|
||||
#include <string.h>
|
||||
#include "tiny-json.h"
|
||||
#include "mtojson.h"
|
||||
|
||||
typedef struct {
|
||||
float param1;
|
||||
char param2[16];
|
||||
uint32_t param3;
|
||||
uint32_t param4;
|
||||
uint32_t param5;
|
||||
} com1;
|
||||
|
||||
typedef struct {
|
||||
uint32_t param1;
|
||||
uint32_t param2;
|
||||
uint32_t param3;
|
||||
uint32_t param4;
|
||||
uint32_t param5;
|
||||
} com2;
|
||||
|
||||
com1 dataCom1 = {1.123456, "qwerty", 3, 4, 5};
|
||||
com2 dataCom2 = {6, 7,8, 9, 0};
|
||||
|
||||
const char *listComName[] = {"com1", "com2"};
|
||||
const void *listComStruct[] = { &dataCom1, &dataCom2};
|
||||
const int countListCom = sizeof(listComStruct) / 4;
|
||||
|
||||
const struct to_json jsonDataArray1[] = {
|
||||
{.value = &dataCom1.param1, .vtype = t_to_float, .stype = t_to_array},
|
||||
{.value = &dataCom1.param2, .vtype = t_to_string,},
|
||||
{.value = &dataCom1.param3, .vtype = t_to_uint32_t,},
|
||||
{.value = &dataCom1.param4, .vtype = t_to_uint32_t,},
|
||||
{.value = &dataCom1.param5, .vtype = t_to_uint32_t,},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
const struct to_json jsonDataArray2[] = {
|
||||
{.value = &dataCom2.param1, .vtype = t_to_uint32_t, .stype = t_to_array},
|
||||
{.value = &dataCom2.param2, .vtype = t_to_uint32_t,},
|
||||
{.value = &dataCom2.param3, .vtype = t_to_uint32_t,},
|
||||
{.value = &dataCom2.param4, .vtype = t_to_uint32_t,},
|
||||
{.value = &dataCom2.param5, .vtype = t_to_uint32_t,},
|
||||
{NULL}
|
||||
|
||||
};
|
||||
|
||||
const struct to_json jsonCom1 = {.name = "com1", .value = &jsonDataArray1, .vtype = t_to_array, .stype = t_to_object};
|
||||
const struct to_json jsonCom2 = {.name = "com2", .value = &jsonDataArray2, .vtype = t_to_array, .stype = t_to_object};
|
||||
|
||||
enum { MAX_STRING_LEN = 1000 };
|
||||
char json_text[MAX_STRING_LEN] = {0};
|
||||
|
||||
void testJson() {
|
||||
|
||||
const struct to_json jsonDataObject[] = {
|
||||
jsonCom1,
|
||||
jsonCom2,
|
||||
{NULL}
|
||||
};
|
||||
|
||||
size_t json_len = json_generate(&json_text[0], jsonDataObject, MAX_STRING_LEN);
|
||||
|
||||
|
||||
dataCom1.param1 = 0;
|
||||
strcpy(dataCom1.param2, "qaz");
|
||||
dataCom1.param3 = 0;
|
||||
dataCom1.param4 = 0;
|
||||
dataCom1.param5 = 0;
|
||||
|
||||
dataCom2.param1 = 0;
|
||||
dataCom2.param2 = 0;
|
||||
dataCom2.param3 = 0;
|
||||
dataCom2.param4 = 0;
|
||||
dataCom2.param5 = 0;
|
||||
|
||||
|
||||
json_t pool[1000];
|
||||
unsigned const qty = sizeof pool / sizeof *pool;
|
||||
char comName[20];
|
||||
|
||||
//char str[] = "{\"com1\":[ 11.12345, \"qwertyuiop\", 13, 14, 15 ], \"com2\":[ 16, 17, 18, 19, 20 ]}";
|
||||
|
||||
json_t const *json = json_create(json_text, pool, qty);
|
||||
|
||||
json_t const *elementRoot = json_getChild(json);
|
||||
while (elementRoot != 0) {
|
||||
|
||||
strcpy(comName, json_getName(elementRoot));
|
||||
|
||||
void *data_p = NULL;
|
||||
|
||||
for (int i = 0; i < countListCom; ++i) {
|
||||
if (strncmp(comName, listComName[i], strlen(listComName[i])) == 0) {
|
||||
data_p = listComStruct[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (data_p == NULL)
|
||||
continue;
|
||||
|
||||
json_t const *array = json_getProperty(json, comName);
|
||||
json_t const *element = json_getChild(array);
|
||||
while (element != 0) {
|
||||
|
||||
if (json_getType(element) == JSON_REAL) {
|
||||
((float *) data_p)[0] = (float) json_getReal(element);
|
||||
data_p += 4;
|
||||
}
|
||||
|
||||
if (json_getType(element) == JSON_INTEGER) {
|
||||
((uint32_t *) data_p)[0] = json_getInteger(element);
|
||||
data_p += 4;
|
||||
}
|
||||
|
||||
if (json_getType(element) == JSON_TEXT) {
|
||||
strcpy(data_p, json_getValue(element));
|
||||
data_p += 16;
|
||||
}
|
||||
|
||||
|
||||
element = json_getSibling(element);
|
||||
}
|
||||
|
||||
elementRoot = json_getSibling(elementRoot);
|
||||
}
|
||||
|
||||
dataCom2.param5 = 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,461 @@
|
|||
|
||||
/*
|
||||
|
||||
<https://github.com/rafagafe/tiny-json>
|
||||
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2016-2018 Rafa Garcia <rafagarcia77@gmail.com>.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "tiny-json.h"
|
||||
|
||||
/** Structure to handle a heap of JSON properties. */
|
||||
typedef struct jsonStaticPool_s {
|
||||
json_t* mem; /**< Pointer to array of json properties. */
|
||||
unsigned int qty; /**< Length of the array of json properties. */
|
||||
unsigned int nextFree; /**< The index of the next free json property. */
|
||||
jsonPool_t pool;
|
||||
} jsonStaticPool_t;
|
||||
|
||||
/* Search a property by its name in a JSON object. */
|
||||
json_t const* json_getProperty( json_t const* obj, char const* property ) {
|
||||
json_t const* sibling;
|
||||
for( sibling = obj->u.c.child; sibling; sibling = sibling->sibling )
|
||||
if ( sibling->name && !strcmp( sibling->name, property ) )
|
||||
return sibling;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Search a property by its name in a JSON object and return its value. */
|
||||
char const* json_getPropertyValue( json_t const* obj, char const* property ) {
|
||||
json_t const* field = json_getProperty( obj, property );
|
||||
if ( !field ) return 0;
|
||||
jsonType_t type = json_getType( field );
|
||||
if ( JSON_ARRAY >= type ) return 0;
|
||||
return json_getValue( field );
|
||||
}
|
||||
|
||||
/* Internal prototypes: */
|
||||
static char* goBlank( char* str );
|
||||
static char* goNum( char* str );
|
||||
static json_t* poolInit( jsonPool_t* pool );
|
||||
static json_t* poolAlloc( jsonPool_t* pool );
|
||||
static char* objValue( char* ptr, json_t* obj, jsonPool_t* pool );
|
||||
static char* setToNull( char* ch );
|
||||
static bool isEndOfPrimitive( char ch );
|
||||
|
||||
/* Parse a string to get a json. */
|
||||
json_t const* json_createWithPool( char *str, jsonPool_t *pool ) {
|
||||
char* ptr = goBlank( str );
|
||||
if ( !ptr || (*ptr != '{' && *ptr != '[') ) return 0;
|
||||
json_t* obj = pool->init( pool );
|
||||
obj->name = 0;
|
||||
obj->sibling = 0;
|
||||
obj->u.c.child = 0;
|
||||
ptr = objValue( ptr, obj, pool );
|
||||
if ( !ptr ) return 0;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* Parse a string to get a json. */
|
||||
json_t const* json_create( char* str, json_t mem[], unsigned int qty ) {
|
||||
jsonStaticPool_t spool;
|
||||
spool.mem = mem;
|
||||
spool.qty = qty;
|
||||
spool.pool.init = poolInit;
|
||||
spool.pool.alloc = poolAlloc;
|
||||
return json_createWithPool( str, &spool.pool );
|
||||
}
|
||||
|
||||
/** Get a special character with its escape character. Examples:
|
||||
* 'b' -> '\\b', 'n' -> '\\n', 't' -> '\\t'
|
||||
* @param ch The escape character.
|
||||
* @retval The character code. */
|
||||
static char getEscape( char ch ) {
|
||||
static struct { char ch; char code; } const pair[] = {
|
||||
{ '\"', '\"' }, { '\\', '\\' },
|
||||
{ '/', '/' }, { 'b', '\b' },
|
||||
{ 'f', '\f' }, { 'n', '\n' },
|
||||
{ 'r', '\r' }, { 't', '\t' },
|
||||
};
|
||||
unsigned int i;
|
||||
for( i = 0; i < sizeof pair / sizeof *pair; ++i )
|
||||
if ( pair[i].ch == ch )
|
||||
return pair[i].code;
|
||||
return '\0';
|
||||
}
|
||||
|
||||
/** Parse 4 characters.
|
||||
* @param str Pointer to first digit.
|
||||
* @retval '?' If the four characters are hexadecimal digits.
|
||||
* @retval '\0' In other cases. */
|
||||
static unsigned char getCharFromUnicode( unsigned char const* str ) {
|
||||
unsigned int i;
|
||||
for( i = 0; i < 4; ++i )
|
||||
if ( !isxdigit( str[i] ) )
|
||||
return '\0';
|
||||
return '?';
|
||||
}
|
||||
|
||||
/** Parse a string and replace the scape characters by their meaning characters.
|
||||
* This parser stops when finds the character '\"'. Then replaces '\"' by '\0'.
|
||||
* @param str Pointer to first character.
|
||||
* @retval Pointer to first non white space after the string. If success.
|
||||
* @retval Null pointer if any error occur. */
|
||||
static char* parseString( char* str ) {
|
||||
unsigned char* head = (unsigned char*)str;
|
||||
unsigned char* tail = (unsigned char*)str;
|
||||
for( ; *head; ++head, ++tail ) {
|
||||
if ( *head == '\"' ) {
|
||||
*tail = '\0';
|
||||
return (char*)++head;
|
||||
}
|
||||
if ( *head == '\\' ) {
|
||||
if ( *++head == 'u' ) {
|
||||
char const ch = getCharFromUnicode( ++head );
|
||||
if ( ch == '\0' ) return 0;
|
||||
*tail = ch;
|
||||
head += 3;
|
||||
}
|
||||
else {
|
||||
char const esc = getEscape( *head );
|
||||
if ( esc == '\0' ) return 0;
|
||||
*tail = esc;
|
||||
}
|
||||
}
|
||||
else *tail = *head;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Parse a string to get the name of a property.
|
||||
* @param ptr Pointer to first character.
|
||||
* @param property The property to assign the name.
|
||||
* @retval Pointer to first of property value. If success.
|
||||
* @retval Null pointer if any error occur. */
|
||||
static char* propertyName( char* ptr, json_t* property ) {
|
||||
property->name = ++ptr;
|
||||
ptr = parseString( ptr );
|
||||
if ( !ptr ) return 0;
|
||||
ptr = goBlank( ptr );
|
||||
if ( !ptr ) return 0;
|
||||
if ( *ptr++ != ':' ) return 0;
|
||||
return goBlank( ptr );
|
||||
}
|
||||
|
||||
/** Parse a string to get the value of a property when its type is JSON_TEXT.
|
||||
* @param ptr Pointer to first character ('\"').
|
||||
* @param property The property to assign the name.
|
||||
* @retval Pointer to first non white space after the string. If success.
|
||||
* @retval Null pointer if any error occur. */
|
||||
static char* textValue( char* ptr, json_t* property ) {
|
||||
++property->u.value;
|
||||
ptr = parseString( ++ptr );
|
||||
if ( !ptr ) return 0;
|
||||
property->type = JSON_TEXT;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/** Compare two strings until get the null character in the second one.
|
||||
* @param ptr sub string
|
||||
* @param str main string
|
||||
* @retval Pointer to next character.
|
||||
* @retval Null pointer if any error occur. */
|
||||
static char* checkStr( char* ptr, char const* str ) {
|
||||
while( *str )
|
||||
if ( *ptr++ != *str++ )
|
||||
return 0;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/** Parser a string to get a primitive value.
|
||||
* If the first character after the value is different of '}' or ']' is set to '\0'.
|
||||
* @param ptr Pointer to first character.
|
||||
* @param property Property handler to set the value and the type, (true, false or null).
|
||||
* @param value String with the primitive literal.
|
||||
* @param type The code of the type. ( JSON_BOOLEAN or JSON_NULL )
|
||||
* @retval Pointer to first non white space after the string. If success.
|
||||
* @retval Null pointer if any error occur. */
|
||||
static char* primitiveValue( char* ptr, json_t* property, char const* value, jsonType_t type ) {
|
||||
ptr = checkStr( ptr, value );
|
||||
if ( !ptr || !isEndOfPrimitive( *ptr ) ) return 0;
|
||||
ptr = setToNull( ptr );
|
||||
property->type = type;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/** Parser a string to get a true value.
|
||||
* If the first character after the value is different of '}' or ']' is set to '\0'.
|
||||
* @param ptr Pointer to first character.
|
||||
* @param property Property handler to set the value and the type, (true, false or null).
|
||||
* @retval Pointer to first non white space after the string. If success.
|
||||
* @retval Null pointer if any error occur. */
|
||||
static char* trueValue( char* ptr, json_t* property ) {
|
||||
return primitiveValue( ptr, property, "true", JSON_BOOLEAN );
|
||||
}
|
||||
|
||||
/** Parser a string to get a false value.
|
||||
* If the first character after the value is different of '}' or ']' is set to '\0'.
|
||||
* @param ptr Pointer to first character.
|
||||
* @param property Property handler to set the value and the type, (true, false or null).
|
||||
* @retval Pointer to first non white space after the string. If success.
|
||||
* @retval Null pointer if any error occur. */
|
||||
static char* falseValue( char* ptr, json_t* property ) {
|
||||
return primitiveValue( ptr, property, "false", JSON_BOOLEAN );
|
||||
}
|
||||
|
||||
/** Parser a string to get a null value.
|
||||
* If the first character after the value is different of '}' or ']' is set to '\0'.
|
||||
* @param ptr Pointer to first character.
|
||||
* @param property Property handler to set the value and the type, (true, false or null).
|
||||
* @retval Pointer to first non white space after the string. If success.
|
||||
* @retval Null pointer if any error occur. */
|
||||
static char* nullValue( char* ptr, json_t* property ) {
|
||||
return primitiveValue( ptr, property, "null", JSON_NULL );
|
||||
}
|
||||
|
||||
/** Analyze the exponential part of a real number.
|
||||
* @param ptr Pointer to first character.
|
||||
* @retval Pointer to first non numerical after the string. If success.
|
||||
* @retval Null pointer if any error occur. */
|
||||
static char* expValue( char* ptr ) {
|
||||
if ( *ptr == '-' || *ptr == '+' ) ++ptr;
|
||||
if ( !isdigit( (int)(*ptr) ) ) return 0;
|
||||
ptr = goNum( ++ptr );
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/** Analyze the decimal part of a real number.
|
||||
* @param ptr Pointer to first character.
|
||||
* @retval Pointer to first non numerical after the string. If success.
|
||||
* @retval Null pointer if any error occur. */
|
||||
static char* fraqValue( char* ptr ) {
|
||||
if ( !isdigit( (int)(*ptr) ) ) return 0;
|
||||
ptr = goNum( ++ptr );
|
||||
if ( !ptr ) return 0;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/** Parser a string to get a numerical value.
|
||||
* If the first character after the value is different of '}' or ']' is set to '\0'.
|
||||
* @param ptr Pointer to first character.
|
||||
* @param property Property handler to set the value and the type: JSON_REAL or JSON_INTEGER.
|
||||
* @retval Pointer to first non white space after the string. If success.
|
||||
* @retval Null pointer if any error occur. */
|
||||
static char* numValue( char* ptr, json_t* property ) {
|
||||
if ( *ptr == '-' ) ++ptr;
|
||||
if ( !isdigit( (int)(*ptr) ) ) return 0;
|
||||
if ( *ptr != '0' ) {
|
||||
ptr = goNum( ptr );
|
||||
if ( !ptr ) return 0;
|
||||
}
|
||||
else if ( isdigit( (int)(*++ptr) ) ) return 0;
|
||||
property->type = JSON_INTEGER;
|
||||
if ( *ptr == '.' ) {
|
||||
ptr = fraqValue( ++ptr );
|
||||
if ( !ptr ) return 0;
|
||||
property->type = JSON_REAL;
|
||||
}
|
||||
if ( *ptr == 'e' || *ptr == 'E' ) {
|
||||
ptr = expValue( ++ptr );
|
||||
if ( !ptr ) return 0;
|
||||
property->type = JSON_REAL;
|
||||
}
|
||||
if ( !isEndOfPrimitive( *ptr ) ) return 0;
|
||||
if ( JSON_INTEGER == property->type ) {
|
||||
char const* value = property->u.value;
|
||||
bool const negative = *value == '-';
|
||||
static char const min[] = "-9223372036854775808";
|
||||
static char const max[] = "9223372036854775807";
|
||||
unsigned int const maxdigits = ( negative? sizeof min: sizeof max ) - 1;
|
||||
unsigned int const len = ( unsigned int const ) ( ptr - value );
|
||||
if ( len > maxdigits ) return 0;
|
||||
if ( len == maxdigits ) {
|
||||
char const tmp = *ptr;
|
||||
*ptr = '\0';
|
||||
char const* const threshold = negative ? min: max;
|
||||
if ( 0 > strcmp( threshold, value ) ) return 0;
|
||||
*ptr = tmp;
|
||||
}
|
||||
}
|
||||
ptr = setToNull( ptr );
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/** Add a property to a JSON object or array.
|
||||
* @param obj The handler of the JSON object or array.
|
||||
* @param property The handler of the property to be added. */
|
||||
static void add( json_t* obj, json_t* property ) {
|
||||
property->sibling = 0;
|
||||
if ( !obj->u.c.child ){
|
||||
obj->u.c.child = property;
|
||||
obj->u.c.last_child = property;
|
||||
} else {
|
||||
obj->u.c.last_child->sibling = property;
|
||||
obj->u.c.last_child = property;
|
||||
}
|
||||
}
|
||||
|
||||
/** Parser a string to get a json object value.
|
||||
* @param ptr Pointer to first character.
|
||||
* @param obj The handler of the JSON root object or array.
|
||||
* @param pool The handler of a json pool for creating json instances.
|
||||
* @retval Pointer to first character after the value. If success.
|
||||
* @retval Null pointer if any error occur. */
|
||||
static char* objValue( char* ptr, json_t* obj, jsonPool_t* pool ) {
|
||||
obj->type = *ptr == '{' ? JSON_OBJ : JSON_ARRAY;
|
||||
obj->u.c.child = 0;
|
||||
obj->sibling = 0;
|
||||
ptr++;
|
||||
for(;;) {
|
||||
ptr = goBlank( ptr );
|
||||
if ( !ptr ) return 0;
|
||||
if ( *ptr == ',' ) {
|
||||
++ptr;
|
||||
continue;
|
||||
}
|
||||
char const endchar = ( obj->type == JSON_OBJ )? '}': ']';
|
||||
if ( *ptr == endchar ) {
|
||||
*ptr = '\0';
|
||||
json_t* parentObj = obj->sibling;
|
||||
if ( !parentObj ) return ++ptr;
|
||||
obj->sibling = 0;
|
||||
obj = parentObj;
|
||||
++ptr;
|
||||
continue;
|
||||
}
|
||||
json_t* property = pool->alloc( pool );
|
||||
if ( !property ) return 0;
|
||||
if( obj->type != JSON_ARRAY ) {
|
||||
if ( *ptr != '\"' ) return 0;
|
||||
ptr = propertyName( ptr, property );
|
||||
if ( !ptr ) return 0;
|
||||
}
|
||||
else property->name = 0;
|
||||
add( obj, property );
|
||||
property->u.value = ptr;
|
||||
switch( *ptr ) {
|
||||
case '{':
|
||||
property->type = JSON_OBJ;
|
||||
property->u.c.child = 0;
|
||||
property->sibling = obj;
|
||||
obj = property;
|
||||
++ptr;
|
||||
break;
|
||||
case '[':
|
||||
property->type = JSON_ARRAY;
|
||||
property->u.c.child = 0;
|
||||
property->sibling = obj;
|
||||
obj = property;
|
||||
++ptr;
|
||||
break;
|
||||
case '\"': ptr = textValue( ptr, property ); break;
|
||||
case 't': ptr = trueValue( ptr, property ); break;
|
||||
case 'f': ptr = falseValue( ptr, property ); break;
|
||||
case 'n': ptr = nullValue( ptr, property ); break;
|
||||
default: ptr = numValue( ptr, property ); break;
|
||||
}
|
||||
if ( !ptr ) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize a json pool.
|
||||
* @param pool The handler of the pool.
|
||||
* @return a instance of a json. */
|
||||
static json_t* poolInit( jsonPool_t* pool ) {
|
||||
jsonStaticPool_t *spool = json_containerOf( pool, jsonStaticPool_t, pool );
|
||||
spool->nextFree = 1;
|
||||
return spool->mem;
|
||||
}
|
||||
|
||||
/** Create an instance of a json from a pool.
|
||||
* @param pool The handler of the pool.
|
||||
* @retval The handler of the new instance if success.
|
||||
* @retval Null pointer if the pool was empty. */
|
||||
static json_t* poolAlloc( jsonPool_t* pool ) {
|
||||
jsonStaticPool_t *spool = json_containerOf( pool, jsonStaticPool_t, pool );
|
||||
if ( spool->nextFree >= spool->qty ) return 0;
|
||||
return spool->mem + spool->nextFree++;
|
||||
}
|
||||
|
||||
/** Checks whether an character belongs to set.
|
||||
* @param ch Character value to be checked.
|
||||
* @param set Set of characters. It is just a null-terminated string.
|
||||
* @return true or false there is membership or not. */
|
||||
static bool isOneOfThem( char ch, char const* set ) {
|
||||
while( *set != '\0' )
|
||||
if ( ch == *set++ )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Increases a pointer while it points to a character that belongs to a set.
|
||||
* @param str The initial pointer value.
|
||||
* @param set Set of characters. It is just a null-terminated string.
|
||||
* @return The final pointer value or null pointer if the null character was found. */
|
||||
static char* goWhile( char* str, char const* set ) {
|
||||
for(; *str != '\0'; ++str ) {
|
||||
if ( !isOneOfThem( *str, set ) )
|
||||
return str;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Set of characters that defines a blank. */
|
||||
static char const* const blank = " \n\r\t\f";
|
||||
|
||||
/** Increases a pointer while it points to a white space character.
|
||||
* @param str The initial pointer value.
|
||||
* @return The final pointer value or null pointer if the null character was found. */
|
||||
static char* goBlank( char* str ) {
|
||||
return goWhile( str, blank );
|
||||
}
|
||||
|
||||
/** Increases a pointer while it points to a decimal digit character.
|
||||
* @param str The initial pointer value.
|
||||
* @return The final pointer value or null pointer if the null character was found. */
|
||||
static char* goNum( char* str ) {
|
||||
for( ; *str != '\0'; ++str ) {
|
||||
if ( !isdigit( (int)(*str) ) )
|
||||
return str;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Set of characters that defines the end of an array or a JSON object. */
|
||||
static char const* const endofblock = "}]";
|
||||
|
||||
/** Set a char to '\0' and increase its pointer if the char is different to '}' or ']'.
|
||||
* @param ch Pointer to character.
|
||||
* @return Final value pointer. */
|
||||
static char* setToNull( char* ch ) {
|
||||
if ( !isOneOfThem( *ch, endofblock ) ) *ch++ = '\0';
|
||||
return ch;
|
||||
}
|
||||
|
||||
/** Indicate if a character is the end of a primitive value. */
|
||||
static bool isEndOfPrimitive( char ch ) {
|
||||
return ch == ',' || isOneOfThem( ch, blank ) || isOneOfThem( ch, endofblock );
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"cmake": {
|
||||
"inc_dirs": [
|
||||
"Inc"
|
||||
],
|
||||
"srcs": [
|
||||
"Src/**.c"
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue