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