/************************************************************************ * Author : Tiago Dionizio * * Library : lzlib - Lua 5 interface to access zlib library functions * * * * Permission is hereby granted, free of charge, to any person obtaining * * a copy of this software and associated documentation files (the * * "Software"), to deal in the Software without restriction, including * * without limitation the rights to use, copy, modify, merge, publish, * * distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to * * the following conditions: * * * * The above copyright notice and this permission notice shall be * * included in all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.* * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ************************************************************************/ #include #include #include "nse_lua.h" #include /* ** ========================================================================= ** compile time options which determine available functionality ** ========================================================================= */ /* TODO - also call flush on table/userdata when flush function is detected - remove io_cb check inflate_block if condition - only set eos when ZSTREAM_END is reached - check for stream errors to close stream when really needed */ /* ** ========================================================================= ** zlib stream metamethods ** ========================================================================= */ #define ZSTREAMMETA "zlib:zstream" #define LZ_ANY -1 #define LZ_NONE 0 #define LZ_DEFLATE 1 #define LZ_INFLATE 2 #if 0 #define LZ_BUFFER_SIZE LUAL_BUFFERSIZE #else #define LZ_BUFFER_SIZE 8192 #endif typedef struct { /* zlib structures */ z_stream zstream; /* stream state. LZ_DEFLATE | LZ_INFLATE */ int state; int error; int peek; int eos; /* user callback source for reading/writing */ int io_cb; /* input buffer */ int i_buffer_ref; size_t i_buffer_pos; size_t i_buffer_len; const char *i_buffer; /* output buffer */ size_t o_buffer_len; size_t o_buffer_max; char o_buffer[LZ_BUFFER_SIZE]; /* dictionary */ const Bytef *dictionary; size_t dictionary_len; } lz_stream; /* forward declarations */ static int lzstream_docompress(lua_State *L, lz_stream *s, int from, int to, int flush); static lz_stream *lzstream_new(lua_State *L, int src) { lz_stream *s = (lz_stream*)lua_newuserdata(L, sizeof(lz_stream)); luaL_getmetatable(L, ZSTREAMMETA); lua_setmetatable(L, -2); /* set metatable */ s->state = LZ_NONE; s->error = Z_OK; s->eos = 0; s->io_cb = LUA_REFNIL; s->i_buffer = NULL; s->i_buffer_ref = LUA_REFNIL; s->i_buffer_pos = 0; s->i_buffer_len = 0; s->peek = 0; s->o_buffer_len = 0; s->o_buffer_max = sizeof(s->o_buffer) / sizeof(s->o_buffer[0]); s->zstream.zalloc = Z_NULL; s->zstream.zfree = Z_NULL; /* prepare source */ if (lua_isstring(L, src)) { lua_pushvalue(L, src); s->i_buffer_ref = luaL_ref(L, LUA_REGISTRYINDEX); s->i_buffer = lua_tolstring(L, src, &s->i_buffer_len); } else { /* table | function | userdata */ lua_pushvalue(L, src); s->io_cb = luaL_ref(L, LUA_REGISTRYINDEX); } return s; } static void lzstream_cleanup(lua_State *L, lz_stream *s) { if (s && s->state != LZ_NONE) { if (s->state == LZ_INFLATE) { inflateEnd(&s->zstream); } if (s->state == LZ_DEFLATE) { deflateEnd(&s->zstream); } luaL_unref(L, LUA_REGISTRYINDEX, s->io_cb); luaL_unref(L, LUA_REGISTRYINDEX, s->i_buffer_ref); s->state = LZ_NONE; } } /* ====================================================================== */ static lz_stream *lzstream_get(lua_State *L, int index) { lz_stream *s = (lz_stream*)luaL_checkudata(L, index, ZSTREAMMETA); if (s == NULL) luaL_argerror(L, index, "bad zlib stream"); return s; } static lz_stream *lzstream_check(lua_State *L, int index, int state) { lz_stream *s = lzstream_get(L, index); if ((state != LZ_ANY && s->state != state) || s->state == LZ_NONE) { luaL_argerror(L, index, "attempt to use invalid zlib stream"); } return s; } /* ====================================================================== */ static int lzstream_tostring(lua_State *L) { lz_stream *s = (lz_stream*)luaL_checkudata(L, 1, ZSTREAMMETA); if (s == NULL) luaL_argerror(L, 1, "bad zlib stream"); if (s->state == LZ_NONE) { lua_pushstring(L, "zlib stream (closed)"); } else if (s->state == LZ_DEFLATE) { lua_pushfstring(L, "zlib deflate stream (%p)", (void*)s); } else if (s->state == LZ_INFLATE) { lua_pushfstring(L, "zlib inflate stream (%p)", (void*)s); } else { lua_pushfstring(L, "%p", (void*)s); } return 1; } /* ====================================================================== */ static int lzstream_gc(lua_State *L) { lz_stream *s = lzstream_get(L, 1); lzstream_cleanup(L, s); return 0; } /* ====================================================================== */ static int lzstream_close(lua_State *L) { lz_stream *s = lzstream_get(L, 1); if (s->state == LZ_DEFLATE) { lua_settop(L, 0); lua_pushliteral(L, ""); return lzstream_docompress(L, s, 1, 1, Z_FINISH); } lzstream_cleanup(L, s); lua_pushboolean(L, 1); return 1; } /* ====================================================================== */ static int lzstream_adler(lua_State *L) { lz_stream *s = lzstream_check(L, 1, LZ_ANY); lua_pushnumber(L, s->zstream.adler); return 1; } /* ====================================================================== */ /* zlib.deflate( sink: function | { write: function [, close: function, flush: function] }, compression level, [Z_DEFAILT_COMPRESSION] method, [Z_DEFLATED] windowBits, [15] memLevel, [8] strategy, [Z_DEFAULT_STRATEGY] dictionary: [""] ) */ static int lzlib_deflate(lua_State *L) { int level, method, windowBits, memLevel, strategy; lz_stream *s; const char *dictionary; size_t dictionary_len; if (lua_istable(L, 1) || lua_isuserdata(L, 1)) { /* is there a :write function? */ lua_getfield(L, 1, "write"); if (!lua_isfunction(L, -1)) { luaL_argerror(L, 1, "output parameter does not provide :write function"); } lua_pop(L, 1); } else if (!lua_isfunction(L, 1)) { luaL_argerror(L, 1, "output parameter must be a function, table or userdata value"); } level = (int) luaL_optinteger(L, 2, Z_DEFAULT_COMPRESSION); method = (int) luaL_optinteger(L, 3, Z_DEFLATED); windowBits = (int) luaL_optinteger(L, 4, 15); memLevel = (int) luaL_optinteger(L, 5, 8); strategy = (int) luaL_optinteger(L, 6, Z_DEFAULT_STRATEGY); dictionary = luaL_optlstring(L, 7, NULL, &dictionary_len); s = lzstream_new(L, 1); if (deflateInit2(&s->zstream, level, method, windowBits, memLevel, strategy) != Z_OK) { lua_pushliteral(L, "call to deflateInit2 failed"); lua_error(L); } if (dictionary) { if (deflateSetDictionary(&s->zstream, (const Bytef *) dictionary, dictionary_len) != Z_OK) { lua_pushliteral(L, "call to deflateSetDictionnary failed"); lua_error(L); } } s->state = LZ_DEFLATE; return 1; } /* zlib.inflate( source: string | function | { read: function, close: function }, windowBits: number, [15] dictionary: [""] ) */ static int lzlib_inflate(lua_State *L) { int windowBits; lz_stream *s; int have_peek = 0; const char *dictionary; size_t dictionary_len; if (lua_istable(L, 1) || lua_isuserdata(L, 1)) { /* is there a :read function? */ lua_getfield(L, 1, "read"); if (!lua_isfunction(L, -1)) { luaL_argerror(L, 1, "input parameter does not provide :read function"); } lua_pop(L, 1); /* check for peek function */ lua_getfield(L, 1, "peek"); have_peek = lua_isfunction(L, -1); lua_pop(L, 1); } else if (!lua_isstring(L, 1) && !lua_isfunction(L, 1)) { luaL_argerror(L, 1, "input parameter must be a string, function, table or userdata value"); } windowBits = (int) luaL_optinteger(L, 2, 15); dictionary = luaL_optlstring(L, 3, NULL, &dictionary_len); s = lzstream_new(L, 1); if (windowBits > 0 && windowBits < 16) { windowBits |= 32; } if (inflateInit2(&s->zstream, windowBits) != Z_OK) { lua_pushliteral(L, "call to inflateInit2 failed"); lua_error(L); } if (dictionary) { s->dictionary = (const Bytef *) dictionary; s->dictionary_len = dictionary_len; } s->peek = have_peek; s->state = LZ_INFLATE; return 1; } /* ====================================================================== */ static int lz_pushresult (lua_State *L, lz_stream *s) { if (s->error == Z_OK) { lua_pushboolean(L, 1); return 1; } else { lua_pushnil(L); lua_pushstring(L, zError(s->error)); lua_pushinteger(L, s->error); return 3; } } /* Get block to process: - top of stack gets */ static const char* lzstream_fetch_block(lua_State *L, lz_stream *s, int hint) { if (s->i_buffer_pos >= s->i_buffer_len) { luaL_unref(L, LUA_REGISTRYINDEX, s->i_buffer_ref); s->i_buffer_ref = LUA_NOREF; s->i_buffer = NULL; lua_rawgeti(L, LUA_REGISTRYINDEX, s->io_cb); if (!lua_isnil(L, -1)) { if (lua_isfunction(L, -1)) { lua_pushinteger(L, hint); lua_call(L, 1, 1); } else { lua_getfield(L, -1, (s->peek ? "peek" : "read")); lua_insert(L, -2); lua_pushinteger(L, hint); lua_call(L, 2, 1); } if (lua_isstring(L, -1)) { s->i_buffer_pos = 0; s->i_buffer = lua_tolstring(L, -1, &s->i_buffer_len); if (s->i_buffer_len > 0) { s->i_buffer_ref = luaL_ref(L, LUA_REGISTRYINDEX); } else { lua_pop(L, 1); } } else if (lua_isnil(L, -1)) { lua_pop(L, 1); } else { lua_pushliteral(L, "deflate callback must return string or nil"); lua_error(L); } } else { lua_pop(L, 1); } } return s->i_buffer; } static int lzstream_inflate_block(lua_State *L, lz_stream *s) { if (lzstream_fetch_block(L, s, LZ_BUFFER_SIZE) || !s->eos) { int r; if (s->i_buffer_len == s->i_buffer_pos) { s->zstream.next_in = NULL; s->zstream.avail_in = 0; } else { s->zstream.next_in = (unsigned char*)(s->i_buffer + s->i_buffer_pos); s->zstream.avail_in = s->i_buffer_len - s->i_buffer_pos; } s->zstream.next_out = (unsigned char*)s->o_buffer + s->o_buffer_len; s->zstream.avail_out = s->o_buffer_max - s->o_buffer_len; /* munch some more */ r = inflate(&s->zstream, Z_SYNC_FLUSH); if (r == Z_NEED_DICT) { if (s->dictionary == NULL) { lua_pushliteral(L, "no inflate dictionary provided"); lua_error(L); } if (inflateSetDictionary(&s->zstream, s->dictionary, s->dictionary_len) != Z_OK) { lua_pushliteral(L, "call to inflateSetDictionnary failed"); lua_error(L); } r = inflate(&s->zstream, Z_SYNC_FLUSH); } if (r != Z_OK && r != Z_STREAM_END && r != Z_BUF_ERROR) { lzstream_cleanup(L, s); s->error = r; #if 1 lua_pushfstring(L, "failed to decompress [%d]", r); lua_error(L); #endif } if (r == Z_STREAM_END) { luaL_unref(L, LUA_REGISTRYINDEX, s->i_buffer_ref); s->i_buffer_ref = LUA_NOREF; s->i_buffer = NULL; s->eos = 1; } /* number of processed bytes */ if (s->peek) { size_t processed = s->i_buffer_len - s->i_buffer_pos - s->zstream.avail_in; lua_rawgeti(L, LUA_REGISTRYINDEX, s->io_cb); lua_getfield(L, -1, "read"); lua_insert(L, -2); lua_pushinteger(L, processed); lua_call(L, 2, 0); } s->i_buffer_pos = s->i_buffer_len - s->zstream.avail_in; s->o_buffer_len = s->o_buffer_max - s->zstream.avail_out; } return s->o_buffer_len; } /* ** Remove n bytes from the output buffer. */ static void lzstream_remove(lz_stream *s, size_t n) { memmove(s->o_buffer, s->o_buffer + n, s->o_buffer_len - n); s->o_buffer_len -= n; } /* ** Copy at most n bytes to buffer b and remove them from the ** output stream buffer. */ static int lzstream_flush_buffer(lua_State *L, lz_stream *s, size_t n, luaL_Buffer *b) { /* check output */ if (n > s->o_buffer_len) { n = s->o_buffer_len; } if (n > 0) { lua_pushlstring(L, s->o_buffer, n); luaL_addvalue(b); lzstream_remove(s, n); } return n; } /* z:read( {number | '*l' | '*a'}* ) */ static int lz_test_eof(lua_State *L, lz_stream *s) { lua_pushlstring(L, NULL, 0); if (s->o_buffer_len > 0) { return 1; } else if (s->eos) { return 0; } else { return lzstream_inflate_block(L, s); } } static int lz_read_line(lua_State *L, lz_stream *s) { luaL_Buffer b; size_t l = 0, n; luaL_buffinit(L, &b); if (s->o_buffer_len > 0 || !s->eos) do { char *p = s->o_buffer; size_t len = s->o_buffer_len; /* find newline in output buffer */ for (n = 0; n < len; ++n, ++p) { if (*p == '\n' || *p == '\r') { int eat_nl = *p == '\r'; luaL_addlstring(&b, s->o_buffer, n); lzstream_remove(s, n+1); l += n; if (eat_nl && lzstream_inflate_block(L, s)) { if (s->o_buffer_len > 0 && *s->o_buffer == '\n') { lzstream_remove(s, 1); } } luaL_pushresult(&b); return 1; } } if (len > 0) { luaL_addlstring(&b, s->o_buffer, len); lzstream_remove(s, len); l += len; } } while (lzstream_inflate_block(L, s)); luaL_pushresult(&b); return l > 0 || !s->eos || s->o_buffer_len > 0; } static int lz_read_chars(lua_State *L, lz_stream *s, size_t n) { size_t len; luaL_Buffer b; luaL_buffinit(L, &b); if (s->o_buffer_len > 0 || !s->eos) do { size_t rlen = lzstream_flush_buffer(L, s, n, &b); n -= rlen; } while (n > 0 && lzstream_inflate_block(L, s)); luaL_pushresult(&b); lua_tolstring(L, -1, &len); return n == 0 || len > 0; } static int lzstream_decompress(lua_State *L) { lz_stream *s = lzstream_check(L, 1, LZ_INFLATE); int nargs = lua_gettop(L) - 1; int success; int n; if (nargs == 0) { /* no arguments? */ success = lz_read_line(L, s); n = 3; /* to return 1 result */ } else { /* ensure stack space for all results and for auxlib's buffer */ luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); success = 1; for (n = 2; nargs-- && success; n++) { if (lua_type(L, n) == LUA_TNUMBER) { size_t l = (size_t)lua_tointeger(L, n); success = (l == 0) ? lz_test_eof(L, s) : lz_read_chars(L, s, l); } else { const char *p = lua_tostring(L, n); luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); switch (p[1]) { case 'l': /* line */ success = lz_read_line(L, s); break; case 'a': /* file */ lz_read_chars(L, s, ~((size_t)0)); /* read MAX_SIZE_T chars */ success = 1; /* always success */ break; default: return luaL_argerror(L, n, "invalid format"); } } } } if (s->error != Z_OK) { return lz_pushresult(L, s); } if (!success) { lua_pop(L, 1); /* remove last result */ lua_pushnil(L); /* push nil instead */ } return n - 2; } static int lzstream_readline(lua_State *L) { lz_stream *s; int success; s = lzstream_check(L, lua_upvalueindex(1), LZ_INFLATE); success = lz_read_line(L, s); if (s->error != Z_OK) { return lz_pushresult(L, s); } if (success) { return 1; } else { /* EOF */ return 0; } } static int lzstream_lines(lua_State *L) { lzstream_check(L, 1, LZ_INFLATE); lua_settop(L, 1); lua_pushcclosure(L, lzstream_readline, 1); return 1; } /* ====================================================================== */ static int lzstream_docompress(lua_State *L, lz_stream *s, int from, int to, int flush) { int r, arg; int self = 0; size_t b_size = s->o_buffer_max; unsigned char *b = (unsigned char *)s->o_buffer; /* number of processed bytes */ lua_rawgeti(L, LUA_REGISTRYINDEX, s->io_cb); if (!lua_isfunction(L, -1)) { self = 1; lua_getfield(L, -1, "write"); } for (arg = from; arg <= to; arg++) { s->zstream.next_in = (unsigned char*)luaL_checklstring(L, arg, (size_t*)&s->zstream.avail_in); do { s->zstream.next_out = b; s->zstream.avail_out = b_size; /* bake some more */ r = deflate(&s->zstream, flush); if (r != Z_OK && r != Z_STREAM_END && r != Z_BUF_ERROR) { lzstream_cleanup(L, s); lua_pushboolean(L, 0); lua_pushfstring(L, "failed to compress [%d]", r); return 2; } if (s->zstream.avail_out != b_size) { /* write output */ lua_pushvalue(L, -1); /* function */ if (self) lua_pushvalue(L, -3); /* self */ lua_pushlstring(L, (char*)b, b_size - s->zstream.avail_out); /* data */ lua_call(L, (self ? 2 : 1), 0); } if (r == Z_STREAM_END) { lzstream_cleanup(L, s); break; } /* process all input */ } while (s->zstream.avail_in > 0 || s->zstream.avail_out == 0); } lua_pushboolean(L, 1); return 1; } static int lzstream_compress(lua_State *L) { lz_stream *s = lzstream_check(L, 1, LZ_DEFLATE); return lzstream_docompress(L, s, 2, lua_gettop(L), Z_NO_FLUSH); } /* ====================================================================== */ static int lzstream_flush(lua_State *L) { static int flush_values[] = { Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH }; static const char *const flush_opts[] = { "sync", "full", "finish" }; lz_stream *s = lzstream_check(L, 1, LZ_DEFLATE); int flush = luaL_checkoption(L, 2, flush_opts[0], flush_opts); lua_settop(L, 0); lua_pushliteral(L, ""); return lzstream_docompress(L, s, 1, 1, flush_values[flush]); } /* ** ========================================================================= ** zlib functions ** ========================================================================= */ static int lzlib_version(lua_State *L) { lua_pushstring(L, zlibVersion()); return 1; } /* ====================================================================== */ static int lzlib_adler32(lua_State *L) { if (lua_gettop(L) == 0) { /* adler32 initial value */ lua_pushnumber(L, adler32(0L, Z_NULL, 0)); } else { /* update adler32 checksum */ size_t len; int adler = (int) luaL_checkinteger(L, 1); const unsigned char* buf = (unsigned char*)luaL_checklstring(L, 2, &len); lua_pushnumber(L, adler32(adler, buf, len)); } return 1; } /* ====================================================================== */ static int lzlib_crc32(lua_State *L) { if (lua_gettop(L) == 0) { /* crc32 initial value */ lua_pushnumber(L, crc32(0L, Z_NULL, 0)); } else { /* update crc32 checksum */ size_t len; int crc = (int) luaL_checkinteger(L, 1); const unsigned char* buf = (unsigned char*)luaL_checklstring(L, 2, &len); lua_pushnumber(L, crc32(crc, buf, len)); } return 1; } /* ====================================================================== */ static int lzlib_compress(lua_State *L) { size_t avail_in; const char *next_in = luaL_checklstring(L, 1, &avail_in); int level = (int) luaL_optinteger(L, 2, Z_DEFAULT_COMPRESSION); int method = (int) luaL_optinteger(L, 3, Z_DEFLATED); int windowBits = (int) luaL_optinteger(L, 4, 15); int memLevel = (int) luaL_optinteger(L, 5, 8); int strategy = (int) luaL_optinteger(L, 6, Z_DEFAULT_STRATEGY); int ret; luaL_Buffer b; z_stream zs; luaL_buffinit(L, &b); zs.zalloc = Z_NULL; zs.zfree = Z_NULL; zs.next_out = Z_NULL; zs.avail_out = 0; zs.next_in = Z_NULL; zs.avail_in = 0; ret = deflateInit2(&zs, level, method, windowBits, memLevel, strategy); if (ret != Z_OK) { lua_pushnil(L); lua_pushnumber(L, ret); return 2; } zs.next_in = (unsigned char*)next_in; zs.avail_in = avail_in; for(;;) { zs.next_out = (unsigned char*)luaL_prepbuffer(&b); zs.avail_out = LUAL_BUFFERSIZE; /* munch some more */ ret = deflate(&zs, Z_FINISH); /* push gathered data */ luaL_addsize(&b, LUAL_BUFFERSIZE - zs.avail_out); /* done processing? */ if (ret == Z_STREAM_END) break; /* error condition? */ if (ret != Z_OK) break; } /* cleanup */ deflateEnd(&zs); luaL_pushresult(&b); lua_pushnumber(L, ret); return 2; } /* ====================================================================== */ static int lzlib_decompress(lua_State *L) { size_t avail_in; const char *next_in = luaL_checklstring(L, 1, &avail_in); int windowBits = (int) luaL_optinteger(L, 2, 15); int ret; luaL_Buffer b; z_stream zs; luaL_buffinit(L, &b); zs.zalloc = Z_NULL; zs.zfree = Z_NULL; zs.next_out = Z_NULL; zs.avail_out = 0; zs.next_in = Z_NULL; zs.avail_in = 0; ret = inflateInit2(&zs, windowBits); if (ret != Z_OK) { lua_pushliteral(L, "failed to initialize zstream structures"); lua_error(L); } zs.next_in = (unsigned char*)next_in; zs.avail_in = avail_in; for (;;) { zs.next_out = (unsigned char*)luaL_prepbuffer(&b); zs.avail_out = LUAL_BUFFERSIZE; /* bake some more */ ret = inflate(&zs, Z_FINISH); /* push gathered data */ luaL_addsize(&b, LUAL_BUFFERSIZE - zs.avail_out); /* done processing? */ if (ret == Z_STREAM_END) break; if (ret != Z_OK && ret != Z_BUF_ERROR) { /* cleanup */ inflateEnd(&zs); lua_pushliteral(L, "failed to process zlib stream"); lua_error(L); } } /* cleanup */ inflateEnd(&zs); luaL_pushresult(&b); return 1; } /* ** ========================================================================= ** Register functions ** ========================================================================= */ #if (LUA_VERSION_NUM >= 502) #define luaL_register(L,n,f) luaL_setfuncs(L,f,0) #endif LUALIB_API int luaopen_zlib(lua_State *L) { const luaL_Reg lzstream_meta[] = { {"write", lzstream_compress }, {"read", lzstream_decompress }, {"lines", lzstream_lines }, {"flush", lzstream_flush }, {"close", lzstream_close }, {"adler", lzstream_adler }, {"__tostring", lzstream_tostring }, {"__gc", lzstream_gc }, {NULL, NULL} }; const luaL_Reg zlib[] = { {"version", lzlib_version }, {"adler32", lzlib_adler32 }, {"crc32", lzlib_crc32 }, {"deflate", lzlib_deflate }, {"inflate", lzlib_inflate }, {"compress", lzlib_compress }, {"decompress", lzlib_decompress }, {NULL, NULL} }; /* ====================================================================== */ /* create new metatable for zlib compression structures */ luaL_newmetatable(L, ZSTREAMMETA); lua_pushliteral(L, "__index"); lua_pushvalue(L, -2); /* push metatable */ lua_rawset(L, -3); /* metatable.__index = metatable */ /* ** Stack: metatable */ luaL_register(L, NULL, lzstream_meta); lua_pop(L, 1); /* remove metatable from stack */ /* ** Stack: */ lua_newtable(L); lua_pushliteral (L, "_COPYRIGHT"); lua_pushliteral (L, "Copyright (C) 2003-2010 Tiago Dionizio"); lua_settable (L, -3); lua_pushliteral (L, "_DESCRIPTION"); lua_pushliteral (L, "Lua 5 interface to access zlib library functions"); lua_settable (L, -3); lua_pushliteral (L, "_VERSION"); lua_pushliteral (L, "lzlib 0.4-work3"); lua_settable (L, -3); #define PUSH_LITERAL(name) \ lua_pushliteral (L, #name); \ lua_pushinteger (L, Z_##name); \ lua_settable (L, -3); #define PUSH_NUMBER(name, value) \ lua_pushliteral (L, #name); \ lua_pushinteger (L, value); \ lua_settable (L, -3); PUSH_LITERAL(NO_COMPRESSION) PUSH_LITERAL(BEST_SPEED) PUSH_LITERAL(BEST_COMPRESSION) PUSH_LITERAL(DEFAULT_COMPRESSION) PUSH_LITERAL(FILTERED) PUSH_LITERAL(HUFFMAN_ONLY) #ifdef Z_RLE PUSH_LITERAL(RLE) #endif #ifdef Z_FIXED PUSH_LITERAL(FIXED) #endif PUSH_LITERAL(DEFAULT_STRATEGY) PUSH_NUMBER(MINIMUM_MEMLEVEL, 1) PUSH_NUMBER(MAXIMUM_MEMLEVEL, 9) PUSH_NUMBER(DEFAULT_MEMLEVEL, 8) PUSH_NUMBER(DEFAULT_WINDOWBITS, 15) PUSH_NUMBER(MINIMUM_WINDOWBITS, 8) PUSH_NUMBER(MAXIMUM_WINDOWBITS, 15) PUSH_NUMBER(GZIP_WINDOWBITS, 16) PUSH_NUMBER(RAW_WINDOWBITS, -1) luaL_register(L, NULL, zlib); /* ** Stack: zlib table */ return 1; }