source: rtems/cpukit/zlib/gzlib.c @ 6ac6a5c8

5
Last change on this file since 6ac6a5c8 was 791d3cdc, checked in by Ralf Corsepius <ralf.corsepius@…>, on 03/19/11 at 07:42:49

Update to zlib-1.2.5.

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