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