This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Clarify that =encoding is global in POD
[perl5.git] / ext / Compress-Raw-Bzip2 / Bzip2.xs
CommitLineData
bdb7fd9f
RGS
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-2007 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
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
43typedef int DualType ;
44typedef int int_undef ;
45
46typedef unsigned long uLong;
47typedef unsigned int uInt;
48
49typedef struct di_stream {
50 int flags ;
51#define FLAG_APPEND_OUTPUT 1
52#define FLAG_CONSUME_INPUT 8
ea6efd2c 53#define FLAG_LIMIT_OUTPUT 16
bdb7fd9f
RGS
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
63typedef di_stream * deflateStream ;
64typedef di_stream * Compress__Raw__Bzip2 ;
65
66typedef di_stream * inflateStream ;
67typedef 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[] = { */
77static 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
122void bz_internal_error(int errorcode)
123{
124 croak("bz_internal_error %d\n", errorcode);
125}
126#endif
127
128static char *
129#ifdef CAN_PROTOTYPE
130GetErrorString(int error_no)
131#else
132GetErrorString(error_no)
133int 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
150static void
151#ifdef CAN_PROTOTYPE
152DispHex(void * ptr, int length)
153#else
154DispHex(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
167static void
168#ifdef CAN_PROTOTYPE
169DispStream(di_stream * s, char * message)
170#else
171DispStream(s, message)
172 di_stream * s;
173 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)
ea6efd2c 186 printf(" - %s \n", message) ;
bdb7fd9f
RGS
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);
ea6efd2c 195 printf(" state 0x%p\n", s->stream.state );
bdb7fd9f
RGS
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);
ea6efd2c
MB
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);
bdb7fd9f
RGS
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));
ea6efd2c 220 printf(" LIMIT %s\n", EnDis(FLAG_LIMIT_OUTPUT));
bdb7fd9f
RGS
221
222 printf("\n");
223
224 }
225}
226
227static di_stream *
228#ifdef CAN_PROTOTYPE
229InitStream(void)
230#else
231InitStream()
232#endif
233{
234 di_stream *s ;
235
236 ZMALLOC(s, di_stream) ;
237
238 return s ;
239
240}
241
242static void
243#ifdef CAN_PROTOTYPE
244PostInitStream(di_stream * s, int flags)
245#else
246PostInitStream(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
257static SV*
258#ifdef CAN_PROTOTYPE
259deRef(SV * sv, const char * string)
260#else
261deRef(sv, string)
262SV * sv ;
263char * 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);
776304fb
PM
277 default:
278 break;
bdb7fd9f
RGS
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 = newSVpv("", 0);
286 }
287
288 return sv ;
289}
290
291static SV*
292#ifdef CAN_PROTOTYPE
293deRef_l(SV * sv, const char * string)
294#else
295deRef_l(sv, string)
296SV * sv ;
297char * string ;
298#endif
299{
300 dTHX;
301 bool wipe = 0 ;
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);
776304fb
PM
316 default:
317 break;
bdb7fd9f
RGS
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 SvCUR_set(sv, 0);
330
331 SvOOK_off(sv);
332 SvPOK_only(sv);
333
334 return sv ;
335}
336
337
338#include "constants.h"
339
340MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2 PREFIX = Zip_
341
342REQUIRE: 1.924
343PROTOTYPES: DISABLE
344
345INCLUDE: constants.xs
346
347BOOT:
c14f59c3
PM
348#ifndef NO_WRITEABLE_DATA
349 trace = TRACE_DEFAULT ;
350#endif
bdb7fd9f
RGS
351 /* Check this version of bzip2 is == 1 */
352 if (BZ2_bzlibVersion()[0] != '1')
353 croak(COMPRESS_CLASS " needs bzip2 version 1.x, you have %s\n", BZ2_bzlibVersion()) ;
354
355
356MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2
357
358#define bzlibversion() BZ2_bzlibVersion()
359const char *
360bzlibversion()
361
362void
c14f59c3
PM
363new(className, appendOut=1, blockSize100k=1, workfactor=0, verbosity=0)
364 const char * className
bdb7fd9f
RGS
365 int appendOut
366 int blockSize100k
367 int workfactor
368 int verbosity
369 PPCODE:
370 {
371 int err ;
372 deflateStream s ;
373#if 0
374 /* if (trace) */
375 warn("in Compress::Raw::Bzip2::_new(items=%d,appendOut=%d, blockSize100k=%d, workfactor=%d, verbosity=%d\n",
376 items, appendOut, blockSize100k, workfactor, verbosity);
377#endif
378 if ((s = InitStream() )) {
379
380 err = BZ2_bzCompressInit ( &(s->stream),
381 blockSize100k,
382 verbosity,
383 workfactor );
384
385 if (err != BZ_OK) {
386 Safefree(s) ;
387 s = NULL ;
388 }
389 else {
390 int flags = 0 ;
391 if (appendOut)
392 flags |= FLAG_APPEND_OUTPUT;
393 PostInitStream(s, appendOut ? FLAG_APPEND_OUTPUT :0) ;
394 }
395 }
396 else
397 err = BZ_MEM_ERROR ;
398
399 {
c14f59c3 400 SV* obj = sv_setref_pv(sv_newmortal(), className, (void*)s);
bdb7fd9f
RGS
401 XPUSHs(obj);
402 }
403 if(0)
404 {
405 SV* obj = sv_2mortal(newSViv(PTR2IV(s))) ;
406 XPUSHs(obj);
407 }
408 if (GIMME == G_ARRAY) {
409 SV * sv = sv_2mortal(newSViv(err)) ;
410 setDUALstatus(sv, err);
411 XPUSHs(sv) ;
412 }
413 }
414
415MODULE = Compress::Raw::Bunzip2 PACKAGE = Compress::Raw::Bunzip2
416
417void
ea6efd2c 418new(className, appendOut=1 , consume=1, small=0, verbosity=0, limitOutput=0)
c14f59c3 419 const char* className
bdb7fd9f
RGS
420 int appendOut
421 int consume
422 int small
423 int verbosity
ea6efd2c 424 int limitOutput
bdb7fd9f
RGS
425 PPCODE:
426 {
427 int err = BZ_OK ;
428 inflateStream s ;
429#if 0
430 if (trace)
431 warn("in _inflateInit(windowBits=%d, bufsize=%lu, dictionary=%lu\n",
432 windowBits, bufsize, (unsigned long)SvCUR(dictionary)) ;
433#endif
434 if ((s = InitStream() )) {
435
436 err = BZ2_bzDecompressInit (&(s->stream), verbosity, small);
437 if (err != BZ_OK) {
438 Safefree(s) ;
439 s = NULL ;
440 }
441 if (s) {
442 int flags = 0;
443 if (appendOut)
444 flags |= FLAG_APPEND_OUTPUT;
445 if (consume)
446 flags |= FLAG_CONSUME_INPUT;
ea6efd2c
MB
447 if (limitOutput)
448 flags |= (FLAG_LIMIT_OUTPUT|FLAG_CONSUME_INPUT);
bdb7fd9f
RGS
449 PostInitStream(s, flags) ;
450 }
451 }
452 else
453 err = BZ_MEM_ERROR ;
454
455 {
c14f59c3 456 SV* obj = sv_setref_pv(sv_newmortal(), className, (void*)s);
bdb7fd9f
RGS
457 XPUSHs(obj);
458 }
459 if (0)
460 {
461 SV* obj = sv_2mortal(newSViv(PTR2IV(s))) ;
462 XPUSHs(obj);
463 }
464 if (GIMME == G_ARRAY) {
465 SV * sv = sv_2mortal(newSViv(err)) ;
466 setDUALstatus(sv, err);
467 XPUSHs(sv) ;
468 }
469 }
470
471
472
473MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2
474
475void
476DispStream(s, message=NULL)
477 Compress::Raw::Bzip2 s
478 char * message
479
480DualType
481bzdeflate (s, buf, output)
482 Compress::Raw::Bzip2 s
483 SV * buf
484 SV * output
485 uInt cur_length = NO_INIT
486 uInt increment = NO_INIT
487 int RETVAL = 0;
488 uInt bufinc = NO_INIT
489 CODE:
490 bufinc = s->bufsize;
491
492 /* If the input buffer is a reference, dereference it */
493 buf = deRef(buf, "deflate") ;
494
495 /* initialise the input buffer */
496#ifdef UTF8_AVAILABLE
497 if (DO_UTF8(buf) && !sv_utf8_downgrade(buf, 1))
498 croak("Wide character in " COMPRESS_CLASS "::bzdeflate input parameter");
499#endif
500 s->stream.next_in = (char*)SvPVbyte_nolen(buf) ;
501 s->stream.avail_in = SvCUR(buf) ;
502
503 /* and retrieve the output buffer */
504 output = deRef_l(output, "deflate") ;
505#ifdef UTF8_AVAILABLE
506 if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1))
507 croak("Wide character in " COMPRESS_CLASS "::bzdeflate output parameter");
508#endif
509
510 if((s->flags & FLAG_APPEND_OUTPUT) != FLAG_APPEND_OUTPUT) {
511 SvCUR_set(output, 0);
512 /* sv_setpvn(output, "", 0); */
513 }
514 cur_length = SvCUR(output) ;
515 s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length;
516 increment = SvLEN(output) - cur_length;
517 s->stream.avail_out = increment;
518 while (s->stream.avail_in != 0) {
519
520 if (s->stream.avail_out == 0) {
521 /* out of space in the output buffer so make it bigger */
522 Sv_Grow(output, SvLEN(output) + bufinc) ;
523 cur_length += increment ;
524 s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length ;
525 increment = bufinc ;
526 s->stream.avail_out = increment;
527 bufinc *= 2 ;
528 }
529
530 RETVAL = BZ2_bzCompress(&(s->stream), BZ_RUN);
531 if (RETVAL != BZ_RUN_OK)
532 break;
533 }
534
535 s->compressedBytes += cur_length + increment - s->stream.avail_out ;
536 s->uncompressedBytes += SvCUR(buf) - s->stream.avail_in ;
537
538 s->last_error = RETVAL ;
539 if (RETVAL == BZ_RUN_OK) {
540 SvPOK_only(output);
541 SvCUR_set(output, cur_length + increment - s->stream.avail_out) ;
542 SvSETMAGIC(output);
543 }
544 OUTPUT:
545 RETVAL
546
547
548void
549DESTROY(s)
550 Compress::Raw::Bzip2 s
551 CODE:
552 BZ2_bzCompressEnd(&s->stream) ;
553 Safefree(s) ;
554
555
556DualType
557bzclose(s, output)
558 Compress::Raw::Bzip2 s
559 SV * output
560 uInt cur_length = NO_INIT
561 uInt increment = NO_INIT
562 uInt bufinc = NO_INIT
563 CODE:
564 bufinc = s->bufsize;
565
566 s->stream.avail_in = 0; /* should be zero already anyway */
567
568 /* retrieve the output buffer */
569 output = deRef_l(output, "close") ;
570#ifdef UTF8_AVAILABLE
571 if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1))
572 croak("Wide character in " COMPRESS_CLASS "::bzclose input parameter");
573#endif
574 if(! s->flags & FLAG_APPEND_OUTPUT) {
575 SvCUR_set(output, 0);
576 /* sv_setpvn(output, "", 0); */
577 }
578 cur_length = SvCUR(output) ;
579 s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length;
580 increment = SvLEN(output) - cur_length;
581 s->stream.avail_out = increment;
582
583 for (;;) {
584 if (s->stream.avail_out == 0) {
585 /* consumed all the available output, so extend it */
586 Sv_Grow(output, SvLEN(output) + bufinc) ;
587 cur_length += increment ;
588 s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length ;
589 increment = bufinc ;
590 s->stream.avail_out = increment;
591 bufinc *= 2 ;
592 }
593 RETVAL = BZ2_bzCompress(&(s->stream), BZ_FINISH);
594
595 /* deflate has finished flushing only when it hasn't used up
596 * all the available space in the output buffer:
597 */
598 /* if (s->stream.avail_out != 0 || RETVAL < 0 ) */
599 if (RETVAL == BZ_STREAM_END || RETVAL < 0 )
600 break;
601 }
602
603 /* RETVAL = (RETVAL == BZ_STREAM_END ? BZ_OK : RETVAL) ; */
604 s->last_error = RETVAL ;
605
606 s->compressedBytes += cur_length + increment - s->stream.avail_out ;
607
608 if (RETVAL == BZ_STREAM_END) {
609 SvPOK_only(output);
610 SvCUR_set(output, cur_length + increment - s->stream.avail_out) ;
611 SvSETMAGIC(output);
612 }
613 OUTPUT:
614 RETVAL
615
616
617DualType
618bzflush(s, output)
619 Compress::Raw::Bzip2 s
620 SV * output
621 uInt cur_length = NO_INIT
622 uInt increment = NO_INIT
623 uInt bufinc = NO_INIT
624 CODE:
625 bufinc = s->bufsize;
626
627 s->stream.avail_in = 0; /* should be zero already anyway */
628
629 /* retrieve the output buffer */
630 output = deRef_l(output, "close") ;
631#ifdef UTF8_AVAILABLE
632 if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1))
633 croak("Wide character in " COMPRESS_CLASS "::bzflush input parameter");
634#endif
635 if(! s->flags & FLAG_APPEND_OUTPUT) {
636 SvCUR_set(output, 0);
637 /* sv_setpvn(output, "", 0); */
638 }
639 cur_length = SvCUR(output) ;
640 s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length;
641 increment = SvLEN(output) - cur_length;
642 s->stream.avail_out = increment;
643
644 for (;;) {
645 if (s->stream.avail_out == 0) {
646 /* consumed all the available output, so extend it */
647 Sv_Grow(output, SvLEN(output) + bufinc) ;
648 cur_length += increment ;
649 s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length ;
650 increment = bufinc ;
651 s->stream.avail_out = increment;
652 bufinc *= 2 ;
653 }
654 RETVAL = BZ2_bzCompress(&(s->stream), BZ_FLUSH);
655
656 if (RETVAL == BZ_RUN_OK || RETVAL < 0)
657 break;
658
659 /* deflate has finished flushing only when it hasn't used up
660 * all the available space in the output buffer:
661 */
662 /* RETVAL == if (s->stream.avail_out != 0 || RETVAL < 0 )
663 break; */
664 }
665
666 /* RETVAL = (RETVAL == BZ_STREAM_END ? BZ_OK : RETVAL) ; */
667 s->last_error = RETVAL ;
668
669 s->compressedBytes += cur_length + increment - s->stream.avail_out ;
670
671 if (RETVAL == BZ_RUN_OK) {
672 SvPOK_only(output);
673 SvCUR_set(output, cur_length + increment - s->stream.avail_out) ;
674 SvSETMAGIC(output);
675 }
676 OUTPUT:
677 RETVAL
678
679uLong
680total_in_lo32(s)
681 Compress::Raw::Bzip2 s
682 CODE:
683 RETVAL = s->stream.total_in_lo32 ;
684 OUTPUT:
685 RETVAL
686
687uLong
688total_out_lo32(s)
689 Compress::Raw::Bzip2 s
690 CODE:
691 RETVAL = s->stream.total_out_lo32 ;
692 OUTPUT:
693 RETVAL
694
695uLong
696compressedBytes(s)
697 Compress::Raw::Bzip2 s
698 CODE:
699 RETVAL = s->compressedBytes;
700 OUTPUT:
701 RETVAL
702
703uLong
704uncompressedBytes(s)
705 Compress::Raw::Bzip2 s
706 CODE:
707 RETVAL = s->uncompressedBytes;
708 OUTPUT:
709 RETVAL
710
711
712MODULE = Compress::Raw::Bunzip2 PACKAGE = Compress::Raw::Bunzip2
713
714void
715DispStream(s, message=NULL)
716 Compress::Raw::Bunzip2 s
717 char * message
718
719DualType
720bzinflate (s, buf, output)
721 Compress::Raw::Bunzip2 s
722 SV * buf
723 SV * output
724 uInt cur_length = 0;
725 uInt prefix_length = 0;
726 uInt increment = 0;
727 STRLEN stmp = NO_INIT
728 uInt bufinc = NO_INIT
729 PREINIT:
730#ifdef UTF8_AVAILABLE
731 bool out_utf8 = FALSE;
732#endif
733 CODE:
734 bufinc = s->bufsize;
735 /* If the buffer is a reference, dereference it */
ea6efd2c 736 buf = deRef(buf, "bzinflate") ;
bdb7fd9f
RGS
737
738 if (s->flags & FLAG_CONSUME_INPUT && SvREADONLY(buf))
739 croak(UNCOMPRESS_CLASS "::bzinflate input parameter cannot be read-only when ConsumeInput is specified");
740#ifdef UTF8_AVAILABLE
741 if (DO_UTF8(buf) && !sv_utf8_downgrade(buf, 1))
742 croak("Wide character in " UNCOMPRESS_CLASS "::bzinflate input parameter");
743#endif
744
745 /* initialise the input buffer */
746 s->stream.next_in = (char*)SvPVbyte_force(buf, stmp) ;
747 s->stream.avail_in = SvCUR(buf);
748
749 /* and retrieve the output buffer */
ea6efd2c 750 output = deRef_l(output, "bzinflate") ;
bdb7fd9f
RGS
751#ifdef UTF8_AVAILABLE
752 if (DO_UTF8(output))
753 out_utf8 = TRUE ;
754 if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1))
755 croak("Wide character in " UNCOMPRESS_CLASS "::bzinflate output parameter");
756#endif
757 if((s->flags & FLAG_APPEND_OUTPUT) != FLAG_APPEND_OUTPUT) {
758 SvCUR_set(output, 0);
759 }
ea6efd2c
MB
760#if 1
761 /* Assume no output buffer - the code below will update if there is any available */
762 s->stream.avail_out = 0;
763
764 if (SvLEN(output)) {
765 prefix_length = cur_length = SvCUR(output) ;
766
767 if (s->flags & FLAG_LIMIT_OUTPUT && SvLEN(output) - cur_length - 1 < bufinc)
768 {
769 Sv_Grow(output, bufinc + cur_length + 1) ;
770 }
771
772 /* Only setup the stream output pointers if there is spare
773 capacity in the outout SV
774 */
775 if (SvLEN(output) > cur_length + 1)
776 {
777 s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length;
778 increment = SvLEN(output) - cur_length - 1;
779 s->stream.avail_out = increment;
780 }
781 }
782
783 s->bytesInflated = 0;
784
785 RETVAL = BZ_OK;
786#else
787
bdb7fd9f
RGS
788 if (SvLEN(output)) {
789 prefix_length = cur_length = SvCUR(output) ;
790 s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length;
791 increment = SvLEN(output) - cur_length - 1;
792 s->stream.avail_out = increment;
793 }
794 else {
795 s->stream.avail_out = 0;
796 }
797 s->bytesInflated = 0;
ea6efd2c 798#endif
bdb7fd9f
RGS
799
800 while (1) {
801
802 if (s->stream.avail_out == 0) {
803 /* out of space in the output buffer so make it bigger */
ea6efd2c 804 Sv_Grow(output, SvLEN(output) + bufinc + 1) ;
bdb7fd9f
RGS
805 cur_length += increment ;
806 s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length ;
807 increment = bufinc ;
808 s->stream.avail_out = increment;
809 bufinc *= 2 ;
810 }
811
ea6efd2c 812 //DispStream(s, "pre");
bdb7fd9f
RGS
813 RETVAL = BZ2_bzDecompress (&(s->stream));
814
ea6efd2c
MB
815 //DispStream(s, "apres");
816 if (RETVAL != BZ_OK || s->flags & FLAG_LIMIT_OUTPUT)
bdb7fd9f
RGS
817 break ;
818
819 if (s->stream.avail_out == 0)
820 continue ;
821
822 if (s->stream.avail_in == 0) {
823 RETVAL = BZ_OK ;
824 break ;
825 }
826
827 }
828
829 s->last_error = RETVAL ;
830 if (RETVAL == BZ_OK || RETVAL == BZ_STREAM_END) {
831 unsigned in ;
832
833 s->bytesInflated = cur_length + increment - s->stream.avail_out - prefix_length;
834 s->uncompressedBytes += s->bytesInflated ;
835 s->compressedBytes += SvCUR(buf) - s->stream.avail_in ;
836
837 SvPOK_only(output);
838 SvCUR_set(output, prefix_length + s->bytesInflated) ;
839 *SvEND(output) = '\0';
840#ifdef UTF8_AVAILABLE
841 if (out_utf8)
842 sv_utf8_upgrade(output);
843#endif
844 SvSETMAGIC(output);
845
846 /* fix the input buffer */
847 if (s->flags & FLAG_CONSUME_INPUT) {
848 in = s->stream.avail_in ;
849 SvCUR_set(buf, in) ;
850 if (in)
851 Move(s->stream.next_in, SvPVbyte_nolen(buf), in, char) ;
852 *SvEND(buf) = '\0';
853 SvSETMAGIC(buf);
854 }
855 }
856 OUTPUT:
857 RETVAL
858
859uLong
860inflateCount(s)
861 Compress::Raw::Bunzip2 s
862 CODE:
863 RETVAL = s->bytesInflated;
864 OUTPUT:
865 RETVAL
866
867
868void
869DESTROY(s)
870 Compress::Raw::Bunzip2 s
871 CODE:
872 BZ2_bzDecompressEnd(&s->stream) ;
873 Safefree(s) ;
874
875
876uLong
877status(s)
878 Compress::Raw::Bunzip2 s
879 CODE:
880 RETVAL = s->last_error ;
881 OUTPUT:
882 RETVAL
883
884uLong
885total_in_lo32(s)
886 Compress::Raw::Bunzip2 s
887 CODE:
888 RETVAL = s->stream.total_in_lo32 ;
889 OUTPUT:
890 RETVAL
891
892uLong
893total_out_lo32(s)
894 Compress::Raw::Bunzip2 s
895 CODE:
896 RETVAL = s->stream.total_out_lo32 ;
897 OUTPUT:
898 RETVAL
899
900uLong
901compressedBytes(s)
902 Compress::Raw::Bunzip2 s
903 CODE:
904 RETVAL = s->compressedBytes;
905 OUTPUT:
906 RETVAL
907
908uLong
909uncompressedBytes(s)
910 Compress::Raw::Bunzip2 s
911 CODE:
912 RETVAL = s->uncompressedBytes;
913 OUTPUT:
914 RETVAL
915
916MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2 PREFIX = Zip_