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