static int lload(lua_State *L) { struct reader rd; rd.source = luaL_checklstring(L,1,&rd.source_sz); const char * filename = luaL_checkstring(L, 2); struct filter flt = { &rd.stream, inflateEnd, NULL, 0, 0 }; struct rc4_sbox sbox; if (lua_isstring(L, 3)) { size_t keysz; const char * key = lua_tolstring(L, 3, &keysz); if (keysz != 8) { return luaL_error(L, "Only support 8 bytes key"); } rc4_init(&sbox, (const uint8_t *)key); rd.crypt_sbox = &sbox; } else { rd.crypt_sbox = NULL; } rd.flags = Z_NO_FLUSH; z_stream *stream = &rd.stream; stream->zalloc = Z_NULL; stream->zfree = Z_NULL; stream->opaque = Z_NULL; stream->avail_in = 0; stream->avail_out = 0; int result = inflateInit(stream); lz_assert(L, result, &flt); result = lua_load (L, zip_reader, &rd, filename, "bt"); inflateEnd(stream); if (result != LUA_OK) { return lua_error(L); } return 1; }
static const char * zip_reader(lua_State *L, void *data, size_t *size) { z_stream *stream; struct reader *rd = data; if (rd->source == NULL) return NULL; stream = &rd->stream; if (stream->avail_in == 0 && rd->flags != Z_FINISH) { if (rd->source_sz <= CHUNK_IN) { rd->flags = Z_FINISH; stream->avail_in = rd->source_sz; } else { stream->avail_in = CHUNK_IN; } if (rd->crypt_sbox) { rc4_crypt(rd->crypt_sbox, (const uint8_t *)rd->source, rd->inbuffer, stream->avail_in); stream->next_in = (z_const Bytef *)rd->inbuffer; } else { stream->next_in = (z_const Bytef *)rd->source; } rd->source += stream->avail_in; rd->source_sz -= stream->avail_in; } stream->next_out = rd->outbuffer; stream->avail_out = CHUNK_IN; int result = inflate(stream, rd->flags); struct filter flt = { &rd->stream, inflateEnd, NULL, 0, 0 }; lz_assert(L, result, &flt); if (rd->flags == Z_FINISH && stream->avail_out != 0) { rd->source = NULL; } *size = CHUNK_IN - stream->avail_out; return (const char *)rd->outbuffer; }
static int ldecompress(lua_State *L) { z_stream stream; stream.zalloc = Z_NULL; stream.zfree = Z_NULL; stream.opaque = Z_NULL; struct filter flt = { &stream, inflateEnd, inflate, CRYPT_NONE, NULL, }; struct rc4_sbox sbox; if (lua_isstring(L, 2)) { size_t keysz; const char * key = lua_tolstring(L, 2, &keysz); if (keysz != 8) { return luaL_error(L, "Only support 8 bytes key"); } rc4_init(&sbox, (const uint8_t *)key); flt.crypt_type = CRYPT_IN; flt.crypt_sbox = &sbox; } int result = inflateInit(&stream); lz_assert(L, result, &flt); return execute(L, &flt); }
static int execute(lua_State *L, struct filter *flt) { z_stream *stream = flt->stream; size_t avail_in; const char * source = lua_tolstring(L, 1, &avail_in); uint8_t chunk[CHUNK_IN]; int flags = Z_NO_FLUSH; stream->avail_in = 0; stream->avail_out = 0; luaL_Buffer buff; luaL_buffinit(L, &buff); int result; do { if (stream->avail_in == 0 && flags != Z_FINISH) { stream->next_in = (z_const Bytef *)chunk; if (avail_in <= CHUNK_IN) { flags = Z_FINISH; stream->avail_in = avail_in; } else { stream->avail_in = CHUNK_IN; } if (flt->crypt_type == CRYPT_IN) { rc4_crypt(flt->crypt_sbox, (const uint8_t *)source, chunk, stream->avail_in); stream->next_in = (z_const Bytef *)chunk; } else { stream->next_in = (z_const Bytef *)source; } source += stream->avail_in; avail_in -= stream->avail_in; } void *buffer = luaL_prepbuffer(&buff); stream->next_out = buffer; stream->avail_out = LUAL_BUFFERSIZE; result = flt->execute(stream, flags); lz_assert(L, result, flt); if (flt->crypt_type == CRYPT_OUT) { rc4_crypt(flt->crypt_sbox, buffer, buffer, LUAL_BUFFERSIZE - stream->avail_out); } luaL_addsize(&buff, LUAL_BUFFERSIZE - stream->avail_out); } while ( result != Z_STREAM_END ); luaL_pushresult(&buff); lua_pushinteger(L, stream->adler); flt->end(stream); return 2; }
static int lz_deflate_new(lua_State *L) { int level = luaL_optint(L, 1, Z_DEFAULT_COMPRESSION); /* Allocate the stream: */ z_stream* stream = (z_stream*)lua_newuserdata(L, sizeof(z_stream)); stream->zalloc = Z_NULL; stream->zfree = Z_NULL; lz_assert(L, deflateInit(stream, level), stream, __FILE__, __LINE__); /* Don't allow destructor to execute unless deflateInit 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_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_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; }
/** * @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), 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: */ stream->next_in = lua_gettop(L) > 0 ? (unsigned char*)lua_tolstring(L, -1, &avail_in) : NULL; 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; }