This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
utf8.pm: Slight clarification in pod
[perl5.git] / cpan / Compress-Raw-Bzip2 / Bzip2.xs
1 /* Filename: Bzip2.xs
2  * Author  : Paul Marquess, <pmqs@cpan.org>
3  * Created : 5th October 2005
4  * Version : 2.000
5  *
6  *   Copyright (c) 2005-2010 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 #define PERL_NO_GET_CONTEXT
13 #include "EXTERN.h"
14 #include "perl.h"
15 #include "XSUB.h"
16
17 #include "bzlib.h" 
18
19 #ifdef USE_PPPORT_H
20 #  define NEED_sv_2pv_nolen
21 #  include "ppport.h" 
22 #endif
23
24 #if PERL_REVISION == 5 && (PERL_VERSION < 8 || (PERL_VERSION == 8 && PERL_SUBVERSION < 4 ))
25
26 #    ifdef SvPVbyte_force
27 #        undef SvPVbyte_force
28 #    endif
29
30 #    define SvPVbyte_force(sv,lp) SvPV_force(sv,lp)
31
32 #endif
33
34 #ifndef SvPVbyte_nolen
35 #    define SvPVbyte_nolen SvPV_nolen
36 #endif
37
38
39 #if PERL_REVISION == 5 && (PERL_VERSION >= 8 || (PERL_VERSION == 8 && PERL_SUBVERSION < 4 ))
40 #    define UTF8_AVAILABLE
41 #endif
42
43 typedef int                     DualType ;
44 typedef int                     int_undef ;
45
46 typedef unsigned long           uLong;
47 typedef unsigned int            uInt;
48
49 typedef struct di_stream {
50     int      flags ;
51 #define FLAG_APPEND_OUTPUT      1
52 #define FLAG_CONSUME_INPUT      8
53 #define FLAG_LIMIT_OUTPUT       16
54     bz_stream stream;
55     uInt     bufsize; 
56     int      last_error ;
57     uLong    bytesInflated ;
58     uLong    compressedBytes ;
59     uLong    uncompressedBytes ;
60     
61 } di_stream;
62
63 typedef di_stream * deflateStream ;
64 typedef di_stream * Compress__Raw__Bzip2 ;
65
66 typedef di_stream * inflateStream ;
67 typedef di_stream * Compress__Raw__Bunzip2 ;
68
69 #define COMPRESS_CLASS    "Compress::Raw::Bzip2"
70 #define UNCOMPRESS_CLASS  "Compress::Raw::Bunzip2"
71
72 #define ZMALLOC(to, typ) ((to = (typ *)safemalloc(sizeof(typ))), \
73                                 Zero(to,1,typ))
74
75
76 /* static const char * const my_z_errmsg[] = { */
77 static const char my_z_errmsg[][32] = {
78     "End of Stream",        /* BZ_STREAM_END        4       */
79     "Finish OK",            /* BZ_FINISH_OK         3       */
80     "Flush OK",             /* BZ_FLUSH_OK          2       */
81     "Run OK",               /* BZ_RUN_OK            1       */
82     "",                     /* BZ_OK                0       */
83     "Sequence Error",       /* BZ_SEQUENCE_ERROR    (-1)    */
84     "Param Error",          /* BZ_PARAM_ERROR       (-2)    */
85     "Memory Error",         /* BZ_MEM_ERROR         (-3)    */
86     "Data Error",           /* BZ_DATA_ERROR        (-4)    */
87     "Magic Error",          /* BZ_DATA_ERROR_MAGIC  (-5)    */
88     "IO Error",             /* BZ_IO_ERROR          (-6)    */
89     "Unexpected EOF",       /* BZ_UNEXPECTED_EOF    (-7)    */
90     "Output Buffer Full",   /* BZ_OUTBUFF_FULL      (-8)    */
91     "Config Error",         /* BZ_CONFIG_ERROR      (-9)    */
92     ""};
93
94 #define setDUALstatus(var, err)                                         \
95                 sv_setnv(var, (double)err) ;                            \
96                 sv_setpv(var, ((err) ? GetErrorString(err) : "")) ;     \
97                 SvNOK_on(var);
98
99    
100 #if defined(__SYMBIAN32__)
101 # define NO_WRITEABLE_DATA
102 #endif
103
104 #define TRACE_DEFAULT 0
105
106 #ifdef NO_WRITEABLE_DATA
107 #  define trace TRACE_DEFAULT
108 #else
109   static int trace = TRACE_DEFAULT ;
110 #endif
111
112 /* Dodge PerlIO hiding of these functions. */
113 #undef printf
114
115 #if 1
116 #define getInnerObject(x) (*av_fetch((AV*)SvRV(x), 0, FALSE))
117 #else
118 #define getInnerObject(x) ((SV*)SvRV(sv))
119 #endif
120
121 #ifdef BZ_NO_STDIO
122 void bz_internal_error(int errorcode)
123 {
124     croak("bz_internal_error %d\n", errorcode);
125 }
126 #endif
127
128 static char *
129 #ifdef CAN_PROTOTYPE
130 GetErrorString(int error_no)
131 #else
132 GetErrorString(error_no)
133 int error_no ;
134 #endif
135 {
136     dTHX;
137     char * errstr ;
138   
139 #if 0
140     if (error_no == BZ_ERRNO) {
141         errstr = Strerror(errno) ;
142     }
143     else
144 #endif
145         errstr = (char*) my_z_errmsg[4 - error_no]; 
146
147     return errstr ;
148 }
149
150 static void
151 #ifdef CAN_PROTOTYPE
152 DispHex(void * ptr, int length)
153 #else
154 DispHex(ptr, length)
155     void * ptr;
156     int length;
157 #endif
158 {
159     char * p = (char*)ptr;
160     int i;
161     for (i = 0; i < length; ++i) {
162         printf(" %02x", 0xFF & *(p+i));
163     }
164 }
165
166
167 static void
168 #ifdef CAN_PROTOTYPE
169 DispStream(di_stream * s, const char * message)
170 #else
171 DispStream(s, message)
172     di_stream * s;
173     const char * message;
174 #endif
175 {
176
177 #if 0
178     if (! trace)
179         return ;
180 #endif
181
182 #define EnDis(f) (s->flags & f ? "Enabled" : "Disabled")
183
184     printf("DispStream 0x%p", s) ;
185     if (message)
186         printf(" - %s \n", message) ;
187     printf("\n") ;
188
189     if (!s)  {
190         printf("    stream pointer is NULL\n");
191     }
192     else     {
193         printf("    stream           0x%p\n", &(s->stream));
194         printf("           opaque    0x%p\n", s->stream.opaque);
195         printf("           state     0x%p\n", s->stream.state );
196         printf("           next_in   0x%p", s->stream.next_in);
197         if (s->stream.next_in){
198             printf(" =>");
199             DispHex(s->stream.next_in, 4);
200         }
201         printf("\n");
202
203         printf("           next_out  0x%p", s->stream.next_out);
204         if (s->stream.next_out){
205             printf(" =>");
206             DispHex(s->stream.next_out, 4);
207         }
208         printf("\n");
209
210         printf("           avail_in  %lu\n",  (unsigned long)s->stream.avail_in);
211         printf("           avail_out %lu\n",  (unsigned long)s->stream.avail_out);
212         printf("    bufsize          %lu\n",  (unsigned long)s->bufsize);
213         printf("      total_in_lo32  %u\n",  s->stream.total_in_lo32);
214         printf("      total_in_hi32  %u\n",  s->stream.total_in_hi32);
215         printf("      total_out_lo32 %u\n",  s->stream.total_out_lo32);
216         printf("      total_out_hi32 %u\n",  s->stream.total_out_hi32);
217         printf("    flags            0x%x\n", s->flags);
218         printf("           APPEND    %s\n",   EnDis(FLAG_APPEND_OUTPUT));
219         printf("           CONSUME   %s\n",   EnDis(FLAG_CONSUME_INPUT));
220         printf("           LIMIT     %s\n",   EnDis(FLAG_LIMIT_OUTPUT));
221
222         printf("\n");
223
224     }
225 }
226
227 static di_stream *
228 #ifdef CAN_PROTOTYPE
229 InitStream(void)
230 #else
231 InitStream()
232 #endif
233 {
234     di_stream *s ;
235
236     ZMALLOC(s, di_stream) ;
237
238     return s ;
239     
240 }
241
242 static void
243 #ifdef CAN_PROTOTYPE
244 PostInitStream(di_stream * s, int flags)
245 #else
246 PostInitStream(s, flags)
247     di_stream *s ;
248     int flags ;
249 #endif
250 {
251     s->bufsize  = 1024 * 16 ;
252     s->last_error = 0 ;
253     s->flags    = flags ;
254 }
255
256
257 static SV* 
258 #ifdef CAN_PROTOTYPE
259 deRef(SV * sv, const char * string)
260 #else
261 deRef(sv, string)
262 SV * sv ;
263 char * string;
264 #endif
265 {
266     dTHX;
267     SvGETMAGIC(sv);
268
269     if (SvROK(sv)) {
270         sv = SvRV(sv) ;
271         SvGETMAGIC(sv);
272         switch(SvTYPE(sv)) {
273             case SVt_PVAV:
274             case SVt_PVHV:
275             case SVt_PVCV:
276                 croak("%s: buffer parameter is not a SCALAR reference", string);
277             default:
278                 break;
279         }
280         if (SvROK(sv))
281             croak("%s: buffer parameter is a reference to a reference", string) ;
282     }
283
284     if (!SvOK(sv))
285         sv = sv_2mortal(newSVpv("", 0));
286
287     return sv ;
288 }
289
290 static SV*
291 #ifdef CAN_PROTOTYPE
292 deRef_l(SV * sv, const char * string)
293 #else
294 deRef_l(sv, string)
295 SV * sv ;
296 char * string ;
297 #endif
298 {
299     dTHX;
300     bool wipe = 0 ;
301     STRLEN na;
302     
303     SvGETMAGIC(sv);
304     wipe = ! SvOK(sv) ;
305
306     if (SvROK(sv)) {
307         sv = SvRV(sv) ;
308         SvGETMAGIC(sv);
309         wipe = ! SvOK(sv) ;
310
311         switch(SvTYPE(sv)) {
312             case SVt_PVAV:
313             case SVt_PVHV:
314             case SVt_PVCV:
315                 croak("%s: buffer parameter is not a SCALAR reference", string);
316             default:
317                 break;
318         }
319         if (SvROK(sv))
320             croak("%s: buffer parameter is a reference to a reference", string) ;
321     }
322
323     if (SvREADONLY(sv) && PL_curcop != &PL_compiling)
324         croak("%s: buffer parameter is read-only", string);
325
326     SvUPGRADE(sv, SVt_PV);
327
328     if (wipe)
329         sv_setpv(sv, "") ;
330     else
331         (void)SvPVbyte_force(sv, na) ;
332
333     return sv ;
334 }
335
336
337 #include "constants.h"
338
339 MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2        PREFIX = Zip_
340
341 REQUIRE:        1.924
342 PROTOTYPES:     DISABLE
343
344 INCLUDE: constants.xs
345
346 BOOT:
347 #ifndef NO_WRITEABLE_DATA
348   trace = TRACE_DEFAULT ;
349 #endif
350     /* Check this version of bzip2 is == 1 */
351     if (BZ2_bzlibVersion()[0] != '1')
352         croak(COMPRESS_CLASS " needs bzip2 version 1.x, you have %s\n", BZ2_bzlibVersion()) ;
353         
354
355 MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2
356
357 #define bzlibversion() BZ2_bzlibVersion()
358 const char *
359 bzlibversion()
360
361 void
362 new(className, appendOut=1, blockSize100k=1, workfactor=0, verbosity=0)
363     const char * className
364     int appendOut
365     int blockSize100k
366     int workfactor
367     int verbosity
368   PPCODE:
369   {
370     int err ;
371     deflateStream s ;
372 #if 0
373     /* if (trace) */
374         warn("in Compress::Raw::Bzip2::_new(items=%d,appendOut=%d, blockSize100k=%d, workfactor=%d, verbosity=%d\n",
375         items, appendOut, blockSize100k, workfactor, verbosity);
376 #endif
377     if ((s = InitStream() )) {
378
379         err = BZ2_bzCompressInit ( &(s->stream), 
380                                      blockSize100k, 
381                                      verbosity,
382                                      workfactor );
383
384         if (err != BZ_OK) {
385             Safefree(s) ;
386             s = NULL ;
387         }
388         else {
389             int flags = 0 ;
390             if (appendOut)
391                 flags |= FLAG_APPEND_OUTPUT;
392             PostInitStream(s, appendOut ? FLAG_APPEND_OUTPUT :0) ;
393         }
394     }
395     else
396         err = BZ_MEM_ERROR ;
397
398     {
399         SV* obj = sv_setref_pv(sv_newmortal(), className, (void*)s);
400         XPUSHs(obj);
401     }
402     if(0)
403     {
404         SV* obj = sv_2mortal(newSViv(PTR2IV(s))) ;
405         XPUSHs(obj);
406     }
407     if (GIMME == G_ARRAY) {
408         SV * sv = sv_2mortal(newSViv(err)) ;
409         setDUALstatus(sv, err);
410         XPUSHs(sv) ;
411     }
412   }
413
414 MODULE = Compress::Raw::Bunzip2 PACKAGE = Compress::Raw::Bunzip2
415
416 void
417 new(className, appendOut=1 , consume=1, small=0, verbosity=0, limitOutput=0)
418     const char* className
419     int appendOut
420     int consume
421     int small
422     int verbosity
423     int limitOutput
424   PPCODE:
425   {
426     int err = BZ_OK ;
427     inflateStream s ;
428 #if 0
429     if (trace)
430         warn("in _inflateInit(windowBits=%d, bufsize=%lu, dictionary=%lu\n",
431                 windowBits, bufsize, (unsigned long)SvCUR(dictionary)) ;
432 #endif
433     if ((s = InitStream() )) {
434
435         err = BZ2_bzDecompressInit (&(s->stream), verbosity, small);
436         if (err != BZ_OK) {
437             Safefree(s) ;
438             s = NULL ;
439         }
440         if (s) {
441             int flags = 0;
442             if (appendOut)
443                 flags |= FLAG_APPEND_OUTPUT;
444             if (consume)
445                 flags |= FLAG_CONSUME_INPUT;
446             if (limitOutput)
447                 flags |= (FLAG_LIMIT_OUTPUT|FLAG_CONSUME_INPUT);
448             PostInitStream(s, flags) ;
449         }
450     }
451     else
452         err = BZ_MEM_ERROR ;
453
454     {
455         SV* obj = sv_setref_pv(sv_newmortal(), className, (void*)s);
456         XPUSHs(obj);
457     }
458        if (0)
459     {
460         SV* obj = sv_2mortal(newSViv(PTR2IV(s))) ;
461         XPUSHs(obj);
462     }
463     if (GIMME == G_ARRAY) {
464         SV * sv = sv_2mortal(newSViv(err)) ;
465         setDUALstatus(sv, err);
466         XPUSHs(sv) ;
467     }
468   }
469  
470
471
472 MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2
473
474 void
475 DispStream(s, message=NULL)
476     Compress::Raw::Bzip2   s
477     const char *  message
478
479 DualType 
480 bzdeflate (s, buf, output)
481     Compress::Raw::Bzip2        s
482     SV *        buf
483     SV *        output 
484     uInt        cur_length = NO_INIT
485     uInt        increment = NO_INIT
486     int         RETVAL = 0;
487     uInt   bufinc = NO_INIT
488   CODE:
489     bufinc = s->bufsize;
490
491     /* If the input buffer is a reference, dereference it */
492     buf = deRef(buf, "deflate") ;
493  
494     /* initialise the input buffer */
495 #ifdef UTF8_AVAILABLE    
496     if (DO_UTF8(buf) && !sv_utf8_downgrade(buf, 1))
497          croak("Wide character in " COMPRESS_CLASS "::bzdeflate input parameter");
498 #endif         
499     s->stream.next_in = (char*)SvPV_nomg_nolen(buf) ;
500     s->stream.avail_in = SvCUR(buf) ;
501      
502     /* and retrieve the output buffer */
503     output = deRef_l(output, "deflate") ;
504 #ifdef UTF8_AVAILABLE    
505     if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1))
506          croak("Wide character in " COMPRESS_CLASS "::bzdeflate output parameter");
507 #endif         
508
509     if((s->flags & FLAG_APPEND_OUTPUT) != FLAG_APPEND_OUTPUT) {
510         SvCUR_set(output, 0);
511         /* sv_setpvn(output, "", 0); */
512     }
513     cur_length =  SvCUR(output) ;
514     s->stream.next_out = (char*) SvPVX(output) + cur_length;
515     increment =  SvLEN(output) -  cur_length;
516     s->stream.avail_out =  increment;
517     while (s->stream.avail_in != 0) {
518
519         if (s->stream.avail_out == 0) {
520             /* out of space in the output buffer so make it bigger */
521             s->stream.next_out = Sv_Grow(output, SvLEN(output) + bufinc) ;
522             cur_length += increment ;
523             s->stream.next_out += cur_length ;
524             increment = bufinc ;
525             s->stream.avail_out = increment;
526             bufinc *= 2 ;
527         }
528
529         RETVAL = BZ2_bzCompress(&(s->stream), BZ_RUN);
530         if (RETVAL != BZ_RUN_OK) 
531             break;
532     }
533
534     s->compressedBytes    += cur_length + increment - s->stream.avail_out ;
535     s->uncompressedBytes  += SvCUR(buf) - s->stream.avail_in  ;
536
537     s->last_error = RETVAL ;
538     if (RETVAL == BZ_RUN_OK) {
539         SvPOK_only(output);
540         SvCUR_set(output, cur_length + increment - s->stream.avail_out) ;
541         SvSETMAGIC(output);
542     }
543     OUTPUT:
544         RETVAL
545   
546
547 void
548 DESTROY(s)
549     Compress::Raw::Bzip2        s
550   CODE:
551     BZ2_bzCompressEnd(&s->stream) ;
552     Safefree(s) ;
553
554
555 DualType
556 bzclose(s, output)
557     Compress::Raw::Bzip2        s
558     SV * output 
559     uInt        cur_length = NO_INIT
560     uInt        increment = NO_INIT
561     uInt    bufinc = NO_INIT
562   CODE:
563     bufinc = s->bufsize;
564   
565     s->stream.avail_in = 0; /* should be zero already anyway */
566   
567     /* retrieve the output buffer */
568     output = deRef_l(output, "close") ;
569 #ifdef UTF8_AVAILABLE    
570     if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1))
571          croak("Wide character in " COMPRESS_CLASS "::bzclose input parameter");
572 #endif         
573     if(! s->flags & FLAG_APPEND_OUTPUT) {
574         SvCUR_set(output, 0);
575         /* sv_setpvn(output, "", 0); */
576     }
577     cur_length =  SvCUR(output) ;
578     s->stream.next_out = (char*) SvPVX(output) + cur_length;
579     increment =  SvLEN(output) -  cur_length;
580     s->stream.avail_out =  increment;
581
582     for (;;) {
583         if (s->stream.avail_out == 0) {
584             /* consumed all the available output, so extend it */
585             s->stream.next_out = Sv_Grow(output, SvLEN(output) + bufinc) ;
586             cur_length += increment ;
587             s->stream.next_out += cur_length ;
588             increment = bufinc ;
589             s->stream.avail_out = increment;
590             bufinc *= 2 ;
591         }
592         RETVAL = BZ2_bzCompress(&(s->stream), BZ_FINISH);
593     
594         /* deflate has finished flushing only when it hasn't used up
595          * all the available space in the output buffer: 
596          */
597         /* if (s->stream.avail_out != 0 || RETVAL < 0 ) */
598         if (RETVAL == BZ_STREAM_END || RETVAL < 0 )
599             break;
600     }
601   
602     /* RETVAL =  (RETVAL == BZ_STREAM_END ? BZ_OK : RETVAL) ; */
603     s->last_error = RETVAL ;
604
605     s->compressedBytes    += cur_length + increment - s->stream.avail_out ;
606   
607     if (RETVAL == BZ_STREAM_END) {
608         SvPOK_only(output);
609         SvCUR_set(output, cur_length + increment - s->stream.avail_out) ;
610         SvSETMAGIC(output);
611     }
612     OUTPUT:
613         RETVAL
614
615
616 DualType
617 bzflush(s, output)
618     Compress::Raw::Bzip2        s
619     SV * output 
620     uInt        cur_length = NO_INIT
621     uInt        increment = NO_INIT
622     uInt    bufinc = NO_INIT
623   CODE:
624     bufinc = s->bufsize;
625   
626     s->stream.avail_in = 0; /* should be zero already anyway */
627   
628     /* retrieve the output buffer */
629     output = deRef_l(output, "close") ;
630 #ifdef UTF8_AVAILABLE    
631     if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1))
632          croak("Wide character in " COMPRESS_CLASS "::bzflush input parameter");
633 #endif         
634     if(! s->flags & FLAG_APPEND_OUTPUT) {
635         SvCUR_set(output, 0);
636         /* sv_setpvn(output, "", 0); */
637     }
638     cur_length =  SvCUR(output) ;
639     s->stream.next_out = (char*) SvPVX(output) + cur_length;
640     increment =  SvLEN(output) -  cur_length;
641     s->stream.avail_out =  increment;
642
643     for (;;) {
644         if (s->stream.avail_out == 0) {
645             /* consumed all the available output, so extend it */
646             s->stream.next_out = Sv_Grow(output, SvLEN(output) + bufinc) ;
647             cur_length += increment ;
648             s->stream.next_out += cur_length ;
649             increment = bufinc ;
650             s->stream.avail_out = increment;
651             bufinc *= 2 ;
652         }
653         RETVAL = BZ2_bzCompress(&(s->stream), BZ_FLUSH);
654     
655         if (RETVAL == BZ_RUN_OK || RETVAL < 0)
656                 break;
657
658         /* deflate has finished flushing only when it hasn't used up
659          * all the available space in the output buffer: 
660          */
661         /* RETVAL == if (s->stream.avail_out != 0 || RETVAL < 0 )
662             break; */
663     }
664   
665     /* RETVAL =  (RETVAL == BZ_STREAM_END ? BZ_OK : RETVAL) ; */
666     s->last_error = RETVAL ;
667
668     s->compressedBytes    += cur_length + increment - s->stream.avail_out ;
669   
670     if (RETVAL == BZ_RUN_OK) {
671         SvPOK_only(output);
672         SvCUR_set(output, cur_length + increment - s->stream.avail_out) ;
673         SvSETMAGIC(output);
674     }
675     OUTPUT:
676         RETVAL
677
678 uLong
679 total_in_lo32(s)
680         Compress::Raw::Bzip2   s
681     CODE:
682         RETVAL = s->stream.total_in_lo32 ;
683     OUTPUT:
684         RETVAL
685
686 uLong
687 total_out_lo32(s)
688         Compress::Raw::Bzip2   s
689     CODE:
690         RETVAL = s->stream.total_out_lo32 ;
691     OUTPUT:
692         RETVAL
693
694 uLong
695 compressedBytes(s)
696         Compress::Raw::Bzip2   s
697     CODE:
698         RETVAL = s->compressedBytes;
699   OUTPUT:
700         RETVAL
701
702 uLong
703 uncompressedBytes(s)
704         Compress::Raw::Bzip2   s
705     CODE:
706         RETVAL = s->uncompressedBytes;
707   OUTPUT:
708         RETVAL
709
710         
711 MODULE = Compress::Raw::Bunzip2 PACKAGE = Compress::Raw::Bunzip2
712
713 void
714 DispStream(s, message=NULL)
715     Compress::Raw::Bunzip2   s
716     const char *  message
717
718 DualType 
719 bzinflate (s, buf, output)
720     Compress::Raw::Bunzip2      s
721     SV *        buf
722     SV *        output 
723     uInt        cur_length = 0;
724     uInt        prefix_length = 0;
725     uInt        increment = 0;
726     uInt    bufinc = NO_INIT
727     STRLEN  na = NO_INIT ;
728   PREINIT:
729 #ifdef UTF8_AVAILABLE    
730     bool        out_utf8  = FALSE;
731 #endif    
732   CODE:
733     bufinc = s->bufsize;
734     /* If the buffer is a reference, dereference it */
735     buf = deRef(buf, "bzinflate") ;
736
737     if (s->flags & FLAG_CONSUME_INPUT) {
738         if (SvREADONLY(buf))
739             croak(UNCOMPRESS_CLASS "::bzinflate input parameter cannot be read-only when ConsumeInput is specified");
740         SvPV_force(buf, na);
741     }
742 #ifdef UTF8_AVAILABLE    
743     if (DO_UTF8(buf) && !sv_utf8_downgrade(buf, 1))
744          croak("Wide character in " UNCOMPRESS_CLASS "::bzinflate input parameter");
745 #endif         
746     
747     /* initialise the input buffer */
748     s->stream.next_in = (char*)SvPV_nomg_nolen(buf) ;
749     s->stream.avail_in = SvCUR(buf);
750         
751     /* and retrieve the output buffer */
752     output = deRef_l(output, "bzinflate") ;
753 #ifdef UTF8_AVAILABLE    
754     if (DO_UTF8(output))
755          out_utf8 = TRUE ;
756     if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1))
757          croak("Wide character in " UNCOMPRESS_CLASS "::bzinflate output parameter");
758 #endif         
759     if((s->flags & FLAG_APPEND_OUTPUT) != FLAG_APPEND_OUTPUT) {
760         SvCUR_set(output, 0);
761     }
762
763     /* Assume no output buffer - the code below will update if there is any available */
764     s->stream.avail_out = 0;
765
766     if (SvLEN(output)) {
767         prefix_length = cur_length =  SvCUR(output) ;
768     
769         if (s->flags & FLAG_LIMIT_OUTPUT && SvLEN(output) - cur_length - 1 < bufinc)
770         {
771             Sv_Grow(output, bufinc + cur_length + 1) ;
772         }
773     
774         /* Only setup the stream output pointers if there is spare 
775            capacity in the outout SV
776         */
777         if (SvLEN(output) > cur_length + 1)
778         {
779             s->stream.next_out = (char*) SvPVX(output) + cur_length;
780             increment = SvLEN(output) -  cur_length - 1;
781             s->stream.avail_out = increment;
782         }
783     }
784
785     s->bytesInflated = 0;
786     
787     RETVAL = BZ_OK;
788     
789     while (1) {
790
791         if (s->stream.avail_out == 0) {
792             /* out of space in the output buffer so make it bigger */
793             s->stream.next_out = Sv_Grow(output, SvLEN(output) + bufinc + 1) ;
794             cur_length += increment ;
795             s->stream.next_out += cur_length ;
796             increment = bufinc ;
797             s->stream.avail_out = increment;
798             bufinc *= 2 ;
799         }
800
801         /* DispStream(s, "pre"); */
802         RETVAL = BZ2_bzDecompress (&(s->stream));
803
804         /* 
805         printf("Status %d\n", RETVAL);
806         DispStream(s, "apres"); 
807         */ 
808         if (RETVAL != BZ_OK || s->flags & FLAG_LIMIT_OUTPUT) 
809             break ;
810
811         if (s->stream.avail_out == 0)
812             continue ;
813
814         if (s->stream.avail_in == 0) {
815             RETVAL = BZ_OK ;
816             break ;
817         }
818         
819     }
820     
821     s->last_error = RETVAL ;
822     if (RETVAL == BZ_OK || RETVAL == BZ_STREAM_END) {
823         unsigned in ;
824
825         s->bytesInflated = cur_length + increment - s->stream.avail_out - prefix_length;
826         s->uncompressedBytes += s->bytesInflated ;
827         s->compressedBytes   += SvCUR(buf) - s->stream.avail_in  ;
828
829         SvPOK_only(output);
830         SvCUR_set(output, prefix_length + s->bytesInflated) ;
831         *SvEND(output) = '\0';
832 #ifdef UTF8_AVAILABLE    
833         if (out_utf8)
834             sv_utf8_upgrade(output);
835 #endif        
836         SvSETMAGIC(output);
837
838         /* fix the input buffer */
839         if (s->flags & FLAG_CONSUME_INPUT) {
840             in = s->stream.avail_in ;
841             SvCUR_set(buf, in) ;
842             if (in)
843                 Move(s->stream.next_in, SvPVX(buf), in, char) ; 
844             *SvEND(buf) = '\0';
845             SvSETMAGIC(buf);
846         }
847     }
848     OUTPUT:
849         RETVAL
850
851 uLong
852 inflateCount(s)
853     Compress::Raw::Bunzip2      s
854     CODE:
855         RETVAL = s->bytesInflated;
856   OUTPUT:
857         RETVAL
858
859
860 void
861 DESTROY(s)
862     Compress::Raw::Bunzip2      s
863   CODE:
864     BZ2_bzDecompressEnd(&s->stream) ;
865     Safefree(s) ;
866
867
868 uLong
869 status(s)
870         Compress::Raw::Bunzip2   s
871     CODE:
872         RETVAL = s->last_error ;
873     OUTPUT:
874         RETVAL
875
876 uLong
877 total_in_lo32(s)
878         Compress::Raw::Bunzip2   s
879     CODE:
880         RETVAL = s->stream.total_in_lo32 ;
881     OUTPUT:
882         RETVAL
883
884 uLong
885 total_out_lo32(s)
886         Compress::Raw::Bunzip2   s
887     CODE:
888         RETVAL = s->stream.total_out_lo32 ;
889     OUTPUT:
890         RETVAL
891
892 uLong
893 compressedBytes(s)
894         Compress::Raw::Bunzip2   s
895     CODE:
896         RETVAL = s->compressedBytes;
897   OUTPUT:
898         RETVAL
899
900 uLong
901 uncompressedBytes(s)
902         Compress::Raw::Bunzip2   s
903     CODE:
904         RETVAL = s->uncompressedBytes;
905   OUTPUT:
906         RETVAL
907
908 MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2        PREFIX = Zip_