]>
Commit | Line | Data |
---|---|---|
36e6637d | 1 | #include <math.h> |
2 | #include <stdlib.h> | |
3 | #include <stdint.h> | |
4 | #include <string.h> | |
5 | #include <assert.h> | |
6 | ||
7 | #include "lua.h" | |
8 | #include "lauxlib.h" | |
9 | ||
10 | #define LUACMSGPACK_VERSION "lua-cmsgpack 0.3.0" | |
11 | #define LUACMSGPACK_COPYRIGHT "Copyright (C) 2012, Salvatore Sanfilippo" | |
12 | #define LUACMSGPACK_DESCRIPTION "MessagePack C implementation for Lua" | |
13 | ||
14 | #define LUACMSGPACK_MAX_NESTING 16 /* Max tables nesting. */ | |
15 | ||
16 | /* ============================================================================== | |
17 | * MessagePack implementation and bindings for Lua 5.1. | |
18 | * Copyright(C) 2012 Salvatore Sanfilippo <antirez@gmail.com> | |
19 | * | |
20 | * http://github.com/antirez/lua-cmsgpack | |
21 | * | |
22 | * For MessagePack specification check the following web site: | |
23 | * http://wiki.msgpack.org/display/MSGPACK/Format+specification | |
24 | * | |
25 | * See Copyright Notice at the end of this file. | |
26 | * | |
27 | * CHANGELOG: | |
28 | * 19-Feb-2012 (ver 0.1.0): Initial release. | |
29 | * 20-Feb-2012 (ver 0.2.0): Tables encoding improved. | |
30 | * 20-Feb-2012 (ver 0.2.1): Minor bug fixing. | |
31 | * 20-Feb-2012 (ver 0.3.0): Module renamed lua-cmsgpack (was lua-msgpack). | |
32 | * ============================================================================ */ | |
33 | ||
34 | /* --------------------------- Endian conversion -------------------------------- | |
35 | * We use it only for floats and doubles, all the other conversions are performed | |
36 | * in an endian independent fashion. So the only thing we need is a function | |
37 | * that swaps a binary string if the arch is little endian (and left it untouched | |
38 | * otherwise). */ | |
39 | ||
40 | /* Reverse memory bytes if arch is little endian. Given the conceptual | |
41 | * simplicity of the Lua build system we prefer to check for endianess at runtime. | |
42 | * The performance difference should be acceptable. */ | |
43 | static void memrevifle(void *ptr, size_t len) { | |
44 | unsigned char *p = ptr, *e = p+len-1, aux; | |
45 | int test = 1; | |
46 | unsigned char *testp = (unsigned char*) &test; | |
47 | ||
48 | if (testp[0] == 0) return; /* Big endian, nothign to do. */ | |
49 | len /= 2; | |
50 | while(len--) { | |
51 | aux = *p; | |
52 | *p = *e; | |
53 | *e = aux; | |
54 | p++; | |
55 | e--; | |
56 | } | |
57 | } | |
58 | ||
59 | /* ----------------------------- String buffer ---------------------------------- | |
60 | * This is a simple implementation of string buffers. The only opereation | |
61 | * supported is creating empty buffers and appending bytes to it. | |
62 | * The string buffer uses 2x preallocation on every realloc for O(N) append | |
63 | * behavior. */ | |
64 | ||
65 | typedef struct mp_buf { | |
66 | unsigned char *b; | |
67 | size_t len, free; | |
68 | } mp_buf; | |
69 | ||
70 | static mp_buf *mp_buf_new(void) { | |
71 | mp_buf *buf = malloc(sizeof(*buf)); | |
72 | ||
73 | buf->b = NULL; | |
74 | buf->len = buf->free = 0; | |
75 | return buf; | |
76 | } | |
77 | ||
78 | void mp_buf_append(mp_buf *buf, const unsigned char *s, size_t len) { | |
79 | if (buf->free < len) { | |
80 | size_t newlen = buf->len+len; | |
81 | ||
82 | buf->b = realloc(buf->b,newlen*2); | |
83 | buf->free = newlen; | |
84 | } | |
85 | memcpy(buf->b+buf->len,s,len); | |
86 | buf->len += len; | |
87 | buf->free -= len; | |
88 | } | |
89 | ||
90 | void mp_buf_free(mp_buf *buf) { | |
91 | free(buf->b); | |
92 | free(buf); | |
93 | } | |
94 | ||
95 | /* ------------------------------ String cursor ---------------------------------- | |
96 | * This simple data structure is used for parsing. Basically you create a cursor | |
97 | * using a string pointer and a length, then it is possible to access the | |
98 | * current string position with cursor->p, check the remaining length | |
99 | * in cursor->left, and finally consume more string using | |
100 | * mp_cur_consume(cursor,len), to advance 'p' and subtract 'left'. | |
101 | * An additional field cursor->error is set to zero on initialization and can | |
102 | * be used to report errors. */ | |
103 | ||
104 | #define MP_CUR_ERROR_NONE 0 | |
105 | #define MP_CUR_ERROR_EOF 1 /* Not enough data to complete the opereation. */ | |
106 | #define MP_CUR_ERROR_BADFMT 2 /* Bad data format */ | |
107 | ||
108 | typedef struct mp_cur { | |
109 | const unsigned char *p; | |
110 | size_t left; | |
111 | int err; | |
112 | } mp_cur; | |
113 | ||
114 | static mp_cur *mp_cur_new(const unsigned char *s, size_t len) { | |
115 | mp_cur *cursor = malloc(sizeof(*cursor)); | |
116 | ||
117 | cursor->p = s; | |
118 | cursor->left = len; | |
119 | cursor->err = MP_CUR_ERROR_NONE; | |
120 | return cursor; | |
121 | } | |
122 | ||
123 | static void mp_cur_free(mp_cur *cursor) { | |
124 | free(cursor); | |
125 | } | |
126 | ||
127 | #define mp_cur_consume(_c,_len) do { _c->p += _len; _c->left -= _len; } while(0) | |
128 | ||
129 | /* When there is not enough room we set an error in the cursor and return, this | |
130 | * is very common across the code so we have a macro to make the code look | |
131 | * a bit simpler. */ | |
132 | #define mp_cur_need(_c,_len) do { \ | |
133 | if (_c->left < _len) { \ | |
134 | _c->err = MP_CUR_ERROR_EOF; \ | |
135 | return; \ | |
136 | } \ | |
137 | } while(0) | |
138 | ||
139 | /* --------------------------- Low level MP encoding -------------------------- */ | |
140 | ||
141 | static void mp_encode_bytes(mp_buf *buf, const unsigned char *s, size_t len) { | |
142 | unsigned char hdr[5]; | |
143 | int hdrlen; | |
144 | ||
145 | if (len < 32) { | |
146 | hdr[0] = 0xa0 | (len&0xff); /* fix raw */ | |
147 | hdrlen = 1; | |
148 | } else if (len <= 0xffff) { | |
149 | hdr[0] = 0xda; | |
150 | hdr[1] = (len&0xff00)>>8; | |
151 | hdr[2] = len&0xff; | |
152 | hdrlen = 3; | |
153 | } else { | |
154 | hdr[0] = 0xdb; | |
155 | hdr[1] = (len&0xff000000)>>24; | |
156 | hdr[2] = (len&0xff0000)>>16; | |
157 | hdr[3] = (len&0xff00)>>8; | |
158 | hdr[4] = len&0xff; | |
159 | hdrlen = 5; | |
160 | } | |
161 | mp_buf_append(buf,hdr,hdrlen); | |
162 | mp_buf_append(buf,s,len); | |
163 | } | |
164 | ||
165 | /* we assume IEEE 754 internal format for single and double precision floats. */ | |
166 | static void mp_encode_double(mp_buf *buf, double d) { | |
167 | unsigned char b[9]; | |
168 | float f = d; | |
169 | ||
170 | assert(sizeof(f) == 4 && sizeof(d) == 8); | |
171 | if (d == (double)f) { | |
172 | b[0] = 0xca; /* float IEEE 754 */ | |
173 | memcpy(b+1,&f,4); | |
174 | memrevifle(b+1,4); | |
175 | mp_buf_append(buf,b,5); | |
176 | } else if (sizeof(d) == 8) { | |
177 | b[0] = 0xcb; /* double IEEE 754 */ | |
178 | memcpy(b+1,&d,8); | |
179 | memrevifle(b+1,8); | |
180 | mp_buf_append(buf,b,9); | |
181 | } | |
182 | } | |
183 | ||
184 | static void mp_encode_int(mp_buf *buf, int64_t n) { | |
185 | unsigned char b[9]; | |
186 | int enclen; | |
187 | ||
188 | if (n >= 0) { | |
189 | if (n <= 127) { | |
190 | b[0] = n & 0x7f; /* positive fixnum */ | |
191 | enclen = 1; | |
192 | } else if (n <= 0xff) { | |
193 | b[0] = 0xcc; /* uint 8 */ | |
194 | b[1] = n & 0xff; | |
195 | enclen = 2; | |
196 | } else if (n <= 0xffff) { | |
197 | b[0] = 0xcd; /* uint 16 */ | |
198 | b[1] = (n & 0xff00) >> 8; | |
199 | b[2] = n & 0xff; | |
200 | enclen = 3; | |
201 | } else if (n <= 0xffffffffLL) { | |
202 | b[0] = 0xce; /* uint 32 */ | |
203 | b[1] = (n & 0xff000000) >> 24; | |
204 | b[2] = (n & 0xff0000) >> 16; | |
205 | b[3] = (n & 0xff00) >> 8; | |
206 | b[4] = n & 0xff; | |
207 | enclen = 5; | |
208 | } else { | |
209 | b[0] = 0xcf; /* uint 64 */ | |
210 | b[1] = (n & 0xff00000000000000LL) >> 56; | |
211 | b[2] = (n & 0xff000000000000LL) >> 48; | |
212 | b[3] = (n & 0xff0000000000LL) >> 40; | |
213 | b[4] = (n & 0xff00000000LL) >> 32; | |
214 | b[5] = (n & 0xff000000) >> 24; | |
215 | b[6] = (n & 0xff0000) >> 16; | |
216 | b[7] = (n & 0xff00) >> 8; | |
217 | b[8] = n & 0xff; | |
218 | enclen = 9; | |
219 | } | |
220 | } else { | |
221 | if (n >= -32) { | |
222 | b[0] = ((char)n); /* negative fixnum */ | |
223 | enclen = 1; | |
224 | } else if (n >= -128) { | |
225 | b[0] = 0xd0; /* int 8 */ | |
226 | b[1] = n & 0xff; | |
227 | enclen = 2; | |
228 | } else if (n >= -32768) { | |
229 | b[0] = 0xd1; /* int 16 */ | |
230 | b[1] = (n & 0xff00) >> 8; | |
231 | b[2] = n & 0xff; | |
232 | enclen = 3; | |
233 | } else if (n >= -2147483648LL) { | |
234 | b[0] = 0xd2; /* int 32 */ | |
235 | b[1] = (n & 0xff000000) >> 24; | |
236 | b[2] = (n & 0xff0000) >> 16; | |
237 | b[3] = (n & 0xff00) >> 8; | |
238 | b[4] = n & 0xff; | |
239 | enclen = 5; | |
240 | } else { | |
241 | b[0] = 0xd3; /* int 64 */ | |
242 | b[1] = (n & 0xff00000000000000LL) >> 56; | |
243 | b[2] = (n & 0xff000000000000LL) >> 48; | |
244 | b[3] = (n & 0xff0000000000LL) >> 40; | |
245 | b[4] = (n & 0xff00000000LL) >> 32; | |
246 | b[5] = (n & 0xff000000) >> 24; | |
247 | b[6] = (n & 0xff0000) >> 16; | |
248 | b[7] = (n & 0xff00) >> 8; | |
249 | b[8] = n & 0xff; | |
250 | enclen = 9; | |
251 | } | |
252 | } | |
253 | mp_buf_append(buf,b,enclen); | |
254 | } | |
255 | ||
256 | static void mp_encode_array(mp_buf *buf, int64_t n) { | |
257 | unsigned char b[5]; | |
258 | int enclen; | |
259 | ||
260 | if (n <= 15) { | |
261 | b[0] = 0x90 | (n & 0xf); /* fix array */ | |
262 | enclen = 1; | |
263 | } else if (n <= 65535) { | |
264 | b[0] = 0xdc; /* array 16 */ | |
265 | b[1] = (n & 0xff00) >> 8; | |
266 | b[2] = n & 0xff; | |
267 | enclen = 3; | |
268 | } else { | |
269 | b[0] = 0xdd; /* array 32 */ | |
270 | b[1] = (n & 0xff000000) >> 24; | |
271 | b[2] = (n & 0xff0000) >> 16; | |
272 | b[3] = (n & 0xff00) >> 8; | |
273 | b[4] = n & 0xff; | |
274 | enclen = 5; | |
275 | } | |
276 | mp_buf_append(buf,b,enclen); | |
277 | } | |
278 | ||
279 | static void mp_encode_map(mp_buf *buf, int64_t n) { | |
280 | unsigned char b[5]; | |
281 | int enclen; | |
282 | ||
283 | if (n <= 15) { | |
284 | b[0] = 0x80 | (n & 0xf); /* fix map */ | |
285 | enclen = 1; | |
286 | } else if (n <= 65535) { | |
287 | b[0] = 0xde; /* map 16 */ | |
288 | b[1] = (n & 0xff00) >> 8; | |
289 | b[2] = n & 0xff; | |
290 | enclen = 3; | |
291 | } else { | |
292 | b[0] = 0xdf; /* map 32 */ | |
293 | b[1] = (n & 0xff000000) >> 24; | |
294 | b[2] = (n & 0xff0000) >> 16; | |
295 | b[3] = (n & 0xff00) >> 8; | |
296 | b[4] = n & 0xff; | |
297 | enclen = 5; | |
298 | } | |
299 | mp_buf_append(buf,b,enclen); | |
300 | } | |
301 | ||
302 | /* ----------------------------- Lua types encoding --------------------------- */ | |
303 | ||
304 | static void mp_encode_lua_string(lua_State *L, mp_buf *buf) { | |
305 | size_t len; | |
306 | const char *s; | |
307 | ||
308 | s = lua_tolstring(L,-1,&len); | |
309 | mp_encode_bytes(buf,(const unsigned char*)s,len); | |
310 | } | |
311 | ||
312 | static void mp_encode_lua_bool(lua_State *L, mp_buf *buf) { | |
313 | unsigned char b = lua_toboolean(L,-1) ? 0xc3 : 0xc2; | |
314 | mp_buf_append(buf,&b,1); | |
315 | } | |
316 | ||
317 | static void mp_encode_lua_number(lua_State *L, mp_buf *buf) { | |
318 | lua_Number n = lua_tonumber(L,-1); | |
319 | ||
320 | if (floor(n) != n) { | |
321 | mp_encode_double(buf,(double)n); | |
322 | } else { | |
323 | mp_encode_int(buf,(int64_t)n); | |
324 | } | |
325 | } | |
326 | ||
327 | static void mp_encode_lua_type(lua_State *L, mp_buf *buf, int level); | |
328 | ||
329 | /* Convert a lua table into a message pack list. */ | |
330 | static void mp_encode_lua_table_as_array(lua_State *L, mp_buf *buf, int level) { | |
331 | size_t len = lua_objlen(L,-1), j; | |
332 | ||
333 | mp_encode_array(buf,len); | |
334 | for (j = 1; j <= len; j++) { | |
335 | lua_pushnumber(L,j); | |
336 | lua_gettable(L,-2); | |
337 | mp_encode_lua_type(L,buf,level+1); | |
338 | } | |
339 | } | |
340 | ||
341 | /* Convert a lua table into a message pack key-value map. */ | |
342 | static void mp_encode_lua_table_as_map(lua_State *L, mp_buf *buf, int level) { | |
343 | size_t len = 0; | |
344 | ||
345 | /* First step: count keys into table. No other way to do it with the | |
346 | * Lua API, we need to iterate a first time. Note that an alternative | |
347 | * would be to do a single run, and then hack the buffer to insert the | |
348 | * map opcodes for message pack. Too hachish for this lib. */ | |
349 | lua_pushnil(L); | |
350 | while(lua_next(L,-2)) { | |
351 | lua_pop(L,1); /* remove value, keep key for next iteration. */ | |
352 | len++; | |
353 | } | |
354 | ||
355 | /* Step two: actually encoding of the map. */ | |
356 | mp_encode_map(buf,len); | |
357 | lua_pushnil(L); | |
358 | while(lua_next(L,-2)) { | |
359 | /* Stack: ... key value */ | |
360 | lua_pushvalue(L,-2); /* Stack: ... key value key */ | |
361 | mp_encode_lua_type(L,buf,level+1); /* encode key */ | |
362 | mp_encode_lua_type(L,buf,level+1); /* encode val */ | |
363 | } | |
364 | } | |
365 | ||
366 | /* Returns true if the Lua table on top of the stack is exclusively composed | |
367 | * of keys from numerical keys from 1 up to N, with N being the total number | |
368 | * of elements, without any hole in the middle. */ | |
369 | static int table_is_an_array(lua_State *L) { | |
370 | long count = 0, max = 0, idx = 0; | |
371 | lua_Number n; | |
372 | ||
373 | lua_pushnil(L); | |
374 | while(lua_next(L,-2)) { | |
375 | /* Stack: ... key value */ | |
376 | lua_pop(L,1); /* Stack: ... key */ | |
377 | if (!lua_isnumber(L,-1)) goto not_array; | |
378 | n = lua_tonumber(L,-1); | |
379 | idx = n; | |
380 | if (idx != n || idx < 1) goto not_array; | |
381 | count++; | |
382 | max = idx; | |
383 | } | |
384 | /* We have the total number of elements in "count". Also we have | |
385 | * the max index encountered in "idx". We can't reach this code | |
386 | * if there are indexes <= 0. If you also note that there can not be | |
387 | * repeated keys into a table, you have that if idx==count you are sure | |
388 | * that there are all the keys form 1 to count (both included). */ | |
389 | return idx == count; | |
390 | ||
391 | not_array: | |
392 | lua_pop(L,1); | |
393 | return 0; | |
394 | } | |
395 | ||
396 | /* If the length operator returns non-zero, that is, there is at least | |
397 | * an object at key '1', we serialize to message pack list. Otherwise | |
398 | * we use a map. */ | |
399 | static void mp_encode_lua_table(lua_State *L, mp_buf *buf, int level) { | |
400 | if (table_is_an_array(L)) | |
401 | mp_encode_lua_table_as_array(L,buf,level); | |
402 | else | |
403 | mp_encode_lua_table_as_map(L,buf,level); | |
404 | } | |
405 | ||
406 | static void mp_encode_lua_null(lua_State *L, mp_buf *buf) { | |
407 | unsigned char b[1]; | |
408 | ||
409 | b[0] = 0xc0; | |
410 | mp_buf_append(buf,b,1); | |
411 | } | |
412 | ||
413 | static void mp_encode_lua_type(lua_State *L, mp_buf *buf, int level) { | |
414 | int t = lua_type(L,-1); | |
415 | ||
416 | /* Limit the encoding of nested tables to a specfiied maximum depth, so that | |
417 | * we survive when called against circular references in tables. */ | |
418 | if (t == LUA_TTABLE && level == LUACMSGPACK_MAX_NESTING) t = LUA_TNIL; | |
419 | switch(t) { | |
420 | case LUA_TSTRING: mp_encode_lua_string(L,buf); break; | |
421 | case LUA_TBOOLEAN: mp_encode_lua_bool(L,buf); break; | |
422 | case LUA_TNUMBER: mp_encode_lua_number(L,buf); break; | |
423 | case LUA_TTABLE: mp_encode_lua_table(L,buf,level); break; | |
424 | default: mp_encode_lua_null(L,buf); break; | |
425 | } | |
426 | lua_pop(L,1); | |
427 | } | |
428 | ||
429 | static int mp_pack(lua_State *L) { | |
430 | mp_buf *buf = mp_buf_new(); | |
431 | ||
432 | mp_encode_lua_type(L,buf,0); | |
433 | lua_pushlstring(L,(char*)buf->b,buf->len); | |
434 | mp_buf_free(buf); | |
435 | return 1; | |
436 | } | |
437 | ||
438 | /* --------------------------------- Decoding --------------------------------- */ | |
439 | ||
440 | void mp_decode_to_lua_type(lua_State *L, mp_cur *c); | |
441 | ||
442 | void mp_decode_to_lua_array(lua_State *L, mp_cur *c, size_t len) { | |
443 | int index = 1; | |
444 | ||
445 | lua_newtable(L); | |
446 | while(len--) { | |
447 | lua_pushnumber(L,index++); | |
448 | mp_decode_to_lua_type(L,c); | |
449 | if (c->err) return; | |
450 | lua_settable(L,-3); | |
451 | } | |
452 | } | |
453 | ||
454 | void mp_decode_to_lua_hash(lua_State *L, mp_cur *c, size_t len) { | |
455 | lua_newtable(L); | |
456 | while(len--) { | |
457 | mp_decode_to_lua_type(L,c); /* key */ | |
458 | if (c->err) return; | |
459 | mp_decode_to_lua_type(L,c); /* value */ | |
460 | if (c->err) return; | |
461 | lua_settable(L,-3); | |
462 | } | |
463 | } | |
464 | ||
465 | /* Decode a Message Pack raw object pointed by the string cursor 'c' to | |
466 | * a Lua type, that is left as the only result on the stack. */ | |
467 | void mp_decode_to_lua_type(lua_State *L, mp_cur *c) { | |
468 | mp_cur_need(c,1); | |
469 | switch(c->p[0]) { | |
470 | case 0xcc: /* uint 8 */ | |
471 | mp_cur_need(c,2); | |
472 | lua_pushnumber(L,c->p[1]); | |
473 | mp_cur_consume(c,2); | |
474 | break; | |
475 | case 0xd0: /* int 8 */ | |
476 | mp_cur_need(c,2); | |
477 | lua_pushnumber(L,(char)c->p[1]); | |
478 | mp_cur_consume(c,2); | |
479 | break; | |
480 | case 0xcd: /* uint 16 */ | |
481 | mp_cur_need(c,3); | |
482 | lua_pushnumber(L, | |
483 | (c->p[1] << 8) | | |
484 | c->p[2]); | |
485 | mp_cur_consume(c,3); | |
486 | break; | |
487 | case 0xd1: /* int 16 */ | |
488 | mp_cur_need(c,3); | |
489 | lua_pushnumber(L,(int16_t) | |
490 | (c->p[1] << 8) | | |
491 | c->p[2]); | |
492 | mp_cur_consume(c,3); | |
493 | break; | |
494 | case 0xce: /* uint 32 */ | |
495 | mp_cur_need(c,5); | |
496 | lua_pushnumber(L, | |
497 | ((uint32_t)c->p[1] << 24) | | |
498 | ((uint32_t)c->p[2] << 16) | | |
499 | ((uint32_t)c->p[3] << 8) | | |
500 | (uint32_t)c->p[4]); | |
501 | mp_cur_consume(c,5); | |
502 | break; | |
503 | case 0xd2: /* int 32 */ | |
504 | mp_cur_need(c,5); | |
505 | lua_pushnumber(L, | |
506 | ((int32_t)c->p[1] << 24) | | |
507 | ((int32_t)c->p[2] << 16) | | |
508 | ((int32_t)c->p[3] << 8) | | |
509 | (int32_t)c->p[4]); | |
510 | mp_cur_consume(c,5); | |
511 | break; | |
512 | case 0xcf: /* uint 64 */ | |
513 | mp_cur_need(c,9); | |
514 | lua_pushnumber(L, | |
515 | ((uint64_t)c->p[1] << 56) | | |
516 | ((uint64_t)c->p[2] << 48) | | |
517 | ((uint64_t)c->p[3] << 40) | | |
518 | ((uint64_t)c->p[4] << 32) | | |
519 | ((uint64_t)c->p[5] << 24) | | |
520 | ((uint64_t)c->p[6] << 16) | | |
521 | ((uint64_t)c->p[7] << 8) | | |
522 | (uint64_t)c->p[8]); | |
523 | mp_cur_consume(c,9); | |
524 | break; | |
525 | case 0xd3: /* int 64 */ | |
526 | mp_cur_need(c,9); | |
527 | lua_pushnumber(L, | |
528 | ((int64_t)c->p[1] << 56) | | |
529 | ((int64_t)c->p[2] << 48) | | |
530 | ((int64_t)c->p[3] << 40) | | |
531 | ((int64_t)c->p[4] << 32) | | |
532 | ((int64_t)c->p[5] << 24) | | |
533 | ((int64_t)c->p[6] << 16) | | |
534 | ((int64_t)c->p[7] << 8) | | |
535 | (int64_t)c->p[8]); | |
536 | mp_cur_consume(c,9); | |
537 | break; | |
538 | case 0xc0: /* nil */ | |
539 | lua_pushnil(L); | |
540 | mp_cur_consume(c,1); | |
541 | break; | |
542 | case 0xc3: /* true */ | |
543 | lua_pushboolean(L,1); | |
544 | mp_cur_consume(c,1); | |
545 | break; | |
546 | case 0xc2: /* false */ | |
547 | lua_pushboolean(L,0); | |
548 | mp_cur_consume(c,1); | |
549 | break; | |
550 | case 0xca: /* float */ | |
551 | mp_cur_need(c,5); | |
552 | assert(sizeof(float) == 4); | |
553 | { | |
554 | float f; | |
555 | memcpy(&f,c->p+1,4); | |
556 | memrevifle(&f,4); | |
557 | lua_pushnumber(L,f); | |
558 | mp_cur_consume(c,5); | |
559 | } | |
560 | break; | |
561 | case 0xcb: /* double */ | |
562 | mp_cur_need(c,9); | |
563 | assert(sizeof(double) == 8); | |
564 | { | |
565 | double d; | |
566 | memcpy(&d,c->p+1,8); | |
567 | memrevifle(&d,8); | |
568 | lua_pushnumber(L,d); | |
569 | mp_cur_consume(c,9); | |
570 | } | |
571 | break; | |
572 | case 0xda: /* raw 16 */ | |
573 | mp_cur_need(c,3); | |
574 | { | |
575 | size_t l = (c->p[1] << 8) | c->p[2]; | |
576 | mp_cur_need(c,3+l); | |
577 | lua_pushlstring(L,(char*)c->p+3,l); | |
578 | mp_cur_consume(c,3+l); | |
579 | } | |
580 | break; | |
581 | case 0xdb: /* raw 32 */ | |
582 | mp_cur_need(c,5); | |
583 | { | |
584 | size_t l = (c->p[1] << 24) | | |
585 | (c->p[2] << 16) | | |
586 | (c->p[3] << 8) | | |
587 | c->p[4]; | |
588 | mp_cur_need(c,5+l); | |
589 | lua_pushlstring(L,(char*)c->p+5,l); | |
590 | mp_cur_consume(c,5+l); | |
591 | } | |
592 | break; | |
593 | case 0xdc: /* array 16 */ | |
594 | mp_cur_need(c,3); | |
595 | { | |
596 | size_t l = (c->p[1] << 8) | c->p[2]; | |
597 | mp_cur_consume(c,3); | |
598 | mp_decode_to_lua_array(L,c,l); | |
599 | } | |
600 | break; | |
601 | case 0xdd: /* array 32 */ | |
602 | mp_cur_need(c,5); | |
603 | { | |
604 | size_t l = (c->p[1] << 24) | | |
605 | (c->p[2] << 16) | | |
606 | (c->p[3] << 8) | | |
607 | c->p[4]; | |
608 | mp_cur_consume(c,5); | |
609 | mp_decode_to_lua_array(L,c,l); | |
610 | } | |
611 | break; | |
612 | case 0xde: /* map 16 */ | |
613 | mp_cur_need(c,3); | |
614 | { | |
615 | size_t l = (c->p[1] << 8) | c->p[2]; | |
616 | mp_cur_consume(c,3); | |
617 | mp_decode_to_lua_hash(L,c,l); | |
618 | } | |
619 | break; | |
620 | case 0xdf: /* map 32 */ | |
621 | mp_cur_need(c,5); | |
622 | { | |
623 | size_t l = (c->p[1] << 24) | | |
624 | (c->p[2] << 16) | | |
625 | (c->p[3] << 8) | | |
626 | c->p[4]; | |
627 | mp_cur_consume(c,5); | |
628 | mp_decode_to_lua_hash(L,c,l); | |
629 | } | |
630 | break; | |
631 | default: /* types that can't be idenitified by first byte value. */ | |
632 | if ((c->p[0] & 0x80) == 0) { /* positive fixnum */ | |
633 | lua_pushnumber(L,c->p[0]); | |
634 | mp_cur_consume(c,1); | |
635 | } else if ((c->p[0] & 0xe0) == 0xe0) { /* negative fixnum */ | |
636 | lua_pushnumber(L,(signed char)c->p[0]); | |
637 | mp_cur_consume(c,1); | |
638 | } else if ((c->p[0] & 0xe0) == 0xa0) { /* fix raw */ | |
639 | size_t l = c->p[0] & 0x1f; | |
640 | mp_cur_need(c,1+l); | |
641 | lua_pushlstring(L,(char*)c->p+1,l); | |
642 | mp_cur_consume(c,1+l); | |
643 | } else if ((c->p[0] & 0xf0) == 0x90) { /* fix map */ | |
644 | size_t l = c->p[0] & 0xf; | |
645 | mp_cur_consume(c,1); | |
646 | mp_decode_to_lua_array(L,c,l); | |
647 | } else if ((c->p[0] & 0xf0) == 0x80) { /* fix map */ | |
648 | size_t l = c->p[0] & 0xf; | |
649 | mp_cur_consume(c,1); | |
650 | mp_decode_to_lua_hash(L,c,l); | |
651 | } else { | |
652 | c->err = MP_CUR_ERROR_BADFMT; | |
653 | } | |
654 | } | |
655 | } | |
656 | ||
657 | static int mp_unpack(lua_State *L) { | |
658 | size_t len; | |
659 | const unsigned char *s; | |
660 | mp_cur *c; | |
661 | ||
662 | if (!lua_isstring(L,-1)) { | |
663 | lua_pushstring(L,"MessagePack decoding needs a string as input."); | |
664 | lua_error(L); | |
665 | } | |
666 | ||
667 | s = (const unsigned char*) lua_tolstring(L,-1,&len); | |
668 | c = mp_cur_new(s,len); | |
669 | mp_decode_to_lua_type(L,c); | |
670 | ||
671 | if (c->err == MP_CUR_ERROR_EOF) { | |
672 | mp_cur_free(c); | |
673 | lua_pushstring(L,"Missing bytes in input."); | |
674 | lua_error(L); | |
675 | } else if (c->err == MP_CUR_ERROR_BADFMT) { | |
676 | mp_cur_free(c); | |
677 | lua_pushstring(L,"Bad data format in input."); | |
678 | lua_error(L); | |
679 | } else if (c->left != 0) { | |
680 | mp_cur_free(c); | |
681 | lua_pushstring(L,"Extra bytes in input."); | |
682 | lua_error(L); | |
683 | } | |
684 | mp_cur_free(c); | |
685 | return 1; | |
686 | } | |
687 | ||
688 | /* ---------------------------------------------------------------------------- */ | |
689 | ||
690 | static const struct luaL_reg thislib[] = { | |
691 | {"pack", mp_pack}, | |
692 | {"unpack", mp_unpack}, | |
693 | {NULL, NULL} | |
694 | }; | |
695 | ||
696 | LUALIB_API int luaopen_cmsgpack (lua_State *L) { | |
697 | luaL_register(L, "cmsgpack", thislib); | |
698 | ||
699 | lua_pushliteral(L, LUACMSGPACK_VERSION); | |
700 | lua_setfield(L, -2, "_VERSION"); | |
701 | lua_pushliteral(L, LUACMSGPACK_COPYRIGHT); | |
702 | lua_setfield(L, -2, "_COPYRIGHT"); | |
703 | lua_pushliteral(L, LUACMSGPACK_DESCRIPTION); | |
704 | lua_setfield(L, -2, "_DESCRIPTION"); | |
705 | return 1; | |
706 | } | |
707 | ||
708 | /****************************************************************************** | |
709 | * Copyright (C) 2012 Salvatore Sanfilippo. All rights reserved. | |
710 | * | |
711 | * Permission is hereby granted, free of charge, to any person obtaining | |
712 | * a copy of this software and associated documentation files (the | |
713 | * "Software"), to deal in the Software without restriction, including | |
714 | * without limitation the rights to use, copy, modify, merge, publish, | |
715 | * distribute, sublicense, and/or sell copies of the Software, and to | |
716 | * permit persons to whom the Software is furnished to do so, subject to | |
717 | * the following conditions: | |
718 | * | |
719 | * The above copyright notice and this permission notice shall be | |
720 | * included in all copies or substantial portions of the Software. | |
721 | * | |
722 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
723 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
724 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
725 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
726 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
727 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
728 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
729 | ******************************************************************************/ |