summaryrefslogtreecommitdiff
path: root/gzio.c
diff options
context:
space:
mode:
Diffstat (limited to 'gzio.c')
-rw-r--r--gzio.c370
1 files changed, 210 insertions, 160 deletions
diff --git a/gzio.c b/gzio.c
index cd932d3..13c7289 100644
--- a/gzio.c
+++ b/gzio.c
@@ -1,5 +1,5 @@
1/* gzio.c -- IO on .gz files 1/* gzio.c -- IO on .gz files
2 * Copyright (C) 1995 Jean-loup Gailly. 2 * Copyright (C) 1995-1996 Jean-loup Gailly.
3 * For conditions of distribution and use, see copyright notice in zlib.h 3 * For conditions of distribution and use, see copyright notice in zlib.h
4 */ 4 */
5 5
@@ -16,8 +16,7 @@ struct internal_state {int dummy;}; /* for buggy compilers */
16#define ALLOC(size) malloc(size) 16#define ALLOC(size) malloc(size)
17#define TRYFREE(p) {if (p) free(p);} 17#define TRYFREE(p) {if (p) free(p);}
18 18
19#define GZ_MAGIC_1 0x1f 19static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
20#define GZ_MAGIC_2 0x8b
21 20
22/* gzip flag byte */ 21/* gzip flag byte */
23#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ 22#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
@@ -27,10 +26,6 @@ struct internal_state {int dummy;}; /* for buggy compilers */
27#define COMMENT 0x10 /* bit 4 set: file comment present */ 26#define COMMENT 0x10 /* bit 4 set: file comment present */
28#define RESERVED 0xE0 /* bits 5..7: reserved */ 27#define RESERVED 0xE0 /* bits 5..7: reserved */
29 28
30#ifndef SEEK_CUR
31# define SEEK_CUR 1
32#endif
33
34typedef struct gz_stream { 29typedef struct gz_stream {
35 z_stream stream; 30 z_stream stream;
36 int z_err; /* error code for last stream operation */ 31 int z_err; /* error code for last stream operation */
@@ -46,44 +41,16 @@ typedef struct gz_stream {
46} gz_stream; 41} gz_stream;
47 42
48 43
49local int destroy OF((gz_stream *s)); 44local gzFile gz_open OF((const char *path, const char *mode, int fd));
50local gzFile gz_open OF((char *path, char *mode, int fd)); 45local int get_byte OF((gz_stream *s));
51local void putLong OF((FILE *file, uLong x)); 46local void check_header OF((gz_stream *s));
52local uLong getLong OF((Bytef *buf)); 47local int destroy OF((gz_stream *s));
53 48local void putLong OF((FILE *file, uLong x));
54 /* =========================================================================== 49local uLong getLong OF((gz_stream *s));
55 * Cleanup then free the given gz_stream. Return a zlib error code.
56 */
57local int destroy (s)
58 gz_stream *s;
59{
60 int err = Z_OK;
61
62 if (!s) return Z_STREAM_ERROR;
63
64 TRYFREE(s->inbuf);
65 TRYFREE(s->outbuf);
66 TRYFREE(s->path);
67 TRYFREE(s->msg);
68
69 if (s->stream.state != NULL) {
70 if (s->mode == 'w') {
71 err = deflateEnd(&(s->stream));
72 } else if (s->mode == 'r') {
73 err = inflateEnd(&(s->stream));
74 }
75 }
76 if (s->file != NULL && fclose(s->file)) {
77 err = Z_ERRNO;
78 }
79 if (s->z_err < 0) err = s->z_err;
80 TRYFREE(s);
81 return err;
82}
83 50
84/* =========================================================================== 51/* ===========================================================================
85 Opens a gzip (.gz) file for reading or writing. The mode parameter 52 Opens a gzip (.gz) file for reading or writing. The mode parameter
86 is as in fopen ("rb" or "wb"). The file is given either by file descritor 53 is as in fopen ("rb" or "wb"). The file is given either by file descriptor
87 or path name (if fd == -1). 54 or path name (if fd == -1).
88 gz_open return NULL if the file could not be opened or if there was 55 gz_open return NULL if the file could not be opened or if there was
89 insufficient memory to allocate the (de)compression state; errno 56 insufficient memory to allocate the (de)compression state; errno
@@ -91,19 +58,25 @@ local int destroy (s)
91 zlib error is Z_MEM_ERROR). 58 zlib error is Z_MEM_ERROR).
92*/ 59*/
93local gzFile gz_open (path, mode, fd) 60local gzFile gz_open (path, mode, fd)
94 char *path; 61 const char *path;
95 char *mode; 62 const char *mode;
96 int fd; 63 int fd;
97{ 64{
98 int err; 65 int err;
99 int level = Z_DEFAULT_COMPRESSION; /* compression level */ 66 int level = Z_DEFAULT_COMPRESSION; /* compression level */
100 char *p = mode; 67 char *p = (char*)mode;
101 gz_stream *s = (gz_stream *)ALLOC(sizeof(gz_stream)); 68 gz_stream *s;
69 char fmode[80]; /* copy of mode, without the compression level */
70 char *m = fmode;
71
72 if (!path || !mode) return Z_NULL;
102 73
74 s = (gz_stream *)ALLOC(sizeof(gz_stream));
103 if (!s) return Z_NULL; 75 if (!s) return Z_NULL;
104 76
105 s->stream.zalloc = (alloc_func)0; 77 s->stream.zalloc = (alloc_func)0;
106 s->stream.zfree = (free_func)0; 78 s->stream.zfree = (free_func)0;
79 s->stream.opaque = (voidpf)0;
107 s->stream.next_in = s->inbuf = Z_NULL; 80 s->stream.next_in = s->inbuf = Z_NULL;
108 s->stream.next_out = s->outbuf = Z_NULL; 81 s->stream.next_out = s->outbuf = Z_NULL;
109 s->stream.avail_in = s->stream.avail_out = 0; 82 s->stream.avail_in = s->stream.avail_out = 0;
@@ -123,14 +96,18 @@ local gzFile gz_open (path, mode, fd)
123 s->mode = '\0'; 96 s->mode = '\0';
124 do { 97 do {
125 if (*p == 'r') s->mode = 'r'; 98 if (*p == 'r') s->mode = 'r';
126 if (*p == 'w') s->mode = 'w'; 99 if (*p == 'w' || *p == 'a') s->mode = 'w';
127 if (*p >= '1' && *p <= '9') level = *p - '0'; 100 if (*p >= '0' && *p <= '9') {
128 } while (*p++); 101 level = *p - '0';
102 } else {
103 *m++ = *p; /* copy the mode */
104 }
105 } while (*p++ && m != fmode + sizeof(fmode));
129 if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; 106 if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
130 107
131 if (s->mode == 'w') { 108 if (s->mode == 'w') {
132 err = deflateInit2(&(s->stream), level, 109 err = deflateInit2(&(s->stream), level,
133 DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0); 110 Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0);
134 /* windowBits is passed < 0 to suppress zlib header */ 111 /* windowBits is passed < 0 to suppress zlib header */
135 112
136 s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); 113 s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
@@ -149,7 +126,7 @@ local gzFile gz_open (path, mode, fd)
149 s->stream.avail_out = Z_BUFSIZE; 126 s->stream.avail_out = Z_BUFSIZE;
150 127
151 errno = 0; 128 errno = 0;
152 s->file = fd < 0 ? FOPEN(path, mode) : fdopen(fd, mode); 129 s->file = fd < 0 ? FOPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
153 130
154 if (s->file == NULL) { 131 if (s->file == NULL) {
155 return destroy(s), (gzFile)Z_NULL; 132 return destroy(s), (gzFile)Z_NULL;
@@ -157,50 +134,10 @@ local gzFile gz_open (path, mode, fd)
157 if (s->mode == 'w') { 134 if (s->mode == 'w') {
158 /* Write a very simple .gz header: 135 /* Write a very simple .gz header:
159 */ 136 */
160 fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", GZ_MAGIC_1, GZ_MAGIC_2, 137 fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
161 DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); 138 Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
162 } else { 139 } else {
163 /* Check and skip the header: 140 check_header(s); /* skip the .gz header */
164 */
165 Byte c1 = 0, c2 = 0;
166 Byte method = 0;
167 Byte flags = 0;
168 Byte xflags = 0;
169 Byte time[4];
170 Byte osCode;
171 int c;
172
173 s->stream.avail_in = fread(s->inbuf, 1, 2, s->file);
174 if (s->stream.avail_in != 2 || s->inbuf[0] != GZ_MAGIC_1
175 || s->inbuf[1] != GZ_MAGIC_2) {
176 s->transparent = 1;
177 return (gzFile)s;
178 }
179 s->stream.avail_in = 0;
180 fscanf(s->file,"%c%c%4c%c%c", &method, &flags, time, &xflags, &osCode);
181
182 if (method != DEFLATED || feof(s->file) || (flags & RESERVED) != 0) {
183 s->z_err = Z_DATA_ERROR;
184 return (gzFile)s;
185 }
186 if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
187 long len;
188 fscanf(s->file, "%c%c", &c1, &c2);
189 len = c1 + ((long)c2<<8);
190 fseek(s->file, len, SEEK_CUR);
191 }
192 if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
193 while ((c = getc(s->file)) != 0 && c != EOF) ;
194 }
195 if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
196 while ((c = getc(s->file)) != 0 && c != EOF) ;
197 }
198 if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
199 fscanf(s->file, "%c%c", &c1, &c2);
200 }
201 if (feof(s->file)) {
202 s->z_err = Z_DATA_ERROR;
203 }
204 } 141 }
205 return (gzFile)s; 142 return (gzFile)s;
206} 143}
@@ -209,26 +146,139 @@ local gzFile gz_open (path, mode, fd)
209 Opens a gzip (.gz) file for reading or writing. 146 Opens a gzip (.gz) file for reading or writing.
210*/ 147*/
211gzFile gzopen (path, mode) 148gzFile gzopen (path, mode)
212 char *path; 149 const char *path;
213 char *mode; 150 const char *mode;
214{ 151{
215 return gz_open (path, mode, -1); 152 return gz_open (path, mode, -1);
216} 153}
217 154
218/* =========================================================================== 155/* ===========================================================================
219 Associate a gzFile with the file descriptor fd. 156 Associate a gzFile with the file descriptor fd. fd is not dup'ed here
157 to mimic the behavio(u)r of fdopen.
220*/ 158*/
221gzFile gzdopen (fd, mode) 159gzFile gzdopen (fd, mode)
222 int fd; 160 int fd;
223 char *mode; 161 const char *mode;
224{ 162{
225 char name[20]; 163 char name[20];
164
165 if (fd < 0) return (gzFile)Z_NULL;
226 sprintf(name, "<fd:%d>", fd); /* for debugging */ 166 sprintf(name, "<fd:%d>", fd); /* for debugging */
227 167
228 return gz_open (name, mode, fd); 168 return gz_open (name, mode, fd);
229} 169}
230 170
231/* =========================================================================== 171/* ===========================================================================
172 Read a byte from a gz_stream; update next_in and avail_in. Return EOF
173 for end of file.
174 IN assertion: the stream s has been sucessfully opened for reading.
175*/
176local int get_byte(s)
177 gz_stream *s;
178{
179 if (s->z_eof) return EOF;
180 if (s->stream.avail_in == 0) {
181 errno = 0;
182 s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
183 if (s->stream.avail_in == 0) {
184 s->z_eof = 1;
185 if (ferror(s->file)) s->z_err = Z_ERRNO;
186 return EOF;
187 }
188 s->stream.next_in = s->inbuf;
189 }
190 s->stream.avail_in--;
191 return *(s->stream.next_in)++;
192}
193
194/* ===========================================================================
195 Check the gzip header of a gz_stream opened for reading. Set the stream
196 mode to transparent if the gzip magic header is not present; set s->err
197 to Z_DATA_ERROR if the magic header is present but the rest of the header
198 is incorrect.
199 IN assertion: the stream s has already been created sucessfully;
200 s->stream.avail_in is zero for the first time, but may be non-zero
201 for concatenated .gz files.
202*/
203local void check_header(s)
204 gz_stream *s;
205{
206 int method = 0;
207 int flags = 0;
208 uInt len;
209 int c;
210
211 /* Check the gzip magic header */
212 for (len = 0; len < 2; len++) {
213 c = get_byte(s);
214 if (c != gz_magic[len]) {
215 s->transparent = 1;
216 if (c != EOF) s->stream.avail_in++, s->stream.next_in--;
217 s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
218 return;
219 }
220 }
221 method = get_byte(s);
222 flags = get_byte(s);
223 if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
224 s->z_err = Z_DATA_ERROR;
225 return;
226 }
227
228 /* Discard time, xflags and OS code: */
229 for (len = 0; len < 6; len++) (void)get_byte(s);
230
231 if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
232 len = (uInt)get_byte(s);
233 len += ((uInt)get_byte(s))<<8;
234 /* len is garbage if EOF but the loop below will quit anyway */
235 while (len-- != 0 && get_byte(s) != EOF) ;
236 }
237 if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
238 while ((c = get_byte(s)) != 0 && c != EOF) ;
239 }
240 if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
241 while ((c = get_byte(s)) != 0 && c != EOF) ;
242 }
243 if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
244 for (len = 0; len < 2; len++) (void)get_byte(s);
245 }
246 s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
247}
248
249 /* ===========================================================================
250 * Cleanup then free the given gz_stream. Return a zlib error code.
251 Try freeing in the reverse order of allocations.
252 */
253local int destroy (s)
254 gz_stream *s;
255{
256 int err = Z_OK;
257
258 if (!s) return Z_STREAM_ERROR;
259
260 TRYFREE(s->msg);
261
262 if (s->stream.state != NULL) {
263 if (s->mode == 'w') {
264 err = deflateEnd(&(s->stream));
265 } else if (s->mode == 'r') {
266 err = inflateEnd(&(s->stream));
267 }
268 }
269 if (s->file != NULL && fclose(s->file)) {
270 err = Z_ERRNO;
271 }
272 if (s->z_err < 0) err = s->z_err;
273
274 TRYFREE(s->inbuf);
275 TRYFREE(s->outbuf);
276 TRYFREE(s->path);
277 TRYFREE(s);
278 return err;
279}
280
281/* ===========================================================================
232 Reads the given number of uncompressed bytes from the compressed file. 282 Reads the given number of uncompressed bytes from the compressed file.
233 gzread returns the number of bytes actually read (0 for end of file). 283 gzread returns the number of bytes actually read (0 for end of file).
234*/ 284*/
@@ -238,52 +288,71 @@ int gzread (file, buf, len)
238 unsigned len; 288 unsigned len;
239{ 289{
240 gz_stream *s = (gz_stream*)file; 290 gz_stream *s = (gz_stream*)file;
291 Byte *start = buf; /* starting point for crc computation */
241 292
242 if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; 293 if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
243 294
244 if (s->transparent) { 295 if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
245 int n = 0; 296 if (s->z_err == Z_STREAM_END) return 0; /* EOF */
246 Byte *b = (Byte*)buf;
247 /* Copy the first two (non-magic) bytes if not done already */
248 while (s->stream.avail_in > 0 && len > 0) {
249 *b++ = *s->stream.next_in++;
250 s->stream.avail_in--;
251 len--; n++;
252 }
253 if (len == 0) return n;
254 return n + fread(b, 1, len, s->file);
255 }
256 if (s->z_err == Z_DATA_ERROR) return -1; /* bad .gz file */
257 if (s->z_err == Z_STREAM_END) return 0; /* don't read crc as data */
258 297
259 s->stream.next_out = buf; 298 s->stream.next_out = buf;
260 s->stream.avail_out = len; 299 s->stream.avail_out = len;
261 300
262 while (s->stream.avail_out != 0) { 301 while (s->stream.avail_out != 0) {
263 302
303 if (s->transparent) {
304 /* Copy first the lookahead bytes: */
305 uInt n = s->stream.avail_in;
306 if (n > s->stream.avail_out) n = s->stream.avail_out;
307 if (n > 0) {
308 zmemcpy(s->stream.next_out, s->stream.next_in, n);
309 s->stream.next_out += n;
310 s->stream.next_in += n;
311 s->stream.avail_out -= n;
312 s->stream.avail_in -= n;
313 }
314 if (s->stream.avail_out > 0) {
315 s->stream.avail_out -= fread(s->stream.next_out,
316 1, s->stream.avail_out, s->file);
317 }
318 return (int)(len - s->stream.avail_out);
319 }
264 if (s->stream.avail_in == 0 && !s->z_eof) { 320 if (s->stream.avail_in == 0 && !s->z_eof) {
265 321
266 errno = 0; 322 errno = 0;
267 s->stream.avail_in = 323 s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file);
268 fread(s->inbuf, 1, Z_BUFSIZE, s->file);
269 if (s->stream.avail_in == 0) { 324 if (s->stream.avail_in == 0) {
270 s->z_eof = 1; 325 s->z_eof = 1;
271 } else if (s->stream.avail_in == (uInt)EOF) { 326 if (ferror(s->file)) {
272 s->stream.avail_in = 0; 327 s->z_err = Z_ERRNO;
273 s->z_eof = 1; 328 break;
274 s->z_err = Z_ERRNO; 329 }
275 break;
276 } 330 }
277 s->stream.next_in = s->inbuf; 331 s->stream.next_in = s->inbuf;
278 } 332 }
279 s->z_err = inflate(&(s->stream), Z_NO_FLUSH); 333 s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
280 334
281 if (s->z_err == Z_STREAM_END || 335 if (s->z_err == Z_STREAM_END) {
282 s->z_err != Z_OK || s->z_eof) break; 336 /* Check CRC and original size */
337 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
338 start = s->stream.next_out;
339
340 if (getLong(s) != s->crc || getLong(s) != s->stream.total_out) {
341 s->z_err = Z_DATA_ERROR;
342 } else {
343 /* Check for concatenated .gz files: */
344 check_header(s);
345 if (s->z_err == Z_OK) {
346 inflateReset(&(s->stream));
347 s->crc = crc32(0L, Z_NULL, 0);
348 }
349 }
350 }
351 if (s->z_err != Z_OK || s->z_eof) break;
283 } 352 }
284 len -= s->stream.avail_out; 353 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
285 s->crc = crc32(s->crc, buf, len); 354
286 return (int)len; 355 return (int)(len - s->stream.avail_out);
287} 356}
288 357
289/* =========================================================================== 358/* ===========================================================================
@@ -292,7 +361,7 @@ int gzread (file, buf, len)
292*/ 361*/
293int gzwrite (file, buf, len) 362int gzwrite (file, buf, len)
294 gzFile file; 363 gzFile file;
295 voidp buf; 364 const voidp buf;
296 unsigned len; 365 unsigned len;
297{ 366{
298 gz_stream *s = (gz_stream*)file; 367 gz_stream *s = (gz_stream*)file;
@@ -343,7 +412,7 @@ int gzflush (file, flush)
343 len = Z_BUFSIZE - s->stream.avail_out; 412 len = Z_BUFSIZE - s->stream.avail_out;
344 413
345 if (len != 0) { 414 if (len != 0) {
346 if (fwrite(s->outbuf, 1, len, s->file) != len) { 415 if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
347 s->z_err = Z_ERRNO; 416 s->z_err = Z_ERRNO;
348 return Z_ERRNO; 417 return Z_ERRNO;
349 } 418 }
@@ -379,18 +448,19 @@ local void putLong (file, x)
379} 448}
380 449
381/* =========================================================================== 450/* ===========================================================================
382 Reads a long in LSB order from the given buffer 451 Reads a long in LSB order from the given gz_stream. Sets
383*/ 452*/
384local uLong getLong (buf) 453local uLong getLong (s)
385 Bytef *buf; 454 gz_stream *s;
386{ 455{
387 uLong x = 0; 456 uLong x = (uLong)get_byte(s);
388 Bytef *p = buf+4; 457 int c;
389 458
390 do { 459 x += ((uLong)get_byte(s))<<8;
391 x <<= 8; 460 x += ((uLong)get_byte(s))<<16;
392 x |= *--p; 461 c = get_byte(s);
393 } while (p != buf); 462 if (c == EOF) s->z_err = Z_DATA_ERROR;
463 x += ((uLong)c)<<24;
394 return x; 464 return x;
395} 465}
396 466
@@ -401,7 +471,6 @@ local uLong getLong (buf)
401int gzclose (file) 471int gzclose (file)
402 gzFile file; 472 gzFile file;
403{ 473{
404 uInt n;
405 int err; 474 int err;
406 gz_stream *s = (gz_stream*)file; 475 gz_stream *s = (gz_stream*)file;
407 476
@@ -414,25 +483,6 @@ int gzclose (file)
414 putLong (s->file, s->crc); 483 putLong (s->file, s->crc);
415 putLong (s->file, s->stream.total_in); 484 putLong (s->file, s->stream.total_in);
416 485
417 } else if (s->mode == 'r' && s->z_err == Z_STREAM_END) {
418
419 /* slide CRC and original size if they are at the end of inbuf */
420 if ((n = s->stream.avail_in) < 8 && !s->z_eof) {
421 Byte *p = s->inbuf;
422 Bytef *q = s->stream.next_in;
423 while (n--) { *p++ = *q++; };
424
425 n = s->stream.avail_in;
426 n += fread(p, 1, 8, s->file);
427 s->stream.next_in = s->inbuf;
428 }
429 /* check CRC and original size */
430 if (n < 8 ||
431 getLong(s->stream.next_in) != s->crc ||
432 getLong(s->stream.next_in + 4) != s->stream.total_out) {
433
434 s->z_err = Z_DATA_ERROR;
435 }
436 } 486 }
437 return destroy(file); 487 return destroy(file);
438} 488}
@@ -453,14 +503,14 @@ char* gzerror (file, errnum)
453 503
454 if (s == NULL) { 504 if (s == NULL) {
455 *errnum = Z_STREAM_ERROR; 505 *errnum = Z_STREAM_ERROR;
456 return z_errmsg[1-Z_STREAM_ERROR]; 506 return ERR_MSG(Z_STREAM_ERROR);
457 } 507 }
458 *errnum = s->z_err; 508 *errnum = s->z_err;
459 if (*errnum == Z_OK) return ""; 509 if (*errnum == Z_OK) return (char*)"";
460 510
461 m = *errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg; 511 m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
462 512
463 if (m == NULL || *m == '\0') m = z_errmsg[1-s->z_err]; 513 if (m == NULL || *m == '\0') m = (char*)z_errmsg[1-s->z_err];
464 514
465 TRYFREE(s->msg); 515 TRYFREE(s->msg);
466 s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); 516 s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);