diff --git a/game/engines/default/engine/PlayerProfile.lua b/game/engines/default/engine/PlayerProfile.lua index 36f9a40fa3b3674234ac32b3ea1d9ed0d40cb71e..e03e900b4bc609b43accfe34555bf5df787acdf2 100644 --- a/game/engines/default/engine/PlayerProfile.lua +++ b/game/engines/default/engine/PlayerProfile.lua @@ -145,7 +145,6 @@ function _M:loadGenericProfile() local field = file:gsub(".profile$", "") self.generic[field] = self.generic[field] or {} self:loadData(f, self.generic[field]) - if not self.generic[field].__uuid then self.generic[field].__uuid = util.uuid() end end end end @@ -223,7 +222,6 @@ function _M:loadModuleProfile(short_name) else self.modules[short_name][field] = self.modules[short_name][field] or {} self:loadData(f, self.modules[short_name][field]) - if not self.modules[short_name][field].__uuid then self.modules[short_name][field].__uuid = util.uuid() end end end end @@ -379,7 +377,7 @@ function _M:eventGetNews(e) end function _M:eventGetConfigs(e) - local data = e.data:unserialize() + local data = zlib.decompress(e.data):unserialize() local module = e.module if not data then print("[ONLINE PROFILE] get configs") return end for name, val in pairs(data) do @@ -464,7 +462,7 @@ function _M:setConfigs(module, name, val) if not self.auth then return end if name == "online" then return end if type(val) ~= "string" then val = serialize(val) end - core.profile.pushOrder(table.serialize{o="SetConfigs", module=module, data=table.serialize{[name] = val}}) + core.profile.pushOrder(table.serialize{o="SetConfigs", module=module, data=zlib.compress(table.serialize{[name] = val})}) end function _M:syncOnline(module) @@ -477,7 +475,7 @@ function _M:syncOnline(module) local data = {} for k, v in pairs(sync) do if k ~= "online" then data[k] = serialize(v) end end - core.profile.pushOrder(table.serialize{o="SetConfigs", module=module, data=table.serialize(data)}) + core.profile.pushOrder(table.serialize{o="SetConfigs", module=module, data=zlib.compress(table.serialize(data))}) end function _M:checkModuleHash(module, md5) diff --git a/game/loader/pre-init.lua b/game/loader/pre-init.lua index 7b78c5f9a44916c7cb4849822c633fb0b4052e2b..c5c759fc5f2eb06f74e5cb109244f48cc424dff0 100644 --- a/game/loader/pre-init.lua +++ b/game/loader/pre-init.lua @@ -82,11 +82,13 @@ function table.serialize(src, sub) local nk, ne = k, e local tk, te = type(k), type(e) - if tk == "table" then nk = table.serialize(nk, true) - elseif tk == "string" then -- nothing, we are good + if tk == "table" then nk = "["..table.serialize(nk, true).."]" + elseif tk == "string" then nk = string.format("[%q]", nk) else nk = "["..nk.."]" end + if not sub then nk = "_G"..nk end + if te == "table" then str = str..string.format("%s=%s ", nk, table.serialize(ne, true)) elseif te == "number" then @@ -106,7 +108,7 @@ function string.unserialize(str) local f, err = loadstring(str) if not f then print("[UNSERIALIZE] error", err, str) return nil end local t = {} - setfenv(f, t) + setfenv(f, setmetatable(t, {__index={_G=t}})) local ok, err = pcall(f) - if ok then return t else print("[UNSERIALIZE] error", err, str) return nil end + if ok then return setmetatable(t, nil) else print("[UNSERIALIZE] error", err, str) return nil end end diff --git a/game/profile-thread/Client.lua b/game/profile-thread/Client.lua index 04de4ca246d76674b7e8d879b9809d903f37241e..57fef177f8fa645df3c765fbcad697ee447a1db3 100644 --- a/game/profile-thread/Client.lua +++ b/game/profile-thread/Client.lua @@ -29,7 +29,7 @@ end function _M:connected() if self.sock then return true end - self.sock = socket.connect("te4.org", 2257) + self.sock = socket.connect("te4.org", 2259) if not self.sock then return false end -- self.sock:settimeout(10) print("[PROFILE] Thread connected to te4.org") @@ -40,8 +40,9 @@ end --- Connects the second tcp channel to receive data function _M:connectedPull() if self.psock then return true end - self.psock = socket.connect("te4.org", 2258) + self.psock = socket.connect("te4.org", 2260) if not self.psock then return false end +-- self.psock:settimeout(10) print("[PROFILE] Pull socket connected to te4.org") self.psock:send(self.auth.push_id.."\n") -- Identify ourself return true @@ -57,8 +58,30 @@ function _M:disconnect() core.game.sleep(5000) -- Wait 5 secs end +function _M:receive(size) + local try = 0 + local l, err = nil, "timeout" + while not l and err == "timeout" and try < 10 do + l, err = self.sock:receive(size) + try = try + 1 + end + if not l then + if err == "closed" then + print("[PROFILE] connection disrupted, trying to reconnect", err) + self:disconnect() + end + return nil + end + return l +end + function _M:read(ncode) - local l, err = self.sock:receive("*l") + local try = 0 + local l, err = nil, "timeout" + while not l and err == "timeout" and try < 10 do + l, err = self.sock:receive("*l") + try = try + 1 + end if not l then if err == "closed" then print("[PROFILE] connection disrupted, trying to reconnect", err) @@ -74,7 +97,12 @@ function _M:read(ncode) end function _M:pread(ncode) - local l, err = self.psock:receive("*l") + local try = 0 + local l, err = nil, "timeout" + while not l and err == "timeout" and try < 10 do + l, err = self.psock:receive("*l") + try = try + 1 + end if not l then if err == "closed" then print("[PROFILE] push connection disrupted, trying to reconnect", err) @@ -201,7 +229,7 @@ function _M:orderGetNews(o) size = tonumber(size) if not size or size < 1 or not title then cprofile.pushEvent("e='News' news=false") return end - local body = self.sock:receive(size) + local body = self:receive(size) cprofile.pushEvent(string.format("e='GetNews' news=%q", table.serialize{title=title, body=body})) else cprofile.pushEvent("e='GetNews' news=false") @@ -215,7 +243,7 @@ function _M:orderGetConfigs(o) local _, _, size = self.last_line:find("^([0-9]+)") size = tonumber(size) if not size or size < 1 then return end - local body = self.sock:receive(size) + local body = self:receive(size) cprofile.pushEvent(string.format("e='GetConfigs' module=%q data=%q", o.module, body)) end end @@ -279,7 +307,7 @@ function _M:orderChatUserInfo(o) local _, _, size = self.last_line:find("^([0-9]+)") size = tonumber(size) if not size or size < 1 then return end - local body = self.sock:receive(size) + local body = self:receive(size) cprofile.pushEvent(string.format("e='Chat' se='UserInfo' user=%q data=%q", o.user, body)) end end diff --git a/premake4.lua b/premake4.lua index 01f89b90c9387b6066ec116b729c5b2f1109a1ac..13dc940720745d8ed8274e9c1be9e6d14d59e75d 100644 --- a/premake4.lua +++ b/premake4.lua @@ -89,7 +89,7 @@ project "TEngine" language "C" targetname "t-engine" files { "src/*.c", } - links { "physfs", "lua".._OPTIONS.lua, "fov", "luasocket", "luaprofiler", "lualanes", "lpeg", "tcodimport", "lxp", "expatstatic", "luamd5" } + links { "physfs", "lua".._OPTIONS.lua, "fov", "luasocket", "luaprofiler", "lualanes", "lpeg", "tcodimport", "lxp", "expatstatic", "luamd5", "luazlib" } defines { "_DEFAULT_VIDEOMODE_FLAGS_='SDL_HWSURFACE|SDL_DOUBLEBUF'" } defines { [[TENGINE_HOME_PATH='".t-engine"']] } @@ -114,7 +114,7 @@ configuration "windows" defines { [[TENGINE_HOME_PATH='"T-Engine"']], 'SELFEXE_WINDOWS' } configuration "linux" - links { "SDL", "SDL_ttf", "SDL_image", "SDL_mixer", "GL", "GLU", "m", "pthread", "uuid" } + links { "SDL", "SDL_ttf", "SDL_image", "SDL_mixer", "GL", "GLU", "m", "pthread" } defines { [[TENGINE_HOME_PATH='".t-engine"']], 'SELFEXE_LINUX' } configuration {"linux", "Debug"} @@ -266,3 +266,10 @@ project "luamd5" targetname "luamd5" files { "src/luamd5/*.c", } + +project "luazlib" + kind "StaticLib" + language "C" + targetname "luazlib" + + files { "src/lzlib/*.c", } diff --git a/src/lzlib/Makefile b/src/lzlib/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8bbfef86528a8bee73af370bea55a2c5d1f377d7 --- /dev/null +++ b/src/lzlib/Makefile @@ -0,0 +1,57 @@ +# $Id: Makefile,v 1.8 2004/07/22 19:10:47 tngd Exp $ +# makefile for zlib library for Lua + +# dist location +DISTDIR=$(HOME)/dist +TMP=/tmp + +# change these to reflect your Lua installation +LUA= $(HOME)/local/lua +LUAINC= $(LUA)/include +LUALIB= $(LUA)/lib +LUABIN= $(LUA)/bin + +ZLIB=../zlib-1.2.3 + +# no need to change anything below here +CFLAGS= $(INCS) $(DEFS) $(WARN) -O2 -fPIC +WARN= -g -Werror -Wall -pedantic #-ansi -pedantic -Wall +INCS= -I$(LUAINC) -I$(ZLIB) +LIBS= -L$(ZLIB) -lz -L$(LUALIB) -L$(LUABIN) # -llua51 + +MYLIB=lzlib + +ZLIB_NAME = zlib +GZIP_NAME = gzip + +T_ZLIB= $(ZLIB_NAME).so +T_GZIP= $(GZIP_NAME).so + +VER=0.3 +TARFILE = $(DISTDIR)/$(MYLIB)-$(VER).tar.gz +TARFILES = Makefile README README.lgzip \ + lzlib.c lgzip.c \ + test_zlib.lua test_gzip.lua + +all: $(T_ZLIB) $(T_GZIP) + +test: $(T_ZLIB) $(T_GZIP) + $(LUABIN)/lua -lluarc test_zlib.lua + $(LUABIN)/lua -lluarc test_gzip.lua + +$(T_ZLIB): lzlib.o + $(CC) -o $@ -shared $< $(LIBS) + +$(T_GZIP): lgzip.o + $(CC) -o $@ -shared $< $(LIBS) + +clean: + rm -f *.o *.so core core.* a.out + +dist: $(TARFILE) + +$(TARFILE): $(TARFILES) + @ln -sf `pwd` $(TMP)/$(MYLIB)-$(VER) + tar -zcvf $(TARFILE) -C $(TMP) $(addprefix $(MYLIB)-$(VER)/,$(TARFILES)) + @rm -f $(TMP)/$(MYLIB)-$(VER) + @lsum $(TARFILE) $(DISTDIR)/md5sums.txt diff --git a/src/lzlib/README b/src/lzlib/README new file mode 100644 index 0000000000000000000000000000000000000000..a3204813cfe968cd54f288bf83de0c7f32dc037f --- /dev/null +++ b/src/lzlib/README @@ -0,0 +1,122 @@ +************************************************************************* +* Author : Tiago Dionizio <tiago.dionizio@gmail.com> * +* Library : lzlib - Lua 5.1 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. * +************************************************************************* + +To use this library you need zlib library. +You can get it from http://www.gzip.org/zlib/ + + +Loading the library: + + If you built the library as a loadable package + [local] zlib = require 'zlib' + + If you compiled the package statically into your application, call + the function "luaopen_zlib(L)". It will create a table with the zlib + functions and leave it on the stack. + +Definitions: + + ds = deflate stream + is = inflate stream + int = number (integer) + * = (any type) + + [...] represent optional parameters that may be omited or nil, in wich case + will be replaced by their default values + +-- zlib functions -- + +string zlib.version() +int zlib.compile_flags() +int zlib.adler32(int adler, string buf) +int zlib.crc32(int crc, string buf) + +string zlib.compress(string buf [, int level] [, int method] [, int windowBits] [, int memLevel] [, int strategy]) +string zlib.uncompress(string buf [, int windowBits]) + +ds zlib.deflate_init([int level] [, int method] [, int windowBits] [, int memLevel] [, int strategy]) +is zlib.inflate_init([int windowBits]) + +-- deflate stream methods -- + +int ds:adler() +int ds:data_type() +int ds:total_in() +int ds:total_out() +int, int df:process(string [, int flush]) +void ds:done() +void ds:callback(function callback, * userdata) +int ds:set_dictionary(string dictionary) +ds [,int] ds:clone() +int ds:reset() +int ds:params(int level, int strategy) +int ds:prime(int bits, int value) + +-- inflate stream methods -- + +int is:adler() +int is:data_type() +int is:total_in() +int is:total_out() +int, int if:process(string [, int flush]) +void if:done() +void is:callback([function callback] [, * userdata]) +void is:dictionary([function callback] [, * userdata]) +int is:set_dictionary(string dictionary) +is [,int] is:clone() +int is:reset() +int, int is:sync(string buf) + +-- callbacks -- +void callback(string buf, * userdata) +void dictionary(* userdata) + +-- general description -- +most functions/methods correspond to the original function in the zlib +library, the main differences are: + +when (de)compressing blocks, the generated output is sent to the callback +function, this is done to prevent passing too much meaningful result values +from the process method + +deflate/inflate zlib functions are interfaced through the process method + +ds:params may invoke the output callback + +process method returns the error value and the number of input bytes +processed + +clone method returns a copy of the stream (also copies callbacks) and +returns a new stream object or nil plus an error code + +dictionary callback is not strictly necessary, but may avoid extra process +calls if used, only needed when compressed stream also used a custom +dictionary. when using it you must call is:set_dictionary as needed, if not +you will have to watch the return code for zlib. + +is:sync returns an error code and the number of input bytes processed + + +** for more information please refer to zlib.h ** + diff --git a/src/lzlib/README.lgzip b/src/lzlib/README.lgzip new file mode 100644 index 0000000000000000000000000000000000000000..78390dde68ec9c2a36b8a14d4ccb5148417a43b5 --- /dev/null +++ b/src/lzlib/README.lgzip @@ -0,0 +1,136 @@ +************************************************************************* +* Author : Tiago Dionizio <tiago.dionizio@gmail.com> * +* Library : lgzip - a gzip file access binding for Lua 5 * +* based on liolib.c from Lua 5.0 library * +* * +* 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. * +************************************************************************* + +To use this library you need zlib library. +You can get it from http://www.gzip.org/zlib/ + + +This shows up as a 'addon' to the zlib binding interface. + +This is a simple binding to work with gzip files. It is based on the file +liolib.c included in the original Lua 5.0 distribuition and contains a similar +interface, of course, duplicated and unrelated features were removed. + + + +Loading the library: + + If you built the library as a loadable package + [local] gzip = require 'gzip' + + If you compiled the package statically into your application, call + the function "luaopen_gzip(L)". It will create a table with the zlib + functions and leave it on the stack. + + +gzip.open(filename [, mode]) + + Opens a file name using "gzopen". Behaviour is identical to the description + given in the zlib library. If mode is not given a default mode "rb" will be + used. Mode is the same as interpreted by gzopen function, ie, it can + include special modes such as characters 1 to 9 that will be treated as the + compression level when opening a file for writing. + + It returns a new file handle, or, in case of errors, nil plus an error + message + +gzip.lines(filename) + + Same behaviour as io.lines in the io standard library provided by lua + with the aditional feature of working with gzip files. If a normal text + file is read it will read it normaly (normal gzopen behaviour). + +gzip.close(file) + + Same as file:close, use file:close instead. + +file:flush() + + This function takes no parameters and flushes all output to working file. + The same as calling 'gzflush(file, Z_FINISH)' so writing to the file will + most likely not work as expected. This is subject to change in the future + if there is a strong reason for it to happen. + +file:read(format1, ...) + Reads the file file, according to the given formats, which specify what + to read. For each format, the function returns a string with the characters + read, or nil if it cannot read data with the specified format. When called + without formats, it uses a default format that reads the entire next line + (see below). + + The available formats are + + "*a" reads the whole file, starting at the current position. On end of + file, it returns the empty string. + "*l" reads the next line (skipping the end of line), returning nil on + end of file. This is the default format. + number reads a string with up to that number of characters, returning + nil on end of file. If number is zero, it reads nothing and + returns an empty string, or nil on end of file. + + Unlike io.read, the "*n" format will not be available. + + +file:lines() + + Returns an iterator function that, each time it is called, returns a new + line from the file. Therefore, the construction + for line in file:lines() do ... end + will iterate over all lines of the file. (Unlike gzip.lines, this function + does not close the file when the loop ends.) + +file:seek([whence] [, offset]) + + Sets and gets the file position, measured from the beginning of the file, + to the position given by offset plus a base specified by the string whence, + as follows: + + "set" base is position 0 (beginning of the file); + "cur" base is current position; + + In case of success, function seek returns the final file position, measured + in bytes from the beginning of the file. If this function fails, it returns + nil, plus a string describing the error. + + The default value for whence is "cur", and for offset is 0. Therefore, the + call file:seek() returns the current file position, without changing it; + the call file:seek("set") sets the position to the beginning of the file + (and returns 0); and the call file:seek("end") sets the position to the end + of the file, and returns its size. + + This function is subject to limitations imposed by gzseek function from + zlib library, such as the inability to use "end" as the base for seeking + and the inability to seek backwards when writing. + +file:write(value1, ...) + + Writes the value of each of its arguments to the filehandle file. The + arguments must be strings or numbers. To write other values, use tostring + or string.format before write + +file:close() + + Closes the file. + diff --git a/src/lzlib/lgzip.c b/src/lzlib/lgzip.c new file mode 100644 index 0000000000000000000000000000000000000000..e1bcc9bcffc103c2b42e3cb912110811ce8e9871 --- /dev/null +++ b/src/lzlib/lgzip.c @@ -0,0 +1,377 @@ +/************************************************************************ +* Author : Tiago Dionizio <tiago.dionizio@gmail.com> * +* Library : lgzip - a gzip file access binding for Lua 5 * +* based on liolib.c from Lua 5.0 library * +* * +* 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 <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <zlib.h> + +#include "lua.h" +#include "lauxlib.h" + + + +/* +** {====================================================== +** FILE Operations +** ======================================================= +*/ + + +#define FILEHANDLE "zlib:gzFile" + + +static int pushresult (lua_State *L, int i, const char *filename) { + if (i) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushnil(L); + if (filename) + lua_pushfstring(L, "%s: %s", filename, strerror(errno)); + else + lua_pushfstring(L, "%s", strerror(errno)); + lua_pushnumber(L, errno); + return 3; + } +} + + +static gzFile *topfile (lua_State *L, int findex) { + gzFile*f = (gzFile*)luaL_checkudata(L, findex, FILEHANDLE); + if (f == NULL) luaL_argerror(L, findex, "bad file"); + return f; +} + + +static gzFile tofile (lua_State *L, int findex) { + gzFile*f = topfile(L, findex); + if (*f == NULL) + luaL_error(L, "attempt to use a closed file"); + return *f; +} + + + +/* +** When creating file handles, always creates a `closed' file handle +** before opening the actual file; so, if there is a memory error, the +** file is not left opened. +*/ +static gzFile *newfile (lua_State *L) { + gzFile *pf = (gzFile*)lua_newuserdata(L, sizeof(gzFile)); + *pf = NULL; /* file handle is currently `closed' */ + luaL_getmetatable(L, FILEHANDLE); + lua_setmetatable(L, -2); + return pf; +} + + +static int aux_close (lua_State *L) { + gzFile f = tofile(L, 1); + int ok = (gzclose(f) == Z_OK); + if (ok) + *(gzFile*)lua_touserdata(L, 1) = NULL; /* mark file as closed */ + return ok; +} + + +static int io_close (lua_State *L) { + return pushresult(L, aux_close(L), NULL); +} + + +static int io_gc (lua_State *L) { + gzFile *f = topfile(L, 1); + if (*f != NULL) /* ignore closed files */ + aux_close(L); + return 0; +} + + +static int io_tostring (lua_State *L) { + char buff[128]; + gzFile *f = topfile(L, 1); + if (*f == NULL) + strcpy(buff, "closed"); + else + sprintf(buff, "%p", lua_touserdata(L, 1)); + lua_pushfstring(L, "gzip file (%s)", buff); + return 1; +} + + +static int io_open (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + const char *mode = luaL_optstring(L, 2, "rb"); + gzFile *pf = newfile(L); + *pf = gzopen(filename, mode); + return (*pf == NULL) ? pushresult(L, 0, filename) : 1; +} + + +static int io_readline (lua_State *L); + +static void aux_lines (lua_State *L, int idx, int close) { + lua_pushliteral(L, FILEHANDLE); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushvalue(L, idx); + lua_pushboolean(L, close); /* close/not close file when finished */ + lua_pushcclosure(L, io_readline, 3); +} + + +static int f_lines (lua_State *L) { + tofile(L, 1); /* check that it's a valid file handle */ + aux_lines(L, 1, 0); + return 1; +} + + +static int io_lines (lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + gzFile *pf = newfile(L); + *pf = gzopen(filename, "rb"); + luaL_argcheck(L, *pf, 1, strerror(errno)); + aux_lines(L, lua_gettop(L), 1); + return 1; +} + + +/* +** {====================================================== +** READ +** ======================================================= +*/ + + +static int test_eof (lua_State *L, gzFile f) { + lua_pushlstring(L, NULL, 0); + return (gzeof(f) != 1); +} + + +static int read_line (lua_State *L, gzFile f) { + luaL_Buffer b; + luaL_buffinit(L, &b); + for (;;) { + size_t l; + char *p = luaL_prepbuffer(&b); + if (gzgets(f, p, LUAL_BUFFERSIZE) == NULL) { /* eof? */ + luaL_pushresult(&b); /* close buffer */ + return (lua_strlen(L, -1) > 0); /* check whether read something */ + } + l = strlen(p); + if (p[l-1] != '\n') + luaL_addsize(&b, l); + else { + luaL_addsize(&b, l - 1); /* do not include `eol' */ + luaL_pushresult(&b); /* close buffer */ + return 1; /* read at least an `eol' */ + } + } +} + + +static int read_chars (lua_State *L, gzFile f, size_t n) { + size_t rlen; /* how much to read */ + size_t nr; /* number of chars actually read */ + luaL_Buffer b; + luaL_buffinit(L, &b); + rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ + do { + char *p = luaL_prepbuffer(&b); + if (rlen > n) rlen = n; /* cannot read more than asked */ + nr = gzread(f, p, rlen); + luaL_addsize(&b, nr); + n -= nr; /* still have to read `n' chars */ + } while (n > 0 && nr == rlen); /* until end of count or eof */ + luaL_pushresult(&b); /* close buffer */ + return (n == 0 || lua_strlen(L, -1) > 0); +} + + +static int g_read (lua_State *L, gzFile f, int first) { + int nargs = lua_gettop(L) - 1; + int success; + int n; + if (nargs == 0) { /* no arguments? */ + success = read_line(L, f); + n = first+1; /* 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 = first; nargs-- && success; n++) { + if (lua_type(L, n) == LUA_TNUMBER) { + size_t l = (size_t)lua_tonumber(L, n); + success = (l == 0) ? test_eof(L, f) : read_chars(L, f, 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 = read_line(L, f); + break; + case 'a': /* file */ + read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ + success = 1; /* always success */ + break; + default: + return luaL_argerror(L, n, "invalid format"); + } + } + } + } + if (!success) { + lua_pop(L, 1); /* remove last result */ + lua_pushnil(L); /* push nil instead */ + } + return n - first; +} + + +static int f_read (lua_State *L) { + return g_read(L, tofile(L, 1), 2); +} + + +static int io_readline (lua_State *L) { + gzFile f = *(gzFile*)lua_touserdata(L, lua_upvalueindex(2)); + if (f == NULL) /* file is already closed? */ + luaL_error(L, "file is already closed"); + if (read_line(L, f)) return 1; + else { /* EOF */ + if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ + lua_settop(L, 0); + lua_pushvalue(L, lua_upvalueindex(2)); + aux_close(L); /* close it */ + } + return 0; + } +} + +/* }====================================================== */ + + +static int g_write (lua_State *L, gzFile f, int arg) { + int nargs = lua_gettop(L) - 1; + int status = 1; + for (; nargs--; arg++) { + if (lua_type(L, arg) == LUA_TNUMBER) { + /* optimization: could be done exactly as for strings */ + status = status && + gzprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; + } + else { + size_t l; + const char *s = luaL_checklstring(L, arg, &l); + status = status && (gzwrite(f, (char*)s, l) == l); + } + } + return pushresult(L, status, NULL); +} + + +static int f_write (lua_State *L) { + return g_write(L, tofile(L, 1), 2); +} + + +static int f_seek (lua_State *L) { + static const int mode[] = {SEEK_SET, SEEK_CUR}; + static const char *const modenames[] = {"set", "cur", NULL}; + gzFile f = tofile(L, 1); + int op = luaL_checkoption(L, 2, "cur", modenames); + long offset = luaL_optlong(L, 3, 0); + op = gzseek(f, offset, mode[op]); + if (op == -1) + return pushresult(L, 0, NULL); /* error */ + else { + lua_pushnumber(L, op); + return 1; + } +} + + +static int f_flush (lua_State *L) { + return pushresult(L, gzflush(tofile(L, 1), Z_FINISH) == Z_OK, NULL); +} + + +/* }====================================================== */ + + +LUALIB_API int luaopen_gzip (lua_State *L) { + const luaL_reg iolib[] = { + {"lines", io_lines}, + {"close", io_close}, + {"open", io_open}, + {NULL, NULL} + }; + + const luaL_reg flib[] = { + {"flush", f_flush}, + {"read", f_read}, + {"lines", f_lines}, + {"seek", f_seek}, + {"write", f_write}, + {"close", io_close}, + {"__gc", io_gc}, + {"__tostring", io_tostring}, + {NULL, NULL} + }; + + + luaL_newmetatable(L, FILEHANDLE); /* create new metatable for file handles */ + /* file methods */ + lua_pushliteral(L, "__index"); + lua_pushvalue(L, -2); /* push metatable */ + lua_rawset(L, -3); /* metatable.__index = metatable */ + + luaL_register(L, NULL, flib); + lua_pop(L, 1); + + lua_newtable(L); + + lua_pushliteral (L, "_COPYRIGHT"); + lua_pushliteral (L, "Copyright (C) 2003-2008 Tiago Dionizio"); + lua_settable (L, -3); + lua_pushliteral (L, "_DESCRIPTION"); + lua_pushliteral (L, "Lua 5 interface to access gzip files"); + lua_settable (L, -3); + lua_pushliteral (L, "_VERSION"); + lua_pushliteral (L, "lgzip 0.3"); + lua_settable (L, -3); + + luaL_register(L, NULL, iolib); + + lua_pop(L, 1); + return 1; +} + diff --git a/src/lzlib/lzlib.c b/src/lzlib/lzlib.c new file mode 100644 index 0000000000000000000000000000000000000000..20c978962870ba1dc7e93e0d3bd5c1e02948c863 --- /dev/null +++ b/src/lzlib/lzlib.c @@ -0,0 +1,592 @@ +/************************************************************************ +* Author : Tiago Dionizio <tiago.dionizio@gmail.com> * +* 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 <stdlib.h> +#include <string.h> + +#include "lua.h" +#include "lauxlib.h" + +#include "zlib.h" + + +/* +** ========================================================================= +** compile time options wich determine available functionality +** ========================================================================= +*/ + + +/* +** ========================================================================= +** zlib stream metamethods +** ========================================================================= +*/ +#define ZSTREAMMETA "zlib:zstream" + +#define LZANY (void*)-1 +#define LZNONE (void*)0 +#define LZDEFLATE (void*)1 +#define LZINFLATE (void*)2 + +static z_stream *lzstream_new(lua_State *L) +{ + z_stream *s = (z_stream*)lua_newuserdata(L, sizeof(z_stream)); + + luaL_getmetatable(L, ZSTREAMMETA); + lua_setmetatable(L, -2); /* set metatable */ + + s->zalloc = Z_NULL; + s->zfree = Z_NULL; + + s->next_out = Z_NULL; + s->avail_out = 0; + s->next_in = Z_NULL; + s->avail_in = 0; + + s->opaque = LZNONE; + + return s; +} + +static void lzstream_cleanup(lua_State *L, z_stream *s) +{ + if (s && s->opaque != LZNONE) + { + if (s->opaque == LZINFLATE) + inflateEnd(s); + if (s->opaque == LZDEFLATE) + deflateEnd(s); + s->opaque = LZNONE; + } +} + +/* ====================================================================== */ + +static z_stream *lzstream_get(lua_State *L, int index) +{ + z_stream *s = (z_stream*)luaL_checkudata(L, index, ZSTREAMMETA); + if (s == NULL) luaL_argerror(L, index, "bad zlib stream"); + return s; +} + +static z_stream *lzstream_check(lua_State *L, int index, void *state) +{ + z_stream *s = lzstream_get(L, index); + if ((state != LZANY && s->opaque != state) || s->opaque == LZNONE) + luaL_argerror(L, index, "attempt to use invalid zlib stream"); + return s; +} + +/* ====================================================================== */ + +static int lzstream_tostring(lua_State *L) +{ + char buf[100]; + z_stream *s = (z_stream*)luaL_checkudata(L, 1, ZSTREAMMETA); + if (s == NULL) luaL_argerror(L, 1, "bad zlib stream"); + + if (s->opaque == LZNONE) + strncpy(buf, "zlib stream (closed)", 100); + else if (s->opaque == LZDEFLATE) + snprintf(buf, 100, "zlib deflate stream (%p)", (void*)s); + else if (s->opaque == LZINFLATE) + snprintf(buf, 100, "zlib inflate stream (%p)", (void*)s); + else + snprintf(buf, 100, "%p", (void*)s); + + lua_pushstring(L, buf); + return 1; +} + +/* ====================================================================== */ + +static int lzstream_gc(lua_State *L) +{ + z_stream *s = lzstream_get(L, 1); + lzstream_cleanup(L, s); + return 0; +} + +/* ====================================================================== */ + +static int lzstream_close(lua_State *L) +{ + z_stream *s = lzstream_check(L, 1, LZANY); + lzstream_cleanup(L, s); + return 0; +} + +/* ====================================================================== */ + +static int lzstream_adler(lua_State *L) +{ + z_stream *s = lzstream_check(L, 1, LZANY); + lua_pushnumber(L, s->adler); + return 1; +} + +/* ====================================================================== */ + +static int lzlib_deflate(lua_State *L) +{ + int level = luaL_optint(L, 1, Z_DEFAULT_COMPRESSION); + int method = luaL_optint(L, 2, Z_DEFLATED); + int windowBits = luaL_optint(L, 3, 15); + int memLevel = luaL_optint(L, 4, 8); + int strategy = luaL_optint(L, 5, Z_DEFAULT_STRATEGY); + + z_stream *s = lzstream_new(L); + + if (deflateInit2(s, level, method, windowBits, memLevel, strategy) != Z_OK) + { + lua_pushliteral(L, "failed to start decompressing"); + lua_error(L); + } + s->opaque = LZDEFLATE; + return 1; +} + +/* ====================================================================== */ + +static int lzlib_inflate(lua_State *L) +{ + int windowBits = luaL_optint(L, 1, 15); + + z_stream *s = lzstream_new(L); + + if (inflateInit2(s, windowBits) != Z_OK) + { + lua_pushliteral(L, "failed to start compressing"); + lua_error(L); + } + + s->opaque = LZINFLATE; + return 1; +} + +/* ====================================================================== */ + +static int lzstream_decompress(lua_State *L) +{ + int r; + luaL_Buffer b; + + z_stream *s = lzstream_check(L, 1, LZINFLATE); + s->next_in = (unsigned char*)luaL_checkstring(L, 2); + s->avail_in = lua_strlen(L, 2); + + luaL_buffinit(L, &b); + + do { + s->next_out = (unsigned char*)luaL_prepbuffer(&b); + s->avail_out = LUAL_BUFFERSIZE; + + /* munch some more */ + r = inflate(s, Z_SYNC_FLUSH); + if (r != Z_OK && r != Z_STREAM_END) { + lua_pushfstring(L, "failed to decompress [%d]", r); + lua_error(L); + } + + /* push gathered data */ + luaL_addsize(&b, LUAL_BUFFERSIZE - s->avail_out); + + /* until we have free space in the output buffer - meaning we are done */ + } while (s->avail_in > 0 || s->avail_out == 0); + + /* send gathered data if any */ + luaL_pushresult(&b); + + return 1; +} + +/* ====================================================================== */ + +static int lzstream_compress(lua_State *L) +{ + int r; + luaL_Buffer b; + + z_stream *s = lzstream_check(L, 1, LZDEFLATE); + s->next_in = (unsigned char*)luaL_checkstring(L, 2); + s->avail_in = lua_strlen(L, 2); + + luaL_buffinit(L, &b); + + do { + s->next_out = (unsigned char*)luaL_prepbuffer(&b); + s->avail_out = LUAL_BUFFERSIZE; + + /* bake some more */ + if ((r = deflate(s, Z_NO_FLUSH)) != Z_OK) + { + lua_pushfstring(L, "failed to compress [%d]", r); + lua_error(L); + } + + /* push gathered data */ + luaL_addsize(&b, LUAL_BUFFERSIZE - s->avail_out); + + /* until we have free space in the output buffer - meaning we are done */ + } while (s->avail_out == 0); + + /* send gathered data if any */ + luaL_pushresult(&b); + + return 1; +} + +/* ====================================================================== */ + +static int lzstream_flush(lua_State *L) +{ + z_stream *s = lzstream_check(L, 1, LZANY); + + if (s->opaque == LZINFLATE) { + lua_pushliteral(L, ""); + return 1; + } + + s->next_in = (unsigned char *)""; + s->avail_in = 0; + + { + int r = 0; + luaL_Buffer b; + luaL_buffinit(L, &b); + + do { + s->next_out = (unsigned char *)luaL_prepbuffer(&b); + s->avail_out = LUAL_BUFFERSIZE; + + r = deflate(s, Z_FINISH); + + if (r != Z_OK && r != Z_STREAM_END) { + lua_pushfstring(L, "failed to flush [%d]", r); + lua_error(L); + } + + /* push gathered data */ + luaL_addsize(&b, LUAL_BUFFERSIZE - s->avail_out); + } while (r != Z_STREAM_END); + + /* send gathered data if any */ + luaL_pushresult(&b); + } + return 1; +} + +/* ====================================================================== */ + +static int lzstream_reset(lua_State *L) +{ + z_stream *s = lzstream_check(L, 1, LZANY); + + if (s->state == LZDEFLATE) + lua_pushnumber(L, deflateReset(s)); + else if (s->opaque == LZINFLATE) + lua_pushnumber(L, inflateReset(s)); + else + { + lua_pushliteral(L, "invalid zlib stream state"); + lua_error(L); + } + + return 1; +} + + +/* +** ========================================================================= +** 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 */ + int adler = luaL_checkint(L, 1); + const unsigned char* buf = (unsigned char*)luaL_checkstring(L, 2); + int len = lua_strlen(L, 2); + + 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 */ + int crc = luaL_checkint(L, 1); + const unsigned char* buf = (unsigned char*)luaL_checkstring(L, 2); + int len = lua_strlen(L, 2); + + lua_pushnumber(L, crc32(crc, buf, len)); + } + return 1; +} + +/* ====================================================================== */ + + +static int lzlib_compress(lua_State *L) +{ + const char *next_in = luaL_checkstring(L, 1); + int avail_in = lua_strlen(L, 1); + int level = luaL_optint(L, 2, Z_DEFAULT_COMPRESSION); + int method = luaL_optint(L, 3, Z_DEFLATED); + int windowBits = luaL_optint(L, 4, 15); + int memLevel = luaL_optint(L, 5, 8); + int strategy = luaL_optint(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) +{ + const char *next_in = luaL_checkstring(L, 1); + int avail_in = lua_strlen(L, 1); + int windowBits = luaL_optint(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_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; + + /* bake some more */ + ret = inflate(&zs, Z_FINISH); + + /* push gathered data */ + luaL_addsize(&b, LUAL_BUFFERSIZE - zs.avail_out); + + /* need dictionary? - no dictionary support here, so just quit */ + if (ret == Z_NEED_DICT) + break; + + /* done processing? */ + if (ret == Z_STREAM_END) + break; + + /* error condition? */ + if (ret != Z_BUF_ERROR) + break; + } + + /* cleanup */ + inflateEnd(&zs); + + luaL_pushresult(&b); + lua_pushnumber(L, ret); + return 2; +} + + +/* +** ========================================================================= +** Register functions +** ========================================================================= +*/ + + +LUALIB_API int luaopen_zlib(lua_State *L) +{ + const luaL_reg zstreamm[] = + { + {"reset", lzstream_reset }, + + {"compress", lzstream_compress }, + {"decompress", lzstream_decompress }, + {"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 }, + + {"compressobj", lzlib_deflate }, + {"decompressobj", lzlib_inflate }, + + {"compress", lzlib_compress }, + {"decompress", lzlib_decompress }, + + {NULL, NULL} + }; + + /* ====================================================================== */ + + /* make sure header and library version are consistent */ + const char* version = zlibVersion(); + if (strcmp(version, ZLIB_VERSION)) + { + lua_pushfstring(L, "zlib library version does not match - header: %s, library: %s", ZLIB_VERSION, version); + lua_error(L); + } + + /* 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, zstreamm); + + lua_pop(L, 1); /* remove metatable from stack */ + + /* + ** Stack: + */ + lua_newtable(L); + + lua_pushliteral (L, "_COPYRIGHT"); + lua_pushliteral (L, "Copyright (C) 2003-2008 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.3"); + lua_settable (L, -3); + + luaL_register(L, "zlib", zlib); + + lua_pop(L, 2); + /* + ** Stack: zlib table + */ + return 1; +} diff --git a/src/lzlib/test_gzip.lua b/src/lzlib/test_gzip.lua new file mode 100644 index 0000000000000000000000000000000000000000..bda6c5ca680db495c6486a1ec4c3e92c7452a497 --- /dev/null +++ b/src/lzlib/test_gzip.lua @@ -0,0 +1,97 @@ + +local gzip = require 'gzip' + +local function line(header, c) + header = header or '' + c = c or '-' + print(string.rep(string.sub(c, 1, 1), 78 - string.len(header))..header) +end + + +line(' gzip', '=') + +line(' gzip writing') +local loops = 1000 +local testfile = "test.gz" + +local of = gzip.open(testfile, "wb9") + +if (not of) then + error("Failed to open file test.gz for writing") +end + +for i = 1, loops do + of:write(i, "\n") +end + +of:close() + +local i = 0 +for l in gzip.lines(testfile) do + i = i + 1 + if (tostring(i) ~= l) then + error(tostring(i)) + end +end + +assert(i == loops) +print('Ok.') +line(' gzip reading') + +local inf = gzip.open(testfile) + +if (not inf) then + error("Failed to open file test.gz for reading") +end + +for i = 1, loops do + if (tostring(i) ~= inf:read("*l")) then + error(tostring(i)) + end +end + +inf:close() + +print('Ok.') +line(' compress seek') + +of = gzip.open(testfile, "wb1") + +if (not of) then + error("Failed to open file test.gz for writing") +end + +assert(of:seek("cur", 5) == 5) +assert(of:seek("set", 10) == 10) + +of:write("1") + +of:close() + +print('Ok.') +line(' uncompress seek') + +inf = gzip.open(testfile) + +if (not inf) then + error("Failed to open file test.gz for reading") +end + +assert(inf:seek("set", 6) == 6) +assert(inf:seek("set", 4) == 4) +assert(inf:seek("cur", 1) == 5) +assert(inf:seek("cur", -1) == 4) +assert(inf:seek("cur", 1) == 5) +assert(inf:seek("set", 6) == 6) + +inf:read(4) + +assert(inf:read(1) == "1") + +inf:close() + +os.remove(testfile) + +print('Ok.') + +line(' gzip', '=') diff --git a/src/lzlib/test_zlib.lua b/src/lzlib/test_zlib.lua new file mode 100644 index 0000000000000000000000000000000000000000..76a9fa868620ae9aabdb3c8bf3c89cf22eb017cd --- /dev/null +++ b/src/lzlib/test_zlib.lua @@ -0,0 +1,105 @@ + +local zlib = require 'zlib' + +local function line(header, c) + header = header or '' + c = c or '-' + print(string.rep(string.sub(c, 1, 1), 78 - string.len(header))..header) +end + +local function ipart(value) + return value - math.mod(value, 1) +end + +local function bitvalues(value, bstart, num) + value = ipart(value / 2^bstart) + return math.mod(value, 2^num) +end + +line(' zlib '..zlib.version(), '=') + +line(' adler32') +local adler = zlib.adler32() +print('adler32 init : '..adler) +adler = zlib.adler32(adler, 'some text') +print('updated adler: '..adler) +adler = zlib.adler32(adler, 'some text') +print('updated adler: '..adler) +adler = zlib.adler32(adler, 'some text') +print('updated adler: '..adler) +adler = zlib.adler32(adler, 'some text') +print('updated adler: '..adler) +adler = zlib.adler32(adler, 'some text') +print('updated adler: '..adler) +adler = zlib.adler32(adler, 'some textd') +print('updated adler: '..adler) + +line(' crc32') +local crc = zlib.crc32() +print('crc32 init : '..crc) +crc = zlib.crc32(crc, 'some text') +print('updated crc: '..crc) +crc = zlib.crc32(crc, 'some text') +print('updated crc: '..crc) +crc = zlib.crc32(crc, 'some text') +print('updated crc: '..crc) +crc = zlib.crc32(crc, 'some text') +print('updated crc: '..crc) +crc = zlib.crc32(crc, 'some text') +print('updated crc: '..crc) +crc = zlib.crc32(crc, 'some textd') +print('updated crc: '..crc) + + +line(' deflate/inflate') +local us +f = io.open('lzlib.c') -- f = io.open('../all.tar') +us = f:read('*a') +f:close() + +do -- local block + +local f, cs, zd, zi, aux_res, res, ret, count + +print('file length : '..string.len(us)) + +cs = '' +zd = zlib.compressobj(1) +print('deflate stream : '..tostring(zd)) + +cs = cs .. zd:compress(string.sub(us, 1, string.len(us)/2)) +cs = cs .. zd:compress(string.sub(us, string.len(us)/2+1)) +cs = cs .. zd:flush() + +print('compressed length : '..string.len(cs)) +print('compressed adler : '..tostring(zd:adler())) +zd:close() + +zi = zlib.decompressobj() +print('inflate stream : '..tostring(zi)) +res = '' +res = res .. zi:decompress(string.sub(cs, 1, 10)) +res = res .. zi:decompress(string.sub(cs, 11)) +res = res .. zi:flush() +print('uncompressed length : '..string.len(res)) +print('uncompressed adler : '..tostring(zi:adler())) +zi:close() +print('result == uncompressed : '..tostring(res == us)) +print('compression ratio : '..tostring(string.len(us)/string.len(cs))) + +end -- local block +collectgarbage() + +line(' compress/uncompress') +do -- local block +local cs, res +print('file length : '..string.len(us)) +cs = zlib.compress(us,1) +print('compressed length : '..string.len(cs)) +res = zlib.decompress(cs) +print('uncompressed length : '..string.len(res)) +print('result == uncompressed : '..tostring(res == us)) +print('compression ratio : '..tostring(string.len(us)/string.len(cs))) +end -- local block + +line(' zlib '..zlib.version(), '=') diff --git a/src/main.c b/src/main.c index c4216b61e4d2784279d72602b84416b788570124..62940a0bcfd3dd04610ce26f07c8ae0797ea02ce 100644 --- a/src/main.c +++ b/src/main.c @@ -707,6 +707,7 @@ void boot_lua(int state, bool rebooting, int argc, char *argv[]) luaopen_shaders(L); luaopen_serial(L); luaopen_profile(L); + luaopen_zlib(L); // Override "print" if requested if (no_debug)