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