CARPLAY版本整理

This commit is contained in:
2025-01-21 16:49:37 +08:00
commit f0fb64e4e6
26542 changed files with 13719676 additions and 0 deletions

View File

@ -0,0 +1,2 @@
# xml 解析器

View File

@ -0,0 +1,103 @@
/**
* File: xml_builder.c
* Author: AWTK Develop Team
* Brief: xml builder interface
*
* Copyright (c) 2018 - 2021 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:
* ================================================================
* 2018-01-19 Li XianJing <xianjimli@hotmail.com> adapted from ftk.
*
*/
#include "xml/xml_builder.h"
void xml_builder_on_start(XmlBuilder* builder, const char* tag, const char** attrs) {
return_if_fail(builder != NULL && builder->on_start != NULL);
builder->on_start(builder, tag, attrs);
return;
}
void xml_builder_on_end(XmlBuilder* builder, const char* tag) {
return_if_fail(builder != NULL);
if (builder->on_end != NULL) {
builder->on_end(builder, tag);
}
return;
}
void xml_builder_on_text(XmlBuilder* builder, const char* text, size_t length) {
return_if_fail(builder != NULL);
if (builder->on_text != NULL) {
builder->on_text(builder, text, length);
}
return;
}
void xml_builder_on_comment(XmlBuilder* builder, const char* text, size_t length) {
return_if_fail(builder != NULL);
if (builder->on_comment != NULL) {
builder->on_comment(builder, text, length);
}
return;
}
void xml_builder_on_pi(XmlBuilder* builder, const char* tag, const char** attrs) {
return_if_fail(builder != NULL);
if (builder->on_pi != NULL) {
builder->on_pi(builder, tag, attrs);
}
return;
}
void xml_builder_on_error(XmlBuilder* builder, int line, int col, const char* message) {
return_if_fail(builder != NULL);
if (builder->on_error != NULL) {
builder->on_error(builder, line, col, message);
} else {
log_debug("%d:%d %s\n", line, col, message);
}
return;
}
void xml_builder_destroy(XmlBuilder* builder) {
if (builder != NULL && builder->destroy != NULL) {
builder->destroy(builder);
}
return;
}
const char* xml_builder_get_attr(const char** attrs, const char* attr) {
uint32_t i = 0;
return_value_if_fail(attrs != NULL && attr != NULL, NULL);
while (attrs[i]) {
const char* name = attrs[i];
const char* value = attrs[i + 1];
if (strcmp(name, attr) == 0) {
return value;
}
i += 2;
}
return NULL;
}

View File

