Commit | Line | Data |
f4c6fd49 |
1 | /* Filename: Zlib.xs |
2 | * Author : Paul Marquess, <pmqs@cpan.org> |
3 | * Created : 30 January 2005 |
4 | * Version : 1.34 |
5 | * |
6 | * Copyright (c) 1995-2005 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 | /* Part of this code is based on the file gzio.c */ |
13 | |
14 | /* gzio.c -- IO on .gz files |
15 | * Copyright (C) 1995 Jean-loup Gailly. |
16 | * For conditions of distribution and use, see copyright notice in zlib.h |
17 | */ |
18 | |
19 | |
20 | |
21 | #include "EXTERN.h" |
22 | #include "perl.h" |
23 | #include "XSUB.h" |
24 | |
25 | #include <zlib.h> |
26 | |
27 | #ifndef PERL_VERSION |
28 | #include "patchlevel.h" |
29 | #define PERL_REVISION 5 |
30 | #define PERL_VERSION PATCHLEVEL |
31 | #define PERL_SUBVERSION SUBVERSION |
32 | #endif |
33 | |
34 | #if PERL_REVISION == 5 && (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION <= 75 )) |
35 | |
36 | # define PL_sv_undef sv_undef |
37 | # define PL_na na |
38 | # define PL_curcop curcop |
39 | # define PL_compiling compiling |
40 | |
41 | #endif |
42 | |
43 | #ifndef newSVuv |
44 | # define newSVuv newSViv |
45 | #endif |
46 | |
47 | typedef struct di_stream { |
48 | z_stream stream; |
49 | uLong bufsize; |
50 | uLong bufinc; |
51 | SV * dictionary ; |
52 | uLong dict_adler ; |
53 | bool deflateParams_out_valid ; |
54 | Bytef deflateParams_out_byte; |
55 | int Level; |
56 | int Method; |
57 | int WindowBits; |
58 | int MemLevel; |
59 | int Strategy; |
60 | } di_stream; |
61 | |
62 | typedef di_stream * deflateStream ; |
63 | typedef di_stream * Compress__Zlib__deflateStream ; |
64 | typedef di_stream * inflateStream ; |
65 | typedef di_stream * Compress__Zlib__inflateStream ; |
66 | |
67 | /* typedef gzFile Compress__Zlib__gzFile ; */ |
68 | typedef struct gzType { |
69 | gzFile gz ; |
70 | SV * buffer ; |
71 | uLong offset ; |
72 | bool closed ; |
73 | } gzType ; |
74 | |
75 | typedef gzType* Compress__Zlib__gzFile ; |
76 | |
77 | |
78 | |
79 | #define GZERRNO "Compress::Zlib::gzerrno" |
80 | |
81 | #define ZMALLOC(to, typ) ((to = (typ *)safemalloc(sizeof(typ))), \ |
82 | Zero(to,1,typ)) |
83 | |
84 | #define adlerInitial adler32(0L, Z_NULL, 0) |
85 | #define crcInitial crc32(0L, Z_NULL, 0) |
86 | |
87 | #if 1 |
88 | static char *my_z_errmsg[] = { |
89 | "need dictionary", /* Z_NEED_DICT 2 */ |
90 | "stream end", /* Z_STREAM_END 1 */ |
91 | "", /* Z_OK 0 */ |
92 | "file error", /* Z_ERRNO (-1) */ |
93 | "stream error", /* Z_STREAM_ERROR (-2) */ |
94 | "data error", /* Z_DATA_ERROR (-3) */ |
95 | "insufficient memory", /* Z_MEM_ERROR (-4) */ |
96 | "buffer error", /* Z_BUF_ERROR (-5) */ |
97 | "incompatible version",/* Z_VERSION_ERROR(-6) */ |
98 | ""}; |
99 | #endif |
100 | |
101 | |
102 | static int trace = 0 ; |
103 | |
104 | static void |
105 | #ifdef CAN_PROTOTYPE |
106 | SetGzErrorNo(int error_no) |
107 | #else |
108 | SetGzErrorNo(error_no) |
109 | int error_no ; |
110 | #endif |
111 | { |
112 | char * errstr ; |
113 | SV * gzerror_sv = perl_get_sv(GZERRNO, FALSE) ; |
114 | |
115 | if (error_no == Z_ERRNO) { |
116 | error_no = errno ; |
117 | errstr = Strerror(errno) ; |
118 | } |
119 | else |
120 | /* errstr = gzerror(fil, &error_no) ; */ |
121 | errstr = (char*) my_z_errmsg[2 - error_no]; |
122 | |
123 | if (SvIV(gzerror_sv) != error_no) { |
124 | sv_setiv(gzerror_sv, error_no) ; |
125 | sv_setpv(gzerror_sv, errstr) ; |
126 | SvIOK_on(gzerror_sv) ; |
127 | } |
128 | |
129 | } |
130 | |
131 | static void |
132 | #ifdef CAN_PROTOTYPE |
133 | SetGzError(gzFile file) |
134 | #else |
135 | SetGzError(file) |
136 | gzFile file ; |
137 | #endif |
138 | { |
139 | int error_no ; |
140 | |
141 | (void)gzerror(file, &error_no) ; |
142 | SetGzErrorNo(error_no) ; |
143 | } |
144 | |
145 | static void |
146 | #ifdef CAN_PROTOTYPE |
147 | DispHex(void * ptr, int length) |
148 | #else |
149 | DispHex(ptr, length) |
150 | void * ptr; |
151 | int length; |
152 | #endif |
153 | { |
154 | char * p = (char*)ptr; |
155 | int i; |
156 | for (i = 0; i < length; ++i) { |
157 | printf(" %02x", 0xFF & *(p+i)); |
158 | } |
159 | } |
160 | |
161 | |
162 | static void |
163 | #ifdef CAN_PROTOTYPE |
164 | DispStream(di_stream * s, char * message) |
165 | #else |
166 | DispStream(s, message) |
167 | di_stream * s; |
168 | char * message; |
169 | #endif |
170 | { |
171 | |
172 | #if 0 |
173 | if (! trace) |
174 | return ; |
175 | #endif |
176 | |
177 | printf("DispStream 0x%p - %s \n", s, message) ; |
178 | |
179 | if (!s) { |
180 | printf(" stream pointer is NULL\n"); |
181 | } |
182 | else { |
183 | printf(" stream 0x%p\n", &(s->stream)); |
184 | printf(" zalloc 0x%p\n", s->stream.zalloc); |
185 | printf(" zfree 0x%p\n", s->stream.zfree); |
186 | printf(" opaque 0x%p\n", s->stream.opaque); |
187 | if (s->stream.msg) |
188 | printf(" msg %s\n", s->stream.msg); |
189 | else |
190 | printf(" msg \n"); |
191 | printf(" next_in 0x%p", s->stream.next_in); |
192 | if (s->stream.next_in) { |
193 | printf(" =>"); |
194 | DispHex(s->stream.next_in, 4); |
195 | } |
196 | printf("\n"); |
197 | |
198 | printf(" next_out 0x%p", s->stream.next_out); |
199 | if (s->stream.next_out){ |
200 | printf(" =>"); |
201 | DispHex(s->stream.next_out, 4); |
202 | } |
203 | printf("\n"); |
204 | |
205 | printf(" avail_in %ld\n", s->stream.avail_in); |
206 | printf(" avail_out %ld\n", s->stream.avail_out); |
207 | printf(" total_in %ld\n", s->stream.total_in); |
208 | printf(" total_out %ld\n", s->stream.total_out); |
209 | printf(" adler 0x%lx\n", s->stream.adler); |
210 | printf(" reserved 0x%lx\n", s->stream.reserved); |
211 | printf(" bufsize %ld\n", s->bufsize); |
212 | printf(" dictionary 0x%p\n", s->dictionary); |
213 | printf(" dict_adler 0x%ld\n", s->dict_adler); |
214 | printf("\n"); |
215 | |
216 | } |
217 | } |
218 | |
219 | |
220 | static di_stream * |
221 | #ifdef CAN_PROTOTYPE |
222 | InitStream(uLong bufsize) |
223 | #else |
224 | InitStream(bufsize) |
225 | uLong bufsize ; |
226 | #endif |
227 | { |
228 | di_stream *s ; |
229 | |
230 | ZMALLOC(s, di_stream) ; |
231 | |
232 | if (s) { |
233 | s->bufsize = bufsize ; |
234 | s->bufinc = bufsize ; |
235 | } |
236 | |
237 | return s ; |
238 | |
239 | } |
240 | |
241 | #define SIZE 4096 |
242 | |
243 | static int |
244 | #ifdef CAN_PROTOTYPE |
245 | gzreadline(Compress__Zlib__gzFile file, SV * output) |
246 | #else |
247 | gzreadline(file, output) |
248 | Compress__Zlib__gzFile file ; |
249 | SV * output ; |
250 | #endif |
251 | { |
252 | |
253 | SV * store = file->buffer ; |
254 | char *nl = "\n"; |
255 | char *p; |
256 | char *out_ptr = SvPVX(store) ; |
257 | int n; |
258 | |
259 | while (1) { |
260 | |
261 | /* anything left from last time */ |
262 | if ((n = SvCUR(store))) { |
263 | |
264 | out_ptr = SvPVX(store) + file->offset ; |
265 | if ((p = ninstr(out_ptr, out_ptr + n - 1, nl, nl))) { |
266 | /* if (rschar != 0777 && */ |
267 | /* p = ninstr(out_ptr, out_ptr + n - 1, rs, rs+rslen-1)) { */ |
268 | |
269 | sv_catpvn(output, out_ptr, p - out_ptr + 1); |
270 | |
271 | file->offset += (p - out_ptr + 1) ; |
272 | n = n - (p - out_ptr + 1); |
273 | SvCUR_set(store, n) ; |
274 | return SvCUR(output); |
275 | } |
276 | else /* no EOL, so append the complete buffer */ |
277 | sv_catpvn(output, out_ptr, n); |
278 | |
279 | } |
280 | |
281 | |
282 | SvCUR_set(store, 0) ; |
283 | file->offset = 0 ; |
284 | out_ptr = SvPVX(store) ; |
285 | |
286 | n = gzread(file->gz, out_ptr, SIZE) ; |
287 | |
288 | if (n <= 0) |
289 | /* Either EOF or an error */ |
290 | /* so return what we have so far else signal eof */ |
291 | return (SvCUR(output)>0) ? SvCUR(output) : n ; |
292 | |
293 | SvCUR_set(store, n) ; |
294 | } |
295 | } |
296 | |
297 | static SV* |
298 | #ifdef CAN_PROTOTYPE |
299 | deRef(SV * sv, char * string) |
300 | #else |
301 | deRef(sv, string) |
302 | SV * sv ; |
303 | char * string; |
304 | #endif |
305 | { |
306 | if (SvROK(sv)) { |
307 | sv = SvRV(sv) ; |
308 | switch(SvTYPE(sv)) { |
309 | case SVt_PVAV: |
310 | case SVt_PVHV: |
311 | case SVt_PVCV: |
312 | croak("%s: buffer parameter is not a SCALAR reference", string); |
313 | } |
314 | if (SvROK(sv)) |
315 | croak("%s: buffer parameter is a reference to a reference", string) ; |
316 | } |
317 | |
318 | if (!SvOK(sv)) { |
319 | sv = newSVpv("", 0); |
320 | } |
321 | return sv ; |
322 | } |
323 | |
324 | #include "constants.h" |
325 | |
326 | MODULE = Compress::Zlib PACKAGE = Compress::Zlib PREFIX = Zip_ |
327 | |
328 | REQUIRE: 1.924 |
329 | PROTOTYPES: DISABLE |
330 | |
331 | INCLUDE: constants.xs |
332 | |
333 | BOOT: |
334 | /* Check this version of zlib is == 1 */ |
335 | if (zlibVersion()[0] != '1') |
336 | croak("Compress::Zlib needs zlib version 1.x\n") ; |
337 | |
338 | { |
339 | /* Create the $gzerror scalar */ |
340 | SV * gzerror_sv = perl_get_sv(GZERRNO, GV_ADDMULTI) ; |
341 | sv_setiv(gzerror_sv, 0) ; |
342 | sv_setpv(gzerror_sv, "") ; |
343 | SvIOK_on(gzerror_sv) ; |
344 | } |
345 | |
346 | |
347 | #define Zip_zlib_version() (char*)zlib_version |
348 | char* |
349 | Zip_zlib_version() |
350 | |
351 | |
352 | void |
353 | DispStream(s, message=NULL) |
354 | Compress::Zlib::inflateStream s |
355 | char * message |
356 | |
357 | Compress::Zlib::gzFile |
358 | gzopen_(path, mode) |
359 | char * path |
360 | char * mode |
361 | CODE: |
362 | gzFile gz ; |
363 | gz = gzopen(path, mode) ; |
364 | if (gz) { |
365 | ZMALLOC(RETVAL, gzType) ; |
366 | RETVAL->buffer = newSV(SIZE) ; |
367 | SvPOK_only(RETVAL->buffer) ; |
368 | SvCUR_set(RETVAL->buffer, 0) ; |
369 | RETVAL->offset = 0 ; |
370 | RETVAL->gz = gz ; |
371 | RETVAL->closed = FALSE ; |
372 | SetGzErrorNo(0) ; |
373 | } |
374 | else { |
375 | RETVAL = NULL ; |
376 | SetGzErrorNo(errno ? Z_ERRNO : Z_MEM_ERROR) ; |
377 | } |
378 | OUTPUT: |
379 | RETVAL |
380 | |
381 | |
382 | Compress::Zlib::gzFile |
383 | gzdopen_(fh, mode, offset) |
384 | int fh |
385 | char * mode |
386 | long offset |
387 | CODE: |
388 | gzFile gz ; |
389 | if (offset != -1) |
390 | lseek(fh, offset, 0) ; |
391 | gz = gzdopen(fh, mode) ; |
392 | if (gz) { |
393 | ZMALLOC(RETVAL, gzType) ; |
394 | RETVAL->buffer = newSV(SIZE) ; |
395 | SvPOK_only(RETVAL->buffer) ; |
396 | SvCUR_set(RETVAL->buffer, 0) ; |
397 | RETVAL->offset = 0 ; |
398 | RETVAL->gz = gz ; |
399 | RETVAL->closed = FALSE ; |
400 | SetGzErrorNo(0) ; |
401 | } |
402 | else { |
403 | RETVAL = NULL ; |
404 | SetGzErrorNo(errno ? Z_ERRNO : Z_MEM_ERROR) ; |
405 | } |
406 | OUTPUT: |
407 | RETVAL |
408 | |
409 | |
410 | MODULE = Compress::Zlib PACKAGE = Compress::Zlib::gzFile PREFIX = Zip_ |
411 | |
412 | #define Zip_gzread(file, buf, len) gzread(file->gz, bufp, len) |
413 | |
414 | int |
415 | Zip_gzread(file, buf, len=4096) |
416 | Compress::Zlib::gzFile file |
417 | unsigned len |
418 | SV * buf |
419 | voidp bufp = NO_INIT |
420 | uLong bufsize = 0 ; |
421 | int RETVAL = 0 ; |
422 | CODE: |
423 | if (SvREADONLY(buf) && PL_curcop != &PL_compiling) |
424 | croak("gzread: buffer parameter is read-only"); |
f2e5e569 |
425 | SvUPGRADE(buf, SVt_PV); |
f4c6fd49 |
426 | SvPOK_only(buf); |
427 | SvCUR_set(buf, 0); |
428 | /* any left over from gzreadline ? */ |
429 | if ((bufsize = SvCUR(file->buffer)) > 0) { |
430 | uLong movesize ; |
431 | |
432 | if (bufsize < len) { |
433 | movesize = bufsize ; |
434 | len -= movesize ; |
435 | } |
436 | else { |
437 | movesize = len ; |
438 | len = 0 ; |
439 | } |
440 | RETVAL = movesize ; |
441 | |
442 | sv_catpvn(buf, SvPVX(file->buffer) + file->offset, movesize); |
443 | |
444 | file->offset += movesize ; |
445 | SvCUR_set(file->buffer, bufsize - movesize) ; |
446 | } |
447 | |
448 | if (len) { |
449 | bufp = (Byte*)SvGROW(buf, bufsize+len+1); |
450 | RETVAL = gzread(file->gz, ((Bytef*)bufp)+bufsize, len) ; |
451 | SetGzError(file->gz) ; |
452 | if (RETVAL >= 0) { |
453 | RETVAL += bufsize ; |
454 | SvCUR_set(buf, RETVAL) ; |
455 | *SvEND(buf) = '\0'; |
456 | } |
457 | } |
458 | OUTPUT: |
459 | RETVAL |
460 | buf |
461 | |
462 | int |
463 | gzreadline(file, buf) |
464 | Compress::Zlib::gzFile file |
465 | SV * buf |
466 | int RETVAL = 0; |
467 | CODE: |
468 | if (SvREADONLY(buf) && PL_curcop != &PL_compiling) |
469 | croak("gzreadline: buffer parameter is read-only"); |
f2e5e569 |
470 | SvUPGRADE(buf, SVt_PV); |
f4c6fd49 |
471 | SvPOK_only(buf); |
472 | /* sv_setpvn(buf, "", SIZE) ; */ |
473 | SvGROW(buf, SIZE) ; |
474 | SvCUR_set(buf, 0); |
475 | RETVAL = gzreadline(file, buf) ; |
476 | SetGzError(file->gz) ; |
477 | OUTPUT: |
478 | RETVAL |
479 | buf |
480 | CLEANUP: |
481 | if (RETVAL >= 0) { |
482 | /* SvCUR(buf) = RETVAL; */ |
483 | /* Don't need to explicitly terminate with '\0', because |
484 | sv_catpvn aready has */ |
485 | } |
486 | |
487 | #define Zip_gzwrite(file, buf) gzwrite(file->gz, buf, (unsigned)len) |
488 | int |
489 | Zip_gzwrite(file, buf) |
490 | Compress::Zlib::gzFile file |
491 | STRLEN len = NO_INIT |
492 | voidp buf = (voidp)SvPV(ST(1), len) ; |
493 | CLEANUP: |
494 | SetGzError(file->gz) ; |
495 | |
496 | #define Zip_gzflush(file, flush) gzflush(file->gz, flush) |
497 | int |
498 | Zip_gzflush(file, flush) |
499 | Compress::Zlib::gzFile file |
500 | int flush |
501 | CLEANUP: |
502 | SetGzError(file->gz) ; |
503 | |
504 | #define Zip_gzclose(file) gzclose(file->gz) |
505 | int |
506 | Zip_gzclose(file) |
507 | Compress::Zlib::gzFile file |
508 | CLEANUP: |
509 | file->closed = TRUE ; |
510 | SetGzErrorNo(RETVAL) ; |
511 | |
512 | |
513 | #define Zip_gzeof(file) gzeof(file->gz) |
514 | int |
515 | Zip_gzeof(file) |
516 | Compress::Zlib::gzFile file |
517 | CODE: |
518 | #ifdef OLD_ZLIB |
519 | croak("gzeof needs zlib 1.0.6 or better") ; |
520 | #else |
521 | RETVAL = gzeof(file->gz); |
522 | #endif |
523 | OUTPUT: |
524 | RETVAL |
525 | |
526 | |
527 | #define Zip_gzsetparams(file,l,s) gzsetparams(file->gz,l,s) |
528 | int |
529 | Zip_gzsetparams(file, level, strategy) |
530 | Compress::Zlib::gzFile file |
531 | int level |
532 | int strategy |
533 | CODE: |
534 | #ifdef OLD_ZLIB |
535 | croak("gzsetparams needs zlib 1.0.6 or better") ; |
536 | #else |
537 | RETVAL = gzsetparams(file->gz, level, strategy); |
538 | #endif |
539 | OUTPUT: |
540 | RETVAL |
541 | |
542 | void |
543 | DESTROY(file) |
544 | Compress::Zlib::gzFile file |
545 | CODE: |
546 | if (! file->closed) |
547 | Zip_gzclose(file) ; |
548 | SvREFCNT_dec(file->buffer) ; |
549 | safefree((char*)file) ; |
550 | |
551 | #define Zip_gzerror(file) (char*)gzerror(file->gz, &errnum) |
552 | |
553 | char * |
554 | Zip_gzerror(file) |
555 | Compress::Zlib::gzFile file |
556 | int errnum = NO_INIT |
557 | CLEANUP: |
558 | sv_setiv(ST(0), errnum) ; |
559 | SvPOK_on(ST(0)) ; |
560 | |
561 | |
562 | |
563 | MODULE = Compress::Zlib PACKAGE = Compress::Zlib PREFIX = Zip_ |
564 | |
565 | |
566 | #define Zip_adler32(buf, adler) adler32(adler, buf, (uInt)len) |
567 | |
568 | uLong |
569 | Zip_adler32(buf, adler=adlerInitial) |
570 | uLong adler = NO_INIT |
571 | STRLEN len = NO_INIT |
572 | Bytef * buf = NO_INIT |
573 | SV * sv = ST(0) ; |
574 | INIT: |
575 | /* If the buffer is a reference, dereference it */ |
576 | sv = deRef(sv, "adler32") ; |
577 | buf = (Byte*)SvPV(sv, len) ; |
578 | |
579 | if (items < 2) |
580 | adler = adlerInitial; |
581 | else if (SvOK(ST(1))) |
582 | adler = SvUV(ST(1)) ; |
583 | else |
584 | adler = adlerInitial; |
585 | |
586 | #define Zip_crc32(buf, crc) crc32(crc, buf, (uInt)len) |
587 | |
588 | uLong |
589 | Zip_crc32(buf, crc=crcInitial) |
590 | uLong crc = NO_INIT |
591 | STRLEN len = NO_INIT |
592 | Bytef * buf = NO_INIT |
593 | SV * sv = ST(0) ; |
594 | INIT: |
595 | /* If the buffer is a reference, dereference it */ |
596 | sv = deRef(sv, "crc32") ; |
597 | buf = (Byte*)SvPV(sv, len) ; |
598 | |
599 | if (items < 2) |
600 | crc = crcInitial; |
601 | else if (SvOK(ST(1))) |
602 | crc = SvUV(ST(1)) ; |
603 | else |
604 | crc = crcInitial; |
605 | |
606 | MODULE = Compress::Zlib PACKAGE = Compress::Zlib |
607 | |
608 | void |
609 | _deflateInit(level, method, windowBits, memLevel, strategy, bufsize, dictionary) |
610 | int level |
611 | int method |
612 | int windowBits |
613 | int memLevel |
614 | int strategy |
615 | uLong bufsize |
616 | SV * dictionary |
617 | PPCODE: |
618 | |
619 | int err ; |
620 | deflateStream s ; |
621 | |
622 | if (trace) |
623 | warn("in _deflateInit(level=%d, method=%d, windowBits=%d, memLevel=%d, strategy=%d, bufsize=%d\n", |
624 | level, method, windowBits, memLevel, strategy, bufsize) ; |
625 | if ((s = InitStream(bufsize)) ) { |
626 | |
627 | s->Level = level; |
628 | s->Method = method; |
629 | s->WindowBits = windowBits; |
630 | s->MemLevel = memLevel; |
631 | s->Strategy = strategy; |
632 | |
633 | err = deflateInit2(&(s->stream), level, |
634 | method, windowBits, memLevel, strategy); |
635 | |
636 | /* Check if a dictionary has been specified */ |
637 | if (err == Z_OK && SvCUR(dictionary)) { |
638 | err = deflateSetDictionary(&(s->stream), (const Bytef*) SvPVX(dictionary), |
639 | SvCUR(dictionary)) ; |
640 | s->dict_adler = s->stream.adler ; |
641 | } |
642 | |
643 | if (err != Z_OK) { |
644 | Safefree(s) ; |
645 | s = NULL ; |
646 | } |
647 | |
648 | } |
649 | else |
650 | err = Z_MEM_ERROR ; |
651 | |
652 | XPUSHs(sv_setref_pv(sv_newmortal(), |
653 | "Compress::Zlib::deflateStream", (void*)s)); |
654 | if (GIMME == G_ARRAY) |
655 | XPUSHs(sv_2mortal(newSViv(err))) ; |
656 | |
657 | void |
658 | _inflateInit(windowBits, bufsize, dictionary) |
659 | int windowBits |
660 | uLong bufsize |
661 | SV * dictionary |
662 | PPCODE: |
663 | |
664 | int err = Z_OK ; |
665 | inflateStream s ; |
666 | |
667 | if (trace) |
668 | warn("in _inflateInit(windowBits=%d, bufsize=%d, dictionary=%d\n", |
669 | windowBits, bufsize, SvCUR(dictionary)) ; |
670 | if ((s = InitStream(bufsize)) ) { |
671 | |
672 | s->WindowBits = windowBits; |
673 | |
674 | err = inflateInit2(&(s->stream), windowBits); |
675 | |
676 | if (err != Z_OK) { |
677 | Safefree(s) ; |
678 | s = NULL ; |
679 | } |
680 | else if (SvCUR(dictionary)) { |
681 | /* Dictionary specified - take a copy for use in inflate */ |
682 | s->dictionary = newSVsv(dictionary) ; |
683 | } |
684 | } |
685 | else |
686 | err = Z_MEM_ERROR ; |
687 | |
688 | XPUSHs(sv_setref_pv(sv_newmortal(), |
689 | "Compress::Zlib::inflateStream", (void*)s)); |
690 | if (GIMME == G_ARRAY) |
691 | XPUSHs(sv_2mortal(newSViv(err))) ; |
692 | |
693 | |
694 | |
695 | MODULE = Compress::Zlib PACKAGE = Compress::Zlib::deflateStream |
696 | |
697 | void |
698 | DispStream(s, message=NULL) |
699 | Compress::Zlib::deflateStream s |
700 | char * message |
701 | |
702 | void |
703 | deflate (s, buf) |
704 | Compress::Zlib::deflateStream s |
705 | SV * buf |
706 | uLong outsize = NO_INIT |
707 | SV * output = NO_INIT |
708 | int err = 0; |
709 | PPCODE: |
710 | |
711 | /* If the buffer is a reference, dereference it */ |
712 | buf = deRef(buf, "deflate") ; |
713 | |
714 | /* initialise the input buffer */ |
715 | s->stream.next_in = (Bytef*)SvPV(buf, *(STRLEN*)&s->stream.avail_in) ; |
716 | /* s->stream.next_in = (Bytef*)SvPVX(buf); */ |
717 | s->stream.avail_in = SvCUR(buf) ; |
718 | |
719 | /* and the output buffer */ |
720 | /* output = sv_2mortal(newSVpv("", s->bufinc)) ; */ |
721 | output = sv_2mortal(newSV(s->bufinc)) ; |
722 | SvPOK_only(output) ; |
723 | SvCUR_set(output, 0) ; |
724 | outsize = s->bufinc ; |
725 | s->stream.next_out = (Bytef*) SvPVX(output) ; |
726 | s->stream.avail_out = outsize; |
727 | |
728 | /* Check for saved output from deflateParams */ |
729 | if (s->deflateParams_out_valid) { |
730 | *(s->stream.next_out) = s->deflateParams_out_byte; |
731 | ++ s->stream.next_out; |
732 | -- s->stream.avail_out ; |
733 | s->deflateParams_out_valid = FALSE; |
734 | } |
735 | |
736 | while (s->stream.avail_in != 0) { |
737 | |
738 | if (s->stream.avail_out == 0) { |
739 | s->bufinc *= 2 ; |
740 | SvGROW(output, outsize + s->bufinc) ; |
741 | s->stream.next_out = (Bytef*) SvPVX(output) + outsize ; |
742 | outsize += s->bufinc ; |
743 | s->stream.avail_out = s->bufinc ; |
744 | } |
745 | err = deflate(&(s->stream), Z_NO_FLUSH); |
746 | if (err != Z_OK) |
747 | break; |
748 | } |
749 | |
750 | if (err == Z_OK) { |
751 | SvPOK_only(output); |
752 | SvCUR_set(output, outsize - s->stream.avail_out) ; |
753 | } |
754 | else |
755 | output = &PL_sv_undef ; |
756 | XPUSHs(output) ; |
757 | if (GIMME == G_ARRAY) |
758 | XPUSHs(sv_2mortal(newSViv(err))) ; |
759 | |
760 | |
761 | |
762 | void |
763 | flush(s, f=Z_FINISH) |
764 | Compress::Zlib::deflateStream s |
765 | int f |
766 | uLong outsize = NO_INIT |
767 | SV * output = NO_INIT |
768 | int err = Z_OK ; |
769 | PPCODE: |
770 | |
771 | s->stream.avail_in = 0; /* should be zero already anyway */ |
772 | |
773 | /* output = sv_2mortal(newSVpv("", s->bufinc)) ; */ |
774 | output = sv_2mortal(newSV(s->bufinc)) ; |
775 | SvPOK_only(output) ; |
776 | SvCUR_set(output, 0) ; |
777 | outsize = s->bufinc ; |
778 | s->stream.next_out = (Bytef*) SvPVX(output) ; |
779 | s->stream.avail_out = outsize; |
780 | |
781 | /* Check for saved output from deflateParams */ |
782 | if (s->deflateParams_out_valid) { |
783 | *(s->stream.next_out) = s->deflateParams_out_byte; |
784 | ++ s->stream.next_out; |
785 | -- s->stream.avail_out ; |
786 | s->deflateParams_out_valid = FALSE; |
787 | } |
788 | |
789 | for (;;) { |
790 | if (s->stream.avail_out == 0) { |
791 | /* consumed all the available output, so extend it */ |
792 | s->bufinc *= 2 ; |
793 | SvGROW(output, outsize + s->bufinc) ; |
794 | s->stream.next_out = (Bytef*)SvPVX(output) + outsize ; |
795 | outsize += s->bufinc ; |
796 | s->stream.avail_out = s->bufinc ; |
797 | } |
798 | err = deflate(&(s->stream), f); |
799 | |
800 | /* deflate has finished flushing only when it hasn't used up |
801 | * all the available space in the output buffer: |
802 | */ |
803 | if (s->stream.avail_out != 0 || err != Z_OK ) |
804 | break; |
805 | } |
806 | |
807 | err = (err == Z_STREAM_END ? Z_OK : err) ; |
808 | |
809 | if (err == Z_OK) { |
810 | SvPOK_only(output); |
811 | SvCUR_set(output, outsize - s->stream.avail_out) ; |
812 | } |
813 | else |
814 | output = &PL_sv_undef ; |
815 | XPUSHs(output) ; |
816 | if (GIMME == G_ARRAY) |
817 | XPUSHs(sv_2mortal(newSViv(err))) ; |
818 | |
819 | int |
820 | _deflateParams(s, flags, level, strategy, bufsize) |
821 | Compress::Zlib::deflateStream s |
822 | int flags |
823 | int level |
824 | int strategy |
825 | uLong bufsize |
826 | CODE: |
827 | if (flags & 1) |
828 | s->Level = level ; |
829 | if (flags & 2) |
830 | s->Strategy = strategy ; |
831 | if (bufsize) { |
832 | s->bufsize = bufsize; |
833 | s->bufinc = bufsize; |
834 | } |
835 | s->stream.avail_in = 0; |
836 | s->stream.next_out = &(s->deflateParams_out_byte) ; |
837 | s->stream.avail_out = 1; |
838 | RETVAL = deflateParams(&(s->stream), s->Level, s->Strategy); |
839 | s->deflateParams_out_valid = |
840 | (RETVAL == Z_OK && s->stream.avail_out == 0) ; |
841 | OUTPUT: |
842 | RETVAL |
843 | |
844 | |
845 | int |
846 | get_Level(s) |
847 | Compress::Zlib::deflateStream s |
848 | CODE: |
849 | RETVAL = s->Level ; |
850 | OUTPUT: |
851 | RETVAL |
852 | |
853 | int |
854 | get_Strategy(s) |
855 | Compress::Zlib::deflateStream s |
856 | CODE: |
857 | RETVAL = s->Strategy ; |
858 | OUTPUT: |
859 | RETVAL |
860 | |
861 | void |
862 | DESTROY(s) |
863 | Compress::Zlib::deflateStream s |
864 | CODE: |
865 | deflateEnd(&s->stream) ; |
866 | if (s->dictionary) |
867 | SvREFCNT_dec(s->dictionary) ; |
868 | Safefree(s) ; |
869 | |
870 | |
871 | uLong |
872 | dict_adler(s) |
873 | Compress::Zlib::deflateStream s |
874 | CODE: |
875 | RETVAL = s->dict_adler ; |
876 | OUTPUT: |
877 | RETVAL |
878 | |
879 | uLong |
880 | total_in(s) |
881 | Compress::Zlib::deflateStream s |
882 | CODE: |
883 | RETVAL = s->stream.total_in ; |
884 | OUTPUT: |
885 | RETVAL |
886 | |
887 | uLong |
888 | total_out(s) |
889 | Compress::Zlib::deflateStream s |
890 | CODE: |
891 | RETVAL = s->stream.total_out ; |
892 | OUTPUT: |
893 | RETVAL |
894 | |
895 | char* |
896 | msg(s) |
897 | Compress::Zlib::deflateStream s |
898 | CODE: |
899 | RETVAL = s->stream.msg; |
900 | OUTPUT: |
901 | RETVAL |
902 | |
903 | |
904 | MODULE = Compress::Zlib PACKAGE = Compress::Zlib::inflateStream |
905 | |
906 | void |
907 | DispStream(s, message=NULL) |
908 | Compress::Zlib::inflateStream s |
909 | char * message |
910 | |
911 | void |
912 | inflate (s, buf) |
913 | Compress::Zlib::inflateStream s |
914 | SV * buf |
915 | uLong outsize = NO_INIT |
916 | SV * output = NO_INIT |
917 | int err = Z_OK ; |
918 | ALIAS: |
919 | __unc_inflate = 1 |
920 | PPCODE: |
921 | |
922 | /* If the buffer is a reference, dereference it */ |
923 | buf = deRef(buf, "inflate") ; |
924 | |
925 | /* initialise the input buffer */ |
926 | s->stream.next_in = (Bytef*)SvPVX(buf) ; |
927 | s->stream.avail_in = SvCUR(buf) ; |
928 | |
929 | /* and the output buffer */ |
930 | output = sv_2mortal(newSV(s->bufinc+1)) ; |
931 | SvPOK_only(output) ; |
932 | SvCUR_set(output, 0) ; |
933 | outsize = s->bufinc ; |
934 | s->stream.next_out = (Bytef*) SvPVX(output) ; |
935 | s->stream.avail_out = outsize; |
936 | |
937 | while (1) { |
938 | |
939 | if (s->stream.avail_out == 0) { |
940 | s->bufinc *= 2 ; |
941 | SvGROW(output, outsize + s->bufinc+1) ; |
942 | s->stream.next_out = (Bytef*) SvPVX(output) + outsize ; |
943 | outsize += s->bufinc ; |
944 | s->stream.avail_out = s->bufinc ; |
945 | } |
946 | |
947 | err = inflate(&(s->stream), Z_SYNC_FLUSH); |
948 | if (err == Z_BUF_ERROR) { |
949 | if (s->stream.avail_out == 0) |
950 | continue ; |
951 | if (s->stream.avail_in == 0) { |
952 | err = Z_OK ; |
953 | break ; |
954 | } |
955 | } |
956 | |
957 | if (err == Z_NEED_DICT && s->dictionary) { |
958 | s->dict_adler = s->stream.adler ; |
959 | err = inflateSetDictionary(&(s->stream), |
960 | (const Bytef*)SvPVX(s->dictionary), |
961 | SvCUR(s->dictionary)); |
962 | } |
963 | |
964 | if (err != Z_OK) |
965 | break; |
966 | } |
967 | |
968 | if (err == Z_OK || err == Z_STREAM_END || err == Z_DATA_ERROR) { |
969 | unsigned in ; |
970 | |
971 | SvPOK_only(output); |
972 | SvCUR_set(output, outsize - s->stream.avail_out) ; |
973 | *SvEND(output) = '\0'; |
974 | |
975 | /* fix the input buffer */ |
976 | if (ix == 0) { |
977 | in = s->stream.avail_in ; |
978 | SvCUR_set(buf, in) ; |
979 | if (in) |
980 | Move(s->stream.next_in, SvPVX(buf), in, char) ; |
981 | *SvEND(buf) = '\0'; |
982 | SvSETMAGIC(buf); |
983 | } |
984 | } |
985 | else |
986 | output = &PL_sv_undef ; |
987 | XPUSHs(output) ; |
988 | if (GIMME == G_ARRAY) |
989 | XPUSHs(sv_2mortal(newSViv(err))) ; |
990 | |
991 | int |
992 | inflateSync (s, buf) |
993 | Compress::Zlib::inflateStream s |
994 | SV * buf |
995 | CODE: |
996 | |
997 | /* If the buffer is a reference, dereference it */ |
998 | buf = deRef(buf, "inflateSync") ; |
999 | |
1000 | /* initialise the input buffer */ |
1001 | s->stream.next_in = (Bytef*)SvPVX(buf) ; |
1002 | s->stream.avail_in = SvCUR(buf) ; |
1003 | |
1004 | /* inflateSync doesn't create any output */ |
1005 | s->stream.next_out = (Bytef*) NULL; |
1006 | s->stream.avail_out = 0; |
1007 | |
1008 | RETVAL = inflateSync(&(s->stream)); |
1009 | { |
1010 | /* fix the input buffer */ |
1011 | unsigned in = s->stream.avail_in ; |
1012 | |
1013 | SvCUR_set(buf, in) ; |
1014 | if (in) |
1015 | Move(s->stream.next_in, SvPVX(buf), in, char) ; |
1016 | *SvEND(buf) = '\0'; |
1017 | SvSETMAGIC(buf); |
1018 | } |
1019 | OUTPUT: |
1020 | RETVAL |
1021 | |
1022 | void |
1023 | DESTROY(s) |
1024 | Compress::Zlib::inflateStream s |
1025 | CODE: |
1026 | inflateEnd(&s->stream) ; |
1027 | if (s->dictionary) |
1028 | SvREFCNT_dec(s->dictionary) ; |
1029 | Safefree(s) ; |
1030 | |
1031 | |
1032 | uLong |
1033 | dict_adler(s) |
1034 | Compress::Zlib::inflateStream s |
1035 | CODE: |
1036 | RETVAL = s->dict_adler ; |
1037 | OUTPUT: |
1038 | RETVAL |
1039 | |
1040 | uLong |
1041 | total_in(s) |
1042 | Compress::Zlib::inflateStream s |
1043 | CODE: |
1044 | RETVAL = s->stream.total_in ; |
1045 | OUTPUT: |
1046 | RETVAL |
1047 | |
1048 | uLong |
1049 | total_out(s) |
1050 | Compress::Zlib::inflateStream s |
1051 | CODE: |
1052 | RETVAL = s->stream.total_out ; |
1053 | OUTPUT: |
1054 | RETVAL |
1055 | |
1056 | char* |
1057 | msg(s) |
1058 | Compress::Zlib::inflateStream s |
1059 | CODE: |
1060 | RETVAL = s->stream.msg; |
1061 | OUTPUT: |
1062 | RETVAL |
1063 | |
1064 | |