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