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