json_parser.[hc] refined for better performance
parent
f24c558761
commit
275279a264
3
HISTORY
3
HISTORY
|
|
@ -1,8 +1,9 @@
|
||||||
|
|
||||||
Version 1.58 2022-05-26
|
Version 1.58 2022-05-29
|
||||||
* add function conn_pool_connect_server_ex1 to support service name
|
* add function conn_pool_connect_server_ex1 to support service name
|
||||||
* add function conn_pool_get_connection_ex to support service name
|
* add function conn_pool_get_connection_ex to support service name
|
||||||
* add function iniGetCharValueEx
|
* add function iniGetCharValueEx
|
||||||
|
* json_parser.[hc] refined for better performance
|
||||||
|
|
||||||
Version 1.57 2022-04-22
|
Version 1.57 2022-04-22
|
||||||
* add function fc_format_path
|
* add function fc_format_path
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
(ch >= '0' && ch <= '9') || (ch == '_' || ch == '-' || \
|
(ch >= '0' && ch <= '9') || (ch == '_' || ch == '-' || \
|
||||||
ch == '.'))
|
ch == '.'))
|
||||||
|
|
||||||
int detect_json_type(const string_t *input)
|
int fc_detect_json_type(const string_t *input)
|
||||||
{
|
{
|
||||||
if (input->len < 2) {
|
if (input->len < 2) {
|
||||||
return FC_JSON_TYPE_STRING;
|
return FC_JSON_TYPE_STRING;
|
||||||
|
|
@ -45,18 +45,9 @@ int detect_json_type(const string_t *input)
|
||||||
return FC_JSON_TYPE_STRING;
|
return FC_JSON_TYPE_STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const char *str; //input string
|
|
||||||
const char *p; //current
|
|
||||||
const char *end;
|
|
||||||
string_t element;
|
|
||||||
char *error_info;
|
|
||||||
int error_size;
|
|
||||||
} ParseContext;
|
|
||||||
|
|
||||||
static void set_parse_error(const char *str, const char *current,
|
static void set_parse_error(const char *str, const char *current,
|
||||||
const int expect_len, const char *front,
|
const int expect_len, const char *front,
|
||||||
char *error_info, const int error_size)
|
string_t *error_info, const int error_size)
|
||||||
{
|
{
|
||||||
const char *show_str;
|
const char *show_str;
|
||||||
int show_len;
|
int show_len;
|
||||||
|
|
@ -66,26 +57,18 @@ static void set_parse_error(const char *str, const char *current,
|
||||||
show_len = expect_len;
|
show_len = expect_len;
|
||||||
}
|
}
|
||||||
show_str = current - show_len;
|
show_str = current - show_len;
|
||||||
snprintf(error_info, error_size, "%s, input: %.*s",
|
error_info->len = snprintf(error_info->str, error_size,
|
||||||
front, show_len, show_str);
|
"%s, input: %.*s", front, show_len, show_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int json_escape_string(const string_t *input, string_t *output,
|
static int json_escape_string(fc_json_context_t *context,
|
||||||
char *error_info, const int error_size)
|
const string_t *input, char *output)
|
||||||
{
|
{
|
||||||
const char *src;
|
const char *src;
|
||||||
const char *end;
|
const char *end;
|
||||||
char *dest;
|
char *dest;
|
||||||
int size;
|
|
||||||
|
|
||||||
size = 2 * input->len + 1;
|
dest = output;
|
||||||
output->str = (char *)fc_malloc(size);
|
|
||||||
if (output->str == NULL) {
|
|
||||||
snprintf(error_info, error_size, "malloc %d bytes fail", size);
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
dest = output->str;
|
|
||||||
end = input->str + input->len;
|
end = input->str + input->len;
|
||||||
for (src=input->str; src<end; src++) {
|
for (src=input->str; src<end; src++) {
|
||||||
switch (*src) {
|
switch (*src) {
|
||||||
|
|
@ -105,9 +88,9 @@ static int json_escape_string(const string_t *input, string_t *output,
|
||||||
*dest++ = '\\';
|
*dest++ = '\\';
|
||||||
*dest++ = 'n';
|
*dest++ = 'n';
|
||||||
break;
|
break;
|
||||||
case '\b':
|
case '\f':
|
||||||
*dest++ = '\\';
|
*dest++ = '\\';
|
||||||
*dest++ = 'b';
|
*dest++ = 'f';
|
||||||
break;
|
break;
|
||||||
case '\"':
|
case '\"':
|
||||||
*dest++ = '\\';
|
*dest++ = '\\';
|
||||||
|
|
@ -123,12 +106,10 @@ static int json_escape_string(const string_t *input, string_t *output,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*dest = '\0';
|
return dest - output;
|
||||||
output->len = dest - output->str;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int next_json_element(ParseContext *context)
|
static int next_json_element(fc_json_context_t *context)
|
||||||
{
|
{
|
||||||
char *dest;
|
char *dest;
|
||||||
char buff[128];
|
char buff[128];
|
||||||
|
|
@ -143,7 +124,7 @@ static int next_json_element(ParseContext *context)
|
||||||
if (++context->p == context->end) {
|
if (++context->p == context->end) {
|
||||||
set_parse_error(context->str, context->p,
|
set_parse_error(context->str, context->p,
|
||||||
EXPECT_STR_LEN, "expect a character after \\",
|
EXPECT_STR_LEN, "expect a character after \\",
|
||||||
context->error_info, context->error_size);
|
&context->error_info, context->error_size);
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
switch (*context->p) {
|
switch (*context->p) {
|
||||||
|
|
@ -162,7 +143,7 @@ static int next_json_element(ParseContext *context)
|
||||||
case 'n':
|
case 'n':
|
||||||
*dest++ = '\n';
|
*dest++ = '\n';
|
||||||
break;
|
break;
|
||||||
case 'b':
|
case 'f':
|
||||||
*dest++ = '\f';
|
*dest++ = '\f';
|
||||||
break;
|
break;
|
||||||
case '"':
|
case '"':
|
||||||
|
|
@ -174,8 +155,9 @@ static int next_json_element(ParseContext *context)
|
||||||
default:
|
default:
|
||||||
sprintf(buff, "invalid escaped character: %c(0x%x)",
|
sprintf(buff, "invalid escaped character: %c(0x%x)",
|
||||||
*context->p, (unsigned char)*context->p);
|
*context->p, (unsigned char)*context->p);
|
||||||
set_parse_error(context->str, context->p + 1, EXPECT_STR_LEN,
|
set_parse_error(context->str, context->p + 1,
|
||||||
buff, context->error_info, context->error_size);
|
EXPECT_STR_LEN, buff, &context->error_info,
|
||||||
|
context->error_size);
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
context->p++;
|
context->p++;
|
||||||
|
|
@ -187,7 +169,7 @@ static int next_json_element(ParseContext *context)
|
||||||
if (context->p == context->end) {
|
if (context->p == context->end) {
|
||||||
sprintf(buff, "expect closed character: %c", quote_ch);
|
sprintf(buff, "expect closed character: %c", quote_ch);
|
||||||
set_parse_error(context->str, context->p, EXPECT_STR_LEN,
|
set_parse_error(context->str, context->p, EXPECT_STR_LEN,
|
||||||
buff, context->error_info, context->error_size);
|
buff, &context->error_info, context->error_size);
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
context->p++; //skip quote char
|
context->p++; //skip quote char
|
||||||
|
|
@ -202,8 +184,8 @@ static int next_json_element(ParseContext *context)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check_alloc_array(common_array_t *array,
|
static int check_alloc_array(fc_json_context_t *context,
|
||||||
char *error_info, const int error_size)
|
fc_common_array_t *array)
|
||||||
{
|
{
|
||||||
int bytes;
|
int bytes;
|
||||||
if (array->count < array->alloc) {
|
if (array->count < array->alloc) {
|
||||||
|
|
@ -219,62 +201,50 @@ static int check_alloc_array(common_array_t *array,
|
||||||
bytes = array->element_size * array->alloc;
|
bytes = array->element_size * array->alloc;
|
||||||
array->elements = fc_realloc(array->elements, bytes);
|
array->elements = fc_realloc(array->elements, bytes);
|
||||||
if (array->elements == NULL) {
|
if (array->elements == NULL) {
|
||||||
snprintf(error_info, error_size, "realloc %d bytes fail", bytes);
|
context->error_info.len = snprintf(context->error_info.str,
|
||||||
|
context->error_size, "realloc %d bytes fail", bytes);
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int check_alloc_json_array(json_array_t *array,
|
static int prepare_json_parse(fc_json_context_t *context,
|
||||||
char *error_info, const int error_size)
|
const string_t *input, const char lquote,
|
||||||
|
const char rquote)
|
||||||
{
|
{
|
||||||
return check_alloc_array((common_array_t *)array, error_info, error_size);
|
int expect_size;
|
||||||
}
|
int result;
|
||||||
|
|
||||||
static inline int check_alloc_json_map(json_map_t *array,
|
|
||||||
char *error_info, const int error_size)
|
|
||||||
{
|
|
||||||
return check_alloc_array((common_array_t *)array, error_info, error_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int prepare_json_parse(const string_t *input, common_array_t *array,
|
|
||||||
char *error_info, const int error_size,
|
|
||||||
const char lquote, const char rquote, ParseContext *context)
|
|
||||||
{
|
|
||||||
int buff_len;
|
|
||||||
|
|
||||||
array->elements = NULL;
|
|
||||||
array->count = array->alloc = 0;
|
|
||||||
array->buff = NULL;
|
|
||||||
|
|
||||||
if (input->len < 2) {
|
if (input->len < 2) {
|
||||||
snprintf(error_info, error_size, "json string is too short");
|
context->error_info.len = snprintf(context->error_info.str,
|
||||||
|
context->error_size, "json string is too short");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input->str[0] != lquote) {
|
if (input->str[0] != lquote) {
|
||||||
snprintf(error_info, error_size,
|
context->error_info.len = snprintf(context->error_info.str, context->
|
||||||
"json array must start with \"%c\"", lquote);
|
error_size, "json array must start with \"%c\"", lquote);
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (input->str[input->len - 1] != rquote) {
|
if (input->str[input->len - 1] != rquote) {
|
||||||
snprintf(error_info, error_size,
|
context->error_info.len = snprintf(context->error_info.str, context->
|
||||||
"json array must end with \"%c\"", rquote);
|
error_size, "json array must end with \"%c\"", rquote);
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
buff_len = input->len - 2;
|
expect_size = input->len;
|
||||||
array->buff = (char *)fc_malloc(buff_len + 1);
|
if (context->output.alloc_size < expect_size) {
|
||||||
if (array->buff == NULL) {
|
if ((result=fc_realloc_buffer(&context->output, context->
|
||||||
snprintf(error_info, error_size,
|
init_buff_size, expect_size)) != 0)
|
||||||
"malloc %d bytes fail", buff_len + 1);
|
{
|
||||||
return ENOMEM;
|
context->error_info.len = snprintf(context->error_info.str,
|
||||||
|
context->error_size, "realloc buffer fail");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context->error_info = error_info;
|
context->element.str = context->output.buff;
|
||||||
context->error_size = error_size;
|
|
||||||
context->element.str = array->buff;
|
|
||||||
context->element.len = 0;
|
context->element.len = 0;
|
||||||
context->str = input->str;
|
context->str = input->str;
|
||||||
context->p = input->str + 1;
|
context->p = input->str + 1;
|
||||||
|
|
@ -282,281 +252,239 @@ static int prepare_json_parse(const string_t *input, common_array_t *array,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int decode_json_array(const string_t *input, json_array_t *array,
|
static inline void json_quote_string(fc_json_context_t
|
||||||
char *error_info, const int error_size)
|
*context, const string_t *input, char **buff)
|
||||||
{
|
{
|
||||||
ParseContext context;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
array->element_size = sizeof(string_t);
|
|
||||||
if ((result=prepare_json_parse(input, (common_array_t *)array,
|
|
||||||
error_info, error_size, '[', ']', &context)) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = 0;
|
|
||||||
while (context.p < context.end) {
|
|
||||||
while (context.p < context.end && JSON_SPACE(*context.p)) {
|
|
||||||
context.p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.p == context.end) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*context.p == ',') {
|
|
||||||
set_parse_error(input->str, context.p + 1,
|
|
||||||
EXPECT_STR_LEN, "unexpect comma \",\"",
|
|
||||||
error_info, error_size);
|
|
||||||
result = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((result=next_json_element(&context)) != 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (context.p < context.end && JSON_SPACE(*context.p)) {
|
|
||||||
context.p++;
|
|
||||||
}
|
|
||||||
if (context.p < context.end) {
|
|
||||||
if (*context.p == ',') {
|
|
||||||
context.p++; //skip comma
|
|
||||||
} else {
|
|
||||||
set_parse_error(input->str, context.p,
|
|
||||||
EXPECT_STR_LEN, "expect comma \",\"",
|
|
||||||
error_info, error_size);
|
|
||||||
result = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((result=check_alloc_json_array(array, error_info, error_size)) != 0) {
|
|
||||||
array->count = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
array->elements[array->count++] = context.element;
|
|
||||||
context.element.str += context.element.len + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != 0) {
|
|
||||||
free_json_array(array);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_common_array(common_array_t *array)
|
|
||||||
{
|
|
||||||
if (array->elements != NULL) {
|
|
||||||
free(array->elements);
|
|
||||||
array->elements = NULL;
|
|
||||||
array->count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array->buff != NULL) {
|
|
||||||
free(array->buff);
|
|
||||||
array->buff = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int json_quote_string(const string_t *input, char **buff,
|
|
||||||
char *error_info, const int error_size)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
string_t escaped;
|
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
if ((result=json_escape_string(input, &escaped,
|
|
||||||
error_info, error_size)) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
p = *buff;
|
p = *buff;
|
||||||
*p++ = '"';
|
*p++ = '"';
|
||||||
memcpy(p, escaped.str, escaped.len);
|
p += json_escape_string(context, input, p);
|
||||||
p += escaped.len;
|
|
||||||
*p++ = '"';
|
*p++ = '"';
|
||||||
|
|
||||||
*buff = p;
|
*buff = p;
|
||||||
free(escaped.str);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int encode_json_array(json_array_t *array, string_t *output,
|
const BufferInfo *fc_encode_json_array(fc_json_context_t
|
||||||
char *error_info, const int error_size)
|
*context, const fc_json_array_t *array)
|
||||||
{
|
{
|
||||||
string_t *el;
|
string_t *el;
|
||||||
string_t *end;
|
string_t *end;
|
||||||
char *p;
|
char *p;
|
||||||
int result;
|
int expect_size;
|
||||||
int size;
|
|
||||||
|
|
||||||
|
expect_size = 3;
|
||||||
end = array->elements + array->count;
|
end = array->elements + array->count;
|
||||||
size = 3;
|
|
||||||
for (el=array->elements; el<end; el++) {
|
for (el=array->elements; el<end; el++) {
|
||||||
size += 2 * el->len + 3;
|
expect_size += 2 * el->len + 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
output->str = (char *)fc_malloc(size);
|
if (context->output.alloc_size < expect_size) {
|
||||||
if (output->str == NULL) {
|
if ((context->error_no=fc_realloc_buffer(&context->output,
|
||||||
snprintf(error_info, error_size, "malloc %d bytes fail", size);
|
context->init_buff_size, expect_size)) != 0)
|
||||||
return ENOMEM;
|
{
|
||||||
|
context->error_info.len = snprintf(context->error_info.str,
|
||||||
|
context->error_size, "realloc buffer fail");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p = output->str;
|
p = context->output.buff;
|
||||||
*p++ = '[';
|
*p++ = '[';
|
||||||
for (el=array->elements; el<end; el++) {
|
for (el=array->elements; el<end; el++) {
|
||||||
if (el > array->elements) {
|
if (el > array->elements) {
|
||||||
*p++ = ',';
|
*p++ = ',';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((result=json_quote_string(el, &p, error_info, error_size)) != 0) {
|
json_quote_string(context, el, &p);
|
||||||
free_json_string(output);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*p++ = ']';
|
*p++ = ']';
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
output->len = p - output->str;
|
context->output.length = p - context->output.buff;
|
||||||
return 0;
|
return &context->output;
|
||||||
}
|
}
|
||||||
|
|
||||||
int decode_json_map(const string_t *input, json_map_t *map,
|
const BufferInfo *fc_encode_json_map(fc_json_context_t
|
||||||
char *error_info, const int error_size)
|
*context, const fc_json_map_t *map)
|
||||||
{
|
|
||||||
ParseContext context;
|
|
||||||
key_value_pair_t kv_pair;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
map->element_size = sizeof(key_value_pair_t);
|
|
||||||
if ((result=prepare_json_parse(input, (common_array_t *)map,
|
|
||||||
error_info, error_size, '{', '}', &context)) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = 0;
|
|
||||||
while (context.p < context.end) {
|
|
||||||
while (context.p < context.end && JSON_SPACE(*context.p)) {
|
|
||||||
context.p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.p == context.end) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*context.p == ',') {
|
|
||||||
set_parse_error(input->str, context.p + 1,
|
|
||||||
EXPECT_STR_LEN, "unexpect comma \",\"",
|
|
||||||
error_info, error_size);
|
|
||||||
result = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((result=next_json_element(&context)) != 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
while (context.p < context.end && JSON_SPACE(*context.p)) {
|
|
||||||
context.p++;
|
|
||||||
}
|
|
||||||
if (!(context.p < context.end && *context.p == ':')) {
|
|
||||||
set_parse_error(input->str, context.p,
|
|
||||||
EXPECT_STR_LEN, "expect colon \":\"",
|
|
||||||
error_info, error_size);
|
|
||||||
result = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
context.p++; //skip colon
|
|
||||||
|
|
||||||
kv_pair.key = context.element;
|
|
||||||
context.element.str += context.element.len + 1;
|
|
||||||
|
|
||||||
while (context.p < context.end && JSON_SPACE(*context.p)) {
|
|
||||||
context.p++;
|
|
||||||
}
|
|
||||||
if ((result=next_json_element(&context)) != 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
while (context.p < context.end && JSON_SPACE(*context.p)) {
|
|
||||||
context.p++;
|
|
||||||
}
|
|
||||||
if (context.p < context.end) {
|
|
||||||
if (*context.p == ',') {
|
|
||||||
context.p++; //skip comma
|
|
||||||
} else {
|
|
||||||
set_parse_error(input->str, context.p,
|
|
||||||
EXPECT_STR_LEN, "expect comma \",\"",
|
|
||||||
error_info, error_size);
|
|
||||||
result = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
kv_pair.value = context.element;
|
|
||||||
context.element.str += context.element.len + 1;
|
|
||||||
|
|
||||||
if ((result=check_alloc_json_map(map, error_info, error_size)) != 0) {
|
|
||||||
map->count = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
map->elements[map->count++] = kv_pair;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != 0) {
|
|
||||||
free_json_map(map);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int encode_json_map(json_map_t *map, string_t *output,
|
|
||||||
char *error_info, const int error_size)
|
|
||||||
{
|
{
|
||||||
key_value_pair_t *pair;
|
key_value_pair_t *pair;
|
||||||
key_value_pair_t *end;
|
key_value_pair_t *end;
|
||||||
char *p;
|
char *p;
|
||||||
int result;
|
int expect_size;
|
||||||
int size;
|
|
||||||
|
|
||||||
|
expect_size = 3;
|
||||||
end = map->elements + map->count;
|
end = map->elements + map->count;
|
||||||
size = 3;
|
|
||||||
for (pair=map->elements; pair<end; pair++) {
|
for (pair=map->elements; pair<end; pair++) {
|
||||||
size += 2 * (pair->key.len + pair->value.len + 2) + 1;
|
expect_size += 2 * (pair->key.len + pair->value.len + 2) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
output->str = (char *)fc_malloc(size);
|
if (context->output.alloc_size < expect_size) {
|
||||||
if (output->str == NULL) {
|
if ((context->error_no=fc_realloc_buffer(&context->output,
|
||||||
snprintf(error_info, error_size, "malloc %d bytes fail", size);
|
context->init_buff_size, expect_size)) != 0)
|
||||||
return ENOMEM;
|
{
|
||||||
|
context->error_info.len = snprintf(context->error_info.str,
|
||||||
|
context->error_size, "realloc buffer fail");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p = output->str;
|
p = context->output.buff;
|
||||||
*p++ = '{';
|
*p++ = '{';
|
||||||
for (pair=map->elements; pair<end; pair++) {
|
for (pair=map->elements; pair<end; pair++) {
|
||||||
if (pair > map->elements) {
|
if (pair > map->elements) {
|
||||||
*p++ = ',';
|
*p++ = ',';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((result=json_quote_string(&pair->key, &p,
|
json_quote_string(context, &pair->key, &p);
|
||||||
error_info, error_size)) != 0)
|
|
||||||
{
|
|
||||||
free_json_string(output);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
*p++ = ':';
|
*p++ = ':';
|
||||||
if ((result=json_quote_string(&pair->value, &p,
|
json_quote_string(context, &pair->value, &p);
|
||||||
error_info, error_size)) != 0)
|
|
||||||
{
|
|
||||||
free_json_string(output);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*p++ = '}';
|
*p++ = '}';
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
output->len = p - output->str;
|
context->output.length = p - context->output.buff;
|
||||||
return 0;
|
return &context->output;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fc_json_array_t *fc_decode_json_array(fc_json_context_t
|
||||||
|
*context, const string_t *input)
|
||||||
|
{
|
||||||
|
if ((context->error_no=prepare_json_parse(context,
|
||||||
|
input, '[', ']')) != 0)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->jarray.count = 0;
|
||||||
|
while (context->p < context->end) {
|
||||||
|
while (context->p < context->end && JSON_SPACE(*context->p)) {
|
||||||
|
context->p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->p == context->end) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*context->p == ',') {
|
||||||
|
set_parse_error(input->str, context->p + 1,
|
||||||
|
EXPECT_STR_LEN, "unexpect comma \",\"",
|
||||||
|
&context->error_info, context->error_size);
|
||||||
|
context->error_no = EINVAL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((context->error_no=next_json_element(context)) != 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (context->p < context->end && JSON_SPACE(*context->p)) {
|
||||||
|
context->p++;
|
||||||
|
}
|
||||||
|
if (context->p < context->end) {
|
||||||
|
if (*context->p == ',') {
|
||||||
|
context->p++; //skip comma
|
||||||
|
} else {
|
||||||
|
set_parse_error(input->str, context->p,
|
||||||
|
EXPECT_STR_LEN, "expect comma \",\"",
|
||||||
|
&context->error_info, context->error_size);
|
||||||
|
context->error_no = EINVAL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((context->error_no=check_alloc_array(context,
|
||||||
|
(fc_common_array_t *)
|
||||||
|
&context->jarray)) != 0)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->jarray.elements[context->jarray.count++] = context->element;
|
||||||
|
context->element.str += context->element.len + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &context->jarray;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fc_json_map_t *fc_decode_json_map(fc_json_context_t
|
||||||
|
*context, const string_t *input)
|
||||||
|
{
|
||||||
|
key_value_pair_t kv_pair;
|
||||||
|
|
||||||
|
if ((context->error_no=prepare_json_parse(context,
|
||||||
|
input, '{', '}')) != 0)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->jmap.count = 0;
|
||||||
|
while (context->p < context->end) {
|
||||||
|
while (context->p < context->end && JSON_SPACE(*context->p)) {
|
||||||
|
context->p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->p == context->end) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*context->p == ',') {
|
||||||
|
set_parse_error(input->str, context->p + 1,
|
||||||
|
EXPECT_STR_LEN, "unexpect comma \",\"",
|
||||||
|
&context->error_info, context->error_size);
|
||||||
|
context->error_no = EINVAL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((context->error_no=next_json_element(context)) != 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
while (context->p < context->end && JSON_SPACE(*context->p)) {
|
||||||
|
context->p++;
|
||||||
|
}
|
||||||
|
if (!(context->p < context->end && *context->p == ':')) {
|
||||||
|
set_parse_error(input->str, context->p,
|
||||||
|
EXPECT_STR_LEN, "expect colon \":\"",
|
||||||
|
&context->error_info, context->error_size);
|
||||||
|
context->error_no = EINVAL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
context->p++; //skip colon
|
||||||
|
|
||||||
|
kv_pair.key = context->element;
|
||||||
|
context->element.str += context->element.len + 1;
|
||||||
|
|
||||||
|
while (context->p < context->end && JSON_SPACE(*context->p)) {
|
||||||
|
context->p++;
|
||||||
|
}
|
||||||
|
if ((context->error_no=next_json_element(context)) != 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
while (context->p < context->end && JSON_SPACE(*context->p)) {
|
||||||
|
context->p++;
|
||||||
|
}
|
||||||
|
if (context->p < context->end) {
|
||||||
|
if (*context->p == ',') {
|
||||||
|
context->p++; //skip comma
|
||||||
|
} else {
|
||||||
|
set_parse_error(input->str, context->p,
|
||||||
|
EXPECT_STR_LEN, "expect comma \",\"",
|
||||||
|
&context->error_info, context->error_size);
|
||||||
|
context->error_no = EINVAL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kv_pair.value = context->element;
|
||||||
|
context->element.str += context->element.len + 1;
|
||||||
|
|
||||||
|
if ((context->error_no=check_alloc_array(context,
|
||||||
|
(fc_common_array_t *)
|
||||||
|
&context->jmap)) != 0)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
context->jmap.elements[context->jmap.count++] = kv_pair;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &context->jmap;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@
|
||||||
|
|
||||||
//json_parser.h
|
//json_parser.h
|
||||||
|
|
||||||
#ifndef _JSON_PARSER_H
|
#ifndef _FC_JSON_PARSER_H
|
||||||
#define _JSON_PARSER_H
|
#define _FC_JSON_PARSER_H
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -36,55 +36,145 @@
|
||||||
/* for internal use */ \
|
/* for internal use */ \
|
||||||
int element_size; \
|
int element_size; \
|
||||||
int alloc; \
|
int alloc; \
|
||||||
char *buff; \
|
|
||||||
} ARRAY_TYPE
|
} ARRAY_TYPE
|
||||||
|
|
||||||
DEFINE_ARRAY_STRUCT(void, common_array_t);
|
DEFINE_ARRAY_STRUCT(void, fc_common_array_t);
|
||||||
DEFINE_ARRAY_STRUCT(string_t, json_array_t);
|
DEFINE_ARRAY_STRUCT(string_t, fc_json_array_t);
|
||||||
DEFINE_ARRAY_STRUCT(key_value_pair_t, json_map_t);
|
DEFINE_ARRAY_STRUCT(key_value_pair_t, fc_json_map_t);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
BufferInfo output; //for json encode
|
||||||
|
string_t element; //string allocator use output buffer
|
||||||
|
int init_buff_size;
|
||||||
|
int error_no;
|
||||||
|
int error_size;
|
||||||
|
char error_holder[256];
|
||||||
|
string_t error_info;
|
||||||
|
|
||||||
|
fc_json_array_t jarray;
|
||||||
|
fc_json_map_t jmap;
|
||||||
|
|
||||||
|
/* for internal use */
|
||||||
|
const char *str; //input string
|
||||||
|
const char *p; //current
|
||||||
|
const char *end;
|
||||||
|
} fc_json_context_t;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void free_common_array(common_array_t *array);
|
static inline void fc_init_common_array(fc_common_array_t *array,
|
||||||
|
const int element_size)
|
||||||
static inline void free_json_array(json_array_t *array)
|
|
||||||
{
|
{
|
||||||
free_common_array((common_array_t *)array);
|
array->elements = NULL;
|
||||||
|
array->element_size = element_size;
|
||||||
|
array->count = array->alloc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void free_json_map(json_map_t *array)
|
static inline void fc_init_json_array(fc_json_array_t *array)
|
||||||
{
|
{
|
||||||
free_common_array((common_array_t *)array);
|
fc_init_common_array((fc_common_array_t *)array, sizeof(string_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void free_json_string(string_t *buffer)
|
static inline void fc_init_json_map(fc_json_map_t *array)
|
||||||
{
|
{
|
||||||
if (buffer->str != NULL) {
|
fc_init_common_array((fc_common_array_t *)array,
|
||||||
free(buffer->str);
|
sizeof(key_value_pair_t));
|
||||||
buffer->str = NULL;
|
}
|
||||||
buffer->len = 0;
|
|
||||||
|
static inline void fc_free_common_array(fc_common_array_t *array)
|
||||||
|
{
|
||||||
|
if (array->elements != NULL) {
|
||||||
|
free(array->elements);
|
||||||
|
array->elements = NULL;
|
||||||
|
array->count = array->alloc = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int detect_json_type(const string_t *input);
|
static inline void fc_free_json_array(fc_json_array_t *array)
|
||||||
|
{
|
||||||
|
fc_free_common_array((fc_common_array_t *)array);
|
||||||
|
}
|
||||||
|
|
||||||
int decode_json_array(const string_t *input, json_array_t *array,
|
static inline void fc_free_json_map(fc_json_map_t *array)
|
||||||
char *error_info, const int error_size);
|
{
|
||||||
|
fc_free_common_array((fc_common_array_t *)array);
|
||||||
|
}
|
||||||
|
|
||||||
int encode_json_array(json_array_t *array, string_t *output,
|
static inline void fc_set_json_error_buffer(fc_json_context_t *ctx,
|
||||||
char *error_info, const int error_size);
|
char *error_info, const int error_size)
|
||||||
|
{
|
||||||
|
if (error_info != NULL && error_size > 0) {
|
||||||
|
ctx->error_info.str = error_info;
|
||||||
|
ctx->error_size = error_size;
|
||||||
|
} else {
|
||||||
|
ctx->error_info.str = ctx->error_holder;
|
||||||
|
ctx->error_size = sizeof(ctx->error_holder);
|
||||||
|
}
|
||||||
|
|
||||||
int decode_json_map(const string_t *input, json_map_t *map,
|
ctx->error_info.len = 0;
|
||||||
char *error_info, const int error_size);
|
*ctx->error_info.str = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
int encode_json_map(json_map_t *map, string_t *output,
|
static inline void fc_init_json_context_ex(fc_json_context_t *ctx,
|
||||||
char *error_info, const int error_size);
|
const int init_buff_size, char *error_info, const int error_size)
|
||||||
|
{
|
||||||
|
ctx->output.buff = NULL;
|
||||||
|
ctx->output.alloc_size = ctx->output.length = 0;
|
||||||
|
FC_SET_STRING_NULL(ctx->element);
|
||||||
|
if (init_buff_size > 0) {
|
||||||
|
ctx->init_buff_size = init_buff_size;
|
||||||
|
} else {
|
||||||
|
ctx->init_buff_size = 1024;
|
||||||
|
}
|
||||||
|
fc_init_json_array(&ctx->jarray);
|
||||||
|
fc_init_json_map(&ctx->jmap);
|
||||||
|
|
||||||
|
ctx->error_no = 0;
|
||||||
|
fc_set_json_error_buffer(ctx, error_info, error_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void fc_init_json_context(fc_json_context_t *ctx)
|
||||||
|
{
|
||||||
|
const int init_buff_size = 0;
|
||||||
|
fc_init_json_context_ex(ctx, init_buff_size, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void fc_destroy_json_context(fc_json_context_t *ctx)
|
||||||
|
{
|
||||||
|
fc_free_buffer(&ctx->output);
|
||||||
|
fc_free_json_array(&ctx->jarray);
|
||||||
|
fc_free_json_map(&ctx->jmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int fc_json_parser_get_error_no(fc_json_context_t *ctx)
|
||||||
|
{
|
||||||
|
return ctx->error_no;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const string_t *fc_json_parser_get_error_info(
|
||||||
|
fc_json_context_t *ctx)
|
||||||
|
{
|
||||||
|
return &ctx->error_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fc_detect_json_type(const string_t *input);
|
||||||
|
|
||||||
|
const BufferInfo *fc_encode_json_array(fc_json_context_t
|
||||||
|
*context, const fc_json_array_t *array);
|
||||||
|
|
||||||
|
const BufferInfo *fc_encode_json_map(fc_json_context_t
|
||||||
|
*context, const fc_json_map_t *map);
|
||||||
|
|
||||||
|
const fc_json_array_t *fc_decode_json_array(fc_json_context_t
|
||||||
|
*context, const string_t *input);
|
||||||
|
|
||||||
|
const fc_json_map_t *fc_decode_json_map(fc_json_context_t
|
||||||
|
*context, const string_t *input);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3550,6 +3550,35 @@ void fc_free_buffer(BufferInfo *buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fc_realloc_buffer(BufferInfo *buffer, const int
|
||||||
|
init_buff_size, const int expect_size)
|
||||||
|
{
|
||||||
|
char *new_buff;
|
||||||
|
int new_size;
|
||||||
|
|
||||||
|
if (buffer->alloc_size == 0) {
|
||||||
|
new_size = (init_buff_size > 0 ?
|
||||||
|
init_buff_size : 256);
|
||||||
|
} else {
|
||||||
|
new_size = buffer->alloc_size;
|
||||||
|
}
|
||||||
|
while (new_size < expect_size) {
|
||||||
|
new_size *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_buff = (char *)fc_malloc(new_size);
|
||||||
|
if (new_buff == NULL) {
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer->buff != NULL) {
|
||||||
|
free(buffer->buff);
|
||||||
|
}
|
||||||
|
buffer->buff = new_buff;
|
||||||
|
buffer->alloc_size = new_size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int fc_check_mkdir_ex(const char *path, const mode_t mode, bool *created)
|
int fc_check_mkdir_ex(const char *path, const mode_t mode, bool *created)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
|
||||||
|
|
@ -1093,6 +1093,15 @@ int fc_init_buffer(BufferInfo *buffer, const int buffer_size);
|
||||||
*/
|
*/
|
||||||
void fc_free_buffer(BufferInfo *buffer);
|
void fc_free_buffer(BufferInfo *buffer);
|
||||||
|
|
||||||
|
/** realloc buffer
|
||||||
|
* parameters:
|
||||||
|
* buffer: the buffer to init
|
||||||
|
* init_buff_size: the init buffer size
|
||||||
|
* expect_size: the expect buffer size
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int fc_realloc_buffer(BufferInfo *buffer, const int
|
||||||
|
init_buff_size, const int expect_size);
|
||||||
|
|
||||||
static inline int fc_get_umask()
|
static inline int fc_get_umask()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue