File Coverage

Zlib.xs
Criterion Covered Total %
statement 216 441 49.0
branch n/a
condition n/a
subroutine n/a
pod n/a
total 216 441 49.0


line stmt bran cond sub pod time code
1             /* Filename: Zlib.xs
2             * Author : Paul Marquess, <pmqs@cpan.org>
3             * Created : 22nd January 1996
4             * Version : 2.000
5             *
6             * Copyright (c) 1995-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             /* Parts of this code are based on the files gzio.c and gzappend.c from
13              * the standard zlib source distribution. Below are the copyright statements
14              * from each.
15              */
16            
17             /* gzio.c -- IO on .gz files
18              * Copyright (C) 1995 Jean-loup Gailly.
19              * For conditions of distribution and use, see copyright notice in zlib.h
20              */
21            
22             /* gzappend -- command to append to a gzip file
23              
24               Copyright (C) 2003 Mark Adler, all rights reserved
25               version 1.1, 4 Nov 2003
26             */
27            
28            
29            
30             #include "EXTERN.h"
31             #include "perl.h"
32             #include "XSUB.h"
33            
34             #include <zlib.h>
35            
36             /* zlib prior to 1.06 doesn't know about z_off_t */
37             #ifndef z_off_t
38             # define z_off_t long
39             #endif
40            
41             #if ! defined(ZLIB_VERNUM) || ZLIB_VERNUM < 0x1200
42             # define NEED_DUMMY_BYTE_AT_END
43             #endif
44            
45             #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1210
46             # define MAGIC_APPEND
47             #endif
48            
49             #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1221
50             # define AT_LEAST_ZLIB_1_2_2_1
51             #endif
52            
53             #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1223
54             # define AT_LEAST_ZLIB_1_2_2_3
55             #endif
56            
57             #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
58             # define AT_LEAST_ZLIB_1_2_3
59             #endif
60            
61             #define NEED_sv_2pvbyte
62             #define NEED_sv_2pv_nolen
63             #include "ppport.h"
64            
65             #if PERL_REVISION == 5 && (PERL_VERSION < 8 || (PERL_VERSION == 8 && PERL_SUBVERSION < 4 ))
66            
67             # ifdef SvPVbyte_force
68             # undef SvPVbyte_force
69             # endif
70            
71             # define SvPVbyte_force(sv,lp) SvPV_force(sv,lp)
72            
73             #endif
74            
75             #ifndef SvPVbyte_nolen
76             # define SvPVbyte_nolen SvPV_nolen
77             #endif
78            
79            
80            
81             #if 0
82             # ifndef SvPVbyte_nolen
83             # define SvPVbyte_nolen SvPV_nolen
84             # endif
85            
86             # ifndef SvPVbyte_force
87             # define SvPVbyte_force(sv,lp) SvPV_force(sv,lp)
88             # endif
89             #endif
90            
91             #if PERL_REVISION == 5 && (PERL_VERSION >= 8 || (PERL_VERSION == 8 && PERL_SUBVERSION < 4 ))
92             # define UTF8_AVAILABLE
93             #endif
94            
95             typedef int DualType ;
96             typedef int int_undef ;
97            
98             typedef struct di_stream {
99             int flags ;
100             #define FLAG_APPEND 1
101             #define FLAG_CRC32 2
102             #define FLAG_ADLER32 4
103             #define FLAG_CONSUME_INPUT 8
104             uLong crc32 ;
105             uLong adler32 ;
106             z_stream stream;
107             uLong bufsize;
108             SV * dictionary ;
109             uLong dict_adler ;
110             int last_error ;
111             bool zip_mode ;
112             #define SETP_BYTE
113             #ifdef SETP_BYTE
114             bool deflateParams_out_valid ;
115             Bytef deflateParams_out_byte;
116             #else
117             #define deflateParams_BUFFER_SIZE 0x4000
118             uLong deflateParams_out_length;
119             Bytef* deflateParams_out_buffer;
120             #endif
121             int Level;
122             int Method;
123             int WindowBits;
124             int MemLevel;
125             int Strategy;
126             uLong bytesInflated ;
127             uLong compressedBytes ;
128             uLong uncompressedBytes ;
129             #ifdef MAGIC_APPEND
130            
131             #define WINDOW_SIZE 32768U
132            
133             bool matchedEndBlock;
134             Bytef* window ;
135             int window_lastbit, window_left, window_full;
136             unsigned window_have;
137             off_t window_lastoff, window_end;
138             off_t window_endOffset;
139            
140             uLong lastBlockOffset ;
141             unsigned char window_lastByte ;
142            
143            
144             #endif
145             } di_stream;
146            
147             typedef di_stream * deflateStream ;
148             typedef di_stream * Compress__Raw__Zlib__deflateStream ;
149             typedef di_stream * inflateStream ;
150             typedef di_stream * Compress__Raw__Zlib__inflateStream ;
151             typedef di_stream * Compress__Raw__Zlib__inflateScanStream ;
152            
153             #define ZMALLOC(to, typ) ((to = (typ *)safemalloc(sizeof(typ))), \
154             Zero(to,1,typ))
155            
156             /* Figure out the Operating System */
157             #ifdef MSDOS
158             # define OS_CODE 0x00
159             #endif
160            
161             #if defined(AMIGA) || defined(AMIGAOS)
162             # define OS_CODE 0x01
163             #endif
164            
165             #if defined(VAXC) || defined(VMS)
166             # define OS_CODE 0x02
167             #endif
168            
169             #if 0 /* VM/CMS */
170             # define OS_CODE 0x04
171             #endif
172            
173             #if defined(ATARI) || defined(atarist)
174             # define OS_CODE 0x05
175             #endif
176            
177             #ifdef OS2
178             # define OS_CODE 0x06
179             #endif
180            
181             #if defined(MACOS) || defined(TARGET_OS_MAC)
182             # define OS_CODE 0x07
183             #endif
184            
185             #if 0 /* Z-System */
186             # define OS_CODE 0x08
187             #endif
188            
189             #if 0 /* CP/M */
190             # define OS_CODE 0x09
191             #endif
192            
193             #ifdef TOPS20
194             # define OS_CODE 0x0a
195             #endif
196            
197             #ifdef WIN32 /* Window 95 & Windows NT */
198             # define OS_CODE 0x0b
199             #endif
200            
201             #if 0 /* QDOS */
202             # define OS_CODE 0x0c
203             #endif
204            
205             #if 0 /* Acorn RISCOS */
206             # define OS_CODE 0x0d
207             #endif
208            
209             #if 0 /* ??? */
210             # define OS_CODE 0x0e
211             #endif
212            
213             #ifdef __50SERIES /* Prime/PRIMOS */
214             # define OS_CODE 0x0F
215             #endif
216            
217             /* Default to UNIX */
218             #ifndef OS_CODE
219             # define OS_CODE 0x03 /* assume Unix */
220             #endif
221            
222             #ifndef GZIP_OS_CODE
223             # define GZIP_OS_CODE OS_CODE
224             #endif
225            
226             #define adlerInitial adler32(0L, Z_NULL, 0)
227             #define crcInitial crc32(0L, Z_NULL, 0)
228            
229            
230             static const char * const my_z_errmsg[] = {
231             "need dictionary", /* Z_NEED_DICT 2 */
232             "stream end", /* Z_STREAM_END 1 */
233             "", /* Z_OK 0 */
234             "file error", /* Z_ERRNO (-1) */
235             "stream error", /* Z_STREAM_ERROR (-2) */
236             "data error", /* Z_DATA_ERROR (-3) */
237             "insufficient memory", /* Z_MEM_ERROR (-4) */
238             "buffer error", /* Z_BUF_ERROR (-5) */
239             "incompatible version",/* Z_VERSION_ERROR(-6) */
240             ""};
241            
242             #define setDUALstatus(var, err) \
243             sv_setnv(var, (double)err) ; \
244             sv_setpv(var, ((err) ? GetErrorString(err) : "")) ; \
245             SvNOK_on(var);
246            
247            
248             #if defined(__SYMBIAN32__)
249             # define NO_WRITEABLE_DATA
250             #endif
251            
252             #define TRACE_DEFAULT 0
253            
254             #ifdef NO_WRITEABLE_DATA
255             # define trace TRACE_DEFAULT
256             #else
257             static int trace = TRACE_DEFAULT ;
258             #endif
259            
260             /* Dodge PerlIO hiding of these functions. */
261             #undef printf
262            
263             static char *
264             #ifdef CAN_PROTOTYPE
265             GetErrorString(int error_no)
266             #else
267             GetErrorString(error_no)
268             int error_no ;
269             #endif
270 201           {
271             dTHX;
272             char * errstr ;
273            
274 201           if (error_no == Z_ERRNO) {
275 0           errstr = Strerror(errno) ;
276             }
277             else
278             /* errstr = gzerror(fil, &error_no) ; */
279 201           errstr = (char*) my_z_errmsg[2 - error_no];
280            
281             return errstr ;
282             }
283            
284            
285             #ifdef MAGIC_APPEND
286            
287             /*
288                The following two functions are taken almost directly from
289                examples/gzappend.c. Only cosmetic changes have been made to conform to
290                the coding style of the rest of the code in this file.
291             */
292            
293            
294             /* return the greatest common divisor of a and b using Euclid's algorithm,
295                modified to be fast when one argument much greater than the other, and
296                coded to avoid unnecessary swapping */
297             static unsigned
298             #ifdef CAN_PROTOTYPE
299             gcd(unsigned a, unsigned b)
300             #else
301             gcd(a, b)
302             unsigned a;
303             unsigned b;
304             #endif
305             {
306             unsigned c;
307            
308 0           while (a && b)
309 0           if (a > b) {
310             c = b;
311 0           while (a - c >= c)
312 0           c <<= 1;
313             a -= c;
314             }
315             else {
316             c = a;
317 0           while (b - c >= c)
318 0           c <<= 1;
319             b -= c;
320             }
321 0           return a + b;
322             }
323            
324             /* rotate list[0..len-1] left by rot positions, in place */
325             static void
326             #ifdef CAN_PROTOTYPE
327             rotate(unsigned char *list, unsigned len, unsigned rot)
328             #else
329             rotate(list, len, rot)
330             unsigned char *list;
331             unsigned len ;
332             unsigned rot;
333             #endif
334             {
335             unsigned char tmp;
336             unsigned cycles;
337             unsigned char *start, *last, *to, *from;
338            
339             /* normalize rot and handle degenerate cases */
340             if (len < 2) return;
341 0           if (rot >= len) rot %= len;
342 0           if (rot == 0) return;
343            
344             /* pointer to last entry in list */
345 0           last = list + (len - 1);
346            
347             /* do simple left shift by one */
348 0           if (rot == 1) {
349 0           tmp = *list;
350 0           memcpy(list, list + 1, len - 1);
351 0           *last = tmp;
352             return;
353             }
354            
355             /* do simple right shift by one */
356 0           if (rot == len - 1) {
357 0           tmp = *last;
358 0           memmove(list + 1, list, len - 1);
359 0           *list = tmp;
360             return;
361             }
362            
363             /* otherwise do rotate as a set of cycles in place */
364             cycles = gcd(len, rot); /* number of cycles */
365             do {
366             start = from = list + cycles; /* start index is arbitrary */
367 0           tmp = *from; /* save entry to be overwritten */
368             for (;;) {
369             to = from; /* next step in cycle */
370 0           from += rot; /* go right rot positions */
371 0           if (from > last) from -= len; /* (pointer better not wrap) */
372 0           if (from == start) break; /* all but one shifted */
373 0           *to = *from; /* shift left */
374 0           }
375 0           *to = tmp; /* complete the circle */
376 0           } while (--cycles);
377             }
378            
379             #endif /* MAGIC_APPEND */
380            
381             static void
382             #ifdef CAN_PROTOTYPE
383             DispHex(void * ptr, int length)
384             #else
385             DispHex(ptr, length)
386             void * ptr;
387             int length;
388             #endif
389 0           {
390 0           char * p = (char*)ptr;
391             int i;
392 0           for (i = 0; i < length; ++i) {
393 0           printf(" %02x", 0xFF & *(p+i));
394             }
395             }
396            
397            
398             static void
399             #ifdef CAN_PROTOTYPE
400             DispStream(di_stream * s, char * message)
401             #else
402             DispStream(s, message)
403             di_stream * s;
404             char * message;
405             #endif
406 0           {
407            
408             #if 0
409             if (! trace)
410             return ;
411             #endif
412            
413             #define EnDis(f) (s->flags & f ? "Enabled" : "Disabled")
414            
415 0           printf("DispStream 0x%p", s) ;
416 0           if (message)
417 0           printf("- %s \n", message) ;
418 0           printf("\n") ;
419            
420 0           if (!s) {
421 0           printf(" stream pointer is NULL\n");
422             }
423             else {
424 0           printf(" stream 0x%p\n", &(s->stream));
425 0           printf(" zalloc 0x%p\n", s->stream.zalloc);
426 0           printf(" zfree 0x%p\n", s->stream.zfree);
427 0           printf(" opaque 0x%p\n", s->stream.opaque);
428 0           if (s->stream.msg)
429 0           printf(" msg %s\n", s->stream.msg);
430             else
431 0           printf(" msg \n");
432 0           printf(" next_in 0x%p", s->stream.next_in);
433 0           if (s->stream.next_in){
434 0           printf(" =>");
435 0           DispHex(s->stream.next_in, 4);
436             }
437 0           printf("\n");
438            
439 0           printf(" next_out 0x%p", s->stream.next_out);
440 0           if (s->stream.next_out){
441 0           printf(" =>");
442 0