lmtziplib.c /size: 6672 b    last modification: 2024-01-16 10:22
1/*
2    See license.txt in the root of this project.
3*/
4
5# define ZLIB_CONST 1
6
7# include "luametatex.h"
8
9/*tex
10
11    This is a rather minimalistic interface to zlib. We can wrap around it and need some specific
12    file overhead anyway. Also, we never needed all that stream stuff.
13
14*/
15
16# define ziplib_in_char_ptr   const unsigned char *
17# define ziplib_out_char_ptr  unsigned char *
18
19# define ziplib_buffer_size 16*1024
20
21static int ziplib_aux_compress(
22    lua_State  *L,
23    const char *data,
24    int         size,
25    int         level,
26    int         method,
27    int         window,
28    int         memory,
29    int         strategy,
30    int         buffersize
31)
32{
33    int state;
34    z_stream zipstream;
35    zipstream.zalloc = &lmt_zlib_alloc; /* Z_NULL */
36    zipstream.zfree = &lmt_zlib_free; /* Z_NULL */
37    zipstream.next_out = Z_NULL;
38    zipstream.avail_out = 0;
39    zipstream.next_in = Z_NULL;
40    zipstream.avail_in = 0;
41    state = deflateInit2(&zipstream, level, method, window, memory, strategy);
42    if (state == Z_OK) {
43        luaL_Buffer buffer;
44        luaL_buffinit(L, &buffer);
45        zipstream.next_in = (ziplib_in_char_ptr) data;
46        zipstream.avail_in = size;
47        while (1) {
48            zipstream.next_out = (ziplib_out_char_ptr) luaL_prepbuffsize(&buffer, buffersize);
49            zipstream.avail_out = buffersize;
50            state = deflate(&zipstream, Z_FINISH);
51            if (state != Z_OK && state != Z_STREAM_END) {
52                lua_pushnil(L);
53                break;
54            } else {
55                luaL_addsize(&buffer, buffersize - zipstream.avail_out);
56                if (zipstream.avail_out != 0) {
57                    luaL_pushresult(&buffer);
58                    break;
59                }
60            }
61        }
62        deflateEnd(&zipstream);
63    } else {
64        lua_pushnil(L);
65    }
66    return 1;
67}
68
69static int ziplib_compress(lua_State *L)
70{
71    const char *data = luaL_checkstring(L, 1);
72    int size = (int) lua_rawlen(L, 1);
73    int level = lmt_optinteger(L, 2, Z_DEFAULT_COMPRESSION);
74    int method = lmt_optinteger(L, 3, Z_DEFLATED);
75    int window = lmt_optinteger(L, 4, 15);
76    int memory = lmt_optinteger(L, 5, 8);
77    int strategy = lmt_optinteger(L, 6, Z_DEFAULT_STRATEGY);
78    return ziplib_aux_compress(L, data, size, level, method, window, memory, strategy, ziplib_buffer_size);
79}
80
81static int ziplib_compresssize(lua_State *L)
82{
83    const char *data = luaL_checkstring(L, 1);
84    int size = (int) lua_rawlen(L, 1);
85    int level = lmt_optinteger(L, 2, Z_DEFAULT_COMPRESSION);
86    int buffersize = lmt_optinteger(L, 3, ziplib_buffer_size);
87    int window = lmt_optinteger(L, 4, 15); /* like decompresssize */
88    return ziplib_aux_compress(L, data, size, level, Z_DEFLATED, window, 8, Z_DEFAULT_STRATEGY, buffersize);
89}
90
91static int ziplib_decompress(lua_State *L)
92{
93    const char *data = luaL_checkstring(L, 1);
94    int size = (int) lua_rawlen(L, 1);
95    int window = lmt_optinteger(L, 2, 15);
96    int state;
97    z_stream zipstream;
98    zipstream.zalloc = &lmt_zlib_alloc; /* Z_NULL */
99    zipstream.zfree = &lmt_zlib_free; /* Z_NULL */
100    zipstream.next_out = Z_NULL;
101    zipstream.avail_out = 0;
102    zipstream.next_in = Z_NULL;
103    zipstream.avail_in = 0;
104    state = inflateInit2(&zipstream, window);
105    if (state == Z_OK) {
106        luaL_Buffer buffer;
107        luaL_buffinit(L, &buffer);
108        zipstream.next_in = (ziplib_in_char_ptr) data;
109        zipstream.avail_in = size;
110        while (1) {
111            zipstream.next_out = (ziplib_out_char_ptr) luaL_prepbuffsize(&buffer, ziplib_buffer_size);
112            zipstream.avail_out = ziplib_buffer_size;
113            state = inflate(&zipstream, Z_NO_FLUSH);
114            luaL_addsize(&buffer, ziplib_buffer_size - zipstream.avail_out);
115            if (state == Z_STREAM_END) {
116                luaL_pushresult(&buffer);
117                break;
118            } else if (state != Z_OK) {
119                lua_pushnil(L);
120                break;
121            } else if (zipstream.avail_out == 0) {
122                continue;
123            } else if (zipstream.avail_in == 0) {
124                luaL_pushresult(&buffer);
125                break;
126            }
127        }
128        inflateEnd(&zipstream);
129    } else {
130        lua_pushnil(L);
131    }
132    return 1;
133}
134
135static int ziplib_decompresssize(lua_State *L)
136{
137    const char *data = luaL_checkstring(L, 1);
138    int size = (int) lua_rawlen(L, 1);
139    int targetsize = lmt_tointeger(L, 2);
140    int window = lmt_optinteger(L, 3, 15);
141    int state;
142    z_stream zipstream;
143    zipstream.zalloc = &lmt_zlib_alloc; /* Z_NULL */
144    zipstream.zfree = &lmt_zlib_free; /* Z_NULL */
145    zipstream.next_out = Z_NULL;
146    zipstream.avail_out = 0;
147    zipstream.next_in = Z_NULL;
148    zipstream.avail_in = 0;
149    state = inflateInit2(&zipstream, window);
150    if (state == Z_OK) {
151        luaL_Buffer buffer;
152        zipstream.next_in = (ziplib_in_char_ptr) data;
153        zipstream.avail_in = size;
154        zipstream.next_out = (ziplib_out_char_ptr) luaL_buffinitsize(L, &buffer, (lua_Integer) targetsize + 100);
155        zipstream.avail_out = targetsize + 100;
156        state = inflate(&zipstream, Z_NO_FLUSH); /* maybe Z_FINISH buffer large enough */
157        if (state != Z_OK && state != Z_STREAM_END) {
158            lua_pushnil(L);
159        } else if (zipstream.avail_in == 0) {
160            luaL_pushresultsize(&buffer, targetsize);
161        } else {
162            lua_pushnil(L);
163        }
164        inflateEnd(&zipstream);
165    } else {
166        lua_pushnil(L);
167    }
168    return 1;
169}
170
171static int ziplib_adler32(lua_State *L)
172{
173    int checksum = lmt_optinteger(L, 2, 0);
174    size_t buffersize = 0;
175    const char *buffer = lua_tolstring(L, 1, &buffersize);
176    checksum = adler32(checksum, (ziplib_in_char_ptr) buffer, (unsigned int) buffersize);
177    lua_pushinteger(L, checksum);
178    return 1;
179}
180
181static int ziplib_crc32(lua_State *L)
182{
183    int checksum = lmt_optinteger(L, 2, 0);
184    size_t buffersize = 0;
185    const char *buffer = lua_tolstring(L, 1, &buffersize);
186    checksum = crc32(checksum, (ziplib_in_char_ptr) buffer, (unsigned int) buffersize);
187    lua_pushinteger(L, checksum);
188    return 1;
189}
190
191static struct luaL_Reg ziplib_function_list[] = {
192    { "compress",       ziplib_compress       },
193    { "compresssize",   ziplib_compresssize   },
194    { "decompress",     ziplib_decompress     },
195    { "decompresssize", ziplib_decompresssize },
196    { "adler32",        ziplib_adler32        },
197    { "crc32",          ziplib_crc32          },
198    { NULL,             NULL                  },
199};
200
201int luaopen_xzip(lua_State *L) {
202    lua_newtable(L);
203    luaL_setfuncs(L, ziplib_function_list, 0);
204    return 1;
205}
206
207