summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/lua-zlib/lua_zlib.c
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/lua-zlib/lua_zlib.c')
-rw-r--r--3rdparty/lua-zlib/lua_zlib.c401
1 files changed, 401 insertions, 0 deletions
diff --git a/3rdparty/lua-zlib/lua_zlib.c b/3rdparty/lua-zlib/lua_zlib.c
new file mode 100644
index 00000000000..b619258c75f
--- /dev/null
+++ b/3rdparty/lua-zlib/lua_zlib.c
@@ -0,0 +1,401 @@
+#include <ctype.h>
+#include <lauxlib.h>
+#include <lua.h>
+#include <stdlib.h>
+#include <string.h>
+#include <zlib.h>
+
+/*
+ * ** compatibility with Lua 5.2
+ * */
+#if (LUA_VERSION_NUM >= 502)
+#undef luaL_register
+#define luaL_register(L,n,f) \
+ { if ((n) == NULL) luaL_setfuncs(L,f,0); else luaL_newlib(L,f); }
+
+#endif
+
+#if (LUA_VERSION_NUM >= 503)
+#undef luaL_optint
+#define luaL_optint(L,n,d) ((int)luaL_optinteger(L,(n),(d)))
+#endif
+
+#define DEF_MEM_LEVEL 8
+
+typedef uLong (*checksum_t) (uLong crc, const Bytef *buf, uInt len);
+typedef uLong (*checksum_combine_t)(uLong crc1, uLong crc2, z_off_t len2);
+
+
+static int lz_deflate(lua_State *L);
+static int lz_deflate_delete(lua_State *L);
+static int lz_inflate_delete(lua_State *L);
+static int lz_inflate(lua_State *L);
+static int lz_checksum(lua_State *L);
+static int lz_checksum_new(lua_State *L, checksum_t checksum, checksum_combine_t combine);
+static int lz_adler32(lua_State *L);
+static int lz_crc32(lua_State *L);
+
+static int lz_version(lua_State *L) {
+ const char* version = zlibVersion();
+ int count = strlen(version) + 1;
+ char* cur = (char*)memcpy(lua_newuserdata(L, count),
+ version, count);
+
+ count = 0;
+ while ( *cur ) {
+ char* begin = cur;
+ /* Find all digits: */
+ while ( isdigit(*cur) ) cur++;
+ if ( begin != cur ) {
+ int is_end = *cur == '\0';
+ *cur = '\0';
+ lua_pushnumber(L, atoi(begin));
+ count++;
+ if ( is_end ) break;
+ cur++;
+ }
+ while ( *cur && ! isdigit(*cur) ) cur++;
+ }
+
+ return count;
+}
+
+static int lz_assert(lua_State *L, int result, const z_stream* stream, const char* file, int line) {
+ /* Both of these are "normal" return codes: */
+ if ( result == Z_OK || result == Z_STREAM_END ) return result;
+ switch ( result ) {
+ case Z_NEED_DICT:
+ lua_pushfstring(L, "RequiresDictionary: input stream requires a dictionary to be deflated (%s) at %s line %d",
+ stream->msg, file, line);
+ break;
+ case Z_STREAM_ERROR:
+ lua_pushfstring(L, "InternalError: inconsistent internal zlib stream (%s) at %s line %d",
+ stream->msg, file, line);
+ break;
+ case Z_DATA_ERROR:
+ lua_pushfstring(L, "InvalidInput: input string does not conform to zlib format or checksum failed at %s line %d",
+ file, line);
+ break;
+ case Z_MEM_ERROR:
+ lua_pushfstring(L, "OutOfMemory: not enough memory (%s) at %s line %d",
+ stream->msg, file, line);
+ break;
+ case Z_BUF_ERROR:
+ lua_pushfstring(L, "InternalError: no progress possible (%s) at %s line %d",
+ stream->msg, file, line);
+ break;
+ case Z_VERSION_ERROR:
+ lua_pushfstring(L, "IncompatibleLibrary: built with version %s, but dynamically linked with version %s (%s) at %s line %d",
+ ZLIB_VERSION, zlibVersion(), stream->msg, file, line);
+ break;
+ default:
+ lua_pushfstring(L, "ZLibError: unknown code %d (%s) at %s line %d",
+ result, stream->msg, file, line);
+ }
+ lua_error(L);
+ return result;
+}
+
+/**
+ * @upvalue z_stream - Memory for the z_stream.
+ * @upvalue remainder - Any remainder from the last deflate call.
+ *
+ * @param string - "print" to deflate stream.
+ * @param int - flush output buffer? Z_SYNC_FLUSH, Z_FULL_FLUSH, or Z_FINISH.
+ *
+ * if no params, terminates the stream (as if we got empty string and Z_FINISH).
+ */
+static int lz_filter_impl(lua_State *L, int (*filter)(z_streamp, int), int (*end)(z_streamp), const char* name) {
+ int flush = Z_NO_FLUSH, result;
+ z_stream* stream;
+ luaL_Buffer buff;
+ size_t avail_in;
+
+ if ( filter == deflate ) {
+ const char *const opts[] = { "none", "sync", "full", "finish", NULL };
+ flush = luaL_checkoption(L, 2, opts[0], opts);
+ if ( flush ) flush++;
+ /* Z_NO_FLUSH(0) Z_SYNC_FLUSH(2), Z_FULL_FLUSH(3), Z_FINISH (4) */
+
+ /* No arguments or nil, we are terminating the stream: */
+ if ( lua_gettop(L) == 0 || lua_isnil(L, 1) ) {
+ flush = Z_FINISH;
+ }
+ }
+
+ stream = (z_stream*)lua_touserdata(L, lua_upvalueindex(1));
+ if ( stream == NULL ) {
+ if ( lua_gettop(L) >= 1 && lua_isstring(L, 1) ) {
+ lua_pushfstring(L, "IllegalState: calling %s function when stream was previously closed", name);
+ lua_error(L);
+ }
+ lua_pushstring(L, "");
+ lua_pushboolean(L, 1);
+ return 2; /* Ignore duplicate calls to "close". */
+ }
+
+ luaL_buffinit(L, &buff);
+
+ if ( lua_gettop(L) > 1 ) lua_pushvalue(L, 1);
+
+ if ( lua_isstring(L, lua_upvalueindex(2)) ) {
+ lua_pushvalue(L, lua_upvalueindex(2));
+ if ( lua_gettop(L) > 1 && lua_isstring(L, -2) ) {
+ lua_concat(L, 2);
+ }
+ }
+
+ /* Do the actual deflate'ing: */
+ if (lua_gettop(L) > 0) {
+ stream->next_in = (unsigned char*)lua_tolstring(L, -1, &avail_in);
+ } else {
+ stream->next_in = NULL;
+ avail_in = 0;
+ }
+ stream->avail_in = avail_in;
+
+ if ( ! stream->avail_in && ! flush ) {
+ /* Passed empty string, make it a noop instead of erroring out. */
+ lua_pushstring(L, "");
+ lua_pushboolean(L, 0);
+ lua_pushinteger(L, stream->total_in);
+ lua_pushinteger(L, stream->total_out);
+ return 4;
+ }
+
+ do {
+ stream->next_out = (unsigned char*)luaL_prepbuffer(&buff);
+ stream->avail_out = LUAL_BUFFERSIZE;
+ result = filter(stream, flush);
+ if ( Z_BUF_ERROR != result ) {
+ /* Ignore Z_BUF_ERROR since that just indicates that we
+ * need a larger buffer in order to proceed. Thanks to
+ * Tobias Markmann for finding this bug!
+ */
+ lz_assert(L, result, stream, __FILE__, __LINE__);
+ }
+ luaL_addsize(&buff, LUAL_BUFFERSIZE - stream->avail_out);
+ } while ( stream->avail_out == 0 );
+
+ /* Need to do this before we alter the stack: */
+ luaL_pushresult(&buff);
+
+ /* Save remainder in lua_upvalueindex(2): */
+ if ( NULL != stream->next_in ) {
+ lua_pushlstring(L, (char*)stream->next_in, stream->avail_in);
+ lua_replace(L, lua_upvalueindex(2));
+ }
+
+ /* "close" the stream/remove finalizer: */
+ if ( result == Z_STREAM_END ) {
+ /* Clear-out the metatable so end is not called twice: */
+ lua_pushnil(L);
+ lua_setmetatable(L, lua_upvalueindex(1));
+
+ /* nil the upvalue: */
+ lua_pushnil(L);
+ lua_replace(L, lua_upvalueindex(1));
+
+ /* Close the stream: */
+ lz_assert(L, end(stream), stream, __FILE__, __LINE__);
+
+ lua_pushboolean(L, 1);
+ } else {
+ lua_pushboolean(L, 0);
+ }
+ lua_pushinteger(L, stream->total_in);
+ lua_pushinteger(L, stream->total_out);
+ return 4;
+}
+
+static void lz_create_deflate_mt(lua_State *L) {
+ luaL_newmetatable(L, "lz.deflate.meta"); /* {} */
+
+ lua_pushcfunction(L, lz_deflate_delete);
+ lua_setfield(L, -2, "__gc");
+
+ lua_pop(L, 1); /* <empty> */
+}
+
+static int lz_deflate_new(lua_State *L) {
+ int level = luaL_optint(L, 1, Z_DEFAULT_COMPRESSION);
+ int window_size = luaL_optint(L, 2, MAX_WBITS);
+
+ /* Allocate the stream: */
+ z_stream* stream = (z_stream*)lua_newuserdata(L, sizeof(z_stream));
+
+ stream->zalloc = Z_NULL;
+ stream->zfree = Z_NULL;
+
+ int result = deflateInit2(stream, level, Z_DEFLATED, window_size,
+ DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+
+ lz_assert(L, result, stream, __FILE__, __LINE__);
+
+ /* Don't allow destructor to execute unless deflateInit2 was successful: */
+ luaL_getmetatable(L, "lz.deflate.meta");
+ lua_setmetatable(L, -2);
+
+ lua_pushnil(L);
+ lua_pushcclosure(L, lz_deflate, 2);
+ return 1;
+}
+
+static int lz_deflate(lua_State *L) {
+ return lz_filter_impl(L, deflate, deflateEnd, "deflate");
+}
+
+static int lz_deflate_delete(lua_State *L) {
+ z_stream* stream = (z_stream*)lua_touserdata(L, 1);
+
+ /* Ignore errors. */
+ deflateEnd(stream);
+
+ return 0;
+}
+
+
+static void lz_create_inflate_mt(lua_State *L) {
+ luaL_newmetatable(L, "lz.inflate.meta"); /* {} */
+
+ lua_pushcfunction(L, lz_inflate_delete);
+ lua_setfield(L, -2, "__gc");
+
+ lua_pop(L, 1); /* <empty> */
+}
+
+static int lz_inflate_new(lua_State *L) {
+ /* Allocate the stream */
+ z_stream* stream = (z_stream*)lua_newuserdata(L, sizeof(z_stream));
+
+ /* By default, we will do gzip header detection w/ max window size */
+ int window_size = lua_isnumber(L, 1) ? lua_tointeger(L, 1) : MAX_WBITS + 32;
+
+ stream->zalloc = Z_NULL;
+ stream->zfree = Z_NULL;
+ stream->next_in = Z_NULL;
+ stream->avail_in = 0;
+
+ lz_assert(L, inflateInit2(stream, window_size), stream, __FILE__, __LINE__);
+
+ /* Don't allow destructor to execute unless deflateInit was successful: */
+ luaL_getmetatable(L, "lz.inflate.meta");
+ lua_setmetatable(L, -2);
+
+ lua_pushnil(L);
+ lua_pushcclosure(L, lz_inflate, 2);
+ return 1;
+}
+
+static int lz_inflate(lua_State *L) {
+ return lz_filter_impl(L, inflate, inflateEnd, "inflate");
+}
+
+static int lz_inflate_delete(lua_State *L) {
+ z_stream* stream = (z_stream*)lua_touserdata(L, 1);
+
+ /* Ignore errors: */
+ inflateEnd(stream);
+
+ return 0;
+}
+
+static int lz_checksum(lua_State *L) {
+ if ( lua_gettop(L) <= 0 ) {
+ lua_pushvalue(L, lua_upvalueindex(3));
+ lua_pushvalue(L, lua_upvalueindex(4));
+ } else if ( lua_isfunction(L, 1) ) {
+ checksum_combine_t combine = (checksum_combine_t)
+ lua_touserdata(L, lua_upvalueindex(2));
+
+ lua_pushvalue(L, 1);
+ lua_call(L, 0, 2);
+ if ( ! lua_isnumber(L, -2) || ! lua_isnumber(L, -1) ) {
+ luaL_argerror(L, 1, "expected function to return two numbers");
+ }
+
+ /* Calculate and replace the checksum */
+ lua_pushnumber(L,
+ combine(lua_tonumber(L, lua_upvalueindex(3)),
+ lua_tonumber(L, -2),
+ lua_tonumber(L, -1)));
+ lua_pushvalue(L, -1);
+ lua_replace(L, lua_upvalueindex(3));
+
+ /* Calculate and replace the length */
+ lua_pushnumber(L,
+ lua_tonumber(L, lua_upvalueindex(4)) + lua_tonumber(L, -2));
+ lua_pushvalue(L, -1);
+ lua_replace(L, lua_upvalueindex(4));
+ } else {
+ const Bytef* str;
+ size_t len;
+
+ checksum_t checksum = (checksum_t)
+ lua_touserdata(L, lua_upvalueindex(1));
+ str = (const Bytef*)luaL_checklstring(L, 1, &len);
+
+ /* Calculate and replace the checksum */
+ lua_pushnumber(L,
+ checksum(lua_tonumber(L, lua_upvalueindex(3)),
+ str,
+ len));
+ lua_pushvalue(L, -1);
+ lua_replace(L, lua_upvalueindex(3));
+
+ /* Calculate and replace the length */
+ lua_pushnumber(L,
+ lua_tonumber(L, lua_upvalueindex(4)) + len);
+ lua_pushvalue(L, -1);
+ lua_replace(L, lua_upvalueindex(4));
+ }
+ return 2;
+}
+
+static int lz_checksum_new(lua_State *L, checksum_t checksum, checksum_combine_t combine) {
+ lua_pushlightuserdata(L, checksum);
+ lua_pushlightuserdata(L, combine);
+ lua_pushnumber(L, checksum(0L, Z_NULL, 0));
+ lua_pushnumber(L, 0);
+ lua_pushcclosure(L, lz_checksum, 4);
+ return 1;
+}
+
+static int lz_adler32(lua_State *L) {
+ return lz_checksum_new(L, adler32, adler32_combine);
+}
+
+static int lz_crc32(lua_State *L) {
+ return lz_checksum_new(L, crc32, crc32_combine);
+}
+
+static const luaL_Reg zlib_functions[] = {
+ { "deflate", lz_deflate_new },
+ { "inflate", lz_inflate_new },
+ { "adler32", lz_adler32 },
+ { "crc32", lz_crc32 },
+ { "version", lz_version },
+ { NULL, NULL }
+};
+
+#define SETLITERAL(n,v) (lua_pushliteral(L, n), lua_pushliteral(L, v), lua_settable(L, -3))
+#define SETINT(n,v) (lua_pushliteral(L, n), lua_pushinteger(L, v), lua_settable(L, -3))
+
+LUALIB_API int luaopen_zlib(lua_State * const L) {
+ lz_create_deflate_mt(L);
+ lz_create_inflate_mt(L);
+
+ luaL_register(L, "zlib", zlib_functions);
+
+ SETINT("BEST_SPEED", Z_BEST_SPEED);
+ SETINT("BEST_COMPRESSION", Z_BEST_COMPRESSION);
+
+ SETLITERAL("_COPYRIGHT", "Copyright (c) 2009-2010 Brian Maher");
+ SETLITERAL("_DESCRIPTION", "Yet another binding to the zlib library");
+ SETLITERAL("_VERSION", "lua-zlib $Id$ $Format:%d$");
+
+ /* Expose this to lua so we can do a test: */
+ SETINT("_TEST_BUFSIZ", LUAL_BUFFERSIZE);
+
+ return 1;
+}