3 * A Lua library for serializing and deserializing Lua values
4 * Richard Hundt <richardhundt@gmail.com>
8 * Copyright (c) 2010 Richard Hundt
10 * Permission is hereby granted, free of charge, to any person
11 * obtaining a copy of this software and associated documentation
12 * files (the "Software"), to deal in the Software without
13 * restriction, including without limitation the rights to use,
14 * copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following
19 * The above copyright notice and this permission notice shall be
20 * included in all copies or substantial portions of the Software.
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
24 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
29 * OTHER DEALINGS IN THE SOFTWARE.
49 #define MAR_MAGIC 0x8e
52 typedef struct mar_Buffer {
59 static int mar_encode_table(lua_State *L, mar_Buffer *buf, size_t *idx);
60 static int mar_decode_table(lua_State *L, const char* buf, size_t len, size_t *idx);
62 static void buf_init(lua_State *L, mar_Buffer *buf)
67 if (!(buf->data = malloc(buf->size))) luaL_error(L, "Out of memory!");
70 static void buf_done(lua_State* L, mar_Buffer *buf)
75 static int buf_write(lua_State* L, const char* str, size_t len, mar_Buffer *buf)
77 if (len > UINT32_MAX) luaL_error(L, "buffer too long");
78 if (buf->size - buf->head < len) {
79 size_t new_size = buf->size << 1;
80 size_t cur_head = buf->head;
81 while (new_size - cur_head <= len) {
82 new_size = new_size << 1;
84 if (!(buf->data = realloc(buf->data, new_size))) {
85 luaL_error(L, "Out of memory!");
89 memcpy(&buf->data[buf->head], str, len);
94 static const char* buf_read(lua_State *L, mar_Buffer *buf, size_t *len)
96 if (buf->seek < buf->head) {
97 buf->seek = buf->head;
105 static void mar_encode_value(lua_State *L, mar_Buffer *buf, int val, size_t *idx)
108 int val_type = lua_type(L, val);
109 lua_pushvalue(L, val);
111 buf_write(L, (void*)&val_type, MAR_CHR, buf);
114 int int_val = lua_toboolean(L, -1);
115 buf_write(L, (void*)&int_val, MAR_CHR, buf);
119 const char *str_val = lua_tolstring(L, -1, &l);
120 buf_write(L, (void*)&l, MAR_I32, buf);
121 buf_write(L, str_val, l, buf);
125 lua_Number num_val = lua_tonumber(L, -1);
126 buf_write(L, (void*)&num_val, MAR_I64, buf);
131 lua_pushvalue(L, -1);
132 lua_rawget(L, SEEN_IDX);
133 if (!lua_isnil(L, -1)) {
134 ref = lua_tointeger(L, -1);
136 buf_write(L, (void*)&tag, MAR_CHR, buf);
137 buf_write(L, (void*)&ref, MAR_I32, buf);
142 lua_pop(L, 1); /* pop nil */
143 if (luaL_getmetafield(L, -1, "__persist")) {
146 lua_pushvalue(L, -2); /* self */
148 if (!lua_isfunction(L, -1)) {
149 luaL_error(L, "__persist must return a function");
152 lua_remove(L, -2); /* __persist */
155 lua_pushvalue(L, -2); /* callback */
156 lua_rawseti(L, -2, 1);
158 buf_init(L, &rec_buf);
159 mar_encode_table(L, &rec_buf, idx);
161 buf_write(L, (void*)&tag, MAR_CHR, buf);
162 buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
163 buf_write(L, rec_buf.data, rec_buf.head, buf);
164 buf_done(L, &rec_buf);
170 lua_pushvalue(L, -1);
171 lua_pushinteger(L, (*idx)++);
172 lua_rawset(L, SEEN_IDX);
174 lua_pushvalue(L, -1);
175 buf_init(L, &rec_buf);
176 mar_encode_table(L, &rec_buf, idx);
179 buf_write(L, (void*)&tag, MAR_CHR, buf);
180 buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
181 buf_write(L, rec_buf.data,rec_buf.head, buf);
182 buf_done(L, &rec_buf);
187 case LUA_TFUNCTION: {
189 lua_pushvalue(L, -1);
190 lua_rawget(L, SEEN_IDX);
191 if (!lua_isnil(L, -1)) {
192 ref = lua_tointeger(L, -1);
194 buf_write(L, (void*)&tag, MAR_CHR, buf);
195 buf_write(L, (void*)&ref, MAR_I32, buf);
202 lua_pop(L, 1); /* pop nil */
204 lua_pushvalue(L, -1);
205 lua_getinfo(L, ">nuS", &ar);
206 if (ar.what[0] != 'L') {
207 luaL_error(L, "attempt to persist a C function '%s'", ar.name);
210 lua_pushvalue(L, -1);
211 lua_pushinteger(L, (*idx)++);
212 lua_rawset(L, SEEN_IDX);
214 lua_pushvalue(L, -1);
215 buf_init(L, &rec_buf);
216 lua_dump(L, (lua_Writer)buf_write, &rec_buf);
218 buf_write(L, (void*)&tag, MAR_CHR, buf);
219 buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
220 buf_write(L, rec_buf.data, rec_buf.head, buf);
221 buf_done(L, &rec_buf);
225 for (i=1; i <= ar.nups; i++) {
226 lua_getupvalue(L, -2, i);
227 lua_rawseti(L, -2, i);
230 buf_init(L, &rec_buf);
231 mar_encode_table(L, &rec_buf, idx);
233 buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
234 buf_write(L, rec_buf.data, rec_buf.head, buf);
235 buf_done(L, &rec_buf);
241 case LUA_TUSERDATA: {
243 lua_pushvalue(L, -1);
244 lua_rawget(L, SEEN_IDX);
245 if (!lua_isnil(L, -1)) {
246 ref = lua_tointeger(L, -1);
248 buf_write(L, (void*)&tag, MAR_CHR, buf);
249 buf_write(L, (void*)&ref, MAR_I32, buf);
254 lua_pop(L, 1); /* pop nil */
255 if (luaL_getmetafield(L, -1, "__persist")) {
258 lua_pushvalue(L, -2);
259 lua_pushinteger(L, (*idx)++);
260 lua_rawset(L, SEEN_IDX);
262 lua_pushvalue(L, -2);
264 if (!lua_isfunction(L, -1)) {
265 luaL_error(L, "__persist must return a function");
268 lua_pushvalue(L, -2);
269 lua_rawseti(L, -2, 1);
272 buf_init(L, &rec_buf);
273 mar_encode_table(L, &rec_buf, idx);
275 buf_write(L, (void*)&tag, MAR_CHR, buf);
276 buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
277 buf_write(L, rec_buf.data, rec_buf.head, buf);
278 buf_done(L, &rec_buf);
281 luaL_error(L, "attempt to encode userdata (no __persist hook)");
287 case LUA_TNIL: break;
289 luaL_error(L, "invalid value type (%s)", lua_typename(L, val_type));
294 static int mar_encode_table(lua_State *L, mar_Buffer *buf, size_t *idx)
297 while (lua_next(L, -2) != 0) {
298 mar_encode_value(L, buf, -2, idx);
299 mar_encode_value(L, buf, -1, idx);
305 #define mar_incr_ptr(l) \
306 if (((*p)-buf)+(l) > len) luaL_error(L, "bad code"); (*p) += (l);
308 #define mar_next_len(l,T) \
309 if (((*p)-buf)+sizeof(T) > len) luaL_error(L, "bad code"); \
310 l = *(T*)*p; (*p) += sizeof(T);
312 static void mar_decode_value
313 (lua_State *L, const char *buf, size_t len, const char **p, size_t *idx)
317 mar_incr_ptr(MAR_CHR);
320 lua_pushboolean(L, *(char*)*p);
321 mar_incr_ptr(MAR_CHR);
324 lua_pushnumber(L, *(lua_Number*)*p);
325 mar_incr_ptr(MAR_I64);
328 mar_next_len(l, uint32_t);
329 lua_pushlstring(L, *p, l);
333 char tag = *(char*)*p;
334 mar_incr_ptr(MAR_CHR);
335 if (tag == MAR_TREF) {
337 mar_next_len(ref, int);
338 lua_rawgeti(L, SEEN_IDX, ref);
340 else if (tag == MAR_TVAL) {
341 mar_next_len(l, uint32_t);
343 lua_pushvalue(L, -1);
344 lua_rawseti(L, SEEN_IDX, (*idx)++);
345 mar_decode_table(L, *p, l, idx);
348 else if (tag == MAR_TUSR) {
349 mar_next_len(l, uint32_t);
351 mar_decode_table(L, *p, l, idx);
352 lua_rawgeti(L, -1, 1);
355 lua_pushvalue(L, -1);
356 lua_rawseti(L, SEEN_IDX, (*idx)++);
360 luaL_error(L, "bad encoded data");
364 case LUA_TFUNCTION: {
368 char tag = *(char*)*p;
370 if (tag == MAR_TREF) {
372 mar_next_len(ref, int);
373 lua_rawgeti(L, SEEN_IDX, ref);
376 mar_next_len(l, uint32_t);
377 dec_buf.data = (char*)*p;
381 lua_load(L, (lua_Reader)buf_read, &dec_buf, "=marshal");
384 lua_pushvalue(L, -1);
385 lua_rawseti(L, SEEN_IDX, (*idx)++);
387 mar_next_len(l, uint32_t);
389 mar_decode_table(L, *p, l, idx);
390 nups = lua_objlen(L, -1);
391 for (i=1; i <= nups; i++) {
392 lua_rawgeti(L, -1, i);
393 lua_setupvalue(L, -3, i);
400 case LUA_TUSERDATA: {
401 char tag = *(char*)*p;
402 mar_incr_ptr(MAR_CHR);
403 if (tag == MAR_TREF) {
405 mar_next_len(ref, int);
406 lua_rawgeti(L, SEEN_IDX, ref);
408 else if (tag == MAR_TUSR) {
409 mar_next_len(l, uint32_t);
411 mar_decode_table(L, *p, l, idx);
412 lua_rawgeti(L, -1, 1);
415 lua_pushvalue(L, -1);
416 lua_rawseti(L, SEEN_IDX, (*idx)++);
419 else { /* tag == MAR_TVAL */
429 luaL_error(L, "bad code");
433 static int mar_decode_table(lua_State *L, const char* buf, size_t len, size_t *idx)
437 while (p - buf < len) {
438 mar_decode_value(L, buf, len, &p, idx);
439 mar_decode_value(L, buf, len, &p, idx);
445 static int mar_encode(lua_State* L)
447 const unsigned char m = MAR_MAGIC;
451 if (lua_isnone(L, 1)) {
454 if (lua_isnoneornil(L, 2)) {
457 else if (!lua_istable(L, 2)) {
458 luaL_error(L, "bad argument #2 to encode (expected table)");
462 len = lua_objlen(L, 2);
464 for (idx = 1; idx <= len; idx++) {
465 lua_rawgeti(L, 2, idx);
466 if (lua_isnil(L, -1)) {
470 lua_pushinteger(L, idx);
471 lua_rawset(L, SEEN_IDX);
476 buf_write(L, (void*)&m, 1, &buf);
478 mar_encode_value(L, &buf, -1, &idx);
482 lua_pushlstring(L, buf.data, buf.head);
486 lua_remove(L, SEEN_IDX);
491 static int mar_decode(lua_State* L)
495 const char *s = luaL_checklstring(L, 1, &l);
497 if (l < 1) luaL_error(L, "bad header");
498 if (*(unsigned char *)s++ != MAR_MAGIC) luaL_error(L, "bad magic");
501 if (lua_isnoneornil(L, 2)) {
504 else if (!lua_istable(L, 2)) {
505 luaL_error(L, "bad argument #2 to decode (expected table)");
509 len = lua_objlen(L, 2);
511 for (idx = 1; idx <= len; idx++) {
512 lua_rawgeti(L, 2, idx);
513 lua_rawseti(L, SEEN_IDX, idx);
517 mar_decode_value(L, s, l, &p, &idx);
519 lua_remove(L, SEEN_IDX);
525 static int mar_clone(lua_State* L)
533 static const luaL_reg R[] =
535 {"encode", mar_encode},
536 {"decode", mar_decode},
537 {"clone", mar_clone},
541 int luaopen_marshal(lua_State *L)
544 luaL_register(L, "marshal", R);