mirror of
https://github.com/sogou/workflow.git
synced 2026-02-08 01:33:17 +08:00
1400 lines
25 KiB
C
1400 lines
25 KiB
C
/*
|
|
Copyright (c) 2022 Sogou, Inc.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
|
|
Author: Xie Han (xiehan@sogou-inc.com)
|
|
*/
|
|
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include "list.h"
|
|
#include "rbtree.h"
|
|
#include "json_parser.h"
|
|
|
|
#define JSON_DEPTH_LIMIT 1024
|
|
|
|
struct __json_object
|
|
{
|
|
struct list_head head;
|
|
struct rb_root root;
|
|
int size;
|
|
};
|
|
|
|
struct __json_array
|
|
{
|
|
struct list_head head;
|
|
int size;
|
|
};
|
|
|
|
struct __json_value
|
|
{
|
|
union
|
|
{
|
|
char *string;
|
|
double number;
|
|
json_object_t object;
|
|
json_array_t array;
|
|
} value;
|
|
int type;
|
|
};
|
|
|
|
struct __json_member
|
|
{
|
|
struct list_head list;
|
|
struct rb_node rb;
|
|
json_value_t value;
|
|
char name[1];
|
|
};
|
|
|
|
struct __json_element
|
|
{
|
|
struct list_head list;
|
|
json_value_t value;
|
|
};
|
|
|
|
typedef struct __json_member json_member_t;
|
|
typedef struct __json_element json_element_t;
|
|
|
|
static int __json_string_length(const char *cursor)
|
|
{
|
|
int len = 0;
|
|
|
|
while (*cursor != '\"')
|
|
{
|
|
if (*cursor == '\\')
|
|
{
|
|
cursor++;
|
|
if (*cursor == '\0')
|
|
return -2;
|
|
}
|
|
else if ((unsigned char)*cursor < 0x20)
|
|
return -2;
|
|
|
|
cursor++;
|
|
len++;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static int __parse_json_hex4(const char *cursor, const char **end,
|
|
unsigned int *code)
|
|
{
|
|
int hex;
|
|
int i;
|
|
|
|
*code = 0;
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
hex = *cursor;
|
|
if (hex >= '0' && hex <= '9')
|
|
hex = hex - '0';
|
|
else if (hex >= 'A' && hex <= 'F')
|
|
hex = hex - 'A' + 10;
|
|
else if (hex >= 'a' && hex <= 'f')
|
|
hex = hex - 'a' + 10;
|
|
else
|
|
return -2;
|
|
|
|
*code = (*code << 4) + hex;
|
|
cursor++;
|
|
}
|
|
|
|
*end = cursor;
|
|
return 0;
|
|
}
|
|
|
|
static int __parse_json_unicode(const char *cursor, const char **end,
|
|
char *utf8)
|
|
{
|
|
unsigned int code;
|
|
unsigned int next;
|
|
int ret;
|
|
|
|
ret = __parse_json_hex4(cursor, end, &code);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
if (code >= 0xdc00 && code <= 0xdfff)
|
|
return -2;
|
|
|
|
if (code >= 0xd800 && code <= 0xdbff)
|
|
{
|
|
cursor = *end;
|
|
if (*cursor != '\\')
|
|
return -2;
|
|
|
|
cursor++;
|
|
if (*cursor != 'u')
|
|
return -2;
|
|
|
|
cursor++;
|
|
ret = __parse_json_hex4(cursor, end, &next);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
if (next < 0xdc00 || next > 0xdfff)
|
|
return -2;
|
|
|
|
code = (((code & 0x3ff) << 10) | (next & 0x3ff)) + 0x10000;
|
|
}
|
|
|
|
if (code <= 0x7f)
|
|
{
|
|
utf8[0] = code;
|
|
return 1;
|
|
}
|
|
else if (code <= 0x7ff)
|
|
{
|
|
utf8[0] = 0xc0 | (code >> 6);
|
|
utf8[1] = 0x80 | (code & 0x3f);
|
|
return 2;
|
|
}
|
|
else if (code <= 0xffff)
|
|
{
|
|
utf8[0] = 0xe0 | (code >> 12);
|
|
utf8[1] = 0x80 | ((code >> 6) & 0x3f);
|
|
utf8[2] = 0x80 | (code & 0x3f);
|
|
return 3;
|
|
}
|
|
else
|
|
{
|
|
utf8[0] = 0xf0 | (code >> 18);
|
|
utf8[1] = 0x80 | ((code >> 12) & 0x3f);
|
|
utf8[2] = 0x80 | ((code >> 6) & 0x3f);
|
|
utf8[3] = 0x80 | (code & 0x3f);
|
|
return 4;
|
|
}
|
|
}
|
|
|
|
static int __parse_json_string(const char *cursor, const char **end,
|
|
char *str)
|
|
{
|
|
int ret;
|
|
|
|
while (*cursor != '\"')
|
|
{
|
|
if (*cursor == '\\')
|
|
{
|
|
cursor++;
|
|
switch (*cursor)
|
|
{
|
|
case '\"':
|
|
*str = '\"';
|
|
break;
|
|
case '\\':
|
|
*str = '\\';
|
|
break;
|
|
case '/':
|
|
*str = '/';
|
|
break;
|
|
case 'b':
|
|
*str = '\b';
|
|
break;
|
|
case 'f':
|
|
*str = '\f';
|
|
break;
|
|
case 'n':
|
|
*str = '\n';
|
|
break;
|
|
case 'r':
|
|
*str = '\r';
|
|
break;
|
|
case 't':
|
|
*str = '\t';
|
|
break;
|
|
case 'u':
|
|
cursor++;
|
|
ret = __parse_json_unicode(cursor, &cursor, str);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
str += ret;
|
|
continue;
|
|
|
|
default:
|
|
return -2;
|
|
}
|
|
}
|
|
else
|
|
*str = *cursor;
|
|
|
|
cursor++;
|
|
str++;
|
|
}
|
|
|
|
*str = '\0';
|
|
*end = cursor + 1;
|
|
return 0;
|
|
}
|
|
|
|
static const double __power_of_10[309] = {
|
|
1e0, 1e1, 1e2, 1e3, 1e4,
|
|
1e5, 1e6, 1e7, 1e8, 1e9,
|
|
1e10, 1e11, 1e12, 1e13, 1e14,
|
|
1e15, 1e16, 1e17, 1e18, 1e19,
|
|
1e20, 1e21, 1e22, 1e23, 1e24,
|
|
1e25, 1e26, 1e27, 1e28, 1e29,
|
|
1e30, 1e31, 1e32, 1e33, 1e34,
|
|
1e35, 1e36, 1e37, 1e38, 1e39,
|
|
1e40, 1e41, 1e42, 1e43, 1e44,
|
|
1e45, 1e46, 1e47, 1e48, 1e49,
|
|
1e50, 1e51, 1e52, 1e53, 1e54,
|
|
1e55, 1e56, 1e57, 1e58, 1e59,
|
|
1e60, 1e61, 1e62, 1e63, 1e64,
|
|
1e65, 1e66, 1e67, 1e68, 1e69,
|
|
1e70, 1e71, 1e72, 1e73, 1e74,
|
|
1e75, 1e76, 1e77, 1e78, 1e79,
|
|
1e80, 1e81, 1e82, 1e83, 1e84,
|
|
1e85, 1e86, 1e87, 1e88, 1e89,
|
|
1e90, 1e91, 1e92, 1e93, 1e94,
|
|
1e95, 1e96, 1e97, 1e98, 1e99,
|
|
1e100, 1e101, 1e102, 1e103, 1e104,
|
|
1e105, 1e106, 1e107, 1e108, 1e109,
|
|
1e110, 1e111, 1e112, 1e113, 1e114,
|
|
1e115, 1e116, 1e117, 1e118, 1e119,
|
|
1e120, 1e121, 1e122, 1e123, 1e124,
|
|
1e125, 1e126, 1e127, 1e128, 1e129,
|
|
1e130, 1e131, 1e132, 1e133, 1e134,
|
|
1e135, 1e136, 1e137, 1e138, 1e139,
|
|
1e140, 1e141, 1e142, 1e143, 1e144,
|
|
1e145, 1e146, 1e147, 1e148, 1e149,
|
|
1e150, 1e151, 1e152, 1e153, 1e154,
|
|
1e155, 1e156, 1e157, 1e158, 1e159,
|
|
1e160, 1e161, 1e162, 1e163, 1e164,
|
|
1e165, 1e166, 1e167, 1e168, 1e169,
|
|
1e170, 1e171, 1e172, 1e173, 1e174,
|
|
1e175, 1e176, 1e177, 1e178, 1e179,
|
|
1e180, 1e181, 1e182, 1e183, 1e184,
|
|
1e185, 1e186, 1e187, 1e188, 1e189,
|
|
1e190, 1e191, 1e192, 1e193, 1e194,
|
|
1e195, 1e196, 1e197, 1e198, 1e199,
|
|
1e200, 1e201, 1e202, 1e203, 1e204,
|
|
1e205, 1e206, 1e207, 1e208, 1e209,
|
|
1e210, 1e211, 1e212, 1e213, 1e214,
|
|
1e215, 1e216, 1e217, 1e218, 1e219,
|
|
1e220, 1e221, 1e222, 1e223, 1e224,
|
|
1e225, 1e226, 1e227, 1e228, 1e229,
|
|
1e230, 1e231, 1e232, 1e233, 1e234,
|
|
1e235, 1e236, 1e237, 1e238, 1e239,
|
|
1e240, 1e241, 1e242, 1e243, 1e244,
|
|
1e245, 1e246, 1e247, 1e248, 1e249,
|
|
1e250, 1e251, 1e252, 1e253, 1e254,
|
|
1e255, 1e256, 1e257, 1e258, 1e259,
|
|
1e260, 1e261, 1e262, 1e263, 1e264,
|
|
1e265, 1e266, 1e267, 1e268, 1e269,
|
|
1e270, 1e271, 1e272, 1e273, 1e274,
|
|
1e275, 1e276, 1e277, 1e278, 1e279,
|
|
1e280, 1e281, 1e282, 1e283, 1e284,
|
|
1e285, 1e286, 1e287, 1e288, 1e289,
|
|
1e290, 1e291, 1e292, 1e293, 1e294,
|
|
1e295, 1e296, 1e297, 1e298, 1e299,
|
|
1e300, 1e301, 1e302, 1e303, 1e304,
|
|
1e305, 1e306, 1e307, 1e308
|
|
};
|
|
|
|
static double __evaluate_json_number(const char *integer,
|
|
const char *fraction,
|
|
int exp)
|
|
{
|
|
long long mant = 0;
|
|
int figures = 0;
|
|
double num;
|
|
int sign;
|
|
|
|
sign = (*integer == '-');
|
|
if (sign)
|
|
integer++;
|
|
|
|
if (*integer != '0')
|
|
{
|
|
mant = *integer - '0';
|
|
integer++;
|
|
figures++;
|
|
while (isdigit(*integer) && figures < 18)
|
|
{
|
|
mant *= 10;
|
|
mant += *integer - '0';
|
|
integer++;
|
|
figures++;
|
|
}
|
|
|
|
while (isdigit(*integer))
|
|
{
|
|
exp++;
|
|
integer++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (*fraction == '0')
|
|
{
|
|
exp--;
|
|
fraction++;
|
|
}
|
|
}
|
|
|
|
while (isdigit(*fraction) && figures < 18)
|
|
{
|
|
mant *= 10;
|
|
mant += *fraction - '0';
|
|
exp--;
|
|
fraction++;
|
|
figures++;
|
|
}
|
|
|
|
if (exp != 0 && figures != 0)
|
|
{
|
|
while (exp > 0 && figures < 18)
|
|
{
|
|
mant *= 10;
|
|
exp--;
|
|
figures++;
|
|
}
|
|
|
|
while (exp < 0 && mant % 10 == 0)
|
|
{
|
|
mant /= 10;
|
|
exp++;
|
|
figures--;
|
|
}
|
|
}
|
|
|
|
num = mant;
|
|
if (exp != 0 && figures != 0)
|
|
{
|
|
if (exp > 291)
|
|
num = INFINITY;
|
|
else if (exp > 0)
|
|
num *= __power_of_10[exp];
|
|
else if (exp > -309)
|
|
num /= __power_of_10[-exp];
|
|
else if (exp > -324 - figures)
|
|
{
|
|
num /= __power_of_10[-exp - 308];
|
|
num /= __power_of_10[308];
|
|
}
|
|
else
|
|
num = 0.0;
|
|
}
|
|
|
|
return sign ? -num : num;
|
|
}
|
|
|
|
static int __parse_json_number(const char *cursor, const char **end,
|
|
double *num)
|
|
{
|
|
const char *integer = cursor;
|
|
const char *fraction = "";
|
|
int exp = 0;
|
|
int sign;
|
|
|
|
if (*cursor == '-')
|
|
cursor++;
|
|
|
|
if (!isdigit(*cursor))
|
|
return -2;
|
|
|
|
if (*cursor == '0' && isdigit(cursor[1]))
|
|
return -2;
|
|
|
|
cursor++;
|
|
while (isdigit(*cursor))
|
|
cursor++;
|
|
|
|
if (*cursor == '.')
|
|
{
|
|
cursor++;
|
|
fraction = cursor;
|
|
if (!isdigit(*cursor))
|
|
return -2;
|
|
|
|
cursor++;
|
|
while (isdigit(*cursor))
|
|
cursor++;
|
|
}
|
|
|
|
if (*cursor == 'E' || *cursor == 'e')
|
|
{
|
|
cursor++;
|
|
sign = (*cursor == '-');
|
|
if (sign || *cursor == '+')
|
|
cursor++;
|
|
|
|
if (!isdigit(*cursor))
|
|
return -2;
|
|
|
|
exp = *cursor - '0';
|
|
cursor++;
|
|
while (isdigit(*cursor) && exp < 2000000)
|
|
{
|
|
exp *= 10;
|
|
exp += *cursor - '0';
|
|
cursor++;
|
|
}
|
|
|
|
while (isdigit(*cursor))
|
|
cursor++;
|
|
|
|
if (sign)
|
|
exp = -exp;
|
|
}
|
|
|
|
if (cursor - integer > 1000000)
|
|
return -2;
|
|
|
|
*num = __evaluate_json_number(integer, fraction, exp);
|
|
*end = cursor;
|
|
return 0;
|
|
}
|
|
|
|
static void __insert_json_member(json_member_t *memb, struct list_head *pos,
|
|
json_object_t *obj)
|
|
{
|
|
struct rb_node **p = &obj->root.rb_node;
|
|
struct rb_node *parent = NULL;
|
|
json_member_t *entry;
|
|
|
|
while (*p)
|
|
{
|
|
parent = *p;
|
|
entry = rb_entry(*p, json_member_t, rb);
|
|
if (strcmp(memb->name, entry->name) < 0)
|
|
p = &(*p)->rb_left;
|
|
else
|
|
p = &(*p)->rb_right;
|
|
}
|
|
|
|
rb_link_node(&memb->rb, parent, p);
|
|
rb_insert_color(&memb->rb, &obj->root);
|
|
list_add(&memb->list, pos);
|
|
}
|
|
|
|
static int __parse_json_value(const char *cursor, const char **end,
|
|
int depth, json_value_t *val);
|
|
|
|
static void __destroy_json_value(json_value_t *val);
|
|
|
|
static int __parse_json_member(const char *cursor, const char **end,
|
|
int depth, json_member_t *memb)
|
|
{
|
|
int ret;
|
|
|
|
ret = __parse_json_string(cursor, &cursor, memb->name);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
while (isspace(*cursor))
|
|
cursor++;
|
|
|
|
if (*cursor != ':')
|
|
return -2;
|
|
|
|
cursor++;
|
|
while (isspace(*cursor))
|
|
cursor++;
|
|
|
|
ret = __parse_json_value(cursor, &cursor, depth, &memb->value);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
*end = cursor;
|
|
return 0;
|
|
}
|
|
|
|
static int __parse_json_members(const char *cursor, const char **end,
|
|
int depth, json_object_t *obj)
|
|
{
|
|
json_member_t *memb;
|
|
int cnt = 0;
|
|
int ret;
|
|
|
|
while (isspace(*cursor))
|
|
cursor++;
|
|
|
|
if (*cursor == '}')
|
|
{
|
|
*end = cursor + 1;
|
|
return 0;
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
if (*cursor != '\"')
|
|
return -2;
|
|
|
|
cursor++;
|
|
ret = __json_string_length(cursor);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
memb = (json_member_t *)malloc(offsetof(json_member_t, name) + ret + 1);
|
|
if (!memb)
|
|
return -1;
|
|
|
|
ret = __parse_json_member(cursor, &cursor, depth, memb);
|
|
if (ret < 0)
|
|
{
|
|
free(memb);
|
|
return ret;
|
|
}
|
|
|
|
__insert_json_member(memb, obj->head.prev, obj);
|
|
cnt++;
|
|
|
|
while (isspace(*cursor))
|
|
cursor++;
|
|
|
|
if (*cursor == ',')
|
|
{
|
|
cursor++;
|
|
while (isspace(*cursor))
|
|
cursor++;
|
|
}
|
|
else if (*cursor == '}')
|
|
break;
|
|
else
|
|
return -2;
|
|
}
|
|
|
|
*end = cursor + 1;
|
|
return cnt;
|
|
}
|
|
|
|
static void __destroy_json_members(json_object_t *obj)
|
|
{
|
|
struct list_head *pos, *tmp;
|
|
json_member_t *memb;
|
|
|
|
list_for_each_safe(pos, tmp, &obj->head)
|
|
{
|
|
memb = list_entry(pos, json_member_t, list);
|
|
__destroy_json_value(&memb->value);
|
|
free(memb);
|
|
}
|
|
}
|
|
|
|
static int __parse_json_object(const char *cursor, const char **end,
|
|
int depth, json_object_t *obj)
|
|
{
|
|
int ret;
|
|
|
|
if (depth == JSON_DEPTH_LIMIT)
|
|
return -3;
|
|
|
|
INIT_LIST_HEAD(&obj->head);
|
|
obj->root.rb_node = NULL;
|
|
ret = __parse_json_members(cursor, end, depth + 1, obj);
|
|
if (ret < 0)
|
|
{
|
|
__destroy_json_members(obj);
|
|
return ret;
|
|
}
|
|
|
|
obj->size = ret;
|
|
return 0;
|
|
}
|
|
|
|
static int __parse_json_elements(const char *cursor, const char **end,
|
|
int depth, json_array_t *arr)
|
|
{
|
|
json_element_t *elem;
|
|
int cnt = 0;
|
|
int ret;
|
|
|
|
while (isspace(*cursor))
|
|
cursor++;
|
|
|
|
if (*cursor == ']')
|
|
{
|
|
*end = cursor + 1;
|
|
return 0;
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
elem = (json_element_t *)malloc(sizeof (json_element_t));
|
|
if (!elem)
|
|
return -1;
|
|
|
|
ret = __parse_json_value(cursor, &cursor, depth, &elem->value);
|
|
if (ret < 0)
|
|
{
|
|
free(elem);
|
|
return ret;
|
|
}
|
|
|
|
list_add_tail(&elem->list, &arr->head);
|
|
cnt++;
|
|
|
|
while (isspace(*cursor))
|
|
cursor++;
|
|
|
|
if (*cursor == ',')
|
|
{
|
|
cursor++;
|
|
while (isspace(*cursor))
|
|
cursor++;
|
|
}
|
|
else if (*cursor == ']')
|
|
break;
|
|
else
|
|
return -2;
|
|
}
|
|
|
|
*end = cursor + 1;
|
|
return cnt;
|
|
}
|
|
|
|
static void __destroy_json_elements(json_array_t *arr)
|
|
{
|
|
struct list_head *pos, *tmp;
|
|
json_element_t *elem;
|
|
|
|
list_for_each_safe(pos, tmp, &arr->head)
|
|
{
|
|
elem = list_entry(pos, json_element_t, list);
|
|
__destroy_json_value(&elem->value);
|
|
free(elem);
|
|
}
|
|
}
|
|
|
|
static int __parse_json_array(const char *cursor, const char **end,
|
|
int depth, json_array_t *arr)
|
|
{
|
|
int ret;
|
|
|
|
if (depth == JSON_DEPTH_LIMIT)
|
|
return -3;
|
|
|
|
INIT_LIST_HEAD(&arr->head);
|
|
ret = __parse_json_elements(cursor, end, depth + 1, arr);
|
|
if (ret < 0)
|
|
{
|
|
__destroy_json_elements(arr);
|
|
return ret;
|
|
}
|
|
|
|
arr->size = ret;
|
|
return 0;
|
|
}
|
|
|
|
static int __parse_json_value(const char *cursor, const char **end,
|
|
int depth, json_value_t *val)
|
|
{
|
|
int ret;
|
|
|
|
switch (*cursor)
|
|
{
|
|
case '\"':
|
|
cursor++;
|
|
ret = __json_string_length(cursor);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
val->value.string = (char *)malloc(ret + 1);
|
|
if (!val->value.string)
|
|
return -1;
|
|
|
|
ret = __parse_json_string(cursor, end, val->value.string);
|
|
if (ret < 0)
|
|
{
|
|
free(val->value.string);
|
|
return ret;
|
|
}
|
|
|
|
val->type = JSON_VALUE_STRING;
|
|
break;
|
|
|
|
case '-':
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
ret = __parse_json_number(cursor, end, &val->value.number);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
val->type = JSON_VALUE_NUMBER;
|
|
break;
|
|
|
|
case '{':
|
|
cursor++;
|
|
ret = __parse_json_object(cursor, end, depth, &val->value.object);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
val->type = JSON_VALUE_OBJECT;
|
|
break;
|
|
|
|
case '[':
|
|
cursor++;
|
|
ret = __parse_json_array(cursor, end, depth, &val->value.array);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
val->type = JSON_VALUE_ARRAY;
|
|
break;
|
|
|
|
case 't':
|
|
if (strncmp(cursor, "true", 4) != 0)
|
|
return -2;
|
|
|
|
*end = cursor + 4;
|
|
val->type = JSON_VALUE_TRUE;
|
|
break;
|
|
|
|
case 'f':
|
|
if (strncmp(cursor, "false", 5) != 0)
|
|
return -2;
|
|
|
|
*end = cursor + 5;
|
|
val->type = JSON_VALUE_FALSE;
|
|
break;
|
|
|
|
case 'n':
|
|
if (strncmp(cursor, "null", 4) != 0)
|
|
return -2;
|
|
|
|
*end = cursor + 4;
|
|
val->type = JSON_VALUE_NULL;
|
|
break;
|
|
|
|
default:
|
|
return -2;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void __destroy_json_value(json_value_t *val)
|
|
{
|
|
switch (val->type)
|
|
{
|
|
case JSON_VALUE_STRING:
|
|
free(val->value.string);
|
|
break;
|
|
|
|
case JSON_VALUE_OBJECT:
|
|
__destroy_json_members(&val->value.object);
|
|
break;
|
|
|
|
case JSON_VALUE_ARRAY:
|
|
__destroy_json_elements(&val->value.array);
|
|
break;
|
|
}
|
|
}
|
|
|
|
json_value_t *json_value_parse(const char *cursor)
|
|
{
|
|
json_value_t *val;
|
|
|
|
val = (json_value_t *)malloc(sizeof (json_value_t));
|
|
if (!val)
|
|
return NULL;
|
|
|
|
while (isspace(*cursor))
|
|
cursor++;
|
|
|
|
if (__parse_json_value(cursor, &cursor, 0, val) >= 0)
|
|
{
|
|
while (isspace(*cursor))
|
|
cursor++;
|
|
|
|
if (*cursor == '\0')
|
|
return val;
|
|
|
|
__destroy_json_value(val);
|
|
}
|
|
|
|
free(val);
|
|
return NULL;
|
|
}
|
|
|
|
static void __move_json_value(json_value_t *src, json_value_t *dest)
|
|
{
|
|
switch (src->type)
|
|
{
|
|
case JSON_VALUE_STRING:
|
|
dest->value.string = src->value.string;
|
|
break;
|
|
|
|
case JSON_VALUE_NUMBER:
|
|
dest->value.number = src->value.number;
|
|
break;
|
|
|
|
case JSON_VALUE_OBJECT:
|
|
INIT_LIST_HEAD(&dest->value.object.head);
|
|
list_splice(&src->value.object.head, &dest->value.object.head);
|
|
dest->value.object.root.rb_node = src->value.object.root.rb_node;
|
|
dest->value.object.size = src->value.object.size;
|
|
break;
|
|
|
|
case JSON_VALUE_ARRAY:
|
|
INIT_LIST_HEAD(&dest->value.array.head);
|
|
list_splice(&src->value.array.head, &dest->value.array.head);
|
|
dest->value.array.size = src->value.array.size;
|
|
break;
|
|
}
|
|
|
|
dest->type = src->type;
|
|
}
|
|
|
|
static int __set_json_value(int type, va_list ap, json_value_t *val)
|
|
{
|
|
json_value_t *src;
|
|
const char *str;
|
|
int len;
|
|
|
|
switch (type)
|
|
{
|
|
case 0:
|
|
src = va_arg(ap, json_value_t *);
|
|
__move_json_value(src, val);
|
|
free(src);
|
|
return 0;
|
|
|
|
case JSON_VALUE_STRING:
|
|
str = va_arg(ap, const char *);
|
|
len = strlen(str);
|
|
val->value.string = (char *)malloc(len + 1);
|
|
if (!val->value.string)
|
|
return -1;
|
|
|
|
memcpy(val->value.string, str, len + 1);
|
|
break;
|
|
|
|
case JSON_VALUE_NUMBER:
|
|
val->value.number = va_arg(ap, double);
|
|
break;
|
|
|
|
case JSON_VALUE_OBJECT:
|
|
INIT_LIST_HEAD(&val->value.object.head);
|
|
val->value.object.root.rb_node = NULL;
|
|
val->value.object.size = 0;
|
|
break;
|
|
|
|
case JSON_VALUE_ARRAY:
|
|
INIT_LIST_HEAD(&val->value.array.head);
|
|
val->value.array.size = 0;
|
|
break;
|
|
}
|
|
|
|
val->type = type;
|
|
return 0;
|
|
}
|
|
|
|
json_value_t *json_value_create(int type, ...)
|
|
{
|
|
json_value_t *val;
|
|
va_list ap;
|
|
int ret;
|
|
|
|
val = (json_value_t *)malloc(sizeof (json_value_t));
|
|
if (!val)
|
|
return NULL;
|
|
|
|
va_start(ap, type);
|
|
ret = __set_json_value(type, ap, val);
|
|
va_end(ap);
|
|
if (ret < 0)
|
|
{
|
|
free(val);
|
|
return NULL;
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
static int __copy_json_value(const json_value_t *src, json_value_t *dest);
|
|
|
|
static int __copy_json_members(const json_object_t *src, json_object_t *dest)
|
|
{
|
|
struct list_head *pos;
|
|
json_member_t *entry;
|
|
json_member_t *memb;
|
|
int len;
|
|
|
|
list_for_each(pos, &src->head)
|
|
{
|
|
entry = list_entry(pos, json_member_t, list);
|
|
len = strlen(entry->name);
|
|
memb = (json_member_t *)malloc(offsetof(json_member_t, name) + len + 1);
|
|
if (!memb)
|
|
return -1;
|
|
|
|
if (__copy_json_value(&entry->value, &memb->value) < 0)
|
|
{
|
|
free(memb);
|
|
return -1;
|
|
}
|
|
|
|
memcpy(memb->name, entry->name, len + 1);
|
|
__insert_json_member(memb, dest->head.prev, dest);
|
|
}
|
|
|
|
return src->size;
|
|
}
|
|
|
|
static int __copy_json_elements(const json_array_t *src, json_array_t *dest)
|
|
{
|
|
struct list_head *pos;
|
|
json_element_t *entry;
|
|
json_element_t *elem;
|
|
|
|
list_for_each(pos, &src->head)
|
|
{
|
|
elem = (json_element_t *)malloc(sizeof (json_element_t));
|
|
if (!elem)
|
|
return -1;
|
|
|
|
entry = list_entry(pos, json_element_t, list);
|
|
if (__copy_json_value(&entry->value, &elem->value) < 0)
|
|
{
|
|
free(elem);
|
|
return -1;
|
|
}
|
|
|
|
list_add_tail(&elem->list, &dest->head);
|
|
}
|
|
|
|
return src->size;
|
|
}
|
|
|
|
static int __copy_json_value(const json_value_t *src, json_value_t *dest)
|
|
{
|
|
int len;
|
|
|
|
switch (src->type)
|
|
{
|
|
case JSON_VALUE_STRING:
|
|
len = strlen(src->value.string);
|
|
dest->value.string = (char *)malloc(len + 1);
|
|
if (!dest->value.string)
|
|
return -1;
|
|
|
|
memcpy(dest->value.string, src->value.string, len + 1);
|
|
break;
|
|
|
|
case JSON_VALUE_NUMBER:
|
|
dest->value.number = src->value.number;
|
|
break;
|
|
|
|
case JSON_VALUE_OBJECT:
|
|
INIT_LIST_HEAD(&dest->value.object.head);
|
|
dest->value.object.root.rb_node = NULL;
|
|
if (__copy_json_members(&src->value.object, &dest->value.object) < 0)
|
|
{
|
|
__destroy_json_members(&dest->value.object);
|
|
return -1;
|
|
}
|
|
|
|
dest->value.object.size = src->value.object.size;
|
|
break;
|
|
|
|
case JSON_VALUE_ARRAY:
|
|
INIT_LIST_HEAD(&dest->value.array.head);
|
|
if (__copy_json_elements(&src->value.array, &dest->value.array) < 0)
|
|
{
|
|
__destroy_json_elements(&dest->value.array);
|
|
return -1;
|
|
}
|
|
|
|
dest->value.array.size = src->value.array.size;
|
|
break;
|
|
}
|
|
|
|
dest->type = src->type;
|
|
return 0;
|
|
}
|
|
|
|
json_value_t *json_value_copy(const json_value_t *val)
|
|
{
|
|
json_value_t *copy;
|
|
|
|
copy = (json_value_t *)malloc(sizeof (json_value_t));
|
|
if (!copy)
|
|
return NULL;
|
|
|
|
if (__copy_json_value(val, copy) < 0)
|
|
{
|
|
free(copy);
|
|
return NULL;
|
|
}
|
|
|
|
return copy;
|
|
}
|
|
|
|
void json_value_destroy(json_value_t *val)
|
|
{
|
|
__destroy_json_value(val);
|
|
free(val);
|
|
}
|
|
|
|
int json_value_type(const json_value_t *val)
|
|
{
|
|
return val->type;
|
|
}
|
|
|
|
const char *json_value_string(const json_value_t *val)
|
|
{
|
|
if (val->type != JSON_VALUE_STRING)
|
|
return NULL;
|
|
|
|
return val->value.string;
|
|
}
|
|
|
|
double json_value_number(const json_value_t *val)
|
|
{
|
|
if (val->type != JSON_VALUE_NUMBER)
|
|
return NAN;
|
|
|
|
return val->value.number;
|
|
}
|
|
|
|
json_object_t *json_value_object(const json_value_t *val)
|
|
{
|
|
if (val->type != JSON_VALUE_OBJECT)
|
|
return NULL;
|
|
|
|
return (json_object_t *)&val->value.object;
|
|
}
|
|
|
|
json_array_t *json_value_array(const json_value_t *val)
|
|
{
|
|
if (val->type != JSON_VALUE_ARRAY)
|
|
return NULL;
|
|
|
|
return (json_array_t *)&val->value.array;
|
|
}
|
|
|
|
const json_value_t *json_object_find(const char *name,
|
|
const json_object_t *obj)
|
|
{
|
|
struct rb_node *p = obj->root.rb_node;
|
|
json_member_t *memb;
|
|
int n;
|
|
|
|
while (p)
|
|
{
|
|
memb = rb_entry(p, json_member_t, rb);
|
|
n = strcmp(name, memb->name);
|
|
if (n < 0)
|
|
p = p->rb_left;
|
|
else if (n > 0)
|
|
p = p->rb_right;
|
|
else
|
|
return &memb->value;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int json_object_size(const json_object_t *obj)
|
|
{
|
|
return obj->size;
|
|
}
|
|
|
|
const char *json_object_next_name(const char *name,
|
|
const json_object_t *obj)
|
|
{
|
|
const struct list_head *pos;
|
|
|
|
if (name)
|
|
pos = &list_entry(name, json_member_t, name)->list;
|
|
else
|
|
pos = &obj->head;
|
|
|
|
if (pos->next == &obj->head)
|
|
return NULL;
|
|
|
|
return list_entry(pos->next, json_member_t, list)->name;
|
|
}
|
|
|
|
const json_value_t *json_object_next_value(const json_value_t *val,
|
|
const json_object_t *obj)
|
|
{
|
|
const struct list_head *pos;
|
|
|
|
if (val)
|
|
pos = &list_entry(val, json_member_t, value)->list;
|
|
else
|
|
pos = &obj->head;
|
|
|
|
if (pos->next == &obj->head)
|
|
return NULL;
|
|
|
|
return &list_entry(pos->next, json_member_t, list)->value;
|
|
}
|
|
|
|
const char *json_object_prev_name(const char *name,
|
|
const json_object_t *obj)
|
|
{
|
|
const struct list_head *pos;
|
|
|
|
if (name)
|
|
pos = &list_entry(name, json_member_t, name)->list;
|
|
else
|
|
pos = &obj->head;
|
|
|
|
if (pos->prev == &obj->head)
|
|
return NULL;
|
|
|
|
return list_entry(pos->prev, json_member_t, list)->name;
|
|
}
|
|
|
|
const json_value_t *json_object_prev_value(const json_value_t *val,
|
|
const json_object_t *obj)
|
|
{
|
|
const struct list_head *pos;
|
|
|
|
if (val)
|
|
pos = &list_entry(val, json_member_t, value)->list;
|
|
else
|
|
pos = &obj->head;
|
|
|
|
if (pos->prev == &obj->head)
|
|
return NULL;
|
|
|
|
return &list_entry(pos->prev, json_member_t, list)->value;
|
|
}
|
|
|
|
static const json_value_t *__json_object_insert(const char *name,
|
|
int type, va_list ap,
|
|
struct list_head *pos,
|
|
json_object_t *obj)
|
|
{
|
|
json_member_t *memb;
|
|
int len;
|
|
|
|
len = strlen(name);
|
|
memb = (json_member_t *)malloc(offsetof(json_member_t, name) + len + 1);
|
|
if (!memb)
|
|
return NULL;
|
|
|
|
memcpy(memb->name, name, len + 1);
|
|
if (__set_json_value(type, ap, &memb->value) < 0)
|
|
{
|
|
free(memb);
|
|
return NULL;
|
|
}
|
|
|
|
__insert_json_member(memb, pos, obj);
|
|
obj->size++;
|
|
return &memb->value;
|
|
}
|
|
|
|
const json_value_t *json_object_append(json_object_t *obj,
|
|
const char *name,
|
|
int type, ...)
|
|
{
|
|
const json_value_t *val;
|
|
va_list ap;
|
|
|
|
va_start(ap, type);
|
|
val = __json_object_insert(name, type, ap, obj->head.prev, obj);
|
|
va_end(ap);
|
|
return val;
|
|
}
|
|
|
|
const json_value_t *json_object_insert_after(const json_value_t *val,
|
|
json_object_t *obj,
|
|
const char *name,
|
|
int type, ...)
|
|
{
|
|
struct list_head *pos;
|
|
va_list ap;
|
|
|
|
if (val)
|
|
pos = &list_entry(val, json_member_t, value)->list;
|
|
else
|
|
pos = &obj->head;
|
|
|
|
va_start(ap, type);
|
|
val = __json_object_insert(name, type, ap, pos, obj);
|
|
va_end(ap);
|
|
return val;
|
|
}
|
|
|
|
const json_value_t *json_object_insert_before(const json_value_t *val,
|
|
json_object_t *obj,
|
|
const char *name,
|
|
int type, ...)
|
|
{
|
|
struct list_head *pos;
|
|
va_list ap;
|
|
|
|
if (val)
|
|
pos = &list_entry(val, json_member_t, value)->list;
|
|
else
|
|
pos = &obj->head;
|
|
|
|
va_start(ap, type);
|
|
val = __json_object_insert(name, type, ap, pos->prev, obj);
|
|
va_end(ap);
|
|
return val;
|
|
}
|
|
|
|
json_value_t *json_object_remove(const json_value_t *val,
|
|
json_object_t *obj)
|
|
{
|
|
json_member_t *memb = list_entry(val, json_member_t, value);
|
|
|
|
val = (json_value_t *)malloc(sizeof (json_value_t));
|
|
if (!val)
|
|
return NULL;
|
|
|
|
list_del(&memb->list);
|
|
rb_erase(&memb->rb, &obj->root);
|
|
obj->size--;
|
|
|
|
__move_json_value(&memb->value, (json_value_t *)val);
|
|
free(memb);
|
|
return (json_value_t *)val;
|
|
}
|
|
|
|
int json_array_size(const json_array_t *arr)
|
|
{
|
|
return arr->size;
|
|
}
|
|
|
|
const json_value_t *json_array_next_value(const json_value_t *val,
|
|
const json_array_t *arr)
|
|
{
|
|
const struct list_head *pos;
|
|
|
|
if (val)
|
|
pos = &list_entry(val, json_element_t, value)->list;
|
|
else
|
|
pos = &arr->head;
|
|
|
|
if (pos->next == &arr->head)
|
|
return NULL;
|
|
|
|
return &list_entry(pos->next, json_element_t, list)->value;
|
|
}
|
|
|
|
const json_value_t *json_array_prev_value(const json_value_t *val,
|
|
const json_array_t *arr)
|
|
{
|
|
const struct list_head *pos;
|
|
|
|
if (val)
|
|
pos = &list_entry(val, json_element_t, value)->list;
|
|
else
|
|
pos = &arr->head;
|
|
|
|
if (pos->prev == &arr->head)
|
|
return NULL;
|
|
|
|
return &list_entry(pos->prev, json_element_t, list)->value;
|
|
}
|
|
|
|
static const json_value_t *__json_array_insert(int type, va_list ap,
|
|
struct list_head *pos,
|
|
json_array_t *arr)
|
|
{
|
|
json_element_t *elem;
|
|
|
|
elem = (json_element_t *)malloc(sizeof (json_element_t));
|
|
if (!elem)
|
|
return NULL;
|
|
|
|
if (__set_json_value(type, ap, &elem->value) < 0)
|
|
{
|
|
free(elem);
|
|
return NULL;
|
|
}
|
|
|
|
list_add(&elem->list, pos);
|
|
arr->size++;
|
|
return &elem->value;
|
|
}
|
|
|
|
const json_value_t *json_array_append(json_array_t *arr,
|
|
int type, ...)
|
|
{
|
|
const json_value_t *val;
|
|
va_list ap;
|
|
|
|
va_start(ap, type);
|
|
val = __json_array_insert(type, ap, arr->head.prev, arr);
|
|
va_end(ap);
|
|
return val;
|
|
}
|
|
|
|
const json_value_t *json_array_insert_after(const json_value_t *val,
|
|
json_array_t *arr,
|
|
int type, ...)
|
|
{
|
|
struct list_head *pos;
|
|
va_list ap;
|
|
|
|
if (val)
|
|
pos = &list_entry(val, json_element_t, value)->list;
|
|
else
|
|
pos = &arr->head;
|
|
|
|
va_start(ap, type);
|
|
val = __json_array_insert(type, ap, pos, arr);
|
|
va_end(ap);
|
|
return val;
|
|
}
|
|
|
|
const json_value_t *json_array_insert_before(const json_value_t *val,
|
|
json_array_t *arr,
|
|
int type, ...)
|
|
{
|
|
struct list_head *pos;
|
|
va_list ap;
|
|
|
|
if (val)
|
|
pos = &list_entry(val, json_element_t, value)->list;
|
|
else
|
|
pos = &arr->head;
|
|
|
|
va_start(ap, type);
|
|
val = __json_array_insert(type, ap, pos->prev, arr);
|
|
va_end(ap);
|
|
return val;
|
|
}
|
|
|
|
json_value_t *json_array_remove(const json_value_t *val,
|
|
json_array_t *arr)
|
|
{
|
|
json_element_t *elem = list_entry(val, json_element_t, value);
|
|
|
|
val = (json_value_t *)malloc(sizeof (json_value_t));
|
|
if (!val)
|
|
return NULL;
|
|
|
|
list_del(&elem->list);
|
|
arr->size--;
|
|
|
|
__move_json_value(&elem->value, (json_value_t *)val);
|
|
free(elem);
|
|
return (json_value_t *)val;
|
|
}
|
|
|