1 /* -*- mode: C; mode: fold; -*- */
2 /*
3 Copyright (C) 2008-2017,2018 John E. Davis
4
5 This file is part of the S-Lang Library.
6
7 The S-Lang Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 The S-Lang Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 USA.
21 */
22
23 #include "config.h"
24
25 #include <stdio.h>
26 #include <errno.h>
27 #include <slang.h>
28
29 #include <string.h>
30 #include <zlib.h>
31
32 SLANG_MODULE(zlib);
33
34 static SLFUTURE_CONST char *Module_Version_String = "0.1.0";
35 #define MODULE_VERSION_NUMBER (0*10000 + 1*100 + 0)
36
37 typedef struct
38 {
39 int type;
40 #define DEFLATE_TYPE 1
41 #define INFLATE_TYPE 2
42
43 int initialized;
44 z_stream zs;
45
46 #define DEFAULT_START_BUFLEN 0x4000
47 SLstrlen_Type start_buflen;
48 #define DEFAULT_BUFLEN_INC 0x4000
49 SLstrlen_Type dbuflen;
50 int windowbits;
51 }
52 ZLib_Type;
53
54 static int ZLib_Type_Id = -1;
55 int ZLib_Error = -1;
56
check_zerror(int e)57 static int check_zerror (int e)
58 {
59 switch (e)
60 {
61 case Z_ERRNO:
62 e = errno;
63 (void) SLerrno_set_errno (e);
64 SLang_verror (ZLib_Error, "Z library errno error: %s", SLerrno_strerror(e));
65 break;
66
67 case Z_STREAM_ERROR:
68 SLang_verror (ZLib_Error, "Z library stream error");
69 break;
70
71 case Z_DATA_ERROR:
72 SLang_verror (ZLib_Error, "Z library data error");
73 break;
74
75 case Z_MEM_ERROR:
76 SLang_verror (SL_Malloc_Error, "Z library memory allocation error");
77 break;
78
79 case Z_BUF_ERROR:
80 SLang_verror (ZLib_Error, "Z library buffer error");
81 break;
82
83 case Z_VERSION_ERROR:
84 SLang_verror (ZLib_Error, "Z library version mismatch error");
85 break;
86
87 case Z_NEED_DICT: /* not handled by this module */
88 SLang_verror (ZLib_Error, "Z library dictionary error");
89 break;
90
91 default:
92 if (e >= 0)
93 return 0;
94
95 SLang_verror (ZLib_Error, "Unknown Error Code");
96 }
97 return -1;
98 }
99
check_deflate_object(ZLib_Type * zp)100 static int check_deflate_object (ZLib_Type *zp)
101 {
102 if (zp->type != DEFLATE_TYPE)
103 {
104 SLang_verror (SL_TypeMismatch_Error, "Expecting a Zlib_Type deflate object");
105 return -1;
106 }
107 return 0;
108 }
109
check_inflate_object(ZLib_Type * zp)110 static int check_inflate_object (ZLib_Type *zp)
111 {
112 if (zp->type != INFLATE_TYPE)
113 {
114 SLang_verror (SL_TypeMismatch_Error, "Expecting a Zlib_Type inflate object");
115 return -1;
116 }
117 return 0;
118 }
119
init_deflate_object(ZLib_Type * z,int level,int method,int windowbits,int memlevel,int strategy)120 static int init_deflate_object (ZLib_Type *z,
121 int level, int method, int windowbits,
122 int memlevel, int strategy)
123 {
124 z_stream *zs;
125 int ret;
126
127 memset ((char *) z, 0, sizeof(ZLib_Type));
128 z->type = DEFLATE_TYPE;
129 z->start_buflen = DEFAULT_START_BUFLEN;
130 z->dbuflen = DEFAULT_BUFLEN_INC;
131
132 zs = &z->zs;
133
134 zs->zalloc = Z_NULL;
135 zs->zfree = Z_NULL;
136 zs->opaque = Z_NULL;
137
138 ret = deflateInit2 (zs, level, method, windowbits, memlevel, strategy);
139 if (ret == Z_STREAM_ERROR)
140 {
141 SLang_verror (ZLib_Error, "One of more deflate parameters are invalid.");
142 deflateEnd (zs);
143 }
144
145 if (-1 == check_zerror (ret))
146 {
147 deflateEnd (zs);
148 return -1;
149 }
150
151 z->initialized = 1;
152 return 0;
153 }
154
run_deflate(ZLib_Type * z,int flush,unsigned char * str,SLstrlen_Type len,unsigned char ** bufp,SLstrlen_Type * totalp)155 static int run_deflate (ZLib_Type *z, int flush,
156 unsigned char *str, SLstrlen_Type len,
157 unsigned char **bufp, SLstrlen_Type *totalp)
158 {
159 z_stream *zs;
160 unsigned char *buf;
161 SLstrlen_Type buflen;
162
163 zs = &z->zs;
164
165 buflen = z->start_buflen;
166 if (NULL == (buf = (unsigned char *) SLmalloc (buflen+1)))
167 {
168 *bufp = NULL;
169 *totalp = 0;
170 return -1;
171 }
172
173 zs->next_in = str;
174 zs->avail_in = len;
175 zs->next_out = buf;
176 zs->avail_out = buflen;
177
178 while (1)
179 {
180 SLstrlen_Type total;
181 int ret;
182
183 ret = deflate (zs, flush);
184
185 if (ret != Z_BUF_ERROR)
186 {
187 if (-1 == check_zerror (ret))
188 goto return_error;
189 }
190
191 total = buflen - zs->avail_out;
192
193 if (/* done -- flush == Z_FINISH */
194 (ret == Z_STREAM_END)
195 /* Done with current input */
196 || ((zs->avail_in == 0) && (zs->avail_out != 0))
197 )
198 {
199 if (total != buflen)
200 {
201 unsigned char *new_buf;
202
203 new_buf = (unsigned char *) SLrealloc ((char *)buf, total+1);
204 if (new_buf == NULL)
205 goto return_error;
206
207 buf = new_buf;
208 }
209 buf[total] = 0; /* ok, because of +1 in malloc calls */
210 *bufp = buf;
211 *totalp = total;
212 return 0;
213 }
214
215 if (zs->avail_out == 0)
216 {
217 unsigned char *new_buf;
218 SLstrlen_Type dbuflen = z->dbuflen;
219 buflen += dbuflen;
220 new_buf = (unsigned char *)SLrealloc ((char *) buf, buflen+1);
221 if (new_buf == NULL)
222 goto return_error;
223
224 buf = new_buf;
225 zs->avail_out = dbuflen;
226 zs->next_out = buf + total;
227 }
228 }
229
230 return_error:
231 SLfree ((char *) buf);
232 *bufp = NULL;
233 *totalp = 0;
234 return -1;
235 }
236
deflate_intrin(ZLib_Type * zp,SLang_BString_Type * inbstr,int * flush)237 static void deflate_intrin (ZLib_Type *zp, SLang_BString_Type *inbstr, int *flush)
238 {
239 SLang_BString_Type *outbstr;
240 unsigned char *inbuf, *outbuf;
241 SLstrlen_Type inlen, outlen;
242
243 if (-1 == check_deflate_object (zp))
244 return;
245
246 if (NULL == (inbuf = SLbstring_get_pointer (inbstr, &inlen)))
247 return;
248
249 if (zp->start_buflen < inlen)
250 zp->start_buflen = inlen;
251
252 if (-1 == run_deflate (zp, *flush, inbuf, inlen, &outbuf, &outlen))
253 return;
254
255 if (NULL == (outbstr = SLbstring_create_malloced (outbuf, outlen, 1)))
256 return;
257
258 (void) SLang_push_bstring (outbstr);
259 SLbstring_free (outbstr);
260 }
261
deflate_reset_intrin(ZLib_Type * z)262 static void deflate_reset_intrin (ZLib_Type *z)
263 {
264 if (-1 == check_deflate_object (z))
265 return;
266
267 check_zerror (deflateReset (&z->zs));
268 }
269
deflate_flush_intrin(ZLib_Type * z,int * flush)270 static void deflate_flush_intrin (ZLib_Type *z, int *flush)
271 {
272 unsigned char *buf;
273 SLstrlen_Type len;
274 SLang_BString_Type *bstr;
275
276 if (-1 == check_deflate_object (z))
277 return;
278
279 if (-1 == run_deflate (z, *flush, (unsigned char *)"", 0, &buf, &len))
280 return;
281
282 if (NULL == (bstr = SLbstring_create_malloced (buf, len, 1)))
283 return;
284
285 (void) SLang_push_bstring (bstr);
286 SLbstring_free (bstr);
287 }
288
free_deflate_object(ZLib_Type * z)289 static void free_deflate_object (ZLib_Type *z)
290 {
291 if (z->initialized)
292 deflateEnd (&z->zs);
293 SLfree ((char *) z);
294 }
295
deflate_new_intrin(int * level,int * method,int * wbits,int * memlevel,int * strategy)296 static void deflate_new_intrin (int *level, int *method, int *wbits,
297 int *memlevel, int *strategy)
298 {
299 /* According to the docs, the parameters are checked by deflateInit2 */
300 ZLib_Type *z;
301 SLang_MMT_Type *mmt;
302
303 if (NULL == (z = (ZLib_Type *) SLmalloc (sizeof (ZLib_Type))))
304 return;
305
306 if (-1 == init_deflate_object (z, *level, *method, *wbits, *memlevel, *strategy))
307 {
308 SLfree ((char *) z);
309 return;
310 }
311
312 if (NULL == (mmt = SLang_create_mmt (ZLib_Type_Id, (VOID_STAR) z)))
313 {
314 free_deflate_object (z);
315 return;
316 }
317
318 if (0 == SLang_push_mmt (mmt))
319 return;
320
321 SLang_free_mmt (mmt);
322 }
323
run_inflate(ZLib_Type * z,int flush,unsigned char * str,SLstrlen_Type len,unsigned char ** bufp,SLstrlen_Type * totalp)324 static int run_inflate (ZLib_Type *z, int flush,
325 unsigned char *str, SLstrlen_Type len,
326 unsigned char **bufp, SLstrlen_Type *totalp)
327 {
328 z_stream *zs;
329 unsigned char *buf;
330 SLstrlen_Type buflen;
331
332 zs = &z->zs;
333 zs->next_in = str;
334 zs->avail_in = len;
335
336 if (z->initialized == 0)
337 {
338 zs = &z->zs;
339 zs->zalloc = Z_NULL;
340 zs->zfree = Z_NULL;
341 zs->opaque = Z_NULL;
342
343 if (-1 == check_zerror (inflateInit2 (zs, z->windowbits)))
344 {
345 inflateEnd (zs);
346 return -1;
347 }
348 z->initialized = 1;
349 }
350
351 buflen = z->start_buflen;
352 if (NULL == (buf = (unsigned char *) SLmalloc (buflen+1)))
353 {
354 *bufp = NULL;
355 *totalp = 0;
356 return -1;
357 }
358 zs->next_out = buf;
359 zs->avail_out = buflen;
360
361 while (1)
362 {
363 SLstrlen_Type total;
364 int ret;
365
366 ret = inflate (zs, flush);
367
368 if (ret != Z_BUF_ERROR)
369 {
370 if (-1 == check_zerror (ret))
371 goto return_error;
372 }
373
374 total = buflen - zs->avail_out;
375
376 if (/* done -- flush == Z_FINISH */
377 (ret == Z_STREAM_END)
378 /* Done with current input */
379 || ((zs->avail_in == 0) && (zs->avail_out != 0))
380 )
381 {
382 if (total != buflen)
383 {
384 unsigned char *new_buf;
385
386 new_buf = (unsigned char *) SLrealloc ((char *)buf, total+1);
387 if (new_buf == NULL)
388 goto return_error;
389
390 buf = new_buf;
391 }
392 buf[total] = 0; /* ok, because of +1 in malloc calls */
393 *bufp = buf;
394 *totalp = total;
395 return 0;
396 }
397
398 if (zs->avail_out == 0)
399 {
400 unsigned char *new_buf;
401 SLstrlen_Type dbuflen = z->dbuflen;
402 buflen += dbuflen;
403 new_buf = (unsigned char *)SLrealloc ((char *) buf, buflen+1);
404 if (new_buf == NULL)
405 goto return_error;
406
407 buf = new_buf;
408 zs->avail_out = dbuflen;
409 zs->next_out = buf + total;
410 }
411 }
412
413 return_error:
414 SLfree ((char *) buf);
415 *bufp = NULL;
416 *totalp = 0;
417 return -1;
418 }
419
inflate_intrin(ZLib_Type * zp,SLang_BString_Type * inbstr,int * flush)420 static void inflate_intrin (ZLib_Type *zp, SLang_BString_Type *inbstr, int *flush)
421 {
422 SLang_BString_Type *outbstr;
423 unsigned char *inbuf, *outbuf;
424 SLstrlen_Type inlen, outlen;
425
426 if (-1 == check_inflate_object (zp))
427 return;
428
429 if (NULL == (inbuf = SLbstring_get_pointer (inbstr, &inlen)))
430 return;
431
432 if (zp->start_buflen < inlen)
433 zp->start_buflen = inlen;
434
435 if (-1 == run_inflate (zp, *flush, inbuf, inlen, &outbuf, &outlen))
436 return;
437
438 if (NULL == (outbstr = SLbstring_create_malloced (outbuf, outlen, 1)))
439 return;
440
441 (void) SLang_push_bstring (outbstr);
442 SLbstring_free (outbstr);
443 }
444
init_inflate_object(ZLib_Type * z,int windowbits)445 static int init_inflate_object (ZLib_Type *z, int windowbits)
446 {
447 memset ((char *) z, 0, sizeof(ZLib_Type));
448 z->type = INFLATE_TYPE;
449 z->windowbits = windowbits;
450 z->initialized = 0;
451 z->start_buflen = DEFAULT_START_BUFLEN;
452 z->dbuflen = DEFAULT_BUFLEN_INC;
453 return 0;
454 }
455
inflate_new_intrin(int * windowbits)456 static void inflate_new_intrin (int *windowbits)
457 {
458 ZLib_Type *z;
459 SLang_MMT_Type *mmt;
460
461 if (NULL == (z = (ZLib_Type *) SLmalloc (sizeof (ZLib_Type))))
462 return;
463
464 if (-1 == init_inflate_object (z, *windowbits))
465 {
466 SLfree ((char *) z);
467 return;
468 }
469
470 if (NULL == (mmt = SLang_create_mmt (ZLib_Type_Id, (VOID_STAR) z)))
471 {
472 free_deflate_object (z);
473 return;
474 }
475
476 if (0 == SLang_push_mmt (mmt))
477 return;
478
479 SLang_free_mmt (mmt);
480 }
481
inflate_reset_intrin(ZLib_Type * z)482 static void inflate_reset_intrin (ZLib_Type *z)
483 {
484 if (-1 == check_inflate_object (z))
485 return;
486
487 if (z->initialized)
488 check_zerror (deflateReset (&z->zs));
489 }
490
inflate_flush_intrin(ZLib_Type * z,int * flush)491 static void inflate_flush_intrin (ZLib_Type *z, int *flush)
492 {
493 unsigned char *buf;
494 SLstrlen_Type len;
495 SLang_BString_Type *bstr;
496
497 if (-1 == check_inflate_object (z))
498 return;
499
500 if (-1 == run_inflate (z, *flush, (unsigned char *)"", 0, &buf, &len))
501 return;
502
503 if (NULL == (bstr = SLbstring_create_malloced (buf, len, 1)))
504 return;
505
506 (void) SLang_push_bstring (bstr);
507 SLbstring_free (bstr);
508 }
509
free_inflate_object(ZLib_Type * z)510 static void free_inflate_object (ZLib_Type *z)
511 {
512 if (z->initialized)
513 inflateEnd (&z->zs);
514 SLfree ((char *) z);
515 }
516
destroy_zlib_type(SLtype type,VOID_STAR f)517 static void destroy_zlib_type (SLtype type, VOID_STAR f)
518 {
519 ZLib_Type *z;
520 (void) type;
521
522 z = (ZLib_Type *) f;
523 if (z->type == DEFLATE_TYPE)
524 free_deflate_object (z);
525 else
526 free_inflate_object (z);
527 }
528
zlib_version_intrin(void)529 static const char *zlib_version_intrin (void)
530 {
531 return zlibVersion ();
532 }
533
534 #define DUMMY_ZLIB_TYPE ((SLtype)-1)
535 #define I SLANG_INT_TYPE
536 #define B SLANG_BSTRING_TYPE
537 static SLang_Intrin_Fun_Type Module_Intrinsics [] =
538 {
539 MAKE_INTRINSIC_0("zlib_version", zlib_version_intrin, SLANG_STRING_TYPE),
540 MAKE_INTRINSIC_5("_zlib_deflate_new", deflate_new_intrin, SLANG_VOID_TYPE, I, I, I, I, I),
541 MAKE_INTRINSIC_3("_zlib_deflate", deflate_intrin, SLANG_VOID_TYPE, DUMMY_ZLIB_TYPE, B, I),
542 MAKE_INTRINSIC_2("_zlib_deflate_flush", deflate_flush_intrin, SLANG_VOID_TYPE, DUMMY_ZLIB_TYPE, I),
543 MAKE_INTRINSIC_1("_zlib_deflate_reset", deflate_reset_intrin, SLANG_VOID_TYPE, DUMMY_ZLIB_TYPE),
544
545 MAKE_INTRINSIC_1("_zlib_inflate_new", inflate_new_intrin, SLANG_VOID_TYPE, I),
546 MAKE_INTRINSIC_3("_zlib_inflate", inflate_intrin, SLANG_VOID_TYPE, DUMMY_ZLIB_TYPE, B, I),
547 MAKE_INTRINSIC_2("_zlib_inflate_flush", inflate_flush_intrin, SLANG_VOID_TYPE, DUMMY_ZLIB_TYPE, I),
548 MAKE_INTRINSIC_1("_zlib_inflate_reset", inflate_reset_intrin, SLANG_VOID_TYPE, DUMMY_ZLIB_TYPE),
549 SLANG_END_INTRIN_FUN_TABLE
550 };
551 #undef I
552
553 static SLang_Intrin_Var_Type Module_Variables [] =
554 {
555 MAKE_VARIABLE("_zlib_module_version_string", &Module_Version_String, SLANG_STRING_TYPE, 1),
556 SLANG_END_INTRIN_VAR_TABLE
557 };
558
559 static SLang_IConstant_Type Module_IConstants [] =
560 {
561 MAKE_ICONSTANT("_zlib_module_version", MODULE_VERSION_NUMBER),
562
563 MAKE_ICONSTANT("ZLIB_NO_COMPRESSION", Z_NO_COMPRESSION),
564 MAKE_ICONSTANT("ZLIB_BEST_SPEED", Z_BEST_SPEED),
565 MAKE_ICONSTANT("ZLIB_BEST_COMPRESSION", Z_BEST_COMPRESSION),
566 MAKE_ICONSTANT("ZLIB_DEFAULT_COMPRESSION", Z_DEFAULT_COMPRESSION),
567
568 MAKE_ICONSTANT("ZLIB_NO_FLUSH", Z_NO_FLUSH),
569 MAKE_ICONSTANT("ZLIB_SYNC_FLUSH", Z_SYNC_FLUSH),
570 MAKE_ICONSTANT("ZLIB_FULL_FLUSH", Z_FULL_FLUSH),
571 MAKE_ICONSTANT("ZLIB_FINISH", Z_FINISH),
572
573 MAKE_ICONSTANT("ZLIB_FILTERED", Z_FILTERED),
574 MAKE_ICONSTANT("ZLIB_HUFFMAN_ONLY", Z_HUFFMAN_ONLY),
575 #ifdef Z_RLE
576 MAKE_ICONSTANT("ZLIB_RLE", Z_RLE),
577 #endif
578 #ifdef Z_FIXED
579 MAKE_ICONSTANT("ZLIB_FIXED", Z_FIXED),
580 #endif
581 MAKE_ICONSTANT("ZLIB_DEFAULT_STRATEGY", Z_DEFAULT_STRATEGY),
582
583 MAKE_ICONSTANT("ZLIB_DEFLATED", Z_DEFLATED),
584 SLANG_END_ICONST_TABLE
585 };
586
register_classes(void)587 static int register_classes (void)
588 {
589 SLang_Class_Type *cl;
590
591 if (ZLib_Type_Id != -1)
592 return 0;
593
594 if (NULL == (cl = SLclass_allocate_class ("ZLib_Type")))
595 return -1;
596
597 (void) SLclass_set_destroy_function (cl, destroy_zlib_type);
598
599 if (-1 == SLclass_register_class (cl, SLANG_VOID_TYPE,
600 sizeof (ZLib_Type),
601 SLANG_CLASS_TYPE_MMT))
602 return -1;
603
604 ZLib_Type_Id = SLclass_get_class_id (cl);
605 if (-1 == SLclass_patch_intrin_fun_table1 (Module_Intrinsics, DUMMY_ZLIB_TYPE, ZLib_Type_Id))
606 return -1;
607
608 return 0;
609 }
610
init_zlib_module_ns(char * ns_name)611 int init_zlib_module_ns (char *ns_name)
612 {
613 SLang_NameSpace_Type *ns = SLns_create_namespace (ns_name);
614 if (ns == NULL)
615 return -1;
616
617 if (-1 == register_classes ())
618 return -1;
619
620 if ((-1 == ZLib_Error)
621 && (-1 == (ZLib_Error = SLerr_new_exception (SL_RunTime_Error, "ZLibError", "ZLib Error"))))
622 return -1;
623
624 if (
625 (-1 == SLns_add_intrin_var_table (ns, Module_Variables, NULL))
626 || (-1 == SLns_add_intrin_fun_table (ns, Module_Intrinsics, NULL))
627 || (-1 == SLns_add_iconstant_table (ns, Module_IConstants, NULL))
628 )
629 return -1;
630
631 return 0;
632 }
633
634 /* This function is optional */
deinit_zlib_module(void)635 void deinit_zlib_module (void)
636 {
637 }
638