Upgrade to Compress::Zlib 1.40
[p5sagit/p5-mst-13.2.git] / ext / Compress / Zlib / Zlib.xs
1 /* Filename: Zlib.xs
2  * Author  : Paul Marquess, <pmqs@cpan.org>
3  * Created : 30 January 2005
4  * Version : 1.40
5  *
6  *   Copyright (c) 1995-2005 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 /* Part of this code is based on the file gzio.c */
13
14 /* gzio.c -- IO on .gz files
15  * Copyright (C) 1995 Jean-loup Gailly.
16  * For conditions of distribution and use, see copyright notice in zlib.h
17  */
18
19
20
21 #include "EXTERN.h"
22 #include "perl.h"
23 #include "XSUB.h"
24
25 #include <zlib.h> 
26
27 #ifndef PERL_VERSION
28 #include "patchlevel.h"
29 #define PERL_REVISION   5
30 #define PERL_VERSION    PATCHLEVEL
31 #define PERL_SUBVERSION SUBVERSION
32 #endif
33
34 #if PERL_REVISION == 5 && (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION <= 75 ))
35
36 #    define PL_sv_undef         sv_undef
37 #    define PL_na               na
38 #    define PL_curcop           curcop
39 #    define PL_compiling        compiling
40
41 #endif
42
43 #ifndef newSVuv
44 #    define newSVuv     newSViv
45 #endif
46
47 typedef struct di_stream {
48     z_stream stream;
49     uLong    bufsize; 
50     uLong    bufinc; 
51     SV *     dictionary ;
52     uLong    dict_adler ;
53     bool     deflateParams_out_valid ;
54     Bytef    deflateParams_out_byte;
55     int      Level;
56     int      Method;
57     int      WindowBits;
58     int      MemLevel;
59     int      Strategy;
60 } di_stream;
61
62 typedef di_stream * deflateStream ;
63 typedef di_stream * Compress__Zlib__deflateStream ;
64 typedef di_stream * inflateStream ;
65 typedef di_stream * Compress__Zlib__inflateStream ;
66
67 /* typedef gzFile Compress__Zlib__gzFile ; */
68 typedef struct gzType {
69     gzFile gz ;
70     SV *   buffer ;
71     uLong   offset ;
72     bool   closed ;
73 }  gzType ;
74
75 typedef gzType* Compress__Zlib__gzFile ; 
76
77
78
79 #define GZERRNO "Compress::Zlib::gzerrno"
80
81 #define ZMALLOC(to, typ) ((to = (typ *)safemalloc(sizeof(typ))), \
82                                 Zero(to,1,typ))
83
84 #define adlerInitial adler32(0L, Z_NULL, 0)
85 #define crcInitial crc32(0L, Z_NULL, 0)
86
87 #if 1
88 static const char * const my_z_errmsg[] = {
89     "need dictionary",     /* Z_NEED_DICT     2 */
90     "stream end",          /* Z_STREAM_END    1 */
91     "",                    /* Z_OK            0 */
92     "file error",          /* Z_ERRNO        (-1) */
93     "stream error",        /* Z_STREAM_ERROR (-2) */
94     "data error",          /* Z_DATA_ERROR   (-3) */
95     "insufficient memory", /* Z_MEM_ERROR    (-4) */
96     "buffer error",        /* Z_BUF_ERROR    (-5) */
97     "incompatible version",/* Z_VERSION_ERROR(-6) */
98     ""};
99 #endif
100
101 #if defined(__SYMBIAN32__)
102 # define NO_WRITEABLE_DATA
103 #endif
104
105 #define TRACE_DEFAULT 0
106
107 #ifdef NO_WRITEABLE_DATA
108 #define trace TRACE_DEFAULT
109 #else
110 static int trace = TRACE_DEFAULT ;
111 #endif
112
113 /* Dodge PerlIO hiding of these functions. */
114 #undef printf
115
116 static void
117 #ifdef CAN_PROTOTYPE
118 SetGzErrorNo(int error_no)
119 #else
120 SetGzErrorNo(error_no)
121 int error_no ;
122 #endif
123 {
124 #ifdef dTHX    
125     dTHX;
126 #endif    
127     char * errstr ;
128     SV * gzerror_sv = perl_get_sv(GZERRNO, FALSE) ;
129   
130     if (error_no == Z_ERRNO) {
131         error_no = errno ;
132         errstr = Strerror(errno) ;
133     }
134     else
135         /* errstr = gzerror(fil, &error_no) ; */
136         errstr = (char*) my_z_errmsg[2 - error_no]; 
137
138     if (SvIV(gzerror_sv) != error_no) {
139         sv_setiv(gzerror_sv, error_no) ;
140         sv_setpv(gzerror_sv, errstr) ;
141         SvIOK_on(gzerror_sv) ;
142     }
143
144 }
145
146 static void
147 #ifdef CAN_PROTOTYPE
148 SetGzError(gzFile file)
149 #else
150 SetGzError(file)
151 gzFile file ;
152 #endif
153 {
154     int error_no ;
155
156     (void)gzerror(file, &error_no) ;
157     SetGzErrorNo(error_no) ;
158 }
159
160 static void
161 #ifdef CAN_PROTOTYPE
162 DispHex(void * ptr, int length)
163 #else
164 DispHex(ptr, length)
165     void * ptr;
166     int length;
167 #endif
168 {
169     char * p = (char*)ptr;
170     int i;
171     for (i = 0; i < length; ++i) {
172         printf(" %02x", 0xFF & *(p+i));
173     }
174 }
175
176
177 static void
178 #ifdef CAN_PROTOTYPE
179 DispStream(di_stream * s, char * message)
180 #else
181 DispStream(s, message)
182     di_stream * s;
183     char * message;
184 #endif
185 {
186
187 #if 0
188     if (! trace)
189         return ;
190 #endif
191
192     printf("DispStream 0x%p - %s \n", s, message) ;
193
194     if (!s)  {
195         printf("    stream pointer is NULL\n");
196     }
197     else     {
198         printf("    stream           0x%p\n", &(s->stream));
199         printf("           zalloc    0x%p\n", s->stream.zalloc);
200         printf("           zfree     0x%p\n", s->stream.zfree);
201         printf("           opaque    0x%p\n", s->stream.opaque);
202         if (s->stream.msg)
203             printf("           msg       %s\n", s->stream.msg);
204         else
205             printf("           msg       \n");
206         printf("           next_in   0x%p", s->stream.next_in);
207         if (s->stream.next_in) {
208             printf(" =>");
209             DispHex(s->stream.next_in, 4);
210         }
211         printf("\n");
212
213         printf("           next_out  0x%p", s->stream.next_out);
214         if (s->stream.next_out){
215             printf(" =>");
216             DispHex(s->stream.next_out, 4);
217         }
218         printf("\n");
219
220         printf("           avail_in  %ld\n", s->stream.avail_in);
221         printf("           avail_out %ld\n", s->stream.avail_out);
222         printf("           total_in  %ld\n", s->stream.total_in);
223         printf("           total_out %ld\n", s->stream.total_out);
224         printf("           adler     0x%lx\n", s->stream.adler);
225         printf("           reserved  0x%lx\n", s->stream.reserved);
226         printf("    bufsize          %ld\n", s->bufsize);
227         printf("    dictionary       0x%p\n", s->dictionary);
228         printf("    dict_adler       0x%ld\n", s->dict_adler);
229         printf("\n");
230
231     }
232 }
233
234
235 static di_stream *
236 #ifdef CAN_PROTOTYPE
237 InitStream(uLong bufsize)
238 #else
239 InitStream(bufsize)
240     uLong bufsize ;
241 #endif
242 {
243     di_stream *s ;
244
245     ZMALLOC(s, di_stream) ;
246
247     if (s)  {
248         s->bufsize = bufsize ;
249         s->bufinc  = bufsize ;
250     }
251
252     return s ;
253     
254 }
255
256 #define SIZE 4096
257
258 static int
259 #ifdef CAN_PROTOTYPE
260 gzreadline(Compress__Zlib__gzFile file, SV * output)
261 #else
262 gzreadline(file, output)
263   Compress__Zlib__gzFile file ;
264   SV * output ;
265 #endif
266 {
267 #ifdef dTHX    
268     dTHX;
269 #endif    
270     SV * store = file->buffer ;
271     char *nl = "\n"; 
272     char *p;
273     char *out_ptr = SvPVX(store) ;
274     int n;
275
276     while (1) {
277
278         /* anything left from last time */
279         if ((n = SvCUR(store))) {
280
281             out_ptr = SvPVX(store) + file->offset ;
282             if ((p = ninstr(out_ptr, out_ptr + n - 1, nl, nl))) {
283             /* if (rschar != 0777 && */
284                 /* p = ninstr(out_ptr, out_ptr + n - 1, rs, rs+rslen-1)) { */
285
286                 sv_catpvn(output, out_ptr, p - out_ptr + 1);
287
288                 file->offset += (p - out_ptr + 1) ;
289                 n = n - (p - out_ptr + 1);
290                 SvCUR_set(store, n) ;
291                 return SvCUR(output);
292             }
293             else /* no EOL, so append the complete buffer */
294                 sv_catpvn(output, out_ptr, n);
295             
296         }
297
298
299         SvCUR_set(store, 0) ;
300         file->offset = 0 ;
301         out_ptr = SvPVX(store) ;
302
303         n = gzread(file->gz, out_ptr, SIZE) ;
304
305         if (n <= 0) 
306             /* Either EOF or an error */
307             /* so return what we have so far else signal eof */
308             return (SvCUR(output)>0) ? SvCUR(output) : n ;
309
310         SvCUR_set(store, n) ;
311     }
312 }
313
314 static SV* 
315 #ifdef CAN_PROTOTYPE
316 deRef(SV * sv, char * string)
317 #else
318 deRef(sv, string)
319 SV * sv ;
320 char * string;
321 #endif
322 {
323 #ifdef dTHX    
324     dTHX;
325 #endif    
326     if (SvROK(sv)) {
327         sv = SvRV(sv) ;
328         switch(SvTYPE(sv)) {
329             case SVt_PVAV:
330             case SVt_PVHV:
331             case SVt_PVCV:
332                 croak("%s: buffer parameter is not a SCALAR reference", string);
333         }
334         if (SvROK(sv))
335             croak("%s: buffer parameter is a reference to a reference", string) ;
336     }
337
338     if (!SvOK(sv)) { 
339         sv = newSVpv("", 0);
340     }   
341     return sv ;
342 }
343
344 #include "constants.h"
345
346 MODULE = Compress::Zlib         PACKAGE = Compress::Zlib        PREFIX = Zip_
347
348 REQUIRE:        1.924
349 PROTOTYPES:     DISABLE
350
351 INCLUDE: constants.xs
352
353 BOOT:
354     /* Check this version of zlib is == 1 */
355     if (zlibVersion()[0] != '1')
356         croak("Compress::Zlib needs zlib version 1.x\n") ;
357         
358     {
359         /* Create the $gzerror scalar */
360         SV * gzerror_sv = perl_get_sv(GZERRNO, GV_ADDMULTI) ;
361         sv_setiv(gzerror_sv, 0) ;
362         sv_setpv(gzerror_sv, "") ;
363         SvIOK_on(gzerror_sv) ;
364     }
365
366
367 #define Zip_zlib_version()      (char*)zlib_version
368 char*
369 Zip_zlib_version()
370
371 unsigned
372 ZLIB_VERNUM()
373     CODE:
374 #ifdef ZLIB_VERNUM
375         RETVAL = ZLIB_VERNUM ;
376 #else
377         /* 1.1.4 => 0x1140 */
378         RETVAL  = (ZLIB_VERSION[0] - '0') << 12 ;
379         RETVAL += (ZLIB_VERSION[2] - '0') <<  8 ;
380         RETVAL += (ZLIB_VERSION[4] - '0') <<  4 ;
381 #endif
382     OUTPUT:
383         RETVAL
384
385     
386
387 void
388 DispStream(s, message=NULL)
389         Compress::Zlib::inflateStream   s
390         char *  message
391
392 Compress::Zlib::gzFile
393 gzopen_(path, mode)
394         char *  path
395         char *  mode
396         CODE:
397         gzFile  gz ;
398         gz = gzopen(path, mode) ;
399         if (gz) {
400             ZMALLOC(RETVAL, gzType) ;
401             RETVAL->buffer = newSV(SIZE) ;
402             SvPOK_only(RETVAL->buffer) ;
403             SvCUR_set(RETVAL->buffer, 0) ; 
404             RETVAL->offset = 0 ;
405             RETVAL->gz = gz ;
406             RETVAL->closed = FALSE ;
407             SetGzErrorNo(0) ;
408         }
409         else {
410             RETVAL = NULL ;
411             SetGzErrorNo(errno ? Z_ERRNO : Z_MEM_ERROR) ;
412         }
413         OUTPUT:
414           RETVAL
415
416
417 Compress::Zlib::gzFile
418 gzdopen_(fh, mode, offset)
419         int     fh
420         char *  mode
421         long    offset
422         CODE:
423         gzFile  gz ;
424         if (offset != -1)
425             lseek(fh, offset, 0) ; 
426         gz = gzdopen(fh, mode) ;
427         if (gz) {
428             ZMALLOC(RETVAL, gzType) ;
429             RETVAL->buffer = newSV(SIZE) ;
430             SvPOK_only(RETVAL->buffer) ;
431             SvCUR_set(RETVAL->buffer, 0) ;
432             RETVAL->offset = 0 ;
433             RETVAL->gz = gz ;
434             RETVAL->closed = FALSE ;
435             SetGzErrorNo(0) ;
436         }
437         else {
438             RETVAL = NULL ;
439             SetGzErrorNo(errno ? Z_ERRNO : Z_MEM_ERROR) ;
440         }
441         OUTPUT:
442           RETVAL
443
444
445 MODULE = Compress::Zlib PACKAGE = Compress::Zlib::gzFile PREFIX = Zip_
446
447 #define Zip_gzread(file, buf, len) gzread(file->gz, bufp, len)
448
449 int
450 Zip_gzread(file, buf, len=4096)
451         Compress::Zlib::gzFile  file
452         unsigned        len
453         SV *            buf
454         voidp           bufp = NO_INIT
455         uLong           bufsize = 0 ;
456         int             RETVAL = 0 ;
457         CODE:
458         if (SvREADONLY(buf) && PL_curcop != &PL_compiling)
459             croak("gzread: buffer parameter is read-only");
460         SvUPGRADE(buf, SVt_PV);
461         SvPOK_only(buf);
462         SvCUR_set(buf, 0);
463         /* any left over from gzreadline ? */
464         if ((bufsize = SvCUR(file->buffer)) > 0) {
465             uLong movesize ;
466         
467             if (bufsize < len) {
468                 movesize = bufsize ;
469                 len -= movesize ;
470             }
471             else {
472                 movesize = len ;
473                 len = 0 ;
474             }
475             RETVAL = movesize ;
476
477             sv_catpvn(buf, SvPVX(file->buffer) + file->offset, movesize);
478
479             file->offset += movesize ;
480             SvCUR_set(file->buffer, bufsize - movesize) ;
481         }
482
483         if (len) {
484             bufp = (Byte*)SvGROW(buf, bufsize+len+1);
485             RETVAL = gzread(file->gz, ((Bytef*)bufp)+bufsize, len) ;
486             SetGzError(file->gz) ; 
487             if (RETVAL >= 0) {
488                 RETVAL += bufsize ;
489                 SvCUR_set(buf, RETVAL) ;
490                 *SvEND(buf) = '\0';
491             }
492         }
493         OUTPUT:
494            RETVAL
495            buf
496
497 int
498 gzreadline(file, buf)
499         Compress::Zlib::gzFile  file
500         SV *            buf
501         int             RETVAL = 0;
502         CODE:
503         if (SvREADONLY(buf) && PL_curcop != &PL_compiling) 
504             croak("gzreadline: buffer parameter is read-only"); 
505         SvUPGRADE(buf, SVt_PV);
506         SvPOK_only(buf);
507         /* sv_setpvn(buf, "", SIZE) ; */
508         SvGROW(buf, SIZE) ;
509         SvCUR_set(buf, 0);
510         RETVAL = gzreadline(file, buf) ;
511         SetGzError(file->gz) ; 
512         OUTPUT:
513           RETVAL
514           buf
515         CLEANUP:
516         if (RETVAL >= 0) {
517             /* SvCUR(buf) = RETVAL; */
518             /* Don't need to explicitly terminate with '\0', because
519                 sv_catpvn aready has */
520         }
521
522 #define Zip_gzwrite(file, buf) gzwrite(file->gz, buf, (unsigned)len)
523 int
524 Zip_gzwrite(file, buf)
525         Compress::Zlib::gzFile  file
526         STRLEN          len = NO_INIT
527         voidp           buf = (voidp)SvPV(ST(1), len) ;
528         CLEANUP:
529           SetGzError(file->gz) ;
530
531 #define Zip_gzflush(file, flush) gzflush(file->gz, flush) 
532 int
533 Zip_gzflush(file, flush)
534         Compress::Zlib::gzFile  file
535         int             flush
536         CLEANUP:
537           SetGzError(file->gz) ;
538
539 #define Zip_gzclose(file) file->closed ? 0 : gzclose(file->gz)
540 int
541 Zip_gzclose(file)
542         Compress::Zlib::gzFile          file
543         CLEANUP:
544           file->closed = TRUE ;
545           SetGzErrorNo(RETVAL) ;
546
547
548 #define Zip_gzeof(file) gzeof(file->gz)
549 int
550 Zip_gzeof(file)
551         Compress::Zlib::gzFile          file
552         CODE:
553 #ifdef OLD_ZLIB
554         croak("gzeof needs zlib 1.0.6 or better") ;
555 #else
556         RETVAL = gzeof(file->gz);
557 #endif
558         OUTPUT:
559             RETVAL
560
561
562 #define Zip_gzsetparams(file,l,s) gzsetparams(file->gz,l,s)
563 int
564 Zip_gzsetparams(file, level, strategy)
565         Compress::Zlib::gzFile          file
566         int             level
567         int             strategy
568         CODE:
569 #ifdef OLD_ZLIB
570         croak("gzsetparams needs zlib 1.0.6 or better") ;
571 #else
572         RETVAL = gzsetparams(file->gz, level, strategy);
573 #endif
574         OUTPUT:
575             RETVAL
576
577 void
578 DESTROY(file)
579         Compress::Zlib::gzFile          file
580         CODE:
581             if (! file->closed)
582                 Zip_gzclose(file) ;
583             SvREFCNT_dec(file->buffer) ;
584             safefree((char*)file) ;
585
586 #define Zip_gzerror(file) (char*)gzerror(file->gz, &errnum)
587
588 char *
589 Zip_gzerror(file)
590         Compress::Zlib::gzFile  file
591         int             errnum = NO_INIT
592         CLEANUP:
593             sv_setiv(ST(0), errnum) ;
594             SvPOK_on(ST(0)) ;
595
596
597
598 MODULE = Compress::Zlib PACKAGE = Compress::Zlib        PREFIX = Zip_
599
600
601 #define Zip_adler32(buf, adler) adler32(adler, buf, (uInt)len)
602
603 uLong
604 Zip_adler32(buf, adler=adlerInitial)
605         uLong    adler = NO_INIT
606         STRLEN   len = NO_INIT
607         Bytef *  buf = NO_INIT
608         SV *     sv = ST(0) ;
609         INIT:
610         /* If the buffer is a reference, dereference it */
611         sv = deRef(sv, "adler32") ;
612         buf = (Byte*)SvPV(sv, len) ;
613
614         if (items < 2)
615           adler = adlerInitial;
616         else if (SvOK(ST(1)))
617           adler = SvUV(ST(1)) ;
618         else
619           adler = adlerInitial;
620  
621 #define Zip_crc32(buf, crc) crc32(crc, buf, (uInt)len)
622
623 uLong
624 Zip_crc32(buf, crc=crcInitial)
625         uLong    crc = NO_INIT
626         STRLEN   len = NO_INIT
627         Bytef *  buf = NO_INIT
628         SV *     sv = ST(0) ;
629         INIT:
630         /* If the buffer is a reference, dereference it */
631         sv = deRef(sv, "crc32") ;
632         buf = (Byte*)SvPV(sv, len) ;
633
634         if (items < 2)
635           crc = crcInitial;
636         else if (SvOK(ST(1)))
637           crc = SvUV(ST(1)) ;
638         else
639           crc = crcInitial;
640
641 MODULE = Compress::Zlib PACKAGE = Compress::Zlib
642
643 void
644 _deflateInit(level, method, windowBits, memLevel, strategy, bufsize, dictionary)
645     int level
646     int method
647     int windowBits
648     int memLevel
649     int strategy
650     uLong bufsize
651     SV * dictionary
652   PPCODE:
653
654     int err ;
655     deflateStream s ;
656
657     if (trace)
658         warn("in _deflateInit(level=%d, method=%d, windowBits=%d, memLevel=%d, strategy=%d, bufsize=%d\n",
659         level, method, windowBits, memLevel, strategy, bufsize) ;
660     if ((s = InitStream(bufsize)) ) {
661
662         s->Level      = level;
663         s->Method     = method;
664         s->WindowBits = windowBits;
665         s->MemLevel   = memLevel;
666         s->Strategy   = strategy;
667
668         err = deflateInit2(&(s->stream), level, 
669                            method, windowBits, memLevel, strategy);
670
671         /* Check if a dictionary has been specified */
672         if (err == Z_OK && SvCUR(dictionary)) {
673             err = deflateSetDictionary(&(s->stream), (const Bytef*) SvPVX(dictionary), 
674                                         SvCUR(dictionary)) ;
675             s->dict_adler = s->stream.adler ;
676         }
677
678         if (err != Z_OK) {
679             Safefree(s) ;
680             s = NULL ;
681         }
682         
683     }
684     else
685         err = Z_MEM_ERROR ;
686
687     XPUSHs(sv_setref_pv(sv_newmortal(), 
688         "Compress::Zlib::deflateStream", (void*)s));
689     if (GIMME == G_ARRAY) 
690         XPUSHs(sv_2mortal(newSViv(err))) ;
691
692 void
693 _inflateInit(windowBits, bufsize, dictionary)
694     int windowBits
695     uLong bufsize
696     SV * dictionary
697   PPCODE:
698  
699     int err = Z_OK ;
700     inflateStream s ;
701  
702     if (trace)
703         warn("in _inflateInit(windowBits=%d, bufsize=%d, dictionary=%d\n",
704                 windowBits, bufsize, SvCUR(dictionary)) ;
705     if ((s = InitStream(bufsize)) ) {
706
707         s->WindowBits = windowBits;
708
709         err = inflateInit2(&(s->stream), windowBits);
710  
711         if (err != Z_OK) {
712             Safefree(s) ;
713             s = NULL ;
714         }
715         else if (SvCUR(dictionary)) {
716             /* Dictionary specified - take a copy for use in inflate */
717             s->dictionary = newSVsv(dictionary) ;
718         }
719     }
720     else
721         err = Z_MEM_ERROR ;
722
723     XPUSHs(sv_setref_pv(sv_newmortal(), 
724                    "Compress::Zlib::inflateStream", (void*)s));
725     if (GIMME == G_ARRAY) 
726         XPUSHs(sv_2mortal(newSViv(err))) ;
727  
728
729
730 MODULE = Compress::Zlib PACKAGE = Compress::Zlib::deflateStream
731
732 void
733 DispStream(s, message=NULL)
734         Compress::Zlib::deflateStream   s
735         char *  message
736
737 void 
738 deflate (s, buf)
739     Compress::Zlib::deflateStream       s
740     SV *        buf
741     uLong       outsize = NO_INIT 
742     SV *        output = NO_INIT
743     int         err = 0;
744   PPCODE:
745   
746     /* If the buffer is a reference, dereference it */
747     buf = deRef(buf, "deflate") ;
748  
749     /* initialise the input buffer */
750     s->stream.next_in = (Bytef*)SvPV(buf, *(STRLEN*)&s->stream.avail_in) ;
751     /* s->stream.next_in = (Bytef*)SvPVX(buf); */
752     s->stream.avail_in = SvCUR(buf) ;
753
754     /* and the output buffer */
755     /* output = sv_2mortal(newSVpv("", s->bufinc)) ; */
756     output = sv_2mortal(newSV(s->bufinc)) ;
757     SvPOK_only(output) ;
758     SvCUR_set(output, 0) ; 
759     outsize = s->bufinc ;
760     s->stream.next_out = (Bytef*) SvPVX(output) ;
761     s->stream.avail_out = outsize;
762
763     /* Check for saved output from deflateParams */
764     if (s->deflateParams_out_valid) {
765         *(s->stream.next_out) = s->deflateParams_out_byte;
766         ++ s->stream.next_out;
767         -- s->stream.avail_out ;
768         s->deflateParams_out_valid = FALSE;
769     }
770
771     while (s->stream.avail_in != 0) {
772
773         if (s->stream.avail_out == 0) {
774             s->bufinc *= 2 ;
775             SvGROW(output, outsize + s->bufinc) ;
776             s->stream.next_out = (Bytef*) SvPVX(output) + outsize ;
777             outsize += s->bufinc ;
778             s->stream.avail_out = s->bufinc ;
779         }
780         err = deflate(&(s->stream), Z_NO_FLUSH);
781         if (err != Z_OK) 
782             break;
783     }
784
785     if (err == Z_OK) {
786         SvPOK_only(output);
787         SvCUR_set(output, outsize - s->stream.avail_out) ;
788     }
789     else
790         output = &PL_sv_undef ;
791     XPUSHs(output) ;
792     if (GIMME == G_ARRAY) 
793         XPUSHs(sv_2mortal(newSViv(err))) ;
794   
795
796
797 void
798 flush(s, f=Z_FINISH)
799     Compress::Zlib::deflateStream       s
800     int f
801     uLong       outsize = NO_INIT
802     SV * output = NO_INIT
803     int err = Z_OK ;
804   PPCODE:
805   
806     s->stream.avail_in = 0; /* should be zero already anyway */
807   
808     /* output = sv_2mortal(newSVpv("", s->bufinc)) ; */
809     output = sv_2mortal(newSV(s->bufinc)) ;
810     SvPOK_only(output) ;
811     SvCUR_set(output, 0) ; 
812     outsize = s->bufinc ;
813     s->stream.next_out = (Bytef*) SvPVX(output) ;
814     s->stream.avail_out = outsize;
815       
816     /* Check for saved output from deflateParams */
817     if (s->deflateParams_out_valid) {
818         *(s->stream.next_out) = s->deflateParams_out_byte;
819         ++ s->stream.next_out;
820         -- s->stream.avail_out ;
821         s->deflateParams_out_valid = FALSE;
822     }
823
824     for (;;) {
825         if (s->stream.avail_out == 0) {
826             /* consumed all the available output, so extend it */
827             s->bufinc *= 2 ;
828             SvGROW(output, outsize + s->bufinc) ;
829             s->stream.next_out = (Bytef*)SvPVX(output) + outsize ;
830             outsize += s->bufinc ;
831             s->stream.avail_out = s->bufinc ;
832         }
833         err = deflate(&(s->stream), f);
834     
835         /* deflate has finished flushing only when it hasn't used up
836          * all the available space in the output buffer: 
837          */
838         if (s->stream.avail_out != 0 || err != Z_OK )
839             break;
840     }
841   
842     err =  (err == Z_STREAM_END ? Z_OK : err) ;
843   
844     if (err == Z_OK) {
845         SvPOK_only(output);
846         SvCUR_set(output, outsize - s->stream.avail_out) ;
847     }
848     else
849         output = &PL_sv_undef ;
850     XPUSHs(output) ;
851     if (GIMME == G_ARRAY) 
852         XPUSHs(sv_2mortal(newSViv(err))) ;
853
854 int
855 _deflateParams(s, flags, level, strategy, bufsize)
856         Compress::Zlib::deflateStream   s
857         int     flags
858         int     level
859         int     strategy
860         uLong   bufsize
861     CODE:
862         if (flags & 1)
863             s->Level = level ;
864         if (flags & 2)
865             s->Strategy = strategy ;
866         if (bufsize) {
867             s->bufsize = bufsize; 
868             s->bufinc  = bufsize; 
869         }
870         s->stream.avail_in = 0; 
871         s->stream.next_out = &(s->deflateParams_out_byte) ;
872         s->stream.avail_out = 1;
873         RETVAL = deflateParams(&(s->stream), s->Level, s->Strategy);
874         s->deflateParams_out_valid = 
875                 (RETVAL == Z_OK && s->stream.avail_out == 0) ;
876     OUTPUT:
877         RETVAL
878
879
880 int
881 get_Level(s)
882         Compress::Zlib::deflateStream   s
883     CODE:
884         RETVAL = s->Level ;
885     OUTPUT:
886         RETVAL
887
888 int
889 get_Strategy(s)
890         Compress::Zlib::deflateStream   s
891     CODE:
892         RETVAL = s->Strategy ;
893     OUTPUT:
894         RETVAL
895
896 void
897 DESTROY(s)
898     Compress::Zlib::deflateStream       s
899   CODE:
900     deflateEnd(&s->stream) ;
901     if (s->dictionary)
902         SvREFCNT_dec(s->dictionary) ;
903     Safefree(s) ;
904
905
906 uLong
907 dict_adler(s)
908         Compress::Zlib::deflateStream   s
909     CODE:
910         RETVAL = s->dict_adler ;
911     OUTPUT:
912         RETVAL
913
914 uLong
915 total_in(s)
916         Compress::Zlib::deflateStream   s
917     CODE:
918         RETVAL = s->stream.total_in ;
919     OUTPUT:
920         RETVAL
921
922 uLong
923 total_out(s)
924         Compress::Zlib::deflateStream   s
925     CODE:
926         RETVAL = s->stream.total_out ;
927     OUTPUT:
928         RETVAL
929
930 char*
931 msg(s)
932         Compress::Zlib::deflateStream   s
933     CODE:
934         RETVAL = s->stream.msg;
935     OUTPUT:
936         RETVAL
937
938
939 MODULE = Compress::Zlib PACKAGE = Compress::Zlib::inflateStream
940
941 void
942 DispStream(s, message=NULL)
943         Compress::Zlib::inflateStream   s
944         char *  message
945
946 void 
947 inflate (s, buf)
948     Compress::Zlib::inflateStream       s
949     SV *        buf
950     uLong       outsize = NO_INIT 
951     SV *        output = NO_INIT
952     int         err = Z_OK ;
953   ALIAS:
954     __unc_inflate = 1
955   PPCODE:
956   
957     /* If the buffer is a reference, dereference it */
958     buf = deRef(buf, "inflate") ;
959     
960     /* initialise the input buffer */
961     s->stream.next_in = (Bytef*)SvPVX(buf) ;
962     s->stream.avail_in = SvCUR(buf) ;
963         
964     /* and the output buffer */
965     output = sv_2mortal(newSV(s->bufinc+1)) ;
966     SvPOK_only(output) ;
967     SvCUR_set(output, 0) ; 
968     outsize = s->bufinc ;
969     s->stream.next_out = (Bytef*) SvPVX(output)  ;
970     s->stream.avail_out = outsize;
971
972     while (1) {
973
974         if (s->stream.avail_out == 0) {
975             s->bufinc *= 2 ;
976             SvGROW(output, outsize + s->bufinc+1) ;
977             s->stream.next_out = (Bytef*) SvPVX(output) + outsize ;
978             outsize += s->bufinc ;
979             s->stream.avail_out = s->bufinc ;
980         }
981
982         err = inflate(&(s->stream), Z_SYNC_FLUSH);
983         if (err == Z_BUF_ERROR) {
984             if (s->stream.avail_out == 0)
985                 continue ;
986             if (s->stream.avail_in == 0) {
987                 err = Z_OK ;
988                 break ;
989             }
990         }
991
992         if (err == Z_NEED_DICT && s->dictionary) {
993             s->dict_adler = s->stream.adler ;
994             err = inflateSetDictionary(&(s->stream), 
995                                         (const Bytef*)SvPVX(s->dictionary),
996                                         SvCUR(s->dictionary));
997         }
998        
999         if (err != Z_OK) 
1000             break;
1001     }
1002
1003     if (err == Z_OK || err == Z_STREAM_END || err == Z_DATA_ERROR) {
1004         unsigned in ;
1005         
1006         SvPOK_only(output);
1007         SvCUR_set(output, outsize - s->stream.avail_out) ;
1008         *SvEND(output) = '\0';
1009         
1010         /* fix the input buffer */
1011         if (ix == 0) {
1012             in = s->stream.avail_in ;
1013             SvCUR_set(buf, in) ;
1014             if (in)
1015                 Move(s->stream.next_in, SvPVX(buf), in, char) ; 
1016             *SvEND(buf) = '\0';
1017             SvSETMAGIC(buf);
1018         }
1019     }
1020     else
1021         output = &PL_sv_undef ;
1022     XPUSHs(output) ;
1023     if (GIMME == G_ARRAY) 
1024         XPUSHs(sv_2mortal(newSViv(err))) ;
1025
1026 int 
1027 inflateSync (s, buf)
1028     Compress::Zlib::inflateStream       s
1029     SV *        buf
1030   CODE:
1031   
1032     /* If the buffer is a reference, dereference it */
1033     buf = deRef(buf, "inflateSync") ;
1034     
1035     /* initialise the input buffer */
1036     s->stream.next_in = (Bytef*)SvPVX(buf) ;
1037     s->stream.avail_in = SvCUR(buf) ;
1038         
1039     /* inflateSync doesn't create any output */
1040     s->stream.next_out = (Bytef*) NULL;
1041     s->stream.avail_out = 0;
1042
1043     RETVAL = inflateSync(&(s->stream));
1044     {
1045         /* fix the input buffer */
1046         unsigned in = s->stream.avail_in ;
1047         
1048         SvCUR_set(buf, in) ;
1049         if (in)
1050             Move(s->stream.next_in, SvPVX(buf), in, char) ;     
1051         *SvEND(buf) = '\0';
1052         SvSETMAGIC(buf);
1053     }
1054     OUTPUT:
1055         RETVAL
1056
1057 void
1058 DESTROY(s)
1059     Compress::Zlib::inflateStream       s
1060   CODE:
1061     inflateEnd(&s->stream) ;
1062     if (s->dictionary)
1063         SvREFCNT_dec(s->dictionary) ;
1064     Safefree(s) ;
1065
1066
1067 uLong
1068 dict_adler(s)
1069         Compress::Zlib::inflateStream   s
1070     CODE:
1071         RETVAL = s->dict_adler ;
1072     OUTPUT:
1073         RETVAL
1074
1075 uLong
1076 total_in(s)
1077         Compress::Zlib::inflateStream   s
1078     CODE:
1079         RETVAL = s->stream.total_in ;
1080     OUTPUT:
1081         RETVAL
1082
1083 uLong
1084 total_out(s)
1085         Compress::Zlib::inflateStream   s
1086     CODE:
1087         RETVAL = s->stream.total_out ;
1088     OUTPUT:
1089         RETVAL
1090
1091 char*
1092 msg(s)
1093         Compress::Zlib::inflateStream   s
1094     CODE:
1095         RETVAL = s->stream.msg;
1096     OUTPUT:
1097         RETVAL
1098
1099