/* -*- mode: C; mode: fold; -*- */ /* Copyright (C) 2008-2017,2018 John E. Davis This file is part of the S-Lang Library. The S-Lang Library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The S-Lang Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include #include #include #include #include SLANG_MODULE(zlib); static SLFUTURE_CONST char *Module_Version_String = "0.1.0"; #define MODULE_VERSION_NUMBER (0*10000 + 1*100 + 0) typedef struct { int type; #define DEFLATE_TYPE 1 #define INFLATE_TYPE 2 int initialized; z_stream zs; #define DEFAULT_START_BUFLEN 0x4000 SLstrlen_Type start_buflen; #define DEFAULT_BUFLEN_INC 0x4000 SLstrlen_Type dbuflen; int windowbits; } ZLib_Type; static int ZLib_Type_Id = -1; int ZLib_Error = -1; static int check_zerror (int e) { switch (e) { case Z_ERRNO: e = errno; (void) SLerrno_set_errno (e); SLang_verror (ZLib_Error, "Z library errno error: %s", SLerrno_strerror(e)); break; case Z_STREAM_ERROR: SLang_verror (ZLib_Error, "Z library stream error"); break; case Z_DATA_ERROR: SLang_verror (ZLib_Error, "Z library data error"); break; case Z_MEM_ERROR: SLang_verror (SL_Malloc_Error, "Z library memory allocation error"); break; case Z_BUF_ERROR: SLang_verror (ZLib_Error, "Z library buffer error"); break; case Z_VERSION_ERROR: SLang_verror (ZLib_Error, "Z library version mismatch error"); break; case Z_NEED_DICT: /* not handled by this module */ SLang_verror (ZLib_Error, "Z library dictionary error"); break; default: if (e >= 0) return 0; SLang_verror (ZLib_Error, "Unknown Error Code"); } return -1; } static int check_deflate_object (ZLib_Type *zp) { if (zp->type != DEFLATE_TYPE) { SLang_verror (SL_TypeMismatch_Error, "Expecting a Zlib_Type deflate object"); return -1; } return 0; } static int check_inflate_object (ZLib_Type *zp) { if (zp->type != INFLATE_TYPE) { SLang_verror (SL_TypeMismatch_Error, "Expecting a Zlib_Type inflate object"); return -1; } return 0; } static int init_deflate_object (ZLib_Type *z, int level, int method, int windowbits, int memlevel, int strategy) { z_stream *zs; int ret; memset ((char *) z, 0, sizeof(ZLib_Type)); z->type = DEFLATE_TYPE; z->start_buflen = DEFAULT_START_BUFLEN; z->dbuflen = DEFAULT_BUFLEN_INC; zs = &z->zs; zs->zalloc = Z_NULL; zs->zfree = Z_NULL; zs->opaque = Z_NULL; ret = deflateInit2 (zs, level, method, windowbits, memlevel, strategy); if (ret == Z_STREAM_ERROR) { SLang_verror (ZLib_Error, "One of more deflate parameters are invalid."); deflateEnd (zs); } if (-1 == check_zerror (ret)) { deflateEnd (zs); return -1; } z->initialized = 1; return 0; } static int run_deflate (ZLib_Type *z, int flush, unsigned char *str, SLstrlen_Type len, unsigned char **bufp, SLstrlen_Type *totalp) { z_stream *zs; unsigned char *buf; SLstrlen_Type buflen; zs = &z->zs; buflen = z->start_buflen; if (NULL == (buf = (unsigned char *) SLmalloc (buflen+1))) { *bufp = NULL; *totalp = 0; return -1; } zs->next_in = str; zs->avail_in = len; zs->next_out = buf; zs->avail_out = buflen; while (1) { SLstrlen_Type total; int ret; ret = deflate (zs, flush); if (ret != Z_BUF_ERROR) { if (-1 == check_zerror (ret)) goto return_error; } total = buflen - zs->avail_out; if (/* done -- flush == Z_FINISH */ (ret == Z_STREAM_END) /* Done with current input */ || ((zs->avail_in == 0) && (zs->avail_out != 0)) ) { if (total != buflen) { unsigned char *new_buf; new_buf = (unsigned char *) SLrealloc ((char *)buf, total+1); if (new_buf == NULL) goto return_error; buf = new_buf; } buf[total] = 0; /* ok, because of +1 in malloc calls */ *bufp = buf; *totalp = total; return 0; } if (zs->avail_out == 0) { unsigned char *new_buf; SLstrlen_Type dbuflen = z->dbuflen; buflen += dbuflen; new_buf = (unsigned char *)SLrealloc ((char *) buf, buflen+1); if (new_buf == NULL) goto return_error; buf = new_buf; zs->avail_out = dbuflen; zs->next_out = buf + total; } } return_error: SLfree ((char *) buf); *bufp = NULL; *totalp = 0; return -1; } static void deflate_intrin (ZLib_Type *zp, SLang_BString_Type *inbstr, int *flush) { SLang_BString_Type *outbstr; unsigned char *inbuf, *outbuf; SLstrlen_Type inlen, outlen; if (-1 == check_deflate_object (zp)) return; if (NULL == (inbuf = SLbstring_get_pointer (inbstr, &inlen))) return; if (zp->start_buflen < inlen) zp->start_buflen = inlen; if (-1 == run_deflate (zp, *flush, inbuf, inlen, &outbuf, &outlen)) return; if (NULL == (outbstr = SLbstring_create_malloced (outbuf, outlen, 1))) return; (void) SLang_push_bstring (outbstr); SLbstring_free (outbstr); } static void deflate_reset_intrin (ZLib_Type *z) { if (-1 == check_deflate_object (z)) return; check_zerror (deflateReset (&z->zs)); } static void deflate_flush_intrin (ZLib_Type *z, int *flush) { unsigned char *buf; SLstrlen_Type len; SLang_BString_Type *bstr; if (-1 == check_deflate_object (z)) return; if (-1 == run_deflate (z, *flush, (unsigned char *)"", 0, &buf, &len)) return; if (NULL == (bstr = SLbstring_create_malloced (buf, len, 1))) return; (void) SLang_push_bstring (bstr); SLbstring_free (bstr); } static void free_deflate_object (ZLib_Type *z) { if (z->initialized) deflateEnd (&z->zs); SLfree ((char *) z); } static void deflate_new_intrin (int *level, int *method, int *wbits, int *memlevel, int *strategy) { /* According to the docs, the parameters are checked by deflateInit2 */ ZLib_Type *z; SLang_MMT_Type *mmt; if (NULL == (z = (ZLib_Type *) SLmalloc (sizeof (ZLib_Type)))) return; if (-1 == init_deflate_object (z, *level, *method, *wbits, *memlevel, *strategy)) { SLfree ((char *) z); return; } if (NULL == (mmt = SLang_create_mmt (ZLib_Type_Id, (VOID_STAR) z))) { free_deflate_object (z); return; } if (0 == SLang_push_mmt (mmt)) return; SLang_free_mmt (mmt); } static int run_inflate (ZLib_Type *z, int flush, unsigned char *str, SLstrlen_Type len, unsigned char **bufp, SLstrlen_Type *totalp) { z_stream *zs; unsigned char *buf; SLstrlen_Type buflen; zs = &z->zs; zs->next_in = str; zs->avail_in = len; if (z->initialized == 0) { zs = &z->zs; zs->zalloc = Z_NULL; zs->zfree = Z_NULL; zs->opaque = Z_NULL; if (-1 == check_zerror (inflateInit2 (zs, z->windowbits))) { inflateEnd (zs); return -1; } z->initialized = 1; } buflen = z->start_buflen; if (NULL == (buf = (unsigned char *) SLmalloc (buflen+1))) { *bufp = NULL; *totalp = 0; return -1; } zs->next_out = buf; zs->avail_out = buflen; while (1) { SLstrlen_Type total; int ret; ret = inflate (zs, flush); if (ret != Z_BUF_ERROR) { if (-1 == check_zerror (ret)) goto return_error; } total = buflen - zs->avail_out; if (/* done -- flush == Z_FINISH */ (ret == Z_STREAM_END) /* Done with current input */ || ((zs->avail_in == 0) && (zs->avail_out != 0)) ) { if (total != buflen) { unsigned char *new_buf; new_buf = (unsigned char *) SLrealloc ((char *)buf, total+1); if (new_buf == NULL) goto return_error; buf = new_buf; } buf[total] = 0; /* ok, because of +1 in malloc calls */ *bufp = buf; *totalp = total; return 0; } if (zs->avail_out == 0) { unsigned char *new_buf; SLstrlen_Type dbuflen = z->dbuflen; buflen += dbuflen; new_buf = (unsigned char *)SLrealloc ((char *) buf, buflen+1); if (new_buf == NULL) goto return_error; buf = new_buf; zs->avail_out = dbuflen; zs->next_out = buf + total; } } return_error: SLfree ((char *) buf); *bufp = NULL; *totalp = 0; return -1; } static void inflate_intrin (ZLib_Type *zp, SLang_BString_Type *inbstr, int *flush) { SLang_BString_Type *outbstr; unsigned char *inbuf, *outbuf; SLstrlen_Type inlen, outlen; if (-1 == check_inflate_object (zp)) return; if (NULL == (inbuf = SLbstring_get_pointer (inbstr, &inlen))) return; if (zp->start_buflen < inlen) zp->start_buflen = inlen; if (-1 == run_inflate (zp, *flush, inbuf, inlen, &outbuf, &outlen)) return; if (NULL == (outbstr = SLbstring_create_malloced (outbuf, outlen, 1))) return; (void) SLang_push_bstring (outbstr); SLbstring_free (outbstr); } static int init_inflate_object (ZLib_Type *z, int windowbits) { memset ((char *) z, 0, sizeof(ZLib_Type)); z->type = INFLATE_TYPE; z->windowbits = windowbits; z->initialized = 0; z->start_buflen = DEFAULT_START_BUFLEN; z->dbuflen = DEFAULT_BUFLEN_INC; return 0; } static void inflate_new_intrin (int *windowbits) { ZLib_Type *z; SLang_MMT_Type *mmt; if (NULL == (z = (ZLib_Type *) SLmalloc (sizeof (ZLib_Type)))) return; if (-1 == init_inflate_object (z, *windowbits)) { SLfree ((char *) z); return; } if (NULL == (mmt = SLang_create_mmt (ZLib_Type_Id, (VOID_STAR) z))) { free_deflate_object (z); return; } if (0 == SLang_push_mmt (mmt)) return; SLang_free_mmt (mmt); } static void inflate_reset_intrin (ZLib_Type *z) { if (-1 == check_inflate_object (z)) return; if (z->initialized) check_zerror (deflateReset (&z->zs)); } static void inflate_flush_intrin (ZLib_Type *z, int *flush) { unsigned char *buf; SLstrlen_Type len; SLang_BString_Type *bstr; if (-1 == check_inflate_object (z)) return; if (-1 == run_inflate (z, *flush, (unsigned char *)"", 0, &buf, &len)) return; if (NULL == (bstr = SLbstring_create_malloced (buf, len, 1))) return; (void) SLang_push_bstring (bstr); SLbstring_free (bstr); } static void free_inflate_object (ZLib_Type *z) { if (z->initialized) inflateEnd (&z->zs); SLfree ((char *) z); } static void destroy_zlib_type (SLtype type, VOID_STAR f) { ZLib_Type *z; (void) type; z = (ZLib_Type *) f; if (z->type == DEFLATE_TYPE) free_deflate_object (z); else free_inflate_object (z); } static const char *zlib_version_intrin (void) { return zlibVersion (); } #define DUMMY_ZLIB_TYPE ((SLtype)-1) #define I SLANG_INT_TYPE #define B SLANG_BSTRING_TYPE static SLang_Intrin_Fun_Type Module_Intrinsics [] = { MAKE_INTRINSIC_0("zlib_version", zlib_version_intrin, SLANG_STRING_TYPE), MAKE_INTRINSIC_5("_zlib_deflate_new", deflate_new_intrin, SLANG_VOID_TYPE, I, I, I, I, I), MAKE_INTRINSIC_3("_zlib_deflate", deflate_intrin, SLANG_VOID_TYPE, DUMMY_ZLIB_TYPE, B, I), MAKE_INTRINSIC_2("_zlib_deflate_flush", deflate_flush_intrin, SLANG_VOID_TYPE, DUMMY_ZLIB_TYPE, I), MAKE_INTRINSIC_1("_zlib_deflate_reset", deflate_reset_intrin, SLANG_VOID_TYPE, DUMMY_ZLIB_TYPE), MAKE_INTRINSIC_1("_zlib_inflate_new", inflate_new_intrin, SLANG_VOID_TYPE, I), MAKE_INTRINSIC_3("_zlib_inflate", inflate_intrin, SLANG_VOID_TYPE, DUMMY_ZLIB_TYPE, B, I), MAKE_INTRINSIC_2("_zlib_inflate_flush", inflate_flush_intrin, SLANG_VOID_TYPE, DUMMY_ZLIB_TYPE, I), MAKE_INTRINSIC_1("_zlib_inflate_reset", inflate_reset_intrin, SLANG_VOID_TYPE, DUMMY_ZLIB_TYPE), SLANG_END_INTRIN_FUN_TABLE }; #undef I static SLang_Intrin_Var_Type Module_Variables [] = { MAKE_VARIABLE("_zlib_module_version_string", &Module_Version_String, SLANG_STRING_TYPE, 1), SLANG_END_INTRIN_VAR_TABLE }; static SLang_IConstant_Type Module_IConstants [] = { MAKE_ICONSTANT("_zlib_module_version", MODULE_VERSION_NUMBER), MAKE_ICONSTANT("ZLIB_NO_COMPRESSION", Z_NO_COMPRESSION), MAKE_ICONSTANT("ZLIB_BEST_SPEED", Z_BEST_SPEED), MAKE_ICONSTANT("ZLIB_BEST_COMPRESSION", Z_BEST_COMPRESSION), MAKE_ICONSTANT("ZLIB_DEFAULT_COMPRESSION", Z_DEFAULT_COMPRESSION), MAKE_ICONSTANT("ZLIB_NO_FLUSH", Z_NO_FLUSH), MAKE_ICONSTANT("ZLIB_SYNC_FLUSH", Z_SYNC_FLUSH), MAKE_ICONSTANT("ZLIB_FULL_FLUSH", Z_FULL_FLUSH), MAKE_ICONSTANT("ZLIB_FINISH", Z_FINISH), MAKE_ICONSTANT("ZLIB_FILTERED", Z_FILTERED), MAKE_ICONSTANT("ZLIB_HUFFMAN_ONLY", Z_HUFFMAN_ONLY), #ifdef Z_RLE MAKE_ICONSTANT("ZLIB_RLE", Z_RLE), #endif #ifdef Z_FIXED MAKE_ICONSTANT("ZLIB_FIXED", Z_FIXED), #endif MAKE_ICONSTANT("ZLIB_DEFAULT_STRATEGY", Z_DEFAULT_STRATEGY), MAKE_ICONSTANT("ZLIB_DEFLATED", Z_DEFLATED), SLANG_END_ICONST_TABLE }; static int register_classes (void) { SLang_Class_Type *cl; if (ZLib_Type_Id != -1) return 0; if (NULL == (cl = SLclass_allocate_class ("ZLib_Type"))) return -1; (void) SLclass_set_destroy_function (cl, destroy_zlib_type); if (-1 == SLclass_register_class (cl, SLANG_VOID_TYPE, sizeof (ZLib_Type), SLANG_CLASS_TYPE_MMT)) return -1; ZLib_Type_Id = SLclass_get_class_id (cl); if (-1 == SLclass_patch_intrin_fun_table1 (Module_Intrinsics, DUMMY_ZLIB_TYPE, ZLib_Type_Id)) return -1; return 0; } int init_zlib_module_ns (char *ns_name) { SLang_NameSpace_Type *ns = SLns_create_namespace (ns_name); if (ns == NULL) return -1; if (-1 == register_classes ()) return -1; if ((-1 == ZLib_Error) && (-1 == (ZLib_Error = SLerr_new_exception (SL_RunTime_Error, "ZLibError", "ZLib Error")))) return -1; if ( (-1 == SLns_add_intrin_var_table (ns, Module_Variables, NULL)) || (-1 == SLns_add_intrin_fun_table (ns, Module_Intrinsics, NULL)) || (-1 == SLns_add_iconstant_table (ns, Module_IConstants, NULL)) ) return -1; return 0; } /* This function is optional */ void deinit_zlib_module (void) { }