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