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