c6fd54df4e3802dc9a20470264fe47080cd4ce6d
[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.35
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 unsigned
352 ZLIB_VERNUM()
353     CODE:
354 #ifdef ZLIB_VERNUM
355         RETVAL = ZLIB_VERNUM ;
356 #else
357         /* 1.1.4 => 0x1140 */
358         RETVAL  = (ZLIB_VERSION[0] - '0') << 12 ;
359         RETVAL += (ZLIB_VERSION[2] - '0') <<  8 ;
360         RETVAL += (ZLIB_VERSION[4] - '0') <<  4 ;
361 #endif
362     OUTPUT:
363         RETVAL
364
365     
366
367 void
368 DispStream(s, message=NULL)
369         Compress::Zlib::inflateStream   s
370         char *  message
371
372 Compress::Zlib::gzFile
373 gzopen_(path, mode)
374         char *  path
375         char *  mode
376         CODE:
377         gzFile  gz ;
378         gz = gzopen(path, mode) ;
379         if (gz) {
380             ZMALLOC(RETVAL, gzType) ;
381             RETVAL->buffer = newSV(SIZE) ;
382             SvPOK_only(RETVAL->buffer) ;
383             SvCUR_set(RETVAL->buffer, 0) ; 
384             RETVAL->offset = 0 ;
385             RETVAL->gz = gz ;
386             RETVAL->closed = FALSE ;
387             SetGzErrorNo(0) ;
388         }
389         else {
390             RETVAL = NULL ;
391             SetGzErrorNo(errno ? Z_ERRNO : Z_MEM_ERROR) ;
392         }
393         OUTPUT:
394           RETVAL
395
396
397 Compress::Zlib::gzFile
398 gzdopen_(fh, mode, offset)
399         int     fh
400         char *  mode
401         long    offset
402         CODE:
403         gzFile  gz ;
404         if (offset != -1)
405             lseek(fh, offset, 0) ; 
406         gz = gzdopen(fh, mode) ;
407         if (gz) {
408             ZMALLOC(RETVAL, gzType) ;
409             RETVAL->buffer = newSV(SIZE) ;
410             SvPOK_only(RETVAL->buffer) ;
411             SvCUR_set(RETVAL->buffer, 0) ;
412             RETVAL->offset = 0 ;
413             RETVAL->gz = gz ;
414             RETVAL->closed = FALSE ;
415             SetGzErrorNo(0) ;
416         }
417         else {
418             RETVAL = NULL ;
419             SetGzErrorNo(errno ? Z_ERRNO : Z_MEM_ERROR) ;
420         }
421         OUTPUT:
422           RETVAL
423
424
425 MODULE = Compress::Zlib PACKAGE = Compress::Zlib::gzFile PREFIX = Zip_
426
427 #define Zip_gzread(file, buf, len) gzread(file->gz, bufp, len)
428
429 int
430 Zip_gzread(file, buf, len=4096)
431         Compress::Zlib::gzFile  file
432         unsigned        len
433         SV *            buf
434         voidp           bufp = NO_INIT
435         uLong           bufsize = 0 ;
436         int             RETVAL = 0 ;
437         CODE:
438         if (SvREADONLY(buf) && PL_curcop != &PL_compiling)
439             croak("gzread: buffer parameter is read-only");
440         SvUPGRADE(buf, SVt_PV);
441         SvPOK_only(buf);
442         SvCUR_set(buf, 0);
443         /* any left over from gzreadline ? */
444         if ((bufsize = SvCUR(file->buffer)) > 0) {
445             uLong movesize ;
446         
447             if (bufsize < len) {
448                 movesize = bufsize ;
449                 len -= movesize ;
450             }
451             else {
452                 movesize = len ;
453                 len = 0 ;
454             }
455             RETVAL = movesize ;
456
457             sv_catpvn(buf, SvPVX(file->buffer) + file->offset, movesize);
458
459             file->offset += movesize ;
460             SvCUR_set(file->buffer, bufsize - movesize) ;
461         }
462
463         if (len) {
464             bufp = (Byte*)SvGROW(buf, bufsize+len+1);
465             RETVAL = gzread(file->gz, ((Bytef*)bufp)+bufsize, len) ;
466             SetGzError(file->gz) ; 
467             if (RETVAL >= 0) {
468                 RETVAL += bufsize ;
469                 SvCUR_set(buf, RETVAL) ;
470                 *SvEND(buf) = '\0';
471             }
472         }
473         OUTPUT:
474            RETVAL
475            buf
476
477 int
478 gzreadline(file, buf)
479         Compress::Zlib::gzFile  file
480         SV *            buf
481         int             RETVAL = 0;
482         CODE:
483         if (SvREADONLY(buf) && PL_curcop != &PL_compiling) 
484             croak("gzreadline: buffer parameter is read-only"); 
485         SvUPGRADE(buf, SVt_PV);
486         SvPOK_only(buf);
487         /* sv_setpvn(buf, "", SIZE) ; */
488         SvGROW(buf, SIZE) ;
489         SvCUR_set(buf, 0);
490         RETVAL = gzreadline(file, buf) ;
491         SetGzError(file->gz) ; 
492         OUTPUT:
493           RETVAL
494           buf
495         CLEANUP:
496         if (RETVAL >= 0) {
497             /* SvCUR(buf) = RETVAL; */
498             /* Don't need to explicitly terminate with '\0', because
499                 sv_catpvn aready has */
500         }
501
502 #define Zip_gzwrite(file, buf) gzwrite(file->gz, buf, (unsigned)len)
503 int
504 Zip_gzwrite(file, buf)
505         Compress::Zlib::gzFile  file
506         STRLEN          len = NO_INIT
507         voidp           buf = (voidp)SvPV(ST(1), len) ;
508         CLEANUP:
509           SetGzError(file->gz) ;
510
511 #define Zip_gzflush(file, flush) gzflush(file->gz, flush) 
512 int
513 Zip_gzflush(file, flush)
514         Compress::Zlib::gzFile  file
515         int             flush
516         CLEANUP:
517           SetGzError(file->gz) ;
518
519 #define Zip_gzclose(file) file->closed ? 0 : gzclose(file->gz)
520 int
521 Zip_gzclose(file)
522         Compress::Zlib::gzFile          file
523         CLEANUP:
524           file->closed = TRUE ;
525           SetGzErrorNo(RETVAL) ;
526
527
528 #define Zip_gzeof(file) gzeof(file->gz)
529 int
530 Zip_gzeof(file)
531         Compress::Zlib::gzFile          file
532         CODE:
533 #ifdef OLD_ZLIB
534         croak("gzeof needs zlib 1.0.6 or better") ;
535 #else
536         RETVAL = gzeof(file->gz);
537 #endif
538         OUTPUT:
539             RETVAL
540
541
542 #define Zip_gzsetparams(file,l,s) gzsetparams(file->gz,l,s)
543 int
544 Zip_gzsetparams(file, level, strategy)
545         Compress::Zlib::gzFile          file
546         int             level
547         int             strategy
548         CODE:
549 #ifdef OLD_ZLIB
550         croak("gzsetparams needs zlib 1.0.6 or better") ;
551 #else
552         RETVAL = gzsetparams(file->gz, level, strategy);
553 #endif
554         OUTPUT:
555             RETVAL
556
557 void
558 DESTROY(file)
559         Compress::Zlib::gzFile          file
560         CODE:
561             if (! file->closed)
562                 Zip_gzclose(file) ;
563             SvREFCNT_dec(file->buffer) ;
564             safefree((char*)file) ;
565
566 #define Zip_gzerror(file) (char*)gzerror(file->gz, &errnum)
567
568 char *
569 Zip_gzerror(file)
570         Compress::Zlib::gzFile  file
571         int             errnum = NO_INIT
572         CLEANUP:
573             sv_setiv(ST(0), errnum) ;
574             SvPOK_on(ST(0)) ;
575
576
577
578 MODULE = Compress::Zlib PACKAGE = Compress::Zlib        PREFIX = Zip_
579
580
581 #define Zip_adler32(buf, adler) adler32(adler, buf, (uInt)len)
582
583 uLong
584 Zip_adler32(buf, adler=adlerInitial)
585         uLong    adler = NO_INIT
586         STRLEN   len = NO_INIT
587         Bytef *  buf = NO_INIT
588         SV *     sv = ST(0) ;
589         INIT:
590         /* If the buffer is a reference, dereference it */
591         sv = deRef(sv, "adler32") ;
592         buf = (Byte*)SvPV(sv, len) ;
593
594         if (items < 2)
595           adler = adlerInitial;
596         else if (SvOK(ST(1)))
597           adler = SvUV(ST(1)) ;
598         else
599           adler = adlerInitial;
600  
601 #define Zip_crc32(buf, crc) crc32(crc, buf, (uInt)len)
602
603 uLong
604 Zip_crc32(buf, crc=crcInitial)
605         uLong    crc = 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, "crc32") ;
612         buf = (Byte*)SvPV(sv, len) ;
613
614         if (items < 2)
615           crc = crcInitial;
616         else if (SvOK(ST(1)))
617           crc = SvUV(ST(1)) ;
618         else
619           crc = crcInitial;
620
621 MODULE = Compress::Zlib PACKAGE = Compress::Zlib
622
623 void
624 _deflateInit(level, method, windowBits, memLevel, strategy, bufsize, dictionary)
625     int level
626     int method
627     int windowBits
628     int memLevel
629     int strategy
630     uLong bufsize
631     SV * dictionary
632   PPCODE:
633
634     int err ;
635     deflateStream s ;
636
637     if (trace)
638         warn("in _deflateInit(level=%d, method=%d, windowBits=%d, memLevel=%d, strategy=%d, bufsize=%d\n",
639         level, method, windowBits, memLevel, strategy, bufsize) ;
640     if ((s = InitStream(bufsize)) ) {
641
642         s->Level      = level;
643         s->Method     = method;
644         s->WindowBits = windowBits;
645         s->MemLevel   = memLevel;
646         s->Strategy   = strategy;
647
648         err = deflateInit2(&(s->stream), level, 
649                            method, windowBits, memLevel, strategy);
650
651         /* Check if a dictionary has been specified */
652         if (err == Z_OK && SvCUR(dictionary)) {
653             err = deflateSetDictionary(&(s->stream), (const Bytef*) SvPVX(dictionary), 
654                                         SvCUR(dictionary)) ;
655             s->dict_adler = s->stream.adler ;
656         }
657
658         if (err != Z_OK) {
659             Safefree(s) ;
660             s = NULL ;
661         }
662         
663     }
664     else
665         err = Z_MEM_ERROR ;
666
667     XPUSHs(sv_setref_pv(sv_newmortal(), 
668         "Compress::Zlib::deflateStream", (void*)s));
669     if (GIMME == G_ARRAY) 
670         XPUSHs(sv_2mortal(newSViv(err))) ;
671
672 void
673 _inflateInit(windowBits, bufsize, dictionary)
674     int windowBits
675     uLong bufsize
676     SV * dictionary
677   PPCODE:
678  
679     int err = Z_OK ;
680     inflateStream s ;
681  
682     if (trace)
683         warn("in _inflateInit(windowBits=%d, bufsize=%d, dictionary=%d\n",
684                 windowBits, bufsize, SvCUR(dictionary)) ;
685     if ((s = InitStream(bufsize)) ) {
686
687         s->WindowBits = windowBits;
688
689         err = inflateInit2(&(s->stream), windowBits);
690  
691         if (err != Z_OK) {
692             Safefree(s) ;
693             s = NULL ;
694         }
695         else if (SvCUR(dictionary)) {
696             /* Dictionary specified - take a copy for use in inflate */
697             s->dictionary = newSVsv(dictionary) ;
698         }
699     }
700     else
701         err = Z_MEM_ERROR ;
702
703     XPUSHs(sv_setref_pv(sv_newmortal(), 
704                    "Compress::Zlib::inflateStream", (void*)s));
705     if (GIMME == G_ARRAY) 
706         XPUSHs(sv_2mortal(newSViv(err))) ;
707  
708
709
710 MODULE = Compress::Zlib PACKAGE = Compress::Zlib::deflateStream
711
712 void
713 DispStream(s, message=NULL)
714         Compress::Zlib::deflateStream   s
715         char *  message
716
717 void 
718 deflate (s, buf)
719     Compress::Zlib::deflateStream       s
720     SV *        buf
721     uLong       outsize = NO_INIT 
722     SV *        output = NO_INIT
723     int         err = 0;
724   PPCODE:
725   
726     /* If the buffer is a reference, dereference it */
727     buf = deRef(buf, "deflate") ;
728  
729     /* initialise the input buffer */
730     s->stream.next_in = (Bytef*)SvPV(buf, *(STRLEN*)&s->stream.avail_in) ;
731     /* s->stream.next_in = (Bytef*)SvPVX(buf); */
732     s->stream.avail_in = SvCUR(buf) ;
733
734     /* and the output buffer */
735     /* output = sv_2mortal(newSVpv("", s->bufinc)) ; */
736     output = sv_2mortal(newSV(s->bufinc)) ;
737     SvPOK_only(output) ;
738     SvCUR_set(output, 0) ; 
739     outsize = s->bufinc ;
740     s->stream.next_out = (Bytef*) SvPVX(output) ;
741     s->stream.avail_out = outsize;
742
743     /* Check for saved output from deflateParams */
744     if (s->deflateParams_out_valid) {
745         *(s->stream.next_out) = s->deflateParams_out_byte;
746         ++ s->stream.next_out;
747         -- s->stream.avail_out ;
748         s->deflateParams_out_valid = FALSE;
749     }
750
751     while (s->stream.avail_in != 0) {
752
753         if (s->stream.avail_out == 0) {
754             s->bufinc *= 2 ;
755             SvGROW(output, outsize + s->bufinc) ;
756             s->stream.next_out = (Bytef*) SvPVX(output) + outsize ;
757             outsize += s->bufinc ;
758             s->stream.avail_out = s->bufinc ;
759         }
760         err = deflate(&(s->stream), Z_NO_FLUSH);
761         if (err != Z_OK) 
762             break;
763     }
764
765     if (err == Z_OK) {
766         SvPOK_only(output);
767         SvCUR_set(output, outsize - s->stream.avail_out) ;
768     }
769     else
770         output = &PL_sv_undef ;
771     XPUSHs(output) ;
772     if (GIMME == G_ARRAY) 
773         XPUSHs(sv_2mortal(newSViv(err))) ;
774   
775
776
777 void
778 flush(s, f=Z_FINISH)
779     Compress::Zlib::deflateStream       s
780     int f
781     uLong       outsize = NO_INIT
782     SV * output = NO_INIT
783     int err = Z_OK ;
784   PPCODE:
785   
786     s->stream.avail_in = 0; /* should be zero already anyway */
787   
788     /* output = sv_2mortal(newSVpv("", s->bufinc)) ; */
789     output = sv_2mortal(newSV(s->bufinc)) ;
790     SvPOK_only(output) ;
791     SvCUR_set(output, 0) ; 
792     outsize = s->bufinc ;
793     s->stream.next_out = (Bytef*) SvPVX(output) ;
794     s->stream.avail_out = outsize;
795       
796     /* Check for saved output from deflateParams */
797     if (s->deflateParams_out_valid) {
798         *(s->stream.next_out) = s->deflateParams_out_byte;
799         ++ s->stream.next_out;
800         -- s->stream.avail_out ;
801         s->deflateParams_out_valid = FALSE;
802     }
803
804     for (;;) {
805         if (s->stream.avail_out == 0) {
806             /* consumed all the available output, so extend it */
807             s->bufinc *= 2 ;
808             SvGROW(output, outsize + s->bufinc) ;
809             s->stream.next_out = (Bytef*)SvPVX(output) + outsize ;
810             outsize += s->bufinc ;
811             s->stream.avail_out = s->bufinc ;
812         }
813         err = deflate(&(s->stream), f);
814     
815         /* deflate has finished flushing only when it hasn't used up
816          * all the available space in the output buffer: 
817          */
818         if (s->stream.avail_out != 0 || err != Z_OK )
819             break;
820     }
821   
822     err =  (err == Z_STREAM_END ? Z_OK : err) ;
823   
824     if (err == Z_OK) {
825         SvPOK_only(output);
826         SvCUR_set(output, outsize - s->stream.avail_out) ;
827     }
828     else
829         output = &PL_sv_undef ;
830     XPUSHs(output) ;
831     if (GIMME == G_ARRAY) 
832         XPUSHs(sv_2mortal(newSViv(err))) ;
833
834 int
835 _deflateParams(s, flags, level, strategy, bufsize)
836         Compress::Zlib::deflateStream   s
837         int     flags
838         int     level
839         int     strategy
840         uLong   bufsize
841     CODE:
842         if (flags & 1)
843             s->Level = level ;
844         if (flags & 2)
845             s->Strategy = strategy ;
846         if (bufsize) {
847             s->bufsize = bufsize; 
848             s->bufinc  = bufsize; 
849         }
850         s->stream.avail_in = 0; 
851         s->stream.next_out = &(s->deflateParams_out_byte) ;
852         s->stream.avail_out = 1;
853         RETVAL = deflateParams(&(s->stream), s->Level, s->Strategy);
854         s->deflateParams_out_valid = 
855                 (RETVAL == Z_OK && s->stream.avail_out == 0) ;
856     OUTPUT:
857         RETVAL
858
859
860 int
861 get_Level(s)
862         Compress::Zlib::deflateStream   s
863     CODE:
864         RETVAL = s->Level ;
865     OUTPUT:
866         RETVAL
867
868 int
869 get_Strategy(s)
870         Compress::Zlib::deflateStream   s
871     CODE:
872         RETVAL = s->Strategy ;
873     OUTPUT:
874         RETVAL
875
876 void
877 DESTROY(s)
878     Compress::Zlib::deflateStream       s
879   CODE:
880     deflateEnd(&s->stream) ;
881     if (s->dictionary)
882         SvREFCNT_dec(s->dictionary) ;
883     Safefree(s) ;
884
885
886 uLong
887 dict_adler(s)
888         Compress::Zlib::deflateStream   s
889     CODE:
890         RETVAL = s->dict_adler ;
891     OUTPUT:
892         RETVAL
893
894 uLong
895 total_in(s)
896         Compress::Zlib::deflateStream   s
897     CODE:
898         RETVAL = s->stream.total_in ;
899     OUTPUT:
900         RETVAL
901
902 uLong
903 total_out(s)
904         Compress::Zlib::deflateStream   s
905     CODE:
906         RETVAL = s->stream.total_out ;
907     OUTPUT:
908         RETVAL
909
910 char*
911 msg(s)
912         Compress::Zlib::deflateStream   s
913     CODE:
914         RETVAL = s->stream.msg;
915     OUTPUT:
916         RETVAL
917
918
919 MODULE = Compress::Zlib PACKAGE = Compress::Zlib::inflateStream
920
921 void
922 DispStream(s, message=NULL)
923         Compress::Zlib::inflateStream   s
924         char *  message
925
926 void 
927 inflate (s, buf)
928     Compress::Zlib::inflateStream       s
929     SV *        buf
930     uLong       outsize = NO_INIT 
931     SV *        output = NO_INIT
932     int         err = Z_OK ;
933   ALIAS:
934     __unc_inflate = 1
935   PPCODE:
936   
937     /* If the buffer is a reference, dereference it */
938     buf = deRef(buf, "inflate") ;
939     
940     /* initialise the input buffer */
941     s->stream.next_in = (Bytef*)SvPVX(buf) ;
942     s->stream.avail_in = SvCUR(buf) ;
943         
944     /* and the output buffer */
945     output = sv_2mortal(newSV(s->bufinc+1)) ;
946     SvPOK_only(output) ;
947     SvCUR_set(output, 0) ; 
948     outsize = s->bufinc ;
949     s->stream.next_out = (Bytef*) SvPVX(output)  ;
950     s->stream.avail_out = outsize;
951
952     while (1) {
953
954         if (s->stream.avail_out == 0) {
955             s->bufinc *= 2 ;
956             SvGROW(output, outsize + s->bufinc+1) ;
957             s->stream.next_out = (Bytef*) SvPVX(output) + outsize ;
958             outsize += s->bufinc ;
959             s->stream.avail_out = s->bufinc ;
960         }
961
962         err = inflate(&(s->stream), Z_SYNC_FLUSH);
963         if (err == Z_BUF_ERROR) {
964             if (s->stream.avail_out == 0)
965                 continue ;
966             if (s->stream.avail_in == 0) {
967                 err = Z_OK ;
968                 break ;
969             }
970         }
971
972         if (err == Z_NEED_DICT && s->dictionary) {
973             s->dict_adler = s->stream.adler ;
974             err = inflateSetDictionary(&(s->stream), 
975                                         (const Bytef*)SvPVX(s->dictionary),
976                                         SvCUR(s->dictionary));
977         }
978        
979         if (err != Z_OK) 
980             break;
981     }
982
983     if (err == Z_OK || err == Z_STREAM_END || err == Z_DATA_ERROR) {
984         unsigned in ;
985         
986         SvPOK_only(output);
987         SvCUR_set(output, outsize - s->stream.avail_out) ;
988         *SvEND(output) = '\0';
989         
990         /* fix the input buffer */
991         if (ix == 0) {
992             in = s->stream.avail_in ;
993             SvCUR_set(buf, in) ;
994             if (in)
995                 Move(s->stream.next_in, SvPVX(buf), in, char) ; 
996             *SvEND(buf) = '\0';
997             SvSETMAGIC(buf);
998         }
999     }
1000     else
1001         output = &PL_sv_undef ;
1002     XPUSHs(output) ;
1003     if (GIMME == G_ARRAY) 
1004         XPUSHs(sv_2mortal(newSViv(err))) ;
1005
1006 int 
1007 inflateSync (s, buf)
1008     Compress::Zlib::inflateStream       s
1009     SV *        buf
1010   CODE:
1011   
1012     /* If the buffer is a reference, dereference it */
1013     buf = deRef(buf, "inflateSync") ;
1014     
1015     /* initialise the input buffer */
1016     s->stream.next_in = (Bytef*)SvPVX(buf) ;
1017     s->stream.avail_in = SvCUR(buf) ;
1018         
1019     /* inflateSync doesn't create any output */
1020     s->stream.next_out = (Bytef*) NULL;
1021     s->stream.avail_out = 0;
1022
1023     RETVAL = inflateSync(&(s->stream));
1024     {
1025         /* fix the input buffer */
1026         unsigned in = s->stream.avail_in ;
1027         
1028         SvCUR_set(buf, in) ;
1029         if (in)
1030             Move(s->stream.next_in, SvPVX(buf), in, char) ;     
1031         *SvEND(buf) = '\0';
1032         SvSETMAGIC(buf);
1033     }
1034     OUTPUT:
1035         RETVAL
1036
1037 void
1038 DESTROY(s)
1039     Compress::Zlib::inflateStream       s
1040   CODE:
1041     inflateEnd(&s->stream) ;
1042     if (s->dictionary)
1043         SvREFCNT_dec(s->dictionary) ;
1044     Safefree(s) ;
1045
1046
1047 uLong
1048 dict_adler(s)
1049         Compress::Zlib::inflateStream   s
1050     CODE:
1051         RETVAL = s->dict_adler ;
1052     OUTPUT:
1053         RETVAL
1054
1055 uLong
1056 total_in(s)
1057         Compress::Zlib::inflateStream   s
1058     CODE:
1059         RETVAL = s->stream.total_in ;
1060     OUTPUT:
1061         RETVAL
1062
1063 uLong
1064 total_out(s)
1065         Compress::Zlib::inflateStream   s
1066     CODE:
1067         RETVAL = s->stream.total_out ;
1068     OUTPUT:
1069         RETVAL
1070
1071 char*
1072 msg(s)
1073         Compress::Zlib::inflateStream   s
1074     CODE:
1075         RETVAL = s->stream.msg;
1076     OUTPUT:
1077         RETVAL
1078
1079