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