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