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