]> git.lizzy.rs Git - zlib.git/blob - gzlib.c
Simplify gzseek() now that raw after gzip is ignored.
[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 ||
269             (state->err != Z_OK && state->err != Z_BUF_ERROR))
270         return -1;
271
272     /* back up and start over */
273     if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
274         return -1;
275     gz_reset(state);
276     return 0;
277 }
278
279 /* -- see zlib.h -- */
280 z_off64_t ZEXPORT gzseek64(file, offset, whence)
281     gzFile file;
282     z_off64_t offset;
283     int whence;
284 {
285     unsigned n;
286     z_off64_t ret;
287     gz_statep state;
288
289     /* get internal structure and check integrity */
290     if (file == NULL)
291         return -1;
292     state = (gz_statep)file;
293     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
294         return -1;
295
296     /* check that there's no error */
297     if (state->err != Z_OK && state->err != Z_BUF_ERROR)
298         return -1;
299
300     /* can only seek from start or relative to current position */
301     if (whence != SEEK_SET && whence != SEEK_CUR)
302         return -1;
303
304     /* normalize offset to a SEEK_CUR specification */
305     if (whence == SEEK_SET)
306         offset -= state->pos;
307     else if (state->seek)
308         offset += state->skip;
309     state->seek = 0;
310
311     /* if within raw area while reading, just go there */
312     if (state->mode == GZ_READ && state->how == COPY &&
313             state->pos + offset >= 0) {
314         ret = LSEEK(state->fd, offset - state->have, SEEK_CUR);
315         if (ret == -1)
316             return -1;
317         state->have = 0;
318         state->eof = 0;
319         state->seek = 0;
320         gz_error(state, Z_OK, NULL);
321         state->strm.avail_in = 0;
322         state->pos += offset;
323         return state->pos;
324     }
325
326     /* calculate skip amount, rewinding if needed for back seek when reading */
327     if (offset < 0) {
328         if (state->mode != GZ_READ)         /* writing -- can't go backwards */
329             return -1;
330         offset += state->pos;
331         if (offset < 0)                     /* before start of file! */
332             return -1;
333         if (gzrewind(file) == -1)           /* rewind, then skip to offset */
334             return -1;
335     }
336
337     /* if reading, skip what's in output buffer (one less gzgetc() check) */
338     if (state->mode == GZ_READ) {
339         n = GT_OFF(state->have) || (z_off64_t)state->have > offset ?
340             (unsigned)offset : state->have;
341         state->have -= n;
342         state->next += n;
343         state->pos += n;
344         offset -= n;
345     }
346
347     /* request skip (if not zero) */
348     if (offset) {
349         state->seek = 1;
350         state->skip = offset;
351     }
352     return state->pos + offset;
353 }
354
355 /* -- see zlib.h -- */
356 z_off_t ZEXPORT gzseek(file, offset, whence)
357     gzFile file;
358     z_off_t offset;
359     int whence;
360 {
361     z_off64_t ret;
362
363     ret = gzseek64(file, (z_off64_t)offset, whence);
364     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
365 }
366
367 /* -- see zlib.h -- */
368 z_off64_t ZEXPORT gztell64(file)
369     gzFile file;
370 {
371     gz_statep state;
372
373     /* get internal structure and check integrity */
374     if (file == NULL)
375         return -1;
376     state = (gz_statep)file;
377     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
378         return -1;
379
380     /* return position */
381     return state->pos + (state->seek ? state->skip : 0);
382 }
383
384 /* -- see zlib.h -- */
385 z_off_t ZEXPORT gztell(file)
386     gzFile file;
387 {
388     z_off64_t ret;
389
390     ret = gztell64(file);
391     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
392 }
393
394 /* -- see zlib.h -- */
395 z_off64_t ZEXPORT gzoffset64(file)
396     gzFile file;
397 {
398     z_off64_t offset;
399     gz_statep state;
400
401     /* get internal structure and check integrity */
402     if (file == NULL)
403         return -1;
404     state = (gz_statep)file;
405     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
406         return -1;
407
408     /* compute and return effective offset in file */
409     offset = LSEEK(state->fd, 0, SEEK_CUR);
410     if (offset == -1)
411         return -1;
412     if (state->mode == GZ_READ)             /* reading */
413         offset -= state->strm.avail_in;     /* don't count buffered input */
414     return offset;
415 }
416
417 /* -- see zlib.h -- */
418 z_off_t ZEXPORT gzoffset(file)
419     gzFile file;
420 {
421     z_off64_t ret;
422
423     ret = gzoffset64(file);
424     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
425 }
426
427 /* -- see zlib.h -- */
428 int ZEXPORT gzeof(file)
429     gzFile file;
430 {
431     gz_statep state;
432
433     /* get internal structure and check integrity */
434     if (file == NULL)
435         return 0;
436     state = (gz_statep)file;
437     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
438         return 0;
439
440     /* return end-of-file state */
441     return state->mode == GZ_READ ?
442         (state->eof && state->strm.avail_in == 0 && state->have == 0) : 0;
443 }
444
445 /* -- see zlib.h -- */
446 const char * ZEXPORT gzerror(file, errnum)
447     gzFile file;
448     int *errnum;
449 {
450     gz_statep state;
451
452     /* get internal structure and check integrity */
453     if (file == NULL)
454         return NULL;
455     state = (gz_statep)file;
456     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
457         return NULL;
458
459     /* return error information */
460     if (errnum != NULL)
461         *errnum = state->err;
462     return state->msg == NULL ? "" : state->msg;
463 }
464
465 /* -- see zlib.h -- */
466 void ZEXPORT gzclearerr(file)
467     gzFile file;
468 {
469     gz_statep state;
470
471     /* get internal structure and check integrity */
472     if (file == NULL)
473         return;
474     state = (gz_statep)file;
475     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
476         return;
477
478     /* clear error and end-of-file */
479     if (state->mode == GZ_READ)
480         state->eof = 0;
481     gz_error(state, Z_OK, NULL);
482 }
483
484 /* Create an error message in allocated memory and set state->err and
485    state->msg accordingly.  Free any previous error message already there.  Do
486    not try to free or allocate space if the error is Z_MEM_ERROR (out of
487    memory).  Simply save the error message as a static string.  If there is an
488    allocation failure constructing the error message, then convert the error to
489    out of memory. */
490 void ZLIB_INTERNAL gz_error(state, err, msg)
491     gz_statep state;
492     int err;
493     const char *msg;
494 {
495     /* free previously allocated message and clear */
496     if (state->msg != NULL) {
497         if (state->err != Z_MEM_ERROR)
498             free(state->msg);
499         state->msg = NULL;
500     }
501
502     /* set error code, and if no message, then done */
503     state->err = err;
504     if (msg == NULL)
505         return;
506
507     /* for an out of memory error, save as static string */
508     if (err == Z_MEM_ERROR) {
509         state->msg = (char *)msg;
510         return;
511     }
512
513     /* construct error message with path */
514     if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) {
515         state->err = Z_MEM_ERROR;
516         state->msg = (char *)"out of memory";
517         return;
518     }
519     strcpy(state->msg, state->path);
520     strcat(state->msg, ": ");
521     strcat(state->msg, msg);
522     return;
523 }
524
525 #ifndef INT_MAX
526 /* portably return maximum value for an int (when limits.h presumed not
527    available) -- we need to do this to cover cases where 2's complement not
528    used, since C standard permits 1's complement and sign-bit representations,
529    otherwise we could just use ((unsigned)-1) >> 1 */
530 unsigned ZLIB_INTERNAL gz_intmax()
531 {
532     unsigned p, q;
533
534     p = 1;
535     do {
536         q = p;
537         p <<= 1;
538         p++;
539     } while (p > q);
540     return q >> 1;
541 }
542 #endif