@ -0,0 +1,159 @@
/**
* File: xml_builder.h
* Author: AWTK Develop Team
* Brief: xml builder interface
*
* Copyright (c) 2018 - 2021 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:
* ================================================================
* 2018-01-19 Li XianJing <xianjimli@hotmail.com> adapted from ftk.
*
*/
#include "tkc/types_def.h"
#ifndef XML_BUILDER_H
#define XML_BUILDER_H
BEGIN_C_DECLS
struct _XmlBuilder;
typedef struct _XmlBuilder XmlBuilder;
typedef void (*XmlBuilderOnStartFunc)(XmlBuilder* builder, const char* tag, const char** attrs);
typedef void (*XmlBuilderOnEndFunc)(XmlBuilder* builder, const char* tag);
typedef void (*XmlBuilderOnTextFunc)(XmlBuilder* builder, const char* text, size_t length);
typedef void (*XmlBuilderOnCommentFunc)(XmlBuilder* builder, const char* text, size_t length);
typedef void (*XmlBuilderOnPiFunc)(XmlBuilder* builder, const char* tag, const char** attrs);
typedef void (*XmlBuilderOnErrorFunc)(XmlBuilder* builder, int line, int col, const char* message);
typedef void (*XmlBuilderDestroyFunc)(XmlBuilder* builder);
/**
* @class xml_builder_t
* xml builder interface
*
*/
struct _XmlBuilder {
XmlBuilderOnStartFunc on_start;
XmlBuilderOnEndFunc on_end;
XmlBuilderOnTextFunc on_text;
XmlBuilderOnCommentFunc on_comment;
XmlBuilderOnPiFunc on_pi;
XmlBuilderOnErrorFunc on_error;
XmlBuilderDestroyFunc destroy;
};
/**
* @method xml_builder_on_start
* 解析到tag开始时调用本函数。
*
* @param {XmlBuilder*} builder builder对象。
* @param {const char*} tag tag名称。
* @param {const char**} attrs 属性列表。
*
* @return {void} 返回无。
*
*/
void xml_builder_on_start(XmlBuilder* builder, const char* tag, const char** attrs);
/**
* @method xml_builder_on_end
* 解析到tag结束时调用本函数。
*
* @param {XmlBuilder*} builder builder对象。
* @param {const char*} tag tag名称。
*
* @return {void} 返回无。
*
*/
void xml_builder_on_end(XmlBuilder* builder, const char* tag);
/**
* @method xml_builder_on_text
* 解析到文本时调用本函数。
*
* @param {XmlBuilder*} builder builder对象。
* @param {const char*} text 文本。
* @param {size_t} length 文本长度。
*
* @return {void} 返回无。
*
*/
void xml_builder_on_text(XmlBuilder* builder, const char* text, size_t length);
/**
* @method xml_builder_on_comment
* 解析到注释时调用本函数。
*
* @param {XmlBuilder*} builder builder对象。
* @param {const char*} text 注释。
* @param {size_t} length 注释长度。
*
* @return {void} 返回无。
*
*/
void xml_builder_on_comment(XmlBuilder* builder, const char* text, size_t length);
/**
* @method xml_builder_on_pi
* 解析到处理指令时调用本函数。
*
* @param {XmlBuilder*} builder builder对象。
* @param {const char*} tag tag名称。
* @param {const char**} attrs 属性列表。
*
* @return {void} 返回无。
*
*/
void xml_builder_on_pi(XmlBuilder* builder, const char* tag, const char** attrs);
/**
* @method xml_builder_on_error
* 解析遇到错误时调用本函数。
*
* @param {XmlBuilder*} builder builder对象。
* @param {int} line 出现错误的行。
* @param {int} col 出现错误的列。
* @param {const char*} message 错误信息。
*
* @return {void} 返回无。
*
*/
void xml_builder_on_error(XmlBuilder* builder, int line, int col, const char* message);
/**
* @method xml_builder_destroy
* 销毁builder对象。
*
* @param {XmlBuilder*} builder builder对象。
*
* @return {void} 返回无。
*
*/
void xml_builder_destroy(XmlBuilder* builder);
/**
* @method xml_builder_get_attr
* 获取属性。
* @annotation ["static"]
* @param {const char**} attrs 属性列表。
* @param {const char*} attr 属性名。
*
* @return {const char*} 返回属性的值。
*
*/
const char* xml_builder_get_attr(const char** attrs, const char* attr);
END_C_DECLS
#endif /*XML_BUILDER_H*/

View File

