summaryrefslogtreecommitdiff
path: root/Bzip2.xs
diff options
context:
space:
mode:
Diffstat (limited to 'Bzip2.xs')
-rw-r--r--Bzip2.xs2619
1 files changed, 2619 insertions, 0 deletions
diff --git a/Bzip2.xs b/Bzip2.xs
new file mode 100644
index 0000000..b675820
--- /dev/null
+++ b/Bzip2.xs
@@ -0,0 +1,2619 @@
+/* Bzip2.xs -- Bzip2 bindings for Perl5 -- -*- mode: c -*- */
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include "ppport.h"
+
+#include <bzlib.h>
+
+#include "const-c.inc"
+
+typedef unsigned char Bool;
+
+#define True ((Bool)1)
+#define False ((Bool)0)
+
+#define BZ_IO_EOF (-100)
+
+#define BZERRNO "Compress::Bzip2::bzerrno"
+int global_bzip_errno = 0;
+
+#define BZ_SETERR(obj, eee, infomsg) bzfile_seterror(obj, eee, infomsg)
+
+#define OPEN_STATUS_ISCLOSED 0
+#define OPEN_STATUS_READ 1
+#define OPEN_STATUS_WRITE 2
+#define OPEN_STATUS_WRITESTREAM 3
+#define OPEN_STATUS_READSTREAM 4
+
+typedef struct bzFile_s {
+ bz_stream strm;
+ PerlIO* handle;
+ int bzip_errno;
+
+ char bufferOfCompressed[BZ_MAX_UNUSED];
+ int nCompressed;
+ int compressedOffset_addmore;
+ int compressedOffset_takeout;
+
+ char bufferOfHolding[BZ_MAX_UNUSED];
+ int nHolding;
+
+ char bufferOfLines[BZ_MAX_UNUSED];
+ int bufferOffset;
+ int nBufferBytes;
+
+ char* streamBuf;
+ int streamBufSize;
+ int streamBufLen;
+ int streamBufOffset;
+
+ int open_status;
+ int run_progress;
+ int io_error;
+ Bool pending_io_error;
+
+ Bool allowUncompressedRead;
+ Bool notCompressed;
+ int scan_BZh9;
+ char BZh9[5];
+ int BZh9_count;
+
+ int verbosity;
+ int small;
+ int blockSize100k;
+ int workFactor;
+
+ long total_in;
+ long total_out;
+} bzFile ;
+
+typedef bzFile* Compress__Bzip2;
+
+#ifdef CAN_PROTOTYPE
+void bzfile_streambuf_set( bzFile* obj, char* buffer, int bufsize );
+int bzfile_closeread( bzFile* obj, int abandon );
+int bzfile_closewrite( bzFile* obj, int abandon );
+int bzfile_read( bzFile* obj, char *bufferOfUncompress, int nUncompress );
+#else
+void bzfile_streambuf_set( );
+int bzfile_closeread( );
+int bzfile_closewrite( );
+int bzfile_read( );
+#endif
+
+
+static SV*
+#ifdef CAN_PROTOTYPE
+deRef(SV * sv, char * string)
+#else
+deRef(sv, string)
+SV * sv ;
+char * string;
+#endif
+{
+ SV *last_sv = NULL;
+
+ while(SvROK(sv) && sv != last_sv) {
+ last_sv = sv;
+ sv = SvRV(sv) ;
+ switch(SvTYPE(sv)) {
+ case SVt_PVAV:
+ case SVt_PVHV:
+ case SVt_PVCV:
+ croak("%s: buffer parameter is not a SCALAR reference", string);
+ break;
+ default:
+ ;
+ }
+ /* if (SvROK(sv))
+ croak("%s: buffer parameter is a reference to a reference", string) ;*/
+ }
+
+ if (!SvOK(sv)) croak("%s: buffer parameter is not a SCALAR reference", string);
+ /*sv = newSVpv("", 0);*/
+
+ return sv ;
+}
+
+static char *bzerrorstrings[] = {
+ "OK"
+ ,"SEQUENCE_ERROR"
+ ,"PARAM_ERROR"
+ ,"MEM_ERROR"
+ ,"DATA_ERROR"
+ ,"DATA_ERROR_MAGIC"
+ ,"IO_ERROR"
+ ,"UNEXPECTED_EOF"
+ ,"OUTBUFF_FULL"
+ ,"CONFIG_ERROR"
+ ,"???" /* for future */
+ ,"???" /* for future */
+ ,"???" /* for future */
+ ,"???" /* for future */
+ ,"???" /* for future */
+ ,"???" /* for future */
+};
+
+
+/* memory allocator */
+static void*
+#ifdef CAN_PROTOTYPE
+bzmemalloc(void* opaque, int n, int m)
+#else
+bzalloc(opaque,n,m) void* opaque; int n; int m;
+#endif
+{
+ New(0,opaque,n*m,char);
+ return opaque;
+}
+
+/* memory deallocator */
+static void
+#ifdef CAN_PROTOTYPE
+bzmemfree(void* opaque, void* p)
+#else
+bzfree(opaque, p) void* opaque; void* p;
+#endif
+{
+ Safefree(p);
+}
+
+int
+#ifdef CAN_PROTOTYPE
+bzfile_seterror(bzFile* obj, int error_num, char *error_info)
+#else
+bzfile_seterror(obj, error_num, error_info)
+bzFile* obj;
+int error_num;
+char* error_info;
+#endif
+{
+ char *errstr ;
+ SV * bzerror_sv = perl_get_sv(BZERRNO, FALSE) ;
+
+ global_bzip_errno = error_num;
+ sv_setiv(bzerror_sv, error_num) ; /* set the integer part of the perl thing */
+
+ errstr = error_num * -1 < 0 || error_num * -1 > 9 ? "Unknown" : (char *) bzerrorstrings[ error_num * -1 ];
+
+ if ( obj!=NULL ) {
+ obj->bzip_errno = error_num;
+ obj->io_error = error_num == BZ_IO_ERROR ? errno : 0;
+ }
+
+ /* set the string part of the perl thing */
+ if ( error_info == NULL ) {
+ if (error_num == BZ_IO_ERROR)
+ sv_setpvf(bzerror_sv, "%s (%d): %d %s", errstr, error_num, errno, Strerror(errno));
+ else
+ sv_setpvf(bzerror_sv, "%s (%d)", errstr, error_num);
+ }
+ else {
+ if (error_num == BZ_IO_ERROR)
+ sv_setpvf(bzerror_sv, "%s (%d): %s - %d %s", errstr, error_num, error_info, errno, Strerror(errno));
+ else
+ sv_setpvf(bzerror_sv, "%s (%d): %s", errstr, error_num, error_info);
+ }
+
+ SvIOK_on(bzerror_sv) ; /* say "I AM INTEGER (too)" */
+
+ return error_num;
+}
+
+#ifdef CAN_PROTOTYPE
+PerlIO* bzfile_getiohandle( bzFile *obj ) {
+#else
+PerlIO* bzfile_getiohandle( obj ) bzFile *obj; {
+#endif
+ return obj->handle;
+}
+
+#ifdef CAN_PROTOTYPE
+Bool bzfile_error( bzFile *obj ) {
+#else
+Bool bzfile_error( obj ) bzFile *obj; {
+#endif
+ return obj!=NULL ? ( obj->bzip_errno ? True : False ) : global_bzip_errno ? True : False;
+}
+
+#ifdef CAN_PROTOTYPE
+int bzfile_geterrno( bzFile *obj ) {
+#else
+int bzfile_geterrno( obj ) bzFile *obj; {
+#endif
+ return obj==NULL ? global_bzip_errno : obj->bzip_errno;
+}
+
+#ifdef CAN_PROTOTYPE
+const char *bzfile_geterrstr( bzFile *obj ) {
+#else
+const char *bzfile_geterrstr( obj ) bzFile *obj; {
+#endif
+ int error_num = obj==NULL ? global_bzip_errno : obj->bzip_errno;
+ char *errstr = error_num * -1 < 0 || error_num * -1 > 9 ? "Unknown" : (char *) bzerrorstrings[ error_num * -1 ];
+ return errstr;
+}
+
+#ifdef CAN_PROTOTYPE
+Bool bzfile_eof( bzFile *obj ) {
+#else
+Bool bzfile_eof( obj ) bzFile *obj; {
+#endif
+ return obj==NULL ? False :
+ obj->bzip_errno == BZ_UNEXPECTED_EOF ? True :
+ obj->bzip_errno == BZ_OK && obj->pending_io_error && obj->io_error == BZ_IO_EOF ? True :
+ obj->bzip_errno != BZ_IO_ERROR ? False :
+ obj->io_error == BZ_IO_EOF ? True : False;
+}
+
+#ifdef CAN_PROTOTYPE
+long bzfile_total_in( bzFile *obj ) {
+#else
+long bzfile_total_in( obj ) bzFile *obj; {
+#endif
+ return obj->total_in;
+}
+
+#ifdef CAN_PROTOTYPE
+long bzfile_total_out( bzFile *obj ) {
+#else
+long bzfile_total_out( obj ) bzFile *obj; {
+#endif
+ return obj->total_out;
+}
+
+#ifdef CAN_PROTOTYPE
+long bzfile_clear_totals( bzFile *obj ) {
+#else
+long bzfile_clear_totals( obj ) bzFile *obj; {
+#endif
+ obj->total_in = 0;
+ obj->total_out = 0;
+ return 0;
+}
+
+#ifdef CAN_PROTOTYPE
+int bzfile_clearerr( bzFile *obj ) {
+#else
+int bzfile_clearerr( obj ) bzFile *obj; {
+#endif
+ int error_num = obj == NULL ? global_bzip_errno : obj->bzip_errno;
+ int clear_flag = 1;
+
+ if ( error_num == BZ_IO_ERROR ) {
+ PerlIO_clearerr( obj->handle );
+ }
+ else if ( error_num == BZ_SEQUENCE_ERROR ) {
+ /* program error */
+ }
+ else if ( error_num == BZ_PARAM_ERROR ) {
+ /* program error */
+ }
+ else if ( error_num == BZ_MEM_ERROR ) {
+ clear_flag = 0; /* must close */
+ }
+ else if ( error_num == BZ_DATA_ERROR ) {
+ clear_flag = 0; /* must close or flush */
+ }
+ else if ( error_num == BZ_DATA_ERROR_MAGIC ) {
+ clear_flag = 0; /* must close or flush */
+ }
+ else if ( error_num == BZ_UNEXPECTED_EOF ) {
+ clear_flag = 0; /* must close */
+ }
+ else if ( error_num == BZ_OUTBUFF_FULL ) {
+ }
+ else if ( error_num == BZ_CONFIG_ERROR ) {
+ clear_flag = 0; /* we don't like the version of bzlib */
+ }
+ else if ( error_num == BZ_OK ) {
+ if ( obj->pending_io_error ) {
+ if ( obj->io_error == BZ_IO_EOF ) {
+ PerlIO_clearerr( obj->handle );
+ clear_flag = 0;
+ }
+ }
+ else {
+ clear_flag = 0; /* this is a state, not an error */
+ return 1; /* but return success anyways */
+ }
+ }
+ else if ( error_num == BZ_RUN_OK ) {
+ clear_flag = 0; /* this is a state, not an error */
+ }
+ else if ( error_num == BZ_FLUSH_OK ) {
+ clear_flag = 0; /* this is a state, not an error */
+ }
+ else if ( error_num == BZ_FINISH_OK ) {
+ clear_flag = 0; /* this is a state, not an error */
+ }
+ else if ( error_num == BZ_STREAM_END ) {
+ clear_flag = 0; /* this is a state, not an error */
+ }
+
+ if ( clear_flag ) {
+ if ( obj != NULL ) {
+ obj->bzip_errno = 0;
+ obj->io_error = 0;
+ obj->pending_io_error = False;
+ }
+
+ global_bzip_errno = 0;
+ }
+
+ return clear_flag;
+}
+
+#ifdef CAN_PROTOTYPE
+bzFile* bzfile_new( int verbosity, int small, int blockSize100k, int workFactor ) {
+#else
+bzFile* bzfile_new( verbosity, small, blockSize100k, workFactor )
+ int verbosity; int small; int blockSize100k; int workFactor; {
+#endif
+ bzFile* obj = NULL;
+
+ /* creates a new bzFile object */
+ /* sets parameters */
+
+ if (small != 0 && small != 1) {
+ BZ_SETERR(NULL, BZ_PARAM_ERROR, "bzfile_new small out of range");
+ return NULL;
+ }
+ if (verbosity < 0 || verbosity > 4) {
+ BZ_SETERR(NULL, BZ_PARAM_ERROR, "bzfile_new verbosity out of range");
+ return NULL;
+ }
+
+ Newz(idthing, obj, 1, bzFile);
+
+ BZ_SETERR(obj, BZ_OK, NULL);
+
+ obj->open_status = OPEN_STATUS_ISCLOSED;
+ obj->run_progress = 0;
+ obj->io_error = 0;
+ obj->pending_io_error = False;
+ obj->handle = NULL;
+ obj->nCompressed = 0;
+ obj->compressedOffset_addmore = 0;
+ obj->compressedOffset_takeout = 0;
+ obj->verbosity = verbosity;
+ obj->small = small;
+ obj->blockSize100k = blockSize100k;
+ obj->workFactor = workFactor;
+
+ obj->bufferOffset = 0;
+ obj->nBufferBytes = 0;
+
+ obj->bzip_errno = 0;
+
+ obj->total_in = 0;
+ obj->total_out = 0;
+
+ obj->strm.bzalloc = bzmemalloc;
+ obj->strm.bzfree = bzmemfree;
+ obj->strm.opaque = NULL;
+
+ obj->allowUncompressedRead = False;
+
+ bzfile_streambuf_set( obj, NULL, 0 );
+
+ if (obj->verbosity >= 4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_new(%d,%d,%d,%d) called %p\n", verbosity, small, blockSize100k, workFactor, obj);
+
+ return obj;
+}
+
+#ifdef CAN_PROTOTYPE
+void bzfile_free( bzFile* obj ) {
+#else
+void bzfile_free( obj ) bzFile* obj; {
+#endif
+ if ( obj!=NULL ) Safefree((void*) obj);
+}
+
+/* query and/or set param setting of bzFile */
+/* param may be verbosity, small, blockSize100k or workFactor */
+/* if setting is -1, the param is not changed, but the current value is returned */
+/* returns -1 on error */
+#ifdef CAN_PROTOTYPE
+int bzfile_setparams( bzFile* obj, char* param, int setting ) {
+#else
+int bzfile_setparams( obj, param, setting ) bzFile* obj; char* param; int setting; {
+#endif
+ int savsetting = -1;
+
+ if ( param[0] == '-' ) param++;
+ if ( param[0] == '-' ) param++;
+
+ if ( strEQ( param, "verbosity" ) ) {
+ savsetting = obj->verbosity;
+
+ if ( setting >= 0 && setting <= 4 )
+ obj->verbosity = setting;
+ else if ( setting != -1 ) {
+ BZ_SETERR(obj, BZ_PARAM_ERROR, NULL);
+ savsetting = -1;
+ }
+ }
+ else if ( strEQ( param, "buffer" ) ) {
+ savsetting = BZ_MAX_UNUSED;
+ }
+ else if ( strEQ( param, "small" ) ) {
+ savsetting = obj->small;
+
+ if ( setting == 0 || setting == 1 )
+ obj->small = setting;
+ else if ( setting != -1 ) {
+ BZ_SETERR(obj, BZ_PARAM_ERROR, NULL);
+ savsetting = -1;
+ }
+ }
+ else if ( strEQ( param, "blockSize100k" ) || strEQ( param, "level" ) ) {
+ savsetting = obj->blockSize100k;
+
+ if ( setting >= 1 && setting <= 9 )
+ obj->blockSize100k = setting;
+ else if ( setting != -1 ) {
+ BZ_SETERR(obj, BZ_PARAM_ERROR, NULL);
+ savsetting = -1;
+ }
+ }
+ else if ( strEQ( param, "workFactor" ) ) {
+ savsetting = obj->workFactor;
+
+ if ( setting >= 0 && setting <= 250 )
+ obj->workFactor = setting;
+ else if ( setting != -1 ) {
+ BZ_SETERR(obj, BZ_PARAM_ERROR, NULL);
+ savsetting = -1;
+ }
+ }
+ else if ( strEQ( param, "readUncompressed" ) ) {
+ savsetting = obj->allowUncompressedRead ? 1 : 0;
+
+ if ( setting >= 0 && setting <= 1 )
+ obj->allowUncompressedRead = setting ? True : False;
+ else if ( setting != -1 ) {
+ BZ_SETERR(obj, BZ_PARAM_ERROR, NULL);
+ savsetting = -1;
+ }
+ }
+ else {
+ BZ_SETERR(obj, BZ_PARAM_ERROR, NULL);
+ savsetting = -1;
+ }
+
+ if (obj->verbosity>1) {
+ if ( savsetting == -1 )
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_setparams invalid param %s => %d\n", param, setting);
+ else
+ if ( setting == -1 )
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_setparams query %s is %d\n", param, savsetting);
+ else
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_setparams set %s (is %d) => %d\n", param, savsetting, setting);
+ }
+ return savsetting;
+}
+
+#ifdef CAN_PROTOTYPE
+bzFile* bzfile_open( char *filename, char *mode, bzFile *obj ) {
+#else
+bzFile* bzfile_open( filename, mode, obj ) char *filename; char *mode; bzFile *obj; {
+#endif
+ PerlIO *io;
+
+ io = PerlIO_open( filename, mode );
+ if ( io == NULL ) {
+ BZ_SETERR(obj, BZ_IO_ERROR, NULL);
+
+ if (obj && obj->verbosity > 0) warn( "Error: PerlIO_open( %s, %s ) failed: %s\n", filename, mode, Strerror(errno) );
+
+ return NULL;
+ }
+
+#if defined(_WIN32) || defined(OS2) || defined(MSDOS) || defined(__CYGWIN__) || defined(WIN32)
+ PerlIO_binmode(aTHX_ io, mode[0]=='w' ? '>' : '<', O_BINARY, Nullch);
+#endif
+
+ if ( obj == NULL ) obj = bzfile_new( 0, 0, 9, 0 );
+
+ obj->handle = io;
+ obj->open_status = mode && mode[0] == 'w' ? OPEN_STATUS_WRITE : OPEN_STATUS_READ;
+
+ if (obj->verbosity>=2)
+ PerlIO_printf(PerlIO_stderr(), "Info: PerlIO_open( %s, %s ) succeeded, obj=%p\n", filename, mode, obj );
+
+ return obj;
+}
+
+#ifdef CAN_PROTOTYPE
+bzFile* bzfile_fdopen( PerlIO *io, char *mode, bzFile *obj ) {
+#else
+bzFile* bzfile_fdopen( io, mode, obj ) PerlIO *io; char *mode; bzFile *obj; {
+#endif
+
+ if ( io == NULL ) {
+ BZ_SETERR(obj, BZ_PARAM_ERROR, NULL);
+ return NULL;
+ }
+
+#if defined(_WIN32) || defined(OS2) || defined(MSDOS) || defined(__CYGWIN__) || defined(WIN32)
+ PerlIO_binmode(aTHX_ io, mode[0]=='w' ? '>' : '<', O_BINARY, Nullch);
+#endif
+
+ if ( obj == NULL ) obj = bzfile_new( 0, 0, 9, 0 );
+
+ obj->handle = io;
+ obj->open_status = mode && mode[0] == 'w' ? OPEN_STATUS_WRITE : OPEN_STATUS_READ;
+
+ return obj;
+}
+
+#ifdef CAN_PROTOTYPE
+bzFile* bzfile_openstream( char *mode, bzFile *obj ) {
+#else
+bzFile* bzfile_openstream( mode, obj ) char *mode; bzFile *obj; {
+#endif
+ if ( obj == NULL ) obj = bzfile_new( 0, 0, 1, 0 );
+ if ( obj == NULL ) return NULL;
+
+ obj->open_status = mode && mode[0] == 'w' ? OPEN_STATUS_WRITESTREAM : OPEN_STATUS_READSTREAM;
+
+ return obj;
+}
+
+#ifdef CAN_PROTOTYPE
+void bzfile_streambuf_deposit( bzFile* obj, char* buffer, int buflen ) {
+#else
+void bzfile_streambuf_deposit( obj, buffer, buflen ) bzFile* obj; char* buffer; int buflen; {
+#endif
+ /* inflate */
+ /* insert compressed data into reading stream */
+ obj->streamBuf = buffer;
+ obj->streamBufSize = buflen;
+ obj->streamBufLen = buflen;
+ obj->streamBufOffset = 0;
+}
+
+#ifdef CAN_PROTOTYPE
+int bzfile_streambuf_read( bzFile* obj, char* out, int outlen ) {
+#else
+int bzfile_streambuf_read( obj, out, outlen ) bzFile* obj; char* out; int outlen; {
+#endif
+ /* inflate */
+ /* read compressed data from buffer */
+ char *in;
+ int i;
+ int n = obj->streamBufLen - obj->streamBufOffset;
+
+ if (obj->verbosity>=4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_streambuf_read( %p, %d ), buffer %p, sz=%d, len=%d, offset=%d\n",
+ out, outlen, obj->streamBuf, obj->streamBufSize, obj->streamBufLen, obj->streamBufOffset );
+
+ if ( n <= 0 ) {
+ /* EAGAIN */
+ errno = EAGAIN;
+ return -1;
+ }
+
+ in = obj->streamBuf + obj->streamBufOffset;
+
+ for ( i=0; i<outlen && i<n; i++)
+ *out++ = *in++;
+
+ obj->streamBufOffset += i;
+
+ return i;
+}
+
+#ifdef CAN_PROTOTYPE
+void bzfile_streambuf_set( bzFile* obj, char* buffer, int bufsize ) {
+#else
+void bzfile_streambuf_set( obj, buffer, bufsize ) bzFile* obj; char* buffer; int bufsize; {
+#endif
+ /* deflate */
+ obj->streamBuf = buffer;
+ obj->streamBufSize = bufsize;
+ obj->streamBufLen = 0;
+ obj->streamBufOffset = 0;
+}
+
+#ifdef CAN_PROTOTYPE
+int bzfile_streambuf_write( bzFile* obj, char* in, int inlen ) {
+#else
+int bzfile_streambuf_write( obj, in, inlen ) bzFile* obj; char* in; int inlen; {
+#endif
+ /* deflate */
+ /* write compressed data to buffer */
+
+ char *out;
+ int i;
+ int available_space = obj->streamBufSize - obj->streamBufLen;
+
+ if (obj->verbosity>=4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_streambuf_write( %p, %d ), buffer %p, sz=%d, len=%d, offset=%d\n",
+ in, inlen, obj->streamBuf, obj->streamBufSize, obj->streamBufLen, obj->streamBufOffset );
+
+ if ( available_space <= 0 ) {
+ errno = EAGAIN;
+ return -1; /* EAGAIN */
+ }
+
+ out = obj->streamBuf + obj->streamBufOffset;
+
+ for ( i=0; i<inlen && i<available_space; i++)
+ *out++ = *in++;
+
+ obj->streamBufLen += i;
+
+ return i;
+}
+
+#ifdef CAN_PROTOTYPE
+int bzfile_streambuf_collect( bzFile* obj, char* out, int outlen ) {
+#else
+int bzfile_streambuf_collect( obj, out, outlen ) bzFile* obj; char* out; int outlen; {
+#endif
+ /* deflate */
+ /* pull collected compressed data from buffer */
+ int ret;
+
+ ret = bzfile_streambuf_read( obj, out, outlen );
+
+ if ( ret == -1 ) {
+ /* got all the data out, reset the counters */
+ obj->streamBufLen = 0;
+ obj->streamBufOffset = 0;
+ }
+
+ return ret;
+}
+
+/* success: 0 returned */
+/* failure: -1 returned, global error set */
+/* other error: -2 returned, global error already set */
+#ifdef CAN_PROTOTYPE
+int bzfile_flush( bzFile* obj ) {
+#else
+int bzfile_flush( obj ) bzFile* obj; {
+#endif
+ int error_num = bzfile_geterrno( obj );
+ int tracker;
+ int compressed_bytes_count;
+
+ if ( obj == NULL ) return 0;
+ if ( obj->run_progress == 0 || obj->run_progress == 10 ) return 0;
+
+ if (obj->verbosity>=4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_flush called, error_num=%d, open_status %d\n",
+ error_num, obj->open_status);
+
+ if ( error_num == BZ_OK ) {
+ }
+ else if ( error_num == BZ_IO_ERROR ) {
+ if ( obj->io_error == EAGAIN || obj->io_error == EINTR ) {
+ obj->io_error = 0;
+ BZ_SETERR(obj, BZ_OK, NULL);
+ }
+ else if ( obj->io_error == BZ_IO_EOF ) {
+ PerlIO_clearerr( obj->handle );
+ }
+ else {
+ return -2;
+ }
+ }
+ else if ( error_num == BZ_DATA_ERROR ) {
+ /* a read error */
+ }
+ else if ( error_num == BZ_UNEXPECTED_EOF ) {
+ /* a read error */
+ }
+ else if ( error_num == BZ_OUTBUFF_FULL ) {
+ /* only when compressing or decompressing a buffer */
+ return -2;
+ }
+ else {
+ return -2;
+ }
+
+ if (obj->open_status == OPEN_STATUS_WRITE || obj->open_status == OPEN_STATUS_WRITESTREAM) {
+ int ret = BZ_OK;
+
+ while (True) {
+ obj->strm.next_out = obj->bufferOfCompressed + obj->compressedOffset_addmore;
+ obj->strm.avail_out = sizeof(obj->bufferOfCompressed) - obj->compressedOffset_addmore;
+
+ if (obj->verbosity>=4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_flush: call to BZ2_bzCompress with avail_in %d, next_in %p, avail_out %d, next_out %p, run_progress %d\n",
+ obj->strm.avail_in, obj->strm.next_in, obj->strm.avail_out, obj->strm.next_out, obj->run_progress);
+
+ compressed_bytes_count = obj->strm.avail_out;
+ tracker = obj->strm.avail_in;
+
+ if ( obj->strm.avail_out <= 0 || obj->run_progress > 2 )
+ ret = obj->run_progress <= 2 ? BZ_FLUSH_OK : BZ_RUN_OK;
+ else {
+ ret = BZ2_bzCompress( &(obj->strm), BZ_FLUSH );
+ if ( ret == BZ_RUN_OK ) obj->run_progress = 3;
+ }
+
+ if (ret != BZ_RUN_OK && ret != BZ_FLUSH_OK) {
+ BZ_SETERR(obj, ret, NULL);
+
+ if (obj->verbosity>1)
+ warn("Error: bzfile_flush, BZ2_bzCompress error %d, strm is %p, strm.state is %p, in state %d\n",
+ ret, &(obj->strm), obj->strm.state, *((int*)obj->strm.state));
+
+ return -1;
+ }
+
+ obj->total_in += tracker - obj->strm.avail_in;
+ compressed_bytes_count -= obj->strm.avail_out;
+ obj->compressedOffset_addmore += compressed_bytes_count;
+ obj->nCompressed += compressed_bytes_count;
+
+ if (obj->verbosity>=4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_flush BZ2_bzCompress, took in %d, put out %d bytes, ret %d\n",
+ tracker-obj->strm.avail_in, compressed_bytes_count, ret);
+
+ if ( obj->nCompressed ) {
+ int n, n2;
+
+ n = obj->nCompressed;
+
+ while ( n > 0 ) {
+ if ( obj->open_status == OPEN_STATUS_WRITESTREAM )
+ n2 = bzfile_streambuf_write( obj, obj->bufferOfCompressed + obj->compressedOffset_takeout, n );
+ else
+ if ( obj->handle )
+ n2 = PerlIO_write( obj->handle, obj->bufferOfCompressed + obj->compressedOffset_takeout, n );
+ else
+ n2 = n;
+
+ if ( n2==-1 ) {
+ BZ_SETERR(obj, BZ_IO_ERROR, NULL);
+
+ if ( errno != EINTR && errno != EAGAIN ) {
+ if (obj->verbosity>0)
+ warn("Error: bzfile_flush io error %d '%s'\n", errno, Strerror(errno));
+ }
+ else {
+ if (obj->verbosity>=4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_flush: file write error %s\n", Strerror(errno));
+ }
+
+ return -1;
+ }
+ else {
+ if (obj->verbosity>=4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_flush: file write took in %d, put out %d\n", n, n2);
+
+ obj->compressedOffset_takeout += n2;
+ obj->nCompressed -= n2;
+ n -= n2;
+
+ obj->total_out += n2;
+ }
+ }
+
+ obj->nCompressed = 0;
+ obj->compressedOffset_addmore = 0;
+ obj->compressedOffset_takeout = 0;
+ }
+
+ if (obj->verbosity>1)
+ PerlIO_printf(PerlIO_stderr(), "Info: bzfile_flush ret %d, total written %ld\n", ret, obj->total_out );
+
+ if (ret == BZ_RUN_OK) {
+ obj->run_progress = 1;
+ break;
+ }
+ }
+
+ if ( obj->handle && !PerlIO_error( obj->handle ) ) {
+ /* ok, we got bzip flushed out, now flush out the IO buffers themselves */
+ if ( -1 == PerlIO_flush( obj->handle ) ) {
+ BZ_SETERR(obj, BZ_IO_ERROR, NULL);
+ return -1;
+ }
+ }
+ }
+ else {
+ /* decompressing from a read IO handle */
+
+ obj->nBufferBytes = 0; /* toss getreadline data */
+ /* can't flush the file handle, that will cause the compression stream to break up */
+ /* the program will be unable to uncompress subsequent data, up to the next checkpoint */
+
+ if ( error_num == BZ_DATA_ERROR ) {
+ /* a read error */
+ /* could look ahead for that 49 bit pattern ... */
+ return -2; /* for now */
+ }
+ else if ( error_num == BZ_UNEXPECTED_EOF ) {
+ return -2;
+ }
+ }
+
+ return 0;
+}
+
+#ifdef CAN_PROTOTYPE
+int bzfile_close( bzFile* obj, int abandon ) {
+#else
+int bzfile_close( obj, abandon ) bzFile* obj; int abandon; {
+#endif
+ /* returns zero on success, -1 on error */
+ int ret;
+
+ if ( obj->open_status == OPEN_STATUS_ISCLOSED ) {
+ BZ_SETERR(obj, BZ_SEQUENCE_ERROR, NULL);
+ return -1;
+ }
+
+ if (obj->open_status == OPEN_STATUS_WRITE || obj->open_status == OPEN_STATUS_WRITESTREAM)
+ ret = bzfile_closewrite( obj, abandon );
+ else
+ ret = bzfile_closeread( obj, abandon );
+
+ if ( ret == BZ_OK ) obj->open_status = OPEN_STATUS_ISCLOSED;
+
+ return ret != BZ_OK ? -1 : 0;
+}
+
+#ifdef CAN_PROTOTYPE
+int bzfile_closeread( bzFile* obj, int abandon ) {
+#else
+int bzfile_closeread( obj, abandon ) bzFile* obj; int abandon; {
+#endif
+ int ret = BZ_OK;
+
+ if (obj->open_status == OPEN_STATUS_WRITE || obj->open_status == OPEN_STATUS_WRITESTREAM)
+ return BZ_SETERR(obj, BZ_SEQUENCE_ERROR, NULL);
+
+ if ( obj->run_progress!=0 && obj->run_progress!=10 )
+ ret = BZ2_bzDecompressEnd( &(obj->strm) );
+
+ obj->run_progress = 0;
+ obj->nBufferBytes = 0; /* toss getreadline data */
+ obj->pending_io_error = False;
+
+ if ( obj->handle )
+ if ( 0 != PerlIO_close( obj->handle ) )
+ ret = BZ_SETERR(obj, BZ_IO_ERROR, NULL);
+
+ return BZ_SETERR(obj, ret, NULL);
+}
+
+#ifdef CAN_PROTOTYPE
+int bzfile_closewrite( bzFile* obj, int abandon ) {
+#else
+int bzfile_closewrite( obj, abandon ) bzFile* obj; int abandon; {
+#endif
+ int error_num = bzfile_geterrno( obj );
+ int ret = BZ_OK;
+ int tracker;
+ int compressed_bytes_count;
+
+ if (obj->verbosity>=2)
+ PerlIO_printf(PerlIO_stderr(), "Info: bzfile_closewrite called, abandon=%d, error_num=%d, open_status %d\n",
+ abandon, error_num, obj->open_status);
+
+ if ( obj == NULL ) return BZ_SETERR(NULL, BZ_OK, NULL);
+ if (obj->open_status != OPEN_STATUS_WRITE && obj->open_status != OPEN_STATUS_WRITESTREAM)
+ return BZ_SETERR(obj, BZ_SEQUENCE_ERROR, NULL);
+
+ if ( error_num == BZ_OK ) {
+ }
+ else if ( error_num == BZ_IO_ERROR ) {
+ if ( obj->io_error == EAGAIN || obj->io_error == EINTR ) {
+ obj->io_error = 0;
+ BZ_SETERR(obj, BZ_OK, NULL);
+ }
+ else if ( !abandon )
+ return error_num;
+ }
+ else if ( error_num == BZ_DATA_ERROR ) {
+ /* a read error */
+ if ( !abandon ) return error_num;
+ }
+ else if ( error_num == BZ_UNEXPECTED_EOF ) {
+ /* a read error */
+ if ( !abandon ) return error_num;
+ }
+ else if ( error_num == BZ_OUTBUFF_FULL ) {
+ /* only when compressing or decompressing a buffer */
+ if ( !abandon ) return error_num;
+ }
+ else {
+ if ( !abandon ) return error_num;
+ }
+
+ if ( obj->run_progress!=0 ) {
+ if ( !abandon ) {
+ while (True) {
+ obj->strm.next_out = obj->bufferOfCompressed + obj->compressedOffset_addmore;
+ obj->strm.avail_out = sizeof(obj->bufferOfCompressed) - obj->compressedOffset_addmore;
+
+ if (obj->verbosity>=4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_closewrite: call to BZ2_bzCompress with avail_in %d, next_in %p, avail_out %d, next_out %p, run_progress %d\n",
+ obj->strm.avail_in, obj->strm.next_in, obj->strm.avail_out, obj->strm.next_out, obj->run_progress);
+
+ compressed_bytes_count = obj->strm.avail_out;
+ tracker = obj->strm.avail_in;
+
+ if ( obj->strm.avail_out <= 0 || obj->run_progress > 2 )
+ ret = obj->run_progress <= 2 ? BZ_FINISH_OK : BZ_STREAM_END;
+ else {
+ ret = BZ2_bzCompress( &(obj->strm), BZ_FINISH );
+ if ( ret == BZ_STREAM_END ) obj->run_progress = 9;
+ }
+
+ if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) {
+ BZ_SETERR(obj, ret, NULL);
+ if (obj->verbosity>=1)
+ PerlIO_printf(PerlIO_stderr(), "Warning: bzfile_closewrite BZ2_bzCompress error %d\n", ret);
+ return ret;
+ }
+
+ obj->total_in += tracker - obj->strm.avail_in;
+ compressed_bytes_count -= obj->strm.avail_out;
+ obj->compressedOffset_addmore += compressed_bytes_count;
+ obj->nCompressed += compressed_bytes_count;
+
+ if (obj->verbosity>=4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_closewrite BZ2_bzCompress, took in %d, put out %d bytes, ret %d\n",
+ tracker-obj->strm.avail_in, compressed_bytes_count, ret);
+
+ if ( obj->nCompressed ) {
+ int n, n2;
+
+ n = obj->nCompressed;
+
+ while ( n > 0 ) {
+ if ( obj->open_status == OPEN_STATUS_WRITESTREAM )
+ n2 = bzfile_streambuf_write( obj, obj->bufferOfCompressed + obj->compressedOffset_takeout, n );
+ else
+ if ( obj->handle )
+ n2 = PerlIO_write( obj->handle, obj->bufferOfCompressed + obj->compressedOffset_takeout, n );
+ else
+ n2 = n;
+
+ if ( n2==-1 ) {
+ BZ_SETERR(obj, BZ_IO_ERROR, NULL);
+
+ if ( errno != EINTR && errno != EAGAIN ) {
+ if (obj->verbosity>0)
+ warn("Error: bzfile_closewrite io error %d '%s'\n", errno, Strerror(errno));
+ }
+ else {
+ if (obj->verbosity>=4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_closewrite: file write error %s\n", Strerror(errno));
+ }
+
+ return BZ_IO_ERROR;
+ }
+ else {
+ if (obj->verbosity>=4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_closewrite: file write took in %d, put out %d\n", n, n2);
+
+ obj->compressedOffset_takeout += n2;
+ obj->nCompressed -= n2;
+ n -= n2;
+
+ obj->total_out += n2;
+ }
+ }
+
+ obj->nCompressed = 0;
+ obj->compressedOffset_addmore = 0;
+ obj->compressedOffset_takeout = 0;
+ }
+
+ if (obj->verbosity>1)
+ PerlIO_printf(PerlIO_stderr(), "Info: bzfile_closewrite ret %d, total written %ld\n", ret, obj->total_out );
+
+ if (ret == BZ_STREAM_END) break;
+ }
+ }
+
+ ret = BZ2_bzCompressEnd ( &(obj->strm) );
+ obj->run_progress = 0;
+ }
+
+ obj->pending_io_error = False;
+
+ if ( obj->handle )
+ if ( 0 != PerlIO_close( obj->handle ) )
+ ret = BZ_SETERR(obj, BZ_IO_ERROR, NULL);
+
+ return BZ_SETERR(obj, ret, NULL);
+}
+
+#ifdef CAN_PROTOTYPE
+int bzfile_readline( bzFile* obj, char *lineOfUncompress, int maxLineLength ) {
+#else
+int bzfile_readline( obj, lineOfUncompress, maxLineLength ) bzFile* obj; char *lineOfUncompress; int maxLineLength; {
+#endif
+ int n = 0;
+ char *p = NULL;
+ int bytes_read = 0;
+ char lastch = 0;
+ int error_num = 0;
+ int done_flag = 0;
+
+ if ( maxLineLength>0 ) lineOfUncompress[0]=0;
+
+ while ( !done_flag && bytes_read < maxLineLength && lastch != '\n' ) {
+ if ( obj->nBufferBytes - obj->bufferOffset > 0 ) {
+ n = obj->nBufferBytes - obj->bufferOffset;
+ p = obj->bufferOfLines + obj->bufferOffset;
+ }
+ else {
+ n = bzfile_read( obj, obj->bufferOfLines, sizeof(obj->bufferOfLines) );
+ if ( n < 0 ) {
+ error_num = bzfile_geterrno( obj );
+
+ if ( error_num == BZ_IO_ERROR ) {
+ if ( obj->io_error == EINTR || obj->io_error == EAGAIN )
+ continue;
+ done_flag = 1;
+ }
+ else if ( error_num == BZ_UNEXPECTED_EOF ) {
+ done_flag = 1;
+ }
+ else {
+ done_flag = 1;
+ }
+ }
+ else if ( n == 0 ) {
+ done_flag = 1;
+ }
+
+ p = obj->bufferOfLines;
+ obj->bufferOffset = 0;
+ obj->nBufferBytes = n;
+ n = 0;
+ }
+
+ if ( obj->nBufferBytes - obj->bufferOffset > 0 ) {
+ lastch = *p;
+ *lineOfUncompress++ = lastch;
+ bytes_read++;
+ obj->bufferOffset++;
+ }
+ }
+
+ if ( done_flag && bytes_read <= 0 && error_num ) return -1;
+
+ if ( maxLineLength>bytes_read ) lineOfUncompress[bytes_read]=0;
+
+ return bytes_read;
+}
+
+#ifdef CAN_PROTOTYPE
+int bzfile_read_notCompressed( bz_stream* strm, int *scan_BZh9 ) {
+#else
+int bzfile_read_notCompressed( strm, scan_BZh9 ) bz_stream* strm; int *scan_BZh9; {
+#endif
+ char ch;
+
+ while ( strm->avail_in>0 && strm->avail_out>0 ) {
+ ch = *(strm->next_out++) = *(strm->next_in++);
+ strm->avail_in--;
+ strm->avail_out--;
+ switch (*scan_BZh9) {
+ case 0: if ( ch=='B' ) *scan_BZh9=1; break;
+ case 1: *scan_BZh9 = ch=='Z' ? 2 : 0; break;
+ case 2: *scan_BZh9 = ch=='h' ? 3 : 0; break;
+ case 3: *scan_BZh9 = ch-'0'>=1 && ch-'0'<=9 ? ch : 0; break;
+ }
+ }
+
+ if ( *scan_BZh9 > 4 ) return BZ_DATA_ERROR_MAGIC;
+
+ return BZ_OK;
+}
+
+#ifdef CAN_PROTOTYPE
+int bzfile_read( bzFile* obj, char *bufferOfUncompress, int nUncompress ) {
+#else
+int bzfile_read( obj, bufferOfUncompress, nUncompress ) bzFile* obj; char *bufferOfUncompress; int nUncompress; {
+#endif
+ int ret;
+ int tracker, rewind_mark;
+ int bytes_uncompressed_count;
+ int error_num = bzfile_geterrno( obj );
+
+ if (obj == NULL || bufferOfUncompress == NULL || nUncompress < 0) {
+ BZ_SETERR(obj, BZ_PARAM_ERROR, NULL);
+
+ if ( obj != NULL && obj->verbosity>1 ) {
+ if ( bufferOfUncompress == NULL ) warn("Error: bzfile_read buf is NULL\n");
+ if ( nUncompress < 0 ) warn("Error: bzfile_read n is negative %d\n", nUncompress);
+ }
+
+ return -1;
+ }
+ if (obj->verbosity>=4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_read(obj, %p, %d) obj->open_status=%d\n",
+ bufferOfUncompress, nUncompress, obj->open_status);
+
+ if (obj->open_status == OPEN_STATUS_WRITE || obj->open_status == OPEN_STATUS_WRITESTREAM) {
+ BZ_SETERR(obj, BZ_SEQUENCE_ERROR, NULL);
+
+ if ( obj->verbosity>1 ) warn("Error: bzfile_read attempted on a writing stream\n");
+
+ return -1;
+ }
+
+ if ( error_num == BZ_OK ) {
+ if ( obj->pending_io_error ) {
+ if ( obj->io_error == BZ_UNEXPECTED_EOF ) {
+ obj->io_error = 0;
+ BZ_SETERR(obj, BZ_UNEXPECTED_EOF, NULL);
+ }
+ else if ( obj->io_error == BZ_IO_EOF ) {
+ return 0;
+ }
+ else {
+ errno = obj->io_error;
+ obj->io_error = 0;
+ BZ_SETERR(obj, BZ_IO_ERROR, NULL);
+ }
+
+ obj->pending_io_error = False;
+ return -1;
+ }
+ }
+ else if ( error_num == BZ_IO_ERROR ) {
+ if ( obj->io_error == EINTR || obj->io_error == EAGAIN ) {
+ obj->io_error=0;
+ BZ_SETERR(obj, BZ_OK, NULL);
+ }
+ else
+ return -2;
+ }
+ else if ( error_num == BZ_DATA_ERROR ) {
+ /* a read error */
+ return -2;
+ }
+ else if ( error_num == BZ_UNEXPECTED_EOF ) {
+ /* a read error */
+ return -2;
+ }
+ else {
+ return -2;
+ }
+
+ if (nUncompress == 0) return 0;
+
+ BZ_SETERR(obj, BZ_OK, NULL);
+
+ obj->nHolding = 0;
+ bytes_uncompressed_count = 0;
+
+ /********************
+ * note: obj->run_progress is used to detect proper end of file
+ * an end of file that doesn't have an end-of-stream marker is INVALID and a result of data corruption
+ * so, here's the run_progress settings:
+ * 0: stream has never been initialized, a call to BZ2_bzDecompressInit is necessary.
+ * 1: stream has just been initialized, for the first time. No data has yet been read.
+ * 2: stream has been initialized, data has been read from the file handle.
+ * in the middle of processing what is probably a LARGE file:
+ * 10: an end of stream marker has been seen, and BZ2_bzDecompressEnd has been called.
+ * before the stream can be used again, a call to BZ2_bzDecompressInit must be made.
+ * 11: ready to read more data - BZ2_bzDecompressInit has been called (but no data has been read yet)
+ * 12: stream has been initialized, data has been read.
+ * the sequence of changes is
+ * 0 => 1 => 2 => 10 => 11 => 12
+ * A FILE EOF, or PerlIO EOF, is only valid when run_progress is 0 or 10, ie when no data has been read,
+ * or just after we've received a valid end-of-stream marker.
+ */
+
+ while (True) {
+ if ( obj->nBufferBytes - obj->bufferOffset > 0 ) {
+ char *p, *s;
+ int i,n;
+
+ p = obj->bufferOfLines + obj->bufferOffset; /* point to next byte */
+ n = obj->nBufferBytes - obj->bufferOffset; /* count of bytes ready to go */
+
+ /* move as much as we can to the Uncompress hopper */
+ for (i=0; i<n && bytes_uncompressed_count+i < nUncompress; i++) bufferOfUncompress[bytes_uncompressed_count+i] = *p++;
+ bytes_uncompressed_count+=i;
+
+ n -= i; /* update number of bytes still to go */
+ for (s = obj->bufferOfLines; i < n; i++) *s++ = *p++; /* move remaining bytes to top of the buffer */
+ obj->nBufferBytes = n;
+ obj->bufferOffset = 0;
+
+ if (bytes_uncompressed_count >= nUncompress) {
+ BZ_SETERR(obj, BZ_OK, NULL);
+ return bytes_uncompressed_count;
+ }
+ }
+
+ obj->strm.avail_out = nUncompress - bytes_uncompressed_count;
+ obj->strm.next_out = bufferOfUncompress + bytes_uncompressed_count;
+
+ if (obj->strm.avail_in == 0) {
+ char *buf = obj->bufferOfCompressed;
+ int bufln = sizeof(obj->bufferOfCompressed);
+
+ char *p;
+ int i,n;
+
+ if ( obj->nHolding ) {
+ /* move held bytes into the hopper */
+ p = obj->bufferOfHolding;
+ n = obj->nHolding;
+
+ for (i=0; i<n; i++) buf[i] = *p++;
+ obj->nHolding = 0;
+ }
+ else if ( obj->BZh9_count ) {
+ /* move header bytes into the hopper */
+ p = obj->BZh9;
+ n = obj->BZh9_count;
+
+ for (i=0; i<n; i++) buf[i] = *p++;
+ obj->BZh9_count = 0;
+ }
+ else {
+ if ( obj->open_status == OPEN_STATUS_READSTREAM )
+ n = bzfile_streambuf_read( obj, buf, bufln );
+ else
+ n = PerlIO_read( obj->handle, buf, bufln );
+
+ if (obj->verbosity>=4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_read file read got %d bytes\n", n);
+
+ if ( n == -1 ) {
+ if ( bytes_uncompressed_count ) {
+ obj->pending_io_error = True;
+ obj->io_error = errno;
+ n = 0;
+ }
+ else {
+ BZ_SETERR(obj, BZ_IO_ERROR, NULL);
+ return -1;
+ }
+ }
+ else if ( n == 0 ) {
+ /* end of file */
+ }
+ }
+
+ obj->total_in += n;
+ obj->strm.avail_in = obj->nCompressed = n;
+ obj->strm.next_in = obj->bufferOfCompressed;
+ }
+
+ if ( obj->strm.avail_in == 0 ) {
+ /* still zero bytes in the input hopper? why? ... */
+ if ( !obj->pending_io_error ) {
+ if ( obj->run_progress != 0 && obj->run_progress != 10 ) {
+ if ( !bytes_uncompressed_count ) {
+ BZ_SETERR(obj, BZ_UNEXPECTED_EOF, NULL);
+
+ if (obj->verbosity>=2) {
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_read got an unexpected EOF, run_progress=%d, avail_in=%d, avail_out=%d\n",
+ obj->run_progress,
+ obj->strm.avail_in,
+ obj->strm.avail_out
+ );
+ }
+
+ return -1;
+ }
+
+ /* hold off on the BZ_UNEXPECTED_EOF until the caller gets their data */
+ obj->pending_io_error = True;
+ obj->io_error = BZ_UNEXPECTED_EOF;
+
+ if (obj->verbosity>=2) {
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_read got an unexpected EOF, run_progress=%d, set pending with %d bytes to go, avail_in=%d, avail_out=%d\n",
+ obj->run_progress,
+ bytes_uncompressed_count,
+ obj->strm.avail_in,
+ obj->strm.avail_out
+ );
+ }
+ }
+ else {
+ obj->pending_io_error = True;
+ obj->io_error = BZ_IO_EOF;
+
+ if (obj->verbosity>=2) {
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_read got an EOF, run_progress=%d, set pending with %d bytes to go, avail_in=%d, avail_out=%d\n",
+ obj->run_progress,
+ bytes_uncompressed_count,
+ obj->strm.avail_in,
+ obj->strm.avail_out
+ );
+ }
+ }
+ }
+ /* if no io_error is pending, this is a proper end of file */
+ return bytes_uncompressed_count;
+ }
+ else {
+ if ( obj->run_progress == 1 || obj->run_progress == 11 ) {
+ /* indicate we have data to uncompress */
+ obj->run_progress = obj->run_progress == 1 ? 2 : 12;
+ } else if ( obj->run_progress == 0 || obj->run_progress == 10 ) {
+ ret = BZ2_bzDecompressInit ( &(obj->strm), obj->verbosity, obj->small );
+
+ if (ret != BZ_OK) {
+ if (obj->verbosity>1) {
+ warn("Error: bzfile_read: BZ2_bzDecompressInit error %d on %d, %d\n",
+ ret, obj->verbosity, obj->small);
+ }
+
+ BZ_SETERR(obj, ret, NULL);
+ return -1;
+ }
+
+ obj->run_progress = obj->run_progress == 0 ? 1 : 11;
+ obj->notCompressed = False;
+ }
+
+ rewind_mark = obj->strm.avail_in;
+ tracker = obj->strm.avail_out;
+ if ( obj->notCompressed )
+ ret = bzfile_read_notCompressed( &(obj->strm), &(obj->scan_BZh9) );
+ else
+ ret = BZ2_bzDecompress( &(obj->strm) );
+
+ if (obj->verbosity>=4) {
+ PerlIO_printf(PerlIO_stderr(), "\ndebug: bzfile_read BZ2_bzDecompress ret %d, run_progress=%d, avail_in=%d/%d, avail_out=%d/%d\n",
+ ret,
+ obj->run_progress,
+ rewind_mark,
+ obj->strm.avail_in,
+ tracker,
+ obj->strm.avail_out
+ );
+ }
+
+ if (ret != BZ_OK && ret != BZ_STREAM_END) {
+ if ( ret != BZ_DATA_ERROR_MAGIC || !obj->allowUncompressedRead ) {
+ BZ_SETERR(obj, ret, NULL);
+
+ if (obj->verbosity>1)
+ warn("Error: bzfile_read, BZ2_bzDecompress error %d, strm is %p, strm.state is %p, in state %d\n",
+ ret, &(obj->strm), obj->strm.state, *((int*)obj->strm.state));
+
+ return -1;
+ }
+ else if ( !obj->notCompressed ) {
+ /* a compressed stream that turns out not to be compressed */
+ obj->strm.avail_in = rewind_mark;
+ obj->notCompressed = True;
+ obj->scan_BZh9 = 0;
+
+ ret = BZ2_bzDecompressEnd( &(obj->strm) );
+ obj->run_progress = 0;
+
+ ret = bzfile_read_notCompressed( &(obj->strm), &(obj->scan_BZh9) );
+ }
+ else {
+ /* an uncompressed stream that turns out to be compressed actually */
+ obj->BZh9[0] = 'B';
+ obj->BZh9[1] = 'Z';
+ obj->BZh9[2] = 'h';
+ obj->BZh9[3] = obj->scan_BZh9;
+ obj->BZh9[4] = 0;
+ obj->BZh9_count = 4;
+
+ continue;
+ }
+ }
+
+ obj->total_out += tracker - obj->strm.avail_out;
+ bytes_uncompressed_count += tracker - obj->strm.avail_out;
+
+ if (ret == BZ_STREAM_END) {
+ char *p;
+ int i,n;
+
+ /* move unused bytes to another place */
+ p = obj->strm.next_in;
+ n = obj->strm.avail_in;
+ for (i=0; i<n; i++) obj->bufferOfHolding[i] = *p++;
+ obj->nHolding = n;
+
+ ret = BZ2_bzDecompressEnd( &(obj->strm) );
+
+ obj->run_progress = 10;
+
+ obj->nCompressed = 0;
+ obj->strm.avail_in = 0;
+ obj->strm.next_in = obj->bufferOfCompressed;
+ }
+ }
+
+ if (bytes_uncompressed_count >= nUncompress) {
+ BZ_SETERR(obj, BZ_OK, NULL);
+ return bytes_uncompressed_count;
+ }
+
+ /* obj->strm.avail_out > 0 */
+ /* need to read more to fill the output hopper, keep going */
+ }
+}
+
+#ifdef CAN_PROTOTYPE
+int bzfile_write( bzFile* obj, char *bufferOfUncompressed, int nUncompressed ) {
+#else
+int bzfile_write( obj, bufferOfUncompressed, nUncompressed ) bzFile* obj; char *bufferOfUncompressed; int nUncompressed; {
+#endif
+ int ret;
+ int tracker;
+ int bytes_compressed_count = 0;
+ int compressed_bytes_count = 0;
+ int error_num = bzfile_geterrno( obj );
+
+ if (obj == NULL || bufferOfUncompressed == NULL || nUncompressed < 0) {
+ BZ_SETERR(obj, BZ_PARAM_ERROR, NULL);
+
+ if ( obj != NULL && obj->verbosity>1 ) {
+ if ( bufferOfUncompressed == NULL ) warn("Error: bzfile_write buf is NULL\n");
+ if ( nUncompressed < 0 ) warn("Error: bzfile_write n is negative %d\n", nUncompressed);
+ }
+
+ return -1;
+ }
+
+ if (obj->open_status != OPEN_STATUS_WRITE && obj->open_status != OPEN_STATUS_WRITESTREAM) {
+ BZ_SETERR(obj, BZ_SEQUENCE_ERROR, NULL);
+
+ if ( obj->verbosity>1 ) warn("Error: bzfile_write attempted on a reading stream\n");
+
+ return -1;
+ }
+
+ if ( error_num == BZ_OK ) {
+ if ( obj->pending_io_error ) {
+ errno = obj->io_error;
+ obj->io_error = 0;
+ BZ_SETERR(obj, BZ_IO_ERROR, NULL);
+
+ obj->pending_io_error = False;
+ return -1;
+ }
+ }
+ else if ( error_num == BZ_IO_ERROR ) {
+ if ( obj->io_error == EINTR || obj->io_error == EAGAIN ) {
+ obj->io_error=0;
+ BZ_SETERR(obj, BZ_OK, NULL);
+ }
+ else
+ return -2;
+ }
+ else {
+ return -2;
+ }
+
+ while (True) {
+ if ( obj->run_progress == 0 ) {
+ ret = BZ2_bzCompressInit ( &(obj->strm), obj->blockSize100k, obj->verbosity, obj->workFactor );
+
+ if (ret != BZ_OK) {
+ BZ_SETERR(obj, ret, NULL);
+
+ if (obj->verbosity>1)
+ warn("Error: bzfile_write: BZ2_bzCompressInit error %d on %d, %d, %d\n",
+ ret, obj->blockSize100k, obj->verbosity, obj->workFactor);
+
+ return -1;
+ }
+
+ obj->run_progress = 1;
+ }
+
+ obj->strm.avail_in = nUncompressed - bytes_compressed_count;
+ obj->strm.next_in = bufferOfUncompressed + bytes_compressed_count;
+
+ obj->strm.avail_out = sizeof(obj->bufferOfCompressed) - obj->compressedOffset_addmore;
+ obj->strm.next_out = obj->bufferOfCompressed + obj->compressedOffset_addmore;
+
+ if (obj->verbosity>=4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_write: call to BZ2_bzCompress with avail_in %d, next_in %p, avail_out %d, next_out %p\n",
+ obj->strm.avail_in, obj->strm.next_in, obj->strm.avail_out, obj->strm.next_out);
+
+ compressed_bytes_count = obj->strm.avail_out;
+
+ tracker = obj->strm.avail_in;
+ if ( tracker == 0 )
+ return nUncompressed;
+
+ /* indicate we have data to compress */
+ if ( obj->run_progress == 1 && tracker > 0 ) obj->run_progress = 2;
+
+ if ( obj->strm.avail_out <= 0 )
+ ret = BZ_RUN_OK;
+ else
+ ret = BZ2_bzCompress ( &(obj->strm), BZ_RUN ) ;
+
+ obj->total_in += tracker - obj->strm.avail_in;
+ bytes_compressed_count += tracker - obj->strm.avail_in;
+
+ compressed_bytes_count -= obj->strm.avail_out;
+ obj->compressedOffset_addmore += compressed_bytes_count;
+ obj->nCompressed += compressed_bytes_count;
+
+ if (ret != BZ_RUN_OK) {
+ BZ_SETERR(obj, ret, NULL);
+
+ if (obj->verbosity>1)
+ warn("Error: bzfile_write, BZ2_bzCompress error %d, strm is %p, strm.state is %p, in state %d\n",
+ ret, &(obj->strm), obj->strm.state, *((int*)obj->strm.state));
+
+ return -1;
+ }
+
+ if (obj->verbosity>=4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_write: BZ2_bzCompress took in %d, put out %d \n",
+ tracker-obj->strm.avail_in, compressed_bytes_count);
+
+ if ( obj->nCompressed ) {
+ int n, n2;
+
+ n = obj->nCompressed;
+
+ while ( n > 0 ) {
+ if ( obj->open_status == OPEN_STATUS_WRITESTREAM )
+ n2 = bzfile_streambuf_write( obj, obj->bufferOfCompressed + obj->compressedOffset_takeout, n );
+ else
+ if ( obj->handle )
+ n2 = PerlIO_write( obj->handle, obj->bufferOfCompressed + obj->compressedOffset_takeout, n );
+ else
+ n2 = n;
+
+ if ( n2==-1 ) {
+ if ( bytes_compressed_count ) {
+ obj->pending_io_error = True;
+ obj->io_error = errno;
+
+ if ( errno != EINTR && errno != EAGAIN ) {
+ if (obj->verbosity>0)
+ warn("Error: bzfile_write file write error %d '%s'\n", errno, Strerror(errno));
+ }
+ else {
+ if (obj->verbosity>=4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_write file write error pending %d '%s'\n", errno, Strerror(errno));
+ }
+
+ return bytes_compressed_count;
+ }
+ else {
+ BZ_SETERR(obj, BZ_IO_ERROR, NULL);
+
+ if ( errno != EINTR && errno != EAGAIN ) {
+ if (obj->verbosity>0)
+ warn("Error: bzfile_write io error %d '%s'\n", errno, Strerror(errno));
+ }
+ else {
+ if (obj->verbosity>=4)
+ PerlIO_printf(PerlIO_stderr(), "debug: bzfile_write: file write error %d '%s'\n", errno, Strerror(errno));
+ }
+
+ return -1;
+ }
+ }
+ else {
+ if (obj->verbosity>=4) PerlIO_printf(PerlIO_stderr(), "debug: bzfile_write: file write took in %d, put out %d\n", n, n2);
+
+ obj->compressedOffset_takeout += n2;
+ obj->nCompressed -= n2;
+ n -= n2;
+
+ obj->total_out += n2;
+ }
+ }
+
+ obj->nCompressed = 0;
+ obj->compressedOffset_takeout = 0;
+ obj->compressedOffset_addmore = 0;
+ }
+
+ if (bytes_compressed_count == nUncompressed) {
+ BZ_SETERR(obj, BZ_OK, NULL);
+ return nUncompressed;
+ }
+ }
+}
+
+/***********************************************************************
+ * XSUB start
+ ***********************************************************************/
+
+MODULE = Compress::Bzip2 PACKAGE = Compress::Bzip2 PREFIX = MY_
+
+INCLUDE: const-xs.inc
+
+REQUIRE: 0.0
+PROTOTYPES: ENABLE
+
+BOOT:
+ if (BZ2_bzlibVersion()[0] != '1')
+ croak("Compress::Bzip2 needs bzlib version 1.x, not %s\n", BZ2_bzlibVersion()) ;
+
+ {
+ /* Create the $bzerror scalar */
+ SV * bzerror_sv = perl_get_sv(BZERRNO, GV_ADDMULTI) ;
+ sv_setiv(bzerror_sv, 0) ;
+ sv_setpv(bzerror_sv, "") ;
+ SvIOK_on(bzerror_sv) ;
+ }
+
+void
+MY_new(...)
+
+ PROTOTYPE: @
+
+ INIT:
+ bzFile* obj;
+ SV *perlobj;
+ char *class, *param;
+ STRLEN lnclass, lnparam;
+ int setting;
+
+ PPCODE:
+ {
+ int i;
+
+ perlobj=NULL;
+ obj=NULL;
+ if ( items == 0 ) {
+ class = "Compress::Bzip2";
+ }
+ else if ( SvPOK( ST(0) ) ) {
+ /* this is the name of a class */
+ class = (char *) SvPV( ST(0), lnclass );
+ }
+ else if ( SvROK( ST(0) ) ) {
+ if (sv_derived_from(ST(0), "Compress::Bzip2")) {
+ IV tmp = SvIV((SV*)SvRV(ST(0)));
+ perlobj = ST(0);
+ obj = INT2PTR(bzFile*, tmp);
+ }
+ }
+
+ if ( obj == NULL ) {
+ obj = bzfile_new( 0, 0, 9, 0 );
+
+ perlobj = newSV(0);
+ sv_setref_iv( perlobj, class, PTR2IV(obj) );
+ sv_2mortal(perlobj);
+ }
+
+ if ( obj == NULL )
+ XSRETURN_UNDEF;
+
+ for (i=1; i<items-1; i+=2) {
+ param = (char*) SvPV( ST(i), lnparam );
+ setting = SvIV( ST(i+1) );
+ bzfile_setparams( obj, param, setting );
+ }
+
+ PUSHs(perlobj);
+ }
+
+void
+DESTROY(obj)
+ Compress::Bzip2 obj
+
+ CODE:
+ {
+ if (obj->verbosity>=1)
+ PerlIO_printf(PerlIO_stderr(), "debug: DESTROY on %p\n", obj);
+ bzfile_close( obj, 0 );
+ bzfile_free( obj );
+ }
+
+char *
+MY_bzlibversion()
+
+ PROTOTYPE:
+
+ CODE:
+ RETVAL = (char *) BZ2_bzlibVersion();
+
+ OUTPUT:
+ RETVAL
+
+
+int
+MY_bz_seterror(error_num, error_str)
+ int error_num;
+ char *error_str;
+
+ PROTOTYPE: $$
+
+ CODE:
+ {
+ SV * bzerror_sv = perl_get_sv(BZERRNO, GV_ADDMULTI);
+ sv_setiv(bzerror_sv, error_num);
+ sv_setpv(bzerror_sv, error_str);
+ SvIOK_on(bzerror_sv);
+
+ RETVAL = error_num;
+ }
+
+ OUTPUT:
+ RETVAL
+
+SV *
+memBzip(sv, level = 6)
+ SV* sv;
+ int level
+
+ PROTOTYPE: $;$
+
+ ALIAS:
+ compress = 1
+
+ PREINIT:
+ STRLEN len;
+ unsigned char * in;
+ unsigned char * out;
+ unsigned int in_len;
+ unsigned int out_len;
+ unsigned int new_len;
+ int err;
+
+ CODE:
+ {
+ if ( !SvOK(sv) )
+ croak(ix==1 ? "compress: buffer is undef" : "memBzip: buffer is undef");;
+
+ sv = deRef(sv, ix==1 ? "compress" : "memBzip");
+
+ in = (unsigned char*) SvPV(sv, len);
+ in_len = len;
+
+ /* use an extra 1% + 600 bytes (see libbz2 documentation) */
+ out_len = in_len + ( in_len + 99 ) / 100 + 600;
+ RETVAL = newSV(5+out_len);
+ SvPOK_only(RETVAL);
+
+ out = (unsigned char*)SvPVX(RETVAL);
+ new_len = out_len;
+
+ out[0] = 0xf0;
+ err = BZ2_bzBuffToBuffCompress((char*)out+5,&new_len,(char*)in,in_len,level,0,240);
+
+ if (err != BZ_OK || new_len > out_len) {
+ SvREFCNT_dec(RETVAL);
+ BZ_SETERR(NULL, err, ix==1 ? "compress" : "memBzip");
+ XSRETURN_UNDEF;
+ }
+
+ SvCUR_set(RETVAL,5+new_len);
+ out[1] = (in_len >> 24) & 0xff;
+ out[2] = (in_len >> 16) & 0xff;
+ out[3] = (in_len >> 8) & 0xff;
+ out[4] = (in_len >> 0) & 0xff;
+ }
+
+ OUTPUT:
+ RETVAL
+
+SV *
+memBunzip(sv)
+ SV* sv
+
+ PROTOTYPE: $
+
+ ALIAS:
+ decompress = 1
+
+ PREINIT:
+ STRLEN len;
+ unsigned char * in;
+ unsigned char * out;
+ unsigned int in_len;
+ unsigned int out_len;
+ unsigned int new_len;
+ int err;
+ int noprefix = 0;
+
+ CODE:
+ {
+ if ( !SvOK(sv) )
+ croak(ix==1 ? "decompress: buffer is undef" : "memBunzip: buffer is undef");;
+
+ sv = deRef(sv, ix==1 ? "decompress" : "memBunzip");
+
+ in = (unsigned char*)SvPV(sv, len);
+ if (len < 5 + 3 || in[0] < 0xf0 || in[0] > 0xf1) {
+ if (len > 16 && in[0] == 'B' && in[1] == 'Z' && in[2] == 'h') {
+ in_len = len;
+ out_len = len * 5; /* guess uncompressed size */
+ noprefix = 1;
+ RETVAL = newSV(len * 10);
+ } else {
+ warn("invalid buffer (too short %ld or bad marker %d)",len,in[0]);
+ XSRETURN_UNDEF;
+ }
+ } else {
+ in_len = len - 5;
+ out_len = (in[1] << 24) | (in[2] << 16) | (in[3] << 8) | in[4];
+ RETVAL = newSV(out_len > 0 ? out_len : 1);
+ }
+ SvPOK_only(RETVAL);
+ out = (unsigned char*)SvPVX(RETVAL);
+ new_len = out_len;
+ err = BZ2_bzBuffToBuffDecompress((char*)out,&new_len,
+ noprefix ? (char*)in:(char *)in+5, in_len,0,0);
+ while (noprefix && (err == BZ_OUTBUFF_FULL)) {
+ new_len = SvLEN(RETVAL) * 2;
+ SvGROW(RETVAL, new_len);
+ err = BZ2_bzBuffToBuffDecompress((char*)out,&new_len,
+ (char *)in,in_len,0,0);
+ }
+ if (err != BZ_OK) {
+ SvREFCNT_dec(RETVAL);
+ BZ_SETERR(NULL, err, ix==1 ? "decompress" : "memBunzip");
+ XSRETURN_UNDEF;
+ }
+ if (!noprefix && new_len != out_len) {
+ SvREFCNT_dec(RETVAL);
+ BZ_SETERR(NULL, err, ix==1 ? "decompress" : "memBunzip");
+ XSRETURN_UNDEF;
+ }
+ SvCUR_set(RETVAL, new_len);
+ }
+
+ OUTPUT:
+ RETVAL
+
+void
+MY_bzopen(...)
+
+## xxx->bzopen( $filename or filehandle, $mode )
+
+ PROTOTYPE: $$;$
+
+ INIT:
+ PerlIO *io;
+ char *filename, *mode, *class;
+ STRLEN ln, lnfilename, lnclass;
+
+ bzFile* obj;
+ SV *perlobj;
+
+ PPCODE:
+ {
+ int i;
+
+ perlobj=NULL;
+ obj=NULL;
+ if ( items == 2 ) {
+ class = "Compress::Bzip2";
+ }
+ else if ( SvPOK( ST(0) ) ) {
+ /* this is the name of a class */
+ class = (char *) SvPV( ST(0), lnclass );
+ }
+ else if ( SvROK( ST(0) ) ) {
+ if (sv_derived_from(ST(0), "Compress::Bzip2")) {
+ IV tmp = SvIV((SV*)SvRV(ST(0)));
+ perlobj = ST(0);
+ obj = INT2PTR(bzFile*, tmp);
+ }
+ }
+
+ i = items==3 ? 2 : 1;
+ mode = (char *) SvPV(ST(i), ln);
+ if (ln==0) {
+ BZ_SETERR(obj, BZ_PARAM_ERROR, NULL);
+
+ if ( obj && obj->verbosity>1 ) warn( "Error: invalid file mode for bzopen %s", mode );
+
+ XSRETURN_UNDEF;
+ }
+
+ i = items==3 ? 1 : 0;
+ if ( SvPOK( ST(i) ) ) {
+ /* is the first argument a filename string or a filehandle?? */
+ filename = (char *) SvPV(ST(i), lnfilename);
+ if (lnfilename==0)
+ XSRETURN_UNDEF;
+
+ filename[lnfilename]=0;
+
+ obj = bzfile_open( filename, mode, obj );
+ }
+ else if ( SvROK( ST(i) ) || SVt_PVIO == SvTYPE( ST(i) ) ) {
+ /* a reference or an IO handle */
+ if ( mode && mode[0] == 'w' ) {
+ io = IoOFP(sv_2io( ST(i) ));
+ }
+ else {
+ io = IoIFP(sv_2io( ST(i) ));
+ }
+
+ obj = bzfile_fdopen( io, mode, obj );
+ }
+ else {
+ BZ_SETERR(obj, BZ_PARAM_ERROR, NULL);
+
+ if ( obj && obj->verbosity>1 ) warn( "Error: invalid file or handle for bzopen" );
+
+ XSRETURN_UNDEF;
+ }
+
+ if ( obj == NULL )
+ XSRETURN_UNDEF;
+
+ if ( perlobj == NULL ) {
+ perlobj = newSV(0);
+ sv_setref_iv( perlobj, class, PTR2IV(obj) );
+ sv_2mortal(perlobj);
+ }
+
+ PUSHs(perlobj);
+ }
+
+void
+MY_bzclose(obj, abandon=0)
+ Compress::Bzip2 obj
+ int abandon
+
+ PROTOTYPE: $;$
+
+ PPCODE:
+ {
+ int i, ret, amt_collected;
+ char *inp;
+ int error_flag = 0;
+
+ if ( obj->open_status != OPEN_STATUS_READSTREAM && obj->open_status != OPEN_STATUS_WRITESTREAM ) {
+ ret = bzfile_close( obj, abandon );
+ XPUSHs(sv_2mortal(newSViv(ret)));
+ }
+ else {
+ char *firstp, *outp;
+ SV *outbuf = NULL;
+ STRLEN outbufl = 0;
+
+ char collect_buffer[10000];
+
+ while ( !error_flag ) {
+ ret = bzfile_close( obj, abandon );
+
+ if ( obj->open_status == OPEN_STATUS_READSTREAM ) break;
+
+ if ( ret == -1 && errno != EAGAIN ) {
+ error_flag =1;
+ break;
+ }
+
+ if ( obj->verbosity>=4 )
+ PerlIO_printf(PerlIO_stderr(), "debug: bzstreamclose, bzfile_close returned %d, errno is %d %s\n", ret, errno, Strerror(errno));
+
+ while ( -1 != ( amt_collected = bzfile_streambuf_collect( obj, collect_buffer, sizeof(collect_buffer) ) ) ) {
+ if ( obj->verbosity>=4 )
+ PerlIO_printf(PerlIO_stderr(), "debug: bzstreamclose, bzfile_streambuf_collect returned %d bytes\n", amt_collected);
+
+ /* put the stuff into the SV output buffer */
+ if ( outbuf == NULL ) {
+ outbuf = newSVpv( collect_buffer, amt_collected );
+ outbufl = amt_collected;
+ firstp = SvPV_nolen( outbuf );
+ outp = firstp;
+ }
+ else {
+ outbufl += amt_collected;
+ SvGROW( outbuf, outbufl );
+ firstp = SvPV_nolen( outbuf );
+ outp = SvEND( outbuf );
+ }
+
+ for ( inp=collect_buffer, i=0; i<amt_collected; i++ ) *outp++ = *inp++;
+ SvCUR_set( outbuf, outp-firstp) ;
+ }
+ if ( errno != EAGAIN )
+ error_flag = 1;
+
+ if ( ret == 0 ) break;
+ }
+
+ if (outbuf==NULL) {
+ if ( error_flag )
+ XPUSHs(sv_newmortal());
+ else
+ XPUSHs(sv_2mortal(newSVpv("",0)));
+ }
+ else
+ XPUSHs(sv_2mortal(outbuf));
+
+ if (GIMME == G_ARRAY)
+ XPUSHs(sv_2mortal(newSViv(global_bzip_errno)));
+ }
+ }
+
+void
+MY_bzflush(obj, flag=0)
+ Compress::Bzip2 obj
+ int flag
+
+ PROTOTYPE: $;$
+
+ PPCODE:
+ {
+ int i, ret, amt_collected;
+ char *inp;
+
+ if ( obj->open_status != OPEN_STATUS_READSTREAM && obj->open_status != OPEN_STATUS_WRITESTREAM ) {
+ ret = !flag || flag!=BZ_FINISH ? bzfile_flush( obj ) : bzfile_close( obj, 0 );
+ XPUSHs(sv_2mortal(newSViv(ret)));
+ }
+ else {
+ char *firstp, *outp;
+ SV *outbuf = NULL;
+ STRLEN outbufl = 0;
+
+ char collect_buffer[10000];
+
+ while ( True ) {
+ ret = !flag || flag!=BZ_FLUSH ? bzfile_flush( obj ) : bzfile_close( obj, 0 );
+
+ if ( obj->open_status == OPEN_STATUS_READSTREAM ) break;
+
+ while ( -1 != ( amt_collected = bzfile_streambuf_collect( obj, collect_buffer, sizeof(collect_buffer) ) ) ) {
+ if ( obj->verbosity>=4 )
+ PerlIO_printf(PerlIO_stderr(), "debug: bzstreamflush, bzfile_streambuf_collect returned %d bytes\n", amt_collected);
+
+ /* put the stuff into the SV output buffer */
+ if ( outbuf == NULL ) {
+ outbuf = newSVpv( collect_buffer, amt_collected );
+ outbufl = amt_collected;
+ firstp = SvPV_nolen( outbuf );
+ outp = firstp;
+ }
+ else {
+ outbufl += amt_collected;
+ SvGROW( outbuf, outbufl );
+ firstp = SvPV_nolen( outbuf );
+ outp = SvEND( outbuf );
+ }
+
+ for ( inp=collect_buffer, i=0; i<amt_collected; i++ ) *outp++ = *inp++;
+ SvCUR_set( outbuf, outp-firstp) ;
+ }
+
+ if ( ret != -1 ) break;
+ }
+
+ if (outbuf==NULL)
+ XPUSHs(sv_newmortal());
+ else
+ XPUSHs(sv_2mortal(outbuf));
+
+ if (GIMME == G_ARRAY)
+ XPUSHs(sv_2mortal(newSViv(global_bzip_errno)));
+ }
+ }
+
+SV*
+MY_bzerror(obj)
+ Compress::Bzip2 obj
+
+ PROTOTYPE: $
+
+ CODE:
+ {
+ int err_num;
+ err_num = bzfile_geterrno( obj );
+
+ if ( err_num == 0 )
+ XSRETURN_NO;
+
+ RETVAL = newSViv( err_num );
+
+ sv_setiv(RETVAL, err_num) ;
+ sv_setpv(RETVAL, (char*) bzfile_geterrstr( obj ));
+ SvIOK_on(RETVAL); /* say "IAM integer (too)" */
+ }
+
+ OUTPUT:
+ RETVAL
+
+int
+MY_bzclearerr(obj)
+ Compress::Bzip2 obj
+
+ PROTOTYPE: $
+
+ CODE:
+ {
+ if ( bzfile_clearerr( obj ) )
+ RETVAL = 1;
+ else
+ RETVAL = 0;
+ }
+
+ OUTPUT:
+ RETVAL
+
+SV*
+MY_bzeof(obj)
+ Compress::Bzip2 obj
+
+ PROTOTYPE: $
+
+ CODE:
+ {
+ if ( bzfile_eof( obj ) )
+ XSRETURN_YES;
+ else
+ XSRETURN_NO;
+ }
+
+long
+MY_total_in(obj)
+ Compress::Bzip2 obj
+
+ PROTOTYPE: $
+
+ CODE:
+ RETVAL = bzfile_total_in( obj );
+
+ OUTPUT:
+ RETVAL
+
+long
+MY_total_out(obj)
+ Compress::Bzip2 obj
+
+ PROTOTYPE: $
+
+ CODE:
+ RETVAL = bzfile_total_out( obj );
+
+ OUTPUT:
+ RETVAL
+
+int
+MY_bzsetparams(obj, param, setting = -1)
+ Compress::Bzip2 obj
+ char* param
+ int setting
+
+ PROTOTYPE: $$;$
+
+ CODE:
+ RETVAL = bzfile_setparams( obj, param, setting );
+
+ OUTPUT:
+ RETVAL
+
+int
+MY_bzread(obj, buf, len=4096)
+ Compress::Bzip2 obj
+ unsigned int len
+ SV *buf
+
+ PROTOTYPE: $$;$
+
+ CODE:
+ {
+ if (SvREADONLY(buf) && PL_curcop != &PL_compiling)
+ croak("bzread: buffer parameter is read-only");
+ SvUPGRADE(buf, SVt_PV);
+ SvPOK_only(buf);
+ SvCUR_set(buf, 0);
+
+ if (len) {
+ char* bufp = SvGROW(buf, len+1);
+
+ RETVAL = bzfile_read( obj, bufp, len);
+
+ if (RETVAL >= 0) {
+ SvCUR_set(buf, RETVAL) ;
+ *SvEND(buf) = '\0';
+ }
+ }
+ else {
+ RETVAL = 0;
+ }
+ }
+
+ OUTPUT:
+ RETVAL
+ buf
+
+
+int
+MY_bzreadline(obj, buf, len=4096)
+ Compress::Bzip2 obj
+ unsigned int len
+ SV *buf
+
+ PROTOTYPE: $$;$
+
+ CODE:
+ {
+ if (SvREADONLY(buf) && PL_curcop != &PL_compiling)
+ croak("bzreadline: buffer parameter is read-only");
+ SvUPGRADE(buf, SVt_PV);
+ SvPOK_only(buf);
+ SvCUR_set(buf, 0);
+
+ if (len) {
+ char* bufp = SvGROW(buf, len+1);
+
+ RETVAL = bzfile_readline( obj, bufp, len);
+
+ if (RETVAL >= 0) {
+ SvCUR_set(buf, RETVAL) ;
+ *SvEND(buf) = '\0';
+ }
+ }
+ else {
+ RETVAL = 0;
+ }
+ }
+
+ OUTPUT:
+ RETVAL
+ buf
+
+int
+MY_bzwrite(obj, buf, limit=0)
+ Compress::Bzip2 obj
+ SV *buf
+ SV *limit
+
+ PROTOTYPE: $$;$
+
+ CODE:
+ {
+ char *bufp;
+ STRLEN len;
+
+ if ( SvTRUE(limit) ) {
+ len = SvUV(limit);
+ SvGROW( buf, len );
+ bufp = SvPV_nolen(buf);
+ }
+ else
+ bufp = SvPV(buf, len);
+
+ RETVAL = bzfile_write( obj, bufp, len);
+
+ if ( RETVAL >= 0 )
+ SvCUR_set( buf, RETVAL );
+ }
+
+ OUTPUT:
+ RETVAL
+
+void
+bzdeflateInit(...)
+
+ PROTOTYPE: @
+
+ ALIAS:
+ compress_init = 1
+
+ INIT:
+ bzFile* obj = NULL;
+ SV *perlobj = NULL;
+ char *param;
+ STRLEN lnparam;
+ int setting;
+
+ PPCODE:
+ {
+ int i;
+
+ if (items % 2) croak("Compress::Bzip2::%s has odd parameter count", ix==0 ? "bzdeflateInit" : "compress_init");
+
+ obj = bzfile_new( 0, 0, 1, 0 );
+ bzfile_openstream( "w", obj );
+
+ perlobj = newSV(0);
+ sv_setref_iv( perlobj, "Compress::Bzip2", PTR2IV(obj) );
+ sv_2mortal(perlobj);
+
+ if ( obj == NULL ) {
+ XPUSHs(sv_newmortal());
+ if (GIMME == G_ARRAY)
+ XPUSHs(sv_2mortal(newSViv(global_bzip_errno)));
+ }
+ else {
+ for (i=0; i<items-1; i+=2) {
+ param = (char*) SvPV( ST(i), lnparam );
+ setting = SvIV( ST(i+1) );
+ bzfile_setparams( obj, param, setting );
+ }
+
+ bzfile_streambuf_set( obj, (char*) obj->bufferOfHolding, sizeof( obj->bufferOfHolding ) );
+
+ XPUSHs(perlobj);
+ if (GIMME == G_ARRAY)
+ XPUSHs(sv_2mortal(newSViv(global_bzip_errno)));
+ }
+ }
+
+void
+MY_bzdeflate(obj, buffer)
+ Compress::Bzip2 obj
+ SV *buffer
+
+ PROTOTYPE: $$
+
+ PPCODE:
+ {
+ char *firstp, *outp;
+ SV *outbuf = NULL;
+ STRLEN outbufl = 0;
+
+ char *bufp, *inp;
+ STRLEN bufl;
+
+ STRLEN bytes_to_go;
+
+ char collect_buffer[1000];
+ int i, amt_written, amt_collected;
+ int error_flag = 0;
+
+ bufp = (char*) SvPV( buffer, bufl );
+
+ for ( bytes_to_go = bufl; bytes_to_go>0; ) {
+ amt_written = bzfile_write( obj, bufp, bytes_to_go );
+
+ if ( amt_written == -1 ) {
+ if ( errno != EAGAIN )
+ error_flag =1;
+ else {
+ while ( -1 != ( amt_collected = bzfile_streambuf_collect( obj, collect_buffer, sizeof(collect_buffer) ) ) ) {
+ /* put the stuff into the SV output buffer */
+ if ( outbuf == NULL ) {
+ outbuf = newSVpv( collect_buffer, amt_collected );
+ outbufl = amt_collected;
+ firstp = SvPV_nolen( outbuf );
+ outp = firstp;
+ }
+ else {
+ outbufl += amt_collected;
+ SvGROW( outbuf, outbufl );
+ firstp = SvPV_nolen( outbuf );
+ outp = SvEND( outbuf );
+ }
+
+ for ( inp=collect_buffer, i=0; i<amt_collected; i++ ) *outp++ = *inp++;
+ SvCUR_set( outbuf, outp-firstp) ;
+
+ if ( obj->verbosity>=4 )
+ PerlIO_printf(PerlIO_stderr(), "debug: bzdeflate collected %d, outbuf is now %ld\n",
+ amt_collected, outp-firstp);
+ }
+
+ if ( errno != EAGAIN ) error_flag = 1;
+ }
+ }
+ else {
+ bytes_to_go -= amt_written;
+ bufp += amt_written;
+ }
+ }
+
+ while ( -1 != ( amt_collected = bzfile_streambuf_collect( obj, collect_buffer, sizeof(collect_buffer) ) ) ) {
+ /* put the stuff into the SV output buffer */
+ if ( outbuf == NULL ) {
+ outbuf = newSVpv( collect_buffer, amt_collected );
+ outbufl = amt_collected;
+ firstp = SvPV_nolen( outbuf );
+ outp = firstp;
+ }
+ else {
+ outbufl += amt_collected;
+ SvGROW( outbuf, outbufl );
+ firstp = SvPV_nolen( outbuf );
+ outp = SvEND( outbuf );
+ }
+
+ for ( inp=collect_buffer, i=0; i<amt_collected; i++ ) *outp++ = *inp++;
+ SvCUR_set( outbuf, outp-firstp) ;
+
+ if ( obj->verbosity>=4 )
+ PerlIO_printf(PerlIO_stderr(), "debug: bzdeflate collected %d, outbuf is now %ld\n",
+ amt_collected, outp-firstp);
+ }
+
+ if ( errno != EAGAIN ) error_flag = 1;
+
+ if (outbuf==NULL) {
+ if ( error_flag )
+ XPUSHs(sv_newmortal());
+ else
+ XPUSHs(sv_2mortal(newSVpv("",0)));
+ }
+ else
+ XPUSHs(sv_2mortal(outbuf));
+
+ if (GIMME == G_ARRAY)
+ XPUSHs(sv_2mortal(newSViv(global_bzip_errno)));
+ }
+
+
+void
+bzinflateInit(...)
+
+ PROTOTYPE: @
+
+ ALIAS:
+ decompress_init = 1
+
+ INIT:
+ bzFile* obj = NULL;
+ SV *perlobj = NULL;
+ char *param;
+ STRLEN lnparam;
+ int setting;
+
+ PPCODE:
+ {
+ int i;
+
+ if (items % 2)
+ croak("Compress::Bzip2::%s has odd parameter count", ix==0 ? "bzinflateInit" : "decompress_init");
+
+ obj = bzfile_new( 0, 0, 1, 0 );
+ bzfile_openstream( "r", obj );
+ if ( obj == NULL ) {
+ XPUSHs(sv_newmortal());
+ if (GIMME == G_ARRAY)
+ XPUSHs(sv_2mortal(newSViv(global_bzip_errno)));
+ }
+
+ perlobj = newSV(0);
+ sv_setref_iv( perlobj, "Compress::Bzip2", PTR2IV(obj) );
+
+ for (i=0; i < items; i+=2) {
+ param = (char*) SvPV( ST(i), lnparam );
+ setting = SvIV( ST(i+1) );
+ bzfile_setparams( obj, param, setting );
+ }
+
+ XPUSHs(sv_2mortal(perlobj));
+ if (GIMME == G_ARRAY)
+ XPUSHs(sv_2mortal(newSViv(global_bzip_errno)));
+ }
+
+void
+MY_bzinflate(obj, buffer)
+ Compress::Bzip2 obj
+ SV *buffer
+
+ PROTOTYPE: $$
+
+ PPCODE:
+ {
+ char *firstp, *outp;
+ SV *outbuf = NULL;
+ STRLEN outbufl = 0;
+
+ STRLEN bufl;
+ char collect_buffer[1000];
+ int i, amt_collected;
+ char *bufp, *inp;
+ int error_flag = 0;
+
+ if (SvTYPE(buffer) == SVt_RV)
+ buffer = SvRV(buffer);
+ bufp = (char*) SvPV( buffer, bufl );
+ bzfile_streambuf_deposit( obj, bufp, bufl );
+
+ while ( ( amt_collected = bzfile_read( obj, collect_buffer, sizeof(collect_buffer) ) ) >= 0 ) {
+ if ( obj->verbosity>=4 )
+ PerlIO_printf(PerlIO_stderr(), "debug: bzinflate, bzfile_read returned %d bytes\n", amt_collected);
+
+ /* put the stuff into the SV output buffer */
+ if ( outbuf == NULL ) {
+ outbuf = newSVpv( collect_buffer, amt_collected );
+ outbufl = amt_collected;
+ firstp = SvPV_nolen( outbuf );
+ outp = firstp;
+ }
+ else {
+ outbufl += amt_collected;
+ SvGROW( outbuf, outbufl );
+ firstp = SvPV_nolen( outbuf );
+ outp = SvEND( outbuf );
+ }
+
+ for ( inp=collect_buffer, i=0; i<amt_collected; i++ ) *outp++ = *inp++;
+ SvCUR_set( outbuf, outp-firstp) ;
+ }
+
+ if ( errno != EAGAIN ) error_flag = 1;
+
+ if (outbuf==NULL) {
+ if ( error_flag )
+ XPUSHs(sv_newmortal());
+ else
+ XPUSHs(sv_2mortal(newSVpv("",0)));
+ }
+ else
+ XPUSHs(sv_2mortal(outbuf));
+
+ if (GIMME == G_ARRAY)
+ XPUSHs(sv_2mortal(newSViv(global_bzip_errno)));
+ }
+
+
+## $stream->prefix: Compress::Bzip2 1.03 compatibility function
+## ... only call this for a compress/deflate stream
+
+SV*
+MY_prefix(obj)
+ Compress::Bzip2 obj
+
+ CODE:
+ {
+ if (obj->strm.total_in_hi32)
+ XSRETURN_UNDEF;
+ else {
+ unsigned int in_len = obj->strm.total_in_lo32;
+ char out[6];
+
+ out[0] = 0xf0;
+ out[1] = (in_len >> 24) & 0xff;
+ out[2] = (in_len >> 16) & 0xff;
+ out[3] = (in_len >> 8) & 0xff;
+ out[4] = (in_len >> 0) & 0xff;
+ out[5] = 0;
+
+ RETVAL = newSVpvn(out,5);
+ }
+ }
+
+ OUTPUT:
+ RETVAL
+
+int
+MY_is_write(obj)
+ Compress::Bzip2 obj
+
+ PROTOTYPE: $
+
+ CODE:
+ RETVAL = obj->open_status == OPEN_STATUS_WRITE || obj->open_status == OPEN_STATUS_WRITESTREAM ? 1 : 0;
+
+ OUTPUT:
+ RETVAL
+
+int
+MY_is_read(obj)
+ Compress::Bzip2 obj
+
+ PROTOTYPE: $
+
+ CODE:
+ RETVAL = obj->open_status == OPEN_STATUS_READ || obj->open_status == OPEN_STATUS_READSTREAM ? 1 : 0;
+
+ OUTPUT:
+ RETVAL
+
+int
+MY_is_stream(obj)
+ Compress::Bzip2 obj
+
+ PROTOTYPE: $
+
+ CODE:
+ RETVAL = obj->open_status == OPEN_STATUS_WRITESTREAM || obj->open_status == OPEN_STATUS_READSTREAM ? 1 : 0;
+
+ OUTPUT:
+ RETVAL