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