2 * Author : Paul Marquess, <pmqs@cpan.org>
3 * Created : 30 January 2005
6 * Copyright (c) 1995-2005 Paul Marquess. All rights reserved.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the same terms as Perl itself.
12 /* Part of this code is based on the file gzio.c */
14 /* gzio.c -- IO on .gz files
15 * Copyright (C) 1995 Jean-loup Gailly.
16 * For conditions of distribution and use, see copyright notice in zlib.h
28 #include "patchlevel.h"
29 #define PERL_REVISION 5
30 #define PERL_VERSION PATCHLEVEL
31 #define PERL_SUBVERSION SUBVERSION
34 #if PERL_REVISION == 5 && (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION <= 75 ))
36 # define PL_sv_undef sv_undef
38 # define PL_curcop curcop
39 # define PL_compiling compiling
44 # define newSVuv newSViv
47 typedef struct di_stream {
53 bool deflateParams_out_valid ;
54 Bytef deflateParams_out_byte;
62 typedef di_stream * deflateStream ;
63 typedef di_stream * Compress__Zlib__deflateStream ;
64 typedef di_stream * inflateStream ;
65 typedef di_stream * Compress__Zlib__inflateStream ;
67 /* typedef gzFile Compress__Zlib__gzFile ; */
68 typedef struct gzType {
75 typedef gzType* Compress__Zlib__gzFile ;
79 #define GZERRNO "Compress::Zlib::gzerrno"
81 #define ZMALLOC(to, typ) ((to = (typ *)safemalloc(sizeof(typ))), \
84 #define adlerInitial adler32(0L, Z_NULL, 0)
85 #define crcInitial crc32(0L, Z_NULL, 0)
88 static char *my_z_errmsg[] = {
89 "need dictionary", /* Z_NEED_DICT 2 */
90 "stream end", /* Z_STREAM_END 1 */
92 "file error", /* Z_ERRNO (-1) */
93 "stream error", /* Z_STREAM_ERROR (-2) */
94 "data error", /* Z_DATA_ERROR (-3) */
95 "insufficient memory", /* Z_MEM_ERROR (-4) */
96 "buffer error", /* Z_BUF_ERROR (-5) */
97 "incompatible version",/* Z_VERSION_ERROR(-6) */
102 static int trace = 0 ;
106 SetGzErrorNo(int error_no)
108 SetGzErrorNo(error_no)
113 SV * gzerror_sv = perl_get_sv(GZERRNO, FALSE) ;
115 if (error_no == Z_ERRNO) {
117 errstr = Strerror(errno) ;
120 /* errstr = gzerror(fil, &error_no) ; */
121 errstr = (char*) my_z_errmsg[2 - error_no];
123 if (SvIV(gzerror_sv) != error_no) {
124 sv_setiv(gzerror_sv, error_no) ;
125 sv_setpv(gzerror_sv, errstr) ;
126 SvIOK_on(gzerror_sv) ;
133 SetGzError(gzFile file)
141 (void)gzerror(file, &error_no) ;
142 SetGzErrorNo(error_no) ;
147 DispHex(void * ptr, int length)
154 char * p = (char*)ptr;
156 for (i = 0; i < length; ++i) {
157 printf(" %02x", 0xFF & *(p+i));
164 DispStream(di_stream * s, char * message)
166 DispStream(s, message)
177 printf("DispStream 0x%p - %s \n", s, message) ;
180 printf(" stream pointer is NULL\n");
183 printf(" stream 0x%p\n", &(s->stream));
184 printf(" zalloc 0x%p\n", s->stream.zalloc);
185 printf(" zfree 0x%p\n", s->stream.zfree);
186 printf(" opaque 0x%p\n", s->stream.opaque);
188 printf(" msg %s\n", s->stream.msg);
191 printf(" next_in 0x%p", s->stream.next_in);
192 if (s->stream.next_in) {
194 DispHex(s->stream.next_in, 4);
198 printf(" next_out 0x%p", s->stream.next_out);
199 if (s->stream.next_out){
201 DispHex(s->stream.next_out, 4);
205 printf(" avail_in %ld\n", s->stream.avail_in);
206 printf(" avail_out %ld\n", s->stream.avail_out);
207 printf(" total_in %ld\n", s->stream.total_in);
208 printf(" total_out %ld\n", s->stream.total_out);
209 printf(" adler 0x%lx\n", s->stream.adler);
210 printf(" reserved 0x%lx\n", s->stream.reserved);
211 printf(" bufsize %ld\n", s->bufsize);
212 printf(" dictionary 0x%p\n", s->dictionary);
213 printf(" dict_adler 0x%ld\n", s->dict_adler);
222 InitStream(uLong bufsize)
230 ZMALLOC(s, di_stream) ;
233 s->bufsize = bufsize ;
234 s->bufinc = bufsize ;
245 gzreadline(Compress__Zlib__gzFile file, SV * output)
247 gzreadline(file, output)
248 Compress__Zlib__gzFile file ;
253 SV * store = file->buffer ;
256 char *out_ptr = SvPVX(store) ;
261 /* anything left from last time */
262 if ((n = SvCUR(store))) {
264 out_ptr = SvPVX(store) + file->offset ;
265 if ((p = ninstr(out_ptr, out_ptr + n - 1, nl, nl))) {
266 /* if (rschar != 0777 && */
267 /* p = ninstr(out_ptr, out_ptr + n - 1, rs, rs+rslen-1)) { */
269 sv_catpvn(output, out_ptr, p - out_ptr + 1);
271 file->offset += (p - out_ptr + 1) ;
272 n = n - (p - out_ptr + 1);
273 SvCUR_set(store, n) ;
274 return SvCUR(output);
276 else /* no EOL, so append the complete buffer */
277 sv_catpvn(output, out_ptr, n);
282 SvCUR_set(store, 0) ;
284 out_ptr = SvPVX(store) ;
286 n = gzread(file->gz, out_ptr, SIZE) ;
289 /* Either EOF or an error */
290 /* so return what we have so far else signal eof */
291 return (SvCUR(output)>0) ? SvCUR(output) : n ;
293 SvCUR_set(store, n) ;
299 deRef(SV * sv, char * string)
312 croak("%s: buffer parameter is not a SCALAR reference", string);
315 croak("%s: buffer parameter is a reference to a reference", string) ;
324 #include "constants.h"
326 MODULE = Compress::Zlib PACKAGE = Compress::Zlib PREFIX = Zip_
331 INCLUDE: constants.xs
334 /* Check this version of zlib is == 1 */
335 if (zlibVersion()[0] != '1')
336 croak("Compress::Zlib needs zlib version 1.x\n") ;
339 /* Create the $gzerror scalar */
340 SV * gzerror_sv = perl_get_sv(GZERRNO, GV_ADDMULTI) ;
341 sv_setiv(gzerror_sv, 0) ;
342 sv_setpv(gzerror_sv, "") ;
343 SvIOK_on(gzerror_sv) ;
347 #define Zip_zlib_version() (char*)zlib_version
353 DispStream(s, message=NULL)
354 Compress::Zlib::inflateStream s
357 Compress::Zlib::gzFile
363 gz = gzopen(path, mode) ;
365 ZMALLOC(RETVAL, gzType) ;
366 RETVAL->buffer = newSV(SIZE) ;
367 SvPOK_only(RETVAL->buffer) ;
368 SvCUR_set(RETVAL->buffer, 0) ;
371 RETVAL->closed = FALSE ;
376 SetGzErrorNo(errno ? Z_ERRNO : Z_MEM_ERROR) ;
382 Compress::Zlib::gzFile
383 gzdopen_(fh, mode, offset)
390 lseek(fh, offset, 0) ;
391 gz = gzdopen(fh, mode) ;
393 ZMALLOC(RETVAL, gzType) ;
394 RETVAL->buffer = newSV(SIZE) ;
395 SvPOK_only(RETVAL->buffer) ;
396 SvCUR_set(RETVAL->buffer, 0) ;
399 RETVAL->closed = FALSE ;
404 SetGzErrorNo(errno ? Z_ERRNO : Z_MEM_ERROR) ;
410 MODULE = Compress::Zlib PACKAGE = Compress::Zlib::gzFile PREFIX = Zip_
412 #define Zip_gzread(file, buf, len) gzread(file->gz, bufp, len)
415 Zip_gzread(file, buf, len=4096)
416 Compress::Zlib::gzFile file
423 if (SvREADONLY(buf) && PL_curcop != &PL_compiling)
424 croak("gzread: buffer parameter is read-only");
425 if (!SvUPGRADE(buf, SVt_PV))
426 croak("cannot use buf argument as lvalue");
429 /* any left over from gzreadline ? */
430 if ((bufsize = SvCUR(file->buffer)) > 0) {
443 sv_catpvn(buf, SvPVX(file->buffer) + file->offset, movesize);
445 file->offset += movesize ;
446 SvCUR_set(file->buffer, bufsize - movesize) ;
450 bufp = (Byte*)SvGROW(buf, bufsize+len+1);
451 RETVAL = gzread(file->gz, ((Bytef*)bufp)+bufsize, len) ;
452 SetGzError(file->gz) ;
455 SvCUR_set(buf, RETVAL) ;
464 gzreadline(file, buf)
465 Compress::Zlib::gzFile file
469 if (SvREADONLY(buf) && PL_curcop != &PL_compiling)
470 croak("gzreadline: buffer parameter is read-only");
471 if (!SvUPGRADE(buf, SVt_PV))
472 croak("cannot use buf argument as lvalue");
474 /* sv_setpvn(buf, "", SIZE) ; */
477 RETVAL = gzreadline(file, buf) ;
478 SetGzError(file->gz) ;
484 /* SvCUR(buf) = RETVAL; */
485 /* Don't need to explicitly terminate with '\0', because
486 sv_catpvn aready has */
489 #define Zip_gzwrite(file, buf) gzwrite(file->gz, buf, (unsigned)len)
491 Zip_gzwrite(file, buf)
492 Compress::Zlib::gzFile file
494 voidp buf = (voidp)SvPV(ST(1), len) ;
496 SetGzError(file->gz) ;
498 #define Zip_gzflush(file, flush) gzflush(file->gz, flush)
500 Zip_gzflush(file, flush)
501 Compress::Zlib::gzFile file
504 SetGzError(file->gz) ;
506 #define Zip_gzclose(file) gzclose(file->gz)
509 Compress::Zlib::gzFile file
511 file->closed = TRUE ;
512 SetGzErrorNo(RETVAL) ;
515 #define Zip_gzeof(file) gzeof(file->gz)
518 Compress::Zlib::gzFile file
521 croak("gzeof needs zlib 1.0.6 or better") ;
523 RETVAL = gzeof(file->gz);
529 #define Zip_gzsetparams(file,l,s) gzsetparams(file->gz,l,s)
531 Zip_gzsetparams(file, level, strategy)
532 Compress::Zlib::gzFile file
537 croak("gzsetparams needs zlib 1.0.6 or better") ;
539 RETVAL = gzsetparams(file->gz, level, strategy);
546 Compress::Zlib::gzFile file
550 SvREFCNT_dec(file->buffer) ;
551 safefree((char*)file) ;
553 #define Zip_gzerror(file) (char*)gzerror(file->gz, &errnum)
557 Compress::Zlib::gzFile file
560 sv_setiv(ST(0), errnum) ;
565 MODULE = Compress::Zlib PACKAGE = Compress::Zlib PREFIX = Zip_
568 #define Zip_adler32(buf, adler) adler32(adler, buf, (uInt)len)
571 Zip_adler32(buf, adler=adlerInitial)
572 uLong adler = NO_INIT
574 Bytef * buf = NO_INIT
577 /* If the buffer is a reference, dereference it */
578 sv = deRef(sv, "adler32") ;
579 buf = (Byte*)SvPV(sv, len) ;
582 adler = adlerInitial;
583 else if (SvOK(ST(1)))
584 adler = SvUV(ST(1)) ;
586 adler = adlerInitial;
588 #define Zip_crc32(buf, crc) crc32(crc, buf, (uInt)len)
591 Zip_crc32(buf, crc=crcInitial)
594 Bytef * buf = NO_INIT
597 /* If the buffer is a reference, dereference it */
598 sv = deRef(sv, "crc32") ;
599 buf = (Byte*)SvPV(sv, len) ;
603 else if (SvOK(ST(1)))
608 MODULE = Compress::Zlib PACKAGE = Compress::Zlib
611 _deflateInit(level, method, windowBits, memLevel, strategy, bufsize, dictionary)
625 warn("in _deflateInit(level=%d, method=%d, windowBits=%d, memLevel=%d, strategy=%d, bufsize=%d\n",
626 level, method, windowBits, memLevel, strategy, bufsize) ;
627 if ((s = InitStream(bufsize)) ) {
631 s->WindowBits = windowBits;
632 s->MemLevel = memLevel;
633 s->Strategy = strategy;
635 err = deflateInit2(&(s->stream), level,
636 method, windowBits, memLevel, strategy);
638 /* Check if a dictionary has been specified */
639 if (err == Z_OK && SvCUR(dictionary)) {
640 err = deflateSetDictionary(&(s->stream), (const Bytef*) SvPVX(dictionary),
642 s->dict_adler = s->stream.adler ;
654 XPUSHs(sv_setref_pv(sv_newmortal(),
655 "Compress::Zlib::deflateStream", (void*)s));
656 if (GIMME == G_ARRAY)
657 XPUSHs(sv_2mortal(newSViv(err))) ;
660 _inflateInit(windowBits, bufsize, dictionary)
670 warn("in _inflateInit(windowBits=%d, bufsize=%d, dictionary=%d\n",
671 windowBits, bufsize, SvCUR(dictionary)) ;
672 if ((s = InitStream(bufsize)) ) {
674 s->WindowBits = windowBits;
676 err = inflateInit2(&(s->stream), windowBits);
682 else if (SvCUR(dictionary)) {
683 /* Dictionary specified - take a copy for use in inflate */
684 s->dictionary = newSVsv(dictionary) ;
690 XPUSHs(sv_setref_pv(sv_newmortal(),
691 "Compress::Zlib::inflateStream", (void*)s));
692 if (GIMME == G_ARRAY)
693 XPUSHs(sv_2mortal(newSViv(err))) ;
697 MODULE = Compress::Zlib PACKAGE = Compress::Zlib::deflateStream
700 DispStream(s, message=NULL)
701 Compress::Zlib::deflateStream s
706 Compress::Zlib::deflateStream s
708 uLong outsize = NO_INIT
709 SV * output = NO_INIT
713 /* If the buffer is a reference, dereference it */
714 buf = deRef(buf, "deflate") ;
716 /* initialise the input buffer */
717 s->stream.next_in = (Bytef*)SvPV(buf, *(STRLEN*)&s->stream.avail_in) ;
718 /* s->stream.next_in = (Bytef*)SvPVX(buf); */
719 s->stream.avail_in = SvCUR(buf) ;
721 /* and the output buffer */
722 /* output = sv_2mortal(newSVpv("", s->bufinc)) ; */
723 output = sv_2mortal(newSV(s->bufinc)) ;
725 SvCUR_set(output, 0) ;
726 outsize = s->bufinc ;
727 s->stream.next_out = (Bytef*) SvPVX(output) ;
728 s->stream.avail_out = outsize;
730 /* Check for saved output from deflateParams */
731 if (s->deflateParams_out_valid) {
732 *(s->stream.next_out) = s->deflateParams_out_byte;
733 ++ s->stream.next_out;
734 -- s->stream.avail_out ;
735 s->deflateParams_out_valid = FALSE;
738 while (s->stream.avail_in != 0) {
740 if (s->stream.avail_out == 0) {
742 SvGROW(output, outsize + s->bufinc) ;
743 s->stream.next_out = (Bytef*) SvPVX(output) + outsize ;
744 outsize += s->bufinc ;
745 s->stream.avail_out = s->bufinc ;
747 err = deflate(&(s->stream), Z_NO_FLUSH);
754 SvCUR_set(output, outsize - s->stream.avail_out) ;
757 output = &PL_sv_undef ;
759 if (GIMME == G_ARRAY)
760 XPUSHs(sv_2mortal(newSViv(err))) ;
766 Compress::Zlib::deflateStream s
768 uLong outsize = NO_INIT
769 SV * output = NO_INIT
773 s->stream.avail_in = 0; /* should be zero already anyway */
775 /* output = sv_2mortal(newSVpv("", s->bufinc)) ; */
776 output = sv_2mortal(newSV(s->bufinc)) ;
778 SvCUR_set(output, 0) ;
779 outsize = s->bufinc ;
780 s->stream.next_out = (Bytef*) SvPVX(output) ;
781 s->stream.avail_out = outsize;
783 /* Check for saved output from deflateParams */
784 if (s->deflateParams_out_valid) {
785 *(s->stream.next_out) = s->deflateParams_out_byte;
786 ++ s->stream.next_out;
787 -- s->stream.avail_out ;
788 s->deflateParams_out_valid = FALSE;
792 if (s->stream.avail_out == 0) {
793 /* consumed all the available output, so extend it */
795 SvGROW(output, outsize + s->bufinc) ;
796 s->stream.next_out = (Bytef*)SvPVX(output) + outsize ;
797 outsize += s->bufinc ;
798 s->stream.avail_out = s->bufinc ;
800 err = deflate(&(s->stream), f);
802 /* deflate has finished flushing only when it hasn't used up
803 * all the available space in the output buffer:
805 if (s->stream.avail_out != 0 || err != Z_OK )
809 err = (err == Z_STREAM_END ? Z_OK : err) ;
813 SvCUR_set(output, outsize - s->stream.avail_out) ;
816 output = &PL_sv_undef ;
818 if (GIMME == G_ARRAY)
819 XPUSHs(sv_2mortal(newSViv(err))) ;
822 _deflateParams(s, flags, level, strategy, bufsize)
823 Compress::Zlib::deflateStream s
832 s->Strategy = strategy ;
834 s->bufsize = bufsize;
837 s->stream.avail_in = 0;
838 s->stream.next_out = &(s->deflateParams_out_byte) ;
839 s->stream.avail_out = 1;
840 RETVAL = deflateParams(&(s->stream), s->Level, s->Strategy);
841 s->deflateParams_out_valid =
842 (RETVAL == Z_OK && s->stream.avail_out == 0) ;
849 Compress::Zlib::deflateStream s
857 Compress::Zlib::deflateStream s
859 RETVAL = s->Strategy ;
865 Compress::Zlib::deflateStream s
867 deflateEnd(&s->stream) ;
869 SvREFCNT_dec(s->dictionary) ;
875 Compress::Zlib::deflateStream s
877 RETVAL = s->dict_adler ;
883 Compress::Zlib::deflateStream s
885 RETVAL = s->stream.total_in ;
891 Compress::Zlib::deflateStream s
893 RETVAL = s->stream.total_out ;
899 Compress::Zlib::deflateStream s
901 RETVAL = s->stream.msg;
906 MODULE = Compress::Zlib PACKAGE = Compress::Zlib::inflateStream
909 DispStream(s, message=NULL)
910 Compress::Zlib::inflateStream s
915 Compress::Zlib::inflateStream s
917 uLong outsize = NO_INIT
918 SV * output = NO_INIT
924 /* If the buffer is a reference, dereference it */
925 buf = deRef(buf, "inflate") ;
927 /* initialise the input buffer */
928 s->stream.next_in = (Bytef*)SvPVX(buf) ;
929 s->stream.avail_in = SvCUR(buf) ;
931 /* and the output buffer */
932 output = sv_2mortal(newSV(s->bufinc+1)) ;
934 SvCUR_set(output, 0) ;
935 outsize = s->bufinc ;
936 s->stream.next_out = (Bytef*) SvPVX(output) ;
937 s->stream.avail_out = outsize;
941 if (s->stream.avail_out == 0) {
943 SvGROW(output, outsize + s->bufinc+1) ;
944 s->stream.next_out = (Bytef*) SvPVX(output) + outsize ;
945 outsize += s->bufinc ;
946 s->stream.avail_out = s->bufinc ;
949 err = inflate(&(s->stream), Z_SYNC_FLUSH);
950 if (err == Z_BUF_ERROR) {
951 if (s->stream.avail_out == 0)
953 if (s->stream.avail_in == 0) {
959 if (err == Z_NEED_DICT && s->dictionary) {
960 s->dict_adler = s->stream.adler ;
961 err = inflateSetDictionary(&(s->stream),
962 (const Bytef*)SvPVX(s->dictionary),
963 SvCUR(s->dictionary));
970 if (err == Z_OK || err == Z_STREAM_END || err == Z_DATA_ERROR) {
974 SvCUR_set(output, outsize - s->stream.avail_out) ;
975 *SvEND(output) = '\0';
977 /* fix the input buffer */
979 in = s->stream.avail_in ;
982 Move(s->stream.next_in, SvPVX(buf), in, char) ;
988 output = &PL_sv_undef ;
990 if (GIMME == G_ARRAY)
991 XPUSHs(sv_2mortal(newSViv(err))) ;
995 Compress::Zlib::inflateStream s
999 /* If the buffer is a reference, dereference it */
1000 buf = deRef(buf, "inflateSync") ;
1002 /* initialise the input buffer */
1003 s->stream.next_in = (Bytef*)SvPVX(buf) ;
1004 s->stream.avail_in = SvCUR(buf) ;
1006 /* inflateSync doesn't create any output */
1007 s->stream.next_out = (Bytef*) NULL;
1008 s->stream.avail_out = 0;
1010 RETVAL = inflateSync(&(s->stream));
1012 /* fix the input buffer */
1013 unsigned in = s->stream.avail_in ;
1015 SvCUR_set(buf, in) ;
1017 Move(s->stream.next_in, SvPVX(buf), in, char) ;
1026 Compress::Zlib::inflateStream s
1028 inflateEnd(&s->stream) ;
1030 SvREFCNT_dec(s->dictionary) ;
1036 Compress::Zlib::inflateStream s
1038 RETVAL = s->dict_adler ;
1044 Compress::Zlib::inflateStream s
1046 RETVAL = s->stream.total_in ;
1052 Compress::Zlib::inflateStream s
1054 RETVAL = s->stream.total_out ;
1060 Compress::Zlib::inflateStream s
1062 RETVAL = s->stream.msg;