RE: [PATCH] Compress::Zlib
[p5sagit/p5-mst-13.2.git] / ext / Compress / Zlib / Zlib.xs
1 /* Filename: Zlib.xs
2  * Author  : Paul Marquess, <pmqs@cpan.org>
3  * Created : 22nd January 1996
4  * Version : 2.000
5  *
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.
9  *
10  */
11
12 /* Parts of this code are based on the files gzio.c and gzappend.c from 
13  * the standard zlib source distribution. Below are the copyright statements
14  * from each. 
15  */
16
17 /* gzio.c -- IO on .gz files
18  * Copyright (C) 1995 Jean-loup Gailly.
19  * For conditions of distribution and use, see copyright notice in zlib.h
20  */
21
22 /* gzappend -- command to append to a gzip file
23
24   Copyright (C) 2003 Mark Adler, all rights reserved
25   version 1.1, 4 Nov 2003
26 */
27
28
29
30 #include "EXTERN.h"
31 #include "perl.h"
32 #include "XSUB.h"
33
34 #include <zlib.h> 
35
36
37 #if  defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1210
38 #  define MAGIC_APPEND
39 #endif
40
41 #if  defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1221
42 #  define AT_LEAST_ZLIB_1_2_2_1
43 #endif
44
45 #if  defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1223
46 #  define AT_LEAST_ZLIB_1_2_2_3
47 #endif
48
49 #if  defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
50 #  define AT_LEAST_ZLIB_1_2_3
51 #endif
52
53 #if 0
54
55 #  include "ppport.h"
56
57 #else
58
59 /* zlib prior to 1.06 doesn't know about z_off_t */
60 #ifndef z_off_t
61 #  define z_off_t   long
62 #endif
63
64 #  ifndef PERL_VERSION
65 #    include "patchlevel.h"
66 #    define PERL_REVISION       5
67 #    define PERL_VERSION        PATCHLEVEL
68 #    define PERL_SUBVERSION     SUBVERSION
69 #  endif
70
71 #  if PERL_REVISION == 5 && (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION <= 75 ))
72
73 #      define PL_sv_undef       sv_undef
74 #      define PL_na             na
75 #      define PL_curcop         curcop
76 #      define PL_compiling      compiling
77
78 #  endif
79
80 #  ifndef newSVuv
81 #      define newSVuv   newSViv
82 #  endif
83
84 #endif
85
86
87 #if PERL_REVISION == 5 && (PERL_VERSION >= 8 || (PERL_VERSION == 8 && PERL_SUBVERSION < 4 ))
88 #    define UTF8_AVAILABLE
89 #endif
90
91 #if PERL_REVISION == 5 && (PERL_VERSION < 8 || (PERL_VERSION == 8 && PERL_SUBVERSION < 4 ))
92
93 #    ifdef SvPVbyte_force
94 #        undef SvPVbyte_force
95 #    endif
96
97 #    define SvPVbyte_force(sv,lp) SvPV_force(sv,lp)
98
99 #endif
100
101 #ifndef SvPVbyte_nolen
102 #    define SvPVbyte_nolen SvPV_nolen
103 #endif
104
105 #ifndef SvPVbyte
106 #    define SvPVbyte SvPV
107 #endif
108
109 #ifndef dTHX
110 #    define dTHX 
111 #endif
112
113 #ifndef SvPV_nolen
114
115 #define sv_2pv_nolen(a) my_sv_2pv_nolen(a)
116
117 static char *
118 my_sv_2pv_nolen(register SV *sv)
119 {   
120   STRLEN n_a;
121   return sv_2pv(sv, &n_a);
122 }
123
124
125 /* SvPV_nolen depends on sv_2pv_nolen */
126 #define SvPV_nolen(sv) \
127           ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \
128            ? SvPVX(sv) : sv_2pv_nolen(sv))
129
130
131 #endif
132
133 #ifndef SvGETMAGIC
134 #  define SvGETMAGIC(x)                  STMT_START { if (SvGMAGICAL(x)) mg_get(x); } STMT_END
135 #endif
136
137 typedef int                     DualType ;
138 typedef int                     int_undef ;
139
140 typedef struct di_stream {
141     int      flags ;
142 #define FLAG_APPEND             1
143 #define FLAG_CRC32              2
144 #define FLAG_ADLER32            4
145 #define FLAG_CONSUME_INPUT      8
146     uLong    crc32 ;
147     uLong    adler32 ;
148     z_stream stream;
149     uLong     bufsize; 
150     uLong     bufinc; 
151     SV *     dictionary ;
152     uLong    dict_adler ;
153     int      last_error ;
154     bool     zip_mode ;
155 #define SETP_BYTE
156 #ifdef SETP_BYTE
157     bool     deflateParams_out_valid ;
158     Bytef    deflateParams_out_byte;
159 #else
160 #define deflateParams_BUFFER_SIZE       0x4000
161     uLong    deflateParams_out_length;
162     Bytef*   deflateParams_out_buffer;
163 #endif
164     int      Level;
165     int      Method;
166     int      WindowBits;
167     int      MemLevel;
168     int      Strategy;
169     uLong    bytesInflated ;
170 #ifdef MAGIC_APPEND
171
172 #define WINDOW_SIZE 32768U
173
174     bool     matchedEndBlock;
175     Bytef*   window ;
176     int      window_lastbit,  window_left,  window_full;
177     unsigned window_have;
178     off_t    window_lastoff, window_end;
179     off_t    window_endOffset;
180
181     uLong    lastBlockOffset ;
182     unsigned char window_lastByte ;
183                 
184
185 #endif
186 } di_stream;
187
188 typedef di_stream * deflateStream ;
189 typedef di_stream * Compress__Zlib__deflateStream ;
190 typedef di_stream * inflateStream ;
191 typedef di_stream * Compress__Zlib__inflateStream ;
192 typedef di_stream * Compress__Zlib__inflateScanStream ;
193
194 #define GZERRNO "Compress::Zlib::gzerrno"
195
196 #define ZMALLOC(to, typ) ((to = (typ *)safemalloc(sizeof(typ))), \
197                                 Zero(to,1,typ))
198
199 /* Figure out the Operating System */
200 #ifdef MSDOS
201 #  define OS_CODE  0x00
202 #endif
203
204 #if defined(AMIGA) || defined(AMIGAOS) 
205 #  define OS_CODE  0x01
206 #endif
207  
208 #if defined(VAXC) || defined(VMS)
209 #  define OS_CODE  0x02
210 #endif
211
212 #if 0 /* VM/CMS */
213 #  define OS_CODE  0x04
214 #endif
215  
216 #if defined(ATARI) || defined(atarist)
217 #  define OS_CODE  0x05
218 #endif
219  
220 #ifdef OS2
221 #  define OS_CODE  0x06
222 #endif
223  
224 #if defined(MACOS) || defined(TARGET_OS_MAC)
225 #  define OS_CODE  0x07
226 #endif
227
228 #if 0 /* Z-System */
229 #  define OS_CODE  0x08
230 #endif
231  
232 #if 0 /* CP/M */
233 #  define OS_CODE  0x09
234 #endif
235  
236 #ifdef TOPS20
237 #  define OS_CODE  0x0a
238 #endif
239
240 #ifdef WIN32 /* Window 95 & Windows NT */
241 #  define OS_CODE  0x0b
242 #endif
243  
244 #if 0 /* QDOS */
245 #  define OS_CODE  0x0c
246 #endif
247  
248 #if 0 /* Acorn RISCOS */
249 #  define OS_CODE  0x0d
250 #endif
251  
252 #if 0 /* ???  */
253 #  define OS_CODE  0x0e
254 #endif
255  
256 #ifdef __50SERIES /* Prime/PRIMOS */
257 #  define OS_CODE  0x0F
258 #endif
259  
260 /* Default to UNIX */ 
261 #ifndef OS_CODE
262 #  define OS_CODE  0x03  /* assume Unix */
263 #endif
264
265 #ifndef GZIP_OS_CODE
266 #  define GZIP_OS_CODE OS_CODE
267 #endif
268
269 #define adlerInitial adler32(0L, Z_NULL, 0)
270 #define crcInitial crc32(0L, Z_NULL, 0)
271
272
273 static const char * const my_z_errmsg[] = {
274     "need dictionary",     /* Z_NEED_DICT     2 */
275     "stream end",          /* Z_STREAM_END    1 */
276     "",                    /* Z_OK            0 */
277     "file error",          /* Z_ERRNO        (-1) */
278     "stream error",        /* Z_STREAM_ERROR (-2) */
279     "data error",          /* Z_DATA_ERROR   (-3) */
280     "insufficient memory", /* Z_MEM_ERROR    (-4) */
281     "buffer error",        /* Z_BUF_ERROR    (-5) */
282     "incompatible version",/* Z_VERSION_ERROR(-6) */
283     ""};
284
285 #define setDUALstatus(var, err)                                         \
286                 sv_setnv(var, (double)err) ;                            \
287                 sv_setpv(var, ((err) ? GetErrorString(err) : "")) ;     \
288                 SvNOK_on(var);
289
290    
291 #if defined(__SYMBIAN32__)
292 # define NO_WRITEABLE_DATA
293 #endif
294
295 #define TRACE_DEFAULT 0
296
297 #ifdef NO_WRITEABLE_DATA
298 #  define trace TRACE_DEFAULT
299 #else
300   static int trace = TRACE_DEFAULT ;
301 #endif
302
303 /* Dodge PerlIO hiding of these functions. */
304 #undef printf
305
306 static char *
307 #ifdef CAN_PROTOTYPE
308 GetErrorString(int error_no)
309 #else
310 GetErrorString(error_no)
311 int error_no ;
312 #endif
313 {
314     dTHX;
315     char * errstr ;
316   
317     if (error_no == Z_ERRNO) {
318         errstr = Strerror(errno) ;
319     }
320     else
321         /* errstr = gzerror(fil, &error_no) ; */
322         errstr = (char*) my_z_errmsg[2 - error_no]; 
323
324     return errstr ;
325 }
326
327 #if 0
328 static void
329 #ifdef CAN_PROTOTYPE
330 SetGzErrorNo(int error_no)
331 #else
332 SetGzErrorNo(error_no)
333 int error_no ;
334 #endif
335 {
336     char * errstr ;
337     SV * gzerror_sv = perl_get_sv(GZERRNO, FALSE) ;
338   
339     if (error_no == Z_ERRNO) {
340         error_no = errno ;
341         errstr = Strerror(errno) ;
342     }
343     else
344         /* errstr = gzerror(fil, &error_no) ; */
345         errstr = (char*) my_z_errmsg[2 - error_no]; 
346
347     if (SvIV(gzerror_sv) != error_no) {
348         sv_setiv(gzerror_sv, error_no) ;
349         sv_setpv(gzerror_sv, errstr) ;
350         SvIOK_on(gzerror_sv) ;
351     }
352
353 }
354
355
356 static void
357 #ifdef CAN_PROTOTYPE
358 SetGzError(gzFile file)
359 #else
360 SetGzError(file)
361 gzFile file ;
362 #endif
363 {
364     int error_no ;
365
366     (void)gzerror(file, &error_no) ;
367     SetGzErrorNo(error_no) ;
368 }
369
370 #endif
371
372 #ifdef MAGIC_APPEND
373
374 /*
375    The following two functions are taken almost directly from
376    examples/gzappend.c. Only cosmetic changes have been made to conform to
377    the coding style of the rest of the code in this file.
378 */
379
380
381 /* return the greatest common divisor of a and b using Euclid's algorithm,
382    modified to be fast when one argument much greater than the other, and
383    coded to avoid unnecessary swapping */
384 static unsigned 
385 #ifdef CAN_PROTOTYPE
386 gcd(unsigned a, unsigned b)
387 #else
388 gcd(a, b)
389     unsigned a;
390     unsigned b;
391 #endif
392 {
393     unsigned c;
394
395     while (a && b)
396         if (a > b) {
397             c = b;
398             while (a - c >= c)
399                 c <<= 1;
400             a -= c;
401         }
402         else {
403             c = a;
404             while (b - c >= c)
405                 c <<= 1;
406             b -= c;
407         }
408     return a + b;
409 }
410
411 /* rotate list[0..len-1] left by rot positions, in place */
412 static void 
413 #ifdef CAN_PROTOTYPE
414 rotate(unsigned char *list, unsigned len, unsigned rot)
415 #else
416 rotate(list, len, rot)
417     unsigned char *list;
418     unsigned len ;
419     unsigned rot;
420 #endif
421 {
422     unsigned char tmp;
423     unsigned cycles;
424     unsigned char *start, *last, *to, *from;
425
426     /* normalize rot and handle degenerate cases */
427     if (len < 2) return;
428     if (rot >= len) rot %= len;
429     if (rot == 0) return;
430
431     /* pointer to last entry in list */
432     last = list + (len - 1);
433
434     /* do simple left shift by one */
435     if (rot == 1) {
436         tmp = *list;
437         memcpy(list, list + 1, len - 1);
438         *last = tmp;
439         return;
440     }
441
442     /* do simple right shift by one */
443     if (rot == len - 1) {
444         tmp = *last;
445         memmove(list + 1, list, len - 1);
446         *list = tmp;
447         return;
448     }
449
450     /* otherwise do rotate as a set of cycles in place */
451     cycles = gcd(len, rot);             /* number of cycles */
452     do {
453         start = from = list + cycles;   /* start index is arbitrary */
454         tmp = *from;                    /* save entry to be overwritten */
455         for (;;) {
456             to = from;                  /* next step in cycle */
457             from += rot;                /* go right rot positions */
458             if (from > last) from -= len;   /* (pointer better not wrap) */
459             if (from == start) break;   /* all but one shifted */
460             *to = *from;                /* shift left */
461         }
462         *to = tmp;                      /* complete the circle */
463     } while (--cycles);
464 }
465
466 #endif /* MAGIC_APPEND */
467
468 static void
469 #ifdef CAN_PROTOTYPE
470 DispHex(void * ptr, int length)
471 #else
472 DispHex(ptr, length)
473     void * ptr;
474     int length;
475 #endif
476 {
477     char * p = (char*)ptr;
478     int i;
479     for (i = 0; i < length; ++i) {
480         printf(" %02x", 0xFF & *(p+i));
481     }
482 }
483
484
485 static void
486 #ifdef CAN_PROTOTYPE
487 DispStream(di_stream * s, char * message)
488 #else
489 DispStream(s, message)
490     di_stream * s;
491     char * message;
492 #endif
493 {
494
495 #if 0
496     if (! trace)
497         return ;
498 #endif
499
500 #define EnDis(f) (s->flags & f ? "Enabled" : "Disabled")
501
502     printf("DispStream 0x%p", s) ;
503     if (message)
504         printf("- %s \n", message) ;
505     printf("\n") ;
506
507     if (!s)  {
508         printf("    stream pointer is NULL\n");
509     }
510     else     {
511         printf("    stream           0x%p\n", &(s->stream));
512         printf("           zalloc    0x%p\n", s->stream.zalloc);
513         printf("           zfree     0x%p\n", s->stream.zfree);
514         printf("           opaque    0x%p\n", s->stream.opaque);
515         if (s->stream.msg)
516             printf("           msg       %s\n", s->stream.msg);
517         else
518             printf("           msg       \n");
519         printf("           next_in   0x%p", s->stream.next_in);
520         if (s->stream.next_in){
521             printf(" =>");
522             DispHex(s->stream.next_in, 4);
523         }
524         printf("\n");
525
526         printf("           next_out  0x%p", s->stream.next_out);
527         if (s->stream.next_out){
528             printf(" =>");
529             DispHex(s->stream.next_out, 4);
530         }
531         printf("\n");
532
533         printf("           avail_in  %lu\n",  (unsigned long)s->stream.avail_in);
534         printf("           avail_out %lu\n",  (unsigned long)s->stream.avail_out);
535         printf("           total_in  %ld\n",  s->stream.total_in);
536         printf("           total_out %ld\n",  s->stream.total_out);
537         printf("           adler     %ld\n",  s->stream.adler    );
538         printf("    bufsize          %ld\n",  s->bufsize);
539         printf("    dictionary       0x%p\n", s->dictionary);
540         printf("    dict_adler       0x%ld\n",s->dict_adler);
541         printf("    zip_mode         %d\n",   s->zip_mode);
542         printf("    crc32            0x%x\n", (unsigned)s->crc32);
543         printf("    adler32          0x%x\n", (unsigned)s->adler32);
544         printf("    flags            0x%x\n", s->flags);
545         printf("           APPEND    %s\n",   EnDis(FLAG_APPEND));
546         printf("           CRC32     %s\n",   EnDis(FLAG_CRC32));
547         printf("           ADLER32   %s\n",   EnDis(FLAG_ADLER32));
548         printf("           CONSUME   %s\n",   EnDis(FLAG_CONSUME_INPUT));
549
550 #ifdef MAGIC_APPEND
551         printf("    window           0x%p\n", s->window);
552 #endif
553         printf("\n");
554
555     }
556 }
557
558 static di_stream *
559 #ifdef CAN_PROTOTYPE
560 InitStream(void)
561 #else
562 InitStream()
563 #endif
564 {
565     di_stream *s ;
566
567     ZMALLOC(s, di_stream) ;
568
569     return s ;
570     
571 }
572
573 static void
574 #ifdef CAN_PROTOTYPE
575 PostInitStream(di_stream * s, int flags, int bufsize, int windowBits)
576 #else
577 PostInitStream(s, flags, bufsize, windowBits)
578     di_stream *s ;
579     int flags ;
580     int bufsize ;
581     int windowBits ;
582 #endif
583 {
584     s->bufsize = bufsize ;
585     s->bufinc  = bufsize ;
586     s->last_error = 0 ;
587     s->flags    = flags ;
588     s->zip_mode = (windowBits < 0) ;
589     if (flags & FLAG_CRC32) 
590         s->crc32 = crcInitial ;
591     if (flags & FLAG_ADLER32) 
592         s->adler32 = adlerInitial ;
593 }
594
595
596 static SV* 
597 #ifdef CAN_PROTOTYPE
598 deRef(SV * sv, char * string)
599 #else
600 deRef(sv, string)
601 SV * sv ;
602 char * string;
603 #endif
604 {
605     dTHX;
606     SvGETMAGIC(sv);
607
608     if (SvROK(sv)) {
609         sv = SvRV(sv) ;
610         SvGETMAGIC(sv);
611         switch(SvTYPE(sv)) {
612             case SVt_PVAV:
613             case SVt_PVHV:
614             case SVt_PVCV:
615                 croak("%s: buffer parameter is not a SCALAR reference", string);
616         }
617         if (SvROK(sv))
618             croak("%s: buffer parameter is a reference to a reference", string) ;
619     }
620
621     if (!SvOK(sv)) { 
622         sv = newSVpv("", 0);
623     }
624
625     return sv ;
626 }
627
628 static SV*
629 #ifdef CAN_PROTOTYPE
630 deRef_l(SV * sv, char * string)
631 #else
632 deRef_l(sv, string)
633 SV * sv ;
634 char * string ;
635 #endif
636 {
637     bool wipe = 0 ;
638     
639     SvGETMAGIC(sv);
640     wipe = ! SvOK(sv) ;
641
642     if (SvROK(sv)) {
643         sv = SvRV(sv) ;
644         SvGETMAGIC(sv);
645         wipe = ! SvOK(sv) ;
646
647         switch(SvTYPE(sv)) {
648             case SVt_PVAV:
649             case SVt_PVHV:
650             case SVt_PVCV:
651                 croak("%s: buffer parameter is not a SCALAR reference", string);
652         }
653         if (SvROK(sv))
654             croak("%s: buffer parameter is a reference to a reference", string) ;
655     }
656
657     if (SvREADONLY(sv) && PL_curcop != &PL_compiling)
658         croak("%s: buffer parameter is read-only", string);
659
660     SvUPGRADE(sv, SVt_PV);
661
662     if (wipe)
663         SvCUR_set(sv, 0);
664     
665     SvOOK_off(sv);
666     SvPOK_only(sv);
667
668     return sv ;
669 }
670
671
672 #include "constants.h"
673
674 MODULE = Compress::Zlib PACKAGE = Compress::Zlib        PREFIX = Zip_
675
676 REQUIRE:        1.924
677 PROTOTYPES:     DISABLE
678
679 INCLUDE: constants.xs
680
681 BOOT:
682     /* Check this version of zlib is == 1 */
683     if (zlibVersion()[0] != '1')
684         croak("Compress::Zlib needs zlib version 1.x\n") ;
685         
686     {
687         /* Create the $os_code scalar */
688         SV * os_code_sv = perl_get_sv("Compress::Zlib::gzip_os_code", GV_ADDMULTI) ;
689         sv_setiv(os_code_sv, GZIP_OS_CODE) ;
690     }
691
692     {
693         /* Create the $gzerror scalar */
694         SV * gzerror_sv = perl_get_sv(GZERRNO, GV_ADDMULTI) ;
695         sv_setiv(gzerror_sv, 0) ;
696         sv_setpv(gzerror_sv, "") ;
697         SvIOK_on(gzerror_sv) ;
698     }
699
700
701 int
702 _readonly_ref(sv)
703     SV* sv
704     CODE:
705         if (SvROK(sv)) 
706             RETVAL = SvREADONLY(SvRV(sv)) ;
707         else 
708             RETVAL = SvREADONLY(sv) ;
709     OUTPUT:
710         RETVAL
711
712 void
713 _dualvar(num,str)
714     SV *        num
715     SV *        str
716 PROTOTYPE: $$
717 CODE:
718 {
719     STRLEN len;
720     char *ptr = SvPVbyte(str,len); 
721     ST(0) = sv_newmortal();
722     SvUPGRADE(ST(0),SVt_PVNV);
723     sv_setpvn(ST(0),ptr,len);
724     if(SvNOK(num) || SvPOK(num) || SvMAGICAL(num)) {
725         SvNV_set(ST(0), SvNV(num));
726         SvNOK_on(ST(0));
727     }
728 #ifdef SVf_IVisUVXXXX
729     else if (SvUOK(num)) {
730         SvUVX(ST(0)) = SvUV(num);
731         SvIOK_on(ST(0));
732         SvIsUV_on(ST(0));
733     }
734 #endif
735     else {
736         SvIV_set(ST(0), SvIV(num));
737         SvIOK_on(ST(0));
738     }
739     XSRETURN(1);
740 }
741
742
743 #define Zip_zlib_version()      (char*)zlib_version
744 char*
745 Zip_zlib_version()
746
747 unsigned
748 ZLIB_VERNUM()
749     CODE:
750 #ifdef ZLIB_VERNUM
751         RETVAL = ZLIB_VERNUM ;
752 #else
753         /* 1.1.4 => 0x1140 */
754         RETVAL  = (ZLIB_VERSION[0] - '0') << 12 ;
755         RETVAL += (ZLIB_VERSION[2] - '0') <<  8 ;
756         RETVAL += (ZLIB_VERSION[4] - '0') <<  4 ;
757 #endif
758     OUTPUT:
759         RETVAL
760
761 MODULE = Compress::Zlib PACKAGE = Compress::Zlib        PREFIX = Zip_
762
763 #define Zip_adler32(buf, adler) adler32(adler, buf, (uInt)len)
764
765 uLong
766 Zip_adler32(buf, adler=adlerInitial)
767         uLong    adler = NO_INIT
768         STRLEN   len = NO_INIT
769         Bytef *  buf = NO_INIT
770         SV *     sv = ST(0) ;
771         INIT:
772         /* If the buffer is a reference, dereference it */
773         sv = deRef(sv, "adler32") ;
774 #ifdef UTF8_AVAILABLE    
775     if (DO_UTF8(sv) && !sv_utf8_downgrade(sv, 1))
776          croak("Wide character in Compress::Zlib::adler32");
777 #endif         
778         buf = (Byte*)SvPVbyte(sv, len) ;
779
780         if (items < 2)
781           adler = adlerInitial;
782         else if (SvOK(ST(1)))
783           adler = SvUV(ST(1)) ;
784         else
785           adler = adlerInitial;
786  
787 #define Zip_crc32(buf, crc) crc32(crc, buf, (uInt)len)
788
789 uLong
790 Zip_crc32(buf, crc=crcInitial)
791         uLong    crc = NO_INIT
792         STRLEN   len = NO_INIT
793         Bytef *  buf = NO_INIT
794         SV *     sv = ST(0) ;
795         INIT:
796         /* If the buffer is a reference, dereference it */
797         sv = deRef(sv, "crc32") ;
798 #ifdef UTF8_AVAILABLE    
799     if (DO_UTF8(sv) && !sv_utf8_downgrade(sv, 1))
800          croak("Wide character in Compress::Zlib::crc32");
801 #endif         
802         buf = (Byte*)SvPVbyte(sv, len) ;
803
804         if (items < 2)
805           crc = crcInitial;
806         else if (SvOK(ST(1)))
807           crc = SvUV(ST(1)) ;
808         else
809           crc = crcInitial;
810
811
812 uLong
813 crc32_combine(crc1, crc2, len2)
814         uLong    crc1 
815         uLong    crc2 
816         z_off_t   len2 
817         CODE:
818 #ifndef AT_LEAST_ZLIB_1_2_2_1
819         crc1 = crc1; crc2 = crc2 ; len2 = len2; /* Silence -Wall */
820         croak("crc32_combine needs zlib 1.2.3 or better");
821 #else
822         RETVAL = crc32_combine(crc1, crc2, len2);
823 #endif
824     OUTPUT:
825         RETVAL
826
827
828 uLong
829 adler32_combine(adler1, adler2, len2)
830         uLong    adler1 
831         uLong    adler2 
832         z_off_t   len2 
833         CODE:
834 #ifndef AT_LEAST_ZLIB_1_2_2_1
835         adler1 = adler1; adler2 = adler2 ; len2 = len2; /* Silence -Wall */
836         croak("adler32_combine needs zlib 1.2.3 or better");
837 #else
838         RETVAL = adler32_combine(adler1, adler2, len2);
839 #endif
840     OUTPUT:
841         RETVAL
842
843
844 MODULE = Compress::Zlib PACKAGE = Compress::Zlib
845
846 void
847 _deflateInit(flags,level, method, windowBits, memLevel, strategy, bufsize, dictionary)
848     int flags
849     int level
850     int method
851     int windowBits
852     int memLevel
853     int strategy
854     uLong bufsize
855     SV* dictionary
856   PPCODE:
857     int err ;
858     deflateStream s ;
859
860     if (trace)
861         warn("in _deflateInit(level=%d, method=%d, windowBits=%d, memLevel=%d, strategy=%d, bufsize=%ld\n",
862         level, method, windowBits, memLevel, strategy, bufsize) ;
863     if ((s = InitStream() )) {
864
865         s->Level      = level;
866         s->Method     = method;
867         s->WindowBits = windowBits;
868         s->MemLevel   = memLevel;
869         s->Strategy   = strategy;
870
871         err = deflateInit2(&(s->stream), level, 
872                            method, windowBits, memLevel, strategy);
873
874         /* Check if a dictionary has been specified */
875
876         if (err == Z_OK && SvCUR(dictionary)) {
877 #ifdef UTF8_AVAILABLE    
878         if (DO_UTF8(dictionary) && !sv_utf8_downgrade(dictionary, 1))
879              croak("Wide character in Compress::Zlib::Deflate::new dicrionary parameter");
880 #endif         
881             err = deflateSetDictionary(&(s->stream), (const Bytef*) SvPVbyte_nolen(dictionary), 
882                                         SvCUR(dictionary)) ;
883             s->dict_adler = s->stream.adler ;
884         }
885
886         if (err != Z_OK) {
887             Safefree(s) ;
888             s = NULL ;
889         }
890         else
891             PostInitStream(s, flags, bufsize, windowBits) ;
892         
893     }
894     else
895         err = Z_MEM_ERROR ;
896
897     XPUSHs(sv_setref_pv(sv_newmortal(), 
898         "Compress::Zlib::deflateStream", (void*)s));
899     if (GIMME == G_ARRAY) {
900         SV * sv = sv_2mortal(newSViv(err)) ;
901         setDUALstatus(sv, err);
902         XPUSHs(sv) ;
903     }
904
905 void
906 _inflateInit(flags, windowBits, bufsize, dictionary)
907     int flags
908     int windowBits
909     uLong bufsize
910     SV * dictionary
911   ALIAS:
912     _inflateScanInit = 1
913   PPCODE:
914  
915     int err = Z_OK ;
916     inflateStream s ;
917 #ifndef MAGIC_APPEND
918     if (ix == 1)
919         croak("inflateScanInit needs zlib 1.2.1 or better");
920 #endif
921     if (trace)
922         warn("in _inflateInit(windowBits=%d, bufsize=%lu, dictionary=%lu\n",
923                 windowBits, bufsize, (unsigned long)SvCUR(dictionary)) ;
924     if ((s = InitStream() )) {
925
926         s->WindowBits = windowBits;
927
928         err = inflateInit2(&(s->stream), windowBits);
929         if (err != Z_OK) {
930             Safefree(s) ;
931             s = NULL ;
932         }
933         else if (SvCUR(dictionary)) {
934             /* Dictionary specified - take a copy for use in inflate */
935             s->dictionary = newSVsv(dictionary) ;
936         }
937         if (s) {
938             PostInitStream(s, flags, bufsize, windowBits) ;
939 #ifdef MAGIC_APPEND
940             if (ix == 1)
941             {
942                 s->window = (unsigned char *)safemalloc(WINDOW_SIZE);
943             }
944 #endif
945         }
946     }
947     else
948         err = Z_MEM_ERROR ;
949
950     XPUSHs(sv_setref_pv(sv_newmortal(), 
951                    ix == 1 
952                    ? "Compress::Zlib::inflateScanStream" 
953                    :  "Compress::Zlib::inflateStream",
954                    (void*)s));
955     if (GIMME == G_ARRAY) {
956         SV * sv = sv_2mortal(newSViv(err)) ;
957         setDUALstatus(sv, err);
958         XPUSHs(sv) ;
959     }
960  
961
962
963 MODULE = Compress::Zlib PACKAGE = Compress::Zlib::deflateStream
964
965 void
966 DispStream(s, message=NULL)
967     Compress::Zlib::deflateStream   s
968     char *  message
969
970 DualType
971 deflateReset(s)
972     Compress::Zlib::deflateStream   s
973   CODE:
974       RETVAL = deflateReset(&(s->stream)) ;
975       if (RETVAL == Z_OK) {
976           PostInitStream(s, s->flags, s->bufsize, s->WindowBits) ;
977       }
978     OUTPUT:
979       RETVAL
980
981 DualType 
982 deflate (s, buf, output)
983     Compress::Zlib::deflateStream       s
984     SV *        buf
985     SV *        output 
986     uInt        cur_length = NO_INIT
987     uInt        increment = NO_INIT
988     int         RETVAL = 0;
989   CODE:
990
991     /* If the input buffer is a reference, dereference it */
992     buf = deRef(buf, "deflate") ;
993  
994     /* initialise the input buffer */
995 #ifdef UTF8_AVAILABLE    
996     if (DO_UTF8(buf) && !sv_utf8_downgrade(buf, 1))
997          croak("Wide character in Compress::Zlib::Deflate::deflate input parameter");
998 #endif         
999     s->stream.next_in = (Bytef*)SvPVbyte_nolen(buf) ;
1000     s->stream.avail_in = SvCUR(buf) ; 
1001     
1002     if (s->flags & FLAG_CRC32)
1003         s->crc32 = crc32(s->crc32, s->stream.next_in, s->stream.avail_in) ;
1004
1005     if (s->flags & FLAG_ADLER32)
1006         s->adler32 = adler32(s->adler32, s->stream.next_in, s->stream.avail_in) ;
1007
1008     /* and retrieve the output buffer */
1009     output = deRef_l(output, "deflate") ;
1010 #ifdef UTF8_AVAILABLE    
1011     if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1))
1012          croak("Wide character in Compress::Zlib::Deflate::deflate output parameter");
1013 #endif         
1014
1015     if((s->flags & FLAG_APPEND) != FLAG_APPEND) {
1016         SvCUR_set(output, 0);
1017         /* sv_setpvn(output, "", 0); */
1018     }
1019     cur_length =  SvCUR(output) ;
1020     s->stream.next_out = (Bytef*) SvPVbyte_nolen(output) + cur_length;
1021     increment =  SvLEN(output) -  cur_length;
1022     s->stream.avail_out =  increment;
1023 #ifdef SETP_BYTE
1024     /* Check for saved output from deflateParams */
1025     if (s->deflateParams_out_valid) {
1026         *(s->stream.next_out) = s->deflateParams_out_byte;
1027         ++ s->stream.next_out;
1028         -- s->stream.avail_out ;
1029         s->deflateParams_out_valid = FALSE;
1030     }
1031 #else
1032     /* Check for saved output from deflateParams */
1033     if (s->deflateParams_out_length) {
1034         uLong plen = s->deflateParams_out_length ;
1035         /* printf("Copy %d bytes saved data\n", plen);*/
1036         if (s->stream.avail_out < plen) {
1037             /*printf("GROW from %d to %d\n", s->stream.avail_out,
1038                         SvLEN(output) + plen - s->stream.avail_out); */
1039             Sv_Grow(output, SvLEN(output) + plen - s->stream.avail_out) ;
1040         }
1041         
1042         Copy(s->stream.next_out, s->deflateParams_out_buffer, plen, Bytef) ;    
1043         cur_length = cur_length + plen;
1044         SvCUR_set(output, cur_length);
1045         s->stream.next_out += plen ;
1046         s->stream.avail_out = SvLEN(output) - cur_length ;
1047         increment = s->stream.avail_out;
1048         s->deflateParams_out_length = 0;
1049     }
1050 #endif
1051     while (s->stream.avail_in != 0) {
1052
1053         if (s->stream.avail_out == 0) {
1054             /* out of space in the output buffer so make it bigger */
1055             s->bufinc *= 2 ;
1056             Sv_Grow(output, SvLEN(output) + s->bufinc) ;
1057             cur_length += increment ;
1058             s->stream.next_out = (Bytef*) SvPVbyte_nolen(output) + cur_length ;
1059             increment = s->bufinc ;
1060             s->stream.avail_out = increment;
1061         }
1062
1063         RETVAL = deflate(&(s->stream), Z_NO_FLUSH);
1064         if (RETVAL != Z_OK) 
1065             break;
1066     }
1067
1068     s->last_error = RETVAL ;
1069     if (RETVAL == Z_OK) {
1070         SvPOK_only(output);
1071         SvCUR_set(output, cur_length + increment - s->stream.avail_out) ;
1072     }
1073     OUTPUT:
1074         RETVAL
1075         output
1076   
1077
1078 void
1079 DESTROY(s)
1080     Compress::Zlib::deflateStream       s
1081   CODE:
1082     deflateEnd(&s->stream) ;
1083     if (s->dictionary)
1084         SvREFCNT_dec(s->dictionary) ;
1085 #ifndef SETP_BYTE
1086     if (s->deflateParams_out_buffer)
1087         Safefree(s->deflateParams_out_buffer);
1088 #endif
1089     Safefree(s) ;
1090
1091
1092 DualType
1093 flush(s, output, f=Z_FINISH)
1094     Compress::Zlib::deflateStream       s
1095     SV * output 
1096     int  f
1097     uInt        cur_length = NO_INIT
1098     uInt        increment = NO_INIT
1099   CODE:
1100   
1101     s->stream.avail_in = 0; /* should be zero already anyway */
1102   
1103     /* retrieve the output buffer */
1104     output = deRef_l(output, "flush") ;
1105 #ifdef UTF8_AVAILABLE    
1106     if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1))
1107          croak("Wide character in Compress::Zlib::Deflate::flush input parameter");
1108 #endif         
1109     if(! s->flags & FLAG_APPEND) {
1110         SvCUR_set(output, 0);
1111         /* sv_setpvn(output, "", 0); */
1112     }
1113     cur_length =  SvCUR(output) ;
1114     s->stream.next_out = (Bytef*) SvPVbyte_nolen(output) + cur_length;
1115     increment =  SvLEN(output) -  cur_length;
1116     s->stream.avail_out =  increment;
1117 #ifdef SETP_BYTE
1118     /* Check for saved output from deflateParams */
1119     if (s->deflateParams_out_valid) {
1120         *(s->stream.next_out) = s->deflateParams_out_byte;
1121         ++ s->stream.next_out;
1122         -- s->stream.avail_out ;
1123         s->deflateParams_out_valid = FALSE;
1124     }
1125 #else
1126     /* Check for saved output from deflateParams */
1127     if (s->deflateParams_out_length) {
1128         uLong plen = s->deflateParams_out_length ;
1129         /* printf("Copy %d bytes saved data\n", plen); */
1130         if (s->stream.avail_out < plen) {
1131             /* printf("GROW from %d to %d\n", s->stream.avail_out, 
1132                         SvLEN(output) + plen - s->stream.avail_out); */
1133             Sv_Grow(output, SvLEN(output) + plen - s->stream.avail_out) ;
1134         }
1135         
1136         Copy(s->stream.next_out, s->deflateParams_out_buffer, plen, Bytef) ;    
1137         cur_length = cur_length + plen;
1138         SvCUR_set(output, cur_length);
1139         s->stream.next_out += plen ;
1140         s->stream.avail_out = SvLEN(output) - cur_length ;
1141         increment = s->stream.avail_out;
1142         s->deflateParams_out_length = 0;
1143     }
1144 #endif
1145
1146     for (;;) {
1147         if (s->stream.avail_out == 0) {
1148             /* consumed all the available output, so extend it */
1149             s->bufinc *= 2 ;
1150             Sv_Grow(output, SvLEN(output) + s->bufinc) ;
1151             cur_length += increment ;
1152             s->stream.next_out = (Bytef*) SvPVbyte_nolen(output) + cur_length ;
1153             increment = s->bufinc ;
1154             s->stream.avail_out = increment;
1155         }
1156         RETVAL = deflate(&(s->stream), f);
1157     
1158         /* deflate has finished flushing only when it hasn't used up
1159          * all the available space in the output buffer: 
1160          */
1161         if (s->stream.avail_out != 0 || RETVAL != Z_OK )
1162             break;
1163     }
1164   
1165     RETVAL =  (RETVAL == Z_STREAM_END ? Z_OK : RETVAL) ;
1166     s->last_error = RETVAL ;
1167   
1168     if (RETVAL == Z_OK) {
1169         SvPOK_only(output);
1170         SvCUR_set(output, cur_length + increment - s->stream.avail_out) ;
1171     }
1172     OUTPUT:
1173         RETVAL
1174         output
1175
1176
1177 DualType
1178 _deflateParams(s, flags, level, strategy, bufsize)
1179         Compress::Zlib::deflateStream   s
1180         int     flags
1181         int     level
1182         int     strategy
1183         uLong   bufsize
1184     CODE:
1185         /* printf("_deflateParams(Flags %d Level %d Strategy %d Bufsize %d)\n", flags, level, strategy, bufsize); 
1186         printf("Before -- Level %d, Strategy %d, Bufsize %d\n", s->Level, s->Strategy, s->bufsize); */
1187         if (flags & 1)
1188             s->Level = level ;
1189         if (flags & 2)
1190             s->Strategy = strategy ;
1191         if (flags & 4) {
1192             s->bufsize = bufsize; 
1193             s->bufinc  = bufsize; 
1194         }
1195         /* printf("After --  Level %d, Strategy %d, Bufsize %d\n", s->Level, s->Strategy, s->bufsize);*/
1196 #ifdef SETP_BYTE
1197         s->stream.avail_in = 0; 
1198         s->stream.next_out = &(s->deflateParams_out_byte) ;
1199         s->stream.avail_out = 1;
1200         RETVAL = deflateParams(&(s->stream), s->Level, s->Strategy);
1201         s->deflateParams_out_valid = 
1202                 (RETVAL == Z_OK && s->stream.avail_out == 0) ;
1203         /* printf("RETVAL %d, avail out %d, byte %c\n", RETVAL, s->stream.avail_out, s->deflateParams_out_byte); */
1204 #else
1205         /* printf("Level %d Strategy %d, Prev Len %d\n", 
1206                 s->Level, s->Strategy, s->deflateParams_out_length); */
1207         s->stream.avail_in = 0; 
1208         if (s->deflateParams_out_buffer == NULL)
1209             s->deflateParams_out_buffer = safemalloc(deflateParams_BUFFER_SIZE);
1210         s->stream.next_out = s->deflateParams_out_buffer ;
1211         s->stream.avail_out = deflateParams_BUFFER_SIZE;
1212
1213         RETVAL = deflateParams(&(s->stream), s->Level, s->Strategy);
1214         s->deflateParams_out_length = deflateParams_BUFFER_SIZE - s->stream.avail_out;
1215         /* printf("RETVAL %d, length out %d, avail %d\n", 
1216                     RETVAL, s->deflateParams_out_length, s->stream.avail_out ); */
1217 #endif
1218     OUTPUT:
1219         RETVAL
1220
1221
1222 int
1223 get_Level(s)
1224         Compress::Zlib::deflateStream   s
1225     CODE:
1226         RETVAL = s->Level ;
1227     OUTPUT:
1228         RETVAL
1229
1230 int
1231 get_Strategy(s)
1232         Compress::Zlib::deflateStream   s
1233     CODE:
1234         RETVAL = s->Strategy ;
1235     OUTPUT:
1236         RETVAL
1237
1238
1239 uLong
1240 get_Bufsize(s)
1241         Compress::Zlib::deflateStream   s
1242     CODE:
1243         RETVAL = s->bufsize ;
1244     OUTPUT:
1245         RETVAL
1246
1247
1248 int
1249 status(s)
1250         Compress::Zlib::deflateStream   s
1251     CODE:
1252         RETVAL = s->last_error ;
1253     OUTPUT:
1254         RETVAL
1255
1256 uLong
1257 crc32(s)
1258         Compress::Zlib::deflateStream   s
1259     CODE:
1260         RETVAL = s->crc32 ;
1261     OUTPUT:
1262         RETVAL
1263
1264 uLong
1265 dict_adler(s)
1266         Compress::Zlib::deflateStream   s
1267     CODE:
1268         RETVAL = s->dict_adler ;
1269     OUTPUT:
1270         RETVAL
1271
1272 uLong
1273 adler32(s)
1274         Compress::Zlib::deflateStream   s
1275     CODE:
1276         RETVAL = s->adler32 ;
1277     OUTPUT:
1278         RETVAL
1279
1280 uLong
1281 total_in(s)
1282         Compress::Zlib::deflateStream   s
1283     CODE:
1284         RETVAL = s->stream.total_in ;
1285     OUTPUT:
1286         RETVAL
1287
1288 uLong
1289 total_out(s)
1290         Compress::Zlib::deflateStream   s
1291     CODE:
1292         RETVAL = s->stream.total_out ;
1293     OUTPUT:
1294         RETVAL
1295
1296 char*
1297 msg(s)
1298         Compress::Zlib::deflateStream   s
1299     CODE:
1300         RETVAL = s->stream.msg;
1301     OUTPUT:
1302         RETVAL
1303
1304 int 
1305 deflateTune(s, good_length, max_lazy, nice_length, max_chain)
1306             Compress::Zlib::deflateStream   s
1307             int good_length
1308             int max_lazy
1309             int nice_length
1310             int max_chain
1311     CODE:
1312 #ifndef AT_LEAST_ZLIB_1_2_2_3
1313         good_length = good_length; max_lazy = max_lazy ; /* Silence -Wall */
1314         nice_length = nice_length; max_chain = max_chain; /* Silence -Wall */
1315         croak("deflateTune needs zlib 1.2.2.3 or better");
1316 #else
1317         RETVAL = deflateTune(&(s->stream), good_length, max_lazy, nice_length, max_chain);
1318 #endif
1319     OUTPUT:
1320         RETVAL
1321     
1322
1323 MODULE = Compress::Zlib PACKAGE = Compress::Zlib::inflateStream
1324
1325 void
1326 DispStream(s, message=NULL)
1327     Compress::Zlib::inflateStream   s
1328     char *  message
1329
1330 DualType
1331 inflateReset(s)
1332     Compress::Zlib::inflateStream   s
1333   CODE:
1334       RETVAL = inflateReset(&(s->stream)) ;
1335       if (RETVAL == Z_OK) {
1336           PostInitStream(s, s->flags, s->bufsize, s->WindowBits) ;
1337       }
1338     OUTPUT:
1339       RETVAL
1340
1341 DualType 
1342 inflate (s, buf, output)
1343     Compress::Zlib::inflateStream       s
1344     SV *        buf
1345     SV *        output 
1346     uInt        cur_length = NO_INIT
1347     uInt        prefix_length = NO_INIT
1348     uInt        increment = NO_INIT
1349     STRLEN  stmp   = NO_INIT
1350   PREINIT:
1351 #ifdef UTF8_AVAILABLE    
1352     bool        out_utf8  = FALSE;
1353 #endif    
1354   CODE:
1355     /* If the buffer is a reference, dereference it */
1356     buf = deRef(buf, "inflate") ;
1357
1358     if (s->flags & FLAG_CONSUME_INPUT && SvREADONLY(buf))
1359         croak("Compress::Zlib::Inflate::inflate input parameter cannot be read-only when ConsumeInput is specified");
1360 #ifdef UTF8_AVAILABLE    
1361     if (DO_UTF8(buf) && !sv_utf8_downgrade(buf, 1))
1362          croak("Wide character in Compress::Zlib::Inflate::inflate input parameter");
1363 #endif         
1364     
1365     /* initialise the input buffer */
1366     s->stream.next_in = (Bytef*)SvPVbyte_force(buf, stmp) ;
1367     s->stream.avail_in = SvCUR(buf) ; 
1368         
1369     /* and retrieve the output buffer */
1370     output = deRef_l(output, "inflate") ;
1371 #ifdef UTF8_AVAILABLE    
1372     if (DO_UTF8(output))
1373          out_utf8 = TRUE ;
1374     if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1))
1375          croak("Wide character in Compress::Zlib::Inflate::inflate output parameter");
1376 #endif         
1377     if((s->flags & FLAG_APPEND) != FLAG_APPEND) {
1378         SvCUR_set(output, 0);
1379     }
1380     prefix_length = cur_length =  SvCUR(output) ;
1381     s->stream.next_out = (Bytef*) SvPVbyte_nolen(output) + cur_length;
1382     increment =  SvLEN(output) -  cur_length;
1383     s->stream.avail_out =  increment;
1384     s->bytesInflated = 0;
1385     
1386     while (1) {
1387
1388         if (s->stream.avail_out == 0) {
1389             /* out of space in the output buffer so make it bigger */
1390             s->bufinc *= 2 ;
1391             Sv_Grow(output, SvLEN(output) + s->bufinc + 1) ;
1392             cur_length += increment ;
1393             s->stream.next_out = (Bytef*) SvPVbyte_nolen(output) + cur_length ;
1394             increment = s->bufinc ;
1395             s->stream.avail_out = increment;
1396         }
1397
1398         RETVAL = inflate(&(s->stream), Z_SYNC_FLUSH);
1399
1400
1401         if (RETVAL == Z_BUF_ERROR) {
1402             if (s->stream.avail_out == 0)
1403                 continue ;
1404             if (s->stream.avail_in == 0) {
1405                 RETVAL = Z_OK ;
1406                 break ;
1407             }
1408         }
1409         
1410         if (RETVAL == Z_NEED_DICT && s->dictionary) {
1411             s->dict_adler = s->stream.adler ;
1412             RETVAL = inflateSetDictionary(&(s->stream), 
1413             (const Bytef*)SvPVbyte_nolen(s->dictionary),
1414             SvCUR(s->dictionary));
1415         }
1416
1417         if (RETVAL != Z_OK) 
1418             break;
1419     }
1420
1421     s->last_error = RETVAL ;
1422     if (RETVAL == Z_OK || RETVAL == Z_STREAM_END || RETVAL == Z_DATA_ERROR) {
1423         unsigned in ;
1424
1425         s->bytesInflated = cur_length + increment - s->stream.avail_out - prefix_length;
1426         SvPOK_only(output);
1427         SvCUR_set(output, prefix_length + s->bytesInflated) ;
1428         *SvEND(output) = '\0';
1429 #ifdef UTF8_AVAILABLE    
1430         if (out_utf8)
1431             sv_utf8_upgrade(output);
1432 #endif        
1433
1434         if (s->flags & FLAG_CRC32 )
1435             s->crc32 = crc32(s->crc32, 
1436                                 (const Bytef*)SvPVbyte_nolen(output)+prefix_length, 
1437                                 SvCUR(output)-prefix_length) ;
1438
1439         if (s->flags & FLAG_ADLER32) 
1440             s->adler32 = adler32(s->adler32, 
1441                                 (const Bytef*)SvPVbyte_nolen(output)+prefix_length, 
1442                                 SvCUR(output)-prefix_length) ;
1443
1444         /* fix the input buffer */
1445         if (s->flags & FLAG_CONSUME_INPUT) {
1446             in = s->stream.avail_in ;
1447             SvCUR_set(buf, in) ;
1448             if (in)
1449                 Move(s->stream.next_in, SvPVbyte_nolen(buf), in, char) ;        
1450             *SvEND(buf) = '\0';
1451             SvSETMAGIC(buf);
1452         }
1453     }
1454     OUTPUT:
1455         RETVAL
1456         buf
1457         output
1458
1459 uLong
1460 inflateCount(s)
1461     Compress::Zlib::inflateStream       s
1462     CODE:
1463         RETVAL = s->bytesInflated;
1464   OUTPUT:
1465         RETVAL
1466
1467
1468 DualType 
1469 inflateSync (s, buf)
1470     Compress::Zlib::inflateStream       s
1471     SV *        buf
1472   CODE:
1473   
1474     /* If the buffer is a reference, dereference it */
1475     buf = deRef(buf, "inflateSync") ;
1476 #ifdef UTF8_AVAILABLE    
1477     if (DO_UTF8(buf) && !sv_utf8_downgrade(buf, 1))
1478          croak("Wide character in Compress::Zlib::Inflate::inflateSync");
1479 #endif         
1480     
1481     /* initialise the input buffer */
1482     s->stream.next_in = (Bytef*)SvPVbyte_nolen(buf) ;
1483     s->stream.avail_in = SvCUR(buf) ;
1484         
1485     /* inflateSync doesn't create any output */
1486     s->stream.next_out = (Bytef*) NULL;
1487     s->stream.avail_out = 0;
1488
1489     RETVAL = inflateSync(&(s->stream));
1490     s->last_error = RETVAL ;
1491
1492     /* fix the input buffer */
1493     {
1494         unsigned in = s->stream.avail_in ;
1495         SvCUR_set(buf, in) ;
1496         if (in)
1497             Move(s->stream.next_in, SvPVbyte_nolen(buf), in, char) ;    
1498         *SvEND(buf) = '\0';
1499         SvSETMAGIC(buf);
1500     }
1501     OUTPUT:
1502         RETVAL
1503         buf
1504
1505 void
1506 DESTROY(s)
1507     Compress::Zlib::inflateStream       s
1508   CODE:
1509     inflateEnd(&s->stream) ;
1510     if (s->dictionary)
1511         SvREFCNT_dec(s->dictionary) ;
1512 #ifndef SETP_BYTE
1513     if (s->deflateParams_out_buffer)
1514         Safefree(s->deflateParams_out_buffer);
1515 #endif
1516 #ifdef MAGIC_APPEND
1517     if (s->window)
1518         Safefree(s->window);
1519 #endif
1520     Safefree(s) ;
1521
1522
1523 uLong
1524 status(s)
1525         Compress::Zlib::inflateStream   s
1526     CODE:
1527         RETVAL = s->last_error ;
1528     OUTPUT:
1529         RETVAL
1530
1531 uLong
1532 crc32(s)
1533         Compress::Zlib::inflateStream   s
1534     CODE:
1535         RETVAL = s->crc32 ;
1536     OUTPUT:
1537         RETVAL
1538
1539 uLong
1540 dict_adler(s)
1541         Compress::Zlib::inflateStream   s
1542     CODE:
1543         RETVAL = s->dict_adler ;
1544     OUTPUT:
1545         RETVAL
1546
1547 uLong
1548 total_in(s)
1549         Compress::Zlib::inflateStream   s
1550     CODE:
1551         RETVAL = s->stream.total_in ;
1552     OUTPUT:
1553         RETVAL
1554
1555 uLong
1556 adler32(s)
1557         Compress::Zlib::inflateStream   s
1558     CODE:
1559         RETVAL = s->adler32 ;
1560     OUTPUT:
1561         RETVAL
1562
1563 uLong
1564 total_out(s)
1565         Compress::Zlib::inflateStream   s
1566     CODE:
1567         RETVAL = s->stream.total_out ;
1568     OUTPUT:
1569         RETVAL
1570
1571 char*
1572 msg(s)
1573         Compress::Zlib::inflateStream   s
1574     CODE:
1575         RETVAL = s->stream.msg;
1576     OUTPUT:
1577         RETVAL
1578
1579
1580 uLong
1581 get_Bufsize(s)
1582         Compress::Zlib::inflateStream   s
1583     CODE:
1584         RETVAL = s->bufsize ;
1585     OUTPUT:
1586         RETVAL
1587
1588 bool
1589 set_Append(s, mode)
1590         Compress::Zlib::inflateStream   s
1591         bool    mode
1592     CODE:
1593         RETVAL = ((s->flags & FLAG_APPEND) == FLAG_APPEND);
1594         if (mode)
1595             s->flags |= FLAG_APPEND ;
1596         else
1597             s->flags &= ~FLAG_APPEND ;
1598     OUTPUT:
1599         RETVAL
1600
1601 MODULE = Compress::Zlib PACKAGE = Compress::Zlib::inflateScanStream
1602
1603 void
1604 DESTROY(s)
1605     Compress::Zlib::inflateScanStream   s
1606   CODE:
1607     inflateEnd(&s->stream) ;
1608     if (s->dictionary)
1609         SvREFCNT_dec(s->dictionary) ;
1610 #ifndef SETP_BYTE
1611     if (s->deflateParams_out_buffer)
1612         Safefree(s->deflateParams_out_buffer);
1613 #endif
1614 #ifdef MAGIC_APPEND
1615     if (s->window)
1616         Safefree(s->window);
1617 #endif
1618     Safefree(s) ;
1619
1620 void
1621 DispStream(s, message=NULL)
1622     Compress::Zlib::inflateScanStream   s
1623     char *  message
1624
1625 DualType 
1626 scan(s, buf, out=NULL)
1627     Compress::Zlib::inflateScanStream   s
1628     SV *        buf
1629     SV *        out
1630     int    start_len = NO_INIT
1631     STRLEN  stmp   = NO_INIT
1632   ALIAS:
1633     inflate = 1
1634   CODE:
1635     /* If the input buffer is a reference, dereference it */
1636     ix = ix ; /* warning suppression */
1637 #ifndef MAGIC_APPEND
1638         buf = buf;
1639         croak("scan needs zlib 1.2.1 or better");
1640 #else
1641     buf = deRef(buf, "inflateScan") ;
1642 #ifdef UTF8_AVAILABLE    
1643     if (DO_UTF8(buf) && !sv_utf8_downgrade(buf, 1))
1644         croak("Wide character in Compress::Zlib::InflateScan::scan input parameter");
1645 #endif         
1646     
1647     /* initialise the input buffer */
1648     s->stream.next_in = (Bytef*)SvPVbyte_force(buf, stmp) ;
1649     s->stream.avail_in = SvCUR(buf) ; 
1650     start_len = s->stream.avail_in ;
1651     s->bytesInflated = 0 ; 
1652     do
1653     {
1654         if (s->stream.avail_in == 0) {
1655             RETVAL = Z_OK ;
1656             break ;
1657         }
1658
1659         /* set up output to next available section of sliding window */
1660         s->stream.avail_out = WINDOW_SIZE - s->window_have;
1661         s->stream.next_out = s->window + s->window_have;
1662
1663         /* DispStream(s, "before inflate\n"); */
1664
1665         /* inflate and check for errors */
1666         RETVAL = inflate(&(s->stream), Z_BLOCK);
1667
1668
1669         if (start_len > 1)
1670             s->window_lastByte = *(s->stream.next_in - 1 ) ;
1671
1672         if (RETVAL == Z_STREAM_ERROR || RETVAL == Z_MEM_ERROR ||
1673             RETVAL == Z_DATA_ERROR )
1674             break ;
1675
1676         if (s->flags & FLAG_CRC32 )
1677             s->crc32 = crc32(s->crc32, s->window + s->window_have, 
1678                              WINDOW_SIZE - s->window_have - s->stream.avail_out);
1679
1680         if (s->flags & FLAG_ADLER32) 
1681             s->adler32 = adler32(s->adler32, s->window + s->window_have, 
1682                                  WINDOW_SIZE - s->window_have - s->stream.avail_out);
1683
1684         s->bytesInflated += WINDOW_SIZE - s->window_have - s->stream.avail_out;
1685
1686         if (s->stream.avail_out)
1687             s->window_have = WINDOW_SIZE - s->stream.avail_out;
1688         else {
1689             s->window_have = 0;
1690             s->window_full = 1;
1691         }
1692
1693         /* process end of block */
1694         if (s->stream.data_type & 128) {
1695             if (s->stream.data_type & 64) {
1696                 s->window_left = s->stream.data_type & 0x1f;
1697             }
1698             else {
1699                 s->window_lastbit = s->stream.data_type & 0x1f;
1700                 s->lastBlockOffset = s->stream.total_in;
1701             }
1702         }
1703
1704     } while (RETVAL != Z_STREAM_END);
1705
1706     s->last_error = RETVAL ;
1707     s->window_lastoff = s->stream.total_in ;
1708
1709     if (RETVAL == Z_STREAM_END)
1710     {
1711         s->matchedEndBlock = 1 ;
1712
1713         /* save the location of the end of the compressed data */
1714         s->window_end = SvCUR(buf) - s->stream.avail_in - 1 ;
1715         s->window_endOffset = s->stream.total_in ;
1716         if (s->window_left)
1717         {
1718             -- s->window_endOffset ;
1719         }
1720
1721         /* if window wrapped, build dictionary from window by rotating */
1722         if (s->window_full) {
1723             rotate(s->window, WINDOW_SIZE, s->window_have);
1724             s->window_have = WINDOW_SIZE;
1725         }
1726
1727         /* if (s->flags & FLAG_CONSUME_INPUT) { */
1728         if (1) {
1729             unsigned in = s->stream.avail_in ;
1730             SvCUR_set(buf, in) ;
1731             if (in)
1732                 Move(s->stream.next_in, SvPVbyte_nolen(buf), in, char) ;        
1733                 *SvEND(buf) = '\0';
1734                 SvSETMAGIC(buf);
1735         }
1736     }
1737 #endif
1738   OUTPUT:
1739         RETVAL
1740
1741
1742 uLong
1743 getEndOffset(s)
1744     Compress::Zlib::inflateScanStream   s
1745     CODE:
1746 #ifndef MAGIC_APPEND
1747         croak("getEndOffset needs zlib 1.2.1 or better");
1748 #else
1749         RETVAL = s->window_endOffset;
1750 #endif
1751   OUTPUT:
1752         RETVAL
1753
1754 uLong
1755 inflateCount(s)
1756     Compress::Zlib::inflateScanStream   s
1757     CODE:
1758 #ifndef MAGIC_APPEND
1759         croak("inflateCount needs zlib 1.2.1 or better");
1760 #else
1761         RETVAL = s->bytesInflated;
1762 #endif
1763   OUTPUT:
1764         RETVAL
1765
1766
1767 uLong
1768 getLastBlockOffset(s)
1769     Compress::Zlib::inflateScanStream   s
1770     CODE:
1771 #ifndef MAGIC_APPEND
1772         croak("getLastBlockOffset needs zlib 1.2.1 or better");
1773 #else
1774         RETVAL = s->lastBlockOffset - (s->window_lastbit != 0);
1775 #endif
1776   OUTPUT:
1777         RETVAL
1778
1779 uLong
1780 getLastBufferOffset(s)
1781     Compress::Zlib::inflateScanStream   s
1782     CODE:
1783 #ifndef MAGIC_APPEND
1784         croak("getLastBufferOffset needs zlib 1.2.1 or better");
1785 #else
1786         RETVAL = s->window_lastoff;
1787 #endif
1788   OUTPUT:
1789         RETVAL
1790
1791 void
1792 resetLastBlockByte(s, byte)
1793     Compress::Zlib::inflateScanStream   s
1794     unsigned char*                      byte
1795     CODE:
1796 #ifndef MAGIC_APPEND
1797         croak("resetLastBlockByte needs zlib 1.2.1 or better");
1798 #else
1799         *byte = *byte ^ (1 << ((8 - s->window_lastbit) & 7));
1800 #endif
1801
1802
1803 void
1804 _createDeflateStream(inf_s, flags,level, method, windowBits, memLevel, strategy, bufsize)
1805     Compress::Zlib::inflateScanStream   inf_s
1806     int flags
1807     int level
1808     int method
1809     int windowBits
1810     int memLevel
1811     int strategy
1812     uLong bufsize
1813   PPCODE:
1814   {
1815 #ifndef MAGIC_APPEND
1816         flags = flags;
1817         level = level ;
1818         method = method;
1819         windowBits = windowBits;
1820         memLevel = memLevel;
1821         strategy = strategy;
1822         bufsize= bufsize;
1823         croak("_createDeflateStream needs zlib 1.2.1 or better");
1824 #else
1825     int err ;
1826     deflateStream s ;
1827
1828     if (trace)
1829         warn("in _createDeflateStream(level=%d, method=%d, windowBits=%d, memLevel=%d, strategy=%d, bufsize=%lu\n",
1830         level, method, windowBits, memLevel, strategy, bufsize) ;
1831     if ((s = InitStream() )) {
1832
1833         s->Level      = level;
1834         s->Method     = method;
1835         s->WindowBits = windowBits;
1836         s->MemLevel   = memLevel;
1837         s->Strategy   = strategy;
1838
1839         err = deflateInit2(&(s->stream), level, 
1840                            method, windowBits, memLevel, strategy);
1841
1842         if (err == Z_OK) {
1843             err = deflateSetDictionary(&(s->stream), inf_s->window, inf_s->window_have);
1844             s->dict_adler = s->stream.adler ;
1845         }
1846
1847         if (err != Z_OK) {
1848             Safefree(s) ;
1849             s = NULL ;
1850         }
1851         else {
1852             PostInitStream(s, flags, bufsize, windowBits) ;
1853             s->crc32            = inf_s->crc32;
1854             s->adler32          = inf_s->adler32;
1855             s->stream.adler     = inf_s->stream.adler ;
1856             /* s->stream.total_out = inf_s->bytesInflated ; */
1857             s->stream.total_in  = inf_s->stream.total_out ;
1858             if (inf_s->window_left) {
1859                 /* printf("** window_left %d, window_lastByte %d\n", inf_s->window_left, inf_s->window_lastByte); */
1860                 deflatePrime(&(s->stream), 8 - inf_s->window_left, inf_s->window_lastByte);
1861             }
1862         }
1863     }
1864     else
1865         err = Z_MEM_ERROR ;
1866
1867     XPUSHs(sv_setref_pv(sv_newmortal(), 
1868             "Compress::Zlib::deflateStream", (void*)s));
1869     if (GIMME == G_ARRAY) {
1870         SV * sv = sv_2mortal(newSViv(err)) ;
1871         setDUALstatus(sv, err);
1872         XPUSHs(sv) ;
1873     }
1874 #endif
1875   }
1876
1877 DualType
1878 status(s)
1879         Compress::Zlib::inflateScanStream   s
1880     CODE:
1881         RETVAL = s->last_error ;
1882     OUTPUT:
1883         RETVAL
1884
1885 uLong
1886 crc32(s)
1887         Compress::Zlib::inflateScanStream   s
1888     CODE:
1889         RETVAL = s->crc32 ;
1890     OUTPUT:
1891         RETVAL
1892
1893
1894 uLong
1895 adler32(s)
1896         Compress::Zlib::inflateScanStream   s
1897     CODE:
1898         RETVAL = s->adler32 ;
1899     OUTPUT:
1900         RETVAL
1901