lmtlzma.c /size: 7492 b    last modification: 2024-01-16 10:22
1/*
2    See license.txt in the root of this project.
3*/
4
5# include <stdlib.h>
6
7# include "luametatex.h"
8# include "lmtoptional.h"
9
10/*
11    We only need a few definitions and it's nice that they are already prepared for extensions.
12*/
13
14typedef enum {
15    LZMA_RESERVED_ENUM = 0
16} lzma_reserved_enum;
17
18typedef enum {
19    LZMA_OK                = 0,
20    LZMA_STREAM_END        = 1,
21    LZMA_NO_CHECK          = 2,
22    LZMA_UNSUPPORTED_CHECK = 3,
23    LZMA_GET_CHECK         = 4,
24    LZMA_MEM_ERROR         = 5,
25    LZMA_MEMLIMIT_ERROR    = 6,
26    LZMA_FORMAT_ERROR      = 7,
27    LZMA_OPTIONS_ERROR     = 8,
28    LZMA_DATA_ERROR        = 9,
29    LZMA_BUF_ERROR         = 10,
30    LZMA_PROG_ERROR        = 11,
31} lzma_ret;
32
33typedef enum {
34    LZMA_RUN          = 0,
35    LZMA_SYNC_FLUSH   = 1,
36    LZMA_FULL_FLUSH   = 2,
37    LZMA_FULL_BARRIER = 4,
38    LZMA_FINISH       = 3
39} lzma_action;
40
41typedef enum {
42    LZMA_CHECK_NONE   = 0,
43    LZMA_CHECK_CRC32  = 1,
44    LZMA_CHECK_CRC64  = 4,
45    LZMA_CHECK_SHA256 = 10
46} lzma_check;
47
48typedef struct lzma_internal_s lzma_internal;
49
50typedef struct {
51    void *(*alloc)(void *opaque, size_t nmemb, size_t size);
52    void  (*free )(void *opaque, void *ptr);
53    void *opaque;
54} lzma_allocator;
55
56typedef struct {
57    const uint8_t        *next_in;
58    size_t                avail_in;
59    uint64_t              total_in;
60    uint8_t              *next_out;
61    size_t                avail_out;
62    uint64_t              total_out;
63    const lzma_allocator *allocator;
64    lzma_internal        *internal;
65    void                 *reserved_ptr1;
66    void                 *reserved_ptr2;
67    void                 *reserved_ptr3;
68    void                 *reserved_ptr4;
69    uint64_t              reserved_int1;
70    uint64_t              reserved_int2;
71    size_t                reserved_int3;
72    size_t                reserved_int4;
73    lzma_reserved_enum    reserved_enum1;
74    lzma_reserved_enum    reserved_enum2;
75} lzma_stream;
76
77
78# define LZMA_STREAM_INIT { NULL, 0, 0, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, LZMA_RESERVED_ENUM, LZMA_RESERVED_ENUM }
79
80# define LZMA_TELL_NO_CHECK          UINT32_C(0x01)
81# define LZMA_TELL_UNSUPPORTED_CHECK UINT32_C(0x02)
82# define LZMA_TELL_ANY_CHECK         UINT32_C(0x04)
83# define LZMA_CONCATENATED           UINT32_C(0x08)
84
85typedef struct lzmalib_state_info {
86
87    int initialized;
88    int padding;
89
90    int (*lzma_auto_decoder) (lzma_stream *strm, uint64_t memlimit, uint32_t flags);
91    int (*lzma_easy_encoder) (lzma_stream *strm, uint32_t preset, lzma_check check);
92    int (*lzma_code)         (lzma_stream *strm, lzma_action action);
93    int (*lzma_end)          (lzma_stream *strm);
94
95} lzmalib_state_info;
96
97static lzmalib_state_info lzmalib_state = {
98
99    .initialized = 0,
100    .padding     = 0,
101
102    .lzma_auto_decoder = NULL,
103    .lzma_easy_encoder = NULL,
104    .lzma_code         = NULL,
105    .lzma_end          = NULL,
106};
107
108
109# define lzma_default_level 6
110# define lzma_default_size  0xFFFF
111
112static int lzmalib_compress(lua_State *L)
113{
114    if (lzmalib_state.initialized) {
115        size_t sourcesize = 0;
116        const char *source = luaL_checklstring(L, 1, &sourcesize);
117        int level = lmt_optinteger(L, 2, lzma_default_level);
118        int targetsize = lmt_optinteger(L, 3, lzma_default_size);
119        if (level < 0 || level > 9) {
120            level = lzma_default_level;
121        }
122        if (source) {
123            lzma_stream strm = LZMA_STREAM_INIT;
124            int errorcode = lzmalib_state.lzma_easy_encoder(&strm, level, LZMA_CHECK_CRC64);
125            if (errorcode == LZMA_OK) {
126                luaL_Buffer buffer;
127                luaL_buffinit(L, &buffer);
128                strm.next_in = (const uint8_t *) source;
129                strm.avail_in = sourcesize;
130                if (targetsize < lzma_default_size) {
131                    targetsize = lzma_default_size;
132                }
133                while (1) {
134                    char *target = luaL_prepbuffsize(&buffer, targetsize);
135                    size_t produced = strm.total_out;
136                    strm.next_out = (uint8_t *) target;
137                    strm.avail_out = targetsize;
138                    errorcode = lzmalib_state.lzma_code(&strm, LZMA_FINISH);
139                    produced = strm.total_out - produced;
140                    luaL_addsize(&buffer, produced);
141                    if (errorcode == LZMA_STREAM_END) {
142                        lzmalib_state.lzma_end(&strm);
143                        luaL_pushresult(&buffer);
144                        return 1;
145                    } else if (errorcode != LZMA_OK) {
146                        lzmalib_state.lzma_end(&strm);
147                        break;
148                    }
149                }
150            }
151        }
152    }
153    lua_pushnil(L);
154    return 1;
155}
156
157static int lzmalib_decompress(lua_State *L)
158{
159    if (lzmalib_state.initialized) {
160        size_t sourcesize = 0;
161        const char *source = luaL_checklstring(L, 1, &sourcesize);
162        int targetsize = lmt_optinteger(L, 2, lzma_default_size);
163        if (source) {
164            lzma_stream strm = LZMA_STREAM_INIT;
165            int errorcode = lzmalib_state.lzma_auto_decoder(&strm, UINT64_MAX, LZMA_CONCATENATED);
166            if (errorcode == LZMA_OK) {
167                luaL_Buffer buffer;
168                luaL_buffinit(L, &buffer);
169                strm.next_in = (const uint8_t *) source;
170                strm.avail_in = sourcesize;
171                if (targetsize < lzma_default_size) {
172                    targetsize = lzma_default_size;
173                }
174                while (1) {
175                    char *target = luaL_prepbuffsize(&buffer, targetsize);
176                    size_t produced = strm.total_out;
177                    strm.next_out = (uint8_t *) target;
178                    strm.avail_out = targetsize;
179                    errorcode = lzmalib_state.lzma_code(&strm, LZMA_RUN);
180                    produced = strm.total_out - produced;
181                    luaL_addsize(&buffer, produced);
182                    if (errorcode == LZMA_STREAM_END || produced == 0) {
183                        lzmalib_state.lzma_end(&strm);
184                        luaL_pushresult(&buffer);
185                        return 1;
186                    } else if (errorcode != LZMA_OK) {
187                        lzmalib_state.lzma_end(&strm);
188                        break;
189                    }
190                }
191            }
192        }
193    }
194    lua_pushnil(L);
195    return 1;
196}
197
198static int lzmalib_initialize(lua_State *L)
199{
200    if (! lzmalib_state.initialized) {
201        const char *filename = lua_tostring(L, 1);
202        if (filename) {
203
204            lmt_library lib = lmt_library_load(filename);
205
206            lzmalib_state.lzma_auto_decoder = lmt_library_find(lib, "lzma_auto_decoder");
207            lzmalib_state.lzma_easy_encoder = lmt_library_find(lib, "lzma_easy_encoder");
208            lzmalib_state.lzma_code         = lmt_library_find(lib, "lzma_code");
209            lzmalib_state.lzma_end          = lmt_library_find(lib, "lzma_end");
210
211            lzmalib_state.initialized = lmt_library_okay(lib);
212        }
213    }
214    lua_pushboolean(L, lzmalib_state.initialized);
215    return 1;
216}
217
218static struct luaL_Reg lzmalib_function_list[] = {
219    { "initialize", lzmalib_initialize },
220    { "compress",   lzmalib_compress   },
221    { "decompress", lzmalib_decompress },
222    { NULL,         NULL               },
223};
224
225int luaopen_lzma(lua_State * L)
226{
227    lmt_library_register(L, "lzma", lzmalib_function_list);
228    return 0;
229}
230