-
Notifications
You must be signed in to change notification settings - Fork 0
/
lxml.c
332 lines (318 loc) · 11.6 KB
/
lxml.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
#define LUA_LIB
#include <core.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
// 设置版本号
#define lua_setlversion(L, k, v) ({lua_pushliteral(L, k); lua_pushliteral(L, v); lua_rawset(L, -3);})
// 确保栈上有4个元素,第四个元素必然是`LUA_TTABLE`类型
#define lua_pushtable(L, name) ({ lua_createtable(L, 16, 16); lua_pushstring(L, (name)); lua_pushvalue(L, -2); lua_rawset(L, -4);})
static int xml_array_encode(lua_State *L, xmlNodePtr node, const char* key);
static int xml_table_encode(lua_State *L, xmlNodePtr node);
static int xml_array_encode(lua_State *L, xmlNodePtr node, const char* key) {
lua_pushnil(L);
if (lua_next(L, -2)) {
if (lua_type(L, -2) != LUA_TNUMBER) {
lua_pop(L, 2);
return xml_table_encode(L, node);
}
lua_pop(L, 2);
lua_pushnil(L);
}
xmlNodePtr son;
size_t bsize;
while (lua_next(L, -2)) {
// 检查Key的类型是否为可序列化类型
if (lua_type(L, -2) != LUA_TNUMBER && lua_type(L, -2) != LUA_TSTRING) {
xmlFreeDoc(node->doc);
return luaL_error(L, "[XML ERROR]: Invalid table key, required (number or string).");
}
// 根据VALUE类型编码
switch (lua_type(L, -1)){
case LUA_TSTRING: //String类型
son = xmlNewNode(NULL, BAD_CAST(key));
xmlAddChild(node, son);
xmlAddChild(son, xmlNewCDataBlock(son->doc, (const xmlChar *)luaL_checklstring(L, -1, &bsize), bsize));
break;
case LUA_TNUMBER: //Number类型
xmlNewTextChild(node, NULL, BAD_CAST(key), BAD_CAST(lua_tostring(L, -1)));
break;
case LUA_TBOOLEAN: //Boolean类型
xmlNewTextChild(node, NULL, BAD_CAST(key), lua_toboolean(L, -1) == 0 ? BAD_CAST("false") : BAD_CAST("true"));
break;
case LUA_TUSERDATA: case LUA_TLIGHTUSERDATA: //指针类型
xmlNewTextChild(node, NULL, BAD_CAST(key), BAD_CAST("NULL"));
break;
case LUA_TTABLE: //LUA_TTABLE类型
lua_pushnil(L);
//如果是一张空表, 则直接返回空节点即可;
if (!lua_next(L, -2)) {
xmlAddChild(node, xmlNewNode(NULL, BAD_CAST(key)));
break;
}
// 如果是一个字典表
if (lua_type(L, -2) == LUA_TSTRING) {
lua_pop(L, 2); lua_checkstack(L, 4); // 防止调用栈过深导致的错误;
son = xmlNewNode(NULL, BAD_CAST(key));
xmlAddChild(node, son);
xml_table_encode(L, son);
// 如果是个数组表
} else if (lua_type(L, -2) == LUA_TNUMBER) {
lua_pop(L, 2); lua_checkstack(L, 4); // 防止调用栈过深导致的错误;
son = xmlNewNode(NULL, BAD_CAST(key));
xmlAddChild(node, son);
xml_array_encode(L, son, "item");
// 其他类型抛出异常.
} else {
luaL_error(L, "Invalid type in lua table key.");
}
break;
default:
xmlFreeDoc(node->doc);
return luaL_error(L, "[XML ERROR]: Invalid table value type, required (`number`/`string`/`boolean`/`table`).");
}
lua_pop(L, 1);
}
return 1;
}
static int xml_table_encode(lua_State *L, xmlNodePtr node) {
lua_pushnil(L);
if (lua_next(L, -2)) {
if (lua_type(L, -2) == LUA_TNUMBER) {
lua_pop(L, 2);
return xml_array_encode(L, node, "XML");
}
lua_pop(L, 2);
lua_pushnil(L);
}
xmlNodePtr son;
size_t bsize;
while (lua_next(L, -2)) {
// 检查Key的类型是否为可序列化类型
if (lua_type(L, -2) != LUA_TNUMBER && lua_type(L, -2) != LUA_TSTRING) {
xmlFreeDoc(node->doc);
return luaL_error(L, "[XML ERROR]: Invalid table key, required (number or string).");
}
// 根据VALUE类型编码
switch (lua_type(L, -1)){
case LUA_TSTRING: //String类型(始终为CDATA)
son = xmlNewNode(NULL, BAD_CAST(lua_tostring(L, -2)));
xmlAddChild(node, son);
xmlAddChild(son, xmlNewCDataBlock(son->doc, BAD_CAST(luaL_checklstring(L, -1, &bsize)), bsize));
break;
case LUA_TNUMBER: //Number类型
xmlNewTextChild(node, NULL, BAD_CAST(lua_tostring(L, -2)), BAD_CAST(lua_tostring(L, -1)));
break;
case LUA_TBOOLEAN: //Boolean类型
xmlNewTextChild(node, NULL, BAD_CAST(lua_tostring(L, -2)), lua_toboolean(L, -1) == 0 ? BAD_CAST("false") : BAD_CAST("true"));
break;
case LUA_TUSERDATA: case LUA_TLIGHTUSERDATA: //指针类型
xmlNewTextChild(node, NULL, BAD_CAST(lua_tostring(L, -2)), BAD_CAST("NULL"));
break;
case LUA_TTABLE: //LUA_TTABLE类型
lua_pushnil(L);
// 如果是一张空表, 则直接返回空节点即可;
if (!lua_next(L, -2)) {
xmlAddChild(node, xmlNewNode(NULL, BAD_CAST(lua_tostring(L, -2))));
break;
}
// 如果是一个字典表
if (lua_type(L, -2) == LUA_TSTRING) {
lua_pop(L, 2); lua_checkstack(L, 4); // 防止调用栈过深导致的错误;
son = xmlNewNode(NULL, BAD_CAST(lua_tostring(L, -2)));
xmlAddChild(node, son);
xml_table_encode(L, son);
// 如果是个数组表
} else if (lua_type(L, -2) == LUA_TNUMBER) {
lua_pop(L, 2); lua_checkstack(L, 4); // 防止调用栈过深导致的错误;
xml_array_encode(L, node, lua_tostring(L, -2));
// 其他类型抛出异常.
} else {
xmlFreeDoc(node->doc);
luaL_error(L, "Invalid type in lua table key.");
}
break;
default:
xmlFreeDoc(node->doc);
return luaL_error(L, "[XML ERROR]: Invalid table value type, required (`number`/`string`/`boolean`/`table`).");
}
lua_pop(L, 1);
}
return 1;
}
// 编码
static int lencode(lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
// 检查是否有指定表名
size_t len;
const char *tn = lua_tolstring(L, 2, &len);
if (!tn || len < 1){
len = 3; tn = "xml";
}
// 解决GC引用的潜在问题
char tabname[len + 1];
memset(tabname, 0x0, len + 1);
memcpy(tabname, tn, len);
// 检查是否取消格式化
int format = lua_toboolean(L, 3);
if (!format) format = 1; else format = 0;
lua_settop(L, 1);
lua_pushnil(L);
// 如果是空表直接给出空表记录
if(lua_next(L, -2) == 0) {
lua_pushfstring(L, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<%s></%s>", tabname, tabname);
return 1;
}
lua_settop(L, 1);
// 创建文档对象与根节点
xmlDocPtr doc = xmlNewDoc(BAD_CAST("1.0"));
xmlNodePtr root = xmlNewNode(NULL, BAD_CAST(tabname));
xmlDocSetRootElement(doc, root);
// LOG("DEBUG", "开始");
// 开始编码
xml_table_encode(L, root);
// LOG("DEBUG", "结束");
// 编码结束
int xsize = 0;;
xmlChar *xmlbuff = NULL;
xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &xsize, "UTF-8", format);
lua_pushlstring(L, (const char *)xmlbuff, xsize);
// 释放XML结构申请的所有内存
xmlFree(xmlbuff); xmlFreeDoc(doc);
return 1;
}
static inline void xml_node_dump(lua_State *L, xmlNodePtr node) {
xmlNodePtr cur_node = NULL;
for (cur_node = node; cur_node; cur_node = cur_node->next) {
if (cur_node->type == XML_ELEMENT_NODE) {
// 如果没有子节点
if (!cur_node->children) {
if (cur_node->next && xmlStrEqual(cur_node->next->name, cur_node->name)) {
int index = 1;
xmlNodePtr e = NULL;
xmlNodePtr p = cur_node;
const xmlChar *name = p->name;
// printf("node->name = [%s]\n", name);
lua_pushtable(L, (const char *)cur_node->name);
for (; p && xmlStrEqual(p->name, name); p = p->next) {
lua_newtable(L);
lua_rawseti(L, -2, index++);
e = p;
}
cur_node = e;
lua_pop(L, 1);
} else {
lua_pushstring(L, (const char *)cur_node->name);
lua_newtable(L); lua_rawset(L, -3);
}
return ;
}
// 如果有字节点但是子节点也是`数组`或者`字典`
if (cur_node->children->type == XML_ELEMENT_NODE){
if (cur_node->next && xmlStrEqual(cur_node->next->name, cur_node->name)) {
int index = 1;
xmlNodePtr e = NULL;
xmlNodePtr p = cur_node;
const xmlChar *name = p->name;
// printf("node->name = [%s]\n", name);
lua_pushtable(L, (const char *)cur_node->name);
for (; p && xmlStrEqual(p->name, name); p = p->next) {
lua_newtable(L);
xml_node_dump(L, p->children);
lua_rawseti(L, -2, index++);
e = p;
}
cur_node = e;
lua_pop(L, 1);
} else {
lua_pushtable(L, (const char *)cur_node->name);
xml_node_dump(L, cur_node->children);
lua_pop(L, 1);
}
continue;
}
// printf("not.\n");
}
// 如果子节点类型数TEXT或者CDATA需要检查是`数组`表示法或是`字典`表示
// 规则是:多个同名节点为`数组`节点, 只有一个数据节点或多个不同名节点则为`字典`节点
if (cur_node->next && xmlStrEqual(cur_node->next->name, cur_node->name)) {
// printf("开始\n");
int index = 1;
xmlNodePtr e = NULL;
xmlNodePtr p = cur_node;
const xmlChar *name = p->name;
lua_pushtable(L, (const char *)p->name);
for (; p && xmlStrEqual(p->name, name); p = p->next) {
// printf("array [%s] = [%s]\n", p->name, xmlNodeGetContent(p->children));
lua_pushstring(L, (const char *)xmlNodeGetContent(p->children));
lua_rawseti(L, -2, index++);
e = p;
}
cur_node = e;
lua_pop(L, 1);
// printf("结束\n");
} else {
// printf("table [%s] = [%s]\n", cur_node->name, xmlNodeGetContent(cur_node->children));
lua_pushstring(L, (const char *)cur_node->name);
lua_pushstring(L, (const char *)xmlNodeGetContent(cur_node));
lua_rawset(L, -3);
}
}
}
static inline int xml_decoder(lua_State *L, xmlDocPtr doc) {
// 文档对象
if (!doc) {
lua_pushnil(L);
lua_pushstring(L, "[XML ERROR]: Invalid string buffer.");
return 2;
}
// 根节点
xmlNodePtr root = xmlDocGetRootElement(doc);
if (!root) {
xmlFreeDoc(doc);
lua_pushnil(L);
lua_pushstring(L, "[XML ERROR]: can't find root node element.");
return 2;
}
lua_settop(L, 0);
// 构建根节点
lua_createtable(L, 0, 1);
lua_pushtable(L, (const char *)root->name);
// 构建根节点
xml_node_dump(L, root->children);
lua_settop(L, 1);
// 清理内存
xmlFreeDoc(doc);
return 1;
}
// 解码
static int ldecode(lua_State *L) {
size_t xlen;
const char *xmlbuffer = luaL_checklstring(L, 1, &xlen);
if (!xmlbuffer || xlen < 7)
return luaL_error(L, "[XML ERROR]: Invalid string buffer.");
// 消除无用的空格与换行
int i;
for (i = 0; i < xlen; i++)
if (xmlbuffer[i] == '<')
break;
if (xlen < 7)
return 0;
return xml_decoder(L, xmlReadMemory(xmlbuffer + i, xlen - i, NULL, NULL, XML_PARSE_HUGE));
}
LUAMOD_API int luaopen_lxml(lua_State *L){
luaL_checkversion(L);
// 去除空白符
xmlKeepBlanksDefault(0);
// 注册方法
luaL_Reg xml_libs[] = {
{"encode", lencode},
{"decode", ldecode},
{NULL, NULL}
};
luaL_newlib(L, xml_libs);
// lxml 版本
lua_setlversion(L, "__VERSION__", "0.1");
// libxml2 版本
lua_setlversion(L, "__XML_VERSION__", LIBXML_DOTTED_VERSION);
return 1;
}