@ -0,0 +1,562 @@
/**
* File: xml_parse.c
* Author: AWTK Develop Team
* Brief: simple xml parser
*
* Copyright (c) 2018 - 2021 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:
* ================================================================
* 2018-01-19 Li XianJing <xianjimli@hotmail.com> adapted from ftk.
*
*/
#include "tkc/fs.h"
#include "tkc/mem.h"
#include "tkc/str.h"
#include "tkc/utils.h"
#include "xml/xml_parser.h"
#ifndef tk_isspace
#define tk_isspace(c) (c == ' ' || c == '\t' || c == '\r' || c == '\n')
#endif
#ifndef tk_isalpha
#define tk_isalpha(c) ((c >= 'a' && c <= 'z') || (c >= 'A' || c <= 'Z'))
#endif
struct _XmlParser {
const char* read_ptr;
const char* end;
int attrs_nr;
char* attrs[MAX_ATTR_KEY_VALUE_NR + 1];
char* buffer;
int buffer_used;
int capacity;
XmlBuilder* builder;
str_t text;
bool_t trim_text;
};
static const char* strtrim(char* str);
static void xml_parser_parse_start_tag(XmlParser* parser);
static void xml_parser_parse_end_tag(XmlParser* parser);
static void xml_parser_parse_comment(XmlParser* parser);
static void xml_parser_parse_doctype(XmlParser* parser);
static void xml_parser_parse_pi(XmlParser* parser);
static void xml_parser_parse_text(XmlParser* parser);
static void xml_parser_reset_buffer(XmlParser* parser);
XmlParser* xml_parser_create(void) {
XmlParser* parser = TKMEM_ZALLOC(XmlParser);
return_value_if_fail(parser != NULL, NULL);
parser->trim_text = TRUE;
str_init(&(parser->text), 100);
return parser;
}
void xml_parser_set_trim_text(XmlParser* parser, bool_t trim_text) {
return_if_fail(parser != NULL);
parser->trim_text = trim_text;
return;
}
void xml_parser_set_builder(XmlParser* parser, XmlBuilder* builder) {
return_if_fail(parser != NULL);
parser->builder = builder;
return;
}
void xml_parser_parse(XmlParser* parser, const char* xml, int length) {
int i = 0;
enum _State {
STAT_NONE,
STAT_AFTER_LT,
STAT_START_TAG,
STAT_END_TAG,
STAT_TEXT,
STAT_PRE_COMMENT1,
STAT_PRE_COMMENT2,
STAT_COMMENT,
STAT_DOCTYPE,
STAT_PROCESS_INSTRUCTION,
} state = STAT_NONE;
parser->read_ptr = xml;
parser->end = xml + length;
for (; *parser->read_ptr != '\0' && (parser->read_ptr - xml) < length; parser->read_ptr++, i++) {
char c = parser->read_ptr[0];
switch (state) {
case STAT_NONE: {
if (c == '<') {
xml_parser_reset_buffer(parser);
state = STAT_AFTER_LT;
} else if (!(parser->trim_text) || !tk_isspace(c)) {
state = STAT_TEXT;
}
break;
}
case STAT_AFTER_LT: {
if (c == '?') {
state = STAT_PROCESS_INSTRUCTION;
} else if (c == '/') {
state = STAT_END_TAG;
} else if (c == '!') {
state = STAT_PRE_COMMENT1;
} else if (tk_isalpha(c) || c == '_') {
state = STAT_START_TAG;
} else {
xml_builder_on_error(parser->builder, 0, 0, "unexpected char");
}
break;
}
case STAT_START_TAG: {
xml_parser_parse_start_tag(parser);
state = STAT_NONE;
break;
}
case STAT_END_TAG: {
xml_parser_parse_end_tag(parser);
state = STAT_NONE;
break;
}
case STAT_PROCESS_INSTRUCTION: {
xml_parser_parse_pi(parser);
state = STAT_NONE;
break;
}
case STAT_TEXT: {
xml_parser_parse_text(parser);
state = STAT_NONE;
break;
}
case STAT_PRE_COMMENT1: {
if (c == '-') {
state = STAT_PRE_COMMENT2;
} else if (c == 'D' || c == 'd') {
state = STAT_DOCTYPE;
} else if (c == '[' && tk_str_start_with(parser->read_ptr, "[CDATA[")) {
parser->read_ptr--;
xml_parser_parse_text(parser);
state = STAT_NONE;
} else {
xml_builder_on_error(parser->builder, 0, 0, "expected \'-\'");
}
break;
}
case STAT_PRE_COMMENT2: {
if (c == '-') {
state = STAT_COMMENT;
} else {
xml_builder_on_error(parser->builder, 0, 0, "expected \'-\'");
}
}
case STAT_COMMENT: {
xml_parser_parse_comment(parser);
state = STAT_NONE;
break;
}
case STAT_DOCTYPE: {
xml_parser_parse_doctype(parser);
state = STAT_NONE;
break;
}
default:
break;
}
if (*parser->read_ptr == '\0') {
break;
}
}
return;
}
static void xml_parser_reset_buffer(XmlParser* parser) {
parser->buffer_used = 0;
parser->attrs_nr = 0;
parser->attrs[0] = NULL;
return;
}
static int xml_parser_strdup(XmlParser* parser, const char* start, int length, bool_t trim) {
int offset = -1;
if ((parser->buffer_used + length) >= parser->capacity) {
int new_capacity = parser->capacity + (parser->capacity >> 1) + length + 32;
char* buffer = (char*)TKMEM_REALLOCT(char, parser->buffer, new_capacity);
if (buffer != NULL) {
parser->buffer = buffer;
parser->capacity = new_capacity;
}
}
if ((parser->buffer_used + length) >= parser->capacity) {
return offset;
}
offset = parser->buffer_used;
strncpy(parser->buffer + offset, start, length);
parser->buffer[offset + length] = '\0';
if (trim) {
strtrim(parser->buffer + offset);
}
parser->buffer_used += length + 1;
return offset;
}
static void xml_parser_parse_attrs(XmlParser* parser, char end_char) {
int i = 0;
enum _State {
STAT_PRE_KEY,
STAT_KEY,
STAT_PRE_VALUE,
STAT_VALUE,
STAT_END,
} state = STAT_PRE_KEY;
char value_end = '\"';
const char* start = parser->read_ptr;
parser->attrs_nr = 0;
for (; *parser->read_ptr != '\0' && parser->attrs_nr < MAX_ATTR_KEY_VALUE_NR;
parser->read_ptr++) {
char c = *parser->read_ptr;
switch (state) {
case STAT_PRE_KEY: {
if (c == end_char || c == '>') {
state = STAT_END;
} else if (!tk_isspace(c)) {
state = STAT_KEY;
start = parser->read_ptr;
}
}
case STAT_KEY: {
if (c == '=') {
parser->attrs[parser->attrs_nr++] =
tk_pointer_from_int(xml_parser_strdup(parser, start, parser->read_ptr - start, TRUE));
state = STAT_PRE_VALUE;
}
break;
}
case STAT_PRE_VALUE: {
if (c == '\"' || c == '\'') {
state = STAT_VALUE;
value_end = c;
start = parser->read_ptr + 1;
}
break;
}
case STAT_VALUE: {
if (c == value_end) {
parser->attrs[parser->attrs_nr++] = tk_pointer_from_int(
xml_parser_strdup(parser, start, parser->read_ptr - start, FALSE));
state = STAT_PRE_KEY;
}
}
default:
break;
}
if (state == STAT_END) {
break;
}
}
for (i = 0; i < parser->attrs_nr; i++) {
parser->attrs[i] = parser->buffer + tk_pointer_to_int(parser->attrs[i]);
}
parser->attrs[parser->attrs_nr] = NULL;
return;
}
static void xml_parser_parse_start_tag(XmlParser* parser) {
enum _State {
STAT_NAME,
STAT_ATTR,
STAT_END,
} state = STAT_NAME;
char* tag_name = NULL;
const char* start = parser->read_ptr - 1;
for (; *parser->read_ptr != '\0'; parser->read_ptr++) {
char c = *parser->read_ptr;
switch (state) {
case STAT_NAME: {
if (tk_isspace(c) || c == '>' || c == '/') {
tag_name =
tk_pointer_from_int(xml_parser_strdup(parser, start, parser->read_ptr - start, TRUE));
state = (c != '>' && c != '/') ? STAT_ATTR : STAT_END;
}
break;
}
case STAT_ATTR: {
xml_parser_parse_attrs(parser, '/');
state = STAT_END;
break;
}
default:
break;
}
if (state == STAT_END) {
break;
}
}
tag_name = parser->buffer + tk_pointer_to_int(tag_name);
xml_builder_on_start(parser->builder, tag_name, (const char**)parser->attrs);
if (parser->read_ptr[0] == '/') {
xml_builder_on_end(parser->builder, tag_name);
}
for (; *parser->read_ptr != '>' && *parser->read_ptr != '\0'; parser->read_ptr++)
;
return;
}
static void xml_parser_parse_end_tag(XmlParser* parser) {
char* tag_name = NULL;
const char* start = parser->read_ptr;
for (; *parser->read_ptr != '\0'; parser->read_ptr++) {
if (*parser->read_ptr == '>') {
tag_name = parser->buffer + xml_parser_strdup(parser, start, parser->read_ptr - start, TRUE);
xml_builder_on_end(parser->builder, tag_name);
break;
}
}
return;
}
static void xml_parser_parse_doctype(XmlParser* parser) {
for (; *parser->read_ptr != '\0'; parser->read_ptr++) {
char c = *parser->read_ptr;
if (c == '>') {
break;
}
}
return;
}
static void xml_parser_parse_comment(XmlParser* parser) {
enum _State {
STAT_COMMENT,
STAT_MINUS1,
STAT_MINUS2,
} state = STAT_COMMENT;
const char* start = ++parser->read_ptr;
for (; *parser->read_ptr != '\0'; parser->read_ptr++) {
char c = *parser->read_ptr;
switch (state) {
case STAT_COMMENT: {
if (c == '-') {
state = STAT_MINUS1;
}
break;
}
case STAT_MINUS1: {
if (c == '-') {
state = STAT_MINUS2;
} else {
state = STAT_COMMENT;
}
break;
}
case STAT_MINUS2: {
if (c == '>') {
xml_builder_on_comment(parser->builder, start, parser->read_ptr - start - 2);
return;
}
}
default:
break;
}
}
return;
}
static void xml_parser_parse_pi(XmlParser* parser) {
enum _State { STAT_NAME, STAT_ATTR, STAT_END } state = STAT_NAME;
char* tag_name = NULL;
const char* start = parser->read_ptr;
for (; *parser->read_ptr != '\0'; parser->read_ptr++) {
char c = *parser->read_ptr;
switch (state) {
case STAT_NAME: {
if (tk_isspace(c) || c == '>') {
tag_name =
tk_pointer_from_int(xml_parser_strdup(parser, start, parser->read_ptr - start, TRUE));
state = c != '>' ? STAT_ATTR : STAT_END;
}
break;
}
case STAT_ATTR: {
xml_parser_parse_attrs(parser, '?');
state = STAT_END;
break;
}
default:
break;
}
if (state == STAT_END) {
break;
}
}
tag_name = parser->buffer + tk_pointer_to_int(tag_name);
xml_builder_on_pi(parser->builder, tag_name, (const char**)parser->attrs);
for (; *parser->read_ptr != '>' && *parser->read_ptr != '\0'; parser->read_ptr++)
;
return;
}
static void xml_parser_on_text(XmlParser* parser) {
if (parser->text.size > 0) {
char* start = parser->text.str;
char* end = parser->text.str + parser->text.size - 1;
if (parser->trim_text) {
while (tk_isspace(*start) && *start) {
start++;
}
while (tk_isspace(*end) && end > start) {
*end = '\0';
end--;
}
}
if (end >= start) {
xml_builder_on_text(parser->builder, start, end - start + 1);
} else if (start == parser->text.str + parser->text.size) {
/* support <![CDATA[]]> grammar */
xml_builder_on_text(parser->builder, start, 0);
}
}
}
static void xml_parser_parse_text(XmlParser* parser) {
str_t* s = &(parser->text);
s->size = 0;
s->str[0] = '\0';
parser->read_ptr--;
for (; *parser->read_ptr != '\0'; parser->read_ptr++) {
char c = *parser->read_ptr;
if (c == '<') {
if (tk_str_start_with(parser->read_ptr, "<![CDATA[")) {
const char* start = parser->read_ptr + 9;
parser->read_ptr = strstr(start, "]]>");
if (parser->read_ptr != NULL) {
str_append_with_len(s, start, parser->read_ptr - start);
parser->read_ptr += 2;
} else {
log_warn("invalid cdata\n");
parser->read_ptr = parser->end;
}
} else {
parser->read_ptr--;
break;
}
} else {
str_append_char(s, c);
}
}
xml_parser_on_text(parser);
return;
}
void xml_parser_destroy(XmlParser* parser) {
if (parser != NULL) {
str_reset(&(parser->text));
TKMEM_FREE(parser->buffer);
TKMEM_FREE(parser);
}
return;
}
static const char* strtrim(char* str) {
char* p = NULL;
p = str + strlen(str) - 1;
while (p != str && tk_isspace(*p)) {
*p = '\0';
p--;
}
p = str;
while (*p != '\0' && tk_isspace(*p)) p++;
if (p != str) {
char* s = p;
char* d = str;
while (*s != '\0') {
*d = *s;
d++;
s++;
}
*d = '\0';
}
return str;
}
static char* read_text_file(const char* filename) {
uint32_t size = 0;
return (char*)file_read(filename, &size);
}
void xml_parser_parse_file(XmlParser* parser, const char* filename) {
char* buff = read_text_file(filename);
return_if_fail(buff != NULL);
xml_parser_parse(parser, buff, strlen(buff));
TKMEM_FREE(buff);
return;
}

