lmtlz4.c /size: 7274 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# define LZ4F_VERSION 100  /* used to check for an incompatible API breaking change */
11
12typedef struct lz4lib_state_info {
13
14    int initialized;
15    int padding;
16
17    int      (*LZ4_compressBound)               (int inputSize);
18    int      (*LZ4_compress_fast)               (const char *src, char *dst, int srcSize, int dstCapacity, int acceleration);
19    int      (*LZ4_decompress_safe)             (const char *src, char *dst, int compressedSize, int dstCapacity);
20    size_t   (*LZ4F_compressFrameBound)         (size_t srcSize, void *);
21    size_t   (*LZ4F_compressFrame)              (void *dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, void *);
22    unsigned (*LZ4F_isError)                    (int code);
23    int      (*LZ4F_createDecompressionContext) (void **dctxPtr, unsigned version);
24    int      (*LZ4F_freeDecompressionContext)   (void *dctx);
25    size_t   (*LZ4F_decompress)                 (void *dctx, void *dstBuffer, size_t *dstSizePtr, const void *srcBuffer, size_t *srcSizePtr, void *);
26
27} lz4lib_state_info;
28
29static lz4lib_state_info lz4lib_state = {
30
31    .initialized = 0,
32    .padding     = 0,
33
34    .LZ4_compressBound               = NULL,
35    .LZ4_compress_fast               = NULL,
36    .LZ4_decompress_safe             = NULL,
37    .LZ4F_compressFrameBound         = NULL,
38    .LZ4F_compressFrame              = NULL,
39    .LZ4F_isError                    = NULL,
40    .LZ4F_createDecompressionContext = NULL,
41    .LZ4F_freeDecompressionContext   = NULL,
42    .LZ4F_decompress                 = NULL,
43
44};
45
46static int lz4lib_compress(lua_State *L)
47{
48    if (lz4lib_state.initialized) {
49        size_t sourcesize = 0;
50        const char *source = luaL_checklstring(L, 1, &sourcesize);
51        lua_Integer acceleration = luaL_optinteger(L, 2, 1);
52        size_t targetsize = lz4lib_state.LZ4_compressBound((int) sourcesize);
53        luaL_Buffer buffer;
54        char *target = luaL_buffinitsize(L, &buffer, targetsize);
55        int result = lz4lib_state.LZ4_compress_fast(source, target, (int) sourcesize, (int) targetsize, (int) acceleration);
56        if (result > 0) {
57            luaL_pushresultsize(&buffer, result);
58        } else {
59            lua_pushnil(L);
60        }
61    }
62    return 1;
63}
64
65/*
66
67    There is no info about the target size so we don't provide a decompress function. Either use
68    the frame variant or save and restore the targetsize,
69
70    static int lz4lib_decompress(lua_State *L)
71    {
72        lua_pushnil(L);
73        return 1;
74    }
75
76*/
77
78static int lz4lib_decompresssize(lua_State *L)
79{
80    if (lz4lib_state.initialized) {
81        size_t sourcesize = 0;
82        size_t targetsize = luaL_checkinteger(L, 2);
83        const char *source = luaL_checklstring(L, 1, &sourcesize);
84        if (source && targetsize > 0) {
85            luaL_Buffer buffer;
86            char *target = luaL_buffinitsize(L, &buffer, targetsize);
87            int result = lz4lib_state.LZ4_decompress_safe(source, target, (int) sourcesize, (int) targetsize);
88            if (result > 0) {
89                luaL_pushresultsize(&buffer, result);
90            } else {
91                lua_pushnil(L);
92            }
93        } else {
94            lua_pushnil(L);
95        }
96    }
97    return 1;
98}
99
100static int lz4lib_framecompress(lua_State *L)
101{
102    if (lz4lib_state.initialized) {
103        size_t sourcesize = 0;
104        const char *source = luaL_checklstring(L, 1, &sourcesize);
105        luaL_Buffer buffer;
106        size_t targetsize = lz4lib_state.LZ4F_compressFrameBound(sourcesize, NULL);
107        char *target = luaL_buffinitsize(L, &buffer, targetsize);
108        size_t result = lz4lib_state.LZ4F_compressFrame(target, targetsize, source, sourcesize, NULL);
109        luaL_pushresultsize(&buffer, result);
110    }
111    return 1;
112}
113
114static int lz4lib_framedecompress(lua_State *L)
115{
116    if (lz4lib_state.initialized) {
117        size_t sourcesize = 0;
118        const char *source = luaL_checklstring(L, 1, &sourcesize);
119        if (source) {
120            void *context = NULL;
121            int errorcode = lz4lib_state.LZ4F_createDecompressionContext(&context, LZ4F_VERSION);
122            if (lz4lib_state.LZ4F_isError(errorcode)) {
123                lua_pushnil(L);
124            } else {
125                luaL_Buffer buffer;
126                luaL_buffinit(L, &buffer);
127                while (1) {
128                    size_t targetsize = 0xFFFF;
129                    char *target = luaL_prepbuffsize(&buffer, targetsize);
130                    size_t consumed = sourcesize;
131                    size_t errorcode = lz4lib_state.LZ4F_decompress(context, target, &targetsize, source, &consumed, NULL);
132                    if (lz4lib_state.LZ4F_isError((int) errorcode)) {
133                        lua_pushnil(L);
134                        break;
135                    } else if (targetsize == 0) {
136                        luaL_pushresult(&buffer);
137                        break;
138                    } else {
139                        luaL_addsize(&buffer, targetsize);
140                        sourcesize -= consumed;
141                        source += consumed;
142                    }
143                }
144            }
145            if (context) {
146                lz4lib_state.LZ4F_freeDecompressionContext(context);
147            }
148        } else {
149            lua_pushnil(L);
150        }
151    }
152    return 1;
153}
154
155static int lz4lib_initialize(lua_State *L)
156{
157    if (! lz4lib_state.initialized) {
158        const char *filename = lua_tostring(L, 1);
159        if (filename) {
160
161            lmt_library lib = lmt_library_load(filename);
162
163            lz4lib_state.LZ4_compressBound               = lmt_library_find(lib, "LZ4_compressBound");
164            lz4lib_state.LZ4_compress_fast               = lmt_library_find(lib, "LZ4_compress_fast");
165            lz4lib_state.LZ4_decompress_safe             = lmt_library_find(lib, "LZ4_decompress_safe");
166            lz4lib_state.LZ4F_compressFrameBound         = lmt_library_find(lib, "LZ4F_compressFrameBound");
167            lz4lib_state.LZ4F_compressFrame              = lmt_library_find(lib, "LZ4F_compressFrame");
168            lz4lib_state.LZ4F_isError                    = lmt_library_find(lib, "LZ4F_isError");
169            lz4lib_state.LZ4F_createDecompressionContext = lmt_library_find(lib, "LZ4F_createDecompressionContext");
170            lz4lib_state.LZ4F_freeDecompressionContext   = lmt_library_find(lib, "LZ4F_freeDecompressionContext");
171            lz4lib_state.LZ4F_decompress                 = lmt_library_find(lib, "LZ4F_decompress");
172
173            lz4lib_state.initialized = lmt_library_okay(lib);
174        }
175    }
176    lua_pushboolean(L, lz4lib_state.initialized);
177    return 1;
178}
179
180static struct luaL_Reg lz4lib_function_list[] = {
181    { "initialize",      lz4lib_initialize      },
182    { "compress",        lz4lib_compress        },
183 /* { "decompress",      lz4lib_decompress      }, */
184    { "decompresssize",  lz4lib_decompresssize  },
185    { "framecompress",   lz4lib_framecompress   },
186    { "framedecompress", lz4lib_framedecompress },
187    { NULL,              NULL                   },
188};
189
190int luaopen_lz4(lua_State * L)
191{
192    lmt_library_register(L, "lz4", lz4lib_function_list);
193    return 0;
194}
195