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 const char * const 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) */
101 #if defined(__SYMBIAN32__)
102 # define NO_WRITEABLE_DATA
105 #define TRACE_DEFAULT 0
107 #ifdef NO_WRITEABLE_DATA
108 #define trace TRACE_DEFAULT
110 static int trace = TRACE_DEFAULT ;
113 /* Dodge PerlIO hiding of these functions. */
118 SetGzErrorNo(int error_no)
120 SetGzErrorNo(error_no)
126 SV * gzerror_sv = perl_get_sv(GZERRNO, FALSE) ;
128 if (error_no == Z_ERRNO) {
130 errstr = Strerror(errno) ;
133 /* errstr = gzerror(fil, &error_no) ; */
134 errstr = (char*) my_z_errmsg[2 - error_no];
136 if (SvIV(gzerror_sv) != error_no) {
137 sv_setiv(gzerror_sv, error_no) ;
138 sv_setpv(gzerror_sv, errstr) ;
139 SvIOK_on(gzerror_sv) ;
146 SetGzError(gzFile file)
154 (void)gzerror(file, &error_no) ;
155 SetGzErrorNo(error_no) ;
160 DispHex(void * ptr, int length)
167 char * p = (char*)ptr;
169 for (i = 0; i < length; ++i) {
170 printf(" %02x", 0xFF & *(p+i));
177 DispStream(di_stream * s, char * message)
179 DispStream(s, message)
190 printf("DispStream 0x%p - %s \n", s, message) ;
193 printf(" stream pointer is NULL\n");
196 printf(" stream 0x%p\n", &(s->stream));
197 printf(" zalloc 0x%p\n", s->stream.zalloc);
198 printf(" zfree 0x%p\n", s->stream.zfree);
199 printf(" opaque 0x%p\n", s->stream.opaque);
201 printf(" msg %s\n", s->stream.msg);
204 printf(" next_in 0x%p", s->stream.next_in);
205 if (s->stream.next_in) {
207 DispHex(s->stream.next_in, 4);
211 printf(" next_out 0x%p", s->stream.next_out);
212 if (s->stream.next_out){
214 DispHex(s->stream.next_out, 4);
218 printf(" avail_in %ld\n", s->stream.avail_in);
219 printf(" avail_out %ld\n", s->stream.avail_out);
220 printf(" total_in %ld\n", s->stream.total_in);
221 printf(" total_out %ld\n", s->stream.total_out);
222 printf(" adler 0x%lx\n", s->stream.adler);
223 printf(" reserved 0x%lx\n", s->stream.reserved);
224 printf(" bufsize %ld\n", s->bufsize);
225 printf(" dictionary 0x%p\n", s->dictionary);
226 printf(" dict_adler 0x%ld\n", s->dict_adler);
235 InitStream(uLong bufsize)
243 ZMALLOC(s, di_stream) ;
246 s->bufsize = bufsize ;
247 s->bufinc = bufsize ;
258 gzreadline(Compress__Zlib__gzFile file, SV * output)
260 gzreadline(file, output)
261 Compress__Zlib__gzFile file ;
266 SV * store = file->buffer ;
269 char *out_ptr = SvPVX(store) ;
274 /* anything left from last time */
275 if ((n = SvCUR(store))) {
277 out_ptr = SvPVX(store) + file->offset ;
278 if ((p = ninstr(out_ptr, out_ptr + n - 1, nl, nl))) {
279 /* if (rschar != 0777 && */
280 /* p = ninstr(out_ptr, out_ptr + n - 1, rs, rs+rslen-1)) { */
282 sv_catpvn(output, out_ptr, p - out_ptr + 1);
284 file->offset += (p - out_ptr + 1) ;
285 n = n - (p - out_ptr + 1);
286 SvCUR_set(store, n) ;
287 return SvCUR(output);
289 else /* no EOL, so append the complete buffer */
290 sv_catpvn(output, out_ptr, n);
295 SvCUR_set(store, 0) ;
297 out_ptr = SvPVX(store) ;
299 n = gzread(file->gz, out_ptr, SIZE) ;
302 /* Either EOF or an error */
303 /* so return what we have so far else signal eof */
304 return (SvCUR(output)>0) ? SvCUR(output) : n ;
306 SvCUR_set(store, n) ;
312 deRef(SV * sv, char * string)
326 croak("%s: buffer parameter is not a SCALAR reference", string);
329 croak("%s: buffer parameter is a reference to a reference", string) ;
338 #include "constants.h"
340 MODULE = Compress::Zlib PACKAGE = Compress::Zlib PREFIX = Zip_
345 INCLUDE: constants.xs
348 /* Check this version of zlib is == 1 */
349 if (zlibVersion()[0] != '1')
350 croak("Compress::Zlib needs zlib version 1.x\n") ;
353 /* Create the $gzerror scalar */
354 SV * gzerror_sv = perl_get_sv(GZERRNO, GV_ADDMULTI) ;
355 sv_setiv(gzerror_sv, 0) ;
356 sv_setpv(gzerror_sv, "") ;
357 SvIOK_on(gzerror_sv) ;
361 #define Zip_zlib_version() (char*)zlib_version
369 RETVAL = ZLIB_VERNUM ;
371 /* 1.1.4 => 0x1140 */
372 RETVAL = (ZLIB_VERSION[0] - '0') << 12 ;
373 RETVAL += (ZLIB_VERSION[2] - '0') << 8 ;
374 RETVAL += (ZLIB_VERSION[4] - '0') << 4 ;
382 DispStream(s, message=NULL)
383 Compress::Zlib::inflateStream s
386 Compress::Zlib::gzFile
392 gz = gzopen(path, mode) ;
394 ZMALLOC(RETVAL, gzType) ;
395 RETVAL->buffer = newSV(SIZE) ;
396 SvPOK_only(RETVAL->buffer) ;
397 SvCUR_set(RETVAL->buffer, 0) ;
400 RETVAL->closed = FALSE ;
405 SetGzErrorNo(errno ? Z_ERRNO : Z_MEM_ERROR) ;
411 Compress::Zlib::gzFile
412 gzdopen_(fh, mode, offset)
419 lseek(fh, offset, 0) ;
420 gz = gzdopen(fh, mode) ;
422 ZMALLOC(RETVAL, gzType) ;
423 RETVAL->buffer = newSV(SIZE) ;
424 SvPOK_only(RETVAL->buffer) ;
425 SvCUR_set(RETVAL->buffer, 0) ;
428 RETVAL->closed = FALSE ;
433 SetGzErrorNo(errno ? Z_ERRNO : Z_MEM_ERROR) ;
439 MODULE = Compress::Zlib PACKAGE = Compress::Zlib::gzFile PREFIX = Zip_
441 #define Zip_gzread(file, buf, len) gzread(file->gz, bufp, len)
444 Zip_gzread(file, buf, len=4096)
445 Compress::Zlib::gzFile file
452 if (SvREADONLY(buf) && PL_curcop != &PL_compiling)
453 croak("gzread: buffer parameter is read-only");
454 SvUPGRADE(buf, SVt_PV);
457 /* any left over from gzreadline ? */
458 if ((bufsize = SvCUR(file->buffer)) > 0) {
471 sv_catpvn(buf, SvPVX(file->buffer) + file->offset, movesize);
473 file->offset += movesize ;
474 SvCUR_set(file->buffer, bufsize - movesize) ;
478 bufp = (Byte*)SvGROW(buf, bufsize+len+1);
479 RETVAL = gzread(file->gz, ((Bytef*)bufp)+bufsize, len) ;
480 SetGzError(file->gz) ;
483 SvCUR_set(buf, RETVAL) ;
492 gzreadline(file, buf)
493 Compress::Zlib::gzFile file
497 if (SvREADONLY(buf) && PL_curcop != &PL_compiling)
498 croak("gzreadline: buffer parameter is read-only");
499 SvUPGRADE(buf, SVt_PV);
501 /* sv_setpvn(buf, "", SIZE) ; */
504 RETVAL = gzreadline(file, buf) ;
505 SetGzError(file->gz) ;
511 /* SvCUR(buf) = RETVAL; */
512 /* Don't need to explicitly terminate with '\0', because
513 sv_catpvn aready has */
516 #define Zip_gzwrite(file, buf) gzwrite(file->gz, buf, (unsigned)len)
518 Zip_gzwrite(file, buf)
519 Compress::Zlib::gzFile file
521 voidp buf = (voidp)SvPV(ST(1), len) ;
523 SetGzError(file->gz) ;
525 #define Zip_gzflush(file, flush) gzflush(file->gz, flush)
527 Zip_gzflush(file, flush)
528 Compress::Zlib::gzFile file
531 SetGzError(file->gz) ;
533 #define Zip_gzclose(file) file->closed ? 0 : gzclose(file->gz)
536 Compress::Zlib::gzFile file
538 file->closed = TRUE ;
539 SetGzErrorNo(RETVAL) ;
542 #define Zip_gzeof(file) gzeof(file->gz)
545 Compress::Zlib::gzFile file
548 croak("gzeof needs zlib 1.0.6 or better") ;
550 RETVAL = gzeof(file->gz);
556 #define Zip_gzsetparams(file,l,s) gzsetparams(file->gz,l,s)
558 Zip_gzsetparams(file, level, strategy)
559 Compress::Zlib::gzFile file
564 croak("gzsetparams needs zlib 1.0.6 or better") ;
566 RETVAL = gzsetparams(file->gz, level, strategy);
573 Compress::Zlib::gzFile file
577 SvREFCNT_dec(file->buffer) ;
578 safefree((char*)file) ;
580 #define Zip_gzerror(file) (char*)gzerror(file->gz, &errnum)
584 Compress::Zlib::gzFile file
587 sv_setiv(ST(0), errnum) ;
592 MODULE = Compress::Zlib PACKAGE = Compress::Zlib PREFIX = Zip_
595 #define Zip_adler32(buf, adler) adler32(adler, buf, (uInt)len)
598 Zip_adler32(buf, adler=adlerInitial)
599 uLong adler = NO_INIT
601 Bytef * buf = NO_INIT
604 /* If the buffer is a reference, dereference it */
605 sv = deRef(sv, "adler32") ;
606 buf = (Byte*)SvPV(sv, len) ;
609 adler = adlerInitial;
610 else if (SvOK(ST(1)))
611 adler = SvUV(ST(1)) ;
613 adler = adlerInitial;
615 #define Zip_crc32(buf, crc) crc32(crc, buf, (uInt)len)
618 Zip_crc32(buf, crc=crcInitial)
621 Bytef * buf = NO_INIT
624 /* If the buffer is a reference, dereference it */
625 sv = deRef(sv, "crc32") ;
626 buf = (Byte*)SvPV(sv, len) ;
630 else if (SvOK(ST(1)))
635 MODULE = Compress::Zlib PACKAGE = Compress::Zlib
638 _deflateInit(level, method, windowBits, memLevel, strategy, bufsize, dictionary)
652 warn("in _deflateInit(level=%d, method=%d, windowBits=%d, memLevel=%d, strategy=%d, bufsize=%d\n",
653 level, method, windowBits, memLevel, strategy, bufsize) ;
654 if ((s = InitStream(bufsize)) ) {
658 s->WindowBits = windowBits;
659 s->MemLevel = memLevel;
660 s->Strategy = strategy;
662 err = deflateInit2(&(s->stream), level,
663 method, windowBits, memLevel, strategy);
665 /* Check if a dictionary has been specified */
666 if (err == Z_OK && SvCUR(dictionary)) {
667 err = deflateSetDictionary(&(s->stream), (const Bytef*) SvPVX(dictionary),
669 s->dict_adler = s->stream.adler ;
681 XPUSHs(sv_setref_pv(sv_newmortal(),
682 "Compress::Zlib::deflateStream", (void*)s));
683 if (GIMME == G_ARRAY)
684 XPUSHs(sv_2mortal(newSViv(err))) ;
687 _inflateInit(windowBits, bufsize, dictionary)
697 warn("in _inflateInit(windowBits=%d, bufsize=%d, dictionary=%d\n",
698 windowBits, bufsize, SvCUR(dictionary)) ;
699 if ((s = InitStream(bufsize)) ) {
701 s->WindowBits = windowBits;
703 err = inflateInit2(&(s->stream), windowBits);
709 else if (SvCUR(dictionary)) {
710 /* Dictionary specified - take a copy for use in inflate */
711 s->dictionary = newSVsv(dictionary) ;
717 XPUSHs(sv_setref_pv(sv_newmortal(),
718 "Compress::Zlib::inflateStream", (void*)s));
719 if (GIMME == G_ARRAY)
720 XPUSHs(sv_2mortal(newSViv(err))) ;
724 MODULE = Compress::Zlib PACKAGE = Compress::Zlib::deflateStream
727 DispStream(s, message=NULL)
728 Compress::Zlib::deflateStream s
733 Compress::Zlib::deflateStream s
735 uLong outsize = NO_INIT
736 SV * output = NO_INIT
740 /* If the buffer is a reference, dereference it */
741 buf = deRef(buf, "deflate") ;
743 /* initialise the input buffer */
744 s->stream.next_in = (Bytef*)SvPV(buf, *(STRLEN*)&s->stream.avail_in) ;
745 /* s->stream.next_in = (Bytef*)SvPVX(buf); */
746 s->stream.avail_in = SvCUR(buf) ;
748 /* and the output buffer */
749 /* output = sv_2mortal(newSVpv("", s->bufinc)) ; */
750 output = sv_2mortal(newSV(s->bufinc)) ;
752 SvCUR_set(output, 0) ;
753 outsize = s->bufinc ;
754 s->stream.next_out = (Bytef*) SvPVX(output) ;
755 s->stream.avail_out = outsize;
757 /* Check for saved output from deflateParams */
758 if (s->deflateParams_out_valid) {
759 *(s->stream.next_out) = s->deflateParams_out_byte;
760 ++ s->stream.next_out;
761 -- s->stream.avail_out ;
762 s->deflateParams_out_valid = FALSE;
765 while (s->stream.avail_in != 0) {
767 if (s->stream.avail_out == 0) {
769 SvGROW(output, outsize + s->bufinc) ;
770 s->stream.next_out = (Bytef*) SvPVX(output) + outsize ;
771 outsize += s->bufinc ;
772 s->stream.avail_out = s->bufinc ;
774 err = deflate(&(s->stream), Z_NO_FLUSH);
781 SvCUR_set(output, outsize - s->stream.avail_out) ;
784 output = &PL_sv_undef ;
786 if (GIMME == G_ARRAY)
787 XPUSHs(sv_2mortal(newSViv(err))) ;
793 Compress::Zlib::deflateStream s
795 uLong outsize = NO_INIT
796 SV * output = NO_INIT
800 s->stream.avail_in = 0; /* should be zero already anyway */
802 /* output = sv_2mortal(newSVpv("", s->bufinc)) ; */
803 output = sv_2mortal(newSV(s->bufinc)) ;
805 SvCUR_set(output, 0) ;
806 outsize = s->bufinc ;
807 s->stream.next_out = (Bytef*) SvPVX(output) ;
808 s->stream.avail_out = outsize;
810 /* Check for saved output from deflateParams */
811 if (s->deflateParams_out_valid) {
812 *(s->stream.next_out) = s->deflateParams_out_byte;
813 ++ s->stream.next_out;
814 -- s->stream.avail_out ;
815 s->deflateParams_out_valid = FALSE;
819 if (s->stream.avail_out == 0) {
820 /* consumed all the available output, so extend it */
822 SvGROW(output, outsize + s->bufinc) ;
823 s->stream.next_out = (Bytef*)SvPVX(output) + outsize ;
824 outsize += s->bufinc ;
825 s->stream.avail_out = s->bufinc ;
827 err = deflate(&(s->stream), f);
829 /* deflate has finished flushing only when it hasn't used up
830 * all the available space in the output buffer:
832 if (s->stream.avail_out != 0 || err != Z_OK )
836 err = (err == Z_STREAM_END ? Z_OK : err) ;
840 SvCUR_set(output, outsize - s->stream.avail_out) ;
843 output = &PL_sv_undef ;
845 if (GIMME == G_ARRAY)
846 XPUSHs(sv_2mortal(newSViv(err))) ;
849 _deflateParams(s, flags, level, strategy, bufsize)
850 Compress::Zlib::deflateStream s
859 s->Strategy = strategy ;
861 s->bufsize = bufsize;
864 s->stream.avail_in = 0;
865 s->stream.next_out = &(s->deflateParams_out_byte) ;
866 s->stream.avail_out = 1;
867 RETVAL = deflateParams(&(s->stream), s->Level, s->Strategy);
868 s->deflateParams_out_valid =
869 (RETVAL == Z_OK && s->stream.avail_out == 0) ;
876 Compress::Zlib::deflateStream s
884 Compress::Zlib::deflateStream s
886 RETVAL = s->Strategy ;
892 Compress::Zlib::deflateStream s
894 deflateEnd(&s->stream) ;
896 SvREFCNT_dec(s->dictionary) ;
902 Compress::Zlib::deflateStream s
904 RETVAL = s->dict_adler ;
910 Compress::Zlib::deflateStream s
912 RETVAL = s->stream.total_in ;
918 Compress::Zlib::deflateStream s
920 RETVAL = s->stream.total_out ;
926 Compress::Zlib::deflateStream s
928 RETVAL = s->stream.msg;
933 MODULE = Compress::Zlib PACKAGE = Compress::Zlib::inflateStream
936 DispStream(s, message=NULL)
937 Compress::Zlib::inflateStream s
942 Compress::Zlib::inflateStream s
944 uLong outsize = NO_INIT
945 SV * output = NO_INIT
951 /* If the buffer is a reference, dereference it */
952 buf = deRef(buf, "inflate") ;
954 /* initialise the input buffer */
955 s->stream.next_in = (Bytef*)SvPVX(buf) ;
956 s->stream.avail_in = SvCUR(buf) ;
958 /* and the output buffer */
959 output = sv_2mortal(newSV(s->bufinc+1)) ;
961 SvCUR_set(output, 0) ;
962 outsize = s->bufinc ;
963 s->stream.next_out = (Bytef*) SvPVX(output) ;
964 s->stream.avail_out = outsize;
968 if (s->stream.avail_out == 0) {
970 SvGROW(output, outsize + s->bufinc+1) ;
971 s->stream.next_out = (Bytef*) SvPVX(output) + outsize ;
972 outsize += s->bufinc ;
973 s->stream.avail_out = s->bufinc ;
976 err = inflate(&(s->stream), Z_SYNC_FLUSH);
977 if (err == Z_BUF_ERROR) {
978 if (s->stream.avail_out == 0)
980 if (s->stream.avail_in == 0) {
986 if (err == Z_NEED_DICT && s->dictionary) {
987 s->dict_adler = s->stream.adler ;
988 err = inflateSetDictionary(&(s->stream),
989 (const Bytef*)SvPVX(s->dictionary),
990 SvCUR(s->dictionary));
997 if (err == Z_OK || err == Z_STREAM_END || err == Z_DATA_ERROR) {
1001 SvCUR_set(output, outsize - s->stream.avail_out) ;
1002 *SvEND(output) = '\0';
1004 /* fix the input buffer */
1006 in = s->stream.avail_in ;
1007 SvCUR_set(buf, in) ;
1009 Move(s->stream.next_in, SvPVX(buf), in, char) ;
1015 output = &PL_sv_undef ;
1017 if (GIMME == G_ARRAY)
1018 XPUSHs(sv_2mortal(newSViv(err))) ;
1021 inflateSync (s, buf)
1022 Compress::Zlib::inflateStream s
1026 /* If the buffer is a reference, dereference it */
1027 buf = deRef(buf, "inflateSync") ;
1029 /* initialise the input buffer */
1030 s->stream.next_in = (Bytef*)SvPVX(buf) ;
1031 s->stream.avail_in = SvCUR(buf) ;
1033 /* inflateSync doesn't create any output */
1034 s->stream.next_out = (Bytef*) NULL;
1035 s->stream.avail_out = 0;
1037 RETVAL = inflateSync(&(s->stream));
1039 /* fix the input buffer */
1040 unsigned in = s->stream.avail_in ;
1042 SvCUR_set(buf, in) ;
1044 Move(s->stream.next_in, SvPVX(buf), in, char) ;
1053 Compress::Zlib::inflateStream s
1055 inflateEnd(&s->stream) ;
1057 SvREFCNT_dec(s->dictionary) ;
1063 Compress::Zlib::inflateStream s
1065 RETVAL = s->dict_adler ;
1071 Compress::Zlib::inflateStream s
1073 RETVAL = s->stream.total_in ;
1079 Compress::Zlib::inflateStream s
1081 RETVAL = s->stream.total_out ;
1087 Compress::Zlib::inflateStream s
1089 RETVAL = s->stream.msg;