View File

@ -0,0 +1,116 @@
/**
* File: xml_parse.h
* Author: AWTK Develop Team
* Brief: simple xml parser
*
* Copyright (c) 2018 - 2021 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:
* ================================================================
* 2018-01-19 Li XianJing <xianjimli@hotmail.com> adapted from ftk.
*
*/
#ifndef XML_PARSER_H
#define XML_PARSER_H
#include "xml/xml_builder.h"
BEGIN_C_DECLS
#ifndef TK_XML_MAX_ATTRS
#define TK_XML_MAX_ATTRS 24
#endif /*TK_XML_MAX_ATTRS*/
#define MAX_ATTR_KEY_VALUE_NR (TK_XML_MAX_ATTRS * 2)
/**
* @class XmlParser
* xml解析器
*/
struct _XmlParser;
typedef struct _XmlParser XmlParser;
/**
* @method xml_parser_create
*
* 创建解析器。
*
* @return {XmlParser*} 返回parser对象。
*/
XmlParser* xml_parser_create(void);
/**
* @method xml_parser_set_builder
*
* 设置builder。
*
* @param {XmlParser*} parser parser对象。
* @param {XmlBuilder*} builder builder对象。
*
* @return {void} 返回无。
*/
void xml_parser_set_builder(XmlParser* parser, XmlBuilder* builder);
/**
* @method xml_parser_set_trim_text
*
* 设置是否去掉文本两端的空白字符。
*
* > 默认值为去掉文本两端的空白字符如果不希望去掉调用本函数设置为FALSE。
*
* @param {XmlParser*} parser parser对象。
* @param {bool_t} trim_text 是否去掉文本两端的空白字符。
*
* @return {void} 返回无。
*/
void xml_parser_set_trim_text(XmlParser* parser, bool_t trim_text);
/**
* @method xml_parser_parse
*
* 解析数据。
*
* @param {XmlParser*} parser parser对象。
* @param {const char*} xml 数据。
* @param {int} length 数据长度。
*
* @return {void} 返回无。
*/
void xml_parser_parse(XmlParser* parser, const char* xml, int length);
/**
* @method xml_parser_parse_file
*
* 解析文件。
*
* @param {XmlParser*} parser parser对象。
* @param {const char*} filename 文件名。
*
* @return {void} 返回无。
*/
void xml_parser_parse_file(XmlParser* parser, const char* filename);
/**
* @method xml_parser_destroy
*
* 销毁parser对象。
*
* @param {XmlParser*} parser parser对象。
*
* @return {void} 返回无。
*/
void xml_parser_destroy(XmlParser* parser);
END_C_DECLS
#endif /*XML_PARSER_H*/