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