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