Commit | Line | Data |
bdb7fd9f |
1 | /* Filename: Bzip2.xs |
2 | * Author : Paul Marquess, <pmqs@cpan.org> |
3 | * Created : 5th October 2005 |
4 | * Version : 2.000 |
5 | * |
6 | * Copyright (c) 2005-2007 Paul Marquess. All rights reserved. |
7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the same terms as Perl itself. |
9 | * |
10 | */ |
11 | |
12 | |
13 | #include "EXTERN.h" |
14 | #include "perl.h" |
15 | #include "XSUB.h" |
16 | |
17 | #include "bzlib.h" |
18 | |
19 | #ifdef USE_PPPORT_H |
20 | # define NEED_sv_2pv_nolen |
21 | # include "ppport.h" |
22 | #endif |
23 | |
24 | #if PERL_REVISION == 5 && (PERL_VERSION < 8 || (PERL_VERSION == 8 && PERL_SUBVERSION < 4 )) |
25 | |
26 | # ifdef SvPVbyte_force |
27 | # undef SvPVbyte_force |
28 | # endif |
29 | |
30 | # define SvPVbyte_force(sv,lp) SvPV_force(sv,lp) |
31 | |
32 | #endif |
33 | |
34 | #ifndef SvPVbyte_nolen |
35 | # define SvPVbyte_nolen SvPV_nolen |
36 | #endif |
37 | |
38 | |
39 | #if PERL_REVISION == 5 && (PERL_VERSION >= 8 || (PERL_VERSION == 8 && PERL_SUBVERSION < 4 )) |
40 | # define UTF8_AVAILABLE |
41 | #endif |
42 | |
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 |
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 |
169 | DispStream(di_stream * s, char * message) |
170 | #else |
171 | DispStream(s, message) |
172 | di_stream * s; |
173 | char * message; |
174 | #endif |
175 | { |
176 | |
177 | #if 0 |
178 | if (! trace) |
179 | return ; |
180 | #endif |
181 | |
182 | #define EnDis(f) (s->flags & f ? "Enabled" : "Disabled") |
183 | |
184 | printf("DispStream 0x%p", s) ; |
185 | if (message) |
ea6efd2c |
186 | printf(" - %s \n", message) ; |
bdb7fd9f |
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 |
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 |
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 |
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 |
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 |
277 | default: |
278 | break; |
bdb7fd9f |
279 | } |
280 | if (SvROK(sv)) |
281 | croak("%s: buffer parameter is a reference to a reference", string) ; |
282 | } |
283 | |
284 | if (!SvOK(sv)) { |
285 | sv = newSVpv("", 0); |
286 | } |
287 | |
288 | return sv ; |
289 | } |
290 | |
291 | static SV* |
292 | #ifdef CAN_PROTOTYPE |
293 | deRef_l(SV * sv, const char * string) |
294 | #else |
295 | deRef_l(sv, string) |
296 | SV * sv ; |
297 | char * string ; |
298 | #endif |
299 | { |
300 | dTHX; |
301 | bool wipe = 0 ; |
302 | |
303 | SvGETMAGIC(sv); |
304 | wipe = ! SvOK(sv) ; |
305 | |
306 | if (SvROK(sv)) { |
307 | sv = SvRV(sv) ; |
308 | SvGETMAGIC(sv); |
309 | wipe = ! SvOK(sv) ; |
310 | |
311 | switch(SvTYPE(sv)) { |
312 | case SVt_PVAV: |
313 | case SVt_PVHV: |
314 | case SVt_PVCV: |
315 | croak("%s: buffer parameter is not a SCALAR reference", string); |
776304fb |
316 | default: |
317 | break; |
bdb7fd9f |
318 | } |
319 | if (SvROK(sv)) |
320 | croak("%s: buffer parameter is a reference to a reference", string) ; |
321 | } |
322 | |
323 | if (SvREADONLY(sv) && PL_curcop != &PL_compiling) |
324 | croak("%s: buffer parameter is read-only", string); |
325 | |
326 | SvUPGRADE(sv, SVt_PV); |
327 | |
328 | if (wipe) |
329 | SvCUR_set(sv, 0); |
330 | |
331 | SvOOK_off(sv); |
332 | SvPOK_only(sv); |
333 | |
334 | return sv ; |
335 | } |
336 | |
337 | |
338 | #include "constants.h" |
339 | |
340 | MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2 PREFIX = Zip_ |
341 | |
342 | REQUIRE: 1.924 |
343 | PROTOTYPES: DISABLE |
344 | |
345 | INCLUDE: constants.xs |
346 | |
347 | BOOT: |
c14f59c3 |
348 | #ifndef NO_WRITEABLE_DATA |
349 | trace = TRACE_DEFAULT ; |
350 | #endif |
bdb7fd9f |
351 | /* Check this version of bzip2 is == 1 */ |
352 | if (BZ2_bzlibVersion()[0] != '1') |
353 | croak(COMPRESS_CLASS " needs bzip2 version 1.x, you have %s\n", BZ2_bzlibVersion()) ; |
354 | |
355 | |
356 | MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2 |
357 | |
358 | #define bzlibversion() BZ2_bzlibVersion() |
359 | const char * |
360 | bzlibversion() |
361 | |
362 | void |
c14f59c3 |
363 | new(className, appendOut=1, blockSize100k=1, workfactor=0, verbosity=0) |
364 | const char * className |
bdb7fd9f |
365 | int appendOut |
366 | int blockSize100k |
367 | int workfactor |
368 | int verbosity |
369 | PPCODE: |
370 | { |
371 | int err ; |
372 | deflateStream s ; |
373 | #if 0 |
374 | /* if (trace) */ |
375 | warn("in Compress::Raw::Bzip2::_new(items=%d,appendOut=%d, blockSize100k=%d, workfactor=%d, verbosity=%d\n", |
376 | items, appendOut, blockSize100k, workfactor, verbosity); |
377 | #endif |
378 | if ((s = InitStream() )) { |
379 | |
380 | err = BZ2_bzCompressInit ( &(s->stream), |
381 | blockSize100k, |
382 | verbosity, |
383 | workfactor ); |
384 | |
385 | if (err != BZ_OK) { |
386 | Safefree(s) ; |
387 | s = NULL ; |
388 | } |
389 | else { |
390 | int flags = 0 ; |
391 | if (appendOut) |
392 | flags |= FLAG_APPEND_OUTPUT; |
393 | PostInitStream(s, appendOut ? FLAG_APPEND_OUTPUT :0) ; |
394 | } |
395 | } |
396 | else |
397 | err = BZ_MEM_ERROR ; |
398 | |
399 | { |
c14f59c3 |
400 | SV* obj = sv_setref_pv(sv_newmortal(), className, (void*)s); |
bdb7fd9f |
401 | XPUSHs(obj); |
402 | } |
403 | if(0) |
404 | { |
405 | SV* obj = sv_2mortal(newSViv(PTR2IV(s))) ; |
406 | XPUSHs(obj); |
407 | } |
408 | if (GIMME == G_ARRAY) { |
409 | SV * sv = sv_2mortal(newSViv(err)) ; |
410 | setDUALstatus(sv, err); |
411 | XPUSHs(sv) ; |
412 | } |
413 | } |
414 | |
415 | MODULE = Compress::Raw::Bunzip2 PACKAGE = Compress::Raw::Bunzip2 |
416 | |
417 | void |
ea6efd2c |
418 | new(className, appendOut=1 , consume=1, small=0, verbosity=0, limitOutput=0) |
c14f59c3 |
419 | const char* className |
bdb7fd9f |
420 | int appendOut |
421 | int consume |
422 | int small |
423 | int verbosity |
ea6efd2c |
424 | int limitOutput |
bdb7fd9f |
425 | PPCODE: |
426 | { |
427 | int err = BZ_OK ; |
428 | inflateStream s ; |
429 | #if 0 |
430 | if (trace) |
431 | warn("in _inflateInit(windowBits=%d, bufsize=%lu, dictionary=%lu\n", |
432 | windowBits, bufsize, (unsigned long)SvCUR(dictionary)) ; |
433 | #endif |
434 | if ((s = InitStream() )) { |
435 | |
436 | err = BZ2_bzDecompressInit (&(s->stream), verbosity, small); |
437 | if (err != BZ_OK) { |
438 | Safefree(s) ; |
439 | s = NULL ; |
440 | } |
441 | if (s) { |
442 | int flags = 0; |
443 | if (appendOut) |
444 | flags |= FLAG_APPEND_OUTPUT; |
445 | if (consume) |
446 | flags |= FLAG_CONSUME_INPUT; |
ea6efd2c |
447 | if (limitOutput) |
448 | flags |= (FLAG_LIMIT_OUTPUT|FLAG_CONSUME_INPUT); |
bdb7fd9f |
449 | PostInitStream(s, flags) ; |
450 | } |
451 | } |
452 | else |
453 | err = BZ_MEM_ERROR ; |
454 | |
455 | { |
c14f59c3 |
456 | SV* obj = sv_setref_pv(sv_newmortal(), className, (void*)s); |
bdb7fd9f |
457 | XPUSHs(obj); |
458 | } |
459 | if (0) |
460 | { |
461 | SV* obj = sv_2mortal(newSViv(PTR2IV(s))) ; |
462 | XPUSHs(obj); |
463 | } |
464 | if (GIMME == G_ARRAY) { |
465 | SV * sv = sv_2mortal(newSViv(err)) ; |
466 | setDUALstatus(sv, err); |
467 | XPUSHs(sv) ; |
468 | } |
469 | } |
470 | |
471 | |
472 | |
473 | MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2 |
474 | |
475 | void |
476 | DispStream(s, message=NULL) |
477 | Compress::Raw::Bzip2 s |
478 | char * message |
479 | |
480 | DualType |
481 | bzdeflate (s, buf, output) |
482 | Compress::Raw::Bzip2 s |
483 | SV * buf |
484 | SV * output |
485 | uInt cur_length = NO_INIT |
486 | uInt increment = NO_INIT |
487 | int RETVAL = 0; |
488 | uInt bufinc = NO_INIT |
489 | CODE: |
490 | bufinc = s->bufsize; |
491 | |
492 | /* If the input buffer is a reference, dereference it */ |
493 | buf = deRef(buf, "deflate") ; |
494 | |
495 | /* initialise the input buffer */ |
496 | #ifdef UTF8_AVAILABLE |
497 | if (DO_UTF8(buf) && !sv_utf8_downgrade(buf, 1)) |
498 | croak("Wide character in " COMPRESS_CLASS "::bzdeflate input parameter"); |
499 | #endif |
500 | s->stream.next_in = (char*)SvPVbyte_nolen(buf) ; |
501 | s->stream.avail_in = SvCUR(buf) ; |
502 | |
503 | /* and retrieve the output buffer */ |
504 | output = deRef_l(output, "deflate") ; |
505 | #ifdef UTF8_AVAILABLE |
506 | if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1)) |
507 | croak("Wide character in " COMPRESS_CLASS "::bzdeflate output parameter"); |
508 | #endif |
509 | |
510 | if((s->flags & FLAG_APPEND_OUTPUT) != FLAG_APPEND_OUTPUT) { |
511 | SvCUR_set(output, 0); |
512 | /* sv_setpvn(output, "", 0); */ |
513 | } |
514 | cur_length = SvCUR(output) ; |
515 | s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length; |
516 | increment = SvLEN(output) - cur_length; |
517 | s->stream.avail_out = increment; |
518 | while (s->stream.avail_in != 0) { |
519 | |
520 | if (s->stream.avail_out == 0) { |
521 | /* out of space in the output buffer so make it bigger */ |
522 | Sv_Grow(output, SvLEN(output) + bufinc) ; |
523 | cur_length += increment ; |
524 | s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length ; |
525 | increment = bufinc ; |
526 | s->stream.avail_out = increment; |
527 | bufinc *= 2 ; |
528 | } |
529 | |
530 | RETVAL = BZ2_bzCompress(&(s->stream), BZ_RUN); |
531 | if (RETVAL != BZ_RUN_OK) |
532 | break; |
533 | } |
534 | |
535 | s->compressedBytes += cur_length + increment - s->stream.avail_out ; |
536 | s->uncompressedBytes += SvCUR(buf) - s->stream.avail_in ; |
537 | |
538 | s->last_error = RETVAL ; |
539 | if (RETVAL == BZ_RUN_OK) { |
540 | SvPOK_only(output); |
541 | SvCUR_set(output, cur_length + increment - s->stream.avail_out) ; |
542 | SvSETMAGIC(output); |
543 | } |
544 | OUTPUT: |
545 | RETVAL |
546 | |
547 | |
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 |
574 | if(! s->flags & FLAG_APPEND_OUTPUT) { |
575 | SvCUR_set(output, 0); |
576 | /* sv_setpvn(output, "", 0); */ |
577 | } |
578 | cur_length = SvCUR(output) ; |
579 | s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length; |
580 | increment = SvLEN(output) - cur_length; |
581 | s->stream.avail_out = increment; |
582 | |
583 | for (;;) { |
584 | if (s->stream.avail_out == 0) { |
585 | /* consumed all the available output, so extend it */ |
586 | Sv_Grow(output, SvLEN(output) + bufinc) ; |
587 | cur_length += increment ; |
588 | s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length ; |
589 | increment = bufinc ; |
590 | s->stream.avail_out = increment; |
591 | bufinc *= 2 ; |
592 | } |
593 | RETVAL = BZ2_bzCompress(&(s->stream), BZ_FINISH); |
594 | |
595 | /* deflate has finished flushing only when it hasn't used up |
596 | * all the available space in the output buffer: |
597 | */ |
598 | /* if (s->stream.avail_out != 0 || RETVAL < 0 ) */ |
599 | if (RETVAL == BZ_STREAM_END || RETVAL < 0 ) |
600 | break; |
601 | } |
602 | |
603 | /* RETVAL = (RETVAL == BZ_STREAM_END ? BZ_OK : RETVAL) ; */ |
604 | s->last_error = RETVAL ; |
605 | |
606 | s->compressedBytes += cur_length + increment - s->stream.avail_out ; |
607 | |
608 | if (RETVAL == BZ_STREAM_END) { |
609 | SvPOK_only(output); |
610 | SvCUR_set(output, cur_length + increment - s->stream.avail_out) ; |
611 | SvSETMAGIC(output); |
612 | } |
613 | OUTPUT: |
614 | RETVAL |
615 | |
616 | |
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 |
635 | if(! s->flags & FLAG_APPEND_OUTPUT) { |
636 | SvCUR_set(output, 0); |
637 | /* sv_setpvn(output, "", 0); */ |
638 | } |
639 | cur_length = SvCUR(output) ; |
640 | s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length; |
641 | increment = SvLEN(output) - cur_length; |
642 | s->stream.avail_out = increment; |
643 | |
644 | for (;;) { |
645 | if (s->stream.avail_out == 0) { |
646 | /* consumed all the available output, so extend it */ |
647 | Sv_Grow(output, SvLEN(output) + bufinc) ; |
648 | cur_length += increment ; |
649 | s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length ; |
650 | increment = bufinc ; |
651 | s->stream.avail_out = increment; |
652 | bufinc *= 2 ; |
653 | } |
654 | RETVAL = BZ2_bzCompress(&(s->stream), BZ_FLUSH); |
655 | |
656 | if (RETVAL == BZ_RUN_OK || RETVAL < 0) |
657 | break; |
658 | |
659 | /* deflate has finished flushing only when it hasn't used up |
660 | * all the available space in the output buffer: |
661 | */ |
662 | /* RETVAL == if (s->stream.avail_out != 0 || RETVAL < 0 ) |
663 | break; */ |
664 | } |
665 | |
666 | /* RETVAL = (RETVAL == BZ_STREAM_END ? BZ_OK : RETVAL) ; */ |
667 | s->last_error = RETVAL ; |
668 | |
669 | s->compressedBytes += cur_length + increment - s->stream.avail_out ; |
670 | |
671 | if (RETVAL == BZ_RUN_OK) { |
672 | SvPOK_only(output); |
673 | SvCUR_set(output, cur_length + increment - s->stream.avail_out) ; |
674 | SvSETMAGIC(output); |
675 | } |
676 | OUTPUT: |
677 | RETVAL |
678 | |
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 |
717 | char * message |
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; |
727 | STRLEN stmp = NO_INIT |
728 | uInt bufinc = NO_INIT |
729 | PREINIT: |
730 | #ifdef UTF8_AVAILABLE |
731 | bool out_utf8 = FALSE; |
732 | #endif |
733 | CODE: |
734 | bufinc = s->bufsize; |
735 | /* If the buffer is a reference, dereference it */ |
ea6efd2c |
736 | buf = deRef(buf, "bzinflate") ; |
bdb7fd9f |
737 | |
738 | if (s->flags & FLAG_CONSUME_INPUT && SvREADONLY(buf)) |
739 | croak(UNCOMPRESS_CLASS "::bzinflate input parameter cannot be read-only when ConsumeInput is specified"); |
740 | #ifdef UTF8_AVAILABLE |
741 | if (DO_UTF8(buf) && !sv_utf8_downgrade(buf, 1)) |
742 | croak("Wide character in " UNCOMPRESS_CLASS "::bzinflate input parameter"); |
743 | #endif |
744 | |
745 | /* initialise the input buffer */ |
746 | s->stream.next_in = (char*)SvPVbyte_force(buf, stmp) ; |
747 | s->stream.avail_in = SvCUR(buf); |
748 | |
749 | /* and retrieve the output buffer */ |
ea6efd2c |
750 | output = deRef_l(output, "bzinflate") ; |
bdb7fd9f |
751 | #ifdef UTF8_AVAILABLE |
752 | if (DO_UTF8(output)) |
753 | out_utf8 = TRUE ; |
754 | if (DO_UTF8(output) && !sv_utf8_downgrade(output, 1)) |
755 | croak("Wide character in " UNCOMPRESS_CLASS "::bzinflate output parameter"); |
756 | #endif |
757 | if((s->flags & FLAG_APPEND_OUTPUT) != FLAG_APPEND_OUTPUT) { |
758 | SvCUR_set(output, 0); |
759 | } |
80b215cb |
760 | |
ea6efd2c |
761 | /* Assume no output buffer - the code below will update if there is any available */ |
762 | s->stream.avail_out = 0; |
763 | |
764 | if (SvLEN(output)) { |
765 | prefix_length = cur_length = SvCUR(output) ; |
766 | |
767 | if (s->flags & FLAG_LIMIT_OUTPUT && SvLEN(output) - cur_length - 1 < bufinc) |
768 | { |
769 | Sv_Grow(output, bufinc + cur_length + 1) ; |
770 | } |
771 | |
772 | /* Only setup the stream output pointers if there is spare |
773 | capacity in the outout SV |
774 | */ |
775 | if (SvLEN(output) > cur_length + 1) |
776 | { |
777 | s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length; |
778 | increment = SvLEN(output) - cur_length - 1; |
779 | s->stream.avail_out = increment; |
780 | } |
781 | } |
782 | |
783 | s->bytesInflated = 0; |
784 | |
785 | RETVAL = BZ_OK; |
bdb7fd9f |
786 | |
787 | while (1) { |
788 | |
789 | if (s->stream.avail_out == 0) { |
790 | /* out of space in the output buffer so make it bigger */ |
ea6efd2c |
791 | Sv_Grow(output, SvLEN(output) + bufinc + 1) ; |
bdb7fd9f |
792 | cur_length += increment ; |
793 | s->stream.next_out = (char*) SvPVbyte_nolen(output) + cur_length ; |
794 | increment = bufinc ; |
795 | s->stream.avail_out = increment; |
796 | bufinc *= 2 ; |
797 | } |
798 | |
80b215cb |
799 | /*DispStream(s, "pre"); */ |
bdb7fd9f |
800 | RETVAL = BZ2_bzDecompress (&(s->stream)); |
801 | |
80b215cb |
802 | /*DispStream(s, "apres");*/ |
ea6efd2c |
803 | if (RETVAL != BZ_OK || s->flags & FLAG_LIMIT_OUTPUT) |
bdb7fd9f |
804 | break ; |
805 | |
806 | if (s->stream.avail_out == 0) |
807 | continue ; |
808 | |
809 | if (s->stream.avail_in == 0) { |
810 | RETVAL = BZ_OK ; |
811 | break ; |
812 | } |
813 | |
814 | } |
815 | |
816 | s->last_error = RETVAL ; |
817 | if (RETVAL == BZ_OK || RETVAL == BZ_STREAM_END) { |
818 | unsigned in ; |
819 | |
820 | s->bytesInflated = cur_length + increment - s->stream.avail_out - prefix_length; |
821 | s->uncompressedBytes += s->bytesInflated ; |
822 | s->compressedBytes += SvCUR(buf) - s->stream.avail_in ; |
823 | |
824 | SvPOK_only(output); |
825 | SvCUR_set(output, prefix_length + s->bytesInflated) ; |
826 | *SvEND(output) = '\0'; |
827 | #ifdef UTF8_AVAILABLE |
828 | if (out_utf8) |
829 | sv_utf8_upgrade(output); |
830 | #endif |
831 | SvSETMAGIC(output); |
832 | |
833 | /* fix the input buffer */ |
834 | if (s->flags & FLAG_CONSUME_INPUT) { |
835 | in = s->stream.avail_in ; |
836 | SvCUR_set(buf, in) ; |
837 | if (in) |
838 | Move(s->stream.next_in, SvPVbyte_nolen(buf), in, char) ; |
839 | *SvEND(buf) = '\0'; |
840 | SvSETMAGIC(buf); |
841 | } |
842 | } |
843 | OUTPUT: |
844 | RETVAL |
845 | |
846 | uLong |
847 | inflateCount(s) |
848 | Compress::Raw::Bunzip2 s |
849 | CODE: |
850 | RETVAL = s->bytesInflated; |
851 | OUTPUT: |
852 | RETVAL |
853 | |
854 | |
855 | void |
856 | DESTROY(s) |
857 | Compress::Raw::Bunzip2 s |
858 | CODE: |
859 | BZ2_bzDecompressEnd(&s->stream) ; |
860 | Safefree(s) ; |
861 | |
862 | |
863 | uLong |
864 | status(s) |
865 | Compress::Raw::Bunzip2 s |
866 | CODE: |
867 | RETVAL = s->last_error ; |
868 | OUTPUT: |
869 | RETVAL |
870 | |
871 | uLong |
872 | total_in_lo32(s) |
873 | Compress::Raw::Bunzip2 s |
874 | CODE: |
875 | RETVAL = s->stream.total_in_lo32 ; |
876 | OUTPUT: |
877 | RETVAL |
878 | |
879 | uLong |
880 | total_out_lo32(s) |
881 | Compress::Raw::Bunzip2 s |
882 | CODE: |
883 | RETVAL = s->stream.total_out_lo32 ; |
884 | OUTPUT: |
885 | RETVAL |
886 | |
887 | uLong |
888 | compressedBytes(s) |
889 | Compress::Raw::Bunzip2 s |
890 | CODE: |
891 | RETVAL = s->compressedBytes; |
892 | OUTPUT: |
893 | RETVAL |
894 | |
895 | uLong |
896 | uncompressedBytes(s) |
897 | Compress::Raw::Bunzip2 s |
898 | CODE: |
899 | RETVAL = s->uncompressedBytes; |
900 | OUTPUT: |
901 | RETVAL |
902 | |
903 | MODULE = Compress::Raw::Bzip2 PACKAGE = Compress::Raw::Bzip2 PREFIX = Zip_ |