2 * Author : Paul Marquess, <pmqs@cpan.org>
3 * Created : 5th October 2005
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.
12 #define PERL_NO_GET_CONTEXT
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
53 #define FLAG_LIMIT_OUTPUT 16
58 uLong compressedBytes ;
59 uLong uncompressedBytes ;
63 typedef di_stream * deflateStream ;
64 typedef di_stream * Compress__Raw__Bzip2 ;
66 typedef di_stream * inflateStream ;
67 typedef di_stream * Compress__Raw__Bunzip2 ;
69 #define COMPRESS_CLASS "Compress::Raw::Bzip2"
70 #define UNCOMPRESS_CLASS "Compress::Raw::Bunzip2"
72 #define ZMALLOC(to, typ) ((to = (typ *)safemalloc(sizeof(typ))), \
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 */
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) */
94 #define setDUALstatus(var, err) \
95 sv_setnv(var, (double)err) ; \
96 sv_setpv(var, ((err) ? GetErrorString(err) : "")) ; \
100 #if defined(__SYMBIAN32__)
101 # define NO_WRITEABLE_DATA
104 #define TRACE_DEFAULT 0
106 #ifdef NO_WRITEABLE_DATA
107 # define trace TRACE_DEFAULT
109 static int trace = TRACE_DEFAULT ;
112 /* Dodge PerlIO hiding of these functions. */
116 #define getInnerObject(x) (*av_fetch((AV*)SvRV(x), 0, FALSE))
118 #define getInnerObject(x) ((SV*)SvRV(sv))
122 void bz_internal_error(int errorcode)
124 croak("bz_internal_error %d\n", errorcode);
130 GetErrorString(int error_no)
132 GetErrorString(error_no)
140 if (error_no == BZ_ERRNO) {
141 errstr = Strerror(errno) ;
145 errstr = (char*) my_z_errmsg[4 - error_no];
152 DispHex(void * ptr, int length)
159 char * p = (char*)ptr;
161 for (i = 0; i < length; ++i) {
162 printf(" %02x", 0xFF & *(p+i));
169 DispStream(di_stream * s, const char * message)
171 DispStream(s, message)
173 const char * message;
182 #define EnDis(f) (s->flags & f ? "Enabled" : "Disabled")
184 printf("DispStream 0x%p", s) ;
186 printf(" - %s \n", message) ;
190 printf(" stream pointer is NULL\n");
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){
199 DispHex(s->stream.next_in, 4);
203 printf(" next_out 0x%p", s->stream.next_out);
204 if (s->stream.next_out){
206 DispHex(s->stream.next_out, 4);
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));
236 ZMALLOC(s, di_stream) ;
244 PostInitStream(di_stream * s, int flags)
246 PostInitStream(s, flags)
251 s->bufsize = 1024 * 16 ;
259 deRef(SV * sv, const char * string)
276 croak("%s: buffer parameter is not a SCALAR reference", string);
281 croak("%s: buffer parameter is a reference to a reference", string) ;
285 sv = sv_2mortal(newSVpv("", 0));
292 deRef_l(SV * sv, const char * string)
315 croak("%s: buffer parameter is not a SCALAR reference", string);
320 croak("%s: buffer parameter is a reference to a reference", string) ;
323 if (SvREADONLY(sv) && PL_curcop != &PL_compiling)
324 croak("%s: buffer parameter is read-only", string);
326 SvUPGRADE(sv, SVt_PV);
331 (void)SvPVbyte_force(sv, na) ;
337 #include "constants.h"
339 MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2 PREFIX = Zip_
344 INCLUDE: constants.xs
347 #ifndef NO_WRITEABLE_DATA
348 trace = TRACE_DEFAULT ;
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()) ;
355 MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2
357 #define bzlibversion() BZ2_bzlibVersion()
362 new(className, appendOut=1, blockSize100k=1, workfactor=0, verbosity=0)
363 const char * className
374 warn("in Compress::Raw::Bzip2::_new(items=%d,appendOut=%d, blockSize100k=%d, workfactor=%d, verbosity=%d\n",
375 items, appendOut, blockSize100k, workfactor, verbosity);
377 if ((s = InitStream() )) {
379 err = BZ2_bzCompressInit ( &(s->stream),
391 flags |= FLAG_APPEND_OUTPUT;
392 PostInitStream(s, appendOut ? FLAG_APPEND_OUTPUT :0) ;
399 SV* obj = sv_setref_pv(sv_newmortal(), className, (void*)s);
404 SV* obj = sv_2mortal(newSViv(PTR2IV(s))) ;
407 if (GIMME == G_ARRAY) {
408 SV * sv = sv_2mortal(newSViv(err)) ;
409 setDUALstatus(sv, err);
414 MODULE = Compress::Raw::Bunzip2 PACKAGE = Compress::Raw::Bunzip2
417 new(className, appendOut=1 , consume=1, small=0, verbosity=0, limitOutput=0)
418 const char* className
430 warn("in _inflateInit(windowBits=%d, bufsize=%lu, dictionary=%lu\n",
431 windowBits, bufsize, (unsigned long)SvCUR(dictionary)) ;
433 if ((s = InitStream() )) {
435 err = BZ2_bzDecompressInit (&(s->stream), verbosity, small);
443 flags |= FLAG_APPEND_OUTPUT;
445 flags |= FLAG_CONSUME_INPUT;
447 flags |= (FLAG_LIMIT_OUTPUT|FLAG_CONSUME_INPUT);
448 PostInitStream(s, flags) ;
455 SV* obj = sv_setref_pv(sv_newmortal(), className, (void*)s);
460 SV* obj = sv_2mortal(newSViv(PTR2IV(s))) ;
463 if (GIMME == G_ARRAY) {
464 SV * sv = sv_2mortal(newSViv(err)) ;
465 setDUALstatus(sv, err);
472 MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2
475 DispStream(s, message=NULL)
476 Compress::Raw::Bzip2 s
480 bzdeflate (s, buf, output)
481 Compress::Raw::Bzip2 s
484 uInt cur_length = NO_INIT
485 uInt increment = NO_INIT
487 uInt bufinc = NO_INIT
491 /* If the input buffer is a reference, dereference it */
492 buf = deRef(buf, "deflate") ;
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");
499 s->stream.next_in = (char*)SvPV_nomg_nolen(buf) ;
500 s->stream.avail_in = SvCUR(buf) ;
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");
509 if((s->flags & FLAG_APPEND_OUTPUT) != FLAG_APPEND_OUTPUT) {
510 SvCUR_set(output, 0);
511 /* sv_setpvn(output, "", 0); */
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) {
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 ;
525 s->stream.avail_out = increment;
529 RETVAL = BZ2_bzCompress(&(s->stream), BZ_RUN);
530 if (RETVAL != BZ_RUN_OK)
534 s->compressedBytes += cur_length + increment - s->stream.avail_out ;
535 s->uncompressedBytes += SvCUR(buf) - s->stream.avail_in ;
537 s->last_error = RETVAL ;
538 if (RETVAL == BZ_RUN_OK) {
540 SvCUR_set(output, cur_length + increment - s->stream.avail_out) ;
549 Compress::Raw::Bzip2 s
551 BZ2_bzCompressEnd(&s->stream) ;
557 Compress::Raw::Bzip2 s
559 uInt cur_length = NO_INIT
560 uInt increment = NO_INIT
561 uInt bufinc = NO_INIT
565 s->stream.avail_in = 0; /* should be zero already anyway */
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");
573 if(! s->flags & FLAG_APPEND_OUTPUT) {
574 SvCUR_set(output, 0);
575 /* sv_setpvn(output, "", 0); */
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;
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 ;
589 s->stream.avail_out = increment;
592 RETVAL = BZ2_bzCompress(&(s->stream), BZ_FINISH);
594 /* deflate has finished flushing only when it hasn't used up
595 * all the available space in the output buffer:
597 /* if (s->stream.avail_out != 0 || RETVAL < 0 ) */
598 if (RETVAL == BZ_STREAM_END || RETVAL < 0 )
602 /* RETVAL = (RETVAL == BZ_STREAM_END ? BZ_OK : RETVAL) ; */
603 s->last_error = RETVAL ;
605 s->compressedBytes += cur_length + increment - s->stream.avail_out ;
607 if (RETVAL == BZ_STREAM_END) {
609 SvCUR_set(output, cur_length + increment - s->stream.avail_out) ;
618 Compress::Raw::Bzip2 s
620 uInt cur_length = NO_INIT
621 uInt increment = NO_INIT
622 uInt bufinc = NO_INIT
626 s->stream.avail_in = 0; /* should be zero already anyway */
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");
634 if(! s->flags & FLAG_APPEND_OUTPUT) {
635 SvCUR_set(output, 0);
636 /* sv_setpvn(output, "", 0); */
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;
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 ;
650 s->stream.avail_out = increment;
653 RETVAL = BZ2_bzCompress(&(s->stream), BZ_FLUSH);
655 if (RETVAL == BZ_RUN_OK || RETVAL < 0)
658 /* deflate has finished flushing only when it hasn't used up
659 * all the available space in the output buffer:
661 /* RETVAL == if (s->stream.avail_out != 0 || RETVAL < 0 )
665 /* RETVAL = (RETVAL == BZ_STREAM_END ? BZ_OK : RETVAL) ; */
666 s->last_error = RETVAL ;
668 s->compressedBytes += cur_length + increment - s->stream.avail_out ;
670 if (RETVAL == BZ_RUN_OK) {
672 SvCUR_set(output, cur_length + increment - s->stream.avail_out) ;
680 Compress::Raw::Bzip2 s
682 RETVAL = s->stream.total_in_lo32 ;
688 Compress::Raw::Bzip2 s
690 RETVAL = s->stream.total_out_lo32 ;
696 Compress::Raw::Bzip2 s
698 RETVAL = s->compressedBytes;
704 Compress::Raw::Bzip2 s
706 RETVAL = s->uncompressedBytes;
711 MODULE = Compress::Raw::Bunzip2 PACKAGE = Compress::Raw::Bunzip2
714 DispStream(s, message=NULL)
715 Compress::Raw::Bunzip2 s
719 bzinflate (s, buf, output)
720 Compress::Raw::Bunzip2 s
724 uInt prefix_length = 0;
726 uInt bufinc = NO_INIT
727 STRLEN na = NO_INIT ;
729 #ifdef UTF8_AVAILABLE
730 bool out_utf8 = FALSE;
734 /* If the buffer is a reference, dereference it */
735 buf = deRef(buf, "bzinflate") ;
737 if (s->flags & FLAG_CONSUME_INPUT) {
739 croak(UNCOMPRESS_CLASS "::bzinflate input parameter cannot be read-only when ConsumeInput is specified");
742 #ifdef UTF8_AVAILABLE
743 if (DO_UTF8(buf) && !sv_utf8_downgrade(buf, 1))
744 croak("Wide character in " UNCOMPRESS_CLASS "::bzinflate input parameter");
747 /* initialise the input buffer */
748 s->stream.next_in = (char*)SvPV_nomg_nolen(buf) ;
749 s->stream.avail_in = SvCUR(buf);
751 /* and retrieve the output buffer */
752 output = deRef_l(output, "bzinflate") ;
753 #ifdef UTF8_AVAILABLE
756 if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1))
757 croak("Wide character in " UNCOMPRESS_CLASS "::bzinflate output parameter");
759 if((s->flags & FLAG_APPEND_OUTPUT) != FLAG_APPEND_OUTPUT) {
760 SvCUR_set(output, 0);
763 /* Assume no output buffer - the code below will update if there is any available */
764 s->stream.avail_out = 0;
767 prefix_length = cur_length = SvCUR(output) ;
769 if (s->flags & FLAG_LIMIT_OUTPUT && SvLEN(output) - cur_length - 1 < bufinc)
771 Sv_Grow(output, bufinc + cur_length + 1) ;
774 /* Only setup the stream output pointers if there is spare
775 capacity in the outout SV
777 if (SvLEN(output) > cur_length + 1)
779 s->stream.next_out = (char*) SvPVX(output) + cur_length;
780 increment = SvLEN(output) - cur_length - 1;
781 s->stream.avail_out = increment;
785 s->bytesInflated = 0;
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 ;
797 s->stream.avail_out = increment;
801 /* DispStream(s, "pre"); */
802 RETVAL = BZ2_bzDecompress (&(s->stream));
805 printf("Status %d\n", RETVAL);
806 DispStream(s, "apres");
808 if (RETVAL != BZ_OK || s->flags & FLAG_LIMIT_OUTPUT)
811 if (s->stream.avail_out == 0)
814 if (s->stream.avail_in == 0) {
821 s->last_error = RETVAL ;
822 if (RETVAL == BZ_OK || RETVAL == BZ_STREAM_END) {
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 ;
830 SvCUR_set(output, prefix_length + s->bytesInflated) ;
831 *SvEND(output) = '\0';
832 #ifdef UTF8_AVAILABLE
834 sv_utf8_upgrade(output);
838 /* fix the input buffer */
839 if (s->flags & FLAG_CONSUME_INPUT) {
840 in = s->stream.avail_in ;
843 Move(s->stream.next_in, SvPVX(buf), in, char) ;
853 Compress::Raw::Bunzip2 s
855 RETVAL = s->bytesInflated;
862 Compress::Raw::Bunzip2 s
864 BZ2_bzDecompressEnd(&s->stream) ;
870 Compress::Raw::Bunzip2 s
872 RETVAL = s->last_error ;
878 Compress::Raw::Bunzip2 s
880 RETVAL = s->stream.total_in_lo32 ;
886 Compress::Raw::Bunzip2 s
888 RETVAL = s->stream.total_out_lo32 ;
894 Compress::Raw::Bunzip2 s
896 RETVAL = s->compressedBytes;
902 Compress::Raw::Bunzip2 s
904 RETVAL = s->uncompressedBytes;
908 MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2 PREFIX = Zip_