]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | // |
2 | // Licensed to the Apache Software Foundation (ASF) under one | |
3 | // or more contributor license agreements. See the NOTICE file | |
4 | // distributed with this work for additional information | |
5 | // regarding copyright ownership. The ASF licenses this file | |
6 | // to you under the Apache License, Version 2.0 (the | |
7 | // "License"); you may not use this file except in compliance | |
8 | // with the License. You may obtain a copy of the License at | |
9 | // | |
10 | // http://www.apache.org/licenses/LICENSE-2.0 | |
11 | // | |
12 | // Unless required by applicable law or agreed to in writing, | |
13 | // software distributed under the License is distributed on an | |
14 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
15 | // KIND, either express or implied. See the License for the | |
16 | // specific language governing permissions and limitations | |
17 | // under the License. | |
18 | // | |
19 | ||
20 | #include <lua.h> | |
21 | #include <lauxlib.h> | |
22 | #include <string.h> | |
23 | #include <inttypes.h> | |
24 | #include <netinet/in.h> | |
25 | ||
26 | extern int64_t lualongnumber_checklong(lua_State *L, int index); | |
27 | extern int64_t lualongnumber_pushlong(lua_State *L, int64_t *val); | |
28 | ||
29 | // host order to network order (64-bit) | |
30 | static int64_t T_htonll(uint64_t data) { | |
31 | uint32_t d1 = htonl((uint32_t)data); | |
32 | uint32_t d2 = htonl((uint32_t)(data >> 32)); | |
33 | return ((uint64_t)d1 << 32) + (uint64_t)d2; | |
34 | } | |
35 | ||
36 | // network order to host order (64-bit) | |
37 | static int64_t T_ntohll(uint64_t data) { | |
38 | uint32_t d1 = ntohl((uint32_t)data); | |
39 | uint32_t d2 = ntohl((uint32_t)(data >> 32)); | |
40 | return ((uint64_t)d1 << 32) + (uint64_t)d2; | |
41 | } | |
42 | ||
43 | /** | |
44 | * bpack(type, data) | |
45 | * c - Signed Byte | |
46 | * s - Signed Short | |
47 | * i - Signed Int | |
48 | * l - Signed Long | |
49 | * d - Double | |
50 | */ | |
51 | static int l_bpack(lua_State *L) { | |
52 | const char *code = luaL_checkstring(L, 1); | |
53 | luaL_argcheck(L, code[1] == '\0', 0, "Format code must be one character."); | |
54 | luaL_Buffer buf; | |
55 | luaL_buffinit(L, &buf); | |
56 | ||
57 | switch (code[0]) { | |
58 | case 'c': { | |
59 | int8_t data = luaL_checknumber(L, 2); | |
60 | luaL_addlstring(&buf, (void*)&data, sizeof(data)); | |
61 | break; | |
62 | } | |
63 | case 's': { | |
64 | int16_t data = luaL_checknumber(L, 2); | |
65 | data = (int16_t)htons(data); | |
66 | luaL_addlstring(&buf, (void*)&data, sizeof(data)); | |
67 | break; | |
68 | } | |
69 | case 'i': { | |
70 | int32_t data = luaL_checkinteger(L, 2); | |
71 | data = (int32_t)htonl(data); | |
72 | luaL_addlstring(&buf, (void*)&data, sizeof(data)); | |
73 | break; | |
74 | } | |
75 | case 'l': { | |
76 | int64_t data = lualongnumber_checklong(L, 2); | |
77 | data = (int64_t)T_htonll(data); | |
78 | luaL_addlstring(&buf, (void*)&data, sizeof(data)); | |
79 | break; | |
80 | } | |
81 | case 'd': { | |
82 | double data = luaL_checknumber(L, 2); | |
83 | luaL_addlstring(&buf, (void*)&data, sizeof(data)); | |
84 | break; | |
85 | } | |
86 | default: | |
87 | luaL_argcheck(L, 0, 0, "Invalid format code."); | |
88 | } | |
89 | ||
90 | luaL_pushresult(&buf); | |
91 | return 1; | |
92 | } | |
93 | ||
94 | /** | |
95 | * bunpack(type, data) | |
96 | * c - Signed Byte | |
97 | * C - Unsigned Byte | |
98 | * s - Signed Short | |
99 | * i - Signed Int | |
100 | * l - Signed Long | |
101 | * d - Double | |
102 | */ | |
103 | static int l_bunpack(lua_State *L) { | |
104 | const char *code = luaL_checkstring(L, 1); | |
105 | luaL_argcheck(L, code[1] == '\0', 0, "Format code must be one character."); | |
106 | const char *data = luaL_checkstring(L, 2); | |
107 | #if LUA_VERSION_NUM >= 502 | |
108 | size_t len = lua_rawlen(L, 2); | |
109 | #else | |
110 | size_t len = lua_objlen(L, 2); | |
111 | #endif | |
112 | ||
113 | switch (code[0]) { | |
114 | case 'c': { | |
115 | int8_t val; | |
116 | luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); | |
117 | memcpy(&val, data, sizeof(val)); | |
118 | lua_pushnumber(L, val); | |
119 | break; | |
120 | } | |
121 | /** | |
122 | * unpack unsigned Byte. | |
123 | */ | |
124 | case 'C': { | |
125 | uint8_t val; | |
126 | luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); | |
127 | memcpy(&val, data, sizeof(val)); | |
128 | lua_pushnumber(L, val); | |
129 | break; | |
130 | } | |
131 | case 's': { | |
132 | int16_t val; | |
133 | luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); | |
134 | memcpy(&val, data, sizeof(val)); | |
135 | val = (int16_t)ntohs(val); | |
136 | lua_pushnumber(L, val); | |
137 | break; | |
138 | } | |
139 | case 'i': { | |
140 | int32_t val; | |
141 | luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); | |
142 | memcpy(&val, data, sizeof(val)); | |
143 | val = (int32_t)ntohl(val); | |
144 | lua_pushnumber(L, val); | |
145 | break; | |
146 | } | |
147 | case 'l': { | |
148 | int64_t val; | |
149 | luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); | |
150 | memcpy(&val, data, sizeof(val)); | |
151 | val = (int64_t)T_ntohll(val); | |
152 | lualongnumber_pushlong(L, &val); | |
153 | break; | |
154 | } | |
155 | case 'd': { | |
156 | double val; | |
157 | luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size."); | |
158 | memcpy(&val, data, sizeof(val)); | |
159 | lua_pushnumber(L, val); | |
160 | break; | |
161 | } | |
162 | default: | |
163 | luaL_argcheck(L, 0, 0, "Invalid format code."); | |
164 | } | |
165 | return 1; | |
166 | } | |
167 | ||
168 | /** | |
169 | * Convert l into a zigzag long. This allows negative numbers to be | |
170 | * represented compactly as a varint. | |
171 | */ | |
172 | static int l_i64ToZigzag(lua_State *L) { | |
173 | int64_t n = lualongnumber_checklong(L, 1); | |
174 | int64_t result = (n << 1) ^ (n >> 63); | |
175 | lualongnumber_pushlong(L, &result); | |
176 | return 1; | |
177 | } | |
178 | /** | |
179 | * Convert n into a zigzag int. This allows negative numbers to be | |
180 | * represented compactly as a varint. | |
181 | */ | |
182 | static int l_i32ToZigzag(lua_State *L) { | |
183 | int32_t n = luaL_checkinteger(L, 1); | |
184 | uint32_t result = (uint32_t)(n << 1) ^ (n >> 31); | |
185 | lua_pushnumber(L, result); | |
186 | return 1; | |
187 | } | |
188 | ||
189 | /** | |
190 | * Convert from zigzag int to int. | |
191 | */ | |
192 | static int l_zigzagToI32(lua_State *L) { | |
193 | uint32_t n = luaL_checkinteger(L, 1); | |
194 | int32_t result = (int32_t)(n >> 1) ^ (uint32_t)(-(int32_t)(n & 1)); | |
195 | lua_pushnumber(L, result); | |
196 | return 1; | |
197 | } | |
198 | ||
199 | /** | |
200 | * Convert from zigzag long to long. | |
201 | */ | |
202 | static int l_zigzagToI64(lua_State *L) { | |
203 | int64_t n = lualongnumber_checklong(L, 1); | |
204 | int64_t result = (int64_t)(n >> 1) ^ (uint64_t)(-(int64_t)(n & 1)); | |
205 | lualongnumber_pushlong(L, &result); | |
206 | return 1; | |
207 | } | |
208 | ||
209 | /** | |
210 | * Convert an i32 to a varint. Results in 1-5 bytes on the buffer. | |
211 | */ | |
212 | static int l_toVarint32(lua_State *L) { | |
213 | uint8_t buf[5]; | |
214 | uint32_t n = luaL_checkinteger(L, 1); | |
215 | uint32_t wsize = 0; | |
216 | ||
217 | while (1) { | |
218 | if ((n & ~0x7F) == 0) { | |
219 | buf[wsize++] = (int8_t)n; | |
220 | break; | |
221 | } else { | |
222 | buf[wsize++] = (int8_t)((n & 0x7F) | 0x80); | |
223 | n >>= 7; | |
224 | } | |
225 | } | |
226 | lua_pushlstring(L, buf, wsize); | |
227 | return 1; | |
228 | } | |
229 | ||
230 | /** | |
231 | * Convert an i64 to a varint. Results in 1-10 bytes on the buffer. | |
232 | */ | |
233 | static int l_toVarint64(lua_State *L) { | |
234 | uint8_t data[10]; | |
235 | uint64_t n = lualongnumber_checklong(L, 1); | |
236 | uint32_t wsize = 0; | |
237 | luaL_Buffer buf; | |
238 | luaL_buffinit(L, &buf); | |
239 | ||
240 | while (1) { | |
241 | if ((n & ~0x7FL) == 0) { | |
242 | data[wsize++] = (int8_t)n; | |
243 | break; | |
244 | } else { | |
245 | data[wsize++] = (int8_t)((n & 0x7F) | 0x80); | |
246 | n >>= 7; | |
247 | } | |
248 | } | |
249 | ||
250 | luaL_addlstring(&buf, (void*)&data, wsize); | |
251 | luaL_pushresult(&buf); | |
252 | return 1; | |
253 | } | |
254 | ||
255 | /** | |
256 | * Convert a varint to i64. | |
257 | */ | |
258 | static int l_fromVarint64(lua_State *L) { | |
259 | int64_t result; | |
260 | uint8_t byte = luaL_checknumber(L, 1); | |
261 | int32_t shift = luaL_checknumber(L, 2); | |
262 | uint64_t n = (uint64_t)lualongnumber_checklong(L, 3); | |
263 | n |= (uint64_t)(byte & 0x7f) << shift; | |
264 | ||
265 | if (!(byte & 0x80)) { | |
266 | result = (int64_t)(n >> 1) ^ (uint64_t)(-(int64_t)(n & 1)); | |
267 | lua_pushnumber(L, 0); | |
268 | } else { | |
269 | result = n; | |
270 | lua_pushnumber(L, 1); | |
271 | } | |
272 | lualongnumber_pushlong(L, &result); | |
273 | return 2; | |
274 | } | |
275 | ||
276 | /** | |
277 | * To pack message type of compact protocol. | |
278 | */ | |
279 | static int l_packMesgType(lua_State *L) { | |
280 | int32_t version_n = luaL_checkinteger(L, 1); | |
281 | int32_t version_mask = luaL_checkinteger(L, 2); | |
282 | int32_t messagetype = luaL_checkinteger(L, 3); | |
283 | int32_t type_shift_amount = luaL_checkinteger(L, 4); | |
284 | int32_t type_mask = luaL_checkinteger(L, 5); | |
285 | int32_t to_mesg_type = (version_n & version_mask) | | |
286 | (((int32_t)messagetype << type_shift_amount) & type_mask); | |
287 | lua_pushnumber(L, to_mesg_type); | |
288 | return 1; | |
289 | } | |
290 | ||
291 | static const struct luaL_Reg lua_bpack[] = { | |
292 | {"bpack", l_bpack}, | |
293 | {"bunpack", l_bunpack}, | |
294 | {"i32ToZigzag", l_i32ToZigzag}, | |
295 | {"i64ToZigzag", l_i64ToZigzag}, | |
296 | {"zigzagToI32", l_zigzagToI32}, | |
297 | {"zigzagToI64", l_zigzagToI64}, | |
298 | {"toVarint32", l_toVarint32}, | |
299 | {"toVarint64", l_toVarint64}, | |
300 | {"fromVarint64", l_fromVarint64}, | |
301 | {"packMesgType", l_packMesgType}, | |
302 | {NULL, NULL} | |
303 | }; | |
304 | ||
305 | int luaopen_libluabpack(lua_State *L) { | |
306 | luaL_register(L, "libluabpack", lua_bpack); | |
307 | return 1; | |
308 | } |