|
|
|
|
|
|
|
#include "global.h" |
#include "zlib_machine.h" |
#include "module.h" |
#include "program.h" |
#include "module_support.h" |
|
#if !defined(HAVE_LIBZ) && !defined(HAVE_LIBGZ) |
#undef HAVE_ZLIB_H |
#endif |
|
#ifdef HAVE_ZLIB_H |
|
#include "interpret.h" |
#include "svalue.h" |
#include "stralloc.h" |
#include "array.h" |
#include "pike_macros.h" |
#include "stralloc.h" |
#include "object.h" |
#include "pike_types.h" |
#include "threads.h" |
#include "dynamic_buffer.h" |
#include "operators.h" |
|
#include <zlib.h> |
|
|
#define sp Pike_sp |
|
struct zipper |
{ |
int level; |
int state; |
struct z_stream_s gz; |
struct pike_string *epilogue; |
#ifdef _REENTRANT |
DEFINE_MUTEX(lock); |
#endif /* _REENTRANT */ |
}; |
|
#define BUF 32768 |
#define MAX_BUF (64*BUF) |
|
#undef THIS |
#define THIS ((struct zipper *)(Pike_fp->current_storage)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void gz_deflate_create(INT32 args) |
{ |
int tmp, wbits = 15; |
int strategy = Z_DEFAULT_STRATEGY; |
THIS->level=Z_DEFAULT_COMPRESSION; |
|
if(THIS->gz.state) |
{ |
|
deflateEnd(&THIS->gz); |
|
} |
|
if(args) |
{ |
if(sp[-args].type != T_INT) |
Pike_error("Bad argument 1 to gz->create()\n"); |
THIS->level=sp[-args].u.integer; |
if( THIS->level < 0 ) |
{ |
wbits = -wbits; |
THIS->level = -THIS->level; |
} |
if(THIS->level < Z_NO_COMPRESSION || |
THIS->level > Z_BEST_COMPRESSION) |
{ |
Pike_error("Compression level out of range for gz_deflate->create()\n"); |
} |
} |
|
if(args>1) |
{ |
if(sp[1-args].type != T_INT) |
Pike_error("Bad argument 2 to gz->create()\n"); |
strategy=sp[1-args].u.integer; |
if(strategy != Z_DEFAULT_STRATEGY && |
strategy != Z_FILTERED && |
#ifdef Z_RLE |
strategy != Z_RLE && |
#endif |
#ifdef Z_FIXED |
strategy != Z_FIXED && |
#endif |
strategy != Z_HUFFMAN_ONLY) |
{ |
Pike_error("Invalid compression strategy for gz_deflate->create()\n"); |
} |
} |
|
THIS->gz.zalloc=Z_NULL; |
THIS->gz.zfree=Z_NULL; |
THIS->gz.opaque=(void *)THIS; |
|
pop_n_elems(args); |
|
tmp=deflateInit2(&THIS->gz, THIS->level, Z_DEFLATED, wbits, 9, strategy ); |
|
switch(tmp) |
{ |
case Z_OK: |
return; |
|
case Z_VERSION_ERROR: |
Pike_error("libz not compatible with zlib.h!!!\n"); |
break; |
|
default: |
if(THIS->gz.msg) |
Pike_error("Failed to initialize gz_deflate: %s\n",THIS->gz.msg); |
else |
Pike_error("Failed to initialize gz_deflate\n"); |
} |
} |
|
|
static int do_deflate(dynamic_buffer *buf, |
struct zipper *this, |
int flush) |
{ |
int ret=0; |
|
THREADS_ALLOW(); |
mt_lock(& this->lock); |
THREADS_DISALLOW(); |
if(!this->gz.state) |
ret=Z_STREAM_ERROR; |
else |
do |
{ |
this->gz.next_out=(Bytef *)low_make_buf_space( |
|
(this->gz.avail_out = |
this->gz.avail_in ? |
this->gz.avail_in+this->gz.avail_in/1000+42 : |
4096), |
buf); |
|
THREADS_ALLOW(); |
ret=deflate(& this->gz, flush); |
THREADS_DISALLOW(); |
|
|
low_make_buf_space(-((ptrdiff_t)this->gz.avail_out), buf); |
|
if(ret == Z_BUF_ERROR) ret=Z_OK; |
} |
while (ret==Z_OK && (this->gz.avail_in || !this->gz.avail_out)); |
|
mt_unlock(& this->lock); |
return ret; |
} |
|
static void free_pack(struct zipper *z) |
{ |
deflateEnd(&z->gz); |
mt_destroy(&z->lock); |
toss_buffer((dynamic_buffer *)z->gz.opaque); |
} |
|
void pack(struct pike_string *data, dynamic_buffer *buf, |
int level, int strategy, int wbits) |
{ |
struct zipper z; |
ONERROR err; |
int ret; |
|
if(level < Z_NO_COMPRESSION || |
level > Z_BEST_COMPRESSION) |
Pike_error("Compression level out of range for pack. %d %d %d\n", |
Z_DEFAULT_COMPRESSION, Z_NO_COMPRESSION, Z_BEST_COMPRESSION); |
|
if(strategy != Z_DEFAULT_STRATEGY && |
strategy != Z_FILTERED && |
#ifdef Z_RLE |
strategy != Z_RLE && |
#endif |
#ifdef Z_FIXED |
strategy != Z_FIXED && |
#endif |
strategy != Z_HUFFMAN_ONLY) |
Pike_error("Invalid compression strategy %d for pack.\n", strategy); |
|
if( wbits!=15 && wbits!=-15 ) |
Pike_error("Invalid wbits value %d for pack.\n", wbits); |
|
MEMSET(&z, 0, sizeof(z)); |
z.gz.zalloc = Z_NULL; |
z.gz.zfree = Z_NULL; |
ret = deflateInit2(&z.gz, level, Z_DEFLATED, wbits, 9, strategy); |
|
switch(ret) |
{ |
case Z_OK: |
break; |
|
case Z_VERSION_ERROR: |
Pike_error("libz not compatible with zlib.h!!!\n"); |
break; |
|
default: |
if(THIS->gz.msg) |
Pike_error("Failed to initialize gz: %s\n",THIS->gz.msg); |
else |
Pike_error("Failed to initialize gz\n"); |
} |
|
z.gz.next_in = (Bytef *)data->str; |
z.gz.avail_in = (unsigned INT32)(data->len); |
|
initialize_buf(buf); |
z.gz.opaque = buf; |
mt_init(&z.lock); |
|
SET_ONERROR(err,free_pack,&z); |
ret = do_deflate(buf, &z, Z_FINISH); |
UNSET_ONERROR(err); |
|
deflateEnd(&z.gz); |
mt_destroy(&z.lock); |
} |
|
|
|
|
static void gz_pack(INT32 args) |
{ |
struct pike_string *data; |
dynamic_buffer buf; |
|
int wbits = 15; |
int raw = 0; |
int level = 8; |
int strategy = Z_DEFAULT_STRATEGY; |
|
get_all_args("pack", args, "%n.%d%d%d", &data, &raw, &level, &strategy); |
|
if( raw ) |
wbits = -wbits; |
|
pack(data, &buf, level, strategy, wbits); |
|
pop_n_elems(args); |
push_string(low_free_buf(&buf)); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void gz_deflate(INT32 args) |
{ |
struct pike_string *data; |
int flush, fail; |
struct zipper *this=THIS; |
dynamic_buffer buf; |
ONERROR err; |
|
if(THIS->state == 1) |
{ |
deflateEnd(& THIS->gz); |
deflateInit(& THIS->gz, THIS->level); |
THIS->state=0; |
} |
|
if(!THIS->gz.state) |
Pike_error("gz_deflate not initialized or destructed\n"); |
|
if(args<1) |
Pike_error("Too few arguments to gz_deflate->deflate()\n"); |
|
if(sp[-args].type != T_STRING) |
Pike_error("Bad argument 1 to gz_deflate->deflate()\n"); |
|
data=sp[-args].u.string; |
|
if(args>1) |
{ |
if(sp[1-args].type != T_INT) |
Pike_error("Bad argument 2 to gz_deflate->deflate()\n"); |
|
flush=sp[1-args].u.integer; |
|
switch(flush) |
{ |
case Z_PARTIAL_FLUSH: |
case Z_FINISH: |
case Z_SYNC_FLUSH: |
case Z_NO_FLUSH: |
break; |
|
default: |
Pike_error("Argument 2 to gz_deflate->deflate() out of range.\n"); |
} |
}else{ |
flush=Z_FINISH; |
} |
|
this->gz.next_in=(Bytef *)data->str; |
this->gz.avail_in = DO_NOT_WARN((unsigned INT32)(data->len)); |
|
initialize_buf(&buf); |
|
SET_ONERROR(err,toss_buffer,&buf); |
fail=do_deflate(&buf,this,flush); |
UNSET_ONERROR(err); |
|
if(fail != Z_OK && fail != Z_STREAM_END) |
{ |
toss_buffer(&buf); |
if(THIS->gz.msg) |
Pike_error("Error in gz_deflate->deflate(): %s\n",THIS->gz.msg); |
else |
Pike_error("Error in gz_deflate->deflate(): %d\n",fail); |
} |
|
if(fail == Z_STREAM_END) |
THIS->state=1; |
|
pop_n_elems(args); |
|
push_string(low_free_buf(&buf)); |
} |
|
|
static void init_gz_deflate(struct object *o) |
{ |
mt_init(& THIS->lock); |
MEMSET(& THIS->gz, 0, sizeof(THIS->gz)); |
THIS->gz.zalloc=Z_NULL; |
THIS->gz.zfree=Z_NULL; |
THIS->gz.opaque=(void *)THIS; |
THIS->state=0; |
deflateInit(& THIS->gz, THIS->level = Z_DEFAULT_COMPRESSION); |
THIS->epilogue = NULL; |
} |
|
static void exit_gz_deflate(struct object *o) |
{ |
|
deflateEnd(&THIS->gz); |
do_free_string(THIS->epilogue); |
|
mt_destroy( & THIS->lock ); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void gz_inflate_create(INT32 args) |
{ |
int tmp; |
if(THIS->gz.state) |
{ |
|
inflateEnd(&THIS->gz); |
|
} |
|
|
THIS->gz.zalloc=Z_NULL; |
THIS->gz.zfree=Z_NULL; |
THIS->gz.opaque=(void *)THIS; |
if( args && Pike_sp[-1].type == PIKE_T_INT ) |
{ |
tmp=inflateInit2(& THIS->gz, Pike_sp[-1].u.integer); |
} |
else |
{ |
tmp=inflateInit( &THIS->gz ); |
} |
pop_n_elems(args); |
|
|
|
switch(tmp) |
{ |
case Z_OK: |
return; |
|
case Z_VERSION_ERROR: |
Pike_error("libz not compatible with zlib.h!!!\n"); |
break; |
|
default: |
if(THIS->gz.msg) |
Pike_error("Failed to initialize gz_inflate: %s\n",THIS->gz.msg); |
else |
Pike_error("Failed to initialize gz_inflate\n"); |
} |
} |
|
static int do_inflate(dynamic_buffer *buf, |
struct zipper *this, |
int flush) |
{ |
int fail=0; |
THREADS_ALLOW(); |
mt_lock(& this->lock); |
THREADS_DISALLOW(); |
if(!this->gz.state) |
{ |
fail=Z_STREAM_ERROR; |
}else{ |
#if 0 |
static int fnord=0; |
fnord++; |
#endif |
|
do |
{ |
char *loc; |
int ret; |
loc=low_make_buf_space(BUF,buf); |
THREADS_ALLOW(); |
this->gz.next_out=(Bytef *)loc; |
this->gz.avail_out=BUF; |
#if 0 |
fprintf(stderr,"INFLATE[%d]: avail_out=%7d avail_in=%7d flush=%d\n", |
fnord, |
this->gz.avail_out, |
this->gz.avail_in, |
flush); |
fprintf(stderr,"INFLATE[%d]: mode=%d\n",fnord, |
this->gz.state ? *(int *)(this->gz.state) : -1); |
#endif |
|
ret=inflate(& this->gz, flush); |
#if 0 |
fprintf(stderr,"Result [%d]: avail_out=%7d avail_in=%7d ret=%d\n", |
fnord, |
this->gz.avail_out, |
this->gz.avail_in, |
ret); |
#endif |
|
THREADS_DISALLOW(); |
low_make_buf_space(-((ptrdiff_t)this->gz.avail_out), buf); |
|
if(ret == Z_BUF_ERROR) ret=Z_OK; |
|
if(ret != Z_OK) |
{ |
fail=ret; |
break; |
} |
} while(!this->gz.avail_out || flush==Z_FINISH || this->gz.avail_in); |
} |
mt_unlock(& this->lock); |
return fail; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void gz_inflate(INT32 args) |
{ |
struct pike_string *data; |
int fail; |
struct zipper *this=THIS; |
dynamic_buffer buf; |
ONERROR err; |
|
if(!THIS->gz.state) |
Pike_error("gz_inflate not initialized or destructed\n"); |
|
if(args<1) |
Pike_error("Too few arguments to gz_inflate->inflate()\n"); |
|
if(sp[-args].type != T_STRING) |
Pike_error("Bad argument 1 to gz_inflate->inflate()\n"); |
|
data=sp[-args].u.string; |
|
this->gz.next_in=(Bytef *)data->str; |
this->gz.avail_in = DO_NOT_WARN((unsigned INT32)(data->len)); |
|
initialize_buf(&buf); |
|
SET_ONERROR(err,toss_buffer,&buf); |
fail=do_inflate(&buf,this,Z_SYNC_FLUSH); |
UNSET_ONERROR(err); |
|
if(fail != Z_OK && fail != Z_STREAM_END) |
{ |
toss_buffer(&buf); |
if(THIS->gz.msg) |
Pike_error("Error in gz_inflate->inflate(): %s\n",THIS->gz.msg); |
else |
Pike_error("Error in gz_inflate->inflate(): %d\n",fail); |
} |
|
pop_n_elems(args); |
|
push_string(low_free_buf(&buf)); |
|
if(fail == Z_STREAM_END) |
{ |
struct pike_string *old_epilogue = this->epilogue; |
if(old_epilogue) { |
push_string(old_epilogue); |
this->epilogue = NULL; |
} |
push_string(make_shared_binary_string((const char *)this->gz.next_in, |
this->gz.avail_in)); |
if(old_epilogue) |
f_add(2); |
if(sp[-1].type == PIKE_T_STRING) |
this->epilogue = (--sp)->u.string; |
else |
pop_stack(); |
} |
|
if(fail != Z_STREAM_END && fail!=Z_OK && !sp[-1].u.string->len) |
{ |
pop_stack(); |
push_int(0); |
} |
} |
|
|
|
|
|
|
|
|
|
static void gz_end_of_stream(INT32 args) |
{ |
struct zipper *this=THIS; |
pop_n_elems(args); |
if(this->epilogue) |
ref_push_string(this->epilogue); |
else |
push_int(0); |
} |
|
static void init_gz_inflate(struct object *o) |
{ |
mt_init(& THIS->lock); |
MEMSET(& THIS->gz, 0, sizeof(THIS->gz)); |
THIS->gz.zalloc=Z_NULL; |
THIS->gz.zfree=Z_NULL; |
THIS->gz.opaque=(void *)THIS; |
inflateInit(&THIS->gz); |
inflateEnd(&THIS->gz); |
THIS->epilogue = NULL; |
} |
|
static void exit_gz_inflate(struct object *o) |
{ |
|
inflateEnd(& THIS->gz); |
do_free_string(THIS->epilogue); |
|
mt_destroy( & THIS->lock ); |
} |
|
|
|
|
|
|
|
|
static void gz_crc32(INT32 args) |
{ |
unsigned INT32 crc; |
if (!args || |
sp[-args].type!=T_STRING) |
Pike_error("Gz.crc32: illegal or missing argument 1 (expected string)\n"); |
|
if (args>1) { |
if (sp[1-args].type!=T_INT) |
Pike_error("Gz.crc32: illegal argument 2 (expected integer)\n"); |
else |
crc=(unsigned INT32)sp[1-args].u.integer; |
} else |
crc=0; |
|
crc=crc32(crc, |
(unsigned char*)sp[-args].u.string->str, |
DO_NOT_WARN((unsigned INT32)(sp[-args].u.string->len))); |
|
pop_n_elems(args); |
push_int((INT32)crc); |
} |
|
|
|
#endif |
|
PIKE_MODULE_EXIT {} |
|
PIKE_MODULE_INIT |
{ |
#ifdef HAVE_ZLIB_H |
start_new_program(); |
ADD_STORAGE(struct zipper); |
|
|
ADD_FUNCTION("create",gz_deflate_create,tFunc(tOr(tInt,tVoid) tOr(tInt,tVoid),tVoid),0); |
|
ADD_FUNCTION("deflate",gz_deflate,tFunc(tStr tOr(tInt,tVoid),tStr),0); |
|
add_integer_constant("NO_FLUSH",Z_NO_FLUSH,0); |
add_integer_constant("PARTIAL_FLUSH",Z_PARTIAL_FLUSH,0); |
add_integer_constant("SYNC_FLUSH",Z_SYNC_FLUSH,0); |
add_integer_constant("FINISH",Z_FINISH,0); |
add_integer_constant("DEFAULT_STRATEGY", Z_DEFAULT_STRATEGY,0); |
add_integer_constant("FILTERED", Z_FILTERED,0); |
add_integer_constant("HUFFMAN_ONLY", Z_HUFFMAN_ONLY,0); |
#ifdef Z_RLE |
add_integer_constant("RLE", Z_RLE,0); |
#endif |
#ifdef Z_FIXED |
add_integer_constant("FIXED", Z_FIXED,0); |
#endif |
|
set_init_callback(init_gz_deflate); |
set_exit_callback(exit_gz_deflate); |
|
end_class("deflate",0); |
|
start_new_program(); |
ADD_STORAGE(struct zipper); |
|
|
ADD_FUNCTION("create",gz_inflate_create,tFunc(tOr(tInt,tVoid),tVoid),0); |
|
ADD_FUNCTION("inflate",gz_inflate,tFunc(tStr,tStr),0); |
|
ADD_FUNCTION("end_of_stream",gz_end_of_stream,tFunc(tNone,tStr),0); |
|
add_integer_constant("NO_FLUSH",Z_NO_FLUSH,0); |
add_integer_constant("PARTIAL_FLUSH",Z_PARTIAL_FLUSH,0); |
add_integer_constant("SYNC_FLUSH",Z_SYNC_FLUSH,0); |
add_integer_constant("FINISH",Z_FINISH,0); |
|
set_init_callback(init_gz_inflate); |
set_exit_callback(exit_gz_inflate); |
|
end_class("inflate",0); |
|
add_integer_constant("NO_FLUSH",Z_NO_FLUSH,0); |
add_integer_constant("PARTIAL_FLUSH",Z_PARTIAL_FLUSH,0); |
add_integer_constant("SYNC_FLUSH",Z_SYNC_FLUSH,0); |
add_integer_constant("FINISH",Z_FINISH,0); |
add_integer_constant("DEFAULT_STRATEGY", Z_DEFAULT_STRATEGY,0); |
add_integer_constant("FILTERED", Z_FILTERED,0); |
add_integer_constant("HUFFMAN_ONLY", Z_HUFFMAN_ONLY,0); |
#ifdef Z_RLE |
add_integer_constant("RLE", Z_RLE,0); |
#endif |
#ifdef Z_FIXED |
add_integer_constant("FIXED", Z_FIXED,0); |
#endif |
|
|
ADD_FUNCTION("crc32",gz_crc32,tFunc(tStr tOr(tVoid,tInt),tInt),0); |
|
|
ADD_FUNCTION("pack",gz_pack,tFunc(tStr tOr(tVoid,tInt01) tOr(tVoid,tInt) tOr(tVoid,tInt),tStr),0); |
|
PIKE_MODULE_EXPORT(Gz, crc32); |
PIKE_MODULE_EXPORT(Gz, pack); |
#else |
if(!TEST_COMPAT(7,6)) |
HIDE_MODULE(); |
#endif |
} |
|
#if defined(HAVE___VTBL__9TYPE_INFO) || defined(HAVE___T_9__NOTHROW) |
|
#ifdef HAVE___VTBL__9TYPE_INFO |
extern void __vtbl__9type_info(void); |
#endif /* HAVE___VTBL__9TYPE_INFO */ |
#ifdef HAVE___T_9__NOTHROW |
extern void __T_9__nothrow(void); |
#endif /* HAVE___T_9__NOTHROW */ |
|
* Not static, so the compiler can't optimize it away totally. |
*/ |
void zlibmod_strap_kluge(void) |
{ |
#ifdef HAVE___VTBL__9TYPE_INFO |
__vtbl__9type_info(); |
#endif /* HAVE___VTBL__9TYPE_INFO */ |
#ifdef HAVE___T_9__NOTHROW |
__T_9__nothrow(); |
#endif /* HAVE___T_9__NOTHROW */ |
} |
#endif /* HAVE___VTBL__9TYPE_INFO || HAVE___T_9__NOTHROW */ |
|
|