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