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