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)
T_htonll(uint64_t data)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)
T_ntohll(uint64_t data)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 */
l_bpack(lua_State * L)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 */
l_bunpack(lua_State * L)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 */
l_i64ToZigzag(lua_State * L)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 */
l_i32ToZigzag(lua_State * L)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 */
l_zigzagToI32(lua_State * L)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 */
l_zigzagToI64(lua_State * L)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 */
l_toVarint32(lua_State * L)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 */
l_toVarint64(lua_State * L)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 */
l_fromVarint64(lua_State * L)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 */
l_packMesgType(lua_State * L)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
luaopen_libluabpack(lua_State * L)305 int luaopen_libluabpack(lua_State *L) {
306 luaL_register(L, "libluabpack", lua_bpack);
307 return 1;
308 }
309