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