From 85c308c7aa75a450a11007dbadac66db56495b62 Mon Sep 17 00:00:00 2001 From: lixianjing Date: Sun, 15 Sep 2019 17:57:19 +0800 Subject: [PATCH] add ubjson parser --- docs/changes.md | 7 ++ src/ubjson/ubjson_parser.c | 160 ++++++++++++++++++++++++++++++++++++ src/ubjson/ubjson_parser.h | 34 ++++++++ src/ubjson/ubjson_reader.c | 1 + src/ubjson/ubjson_writer.c | 2 +- src/ubjson/ubjson_writer.h | 2 +- tests/ubjson_parser_test.cc | 63 ++++++++++++++ tests/ubjson_reader_test.cc | 2 +- tests/ubjson_writer_test.cc | 2 +- 9 files changed, 269 insertions(+), 4 deletions(-) create mode 100644 src/ubjson/ubjson_parser.c create mode 100644 src/ubjson/ubjson_parser.h create mode 100644 tests/ubjson_parser_test.cc diff --git a/docs/changes.md b/docs/changes.md index 7ef3baa2d..8b21d1570 100644 --- a/docs/changes.md +++ b/docs/changes.md @@ -1,5 +1,12 @@ # 最新动态 +* 2019/09/15 + * ubjson reader + * ubjson parser + +* 2019/09/14 + * ubjson writer + * 2019/09/13 * 窗口切换到后台时自动失去焦点。 diff --git a/src/ubjson/ubjson_parser.c b/src/ubjson/ubjson_parser.c new file mode 100644 index 000000000..3f613d4ad --- /dev/null +++ b/src/ubjson/ubjson_parser.c @@ -0,0 +1,160 @@ +/** + * File: ubjson_parser.c + * Author: AWTK Develop Team + * Brief: ubjson parser + * + * Copyright (c) 2019 - 2019 Guangzhou ZHIYUAN Electronics Co.,Ltd. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * License file for more details. + * + */ + +/** + * History: + * ================================================================ + * 2019-09-15 Li XianJing created + * + */ + +#include "tkc/buffer.h" +#include "ubjson/ubjson_parser.h" + +typedef enum _parse_state_t { + STATE_NONE, + STATE_KEY, + STATE_VALUE, + STATE_ARRAY, +} parse_state_t; + +typedef struct _ubjson_parser_t { + void* ctx; + str_t temp; + rbuffer_t rb; + object_t* obj; + object_t* root; + parse_state_t state; + ubjson_reader_t reader; +} ubjson_parser_t; + +#define PROP_PARENT "__parent__" + +static ubjson_parser_t* ubjson_parser_init(ubjson_parser_t* parser, void* data, uint32_t size) { + str_t* temp = &(parser->temp); + rbuffer_t* rb = &(parser->rb); + ubjson_reader_t* reader = &(parser->reader); + + str_init(temp, 64); + rbuffer_init(rb, data, size); + parser->state = STATE_NONE; + ubjson_reader_init(reader, (ubjson_read_callback_t)rbuffer_read_binary, rb); + + return parser; +} + +static ret_t ubjson_parser_deinit(ubjson_parser_t* parser) { + str_t* temp = &(parser->temp); + ubjson_reader_t* reader = &(parser->reader); + + str_reset(temp); + ubjson_reader_reset(reader); + + return RET_OK; +} + +static ret_t ubjson_parser_read(ubjson_parser_t* parser, value_t* v) { + ubjson_reader_t* reader = &(parser->reader); + + return ubjson_reader_read(reader, v); +} + +static ret_t ubjson_parser_on_value(ubjson_parser_t* parser, value_t* v) { + str_t* str = &(parser->temp); + + switch (parser->state) { + case STATE_NONE: { + if (v->type == VALUE_TYPE_TOKEN && value_token(v) == UBJSON_MARKER_OBJECT_BEGIN) { + parser->obj = object_default_create(); + return_value_if_fail(parser->obj != NULL, RET_OOM); + + parser->state = STATE_KEY; + parser->root = parser->obj; + } else { + assert(!"invalid format"); + return RET_BAD_PARAMS; + } + break; + } + case STATE_KEY: { + if (v->type == VALUE_TYPE_TOKEN) { + if (value_token(v) == UBJSON_MARKER_OBJECT_END) { + object_t* parent = (object_t*)object_get_prop_pointer(parser->obj, PROP_PARENT); + parser->obj = parent; + } else { + assert(!"invalid format"); + return RET_BAD_PARAMS; + } + } else if (v->type == VALUE_TYPE_STRING) { + return_value_if_fail(str_set(str, value_str(v)) == RET_OK, RET_OOM); + parser->state = STATE_VALUE; + } else { + assert(!"invalid format"); + return RET_BAD_PARAMS; + } + break; + } + case STATE_VALUE: { + if (v->type == VALUE_TYPE_TOKEN) { + if (value_token(v) == UBJSON_MARKER_OBJECT_BEGIN) { + object_t* obj = object_default_create(); + return_value_if_fail(obj != NULL, RET_OOM); + + parser->state = STATE_KEY; + object_set_prop_object(parser->obj, str->str, obj); + object_set_prop_pointer(obj, PROP_PARENT, parser->obj); + parser->obj = obj; + + object_unref(obj); + } else { + assert(!"invalid format"); + return RET_BAD_PARAMS; + } + } else { + parser->state = STATE_KEY; + object_set_prop(parser->obj, str->str, v); + } + break; + } + default: + break; + } + + return RET_OK; +} + +ret_t ubjson_do_parse(ubjson_parser_t* parser) { + value_t v; + + while (TRUE) { + if (ubjson_parser_read(parser, &v) != RET_OK) { + break; + } + + ubjson_parser_on_value(parser, &v); + } + + return RET_OK; +} + +object_t* ubjson_parse(void* data, uint32_t size) { + ubjson_parser_t parser; + return_value_if_fail(data != NULL && size > 0, NULL); + + ubjson_parser_init(&parser, data, size); + ubjson_do_parse(&parser); + ubjson_parser_deinit(&parser); + + return parser.root; +} diff --git a/src/ubjson/ubjson_parser.h b/src/ubjson/ubjson_parser.h new file mode 100644 index 000000000..76be12f0d --- /dev/null +++ b/src/ubjson/ubjson_parser.h @@ -0,0 +1,34 @@ +/** + * File: ubjson_parser.h + * Author: AWTK Develop Team + * Brief: ubjson parser + * + * Copyright (c) 2019 - 2019 Guangzhou ZHIYUAN Electronics Co.,Ltd. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * License file for more details. + * + */ + +/** + * History: + * ================================================================ + * 2019-09-15 Li XianJing created + * + */ + +#ifndef TK_UBJSON_PARSER_H +#define TK_UBJSON_PARSER_H + +#include "tkc/object_default.h" +#include "ubjson/ubjson_reader.h" + +BEGIN_C_DECLS + +object_t* ubjson_parse(void* data, uint32_t size); + +END_C_DECLS + +#endif /*TK_UBJSON_PARSER_H*/ diff --git a/src/ubjson/ubjson_reader.c b/src/ubjson/ubjson_reader.c index 76f9cca7e..10fbb64f6 100644 --- a/src/ubjson/ubjson_reader.c +++ b/src/ubjson/ubjson_reader.c @@ -137,6 +137,7 @@ ret_t ubjson_reader_read(ubjson_reader_t* reader, value_t* v) { return_value_if_fail(str_extend(str, len + 1) == RET_OK, RET_OOM); return_value_if_fail(ubjson_reader_read_data(reader, str->str, len) == RET_OK, RET_FAIL); + str->str[len] = '\0'; value_set_str(v, str->str); break; } diff --git a/src/ubjson/ubjson_writer.c b/src/ubjson/ubjson_writer.c index 2d704ec28..4963ff704 100644 --- a/src/ubjson/ubjson_writer.c +++ b/src/ubjson/ubjson_writer.c @@ -139,7 +139,7 @@ ret_t ubjson_writer_write_char(ubjson_writer_t* writer, char value) { return RET_OK; } -ret_t ubjson_writer_write_string(ubjson_writer_t* writer, const char* value) { +ret_t ubjson_writer_write_str(ubjson_writer_t* writer, const char* value) { uint32_t len = 0; return_value_if_fail(writer != NULL && value != NULL, RET_BAD_PARAMS); return_value_if_fail(ubjson_writer_write_marker(writer, UBJSON_MARKER_STRING) == RET_OK, RET_OOM); diff --git a/src/ubjson/ubjson_writer.h b/src/ubjson/ubjson_writer.h index 6af54bfd7..586fd325f 100644 --- a/src/ubjson/ubjson_writer.h +++ b/src/ubjson/ubjson_writer.h @@ -52,7 +52,7 @@ ret_t ubjson_writer_write_int64(ubjson_writer_t* writer, int64_t value); ret_t ubjson_writer_write_float32(ubjson_writer_t* writer, float value); ret_t ubjson_writer_write_float64(ubjson_writer_t* writer, double value); ret_t ubjson_writer_write_char(ubjson_writer_t* writer, char value); -ret_t ubjson_writer_write_string(ubjson_writer_t* writer, const char* value); +ret_t ubjson_writer_write_str(ubjson_writer_t* writer, const char* value); ret_t ubjson_writer_write_array_begin(ubjson_writer_t* writer); ret_t ubjson_writer_write_array_end(ubjson_writer_t* writer); ret_t ubjson_writer_write_object_begin(ubjson_writer_t* writer); diff --git a/tests/ubjson_parser_test.cc b/tests/ubjson_parser_test.cc new file mode 100644 index 000000000..b51d1a52c --- /dev/null +++ b/tests/ubjson_parser_test.cc @@ -0,0 +1,63 @@ +#include "gtest/gtest.h" +#include "tkc/buffer.h" +#include "ubjson/ubjson_writer.h" +#include "ubjson/ubjson_parser.h" + +TEST(UBJsonWriter, basic) { + uint8_t buff[256]; + wbuffer_t wb; + ubjson_writer_t ub; + object_t* obj = NULL; + wbuffer_init(&wb, buff, sizeof(buff)); + ubjson_writer_init(&ub, (ubjson_write_callback_t)wbuffer_write_binary, &wb); + + ASSERT_EQ(ubjson_writer_write_object_begin(&ub), RET_OK); + ASSERT_EQ(ubjson_writer_write_str(&ub, "name"), RET_OK); + ASSERT_EQ(ubjson_writer_write_str(&ub, "aaa"), RET_OK); + ASSERT_EQ(ubjson_writer_write_str(&ub, "age"), RET_OK); + ASSERT_EQ(ubjson_writer_write_int32(&ub, 100), RET_OK); + ASSERT_EQ(ubjson_writer_write_object_end(&ub), RET_OK); + + obj = ubjson_parse(wb.data, wb.cursor); + ASSERT_STREQ(object_get_prop_str(obj, "name"), "aaa"); + ASSERT_EQ(object_get_prop_int(obj, "age", 0), 100); + + object_unref(obj); +} + +TEST(UBJsonWriter, embedded) { + uint8_t buff[256]; + wbuffer_t wb; + ubjson_writer_t ub; + object_t* obj = NULL; + object_t* addr = NULL; + wbuffer_init(&wb, buff, sizeof(buff)); + ubjson_writer_init(&ub, (ubjson_write_callback_t)wbuffer_write_binary, &wb); + + ASSERT_EQ(ubjson_writer_write_object_begin(&ub), RET_OK); + ASSERT_EQ(ubjson_writer_write_str(&ub, "name"), RET_OK); + ASSERT_EQ(ubjson_writer_write_str(&ub, "aaa"), RET_OK); + ASSERT_EQ(ubjson_writer_write_str(&ub, "age"), RET_OK); + ASSERT_EQ(ubjson_writer_write_int32(&ub, 100), RET_OK); + + ASSERT_EQ(ubjson_writer_write_str(&ub, "addr"), RET_OK); + ASSERT_EQ(ubjson_writer_write_object_begin(&ub), RET_OK); + ASSERT_EQ(ubjson_writer_write_str(&ub, "city"), RET_OK); + ASSERT_EQ(ubjson_writer_write_str(&ub, "shenzhen"), RET_OK); + ASSERT_EQ(ubjson_writer_write_str(&ub, "post"), RET_OK); + ASSERT_EQ(ubjson_writer_write_str(&ub, "518000"), RET_OK); + ASSERT_EQ(ubjson_writer_write_object_end(&ub), RET_OK); + + ASSERT_EQ(ubjson_writer_write_object_end(&ub), RET_OK); + + obj = ubjson_parse(wb.data, wb.cursor); + ASSERT_STREQ(object_get_prop_str(obj, "name"), "aaa"); + ASSERT_EQ(object_get_prop_int(obj, "age", 0), 100); + addr = object_get_prop_object(obj, "addr"); + ASSERT_EQ(addr != NULL, true); + + ASSERT_STREQ(object_get_prop_str(addr, "city"), "shenzhen"); + ASSERT_STREQ(object_get_prop_str(addr, "post"), "518000"); + + object_unref(obj); +} diff --git a/tests/ubjson_reader_test.cc b/tests/ubjson_reader_test.cc index 3846a9ee0..70d3c7080 100644 --- a/tests/ubjson_reader_test.cc +++ b/tests/ubjson_reader_test.cc @@ -180,7 +180,7 @@ TEST(UBJsonReader, double) { TEST(UBJsonReader, string) { PREPARE_TEST(); - ASSERT_EQ(ubjson_writer_write_string(&ub, "a"), RET_OK); + ASSERT_EQ(ubjson_writer_write_str(&ub, "a"), RET_OK); rb.capacity = wb.cursor; ASSERT_EQ(ubjson_reader_read(&ur, &v), RET_OK); diff --git a/tests/ubjson_writer_test.cc b/tests/ubjson_writer_test.cc index 46923110b..3ac651233 100644 --- a/tests/ubjson_writer_test.cc +++ b/tests/ubjson_writer_test.cc @@ -184,7 +184,7 @@ TEST(UBJsonWriter, string) { wbuffer_init(&wb, buff, sizeof(buff)); ubjson_writer_init(&ub, (ubjson_write_callback_t)wbuffer_write_binary, &wb); - ASSERT_EQ(ubjson_writer_write_string(&ub, "a"), RET_OK); + ASSERT_EQ(ubjson_writer_write_str(&ub, "a"), RET_OK); ASSERT_EQ(buff[0], UBJSON_MARKER_STRING); ASSERT_EQ(buff[1], UBJSON_MARKER_INT8);