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