4 * Copyright 2015, 2016 Dima Krasner <dima@dimakrasner.com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * The views and conclusions contained in the software and documentation
31 * are those of the authors and should not be interpreted as representing
32 * official policies, either expressed or implied, of the Jim Tcl Project.
38 #include <jim-subcmd.h>
41 #define PASTE(x) _PASTE(x)
43 #define WBITS_GZIP (MAX_WBITS | 16)
44 /* use small 64K chunks if no size was specified during decompression, to reduce memory consumption */
45 #define DEF_DECOMPRESS_BUFSIZ (64 * 1024)
47 static int Jim_Crc32(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
54 init
= crc32(0L, Z_NULL
, 0);
56 if (Jim_GetLong(interp
, argv
[1], &init
) != JIM_OK
) {
61 in
= Jim_GetString(argv
[0], &len
);
62 Jim_SetResultInt(interp
, crc32((uLong
)init
, (const Bytef
*)in
, (uInt
)len
) & 0xFFFFFFFF);
67 static int Jim_Compress(Jim_Interp
*interp
, const char *in
, int len
, long level
, int wbits
)
72 if ((level
!= Z_DEFAULT_COMPRESSION
) && ((level
< Z_NO_COMPRESSION
) || (level
> Z_BEST_COMPRESSION
))) {
73 Jim_SetResultString(interp
, "level must be 0 to 9", -1);
77 if (deflateInit2(&strm
, level
, Z_DEFLATED
, wbits
, MAX_MEM_LEVEL
, Z_DEFAULT_STRATEGY
) != Z_OK
) {
81 strm
.avail_out
= deflateBound(&strm
, (uLong
)len
);
82 if (strm
.avail_out
> INT_MAX
) {
86 buf
= (Bytef
*)Jim_Alloc((int)strm
.avail_out
);
88 strm
.next_in
= (Bytef
*)in
;
89 strm
.avail_in
= (uInt
)len
;
91 /* always compress in one pass - the return value holds the entire
92 * decompressed data anyway, so there's no reason to do chunked
94 if (deflate(&strm
, Z_FINISH
) != Z_STREAM_END
) {
95 Jim_Free(strm
.next_out
);
102 if (strm
.total_out
> INT_MAX
) {
103 Jim_Free(strm
.next_out
);
107 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, (char *)buf
, (int)strm
.total_out
));
111 static int Jim_Deflate(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
113 long level
= Z_DEFAULT_COMPRESSION
;
118 if (Jim_GetLong(interp
, argv
[1], &level
) != JIM_OK
) {
123 in
= Jim_GetString(argv
[0], &len
);
124 return Jim_Compress(interp
, in
, len
, level
, -MAX_WBITS
);
127 static int Jim_Gzip(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
129 long level
= Z_DEFAULT_COMPRESSION
;
134 if (!Jim_CompareStringImmediate(interp
, argv
[1], "-level")) {
135 Jim_WrongNumArgs(interp
, 0, argv
, "data ?-level level?");
139 if (Jim_GetLong(interp
, argv
[2], &level
) != JIM_OK
) {
140 Jim_WrongNumArgs(interp
, 0, argv
, "data ?-level level?");
145 else if (argc
!= 1) {
146 Jim_WrongNumArgs(interp
, 0, argv
, "data ?-level level?");
150 in
= Jim_GetString(argv
[0], &len
);
151 return Jim_Compress(interp
, in
, len
, level
, WBITS_GZIP
);
154 static int Jim_Decompress(Jim_Interp
*interp
, const char *in
, int len
, long bufsiz
, int wbits
)
161 if ((bufsiz
<= 0) || (bufsiz
> INT_MAX
)) {
162 Jim_SetResultString(interp
, "buffer size must be 0 to "PASTE(INT_MAX
), -1);
166 if (inflateInit2(&strm
, wbits
) != Z_OK
) {
170 /* allocate a buffer - decompression is done in chunks, into this buffer;
171 * when the decompressed data size is given, decompression is faster because
172 * it's done in one pass, with less memcpy() overhead */
173 buf
= Jim_Alloc((int)bufsiz
);
175 out
= Jim_NewEmptyStringObj(interp
);
176 Jim_IncrRefCount(out
);
178 strm
.next_in
= (Bytef
*)in
;
179 strm
.avail_in
= (uInt
)len
;
183 strm
.avail_out
= (uInt
)bufsiz
;
185 ret
= inflate(&strm
, Z_NO_FLUSH
);
189 /* append each chunk to the output object */
190 Jim_AppendString(interp
, out
, buf
, (int)(bufsiz
- (long)strm
.avail_out
));
194 Jim_DecrRefCount(interp
, out
);
197 if (strm
.msg
!= NULL
)
198 Jim_SetResultString(interp
, strm
.msg
, -1);
201 } while (strm
.avail_out
== 0);
202 } while (ret
!= Z_STREAM_END
);
204 /* free memory used for decompression before we assign the return value */
208 Jim_SetResult(interp
, out
);
209 Jim_DecrRefCount(interp
, out
);
214 static int Jim_Inflate(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
216 long bufsiz
= DEF_DECOMPRESS_BUFSIZ
;
221 if (Jim_GetLong(interp
, argv
[1], &bufsiz
) != JIM_OK
) {
225 if ((bufsiz
<= 0) || (bufsiz
> INT_MAX
)) {
226 Jim_SetResultString(interp
, "buffer size must be 0 to "PASTE(INT_MAX
), -1);
231 in
= Jim_GetString(argv
[0], &len
);
232 return Jim_Decompress(interp
, in
, len
, bufsiz
, -MAX_WBITS
);
235 static int Jim_Gunzip(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
237 long bufsiz
= DEF_DECOMPRESS_BUFSIZ
;
242 if (!Jim_CompareStringImmediate(interp
, argv
[1], "-buffersize")) {
243 Jim_WrongNumArgs(interp
, 0, argv
, "data ?-buffersize size?");
247 if (Jim_GetLong(interp
, argv
[2], &bufsiz
) != JIM_OK
) {
248 Jim_WrongNumArgs(interp
, 0, argv
, "data ?-buffersize size?");
253 else if (argc
!= 1) {
254 Jim_WrongNumArgs(interp
, 0, argv
, "data ?-buffersize size?");
258 in
= Jim_GetString(argv
[0], &len
);
259 return Jim_Decompress(interp
, in
, len
, bufsiz
, WBITS_GZIP
);
262 static const jim_subcmd_type zlib_command_table
[] = {
268 /* Description: Calculates the CRC32 checksum of a string */
275 /* Description: Compresses a string and outputs a raw, zlib-compressed stream */
278 "data ?-level level?",
282 /* Description: Compresses a string and outputs a gzip-compressed stream */
289 /* Description: Decompresses a raw, zlib-compressed stream */
292 "data ?-buffersize size?",
296 /* Description: Decompresses a gzip-compressed stream */
301 static int JimZlibCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
303 return Jim_CallSubCmd(interp
, Jim_ParseSubCmd(interp
, zlib_command_table
, argc
, argv
), argc
, argv
);
306 int Jim_zlibInit(Jim_Interp
*interp
)
308 if (Jim_PackageProvide(interp
, "zlib", "1.0", JIM_ERRMSG
)) {
312 Jim_CreateCommand(interp
, "zlib", JimZlibCmd
, 0, 0);