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