2 * Author : Paul Marquess, <pmqs@cpan.org>
3 * Created : 5th October 2005
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.
20 # define NEED_sv_2pv_nolen
24 #if PERL_REVISION == 5 && (PERL_VERSION < 8 || (PERL_VERSION == 8 && PERL_SUBVERSION < 4 ))
26 # ifdef SvPVbyte_force
27 # undef SvPVbyte_force
30 # define SvPVbyte_force(sv,lp) SvPV_force(sv,lp)
34 #ifndef SvPVbyte_nolen
35 # define SvPVbyte_nolen SvPV_nolen
39 #if PERL_REVISION == 5 && (PERL_VERSION >= 8 || (PERL_VERSION == 8 && PERL_SUBVERSION < 4 ))
40 # define UTF8_AVAILABLE
43 typedef int DualType ;
44 typedef int int_undef ;
46 typedef unsigned long uLong;
47 typedef unsigned int uInt;
49 typedef struct di_stream {
51 #define FLAG_APPEND_OUTPUT 1
52 #define FLAG_CONSUME_INPUT 8
57 uLong compressedBytes ;
58 uLong uncompressedBytes ;
62 typedef di_stream * deflateStream ;
63 typedef di_stream * Compress__Raw__Bzip2 ;
65 typedef di_stream * inflateStream ;
66 typedef di_stream * Compress__Raw__Bunzip2 ;
68 #define COMPRESS_CLASS "Compress::Raw::Bzip2"
69 #define UNCOMPRESS_CLASS "Compress::Raw::Bunzip2"
71 #define ZMALLOC(to, typ) ((to = (typ *)safemalloc(sizeof(typ))), \
75 /* static const char * const my_z_errmsg[] = { */
76 static const char my_z_errmsg[][32] = {
77 "End of Stream", /* BZ_STREAM_END 4 */
78 "Finish OK", /* BZ_FINISH_OK 3 */
79 "Flush OK", /* BZ_FLUSH_OK 2 */
80 "Run OK", /* BZ_RUN_OK 1 */
82 "Sequence Error", /* BZ_SEQUENCE_ERROR (-1) */
83 "Param Error", /* BZ_PARAM_ERROR (-2) */
84 "Memory Error", /* BZ_MEM_ERROR (-3) */
85 "Data Error", /* BZ_DATA_ERROR (-4) */
86 "Magic Error", /* BZ_DATA_ERROR_MAGIC (-5) */
87 "IO Error", /* BZ_IO_ERROR (-6) */
88 "Unexpected EOF", /* BZ_UNEXPECTED_EOF (-7) */
89 "Output Buffer Full", /* BZ_OUTBUFF_FULL (-8) */
90 "Config Error", /* BZ_CONFIG_ERROR (-9) */
93 #define setDUALstatus(var, err) \
94 sv_setnv(var, (double)err) ; \
95 sv_setpv(var, ((err) ? GetErrorString(err) : "")) ; \
99 #if defined(__SYMBIAN32__)
100 # define NO_WRITEABLE_DATA
103 #define TRACE_DEFAULT 0
105 #ifdef NO_WRITEABLE_DATA
106 # define trace TRACE_DEFAULT
108 static int trace = TRACE_DEFAULT ;
111 /* Dodge PerlIO hiding of these functions. */
115 #define getInnerObject(x) (*av_fetch((AV*)SvRV(x), 0, FALSE))
117 #define getInnerObject(x) ((SV*)SvRV(sv))
121 void bz_internal_error(int errorcode)
123 croak("bz_internal_error %d\n", errorcode);
129 GetErrorString(int error_no)
131 GetErrorString(error_no)
139 if (error_no == BZ_ERRNO) {
140 errstr = Strerror(errno) ;
144 errstr = (char*) my_z_errmsg[4 - error_no];
151 DispHex(void * ptr, int length)
158 char * p = (char*)ptr;
160 for (i = 0; i < length; ++i) {
161 printf(" %02x", 0xFF & *(p+i));
168 DispStream(di_stream * s, char * message)
170 DispStream(s, message)
181 #define EnDis(f) (s->flags & f ? "Enabled" : "Disabled")
183 printf("DispStream 0x%p", s) ;
185 printf("- %s \n", message) ;
189 printf(" stream pointer is NULL\n");
192 printf(" stream 0x%p\n", &(s->stream));
193 printf(" opaque 0x%p\n", s->stream.opaque);
194 printf(" next_in 0x%p", s->stream.next_in);
195 if (s->stream.next_in){
197 DispHex(s->stream.next_in, 4);
201 printf(" next_out 0x%p", s->stream.next_out);
202 if (s->stream.next_out){
204 DispHex(s->stream.next_out, 4);
208 printf(" avail_in %lu\n", (unsigned long)s->stream.avail_in);
209 printf(" avail_out %lu\n", (unsigned long)s->stream.avail_out);
210 printf(" bufsize %lu\n", (unsigned long)s->bufsize);
211 printf(" flags 0x%x\n", s->flags);
212 printf(" APPEND %s\n", EnDis(FLAG_APPEND_OUTPUT));
213 printf(" CONSUME %s\n", EnDis(FLAG_CONSUME_INPUT));
229 ZMALLOC(s, di_stream) ;
237 PostInitStream(di_stream * s, int flags)
239 PostInitStream(s, flags)
244 s->bufsize = 1024 * 16 ;
252 deRef(SV * sv, const char * string)
269 croak("%s: buffer parameter is not a SCALAR reference", string);
272 croak("%s: buffer parameter is a reference to a reference", string) ;
284 deRef_l(SV * sv, const char * string)
306 croak("%s: buffer parameter is not a SCALAR reference", string);
309 croak("%s: buffer parameter is a reference to a reference", string) ;
312 if (SvREADONLY(sv) && PL_curcop != &PL_compiling)
313 croak("%s: buffer parameter is read-only", string);
315 SvUPGRADE(sv, SVt_PV);
327 #include "constants.h"
329 MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2 PREFIX = Zip_
334 INCLUDE: constants.xs
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()) ;
342 MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2
344 #define bzlibversion() BZ2_bzlibVersion()
349 new(class, appendOut=1, blockSize100k=1, workfactor=0, verbosity=0)
361 warn("in Compress::Raw::Bzip2::_new(items=%d,appendOut=%d, blockSize100k=%d, workfactor=%d, verbosity=%d\n",
362 items, appendOut, blockSize100k, workfactor, verbosity);
364 if ((s = InitStream() )) {
366 err = BZ2_bzCompressInit ( &(s->stream),
378 flags |= FLAG_APPEND_OUTPUT;
379 PostInitStream(s, appendOut ? FLAG_APPEND_OUTPUT :0) ;
386 SV* obj = sv_setref_pv(sv_newmortal(), class, (void*)s);
391 SV* obj = sv_2mortal(newSViv(PTR2IV(s))) ;
394 if (GIMME == G_ARRAY) {
395 SV * sv = sv_2mortal(newSViv(err)) ;
396 setDUALstatus(sv, err);
401 MODULE = Compress::Raw::Bunzip2 PACKAGE = Compress::Raw::Bunzip2
404 new(class, appendOut=1 , consume=1, small=0, verbosity=0)
416 warn("in _inflateInit(windowBits=%d, bufsize=%lu, dictionary=%lu\n",
417 windowBits, bufsize, (unsigned long)SvCUR(dictionary)) ;
419 if ((s = InitStream() )) {
421 err = BZ2_bzDecompressInit (&(s->stream), verbosity, small);
429 flags |= FLAG_APPEND_OUTPUT;
431 flags |= FLAG_CONSUME_INPUT;
432 PostInitStream(s, flags) ;
439 SV* obj = sv_setref_pv(sv_newmortal(), class, (void*)s);
444 SV* obj = sv_2mortal(newSViv(PTR2IV(s))) ;
447 if (GIMME == G_ARRAY) {
448 SV * sv = sv_2mortal(newSViv(err)) ;
449 setDUALstatus(sv, err);
456 MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2
459 DispStream(s, message=NULL)
460 Compress::Raw::Bzip2 s
464 bzdeflate (s, buf, output)
465 Compress::Raw::Bzip2 s
468 uInt cur_length = NO_INIT
469 uInt increment = NO_INIT
471 uInt bufinc = NO_INIT
475 /* If the input buffer is a reference, dereference it */
476 buf = deRef(buf, "deflate") ;
478 /* initialise the input buffer */
479 #ifdef UTF8_AVAILABLE
480 if (DO_UTF8(buf) && !sv_utf8_downgrade(buf, 1))
481 croak("Wide character in " COMPRESS_CLASS "::bzdeflate input parameter");
483 s->stream.next_in = (char*)SvPVbyte_nolen(buf) ;
484 s->stream.avail_in = SvCUR(buf) ;
486 /* and retrieve the output buffer */
487 output = deRef_l(output, "deflate") ;
488 #ifdef UTF8_AVAILABLE
489 if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1))
490 croak("Wide character in " COMPRESS_CLASS "::bzdeflate output parameter");
493 if((s->flags & FLAG_APPEND_OUTPUT) != FLAG_APPEND_OUTPUT) {
494 SvCUR_set(output, 0);
495 /* sv_setpvn(output, "", 0); */
497 cur_length = SvCUR(output) ;
498 s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length;
499 increment = SvLEN(output) - cur_length;
500 s->stream.avail_out = increment;
501 while (s->stream.avail_in != 0) {
503 if (s->stream.avail_out == 0) {
504 /* out of space in the output buffer so make it bigger */
505 Sv_Grow(output, SvLEN(output) + bufinc) ;
506 cur_length += increment ;
507 s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length ;
509 s->stream.avail_out = increment;
513 RETVAL = BZ2_bzCompress(&(s->stream), BZ_RUN);
514 if (RETVAL != BZ_RUN_OK)
518 s->compressedBytes += cur_length + increment - s->stream.avail_out ;
519 s->uncompressedBytes += SvCUR(buf) - s->stream.avail_in ;
521 s->last_error = RETVAL ;
522 if (RETVAL == BZ_RUN_OK) {
524 SvCUR_set(output, cur_length + increment - s->stream.avail_out) ;
533 Compress::Raw::Bzip2 s
535 BZ2_bzCompressEnd(&s->stream) ;
541 Compress::Raw::Bzip2 s
543 uInt cur_length = NO_INIT
544 uInt increment = NO_INIT
545 uInt bufinc = NO_INIT
549 s->stream.avail_in = 0; /* should be zero already anyway */
551 /* retrieve the output buffer */
552 output = deRef_l(output, "close") ;
553 #ifdef UTF8_AVAILABLE
554 if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1))
555 croak("Wide character in " COMPRESS_CLASS "::bzclose input parameter");
557 if(! s->flags & FLAG_APPEND_OUTPUT) {
558 SvCUR_set(output, 0);
559 /* sv_setpvn(output, "", 0); */
561 cur_length = SvCUR(output) ;
562 s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length;
563 increment = SvLEN(output) - cur_length;
564 s->stream.avail_out = increment;
567 if (s->stream.avail_out == 0) {
568 /* consumed all the available output, so extend it */
569 Sv_Grow(output, SvLEN(output) + bufinc) ;
570 cur_length += increment ;
571 s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length ;
573 s->stream.avail_out = increment;
576 RETVAL = BZ2_bzCompress(&(s->stream), BZ_FINISH);
578 /* deflate has finished flushing only when it hasn't used up
579 * all the available space in the output buffer:
581 /* if (s->stream.avail_out != 0 || RETVAL < 0 ) */
582 if (RETVAL == BZ_STREAM_END || RETVAL < 0 )
586 /* RETVAL = (RETVAL == BZ_STREAM_END ? BZ_OK : RETVAL) ; */
587 s->last_error = RETVAL ;
589 s->compressedBytes += cur_length + increment - s->stream.avail_out ;
591 if (RETVAL == BZ_STREAM_END) {
593 SvCUR_set(output, cur_length + increment - s->stream.avail_out) ;
602 Compress::Raw::Bzip2 s
604 uInt cur_length = NO_INIT
605 uInt increment = NO_INIT
606 uInt bufinc = NO_INIT
610 s->stream.avail_in = 0; /* should be zero already anyway */
612 /* retrieve the output buffer */
613 output = deRef_l(output, "close") ;
614 #ifdef UTF8_AVAILABLE
615 if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1))
616 croak("Wide character in " COMPRESS_CLASS "::bzflush input parameter");
618 if(! s->flags & FLAG_APPEND_OUTPUT) {
619 SvCUR_set(output, 0);
620 /* sv_setpvn(output, "", 0); */
622 cur_length = SvCUR(output) ;
623 s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length;
624 increment = SvLEN(output) - cur_length;
625 s->stream.avail_out = increment;
628 if (s->stream.avail_out == 0) {
629 /* consumed all the available output, so extend it */
630 Sv_Grow(output, SvLEN(output) + bufinc) ;
631 cur_length += increment ;
632 s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length ;
634 s->stream.avail_out = increment;
637 RETVAL = BZ2_bzCompress(&(s->stream), BZ_FLUSH);
639 if (RETVAL == BZ_RUN_OK || RETVAL < 0)
642 /* deflate has finished flushing only when it hasn't used up
643 * all the available space in the output buffer:
645 /* RETVAL == if (s->stream.avail_out != 0 || RETVAL < 0 )
649 /* RETVAL = (RETVAL == BZ_STREAM_END ? BZ_OK : RETVAL) ; */
650 s->last_error = RETVAL ;
652 s->compressedBytes += cur_length + increment - s->stream.avail_out ;
654 if (RETVAL == BZ_RUN_OK) {
656 SvCUR_set(output, cur_length + increment - s->stream.avail_out) ;
664 Compress::Raw::Bzip2 s
666 RETVAL = s->stream.total_in_lo32 ;
672 Compress::Raw::Bzip2 s
674 RETVAL = s->stream.total_out_lo32 ;
680 Compress::Raw::Bzip2 s
682 RETVAL = s->compressedBytes;
688 Compress::Raw::Bzip2 s
690 RETVAL = s->uncompressedBytes;
695 MODULE = Compress::Raw::Bunzip2 PACKAGE = Compress::Raw::Bunzip2
698 DispStream(s, message=NULL)
699 Compress::Raw::Bunzip2 s
703 bzinflate (s, buf, output)
704 Compress::Raw::Bunzip2 s
708 uInt prefix_length = 0;
710 STRLEN stmp = NO_INIT
711 uInt bufinc = NO_INIT
713 #ifdef UTF8_AVAILABLE
714 bool out_utf8 = FALSE;
718 /* If the buffer is a reference, dereference it */
719 buf = deRef(buf, "inflate") ;
721 if (s->flags & FLAG_CONSUME_INPUT && SvREADONLY(buf))
722 croak(UNCOMPRESS_CLASS "::bzinflate input parameter cannot be read-only when ConsumeInput is specified");
723 #ifdef UTF8_AVAILABLE
724 if (DO_UTF8(buf) && !sv_utf8_downgrade(buf, 1))
725 croak("Wide character in " UNCOMPRESS_CLASS "::bzinflate input parameter");
728 /* initialise the input buffer */
729 s->stream.next_in = (char*)SvPVbyte_force(buf, stmp) ;
730 s->stream.avail_in = SvCUR(buf);
732 /* and retrieve the output buffer */
733 output = deRef_l(output, "inflate") ;
734 #ifdef UTF8_AVAILABLE
737 if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1))
738 croak("Wide character in " UNCOMPRESS_CLASS "::bzinflate output parameter");
740 if((s->flags & FLAG_APPEND_OUTPUT) != FLAG_APPEND_OUTPUT) {
741 SvCUR_set(output, 0);
744 prefix_length = cur_length = SvCUR(output) ;
745 s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length;
746 increment = SvLEN(output) - cur_length - 1;
747 s->stream.avail_out = increment;
750 s->stream.avail_out = 0;
752 s->bytesInflated = 0;
756 if (s->stream.avail_out == 0) {
757 /* out of space in the output buffer so make it bigger */
758 Sv_Grow(output, SvLEN(output) + bufinc) ;
759 cur_length += increment ;
760 s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length ;
762 s->stream.avail_out = increment;
766 RETVAL = BZ2_bzDecompress (&(s->stream));
771 if (s->stream.avail_out == 0)
774 if (s->stream.avail_in == 0) {
781 s->last_error = RETVAL ;
782 if (RETVAL == BZ_OK || RETVAL == BZ_STREAM_END) {
785 s->bytesInflated = cur_length + increment - s->stream.avail_out - prefix_length;
786 s->uncompressedBytes += s->bytesInflated ;
787 s->compressedBytes += SvCUR(buf) - s->stream.avail_in ;
790 SvCUR_set(output, prefix_length + s->bytesInflated) ;
791 *SvEND(output) = '\0';
792 #ifdef UTF8_AVAILABLE
794 sv_utf8_upgrade(output);
798 /* fix the input buffer */
799 if (s->flags & FLAG_CONSUME_INPUT) {
800 in = s->stream.avail_in ;
803 Move(s->stream.next_in, SvPVbyte_nolen(buf), in, char) ;
813 Compress::Raw::Bunzip2 s
815 RETVAL = s->bytesInflated;
822 Compress::Raw::Bunzip2 s
824 BZ2_bzDecompressEnd(&s->stream) ;
830 Compress::Raw::Bunzip2 s
832 RETVAL = s->last_error ;
838 Compress::Raw::Bunzip2 s
840 RETVAL = s->stream.total_in_lo32 ;
846 Compress::Raw::Bunzip2 s
848 RETVAL = s->stream.total_out_lo32 ;
854 Compress::Raw::Bunzip2 s
856 RETVAL = s->compressedBytes;
862 Compress::Raw::Bunzip2 s
864 RETVAL = s->uncompressedBytes;
868 MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2 PREFIX = Zip_