1
1
s-lang/modules/zlib-module.c

638 строки
14 KiB
C

/* -*- 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 <stdio.h>
#include <errno.h>
#include <slang.h>
#include <string.h>
#include <zlib.h>
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)
{
}