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