选择支持google protobuf的lua库
- 选择了几个相对质量不错的库
- lua-protobuf,A Lua module to work with Google protobuf
- pbc,A protocol buffers library for C
- LuaPbIntf,Binding Protobuf 3 to Lua 5.3
- libprotolua,A Lua module to work with Google protobuf
- 经过对比,pbc相对名气比较大,且已有蛮多人使用于cocos2dx项目,比较成熟;问题是目测不支持proto3,在lua5.1环境下不支持int64(cocos2dx使用的是luajit2.x,对应lua5.1的版本,可以排除LuaPbIntf);整个对比不细说,总的来说pbc>lua-protobuf>libprotolua,所以这边选择pbc集成
pbc集成
添加c源码:在“frameworks\cocos2d-x\external\pbc”目录下添加pbc源码(pbc/src),并在本目录下添加CMakeLists.txt(Android studio默认是使用cmake编译了)
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
35cmake_minimum_required(VERSION 3.6)
set(lib_name pbc)
set(target_name ext_${lib_name})
project(${lib_name})
set(${target_name}_src
alloc.c
array.c
bootstrap.c
context.c
decode.c
map.c
pattern.c
proto.c
register.c
rmessage.c
stringpool.c
varint.c
wmessage.c
)
add_library(${target_name} STATIC
${${target_name}_src}
)
target_include_directories(${target_name} PUBLIC ..)
set_target_properties(${target_name}
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
FOLDER "External"
)修改c源码对应的cmake脚本:在“frameworks\cocos2d-x\external”目录的CMakeList.txt添加以下内容
1
2# 在add_subdirectory(md5)后添加
add_subdirectory(pbc)添加lua绑定源码:在“frameworks\cocos2d-x\cocos\scripting\lua-bindings\manual\pbc”目录添加lua绑定代码(pbc-lua.c、pbc-lua.h、lua_cocos2dx_pbc_manual.cpp、lua_cocos2dx_pbc_manual.h)
pbc-lua.c 为 “pbc/binding/lua/pbc-lua.c”
pbc-lua.h
1 | // pbc-lua.h |
- lua_cocos2dx_pbc_manual.cpp
1 | // lua_cocos2dx_pbc_manual.cpp |
- lua_cocos2dx_pbc_manual.h
1 | # lua_cocos2dx_pbc_manual.h |
- 修改lua绑定源码的cmake脚本:修改“frameworks\cocos2d-x\cocos\scripting\lua-bindings”下的CMakeList.txt
1 | # 在lua_bindings_manual_headers最后面添加manual/pbc/lua_cocos2dx_pbc_manual.h、manual/pbc/pbc-lua.h |
添加lua文件:把“pbc/binding/lua/protobuf.lua,parser.lua”复制到“src\packages\base”目录下
win32和ios下编译:将对应文件加到工程中就行了
android编译:上面已经将CMakelist.txt修改好了,直接编译就行。如果需要使用Android.mk编译,需要修改对应的脚本
pbc测试
- 将“pbc/test/addressbook.proto”拷贝到本地测试目录
生成addressbook.pb,protoc.exe从“https://github.com/protocolbuffers/protobuf/releases”下载最新版本
1
protoc.exe --descriptor_set_out=./addressbook.pb addressbook.proto
测试代码如下
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
54require "packages.base.protobuf"
--addr = io.open("../../src/test/addressbook.pb","rb")
--buffer = addr:read "*a"
--addr:close()
local filePath = cc.FileUtils:getInstance():fullPathForFilename("test/addressbook.pb")
local buffer = read_protobuf_file_c(filePath)
print("---test pbc----------")
print(filePath..buffer)
protobuf.register(buffer)
local t = protobuf.decode("google.protobuf.FileDescriptorSet", buffer)
local proto = t.file[1]
print(proto.name)
print(proto.package)
local message = proto.message_type
for _,v in ipairs(message) do
print(v.name)
for _,v in ipairs(v.field) do
print("\t".. v.name .. " ["..v.number.."] " .. v.label)
end
end
local addressbook = {
name = "Alice",
id = 12345,
phone = {
{ number = "1301234567" },
{ number = "87654321", type = "WORK" },
}
}
local code = protobuf.encode("tutorial.Person", addressbook)
local decode = protobuf.decode("tutorial.Person" , code)
print(decode.name)
print(decode.id)
for _,v in ipairs(decode.phone) do
print("\t"..v.number, v.type)
end
local phonebuf = protobuf.pack("tutorial.Person.PhoneNumber number","87654321")
local buffer = protobuf.pack("tutorial.Person name id phone", "Alice", 123, { phonebuf })
print(protobuf.unpack("tutorial.Person name id phone", buffer))
print("--------------------")
pbc int64 支持
由于lua 51本身不支持int64,所以得先集成一个int64库,github上有蛮多int64库,这次选择了lua-int64,集成方式跟上面类似
- lua 51 不支持int64,赋值的时候使用string进行赋值,如“local id=require(“int64”).new_unsigned(“9223372036854775807”)”
修改lua-int64源码,并导出以下接口函数,修改pbc的时候需要用到着两个接口函数
1 | LUALIB_API void luaL_i64pushobj(lua_State *L, int64_t n) { |
修改pbc-lua.c源码
添加lua-int64头文件
1
读取pb消息修改
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
53static int
_rmessage_int64(lua_State *L) {
struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1);
const char * key = luaL_checkstring(L,2);
int index = luaL_checkinteger(L,3);
/*uint32_t v[2];
v[0] = pbc_rmessage_integer(m, key, index, &v[1]);
lua_pushlstring(L,(const char *)v,sizeof(v));*/
uint32_t hi, low;
low = pbc_rmessage_integer(m, key, index, &hi);
uint64_t v = (uint64_t)hi << 32 | (uint64_t)low;
luaL_u64pushobj(L, v);
return 1;
}
static int
_rmessage_int52(lua_State *L) {
struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1);
const char * key = luaL_checkstring(L,2);
int index = luaL_checkinteger(L,3);
uint32_t hi,low;
low = pbc_rmessage_integer(m, key, index, &hi);
int64_t v = (int64_t)((uint64_t)hi << 32 | (uint64_t)low);
if (hi == 0) {
lua_pushnumber(L, (lua_Number)v);
}
else {
luaL_i64pushobj(L, v);
}
return 1;
}
static int
_rmessage_uint52(lua_State *L) {
struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1);
const char * key = luaL_checkstring(L,2);
int index = luaL_checkinteger(L,3);
uint32_t hi,low;
low = pbc_rmessage_integer(m, key, index, &hi);
uint64_t v = (uint64_t)hi << 32 | (uint64_t)low;
if (hi == 0) {
lua_pushnumber(L, (lua_Number)v);
} else {
luaL_u64pushobj(L, v);
}
return 1;
}写入pb消息修改
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
static int
_wmessage_int64(lua_State *L) {
struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1);
const char * key = luaL_checkstring(L,2);
int isnum;
uint64_t v64 = luaL_tou64x(L, 3, &isnum);
if (isnum == 0) {
return luaL_error(L, "Need an int64 type");
}
pbc_wmessage_integer(m, key, (uint32_t)v64, (uint32_t)(v64 >> 32));
/*switch (lua_type(L,3)) {
case LUA_TSTRING : {
size_t len = 0;
const char * number = lua_tolstring(L,3,&len);
if (len !=8 ) {
return luaL_error(L,"Need an 8 length string for int64");
}
const uint32_t * v = (const uint32_t *) number;
pbc_wmessage_integer(m, key, v[0] , v[1]);
break;
}
case LUA_TLIGHTUSERDATA : {
void * v = lua_touserdata(L,3);
uint64_t v64 = (uintptr_t)v;
pbc_wmessage_integer(m, key, (uint32_t)v64 , (uint32_t)(v64>>32));
break;
}
default :
return luaL_error(L, "Need an int64 type");
}*/
return 0;
}
static int
_wmessage_int52(lua_State *L) {
struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1);
const char * key = luaL_checkstring(L,2);
int isnum;
uint64_t v64 = (uint64_t)luaL_toi64x(L, 3, &isnum);
if (isnum == 0) {
return luaL_error(L, "Need an int type");
}
pbc_wmessage_integer(m, key, (uint32_t)v64, (uint32_t)(v64 >> 32));
/*int64_t number = (int64_t)(luaL_checknumber(L,3));
uint32_t hi = (uint32_t)(number >> 32);
pbc_wmessage_integer(m, key, (uint32_t)number, hi);*/
return 0;
}
static int
_wmessage_uint52(lua_State *L) {
struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1);
const char * key = luaL_checkstring(L,2);
int isnum;
uint64_t v64 = luaL_tou64x(L, 3, &isnum);
if (isnum == 0) {
return luaL_error(L, "Need an uint type");
}
pbc_wmessage_integer(m, key, (uint32_t)v64, (uint32_t)(v64 >> 32));
/*lua_Number v = (luaL_checknumber(L,3));
if (v < 0) {
return luaL_error(L, "negative number : %f passed to unsigned field",v);
}
uint64_t number = (uint64_t)v;
uint32_t hi = (uint32_t)(number >> 32);
pbc_wmessage_integer(m, key, (uint32_t)number, hi);*/
return 0;
}其他修改
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
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350static void *
_push_value(lua_State *L, char * ptr, char type) {
switch(type) {
case 'u': {
uint64_t v = *(uint64_t*)ptr;
ptr += 8;
//lua_pushnumber(L,(lua_Number)v);
luaL_u64pushobj(L, v);
break;
}
case 'i': {
int32_t v = *(int32_t*)ptr;
ptr += 4;
lua_pushinteger(L,v);
break;
}
case 'b': {
int32_t v = *(int32_t*)ptr;
ptr += 4;
lua_pushboolean(L,v);
break;
}
case 'p': {
uint32_t v = *(uint32_t*)ptr;
ptr += 4;
lua_pushlightuserdata(L,(void *)(intptr_t)v);
break;
}
case 'x': {
/*lua_pushlstring(L,ptr,8);
ptr += 8;*/
uint64_t v = *(uint64_t*)ptr;
ptr += 8;
luaL_u64pushobj(L, v);
break;
}
case 'd': {
int64_t v = *(int64_t*)ptr;
ptr += 8;
//lua_pushnumber(L,(lua_Number)v);
luaL_i64pushobj(L, v);
break;
}
case 'r': {
double v = *(double *)ptr;
ptr += 8;
lua_pushnumber(L,v);
break;
}
case 's': {
struct pbc_slice * slice = (struct pbc_slice *)ptr;
lua_pushlstring(L,(const char *)slice->buffer, slice->len);
ptr += sizeof(struct pbc_slice);
break;
}
case 'm': {
struct pbc_slice * slice = (struct pbc_slice *)ptr;
lua_createtable(L,2,0);
lua_pushlightuserdata(L, slice->buffer);
lua_rawseti(L,-2,1);
lua_pushinteger(L,slice->len);
lua_rawseti(L,-2,2);
ptr += sizeof(struct pbc_slice);
break;
}
}
return ptr;
}
static void
_push_array(lua_State *L, pbc_array array, char type, int index) {
switch (type) {
case 'I': {
int v = pbc_array_integer(array, index, NULL);
lua_pushinteger(L, v);
break;
}
case 'U': {
uint32_t hi = 0;
uint32_t low = pbc_array_integer(array, index, &hi);
uint64_t v = (uint64_t)hi << 32 | (uint64_t)low;
//lua_pushnumber(L, (lua_Number)v);
luaL_u64pushobj(L, v);
break;
}
case 'D': {
uint32_t hi = 0;
uint32_t low = pbc_array_integer(array, index, &hi);
uint64_t v = (uint64_t)hi << 32 | (uint64_t)low;
//lua_pushnumber(L, (lua_Number)((int64_t)v));
luaL_i64pushobj(L, v);
break;
}
case 'B': {
int v = pbc_array_integer(array, index, NULL);
lua_pushboolean(L, v);
break;
}
case 'P': {
uint32_t v = pbc_array_integer(array, index, NULL);
lua_pushlightuserdata(L,(void *)(intptr_t)v);
break;
}
case 'X': {
uint32_t hi = 0;
uint32_t low = pbc_array_integer(array, index, &hi);
uint64_t v = (uint64_t)low | (uint64_t)hi << 32;
//lua_pushlstring(L, (char *)&v, 8);
luaL_u64pushobj(L, v);
break;
}
case 'R': {
double v = pbc_array_real(array, index);
lua_pushnumber(L, v);
break;
}
case 'S': {
struct pbc_slice * slice = pbc_array_slice(array, index);
lua_pushlstring(L, (const char *)slice->buffer,slice->len);
break;
}
case 'M': {
struct pbc_slice * slice = pbc_array_slice(array, index);
lua_createtable(L,2,0);
lua_pushlightuserdata(L,slice->buffer);
lua_rawseti(L,-2,1);
lua_pushinteger(L,slice->len);
lua_rawseti(L,-2,2);
break;
}
}
lua_rawseti(L,-2,index+1);
}
static char *
_get_value(lua_State *L, int index, char * ptr, char type) {
switch(type) {
case 'i': {
int32_t v = luaL_checkinteger(L, index);
memcpy(ptr, &v, 4);
return ptr + 4;
}
case 'u': {
//uint64_t v = (uint64_t)luaL_checknumber(L, index);
uint64_t v = luaL_tou64x(L, index, NULL);
memcpy(ptr, &v, 8);
return ptr + 8;
}
case 'd': {
//int64_t v = (int64_t)luaL_checknumber(L, index);
int64_t v = luaL_toi64x(L, index, NULL);
memcpy(ptr, &v, 8);
return ptr + 8;
}
case 'b': {
int32_t v = lua_toboolean(L, index);
memcpy(ptr, &v, 4);
return ptr + 4;
}
case 'p': {
void *p = lua_touserdata(L, index);
uint32_t v = (uint32_t)(intptr_t)p;
memcpy(ptr, &v , 4);
return ptr + 4;
}
case 'x': {
//const char * i64 = luaL_checkstring(L, index);
uint64_t v = luaL_tou64x(L, index, NULL);
memcpy(ptr, &v, 8);
return ptr + 8;
}
case 'r': {
double v = luaL_checknumber(L, index);
memcpy(ptr, &v, 8);
return ptr + 8;
}
case 's': {
size_t sz = 0;
const char * str = luaL_checklstring(L, index, &sz);
struct pbc_slice * slice = (struct pbc_slice *)ptr;
slice->buffer = (void*)str;
slice->len = sz;
return ptr + sizeof(struct pbc_slice);
}
case 'm': {
struct pbc_slice * slice = (struct pbc_slice *)ptr;
if (lua_istable(L,index)) {
lua_rawgeti(L,index,1);
slice->buffer = lua_touserdata(L,-1);
lua_rawgeti(L,index,2);
slice->len = lua_tointeger(L,-1);
lua_pop(L,2);
} else {
size_t sz = 0;
const char * buffer = luaL_checklstring(L, index, &sz);
slice->buffer = (void *)buffer;
slice->len = sz;
}
return ptr + sizeof(struct pbc_slice);
}
default:
luaL_error(L,"unknown format %c", type);
return ptr;
}
}
static void
_get_array_value(lua_State *L, pbc_array array, char type) {
switch(type) {
case 'I': {
int32_t v = luaL_checkinteger(L, -1);
uint32_t hi = 0;
if (v<0) {
hi = ~0;
}
pbc_array_push_integer(array, v, hi);
break;
}
case 'U' : {
//uint64_t v = (uint64_t)luaL_checknumber(L, -1);
uint64_t v = luaL_tou64x(L, -1, NULL);
pbc_array_push_integer(array, (uint32_t)v, (uint32_t)(v >> 32));
break;
}
case 'D' : {
//int64_t v = (int64_t)luaL_checknumber(L, -1);
int64_t v = luaL_toi64x(L, -1, NULL);
pbc_array_push_integer(array, (uint32_t)v, (uint32_t)(v >> 32));
break;
}
case 'B': {
int32_t v = lua_toboolean(L, -1);
pbc_array_push_integer(array, v ? 1: 0, 0);
break;
}
case 'P': {
void *p = lua_touserdata(L, -1);
uint32_t v = (uint32_t)(intptr_t)p;
pbc_array_push_integer(array, v, 0);
break;
}
case 'X': {
//const char * i64 = luaL_checkstring(L, -1);
//uint64_t v = *(uint64_t *)i64;
uint64_t v = luaL_tou64x(L, -1, NULL);
pbc_array_push_integer(array, (uint32_t)v, (uint32_t)(v >> 32));
break;
}
case 'R': {
double v = luaL_checknumber(L, -1);
pbc_array_push_real(array, v);
break;
}
case 'S': {
size_t sz = 0;
const char * str = luaL_checklstring(L, -1, &sz);
struct pbc_slice slice;
slice.buffer = (void*)str;
slice.len = sz;
pbc_array_push_slice(array, &slice);
break;
}
case 'M': {
struct pbc_slice slice;
if (lua_istable(L,-1)) {
lua_rawgeti(L,-1,1);
slice.buffer = lua_touserdata(L,-1);
lua_rawgeti(L,-2,2);
slice.len = lua_tointeger(L,-1);
lua_pop(L,2);
} else {
size_t sz = 0;
const char * buffer = luaL_checklstring(L, -1, &sz);
slice.buffer = (void *)buffer;
slice.len = sz;
}
pbc_array_push_slice(array, &slice);
break;
}
}
}
static void
push_value(lua_State *L, int type, const char * type_name, union pbc_value *v) {
switch(type) {
case PBC_INT:
lua_pushinteger(L, (int)v->i.low);
break;
case PBC_REAL:
lua_pushnumber(L, v->f);
break;
case PBC_BOOL:
lua_pushboolean(L, v->i.low);
break;
case PBC_ENUM:
lua_pushstring(L, v->e.name);
break;
case PBC_BYTES:
case PBC_STRING:
lua_pushlstring(L, (const char *)v->s.buffer , v->s.len);
break;
case PBC_MESSAGE:
lua_pushvalue(L, -3);
lua_pushstring(L, type_name);
lua_pushlstring(L, (const char *)v->s.buffer , v->s.len);
lua_call(L, 2 , 1);
break;
case PBC_FIXED64: {
//lua_pushlstring(L, (const char *)&(v->i), 8);
uint64_t v64 = (uint64_t)(v->i.hi) << 32 | (uint64_t)(v->i.low);
if (v->i.hi == 0) {
lua_pushnumber(L, (lua_Number)v64);
}
else {
luaL_u64pushobj(L, v64);
}
break;
}
case PBC_FIXED32:
lua_pushlightuserdata(L,(void *)(intptr_t)v->i.low);
break;
case PBC_INT64: {
uint64_t v64 = (uint64_t)(v->i.hi) << 32 | (uint64_t)(v->i.low);
//lua_pushnumber(L,(lua_Number)(int64_t)v64);
if (v->i.hi == 0) {
lua_pushnumber(L, (lua_Number)(int64_t)v64);
}
else {
luaL_i64pushobj(L, (int64_t)v64);
}
break;
}
case PBC_UINT: {
uint64_t v64 = (uint64_t)(v->i.hi) << 32 | (uint64_t)(v->i.low);
if (v->i.hi == 0) {
lua_pushnumber(L, (lua_Number)v64);
}
else {
luaL_u64pushobj(L, v64);
}
//lua_pushnumber(L,(lua_Number)v64);
break;
}
default:
luaL_error(L, "Unknown type %s", type_name);
break;
}
}
测试:把addressbook.id改成int64,测试代码对应如下修改,输出结果为9223372036854775807LL
1 | id = "9223372036854775807", -- 修改了pbc底层,会自动序列化成int64格式 |