]> git.lizzy.rs Git - zlib.git/blob - gzlib.c
zlib 1.2.3.9
[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 #ifdef _LARGEFILE64_SOURCE
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 && defined NO_ERRNO_H
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 ZEXPORT *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 && NO_ERRNO_H */
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     /* allocate gzFile structure to return */
95     state = malloc(sizeof(gz_state));
96     if (state == NULL)
97         return NULL;
98     state->size = 0;            /* no buffers allocated yet */
99     state->want = GZBUFSIZE;    /* requested buffer size */
100     state->msg = NULL;          /* no error message yet */
101
102     /* interpret mode */
103     state->mode = GZ_NONE;
104     state->level = Z_DEFAULT_COMPRESSION;
105     state->strategy = Z_DEFAULT_STRATEGY;
106     while (*mode) {
107         if (*mode >= '0' && *mode <= '9')
108             state->level = *mode - '0';
109         else
110             switch (*mode) {
111             case 'r':
112                 state->mode = GZ_READ;
113                 break;
114 #ifndef NO_GZCOMPRESS
115             case 'w':
116                 state->mode = GZ_WRITE;
117                 break;
118             case 'a':
119                 state->mode = GZ_APPEND;
120                 break;
121 #endif
122             case '+':       /* can't read and write at the same time */
123                 free(state);
124                 return NULL;
125             case 'b':       /* ignore -- will request binary anyway */
126                 break;
127             case 'f':
128                 state->strategy = Z_FILTERED;
129                 break;
130             case 'h':
131                 state->strategy = Z_HUFFMAN_ONLY;
132                 break;
133             case 'R':
134                 state->strategy = Z_RLE;
135                 break;
136             case 'F':
137                 state->strategy = Z_FIXED;
138             default:        /* could consider as an error, but just ignore */
139                 ;
140             }
141         mode++;
142     }
143
144     /* must provide an "r", "w", or "a" */
145     if (state->mode == GZ_NONE) {
146         free(state);
147         return NULL;
148     }
149
150     /* open the file with the appropriate mode (or just use fd) */
151     state->fd = fd != -1 ? fd :
152         open(path,
153 #ifdef O_LARGEFILE
154             O_LARGEFILE |
155 #endif
156 #ifdef O_BINARY
157             O_BINARY |
158 #endif
159             (state->mode == GZ_READ ?
160                 O_RDONLY :
161                 (O_WRONLY | O_CREAT | (
162                     state->mode == GZ_WRITE ?
163                         O_TRUNC :
164                         O_APPEND))),
165             0666);
166     if (state->fd == -1) {
167         free(state);
168         return NULL;
169     }
170     if (state->mode == GZ_APPEND)
171         state->mode = GZ_WRITE;         /* simplify later checks */
172
173     /* save the path name for error messages */
174     state->path = malloc(strlen(path) + 1);
175     if (state->path == NULL) {
176         free(state);
177         return NULL;
178     }
179     strcpy(state->path, path);
180
181     /* save the current position for rewinding (only if reading) */
182     if (state->mode == GZ_READ) {
183         state->start = LSEEK(state->fd, 0, SEEK_CUR);
184         if (state->start == -1) state->start = 0;
185     }
186
187     /* initialize stream */
188     gz_reset(state);
189
190     /* return stream */
191     return (gzFile)state;
192 }
193
194 /* -- see zlib.h -- */
195 gzFile ZEXPORT gzopen(path, mode)
196     const char *path;
197     const char *mode;
198 {
199     return gz_open(path, -1, mode);
200 }
201
202 /* -- see zlib.h -- */
203 gzFile ZEXPORT gzopen64(path, mode)
204     const char *path;
205     const char *mode;
206 {
207     return gz_open(path, -1, mode);
208 }
209
210 /* -- see zlib.h -- */
211 gzFile ZEXPORT gzdopen(fd, mode)
212     int fd;
213     const char *mode;
214 {
215     char *path;         /* identifier for error messages */
216     gzFile gz;
217
218     if (fd == -1 || (path = malloc(7 + 3 * sizeof(int))) == NULL)
219         return NULL;
220     sprintf(path, "<fd:%d>", fd);
221     gz = gz_open(path, fd, mode);
222     free(path);
223     return gz;
224 }
225
226 /* -- see zlib.h -- */
227 int ZEXPORT gzbuffer(file, size)
228     gzFile file;
229     unsigned size;
230 {
231     gz_statep state;
232
233     /* get internal structure and check integrity */
234     if (file == NULL)
235         return -1;
236     state = (gz_statep)file;
237     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
238         return -1;
239
240     /* make sure we haven't already allocated memory */
241     if (state->size != 0)
242         return -1;
243
244     /* check and set requested size */
245     if (size == 0)
246         return -1;
247     state->want = size;
248     return 0;
249 }
250
251 /* -- see zlib.h -- */
252 int ZEXPORT gzrewind(file)
253     gzFile file;
254 {
255     gz_statep state;
256
257     /* get internal structure */
258     if (file == NULL)
259         return -1;
260     state = (gz_statep)file;
261
262     /* check that we're reading and that there's no error */
263     if (state->mode != GZ_READ || state->err != Z_OK)
264         return -1;
265
266     /* back up and start over */
267     if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
268         return -1;
269     gz_reset(state);
270     return 0;
271 }
272
273 /* -- see zlib.h -- */
274 z_off64_t ZEXPORT gzseek64(file, offset, whence)
275     gzFile file;
276     z_off64_t offset;
277     int whence;
278 {
279     unsigned n;
280     z_off64_t ret;
281     gz_statep state;
282
283     /* get internal structure and check integrity */
284     if (file == NULL)
285         return -1;
286     state = (gz_statep)file;
287     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
288         return -1;
289
290     /* check that there's no error */
291     if (state->err != Z_OK)
292         return -1;
293
294     /* can only seek from start or relative to current position */
295     if (whence != SEEK_SET && whence != SEEK_CUR)
296         return -1;
297
298     /* normalize offset to a SEEK_CUR specification */
299     if (whence == SEEK_SET)
300         offset -= state->pos;
301     else if (state->seek)
302         offset += state->skip;
303     state->seek = 0;
304
305     /* if within raw area while reading, just go there */
306     if (state->mode == GZ_READ && state->how == COPY &&
307         state->pos + offset >= state->raw) {
308         ret = LSEEK(state->fd, offset, SEEK_CUR);
309         if (ret == -1)
310             return -1;
311         state->have = 0;
312         state->eof = 0;
313         state->seek = 0;
314         gz_error(state, Z_OK, NULL);
315         state->strm.avail_in = 0;
316         state->pos += offset;
317         return state->pos;
318     }
319
320     /* calculate skip amount, rewinding if needed for back seek when reading */
321     if (offset < 0) {
322         if (state->mode != GZ_READ)         /* writing -- can't go backwards */
323             return -1;
324         offset += state->pos;
325         if (offset < 0)                     /* before start of file! */
326             return -1;
327         if (gzrewind(file) == -1)           /* rewind, then skip to offset */
328             return -1;
329     }
330
331     /* if reading, skip what's in output buffer (one less gzgetc() check) */
332     if (state->mode == GZ_READ) {
333         n = GT_OFF(state->have) || (z_off64_t)state->have > offset ?
334             (unsigned)offset : state->have;
335         state->have -= n;
336         state->next += n;
337         state->pos += n;
338         offset -= n;
339     }
340
341     /* request skip (if not zero) */
342     if (offset) {
343         state->seek = 1;
344         state->skip = offset;
345     }
346     return state->pos + offset;
347 }
348
349 /* -- see zlib.h -- */
350 z_off_t ZEXPORT gzseek(file, offset, whence)
351     gzFile file;
352     z_off_t offset;
353     int whence;
354 {
355     z_off64_t ret;
356
357     ret = gzseek64(file, (z_off64_t)offset, whence);
358     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
359 }
360
361 /* -- see zlib.h -- */
362 z_off64_t ZEXPORT gztell64(file)
363     gzFile file;
364 {
365     gz_statep state;
366
367     /* get internal structure and check integrity */
368     if (file == NULL)
369         return -1;
370     state = (gz_statep)file;
371     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
372         return -1;
373
374     /* return position */
375     return state->pos + (state->seek ? state->skip : 0);
376 }
377
378 /* -- see zlib.h -- */
379 z_off_t ZEXPORT gztell(file)
380     gzFile file;
381 {
382     z_off64_t ret;
383
384     ret = gztell64(file);
385     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
386 }
387
388 /* -- see zlib.h -- */
389 z_off64_t ZEXPORT gzoffset64(file)
390     gzFile file;
391 {
392     z_off64_t offset;
393     gz_statep state;
394
395     /* get internal structure and check integrity */
396     if (file == NULL)
397         return -1;
398     state = (gz_statep)file;
399     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
400         return -1;
401
402     /* compute and return effective offset in file */
403     offset = LSEEK(state->fd, 0, SEEK_CUR);
404     if (offset == -1)
405         return -1;
406     if (state->mode == GZ_READ)             /* reading */
407         offset -= state->strm.avail_in;     /* don't count buffered input */
408     return offset;
409 }
410
411 /* -- see zlib.h -- */
412 z_off_t ZEXPORT gzoffset(file)
413     gzFile file;
414 {
415     z_off64_t ret;
416
417     ret = gzoffset64(file);
418     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
419 }
420
421 /* -- see zlib.h -- */
422 int ZEXPORT gzeof(file)
423     gzFile file;
424 {
425     gz_statep state;
426
427     /* get internal structure and check integrity */
428     if (file == NULL)
429         return 0;
430     state = (gz_statep)file;
431     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
432         return 0;
433
434     /* return end-of-file state */
435     return state->mode == GZ_READ ? (state->eof && state->have == 0) : 0;
436 }
437
438 /* -- see zlib.h -- */
439 const char * ZEXPORT gzerror(file, errnum)
440     gzFile file;
441     int *errnum;
442 {
443     gz_statep state;
444
445     /* get internal structure and check integrity */
446     if (file == NULL)
447         return NULL;
448     state = (gz_statep)file;
449     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
450         return NULL;
451
452     /* return error information */
453     *errnum = state->err;
454     return state->msg == NULL ? "" : state->msg;
455 }
456
457 /* -- see zlib.h -- */
458 void ZEXPORT gzclearerr(file)
459     gzFile file;
460 {
461     gz_statep state;
462
463     /* get internal structure and check integrity */
464     if (file == NULL)
465         return;
466     state = (gz_statep)file;
467     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
468         return;
469
470     /* clear error and end-of-file */
471     if (state->mode == GZ_READ)
472         state->eof = 0;
473     gz_error(state, Z_OK, NULL);
474 }
475
476 /* Create an error message in allocated memory and set state->err and
477    state->msg accordingly.  Free any previous error message already there.  Do
478    not try to free or allocate space if the error is Z_MEM_ERROR (out of
479    memory).  Simply save the error message as a static string.  If there is an
480    allocation failure constructing the error message, then convert the error to
481    out of memory. */
482 void ZEXPORT gz_error(state, err, msg)
483     gz_statep state;
484     int err;
485     const char *msg;
486 {
487     /* free previously allocated message and clear */
488     if (state->msg != NULL) {
489         if (state->err != Z_MEM_ERROR)
490             free(state->msg);
491         state->msg = NULL;
492     }
493
494     /* set error code, and if no message, then done */
495     state->err = err;
496     if (msg == NULL)
497         return;
498
499     /* for an out of memory error, save as static string */
500     if (err == Z_MEM_ERROR) {
501         state->msg = (char *)msg;
502         return;
503     }
504
505     /* construct error message with path */
506     if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) {
507         state->err = Z_MEM_ERROR;
508         state->msg = (char *)"out of memory";
509         return;
510     }
511     strcpy(state->msg, state->path);
512     strcat(state->msg, ": ");
513     strcat(state->msg, msg);
514     return;
515 }
516
517 #ifndef INT_MAX
518 /* portably return maximum value for an int (when limits.h presumed not
519    available) -- we need to do this to cover cases where 2's complement not
520    used, since C standard permits 1's complement and sign-bit representations,
521    otherwise we could just use ((unsigned)-1) >> 1 */
522 unsigned ZEXPORT gz_intmax()
523 {
524     unsigned p, q;
525
526     p = 1;
527     do {
528         q = p;
529         p <<= 1;
530         p++;
531     } while (p > q);
532     return q >> 1;
533 }
534 #endif