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