|
/* |
|
|
|
* Licensing Info: 2023 - Chubak Bidpaa |
|
* This program is free for use under any conditions or lack thereof. |
|
* Redistribution of this file is permitted under the warranty that the |
|
* distributor agrees with the possible errors and shortcomings of this |
|
program. |
|
* There is zero promise that this code will function without any issues. |
|
* This program has been produced for limited, personal use, and although it |
|
is free |
|
* to distribute and use, the author of this program offers nothing in terms |
|
of assurance |
|
* that it will work and function as the distributor or the user expects it |
|
to do so. |
|
|
|
* NOTICE: Parts of this program remains partly untested. The reason for |
|
posting this is overall comments |
|
|
|
Contact the Author: |
|
* Github: Github.com/chubek |
|
* Email: [email protected] |
|
* Discord: .chubak |
|
|
|
---- shibajs1.h: Quick and Dirty JSON Parsing ---- |
|
No lexing, no syntax analysis, JUST PARSING! |
|
|
|
Notice that this tagline is not a feature. I have made this header-only |
|
'thingy' for my own use, mostly in Native Messaging between my C daemons and |
|
browsers, and other applications with a higher interface which yield a good JSON |
|
serializer. I am posting this application programming interface on the |
|
world-wide web for comments only. However, I am going to teach you how to use |
|
it. Most of shibajs1.h is macros. There's a lot of them. All these macros begin |
|
with J_ as not to be mixed with macros in other source or header files which |
|
will be in the application source tree. If you wish to change this prefix you |
|
may CTRL+F, CTRL+H it. Or you can undefine that macro using `#undef J_[MACRO]`. |
|
|
|
shibajs1.h also has another type of macro, which direct the course of CPP in |
|
preprocessing the file. There is a long list of these macros which I will |
|
mention so shortly. These macros, for example, let you control wether you want |
|
Unicode support or not (which is off by default), whether you want your integer |
|
type to be signed, long etc, whether you want the string parser to mind the |
|
escape characters, etc etc. |
|
|
|
But before introducing these macros, let me tell you about the functions. |
|
There is a total of 9 functions available. The prefix of these functions is |
|
`shibajs1_*` but you may change it, as we will see later. 8 of these functions |
|
are for parsing various aspects of a JSON stream. The 9th function is for |
|
freeing any memory reserved by the key-value pair. These functions are: |
|
|
|
* jstream_t shibajs1_parse_key(jstream_t, jkvpair_t*) |
|
* jstream_t shibajs1_parse_primitive(jstream_t, jkvpair_t*) |
|
* jstream_t shibajs1_parse_integer(jstream_t, jkvpair_t*) |
|
* jstream_t shibajs1_parse_float(jstream_t, jkvpair_t*) |
|
* jstream_t shibajs1_parse_string(jstream_t, jkvpair_t*) |
|
* jstream_t shibajs1_parse_ineger_array(jstream_t, jkvpair_t*, jlength_t) |
|
* jstream_t shibajs1_parse_float_array(jstream_t, jkvpair_t*, jlength_t) |
|
* jstream_t shibajs1_parse_string_array(jstream_t, jkvpair_t*, jlength_t) |
|
* void shibajs1_free_json(jkvpair_t*) |
|
|
|
Keep this in mind: shibajs1.h does NOT do any I/O! You yourself must handle the |
|
I/O. Whether it be Unicode, or ASCII. Generally, to parse a this JSON string: |
|
|
|
``` |
|
{ |
|
"myNull": null, |
|
"myTrue": true, |
|
"myFalse": false, |
|
"myInt": 12000, |
|
"myFloat": 1e-12, |
|
"myString": "myValue", |
|
"myIntArray": [ |
|
1, |
|
2, |
|
4 |
|
], |
|
"myFloatArray": [1.23, 11.2, 1.222, 1e-2], |
|
"myStringArray": [ |
|
"myValue1", |
|
"myValue3" |
|
] |
|
} |
|
``` |
|
|
|
Regardless of where it comes from: |
|
|
|
``` |
|
jstream_t jstream = "...."; |
|
jkvpair_t kvpair; |
|
jstream = shibajs1_parse_key(jstream, &kvpair); |
|
jstream = shibajs1_parse_primitive(jstream, &kvpair); |
|
// ...operate on kvpair... |
|
shibajs1_free_json(&kvpair); |
|
jstream = shibajs1_parse_key(jstream, &kvpair); |
|
jstream = shibajs1_parse_primitive(jstream, &kvpair); |
|
// ...operate on kvpair... |
|
shibajs1_free_json(&kvpair); |
|
jstream = shibajs1_parse_key(jstream, &kvpair); |
|
jstream = shibajs1_parse_primitive(jstream, &kvpair); |
|
// ...operate on kvpair... |
|
shibajs1_free_json(&kvpair); |
|
jstream = shibajs1_parse_key(jstream, &kvpair); |
|
jstream = shibajs1_parse_integer(jstream, &kvpair); |
|
// ...operate on kvpair... |
|
shibajs1_free_json(&kvpair); |
|
jstream = shibajs1_parse_key(jstream, &kvpair); |
|
jstream = shibajs1_parse_float(jstream, &kvpair); |
|
shibajs1_free_json(&kvpair); |
|
jstream = shibajs1_parse_key(jstream, &kvpair); |
|
jstream = shibajs1_parse_string(jstream, &kvpair); |
|
// ...operate on kvpair... |
|
shibajs1_free_json(&kvpair); |
|
jstream = shibajs1_parse_key(jstream, &kvpair); |
|
jstream = shibajs1_parse_integer_array(jstream, &kvpair, 3); |
|
// ...operate on kvpair... |
|
shibajs1_free_json(&kvpair); |
|
jstream = shibajs1_parse_key(jstream, &kvpair); |
|
jstream = shibajs1_parse_float_array(jstream, &kvpair, 4); |
|
shibajs1_free_json(&kvpair); |
|
jstream = shibajs1_parse_key(jstream, &kvpair); |
|
jstream = shibajs1_parse_string_array(jstream, &kvpair, 2); |
|
// ...operate on kvpair... |
|
shibajs1_free_json(&kvpair); |
|
``` |
|
|
|
You don't need to NECESSIRALY use it like this, this is a general guide line |
|
as of how to utilize the functions. NOTE: ALWAYS FREE THE KEY-VALUE PAIR AFTER |
|
USE!!!! Even if it is an integer, float or a primitive, the key is allocated |
|
dynamically (unless you enable __J_ALLOC_ON_STACK__, as we will see). |
|
|
|
So now, let's see what directive preprocessor macros you may use to change the |
|
function of these program. There is a total of 79 macros provided, you can use |
|
any of them basically. Here they are, in alphabetic from: |
|
|
|
|
|
``` |
|
__J_ALLOC_ON_STACK__ |
|
__J_CUST_FALSE_LIT_LEN__ |
|
__J_CUST_FALSE_LIT__ |
|
__J_CUST_FALSE_VAL__ |
|
__J_CUST_FLTCONVFN_REENTRANT__ |
|
__J_CUST_FLTCONVFN__ |
|
__J_CUST_FN_PREFIX__ |
|
__J_CUST_INTCONVFN_REENTRANT__ |
|
__J_CUST_INTCONVFN__ |
|
__J_CUST_INT_BASE__ |
|
__J_CUST_MEMALLOCFN__ |
|
__J_CUST_MEMALLOCFN___ |
|
__J_CUST_MEMCPYFN__ |
|
__J_CUST_MEMFREEFN__ |
|
__J_CUST_MEMSETFN__ |
|
__J_CUST_NULL_LIT_LEN__ |
|
__J_CUST_NULL_LIT__ |
|
__J_CUST_NULL_VAL__ |
|
__J_CUST_PRIMITIVE_VALS__ |
|
__J_CUST_SENTINEL__ |
|
__J_CUST_STRCMPFN__ |
|
__J_CUST_TRUE_LIT_LEN__ |
|
__J_CUST_TRUE_LIT__ |
|
__J_CUST_TRUE_VAL__ |
|
__J_ECONOMIC_ALLOC__ |
|
__J_HEX_MSB_LEFT__ |
|
__J_NO_ERRORS_AT_PREPROCESS__ |
|
__J_NO_FREE_FN__ |
|
__J_NO_INC_ALLOCA_H__ |
|
__J_NO_INC_STDLIB_H__ |
|
__J_NO_INC_STRING_H__ |
|
__J_NO_INC_UNISTD_H__ |
|
__J_NO_INC_WCHAR_H__ |
|
__J_NO_INLINE__ |
|
__J_NO_PARSE_FLOAT_FN__ |
|
__J_NO_PARSE_FLT_ARRAY_FN__ |
|
__J_NO_PARSE_INTEGER_FN__ |
|
__J_NO_PARSE_INT_ARRAY_FN__ |
|
__J_NO_PARSE_KEY_FN__ |
|
__J_NO_PARSE_PRIMITIVE_FN__ |
|
__J_NO_PARSE_STRING_FN__ |
|
__J_NO_PARSE_STR_ARRAY_FN__ |
|
__J_NO_REGISTER__ |
|
__J_NO_SHIBAJS1_PREFIX__ |
|
__J_NO_STATIC__ |
|
__J_NO_STR_ESCAPE__ |
|
__J_NO_ZERO_OUT__ |
|
__J_PEDANTIC_PREPROCESS__ |
|
__J_TYMEMOD_FLOAT_F64__ |
|
__J_TYPEMOD_FLOAT_E64__ |
|
__J_TYPEMOD_FLOAT_F32__ |
|
__J_TYPEMOD_INTEGER_INT__ |
|
__J_TYPEMOD_INTEGER_LONG_LONG__ |
|
__J_TYPEMOD_INTEGER_LONG__ |
|
__J_TYPEMOD_INTEGER_NONE__ |
|
__J_TYPEMOD_INTEGER_SHORT__ |
|
__J_TYPEMOD_INTEGER_SIGNED__ |
|
__J_TYPEMOD_INTEGER_UNSIGNED__ |
|
__J_TYPEMOD_LENGTH_INT__ |
|
__J_TYPEMOD_LENGTH_LONG_LONG__ |
|
__J_TYPEMOD_LENGTH_LONG__ |
|
__J_TYPEMOD_LENGTH_NO_SIGN__ |
|
__J_TYPEMOD_LENGTH_SHORT__ |
|
__J_TYPEMOD_LENGTH_SIGNED__ |
|
__J_TYPEMOD_LENGTH_UNSIGNED__ |
|
__J_UNICODE__ |
|
__J_USE_ATOF__ |
|
__J_USE_ATOI__ |
|
__J_USE_ATOLL__ |
|
__J_USE_ATOL__ |
|
__J_USE_C_PRIMITIVE_VALS__ |
|
__J_USE_MALLOC__ |
|
__J_USE_MEMCPY__ |
|
__J_USE_STRCMP__ |
|
__J_USE_STRTOF__ |
|
__J_USE_STRTOLD__ |
|
__J_USE_STRTOLL__ |
|
__J_USE_STRTOL__ |
|
__J_USE_STRTOULL__ |
|
``` |
|
|
|
I do believe these are, name-wise, descriptive enough so I don't need to |
|
explain them. But just so you know, if you define |
|
`__J_PEDANTIC_PREPROCESS__`, the preprocessor will warn you about the wrong |
|
choices that you may make. The directive `__J_NO_ERRORS_AT_PREPROCESS__` will |
|
disable any errors that CPP may ommit based on your choices. |
|
|
|
As I said, I posted this online mostly for comments. Please share them with |
|
me. I have my contacts above, and I will definitely post this on various fora. |
|
|
|
|
|
Thanks, Chubak! |
|
|
|
Fun fact: shibajs1.h has 79! = 8.94618213 E+116 different combinations. Can you generate them all? Haha. |
|
*/ |
|
|
|
#ifndef __SHIBAJS1_H_ |
|
#define __SHIBAJS1_H_ |
|
|
|
#if !defined(__INC_STDLIB_H_) && !defined(__J_NO_INC_STDLIB_H__) |
|
#define __INC_STDLIB_H_ |
|
#include <stdlib.h> |
|
#endif |
|
|
|
#if !defined(__INC_STRING_H_) && !defined(__J_NO_INC_STRING_H__) |
|
#define __INC_STRING_H_ |
|
#include <string.h> |
|
#endif |
|
|
|
#if !defined(__INC_WCHAR_H_) && !defined(__J_NO_INC_WCHAR_H__) |
|
#define __IN_WCHAR_H_ |
|
#include <wchar.h> |
|
#endif |
|
|
|
#if !defined(__INC_UNISTD_H_) && !defined(__J_NO_INC_UNISTD_H__) |
|
#define __INC_UNISTD_H_ |
|
#include <unistd.h> |
|
#endif |
|
|
|
#if !defined(__INC_ALLOCA_H_) && !defined(__J_NO_INC_ALLOCA_H__) |
|
#define __INC_ALLOCA_H_ |
|
#include <alloca.h> |
|
#endif |
|
|
|
#ifdef __J_PEDANTIC_PREPROCESS__ |
|
#ifdef __J_CUST_INT_BASE__ |
|
#warning \ |
|
"Defining a custom base for integers means all the numerical values in the JSON string will be non-compliant to JSON grammar" |
|
#endif |
|
#if defined(__J_CUST_NULL_LIT__) || defined(__J_CUST_TRUE_LIT__) || \ |
|
defined(__J_CUST_FALSE_LIT__) |
|
#warning \ |
|
"Defining custom literal values for primitives (true, false and null) means they will be non-compliant to the JSON grammar" |
|
#endif |
|
#ifdef __J_USE_MEMCPY__ |
|
#warning \ |
|
"Sinature of J_MEMCPYFN must be J_MEMCPYFN(void *dst, void *src, integer bytestocopy)" |
|
#endif |
|
#ifdef __J_CUST_MEMFREEFN__ |
|
#warning "Sinature of J_MEMFREEFN must be J_MEMFREEFN(void *address)" |
|
#endif |
|
#ifdef J_CUST_MEMSETFN |
|
#warning \ |
|
"Sinature of J_MEMSETFN must be J_MEMSETFN(void *memory, integer tofillwith, integer bytestofill)" |
|
#endif |
|
#ifdef __J_CUST_STRCMPFN__ |
|
#warning \ |
|
"Sinature of J_STRCMPFN must be J_STRCMP(char *str1, char *str2, integer bytesstocompare)" |
|
#endif |
|
#ifdef __J_CUST_MEMALLOCFN__ |
|
#warning \ |
|
"The signature of J_MEMALLOCFN must be J_MEMALLOCFN(integer totalsize, integer membersize)" |
|
#endif |
|
#if defined(__J_USE_MALLOC__) && defined(__J_NO_ZERO_OUT__) |
|
#warning \ |
|
"When using malloc as the J_MEMALLOCFN, it's best not to pass __J_NO_ZERO_OUT__" |
|
#endif |
|
#if defined(__J_USE_ATOF__) && !defined(__J_TYPEMOD_FLOAT_F32__) |
|
#warning "When using atof, it's best to define __J_TYPEMOD_FLOAT_F32__" |
|
#endif |
|
#if defined(__J_USE_STRTOLD__) && !defined(__J_TYPEMOD_FLOAT_E64__) |
|
#warning "When using atoi, it's best to define __J_TYPEMOD_FLOAT_E64__" |
|
#endif |
|
#if defined(__J_USE_STRTOL__) && (!defined(__J_TYPEMOD_INTEGER_LONG__) || \ |
|
defined(__J_TYPEMOD_INTEGER_UNSIGNED__)) |
|
#warning \ |
|
"When using strtol, it's best to define __J_TYPEMOD_INTEGER_LONG__ and don't define __J_TYPEMOD_INTEGER_UNSIGNED__" |
|
#endif |
|
#if defined(__J_USE_STRTOLL__) && \ |
|
(!defined(__J_TYPEMOD_INTEGER_LONG_LONG__) || \ |
|
defined(__J_TYPEMOD_INTEGER_UNSIGNED__)) |
|
#warning \ |
|
"When using strtoll, it's best to define __J_TYPEMOD_INTEGER_LONG_LONG__ and don't define __J_TYPEMOD_INTEGER_UNSIGNED__" |
|
#endif |
|
#if defined(__J_USE_STRTOULL__) && (!defined(__J_TYPEMOD_INTEGER_LONG__) || \ |
|
!defined(__J_TYPEMOD_INTEGER_UNSIGNED__)) |
|
#warning \ |
|
"When using strtoull, it's best to define __J_TYPEMOD_INTEGER_LONG_LONG__ and define __J_TYPEMOD_INTEGER_UNSIGNED__" |
|
#endif |
|
#if defined(__J_USE_ATOI__) && !defined(__J_TYPEMOD_INTEGER_INT__) |
|
#warning "When using atoi, it's best to define __J_TYPEMOD_INTEGER_INT__" |
|
#endif |
|
#if defined(__J_CUST_FLTCONVFN__) && defined(__J_CUST_FLTCONVFN_REENTRANT__) |
|
#warning \ |
|
"The signature of a reentrant float parser must be J_FLTCONVFN(char *eptr, char **scratch)" |
|
#endif |
|
#if defined(__J_CUST_FLTCONVFN__) && !defined(__J_CUST_INTCONVFN_REENTRANT__) |
|
#warning \ |
|
"The signature of a non-reentrant float parser must be J_FLTCONVFN(char *eptr)" |
|
#endif |
|
#if defined(__J_CUST_INTCONVFN__) && defined(__J_CUST_INTCONVFN_REENTRANT__) |
|
#warning \ |
|
"The signature of a reentrant integer parser must be J_INTCONVFN(char *eptr, char **scratch)" |
|
#endif |
|
#if defined(__J_CUST_INTCONVFN__) && !defined(__J_CUST_INTCONVFN_REENTRANT__) |
|
#warning \ |
|
"The signature of a non-reentrant integer parser must be J_INTCONVFN(char *eptr)" |
|
#endif |
|
#if defined(__J_ALLOC_ON_STACK__) !defined(__INC_ALLOCA_H_) |
|
#warning \ |
|
"You have defined __J_ALLOC_ON_STACK__ but have thwarted the inclusion of alloca.h, this could cause complications if this file is not included somewhere else" |
|
#endif |
|
#if !defined(__INC_WCHAR_H_) && defined(__J_UNICODE__) |
|
#warning \ |
|
"You have defined __J_UNICODE__ but have thwarted the inclusion of wchar.h, this could cause complications if this file is not included somewhere else" |
|
#endif |
|
#ifdef __J_ALLOC_ON_STACK__ |
|
#warning \ |
|
"When allocating on the stack, your data only lives within that stack frame (so when a new stack frame is created, e.g. calling a new function, your data is lost)" |
|
#endif |
|
#endif |
|
|
|
#ifndef __J_NO_ERRORS_AT_PREPROCESS__ |
|
#if defined(__J_CUST_PRIMITIVE_VALS__) && \ |
|
(!defined(__J_CUST_TRUE_VAL__) || !defined(__J_CUST_FALSE_VAL__) || \ |
|
!defined(__J_CUST_NULL_VAL__)) |
|
#error \ |
|
"You have defined __J_CUST_PRIMITIVE_VALS__ without all of their respective values (__J_CUST_TRUE_VAL__, __J_CUST_FALSE_VAL__ and __J_CUST_NULL_VAL__), note that these macros must be defined ``in tandem``" |
|
#endif |
|
#if defined(__J_CUST_TRUE_LIT__) && !defined(__J_CUST_TRUE_LIT_LEN__) |
|
#error "You have defined __J_CUST_TRUE_LIT__ without __J_CUST_TRUE_LIT_LEN__" |
|
#endif |
|
#if defined(__J_CUST_FALSE_LIT__) && !defined(__J_CUST_FALSE_LIT_LEN__) |
|
#error "You have defined __J_CUST_FALSE_LIT__ without __J_CUST_FALSE_LIT_LEN__" |
|
#endif |
|
#if defined(__J_CUST_NULL_LIT__) && !defined(__J_CUST_NULL_LIT_LEN__) |
|
#error "You have defined __J_CUST_NULL_LIT__ without __J_CUST_NULL_LIT_LEN__" |
|
#endif |
|
#endif |
|
|
|
#ifdef __J_NO_STATIC__ |
|
#define J_STATIC |
|
#else |
|
#define J_STATIC static |
|
#endif |
|
|
|
#ifdef __J_NO_INLINE__ |
|
#define J_INLINE |
|
#else |
|
#define J_INLINE inline |
|
#endif |
|
|
|
#ifdef __J_NO_REGISTER__ |
|
#define J_REGISTER |
|
#else |
|
#define J_REGISTER register |
|
#endif |
|
|
|
#ifdef __J_CUST_MEMFREEFN__ |
|
#define J_MEMFREEFN __J_CUST_MEMFREEFN__ |
|
#else |
|
#define J_MEMFREEFN free |
|
#endif |
|
|
|
#ifdef __J_USE_MEMCPY__ |
|
#define J_MEMCPYFN memcpy |
|
#elif __J_CUST_MEMCPYFN__ |
|
#define J_MEMCPYFN __J_CUST_MEMCPYFN__ |
|
#else |
|
#define J_MEMCPYFN memmove |
|
#endif |
|
|
|
#ifdef __J_CUST_MEMSETFN__ |
|
#define J_MEMSETFN __J_CUST_MEMSETFN__ |
|
#else |
|
#define J_MEMSETFN memset |
|
#endif |
|
|
|
#ifdef __J_USE_STRCMP__ |
|
#define J_STRCMPFN(str1, str2, len) strcmp(str1, str2) |
|
#elif __J_CUST_STRCMPFN__ |
|
#define J_STRCMPFN __J_CUST_STRCMPFN__ |
|
#else |
|
#define J_STRCMPFN(str1, str2, len) strncmp(str1, str2, len) |
|
#endif |
|
|
|
#ifdef __J_ALLOC_ON_STACK__ |
|
#define J_MEMALLOCFN(alloclen, memlen) alloca((alloclen)*memlen) |
|
#elif __J_USE_MALLOC__ |
|
#define J_MEMALLOCFN(alloclen, memlen) malloc((alloclen)*memlen) |
|
#elif __J_CUST_MEMALLOCFN__ |
|
#define J_MEMALLOCFN __J_CUST_MEMALLOCFN___ |
|
#else |
|
#define J_MEMALLOCFN(alloclen, memlen) calloc(alloclen, memlen) |
|
#endif |
|
|
|
#ifdef __J_USE_STRTOF__ |
|
#define J_FLTCONVFN strtof |
|
#elif __J_USE_STRTOLD__ |
|
#define J_FLTCONVFN strtold |
|
#elif __J_USE_ATOF__ |
|
#define J_FLTCONVFN(eptr, spare) atof(eptr) |
|
#elif defined(__J_CUST_FLTCONVFN__) && defined(__J_CUST_FLTCONVFN_REENTRANT__) |
|
#define J_FLTCONVFN __J_CUST_FLTCONVFN__ |
|
#elif defined(__J_CUST_FLTCONVFN__) && !defined(__J_CUST_FLTCONVFN_REENTRANT__) |
|
#define J_FLTCONVFN(eptr, spare) __J_CUST_FLTCONVFN__(eptr, spare) |
|
#else |
|
#define J_FLTCONVFN strtod |
|
#endif |
|
|
|
#ifdef __J_USE_STRTOLL__ |
|
#define J_INTCONVFN strtoll |
|
#elif __J_USE_STRTOULL__ |
|
#define J_INTCONVFN strtoull |
|
#elif __J_USE_STRTOL__ |
|
#define J_INTCONVFN strtol |
|
#elif __J_USE_ATOI__ |
|
#define J_INTCONVFN(eptr, spare1, spare2) atoi(eptr) |
|
#elif __J_USE_ATOL__ |
|
#define J_INTCONVFN(eptr, spare1, spare2) atol(eptr) |
|
#elif __J_USE_ATOLL__ |
|
#define J_INTCONVFN(eptr, spare1, spare2) atoll(eptr) |
|
#elif defined(__J_CUST_INTCONVFN__) && defined(__J_CUST_INTCONVFN_REENTRANT__) |
|
#define J_INTCONVFN __J_CUST_INTCONVFN__ |
|
#elif defined(__J_CUST_INTCONVFN__) && !defined(__J_CUST_INTCONVFN_REENTRANT__) |
|
#define J_INTCONVFN(eptr, spare) __J_CUST_INTCONVFN__(eptr, spare) |
|
#else |
|
#define J_INTCONVFN strtoul |
|
#endif |
|
|
|
#ifdef __J_CUST_PRIMITIVE_VALS__ |
|
#define J_TRUE __J_CUST_TRUE_VAL__ |
|
#define J_FALSE __J_CUST_FALSE_VAL__ |
|
#define J_NULL __J_CUST_NULL_VAL__ |
|
#elif __J_USE_C_PRIMITIVE_VALS__ |
|
#define J_TRUE 1 |
|
#define J_FALSE 0 |
|
#define J_NULL NULL |
|
#else |
|
#define J_TRUE 1 |
|
#define J_FALSE 2 |
|
#define J_NULL 3 |
|
#endif |
|
|
|
#if defined(__J_CUST_TRUE_LIT__) && defined(__J_CUST_TRUE_LIT_LEN__) |
|
#define J_TRUE_LIT __J_CUST_TRUE_LIT__ |
|
#define J_TRUE_LIT_LEN __J_CUST_TRUE_LIT_LEN__ |
|
#else |
|
#define J_TRUE_LIT "true" |
|
#define J_TRUE_LIT_LEN 5 |
|
#endif |
|
|
|
#if defined(__J_CUST_FALSE_LIT__) && defined(__J_CUST_FALSE_LIT_LEN__) |
|
#define J_FALSE_LIT __J_CUST_FALSE_LIT__ |
|
#define J_FALSE_LIT_LEN __J_CUST_FALSE_LIT_LEN__ |
|
#else |
|
#define J_FALSE_LIT "false" |
|
#define J_FALSE_LIT_LEN 6 |
|
#endif |
|
|
|
#if defined(__J_CUST_NULL_LIT__) && defined(__J_CUST_NULL_LIT_LEN__) |
|
#define J_NULL_LIT __J_CUST_NULL_LIT__ |
|
#define J_NULL_LIT_LEN __J_CUST_NULL_LIT_LEN__ |
|
#else |
|
#define J_NULL_LIT "null" |
|
#define J_NULL_LIT_LEN 4 |
|
#endif |
|
|
|
#ifdef __J_CUST_INT_BASE__ |
|
#define J_INT_BASE __J_CUST_INT_BASE__ |
|
#else |
|
#define J_INT_BASE 10 |
|
#endif |
|
|
|
#ifdef __J_CUST_SENTINEL__ |
|
#define J_SENTINEL __J_CUST_SENTINEL__ |
|
#else |
|
#define J_SENTINEL -1 |
|
#endif |
|
|
|
#ifdef __J_TYPEMOD_LENGTH_SIGNED__ |
|
#define J_TYPEMOD_LENGTH_SIGN signed |
|
#elif __J_TYPEMOD_LENGTH_UNSIGNED__ |
|
#define J_TYPEMOD_LENGTH_SIGN unsigned |
|
#elif __J_TYPEMOD_LENGTH_NO_SIGN__ |
|
#define J_TYPEMOD_LENGTH_SIGN |
|
#else |
|
#define J_TYPEMOD_LENGTH_SIGN unsigned |
|
#endif |
|
|
|
#ifdef __J_TYPEMOD_INTEGER_SIGNED__ |
|
#define J_TYPEMOD_INTEGER_SIGN signed |
|
#elif __J_TYPEMOD_INTEGER_UNSIGNED__ |
|
#define J_TYPEMOD_INTEGER_SIGN unsigned |
|
#elif __J_TYPEMOD_INTEGER_NONE__ |
|
#define J_TYPEMOD_INTEGER_SIGN |
|
#else |
|
#define J_TYPEMOD_INTEGER_SIGN unsigned |
|
#endif |
|
|
|
#ifdef __J_TYPEMOD_LENGTH_LONG__ |
|
#define J_TYPEMOD_LENGTH_SIZE long int |
|
#elif __J_TYPEMOD_LENGTH_LONG_LONG__ |
|
#define J_TYPEMOD_LENGTH_SIZE long long int |
|
#elif __J_TYPEMOD_LENGTH_SHORT__ |
|
#define J_TYPEMOD_LENGTH_SIZE short int |
|
#elif __J_TYPEMOD_LENGTH_INT__ |
|
#define J_TYPEMOD_LENGTH_SIZE int |
|
#else |
|
#define J_TYPEMOD_LENGTH_SIZE long int |
|
#endif |
|
|
|
#ifdef __J_TYPEMOD_INTEGER_LONG__ |
|
#define J_TYPEMOD_INTEGER_SIZE long int |
|
#elif __J_TYPEMOD_INTEGER_LONG_LONG__ |
|
#define J_TYPEMOD_INTEGER_SIZE long long int |
|
#elif __J_TYPEMOD_INTEGER_SHORT__ |
|
#define J_TYPEMOD_INTEGER_SIZE short int |
|
#elif __J_TYPEMOD_INTEGER_INT__ |
|
#define J_TYPEMOD_INTEGER_SIZE int |
|
#else |
|
#define J_TYPEMOD_INTEGER_SIZE long int |
|
#endif |
|
|
|
#define J_LENGTH_TYPE J_TYPEMOD_LENGTH_SIGN J_TYPEMOD_LENGTH_SIZE |
|
#define J_INTEGER_TYPE J_TYPEMOD_INTEGER_SIGN J_TYPEMOD_INTEGER_SIZE |
|
|
|
#ifdef __J_TYPEMOD_FLOAT_F32__ |
|
#define J_FLOAT_TYPE float |
|
#elif __J_TYMEMOD_FLOAT_F64__ |
|
#define J_FLOAT_TYPE double |
|
#elif __J_TYPEMOD_FLOAT_E64__ |
|
#define J_FLOAT_TYPE long double |
|
#else |
|
#define J_FLOAT_TYPE double |
|
#endif |
|
|
|
#ifdef __J_UNICODE__ |
|
#define J_CHAR_TYPE wchar_t |
|
#else |
|
#define J_CHAR_TYPE char |
|
#endif |
|
|
|
#define J_UNICODE_ESCAPE_LEN 4 |
|
#define J_ESCAPE_SEQ_LEN 2 |
|
#define J_INT_BASE_HEXA 16 |
|
|
|
#define J_STATICMEM_INTEGER 0ULL |
|
#define J_STATICMEM_FLOAT 2ULL |
|
#define J_STATICMEM_PRIMITIVE 4ULL |
|
|
|
#define J_ALLOCABLE_STRING 1ULL |
|
#define J_ALLOCABLE_INTEGER 3ULL |
|
#define J_ALLOCABLE_FLOAT 7ULL |
|
#define J_ALLOCABLE_MEMADDR 15ULL |
|
|
|
#define J_CURR_CHR(stream) *stream |
|
#define J_ADVANCE_PTR(stream) stream++ |
|
#define J_ADVANCE_PTR_N(stream, n) stream += n |
|
#define J_NEXT_CHR(stream) *stream++ |
|
#define J_PEEK_NXT(stream) *(stream + 1) |
|
#define J_PEEK_PRV(stream) *(stream - 2) |
|
|
|
#ifndef __J_UNICODE__ |
|
#define J_IS_SENTINEL(character) (character == J_SENTINEL) |
|
#define J_IS_NULLCHR(character) (character == '\0') |
|
#define J_IS_QUOTE(character) (character == '"') |
|
#define J_IS_LBRACK(character) (character == '[') |
|
#define J_IS_RBRACK(character) (character == ']') |
|
#define J_IS_LCURLY(character) (character == '{') |
|
#define J_IS_RCURLY(character) (character == '}') |
|
#define J_IS_BSOLIDUS(character) (character == '\\') |
|
#define J_IS_COMMA(character) (character == ',') |
|
#define J_IS_COLON(character) (character == ':') |
|
#define J_IS_DIGIT(character) (character >= '0' && character <= '9') |
|
#define J_IS_SIGN(character) (character == '+' || character == '-') |
|
#define J_IS_EXP(character) (character == 'e' || character == 'E') |
|
#define J_IS_FRACT(character) (character == '.') |
|
#define J_IS_UNCDESCAPE(character) (character == 'u') |
|
#define J_IS_ESCAPECHR(character) \ |
|
(character == 'b' || character == 'u' || character == 'n' || \ |
|
character == '\\' || character == '/' || character == 't' || \ |
|
character == 'r' || character == 'f') |
|
#define J_IS_WSPACE(character) \ |
|
(character == '\n' || character == ' ' || character == '\t' || \ |
|
character == '\r') |
|
#define J_IS_PRINTABLE(character) (character >= ' ') |
|
#else |
|
#define J_IS_SENTINEL(character) (character == J_SENTINEL) |
|
#define J_IS_NULLCHR(character) (character == L'\0') |
|
#define J_IS_QUOTE(character) (character == L'"') |
|
#define J_IS_LBRACK(character) (character == L'[') |
|
#define J_IS_RBRACK(character) (character == L']') |
|
#define J_IS_LCURLY(character) (character == L'{') |
|
#define J_IS_RCURLY(character) (character == L'}') |
|
#define J_IS_BSOLIDUS(character) (character == L'\\') |
|
#define J_IS_COMMA(character) (character == L',') |
|
#define J_IS_COLON(character) (character == L':') |
|
#define J_IS_DIGIT(character) (character >= L'0' && character <= L'9') |
|
#define J_IS_SIGN(character) (character == L'+' || character == L'-') |
|
#define J_IS_EXP(character) (character == L'e' || character == L'E') |
|
#define J_IS_FRACT(character) (character == L'.') |
|
#define J_IS_UNCDESCAPE(character) (character == L'u') |
|
#define J_IS_ESCAPECHR(character) \ |
|
(character == L'b' || character == L'u' || character == L'n' || \ |
|
character == L'\\' || character == L'/' || character == L't' || \ |
|
character == L'r' || character == L'f') |
|
#define J_IS_WSPACE(character) \ |
|
(character == L'\n' || character == L' ' || character == L'\t' || \ |
|
character == L'\r') |
|
#define J_IS_PRINTABLE(character) (character >= L' ') |
|
#endif |
|
|
|
#define J_QUOTE_NO_ESCAPE(chrcur, chrprv) \ |
|
(J_IS_QUOTE(chrcur) && !J_IS_BSOLIDUS(chrprv)) |
|
|
|
#define J_IS_KVSEP(character) (J_IS_COLON(character) || J_IS_WSPACE(character)) |
|
#define J_IS_VTERM(character) \ |
|
(J_IS_COMMA(character) || J_IS_RCURLY(character) || \ |
|
J_IS_WSPACE(character) || J_IS_SENTINEL(character) || \ |
|
J_IS_NULLCHR(character)) |
|
#define J_IS_CONTEXT(character) \ |
|
(J_IS_LCURLY(character) || J_IS_WSPACE(character) || J_IS_COMMA(character)) |
|
#define J_IS_ELTERM(character) \ |
|
(J_IS_COMMA(character) || J_IS_RBRACK(character) || J_IS_WSPACE(character)) |
|
|
|
#define J_IS_FLOAT(character) \ |
|
(J_IS_DIGIT(character) || J_IS_FRACT(character) || J_IS_EXP(character) || \ |
|
J_IS_SIGN(character)) |
|
|
|
#define J_IS_INTEGER(character) (J_IS_DIGIT(character) || J_IS_SIGN(character)) |
|
|
|
#define J_INT_ELEMENT_ENDED(stream, character) \ |
|
(J_IS_INTEGER(character) && J_IS_ELTERM(J_CURR_CHR(stream))) |
|
#define J_FLT_ELEMENT_ENDED(stream, character) \ |
|
(J_IS_FLOAT(character) && J_IS_ELTERM(J_CURR_CHR(stream))) |
|
|
|
#define J_STR_BEGAN(stream, character) \ |
|
(J_IS_PRINTABLE(J_CURR_CHR(stream)) && J_IS_QUOTE(character) && \ |
|
J_IS_KVSEP(J_PEEK_PRV(stream))) |
|
#define J_STR_ENDED(stream, character) \ |
|
(J_QUOTE_NO_ESCAPE(J_CURR_CHR(stream), character) && \ |
|
J_IS_VTERM(J_PEEK_NXT(stream))) |
|
|
|
#define J_INT_BEGAN(stream, character) \ |
|
(J_IS_INTEGER(J_CURR_CHR(stream)) && J_IS_KVSEP(character)) |
|
#define J_INT_ENDED(stream, character) \ |
|
(J_IS_INTEGER(character) && J_IS_VTERM(J_CURR_CHR(stream))) |
|
|
|
#define J_FLT_BEGAN(stream, character) \ |
|
(J_IS_FLOAT(J_CURR_CHR(stream)) && J_IS_KVSEP(character)) |
|
#define J_FLT_ENDED(stream, character) \ |
|
(J_IS_FLOAT(character) && J_IS_VTERM(J_CURR_CHR(stream))) |
|
|
|
#define J_ARR_BEGAN(stream, character) \ |
|
(J_IS_LBRACK(J_CURR_CHR(stream)) && J_IS_KVSEP(character)) |
|
|
|
#define J_VAL_BEGAN(stream, character) \ |
|
(J_IS_KVSEP(J_PEEK_PRV(stream)) && J_IS_PRINTABLE(character)) |
|
#define J_VAL_ENDED(stream, character) \ |
|
(J_IS_VTERM(J_CURR_CHR(stream)) && J_IS_PRINTABLE(character)) |
|
|
|
#define J_KEY_BEGAN(stream, character) \ |
|
(J_IS_PRINTABLE(J_CURR_CHR(stream)) && J_IS_QUOTE(character) && \ |
|
J_IS_CONTEXT(J_PEEK_PRV(stream))) |
|
#define J_KEY_ENDED(stream, character) \ |
|
(J_QUOTE_NO_ESCAPE(J_CURR_CHR(stream), character) && \ |
|
J_IS_KVSEP(J_PEEK_NXT(stream))) |
|
|
|
#define J_SKIP_TIL_STR_BEGIN(stream, character) \ |
|
for (character = J_CURR_CHR(stream); !J_STR_BEGAN(stream, character); \ |
|
character = J_NEXT_CHR(stream)) |
|
#define J_SKIP_TIL_STR_ENDED(stream, character) \ |
|
for (character = J_CURR_CHR(stream); !J_STR_ENDED(stream, character); \ |
|
character = J_NEXT_CHR(stream)) |
|
|
|
#define J_SKIP_TIL_INT_BEGIN(stream, character) \ |
|
for (character = J_CURR_CHR(stream); !J_INT_BEGAN(stream, character); \ |
|
character = J_NEXT_CHR(stream)) |
|
#define J_SKIP_TIL_INT_ENDED(stream, character) \ |
|
for (character = J_CURR_CHR(stream); !J_INT_ENDED(stream, character); \ |
|
character = J_NEXT_CHR(stream)) |
|
|
|
#define J_SKIP_TIL_FLT_BEGIN(stream, character) \ |
|
for (character = J_CURR_CHR(stream); !J_FLT_BEGAN(stream, character); \ |
|
character = J_NEXT_CHR(stream)) |
|
#define J_SKIP_TIL_FLT_ENDED(stream, character) \ |
|
for (character = J_CURR_CHR(stream); !J_FLT_ENDED(stream, character); \ |
|
character = J_NEXT_CHR(stream)) |
|
|
|
#define J_SKIP_TIL_ARR_BEGIN(stream, character) \ |
|
for (character = J_CURR_CHR(stream); !J_ARR_BEGAN(stream, character); \ |
|
character = J_NEXT_CHR(stream)) |
|
|
|
#define J_SKIP_TIL_KEY_BEGIN(stream, character) \ |
|
for (character = J_CURR_CHR(stream); !J_KEY_BEGAN(stream, character); \ |
|
character = J_NEXT_CHR(stream)) |
|
#define J_SKIP_TIL_KEY_ENDED(stream, character) \ |
|
for (character = J_CURR_CHR(stream); !J_KEY_ENDED(stream, character); \ |
|
character = J_NEXT_CHR(stream)) |
|
|
|
#define J_SKIP_TIL_VAL_BEGIN(stream, character) \ |
|
for (character = J_CURR_CHR(stream); !J_VAL_BEGAN(stream, character); \ |
|
character = J_NEXT_CHR(stream)) |
|
#define J_SKIP_TIL_VAL_ENDED(stream, character) \ |
|
for (character = J_CURR_CHR(stream); !J_VAL_ENDED(stream, character); \ |
|
character = J_NEXT_CHR(stream)) |
|
|
|
#define J_ADDR_REF(arr) (void *)&arr[0] |
|
|
|
#ifndef __J_NO_ZERO_OUT__ |
|
#define J_ZERO_OUT(stream, len) J_MEMSETFN(J_ADDR_REF(stream), 0, len) |
|
#else |
|
#define J_ZERO_OUT(stream, len) |
|
#endif |
|
|
|
#ifndef __J_NO_SHIBAJS1_PREFIX__ |
|
#define J_DECL_FN(rettype, fnname, ...) \ |
|
J_STATIC J_INLINE rettype shibajs1_##fnname(__VA_ARGS__) |
|
#elif __J_CUST_FN_PREFIX__ |
|
#define J_DECL_FN(rettype, fnname, ...) \ |
|
J_STATIC J_INLINE rettype __J_CUST_FN_PREFIX__##fnname(__VA_ARGS__) |
|
#else |
|
#define J_DECL_FN(rettype, fnname, ...) \ |
|
J_STATIC J_INLINE rettype fnname(__VA_ARGS__) |
|
#endif |
|
|
|
#define J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream) \ |
|
J_REGISTER jchar_t tmpChar = 0; \ |
|
J_REGISTER jlength_t tmpLen = 0; \ |
|
J_REGISTER jstream_t tmpStream, mainStream; \ |
|
mainStream = &jsonStream[0] |
|
|
|
#define J_GET_ALLOC_LEN(tmpLen, tmpStream, mainStream) \ |
|
tmpLen = (jlength_t)(tmpStream - mainStream) |
|
|
|
#define J_ALLOC_STATIC_ASCIIZ(strName, strLen) jchar_t strName[strLen + 1] |
|
|
|
#define J_ALLOC_KV_MEMORY(address, size, unit) \ |
|
address = J_MEMALLOCFN(size, unit) |
|
|
|
#define J_ASSIGN_KV_TYPE(pair, tyy) pair->type = tyy |
|
|
|
#define J_MAKE_ASCIIZ(stream) *(stream) = '\0' |
|
#define J_ASCIIZ_LEN(len) (len + 1) * sizeof(jchar_t) |
|
|
|
#define J_PARSE_INTEGER_VALUE(integerDst, intString) \ |
|
do { \ |
|
jstring_t scratch; \ |
|
integerDst = (jinteger_t)J_INTCONVFN(intString, &scratch, J_INT_BASE); \ |
|
} while (0) |
|
|
|
#define J_PARSE_FLOAT_VALUE(floatDst, floatString) \ |
|
do { \ |
|
jstring_t scratch; \ |
|
floatDst = (jfloat_t)J_FLTCONVFN(floatString, &scratch); \ |
|
} while (0) |
|
|
|
#define J_ASSIGN_ADDR(address, stream) address = &stream[0] |
|
|
|
#define J_NULLIFY_ADDR(address) address = NULL |
|
|
|
#ifdef __J_HEX_MSB_LEFT__ |
|
#define J_SHORT_TO_BYTE(shortint, dstbytemsb, dstbytelsb) \ |
|
do { \ |
|
dstbytelsb = (jchar_t)((shortint)&0xff); \ |
|
dstbytemsb = (jchar_t)((shortint & 0xff00) >> 8); \ |
|
} while (0) |
|
#else |
|
#define J_SHORT_TO_BYTE(shortint, dstbytemsb, dstbytelsb) \ |
|
do { \ |
|
dstbytemsb = (jchar_t)((shortint)&0xff); \ |
|
dstbytelsb = (jchar_t)((shortint & 0xff00) >> 8); \ |
|
} while (0) |
|
#endif |
|
|
|
#define J_TOKENIZE_LOOP(str, sep, scratch, tok) \ |
|
for (tok = J_STRTOKFN(str, sep, &scratch); tok; \ |
|
tok = J_STRTOKFN(str, sep, &scratch)) |
|
|
|
#ifndef __J_UNICODE__ |
|
#define J_PARSE_ESCAPE_UNICODE(mainStream, destination) \ |
|
do { \ |
|
unsigned short unicodeInteger = 0; \ |
|
const char unicodeString[J_UNICODE_ESCAPE_LEN + 1]; \ |
|
J_MEMCPYFN(J_ADDR_REF(unicodeString), J_ADDR_REF(mainStream) + 1, \ |
|
J_UNICODE_ESCAPE_LEN); \ |
|
unicodeInteger = J_INTCONVFN(unicodeString, NULL, J_INT_BASE_HEXA); \ |
|
J_SHORT_TO_BYTE(unicodeInteger, J_NEXT_CHR(destination), \ |
|
J_NEXT_CHR(destination)); \ |
|
J_ADVANCE_PTR_N(mainStream, J_UNICODE_ESCAPE_LEN + 2); \ |
|
} while (0) |
|
#else |
|
#define J_PARSE_ESCAPE_UNICODE(mainStream, destination) \ |
|
do { \ |
|
unsigned short unicodeInteger = 0; \ |
|
const char unicodeString[J_UNICODE_ESCAPE_LEN + 1]; \ |
|
J_MEMCPYFN(J_ADDR_REF(unicodeString), J_ADDR_REF(mainStream) + 1, \ |
|
J_UNICODE_ESCAPE_LEN); \ |
|
unicodeInteger = J_INTCONVFN(unicodeString, NULL, J_INT_BASE_HEXA); \ |
|
*(destination) = unicodeInteger; \ |
|
J_ADVANCE_PTR(destination); \ |
|
J_ADVANCE_PTR_N(mainStream, J_UNICODE_ESCAPE_LEN + 2); \ |
|
} while (0) |
|
#endif |
|
|
|
#ifdef __J_ECONOMIC_ALLOC__ |
|
#define J_ECONOMIZE_STR_LENGTH(stream, character, dstlen) \ |
|
do { \ |
|
jstream_t streamCopy = stream; \ |
|
J_REGISTER jlength_t lenCopy = dstlen; \ |
|
for (character = J_CURR_CHR(streamCopy); lenCopy--; \ |
|
character = J_NEXT_CHR(streamCopy)) { \ |
|
if (J_IS_BSOLIDUS(character) && \ |
|
J_IS_ESCAPECHR(J_PEEK_NXT(streamCopy))) { \ |
|
character = J_NEXT_CHR(streamCopy); \ |
|
if (J_IS_UNCDESCAPE(character)) { \ |
|
dstlen -= J_UNICD_NUM_LEN; \ |
|
streamCopy += J_UNICD_NUM_LEN * sizeof(jchar_t); \ |
|
} else { \ |
|
dstlen -= J_ESCAPE_SEQ_LEN; \ |
|
} \ |
|
} \ |
|
} \ |
|
} while (0) |
|
#else |
|
#define J_ECONOMIZE_STR_LENGTH(stream, character, len) |
|
#endif |
|
|
|
#ifndef __J_NO_STR_ESCAPE__ |
|
#define J_STR_PARSE_LOOP(stream, character, length, head) \ |
|
do { \ |
|
jstring_t streamCopy = stream; \ |
|
jstring_t headCopy = head; \ |
|
J_REGISTER jlength_t lengthCopy = length; \ |
|
do { \ |
|
character = J_NEXT_CHR(streamCopy); \ |
|
if (character == '\\') { \ |
|
character = J_NEXT_CHR(streamCopy); \ |
|
--lengthCopy; \ |
|
switch (character) { \ |
|
case 'b': \ |
|
character = '\b'; \ |
|
break; \ |
|
case 'f': \ |
|
character = '\f'; \ |
|
break; \ |
|
case 'n': \ |
|
character = '\n'; \ |
|
break; \ |
|
case 'r': \ |
|
character = '\r'; \ |
|
break; \ |
|
case 't': \ |
|
character = '\t'; \ |
|
break; \ |
|
case 'u': \ |
|
J_PARSE_ESCAPE_UNICODE(streamCopy, head); \ |
|
continue; \ |
|
default: \ |
|
break; \ |
|
} \ |
|
} \ |
|
*(headCopy++) = character; \ |
|
} while (--lengthCopy); \ |
|
} while (0) |
|
#else |
|
#define J_STR_PARSE_LOOP(stream, character, length, head) \ |
|
do { \ |
|
jstring_t streamCopy = stream; \ |
|
jstring_t headCopy = head; \ |
|
J_REGISTER jlength_t lengthCopy = length; \ |
|
for (*(headCopy++) = J_NEXT_CHR(streamCopy); --lengthCopy; \ |
|
*(headCopy++) = J_NEXT_CHR(streamCopy)) \ |
|
; \ |
|
} while (0) |
|
#endif |
|
|
|
#define J_INT_ARRAY_PARSE_LOOP(stream, character, numElements, destination) \ |
|
do { \ |
|
jstring_t scratch, integerContext = NULL; \ |
|
J_REGISTER jlength_t elementIdx = 0; \ |
|
do { \ |
|
character = J_NEXT_CHR(stream); \ |
|
if (!integerContext && J_IS_INTEGER(J_CURR_CHR(stream))) \ |
|
J_ASSIGN_ADDR(integerContext, stream); \ |
|
else if (integerContext && J_INT_ELEMENT_ENDED(stream, character)) { \ |
|
J_MAKE_ASCIIZ(stream); \ |
|
J_PARSE_INTEGER_VALUE(destination[elementIdx++], integerContext); \ |
|
J_NULLIFY_ADDR(integerContext); \ |
|
} else \ |
|
continue; \ |
|
} while (numElements > elementIdx); \ |
|
} while (0) |
|
|
|
#define J_FLT_ARRAY_PARSE_LOOP(stream, character, numElements, destination) \ |
|
do { \ |
|
jstring_t scratch, floatContext = NULL; \ |
|
J_REGISTER jlength_t elementIdx = 0; \ |
|
do { \ |
|
character = J_NEXT_CHR(stream); \ |
|
if (!floatContext && J_IS_FLOAT(J_CURR_CHR(stream))) \ |
|
J_ASSIGN_ADDR(floatContext, stream); \ |
|
else if (floatContext && J_FLT_ELEMENT_ENDED(stream, character)) { \ |
|
J_MAKE_ASCIIZ(stream); \ |
|
J_PARSE_FLOAT_VALUE(destination[elementIdx++], floatContext); \ |
|
J_NULLIFY_ADDR(floatContext); \ |
|
} else \ |
|
continue; \ |
|
} while (numElements > elementIdx); \ |
|
} while (0) |
|
|
|
#define J_STR_ARRAY_PARSE_LOOP(stream, character, numElements, destination) \ |
|
do { \ |
|
jstring_t head, stringContext = NULL; \ |
|
J_REGISTER jlength_t elementIdx = 0, currentLength = 0; \ |
|
do { \ |
|
character = J_NEXT_CHR(stream); \ |
|
if (J_QUOTE_NO_ESCAPE(J_CURR_CHR(stream), character)) { \ |
|
if (!stringContext) \ |
|
J_ASSIGN_ADDR(stringContext, (++stream)); \ |
|
else { \ |
|
J_GET_ALLOC_LEN(currentLength, stream, stringContext); \ |
|
J_ECONOMIZE_STR_LENGTH(stringContext, character, currentLength); \ |
|
J_ALLOC_KV_MEMORY(destination[elementIdx++] = head, currentLength, \ |
|
sizeof(jchar_t)); \ |
|
J_STR_PARSE_LOOP(stringContext, character, currentLength, head); \ |
|
J_NULLIFY_ADDR(stringContext); \ |
|
} \ |
|
} else if (J_IS_WSPACE(character)) \ |
|
continue; \ |
|
} while (numElements > elementIdx); \ |
|
} while (0) |
|
|
|
typedef J_FLOAT_TYPE jfloat_t; |
|
typedef J_INTEGER_TYPE jinteger_t; |
|
typedef J_LENGTH_TYPE jlength_t; |
|
typedef J_CHAR_TYPE *jstream_t; |
|
typedef J_CHAR_TYPE *jstring_t; |
|
typedef J_CHAR_TYPE *jkey_t; |
|
typedef J_CHAR_TYPE jchar_t; |
|
typedef J_INTEGER_TYPE jtype_t; |
|
typedef J_INTEGER_TYPE jprimitive_t; |
|
|
|
typedef struct JsonKVPair { |
|
jkey_t key; |
|
union { |
|
jinteger_t integer; |
|
jfloat_t floatNum; |
|
jstring_t string; |
|
jprimitive_t primFalse; |
|
jprimitive_t primTrue; |
|
jprimitive_t primNull; |
|
jfloat_t *floatArray; |
|
jinteger_t *integerArray; |
|
jstring_t *stringArray; |
|
} value; |
|
jtype_t type; |
|
} jkvpair_t; |
|
|
|
#ifndef __J_NO_PARSE_KEY_FN__ |
|
|
|
J_DECL_FN(jstream_t, parse_key, jstream_t jsonStream, jkvpair_t *kvpair) { |
|
J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream); |
|
J_SKIP_TIL_KEY_BEGIN(mainStream, tmpChar); |
|
J_ASSIGN_ADDR(tmpStream, mainStream); |
|
J_SKIP_TIL_KEY_ENDED(tmpStream, tmpChar); |
|
J_GET_ALLOC_LEN(tmpLen, tmpStream, mainStream); |
|
J_ALLOC_KV_MEMORY(kvpair->key, tmpLen + 1, sizeof(jchar_t)); |
|
J_ZERO_OUT(kvpair->key, J_ASCIIZ_LEN(tmpLen)); |
|
J_MEMCPYFN(J_ADDR_REF(kvpair->key), J_ADDR_REF(mainStream), |
|
tmpLen * sizeof(jchar_t)); |
|
return tmpStream; |
|
} |
|
|
|
#endif |
|
|
|
#ifndef __J_NO_PARSE_PRIMITIVE_FN__ |
|
|
|
J_DECL_FN(jstream_t, parse_primitive, jstream_t jsonStream, jkvpair_t *kvpair) { |
|
J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream); |
|
J_SKIP_TIL_VAL_BEGIN(mainStream, tmpChar); |
|
J_ASSIGN_ADDR(tmpStream, mainStream); |
|
J_SKIP_TIL_VAL_ENDED(tmpStream, tmpChar); |
|
J_GET_ALLOC_LEN(tmpLen, tmpStream, mainStream); |
|
J_ALLOC_STATIC_ASCIIZ(primStr, tmpLen); |
|
J_ZERO_OUT(primStr, J_ASCIIZ_LEN(tmpLen)); |
|
J_MEMCPYFN(J_ADDR_REF(primStr), mainStream, tmpLen); |
|
if (!J_STRCMPFN(primStr, J_TRUE_LIT, J_TRUE_LIT_LEN)) |
|
kvpair->value.primTrue = J_TRUE; |
|
else if (!J_STRCMPFN(primStr, J_FALSE_LIT, J_FALSE_LIT_LEN)) |
|
kvpair->value.primFalse = J_FALSE; |
|
else if (!J_STRCMPFN(primStr, J_NULL_LIT, J_NULL_LIT_LEN)) |
|
kvpair->value.primNull = J_NULL; |
|
J_ASSIGN_KV_TYPE(kvpair, J_STATICMEM_PRIMITIVE); |
|
return tmpStream; |
|
} |
|
|
|
#endif |
|
|
|
#ifndef __J_NO_PARSE_INTEGER_FN__ |
|
|
|
J_DECL_FN(jstream_t, parse_integer, jstream_t jsonStream, jkvpair_t *kvpair) { |
|
J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream); |
|
J_SKIP_TIL_INT_BEGIN(mainStream, tmpChar); |
|
J_ASSIGN_ADDR(tmpStream, mainStream); |
|
J_SKIP_TIL_INT_ENDED(tmpStream, tmpChar); |
|
J_GET_ALLOC_LEN(tmpLen, tmpStream, mainStream); |
|
J_ALLOC_STATIC_ASCIIZ(intString, tmpLen); |
|
J_ZERO_OUT(intString, J_ASCIIZ_LEN(tmpLen)); |
|
J_MEMCPYFN(J_ADDR_REF(intString), mainStream, tmpLen); |
|
J_PARSE_INTEGER_VALUE(kvpair->value.integer, intString); |
|
J_ASSIGN_KV_TYPE(kvpair, J_STATICMEM_INTEGER); |
|
return tmpStream; |
|
} |
|
|
|
#endif |
|
|
|
#ifndef __J_NO_PARSE_FLOAT_FN__ |
|
|
|
J_DECL_FN(jstream_t, parse_float, jstream_t jsonStream, jkvpair_t *kvpair) { |
|
J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream); |
|
J_SKIP_TIL_FLT_BEGIN(mainStream, tmpChar); |
|
J_ASSIGN_ADDR(tmpStream, mainStream); |
|
J_SKIP_TIL_FLT_ENDED(tmpStream, tmpChar); |
|
J_GET_ALLOC_LEN(tmpLen, tmpStream, mainStream); |
|
J_ALLOC_STATIC_ASCIIZ(floatString, tmpLen); |
|
J_ZERO_OUT(floatString, J_ASCIIZ_LEN(tmpLen)); |
|
J_MEMCPYFN(J_ADDR_REF(floatString), mainStream, tmpLen); |
|
J_PARSE_FLOAT_VALUE(kvpair->value.floatNum, floatString); |
|
J_ASSIGN_KV_TYPE(kvpair, J_STATICMEM_FLOAT); |
|
return tmpStream; |
|
} |
|
|
|
#endif |
|
|
|
#ifndef __J_NO_PARSE_STRING_FN__ |
|
|
|
J_DECL_FN(jstream_t, parse_string, jstream_t jsonStream, jkvpair_t *kvpair) { |
|
J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream); |
|
J_SKIP_TIL_STR_BEGIN(mainStream, tmpChar); |
|
J_ASSIGN_ADDR(tmpStream, mainStream); |
|
J_SKIP_TIL_STR_ENDED(tmpStream, tmpChar); |
|
J_GET_ALLOC_LEN(tmpLen, tmpStream, mainStream); |
|
J_ECONOMIZE_STR_LENGTH(mainStream, tmpChar, tmpLen); |
|
J_ALLOC_KV_MEMORY(kvpair->value.string, tmpLen + 1, sizeof(jchar_t)); |
|
J_ZERO_OUT(kvpair->value.string, J_ASCIIZ_LEN(tmpLen)); |
|
J_STR_PARSE_LOOP(mainStream, tmpChar, tmpLen, kvpair->value.string); |
|
J_ASSIGN_KV_TYPE(kvpair, J_ALLOCABLE_STRING | (tmpLen << 4)); |
|
return tmpStream; |
|
} |
|
|
|
#endif |
|
|
|
#ifndef __J_NO_PARSE_INT_ARRAY_FN__ |
|
|
|
J_DECL_FN(jstream_t, parse_integer_array, jstream_t jsonStream, |
|
jkvpair_t *kvpair, jlength_t numElements) { |
|
J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream); |
|
J_SKIP_TIL_ARR_BEGIN(mainStream, tmpChar); |
|
J_ASSIGN_ADDR(tmpStream, mainStream); |
|
J_ALLOC_KV_MEMORY(kvpair->value.integerArray, numElements, |
|
sizeof(jinteger_t)); |
|
J_ZERO_OUT(kvpair->value.integerArray, numElements * sizeof(jinteger_t)); |
|
J_INT_ARRAY_PARSE_LOOP(tmpStream, tmpChar, numElements, |
|
kvpair->value.integerArray); |
|
J_ASSIGN_KV_TYPE(kvpair, J_ALLOCABLE_INTEGER | (numElements << 4)); |
|
return tmpStream; |
|
} |
|
|
|
#endif |
|
|
|
#ifndef __J_NO_PARSE_FLT_ARRAY_FN__ |
|
|
|
J_DECL_FN(jstream_t, parse_float_array, jstream_t jsonStream, jkvpair_t *kvpair, |
|
jlength_t numElements) { |
|
J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream); |
|
J_SKIP_TIL_ARR_BEGIN(mainStream, tmpChar); |
|
J_ASSIGN_ADDR(tmpStream, mainStream); |
|
J_ALLOC_KV_MEMORY(kvpair->value.floatArray, numElements, sizeof(jfloat_t)); |
|
J_ZERO_OUT(kvpair->value.floatArray, numElements * sizeof(jfloat_t)); |
|
J_FLT_ARRAY_PARSE_LOOP(tmpStream, tmpChar, numElements, |
|
kvpair->value.floatArray); |
|
J_ASSIGN_KV_TYPE(kvpair, J_ALLOCABLE_FLOAT | (numElements << 4)); |
|
return tmpStream; |
|
} |
|
|
|
#endif |
|
|
|
#ifndef __J_NO_PARSE_STR_ARRAY_FN__ |
|
|
|
J_DECL_FN(jstream_t, parse_string_array, jstream_t jsonStream, |
|
jkvpair_t *kvpair, jlength_t numElements) { |
|
J_INIT_PARSE_FN(jsonStream, tmpChar, tmpLen, tmpStream, mainStream); |
|
J_SKIP_TIL_ARR_BEGIN(mainStream, tmpChar); |
|
J_ASSIGN_ADDR(tmpStream, mainStream); |
|
J_ALLOC_KV_MEMORY(kvpair->value.stringArray, numElements, sizeof(jstring_t)); |
|
J_ZERO_OUT(kvpair->value.stringArray, numElements * sizeof(jstring_t)); |
|
J_STR_ARRAY_PARSE_LOOP(tmpStream, tmpChar, numElements, |
|
kvpair->value.stringArray); |
|
J_ASSIGN_KV_TYPE(kvpair, J_ALLOCABLE_MEMADDR | (numElements << 4)); |
|
return tmpStream; |
|
} |
|
|
|
#endif |
|
|
|
#ifndef __J_NO_FREE_FN__ |
|
|
|
J_DECL_FN(void, free_json, jkvpair_t *kvpair) { |
|
J_MEMFREEFN(kvpair->key); |
|
switch (kvpair->type & 0xf) { |
|
case J_ALLOCABLE_STRING: |
|
J_MEMFREEFN(kvpair->value.string); |
|
break; |
|
case J_ALLOCABLE_INTEGER: |
|
J_MEMFREEFN(kvpair->value.integerArray); |
|
break; |
|
case J_ALLOCABLE_FLOAT: |
|
J_MEMFREEFN(kvpair->value.floatArray); |
|
break; |
|
case J_ALLOCABLE_MEMADDR: |
|
for (J_REGISTER jlength_t i = 0; i < ((kvpair->type & ~0xfULL) >> 4); i++) { |
|
J_MEMFREEFN(kvpair->value.stringArray[i]); |
|
} |
|
J_MEMFREEFN(kvpair->value.stringArray); |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
|
|
#endif |
|
|
|
#endif |