add json parser and update library version

This commit is contained in:
XieHan
2022-03-10 19:44:39 +08:00
parent 71b5531728
commit 1f911d684c
6 changed files with 1001 additions and 6 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ set(CMAKE_SKIP_RPATH TRUE)
project(
workflow
VERSION 0.9.11
VERSION 0.10.1
LANGUAGES C CXX
)
+2 -5
View File
@@ -17,11 +17,7 @@ set(COMMON_KERNEL_HEADERS
src/kernel/thrdpool.h
)
if (WIN32)
set(INCLUDE_KERNEL_HEADERS
src/kernel_win/list.h
)
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
set(INCLUDE_KERNEL_HEADERS
${COMMON_KERNEL_HEADERS}
src/kernel/IOService_linux.h
@@ -72,6 +68,7 @@ set(INCLUDE_HEADERS
src/manager/WFFuture.h
src/manager/WFFacilities.h
src/manager/WFFacilities.inl
src/util/json_parser.h
src/util/EncodeStream.h
src/util/LRUCache.h
src/util/StringUtil.h
+1
View File
@@ -0,0 +1 @@
../../util/json_parser.h
+1
View File
@@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.6)
project(util)
set(SRC
json_parser.c
EncodeStream.cc
StringUtil.cc
URIParser.cc
+915
View File
@@ -0,0 +1,915 @@
/*
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
{
int type;
union
{
char *string;
double number;
json_object_t object;
json_array_t array;
} value;
};
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 void __insert_json_member(json_member_t *memb, 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_tail(&memb->list, &obj->head);
}
static int __json_string_length(const char *cursor)
{
int len = 0;
while (1)
{
if (*cursor == '\"')
break;
if (*(const unsigned char *)cursor < ' ')
return -2;
cursor++;
if (cursor[-1] == '\\')
{
if (!*cursor)
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 int __parse_json_number(const char *cursor, const char **end,
double *num)
{
const char *p = cursor;
if (*p == '-')
p++;
if (*p == '0' && (isdigit(p[1]) || p[1] == 'X' || p[1] == 'x'))
return -2;
*num = strtod(cursor, (char **)end);
if (*end == cursor)
return -2;
return 0;
}
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_object(const char *cursor, const char **end,
int depth, json_object_t *obj);
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)
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 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)
break;
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);
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);
list_del(pos);
rb_erase(&memb->rb, &obj->root);
__destroy_json_value(&memb->value);
free(memb);
}
}
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;
}
}
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 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;
free(src);
}
static int __set_json_value(int type, va_list ap, json_value_t *val)
{
switch (type)
{
case 0:
__move_json_value(va_arg(ap, json_value_t *), val);
return 0;
case JSON_VALUE_STRING:
val->value.string = strdup(va_arg(ap, const char *));
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;
}
if (type == JSON_VALUE_STRING && !val->value.string)
return -1;
val->type = type;
return 0;
}
json_value_t *json_value_parse(const char *doc)
{
json_value_t *val;
int ret;
val = (json_value_t *)malloc(sizeof (json_value_t));
if (!val)
return NULL;
while (isspace(*doc))
doc++;
ret = __parse_json_value(doc, &doc, 0, val);
if (ret >= 0)
{
while (isspace(*doc))
doc++;
if (*doc)
{
__destroy_json_value(val);
ret = -2;
}
}
if (ret < 0)
{
free(val);
return NULL;
}
return val;
}
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;
}
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 *prev,
const json_object_t *obj)
{
struct list_head *pos;
json_member_t *memb;
if (prev)
{
memb = list_entry(prev, json_member_t, name);
pos = memb->list.next;
}
else
pos = obj->head.next;
if (pos == &obj->head)
return NULL;
memb = list_entry(pos, json_member_t, list);
return memb->name;
}
const json_value_t *json_object_next_value(const json_value_t *prev,
const json_object_t *obj)
{
struct list_head *pos;
json_member_t *memb;
if (prev)
{
memb = list_entry(prev, json_member_t, value);
pos = memb->list.next;
}
else
pos = obj->head.next;
if (pos == &obj->head)
return NULL;
memb = list_entry(pos, json_member_t, list);
return &memb->value;
}
const json_value_t *json_object_append(json_object_t *obj,
const char *name,
int type, ...)
{
json_member_t *memb;
va_list ap;
int ret;
ret = strlen(name);
memb = (json_member_t *)malloc(offsetof(json_member_t, name) + ret + 1);
if (!memb)
return NULL;
memcpy(memb->name, name, ret + 1);
va_start(ap, type);
ret = __set_json_value(type, ap, &memb->value);
va_end(ap);
if (ret < 0)
{
free(memb);
return NULL;
}
__insert_json_member(memb, obj);
obj->size++;
return &memb->value;
}
int json_array_size(const json_array_t *arr)
{
return arr->size;
}
const json_value_t *json_array_next_value(const json_value_t *prev,
const json_array_t *arr)
{
struct list_head *pos;
json_element_t *elem;
if (prev)
{
elem = list_entry(prev, json_element_t, value);
pos = elem->list.next;
}
else
pos = arr->head.next;
if (pos == &arr->head)
return NULL;
elem = list_entry(pos, json_element_t, list);
return &elem->value;
}
const json_value_t *json_array_append(json_array_t *arr,
int type, ...)
{
json_element_t *elem;
va_list ap;
int ret;
elem = (json_element_t *)malloc(sizeof (json_element_t));
if (!elem)
return NULL;
va_start(ap, type);
ret = __set_json_value(type, ap, &elem->value);
va_end(ap);
if (ret < 0)
{
free(elem);
return NULL;
}
list_add_tail(&elem->list, &arr->head);
arr->size++;
return &elem->value;
}
+81
View File
@@ -0,0 +1,81 @@
/*
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)
*/
#ifndef _JSON_PARSER_H_
#define _JSON_PARSER_H_
#include <stddef.h>
#define JSON_VALUE_STRING 1
#define JSON_VALUE_NUMBER 2
#define JSON_VALUE_OBJECT 3
#define JSON_VALUE_ARRAY 4
#define JSON_VALUE_TRUE 5
#define JSON_VALUE_FALSE 6
#define JSON_VALUE_NULL 7
typedef struct __json_value json_value_t;
typedef struct __json_object json_object_t;
typedef struct __json_array json_array_t;
#ifdef __cplusplus
extern "C"
{
#endif
json_value_t *json_value_parse(const char *doc);
json_value_t *json_value_create(int type, ...);
void json_value_destroy(json_value_t *val);
int json_value_type(const json_value_t *val);
const char *json_value_string(const json_value_t *val);
double json_value_number(const json_value_t *val);
json_object_t *json_value_object(const json_value_t *val);
json_array_t *json_value_array(const json_value_t *val);
const json_value_t *json_object_find(const char *name,
const json_object_t *obj);
int json_object_size(const json_object_t *obj);
const char *json_object_next_name(const char *prev,
const json_object_t *obj);
const json_value_t *json_object_next_value(const json_value_t *prev,
const json_object_t *obj);
const json_value_t *json_object_append(json_object_t *obj,
const char *name,
int type, ...);
int json_array_size(const json_array_t *arr);
const json_value_t *json_array_next_value(const json_value_t *val,
const json_array_t *arr);
const json_value_t *json_array_append(json_array_t *arry,
int type, ...);
#ifdef __cplusplus
}
#endif
#define json_object_for_each(name, val, obj) \
for (name = NULL, val = NULL; \
name = json_object_next_name(name, obj), \
val = json_object_next_value(val, obj), val; )
#define json_array_for_each(val, arr) \
for (val = NULL; val = json_array_next_value(val, arr), val; )
#endif