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