]> git.lizzy.rs Git - zlib.git/blob - gzlib.c
Allow gzread() and related to continue after gzclearerr().
[zlib.git] / gzlib.c
1 /* gzlib.c -- zlib functions common to reading and writing gzip files
2  * Copyright (C) 2004, 2010 Mark Adler
3  * For conditions of distribution and use, see copyright notice in zlib.h
4  */
5
6 #include "gzguts.h"
7
8 #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
9 #  define LSEEK lseek64
10 #else
11 #  define LSEEK lseek
12 #endif
13
14 /* Local functions */
15 local void gz_reset OF((gz_statep));
16 local gzFile gz_open OF((const char *, int, const char *));
17
18 #if defined UNDER_CE
19
20 /* Map the Windows error number in ERROR to a locale-dependent error message
21    string and return a pointer to it.  Typically, the values for ERROR come
22    from GetLastError.
23
24    The string pointed to shall not be modified by the application, but may be
25    overwritten by a subsequent call to gz_strwinerror
26
27    The gz_strwinerror function does not change the current setting of
28    GetLastError. */
29 char ZLIB_INTERNAL *gz_strwinerror (error)
30      DWORD error;
31 {
32     static char buf[1024];
33
34     wchar_t *msgbuf;
35     DWORD lasterr = GetLastError();
36     DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
37         | FORMAT_MESSAGE_ALLOCATE_BUFFER,
38         NULL,
39         error,
40         0, /* Default language */
41         (LPVOID)&msgbuf,
42         0,
43         NULL);
44     if (chars != 0) {
45         /* If there is an \r\n appended, zap it.  */
46         if (chars >= 2
47             && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
48             chars -= 2;
49             msgbuf[chars] = 0;
50         }
51
52         if (chars > sizeof (buf) - 1) {
53             chars = sizeof (buf) - 1;
54             msgbuf[chars] = 0;
55         }
56
57         wcstombs(buf, msgbuf, chars + 1);
58         LocalFree(msgbuf);
59     }
60     else {
61         sprintf(buf, "unknown win32 error (%ld)", error);
62     }
63
64     SetLastError(lasterr);
65     return buf;
66 }
67
68 #endif /* UNDER_CE */
69
70 /* Reset gzip file state */
71 local void gz_reset(state)
72     gz_statep state;
73 {
74     if (state->mode == GZ_READ) {   /* for reading ... */
75         state->have = 0;            /* no output data available */
76         state->eof = 0;             /* not at end of file */
77         state->how = LOOK;          /* look for gzip header */
78         state->direct = 1;          /* default for empty file */
79     }
80     state->seek = 0;                /* no seek request pending */
81     gz_error(state, Z_OK, NULL);    /* clear error */
82     state->pos = 0;                 /* no uncompressed data yet */
83     state->strm.avail_in = 0;       /* no input data yet */
84 }
85
86 /* Open a gzip file either by name or file descriptor. */
87 local gzFile gz_open(path, fd, mode)
88     const char *path;
89     int fd;
90     const char *mode;
91 {
92     gz_statep state;
93
94     /* check input */
95     if (path == NULL)
96         return NULL;
97
98     /* allocate gzFile structure to return */
99     state = malloc(sizeof(gz_state));
100     if (state == NULL)
101         return NULL;
102     state->size = 0;            /* no buffers allocated yet */
103     state->want = GZBUFSIZE;    /* requested buffer size */
104     state->msg = NULL;          /* no error message yet */
105
106     /* interpret mode */
107     state->mode = GZ_NONE;
108     state->level = Z_DEFAULT_COMPRESSION;
109     state->strategy = Z_DEFAULT_STRATEGY;
110     while (*mode) {
111         if (*mode >= '0' && *mode <= '9')
112             state->level = *mode - '0';
113         else
114             switch (*mode) {
115             case 'r':
116                 state->mode = GZ_READ;
117                 break;
118 #ifndef NO_GZCOMPRESS
119             case 'w':
120                 state->mode = GZ_WRITE;
121                 break;
122             case 'a':
123                 state->mode = GZ_APPEND;
124                 break;
125 #endif
126             case '+':       /* can't read and write at the same time */
127                 free(state);
128                 return NULL;
129             case 'b':       /* ignore -- will request binary anyway */
130                 break;
131             case 'f':
132                 state->strategy = Z_FILTERED;
133                 break;
134             case 'h':
135                 state->strategy = Z_HUFFMAN_ONLY;
136                 break;
137             case 'R':
138                 state->strategy = Z_RLE;
139                 break;
140             case 'F':
141                 state->strategy = Z_FIXED;
142             default:        /* could consider as an error, but just ignore */
143                 ;
144             }
145         mode++;
146     }
147
148     /* must provide an "r", "w", or "a" */
149     if (state->mode == GZ_NONE) {
150         free(state);
151         return NULL;
152     }
153
154     /* save the path name for error messages */
155     state->path = malloc(strlen(path) + 1);
156     if (state->path == NULL) {
157         free(state);
158         return NULL;
159     }
160     strcpy(state->path, path);
161
162     /* open the file with the appropriate mode (or just use fd) */
163     state->fd = fd != -1 ? fd :
164         open(path,
165 #ifdef O_LARGEFILE
166             O_LARGEFILE |
167 #endif
168 #ifdef O_BINARY
169             O_BINARY |
170 #endif
171             (state->mode == GZ_READ ?
172                 O_RDONLY :
173                 (O_WRONLY | O_CREAT | (
174                     state->mode == GZ_WRITE ?
175                         O_TRUNC :
176                         O_APPEND))),
177             0666);
178     if (state->fd == -1) {
179         free(state->path);
180         free(state);
181         return NULL;
182     }
183     if (state->mode == GZ_APPEND)
184         state->mode = GZ_WRITE;         /* simplify later checks */
185
186     /* save the current position for rewinding (only if reading) */
187     if (state->mode == GZ_READ) {
188         state->start = LSEEK(state->fd, 0, SEEK_CUR);
189         if (state->start == -1) state->start = 0;
190     }
191
192     /* initialize stream */
193     gz_reset(state);
194
195     /* return stream */
196     return (gzFile)state;
197 }
198
199 /* -- see zlib.h -- */
200 gzFile ZEXPORT gzopen(path, mode)
201     const char *path;
202     const char *mode;
203 {
204     return gz_open(path, -1, mode);
205 }
206
207 /* -- see zlib.h -- */
208 gzFile ZEXPORT gzopen64(path, mode)
209     const char *path;
210     const char *mode;
211 {
212     return gz_open(path, -1, mode);
213 }
214
215 /* -- see zlib.h -- */
216 gzFile ZEXPORT gzdopen(fd, mode)
217     int fd;
218     const char *mode;
219 {
220     char *path;         /* identifier for error messages */
221     gzFile gz;
222
223     if (fd == -1 || (path = malloc(7 + 3 * sizeof(int))) == NULL)
224         return NULL;
225     sprintf(path, "<fd:%d>", fd);   /* for debugging */
226     gz = gz_open(path, fd, mode);
227     free(path);
228     return gz;
229 }
230
231 /* -- see zlib.h -- */
232 int ZEXPORT gzbuffer(file, size)
233     gzFile file;
234     unsigned size;
235 {
236     gz_statep state;
237
238     /* get internal structure and check integrity */
239     if (file == NULL)
240         return -1;
241     state = (gz_statep)file;
242     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
243         return -1;
244
245     /* make sure we haven't already allocated memory */
246     if (state->size != 0)
247         return -1;
248
249     /* check and set requested size */
250     if (size < 2)
251         size = 2;               /* need two bytes to check magic header */
252     state->want = size;
253     return 0;
254 }
255
256 /* -- see zlib.h -- */
257 int ZEXPORT gzrewind(file)
258     gzFile file;
259 {
260     gz_statep state;
261
262     /* get internal structure */
263     if (file == NULL)
264         return -1;
265     state = (gz_statep)file;
266
267     /* check that we're reading and that there's no error */
268     if (state->mode != GZ_READ || state->err != Z_OK)
269         return -1;
270
271     /* back up and start over */
272     if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
273         return -1;
274     gz_reset(state);
275     return 0;
276 }
277
278 /* -- see zlib.h -- */
279 z_off64_t ZEXPORT gzseek64(file, offset, whence)
280     gzFile file;
281     z_off64_t offset;
282     int whence;
283 {
284     unsigned n;
285     z_off64_t ret;
286     gz_statep state;
287
288     /* get internal structure and check integrity */
289     if (file == NULL)
290         return -1;
291     state = (gz_statep)file;
292     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
293         return -1;
294
295     /* check that there's no error */
296     if (state->err != Z_OK)
297         return -1;
298
299     /* can only seek from start or relative to current position */
300     if (whence != SEEK_SET && whence != SEEK_CUR)
301         return -1;
302
303     /* normalize offset to a SEEK_CUR specification */
304     if (whence == SEEK_SET)
305         offset -= state->pos;
306     else if (state->seek)
307         offset += state->skip;
308     state->seek = 0;
309
310     /* if within raw area while reading, just go there */
311     if (state->mode == GZ_READ && state->how == COPY &&
312         state->pos + offset >= state->raw) {
313         ret = LSEEK(state->fd, offset - state->have, SEEK_CUR);
314         if (ret == -1)
315             return -1;
316         state->have = 0;
317         state->eof = 0;
318         state->seek = 0;
319         gz_error(state, Z_OK, NULL);
320         state->strm.avail_in = 0;
321         state->pos += offset;
322         return state->pos;
323     }
324
325     /* calculate skip amount, rewinding if needed for back seek when reading */
326     if (offset < 0) {
327         if (state->mode != GZ_READ)         /* writing -- can't go backwards */
328             return -1;
329         offset += state->pos;
330         if (offset < 0)                     /* before start of file! */
331             return -1;
332         if (gzrewind(file) == -1)           /* rewind, then skip to offset */
333             return -1;
334     }
335
336     /* if reading, skip what's in output buffer (one less gzgetc() check) */
337     if (state->mode == GZ_READ) {
338         n = GT_OFF(state->have) || (z_off64_t)state->have > offset ?
339             (unsigned)offset : state->have;
340         state->have -= n;
341         state->next += n;
342         state->pos += n;
343         offset -= n;
344     }
345
346     /* request skip (if not zero) */
347     if (offset) {
348         state->seek = 1;
349         state->skip = offset;
350     }
351     return state->pos + offset;
352 }
353
354 /* -- see zlib.h -- */
355 z_off_t ZEXPORT gzseek(file, offset, whence)
356     gzFile file;
357     z_off_t offset;
358     int whence;
359 {
360     z_off64_t ret;
361
362     ret = gzseek64(file, (z_off64_t)offset, whence);
363     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
364 }
365
366 /* -- see zlib.h -- */
367 z_off64_t ZEXPORT gztell64(file)
368     gzFile file;
369 {
370     gz_statep state;
371
372     /* get internal structure and check integrity */
373     if (file == NULL)
374         return -1;
375     state = (gz_statep)file;
376     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
377         return -1;
378
379     /* return position */
380     return state->pos + (state->seek ? state->skip : 0);
381 }
382
383 /* -- see zlib.h -- */
384 z_off_t ZEXPORT gztell(file)
385     gzFile file;
386 {
387     z_off64_t ret;
388
389     ret = gztell64(file);
390     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
391 }
392
393 /* -- see zlib.h -- */
394 z_off64_t ZEXPORT gzoffset64(file)
395     gzFile file;
396 {
397     z_off64_t offset;
398     gz_statep state;
399
400     /* get internal structure and check integrity */
401     if (file == NULL)
402         return -1;
403     state = (gz_statep)file;
404     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
405         return -1;
406
407     /* compute and return effective offset in file */
408     offset = LSEEK(state->fd, 0, SEEK_CUR);
409     if (offset == -1)
410         return -1;
411     if (state->mode == GZ_READ)             /* reading */
412         offset -= state->strm.avail_in;     /* don't count buffered input */
413     return offset;
414 }
415
416 /* -- see zlib.h -- */
417 z_off_t ZEXPORT gzoffset(file)
418     gzFile file;
419 {
420     z_off64_t ret;
421
422     ret = gzoffset64(file);
423     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
424 }
425
426 /* -- see zlib.h -- */
427 int ZEXPORT gzeof(file)
428     gzFile file;
429 {
430     gz_statep state;
431
432     /* get internal structure and check integrity */
433     if (file == NULL)
434         return 0;
435     state = (gz_statep)file;
436     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
437         return 0;
438
439     /* return end-of-file state */
440     return state->mode == GZ_READ ?
441         (state->eof && state->strm.avail_in == 0 && state->have == 0) : 0;
442 }
443
444 /* -- see zlib.h -- */
445 const char * ZEXPORT gzerror(file, errnum)
446     gzFile file;
447     int *errnum;
448 {
449     gz_statep state;
450
451     /* get internal structure and check integrity */
452     if (file == NULL)
453         return NULL;
454     state = (gz_statep)file;
455     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
456         return NULL;
457
458     /* return error information */
459     if (errnum != NULL)
460         *errnum = state->err;
461     return state->msg == NULL ? "" : state->msg;
462 }
463
464 /* -- see zlib.h -- */
465 void ZEXPORT gzclearerr(file)
466     gzFile file;
467 {
468     gz_statep state;
469
470     /* get internal structure and check integrity */
471     if (file == NULL)
472         return;
473     state = (gz_statep)file;
474     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
475         return;
476
477     /* clear error and end-of-file */
478     if (state->mode == GZ_READ)
479         state->eof = 0;
480     gz_error(state, Z_OK, NULL);
481 }
482
483 /* Create an error message in allocated memory and set state->err and
484    state->msg accordingly.  Free any previous error message already there.  Do
485    not try to free or allocate space if the error is Z_MEM_ERROR (out of
486    memory).  Simply save the error message as a static string.  If there is an
487    allocation failure constructing the error message, then convert the error to
488    out of memory. */
489 void ZLIB_INTERNAL gz_error(state, err, msg)
490     gz_statep state;
491     int err;
492     const char *msg;
493 {
494     /* free previously allocated message and clear */
495     if (state->msg != NULL) {
496         if (state->err != Z_MEM_ERROR)
497             free(state->msg);
498         state->msg = NULL;
499     }
500
501     /* set error code, and if no message, then done */
502     state->err = err;
503     if (msg == NULL)
504         return;
505
506     /* for an out of memory error, save as static string */
507     if (err == Z_MEM_ERROR) {
508         state->msg = (char *)msg;
509         return;
510     }
511
512     /* construct error message with path */
513     if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) {
514         state->err = Z_MEM_ERROR;
515         state->msg = (char *)"out of memory";
516         return;
517     }
518     strcpy(state->msg, state->path);
519     strcat(state->msg, ": ");
520     strcat(state->msg, msg);
521     return;
522 }
523
524 #ifndef INT_MAX
525 /* portably return maximum value for an int (when limits.h presumed not
526    available) -- we need to do this to cover cases where 2's complement not
527    used, since C standard permits 1's complement and sign-bit representations,
528    otherwise we could just use ((unsigned)-1) >> 1 */
529 unsigned ZLIB_INTERNAL gz_intmax()
530 {
531     unsigned p, q;
532
533     p = 1;
534     do {
535         q = p;
536         p <<= 1;
537         p++;
538     } while (p > q);
539     return q >> 1;
540 }
541 #endif