Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1896 serge 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 */
15
local void gz_reset OF((gz_statep));
16
local 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. */
29
char 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 */
71
local 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. */
87
local 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 -- */
196
gzFile 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 -- */
204
gzFile 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 -- */
212
gzFile 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);   /* for debugging */
222
    gz = gz_open(path, fd, mode);
223
    free(path);
224
    return gz;
225
}
226
 
227
/* -- see zlib.h -- */
228
int 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 -- */
253
int 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 -- */
275
z_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 -- */
351
z_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 -- */
363
z_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 -- */
380
z_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 -- */
390
z_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 -- */
413
z_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 -- */
423
int 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 -- */
441
const 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 -- */
461
void 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. */
485
void 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 */
525
unsigned 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