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