~ubuntu-branches/ubuntu/wily/opencollada/wily-proposed

« back to all changes in this revision

Viewing changes to Externals/zziplib/src/file.c

  • Committer: Package Import Robot
  • Author(s): Matteo F. Vescovi
  • Date: 2015-05-14 17:23:27 UTC
  • Revision ID: package-import@ubuntu.com-20150514172327-f862u8envms01fra
Tags: upstream-0.1.0~20140703.ddf8f47+dfsg1
ImportĀ upstreamĀ versionĀ 0.1.0~20140703.ddf8f47+dfsg1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*
 
3
 * Author: 
 
4
 *      Guido Draheim <guidod@gmx.de>
 
5
 *      Tomi Ollila <Tomi.Ollila@iki.fi>
 
6
 *
 
7
 * Copyright (c) 1999,2000,2001,2002,2003 Guido Draheim
 
8
 *          All rights reserved,
 
9
 *          use under the restrictions of the
 
10
 *          Lesser GNU General Public License
 
11
 *          or alternatively the restrictions 
 
12
 *          of the Mozilla Public License 1.1
 
13
 */
 
14
 
 
15
#include <zzip/lib.h>           /* exported... */
 
16
#include <zzip/file.h>
 
17
 
 
18
#include <string.h>
 
19
#include <sys/stat.h>
 
20
#include <errno.h>
 
21
#include <stdlib.h>
 
22
#include <ctype.h>
 
23
 
 
24
#include <zzip/format.h>
 
25
#include <zzip/fetch.h>
 
26
#include <zzip/__debug.h>
 
27
 
 
28
#if 0
 
29
# if defined ZZIP_HAVE_IO_H
 
30
# include <io.h>                /* tell */
 
31
# else
 
32
# define tell(fd) lseek(fd,0,SEEK_CUR)
 
33
# endif
 
34
#else
 
35
#define tells(fd) seeks(fd,0,SEEK_CUR)
 
36
#endif
 
37
 
 
38
/**
 
39
 * the direct function of => zzip_close(fp). it will cleanup the
 
40
 * inflate-portion of => zlib and free the structure given.
 
41
 * 
 
42
 * it is called quite from the error-cleanup parts
 
43
 * of the various => _open functions. 
 
44
 * 
 
45
 * the .refcount is decreased and if zero the fp->dir is closed just as well.
 
46
 */
 
47
int
 
48
zzip_file_close(ZZIP_FILE * fp)
 
49
{
 
50
    auto int self;
 
51
    ZZIP_DIR *dir = fp->dir;
 
52
 
 
53
    if (fp->method)
 
54
        inflateEnd(&fp->d_stream);      /* inflateEnd() can be called many times */
 
55
 
 
56
    if (dir->cache.locked == NULL)
 
57
        dir->cache.locked = &self;
 
58
 
 
59
    if (fp->buf32k)
 
60
    {
 
61
        if (dir->cache.locked == &self && dir->cache.buf32k == NULL)
 
62
            dir->cache.buf32k = fp->buf32k;
 
63
        else
 
64
            free(fp->buf32k);
 
65
    }
 
66
 
 
67
    if (dir->currentfp == fp)
 
68
        dir->currentfp = NULL;
 
69
 
 
70
    dir->refcount--;
 
71
    /* ease to notice possible dangling reference errors */
 
72
    memset(fp, 0, sizeof(*fp));
 
73
 
 
74
    if (dir->cache.locked == &self && dir->cache.fp == NULL)
 
75
        dir->cache.fp = fp;
 
76
    else
 
77
        free(fp);
 
78
 
 
79
    if (dir->cache.locked == &self)
 
80
        dir->cache.locked = NULL;
 
81
 
 
82
    if (! dir->refcount)
 
83
        return zzip_dir_close(dir);
 
84
    else
 
85
        return 0;
 
86
}
 
87
 
 
88
 
 
89
static int
 
90
zzip_file_saveoffset(ZZIP_FILE * fp)
 
91
{
 
92
    if (fp)
 
93
    {
 
94
        int fd = fp->dir->fd;
 
95
        zzip_off_t off = fp->io->fd.seeks(fd, 0, SEEK_CUR);
 
96
 
 
97
        if (off < 0)
 
98
            return -1;
 
99
 
 
100
        fp->offset = off;
 
101
    }
 
102
    return 0;
 
103
}
 
104
 
 
105
# ifndef ZZIP_CHECK_BACKSLASH_DIRSEPARATOR      /* NOTE: also default */
 
106
# define ZZIP_CHECK_BACKSLASH_DIRSEPARATOR 0    /* to "NO" on win32 ! */
 
107
# endif
 
108
 
 
109
# if ! defined strcasecmp && ! defined ZZIP_HAVE_STRCASECMP
 
110
# define ZZIP_CHECK_BACKSLASH_DIRSEPARATOR 1
 
111
# endif
 
112
 
 
113
#if ! ZZIP_CHECK_BACKSLASH_DIRSEPARATOR+0
 
114
#define dirsep_strrchr(N,C) strrchr(N,C)
 
115
#define dirsep_casecmp strcasecmp
 
116
#else
 
117
#define dirsep_strrchr(N,C) _dirsep_strrchr(N)
 
118
#define dirsep_casecmp _dirsep_casecmp
 
119
static zzip_char_t *
 
120
_dirsep_strrchr(zzip_char_t * name)
 
121
{
 
122
    char *n = strrchr(name, '/');
 
123
    char *m = strrchr(name, '\\');
 
124
 
 
125
    if (m && n && m > n)
 
126
        n = m;
 
127
    return n;
 
128
}
 
129
static int
 
130
_dirsep_casecmp(zzip_char_t * s1, zzip_char_t * s2)
 
131
{
 
132
    /* ASCII tolower - including mapping of backslash in normal slash */
 
133
    static const char mapping[] = "@abcdefghijklmnopqrstuvwxyz[/]^_";
 
134
    int c1, c2;
 
135
 
 
136
    while (*s1 && *s2)
 
137
    {
 
138
        c1 = (int) (unsigned char) *s1;
 
139
        c2 = (int) (unsigned char) *s2;
 
140
        if ((c1 & 0xE0) == 0x40)
 
141
            c1 = mapping[c1 & 0x1f];
 
142
        if ((c2 & 0xE0) == 0x40)
 
143
            c2 = mapping[c2 & 0x1f];
 
144
        if (c1 != c2)
 
145
            return (c1 - c2);
 
146
        s1++;
 
147
        s2++;
 
148
    }
 
149
 
 
150
    return (((int) (unsigned char) *s1) - ((int) (unsigned char) *s2));
 
151
}
 
152
#endif
 
153
 
 
154
static int zzip_inflate_init(ZZIP_FILE *, struct zzip_dir_hdr *);
 
155
 
 
156
/**
 
157
 * open an => ZZIP_FILE from an already open => ZZIP_DIR handle. Since
 
158
 * we have a chance to reuse a cached => buf32k and => ZZIP_FILE memchunk
 
159
 * this is the best choice to unpack multiple files.
 
160
 * 
 
161
 * Note: the zlib supports 2..15 bit windowsize, hence we provide a 32k
 
162
 *       memchunk here... just to be safe.
 
163
 *
 
164
 * On error it returns null and sets errcode in the ZZIP_DIR.
 
165
 */
 
166
ZZIP_FILE *
 
167
zzip_file_open(ZZIP_DIR * dir, zzip_char_t * name, int o_mode)
 
168
{
 
169
    auto int self;
 
170
    zzip_error_t err = 0;
 
171
    struct zzip_file *fp = 0;
 
172
    struct zzip_dir_hdr *hdr = dir->hdr0;
 
173
    int (*cmp) (zzip_char_t *, zzip_char_t *);
 
174
 
 
175
    cmp = (o_mode & ZZIP_CASELESS) ? dirsep_casecmp : strcmp;
 
176
 
 
177
    if (! dir)
 
178
        return NULL;
 
179
    if (! dir->fd || dir->fd == -1)
 
180
        { dir->errcode = EBADF; return NULL; }
 
181
    if (! hdr)
 
182
        { dir->errcode = ENOENT; return NULL; }
 
183
 
 
184
    if (o_mode & ZZIP_NOPATHS)
 
185
    {
 
186
        register zzip_char_t *n = dirsep_strrchr(name, '/');
 
187
 
 
188
        if (n)
 
189
            name = n + 1;
 
190
    }
 
191
 
 
192
    while (1)
 
193
    {
 
194
        register zzip_char_t *hdr_name = hdr->d_name;
 
195
 
 
196
        if (o_mode & ZZIP_NOPATHS)
 
197
        {
 
198
            register zzip_char_t *n = dirsep_strrchr(hdr_name, '/');
 
199
 
 
200
            if (n)
 
201
                hdr_name = n + 1;
 
202
        }
 
203
 
 
204
        HINT4("name='%s', compr=%d, size=%d\n",
 
205
              hdr->d_name, hdr->d_compr, hdr->d_usize);
 
206
 
 
207
        if (! cmp(hdr_name, name))
 
208
        {
 
209
            switch (hdr->d_compr)
 
210
            {
 
211
            case 0:            /* store */
 
212
            case 8:            /* inflate */
 
213
                break;
 
214
            default:
 
215
                { err = ZZIP_UNSUPP_COMPR; goto error; }
 
216
            }
 
217
 
 
218
            if (dir->cache.locked == NULL)
 
219
                dir->cache.locked = &self;
 
220
 
 
221
            if (dir->cache.locked == &self && dir->cache.fp)
 
222
            {
 
223
                fp = dir->cache.fp;
 
224
                dir->cache.fp = NULL;
 
225
                /* memset(zfp, 0, sizeof *fp); cleared in zzip_file_close() */
 
226
            } else
 
227
            {
 
228
                if (! (fp = (ZZIP_FILE *) calloc(1, sizeof(*fp))))
 
229
                    { err =  ZZIP_OUTOFMEM; goto error; }
 
230
            }
 
231
 
 
232
            fp->dir = dir;
 
233
            fp->io = dir->io;
 
234
            dir->refcount++;
 
235
 
 
236
            if (dir->cache.locked == &self && dir->cache.buf32k)
 
237
            {
 
238
                fp->buf32k = dir->cache.buf32k;
 
239
                dir->cache.buf32k = NULL;
 
240
            } else
 
241
            {
 
242
                if (! (fp->buf32k = (char *) malloc(ZZIP_32K)))
 
243
                    { err = ZZIP_OUTOFMEM; goto error; }
 
244
            }
 
245
 
 
246
            if (dir->cache.locked == &self)
 
247
                dir->cache.locked = NULL;
 
248
            /*
 
249
             * In order to support simultaneous open files in one zip archive
 
250
             * we'll fix the fd offset when opening new file/changing which
 
251
             * file to read...
 
252
             */
 
253
 
 
254
            if (zzip_file_saveoffset(dir->currentfp) < 0)
 
255
                { err = ZZIP_DIR_SEEK; goto error; }
 
256
 
 
257
            fp->offset = hdr->d_off;
 
258
            dir->currentfp = fp;
 
259
 
 
260
            if (dir->io->fd.seeks(dir->fd, hdr->d_off, SEEK_SET) < 0)
 
261
                { err = ZZIP_DIR_SEEK; goto error; }
 
262
 
 
263
            {
 
264
                /* skip local header - should test tons of other info, 
 
265
                 * but trust that those are correct */
 
266
                zzip_ssize_t dataoff;
 
267
                struct zzip_file_header *p = (void *) fp->buf32k;
 
268
 
 
269
                dataoff = dir->io->fd.read(dir->fd, (void *) p, sizeof(*p));
 
270
                if (dataoff < (zzip_ssize_t) sizeof(*p))
 
271
                    { err = ZZIP_DIR_READ;  goto error; }
 
272
                if (! zzip_file_header_check_magic(p))   /* PK\3\4 */
 
273
                    { err = ZZIP_CORRUPTED; goto error; }
 
274
 
 
275
                dataoff = zzip_file_header_sizeof_tail(p);
 
276
 
 
277
                if (dir->io->fd.seeks(dir->fd, dataoff, SEEK_CUR) < 0)
 
278
                    { err = ZZIP_DIR_SEEK; goto error; }
 
279
 
 
280
                fp->dataoffset = dir->io->fd.tells(dir->fd);
 
281
                fp->usize = hdr->d_usize;
 
282
                fp->csize = hdr->d_csize;
 
283
            }
 
284
 
 
285
            err = zzip_inflate_init(fp, hdr);
 
286
            if (err)
 
287
                goto error;
 
288
 
 
289
            return fp;
 
290
        } else
 
291
        {
 
292
            if (hdr->d_reclen == 0)
 
293
                break;
 
294
            hdr = (struct zzip_dir_hdr *) ((char *) hdr + hdr->d_reclen);
 
295
        }                       /*cmp name */
 
296
    }                           /*forever */
 
297
    dir->errcode = ZZIP_ENOENT;
 
298
    return NULL;
 
299
  error:
 
300
    if (fp)
 
301
        zzip_file_close(fp);
 
302
    dir->errcode = err;
 
303
    return NULL;
 
304
}
 
305
 
 
306
/**
 
307
 *  call => inflateInit and setup fp's iterator variables, 
 
308
 *  used by lowlevel => _open functions.
 
309
 */
 
310
static int
 
311
zzip_inflate_init(ZZIP_FILE * fp, struct zzip_dir_hdr *hdr)
 
312
{
 
313
    int err;
 
314
 
 
315
    fp->method = hdr->d_compr;
 
316
    fp->restlen = hdr->d_usize;
 
317
 
 
318
    if (fp->method)
 
319
    {
 
320
        memset(&fp->d_stream, 0, sizeof(fp->d_stream));
 
321
 
 
322
        err = inflateInit2(&fp->d_stream, -MAX_WBITS);
 
323
        if (err != Z_OK)
 
324
            goto error;
 
325
 
 
326
        fp->crestlen = hdr->d_csize;
 
327
    }
 
328
    return 0;
 
329
  error:
 
330
    if (fp)
 
331
        zzip_file_close(fp);
 
332
    return err;
 
333
}
 
334
 
 
335
/**                                                             
 
336
 * This function closes the given ZZIP_FILE handle. 
 
337
 *
 
338
 * If the ZZIP_FILE wraps a normal stat'fd then it is just that int'fd 
 
339
 * that is being closed and the otherwise empty ZZIP_FILE gets freed.
 
340
 */
 
341
int
 
342
zzip_fclose(ZZIP_FILE * fp)
 
343
{
 
344
    if (! fp)
 
345
        return 0;
 
346
    if (! fp->dir)               /* stat fd */
 
347
        { int r = fp->io->fd.close(fp->fd); free(fp); return r; }
 
348
    else
 
349
        return zzip_file_close(fp);
 
350
}
 
351
 
 
352
/** => zzip_fclose
 
353
 */
 
354
int
 
355
zzip_close(ZZIP_FILE * fp)
 
356
{
 
357
    return zzip_fclose(fp);
 
358
}
 
359
 
 
360
/**                                                              
 
361
 * This functions read data from zip-contained file.
 
362
 *
 
363
 * It works like => read(2) and will fill the given buffer with bytes from
 
364
 * the opened file. It will return the number of bytes read, so if the => EOF
 
365
 * is encountered you will be prompted with the number of bytes actually read.
 
366
 * 
 
367
 * This is the routines that needs the => buf32k buffer, and it would have
 
368
 * need for much more polishing but it does already work quite well.
 
369
 * 
 
370
 * Note: the 32K buffer is rather big. The original inflate-algorithm
 
371
 *       required just that but the latest zlib would work just fine with
 
372
 *       a smaller buffer.
 
373
 */
 
374
zzip_ssize_t
 
375
zzip_file_read(ZZIP_FILE * fp, void *buf, zzip_size_t len)
 
376
{
 
377
    ZZIP_DIR *dir;
 
378
    zzip_size_t l;
 
379
    zzip_ssize_t rv;
 
380
 
 
381
    if (! fp || ! fp->dir)
 
382
        return 0;
 
383
 
 
384
    dir = fp->dir;
 
385
    l = fp->restlen > len ? len : fp->restlen;
 
386
    if (fp->restlen == 0)
 
387
        return 0;
 
388
 
 
389
    /*
 
390
     * If this is other handle than previous, save current seek pointer
 
391
     * and read the file position of `this' handle.
 
392
     */
 
393
    if (dir->currentfp != fp)
 
394
    {
 
395
        if (zzip_file_saveoffset(dir->currentfp) < 0
 
396
            || fp->io->fd.seeks(dir->fd, fp->offset, SEEK_SET) < 0)
 
397
            { dir->errcode = ZZIP_DIR_SEEK; return -1; }
 
398
        else
 
399
            { dir->currentfp = fp; }
 
400
    }
 
401
 
 
402
    /* if more methods is to be supported, change this to `switch ()' */
 
403
    if (fp->method)             /* method != 0   == 8, inflate */
 
404
    {
 
405
        fp->d_stream.avail_out = l;
 
406
        fp->d_stream.next_out = (unsigned char *) buf;
 
407
 
 
408
        do
 
409
        {
 
410
            int err;
 
411
            zzip_size_t startlen;
 
412
 
 
413
            if (fp->crestlen > 0 && fp->d_stream.avail_in == 0)
 
414
            {
 
415
                zzip_size_t cl = (fp->crestlen < ZZIP_32K ?
 
416
                                  fp->crestlen : ZZIP_32K);
 
417
                /*  zzip_size_t cl = 
 
418
                 *      fp->crestlen > 128 ? 128 : fp->crestlen; 
 
419
                 */
 
420
                zzip_ssize_t i = fp->io->fd.read(dir->fd, fp->buf32k, cl);
 
421
 
 
422
                if (i <= 0)
 
423
                {
 
424
                    dir->errcode = ZZIP_DIR_READ;
 
425
                    /* or ZZIP_DIR_READ_EOF ? */
 
426
                    return -1;
 
427
                }
 
428
                fp->crestlen -= i;
 
429
                fp->d_stream.avail_in = i;
 
430
                fp->d_stream.next_in = (unsigned char *) fp->buf32k;
 
431
            }
 
432
 
 
433
            startlen = fp->d_stream.total_out;
 
434
            err = inflate(&fp->d_stream, Z_NO_FLUSH);
 
435
 
 
436
            if (err == Z_STREAM_END)
 
437
                { fp->restlen = 0; }
 
438
            else if (err == Z_OK)
 
439
                { fp->restlen -= (fp->d_stream.total_out - startlen); }
 
440
            else
 
441
                { dir->errcode = err; return -1; }
 
442
        }
 
443
        while (fp->restlen && fp->d_stream.avail_out);
 
444
 
 
445
        return l - fp->d_stream.avail_out;
 
446
    } else
 
447
    {                           /* method == 0 -- unstore */
 
448
        rv = fp->io->fd.read(dir->fd, buf, l);
 
449
        if (rv > 0)
 
450
            { fp->restlen-= rv; }
 
451
        else if (rv < 0)
 
452
            { dir->errcode = ZZIP_DIR_READ; }
 
453
        return rv;
 
454
    }
 
455
}
 
456
 
 
457
/**                                                               
 
458
 * This function will read(2) data from a real/zipped file.
 
459
 *
 
460
 * the replacement for => read(2) will fill the given buffer with bytes from
 
461
 * the opened file. It will return the number of bytes read, so if the EOF
 
462
 * is encountered you will be prompted with the number of bytes actually read.
 
463
 * 
 
464
 * If the file-handle is wrapping a stat'able file then it will actually just
 
465
 * perform a normal => read(2)-call, otherwise => zzip_file_read is called
 
466
 * to decompress the data stream and any error is mapped to => errno(3).
 
467
 */
 
468
zzip_ssize_t
 
469
zzip_read(ZZIP_FILE * fp, void *buf, zzip_size_t len)
 
470
{
 
471
    if (! fp)
 
472
        return 0;
 
473
    if (! fp->dir)
 
474
        { return fp->io->fd.read(fp->fd, buf, len); }    /* stat fd */
 
475
    else
 
476
    {
 
477
        register zzip_ssize_t v;
 
478
 
 
479
        v = zzip_file_read(fp, buf, len);
 
480
        if (v == -1)
 
481
            { errno = zzip_errno(fp->dir->errcode); }
 
482
        return v;
 
483
    }
 
484
}
 
485
 
 
486
/** => zzip_read
 
487
 */
 
488
zzip_size_t
 
489
zzip_fread(void *ptr, zzip_size_t size, zzip_size_t nmemb, ZZIP_FILE * file)
 
490
{
 
491
    if (! size)
 
492
        size = 1;
 
493
    return zzip_read(file, ptr, size * nmemb) / size;
 
494
}
 
495
 
 
496
 
 
497
#define ZZIP_WRONLY             O_WRONLY
 
498
#define ZZIP_EXCL               O_EXCL
 
499
 
 
500
#if     defined                 O_SYNC
 
501
#define ZZIP_SYNC               O_SYNC
 
502
#else
 
503
#define ZZIP_SYNC               0
 
504
#endif
 
505
 
 
506
#if     defined                 O_NONBLOCK
 
507
#define ZZIP_NONBLOCK           O_NONBLOCK
 
508
#elif   defined                 O_NDELAY
 
509
#define ZZIP_NOCTTY             O_NDELAY
 
510
#else
 
511
#define ZZIP_NOCTTY             0
 
512
#endif
 
513
 
 
514
/* ------------------------------------------------------------------- */
 
515
 
 
516
/**                                                          also: fopen(2)  
 
517
 * This function will => fopen(3) a real/zipped file.
 
518
 * 
 
519
 * It has some magic functionality builtin - it will first try to open
 
520
 * the given <em>filename</em> as a normal file. If it does not
 
521
 * exist, the given path to the filename (if any) is split into
 
522
 * its directory-part and the file-part. A ".zip" extension is
 
523
 * then added to the directory-part to create the name of a
 
524
 * zip-archive. That zip-archive (if it exists) is being searched
 
525
 * for the file-part, and if found a zzip-handle is returned. 
 
526
 * 
 
527
 * Note that if the file is found in the normal fs-directory the
 
528
 * returned structure is mostly empty and the => zzip_read call will
 
529
 * use the libc => read to obtain data. Otherwise a => zzip_file_open 
 
530
 * is performed and any error mapped to => errno(3).
 
531
 * 
 
532
 * unlike the posix-wrapper => zzip_open the mode-argument is
 
533
 * a string which allows for more freedom to support the extra
 
534
 * zzip modes called ZZIP_CASEINSENSITIVE and ZZIP_IGNOREPATH.
 
535
 * Currently, this => zzip_fopen call will convert the following
 
536
 * characters in the mode-string into their corrsponding mode-bits: 
 
537
 * * <code> "r" : O_RDONLY : </code> read-only
 
538
 * * <code> "b" : O_BINARY : </code> binary (win32 specific)
 
539
 * * <code> "f" : O_NOCTTY : </code> no char device (unix)
 
540
 * * <code> "i" : ZZIP_CASELESS : </code> inside zip file
 
541
 * * <code> "*" : ZZIP_NOPATHS : </code> inside zip file only
 
542
 * all other modes will be ignored for zip-contained entries
 
543
 * but they are transferred for compatibility and portability,
 
544
 * including these extra sugar bits:
 
545
 * * <code> "x" : O_EXCL :</code> fail if file did exist
 
546
 * * <code> "s" : O_SYNC :</code> synchronized access
 
547
 * * <code> "n" : O_NONBLOCK :</code> nonblocking access
 
548
 * * <code> "z#" : compression level :</code> for zlib
 
549
 * * <code> "g#" : group access :</code> unix access bits
 
550
 * * <code> "u#" : owner access :</code> unix access bits
 
551
 * * <code> "o#" : world access :</code> unix access bits
 
552
 * ... the access bits are in traditional unix bit format
 
553
 * with 7 = read/write/execute, 6 = read/write, 4 = read-only.
 
554
 *
 
555
 * The default access mode is 0664, and the compression level
 
556
 * is ignored since the lib can not yet write zip files, otherwise
 
557
 * it would be the initialisation value for the zlib deflateInit
 
558
 * where 0 = no-compression, 1 = best-speed, 9 = best-compression.
 
559
 *
 
560
 * This function returns a new zzip-handle (use => zzip_close to return
 
561
 * it). On error this function will return null setting => errno(3).
 
562
 */
 
563
ZZIP_FILE *
 
564
zzip_fopen(zzip_char_t * filename, zzip_char_t * mode)
 
565
{
 
566
    return zzip_freopen(filename, mode, 0);
 
567
}
 
568
 
 
569
/** => zzip_fopen
 
570
 *
 
571
 * This function receives an additional argument pointing to
 
572
 * a ZZIP_FILE* being already in use. If this extra argument is
 
573
 * null then this function is identical with calling => zzip_fopen
 
574
 *
 
575
 * Per default, the old file stream is closed and only the internal
 
576
 * structures associated with it are kept. These internal structures
 
577
 * may be reused for the return value, and this is a lot quicker when
 
578
 * the filename matches a zipped file that is incidently in the very
 
579
 * same zip arch as the old filename wrapped in the stream struct.
 
580
 *
 
581
 * That's simply because the zip arch's central directory does not 
 
582
 * need to be read again. As an extension for this function, if the 
 
583
 * mode-string contains a "q" then the old stream is not closed but
 
584
 * left untouched, instead it is only given as a hint that a new
 
585
 * file handle may share/copy the zip arch structures of the old file
 
586
 * handle if that is possible, i.e when they are in the same zip arch.
 
587
 *
 
588
 * This function returns a new zzip-handle (use => zzip_close to return
 
589
 * it). On error this function will return null setting => errno(3).
 
590
 */
 
591
ZZIP_FILE *
 
592
zzip_freopen(zzip_char_t * filename, zzip_char_t * mode, ZZIP_FILE * stream)
 
593
{
 
594
    int o_flags = 0;
 
595
    int o_modes = 0664;
 
596
 
 
597
    if (! mode)
 
598
        mode = "rb";
 
599
 
 
600
#   ifndef O_BINARY
 
601
#   define O_BINARY 0
 
602
#   endif
 
603
#   ifndef O_NOCTTY
 
604
#   define O_NOCTTY 0
 
605
#   endif
 
606
#   ifndef O_SYNC
 
607
#   define O_SYNC 0
 
608
#   endif
 
609
#   ifndef O_NONBLOCK
 
610
#   define O_NONBLOCK 0
 
611
#   endif
 
612
 
 
613
    for (; *mode; mode++)
 
614
    {
 
615
        switch (*mode)
 
616
        {
 
617
            /* *INDENT-OFF* */
 
618
        case '0': case '1': case '2': case '3': case '4': 
 
619
        case '5': case '6': case '7': case '8': case '9':
 
620
            continue; /* ignore if not attached to other info */
 
621
        case 'r': o_flags |= mode[1] == '+' ? O_RDWR : O_RDONLY; break;
 
622
        case 'w': o_flags |= mode[1] == '+' ? O_RDWR : O_WRONLY; 
 
623
                  o_flags |= O_TRUNC; break;
 
624
        case 'b': o_flags |= O_BINARY; break;
 
625
        case 'f': o_flags |= O_NOCTTY; break;
 
626
        case 'i': o_modes |= ZZIP_CASELESS; break;
 
627
        case '*': o_modes |= ZZIP_NOPATHS; break;
 
628
        case 'x': o_flags |= O_EXCL; break;
 
629
        case 's': o_flags |= O_SYNC; break;
 
630
        case 'n': o_flags |= O_NONBLOCK; break;
 
631
        case 'o': o_modes &=~ 07; 
 
632
                  o_modes |= ((mode[1] - '0')) & 07; continue;
 
633
        case 'g': o_modes &=~ 070; 
 
634
                  o_modes |= ((mode[1] - '0') << 3) & 070; continue;
 
635
        case 'u': o_modes &=~ 0700; 
 
636
                  o_modes |= ((mode[1] - '0') << 6) & 0700; continue;
 
637
        case 'q': o_modes |= ZZIP_FACTORY; break;
 
638
        case 'z': /* compression level */
 
639
            continue; /* currently ignored, just for write mode */
 
640
            /* *INDENT-ON* */
 
641
        }
 
642
    }
 
643
 
 
644
    {
 
645
        ZZIP_FILE *fp =
 
646
            zzip_open_shared_io(stream, filename, o_flags, o_modes, 0, 0);
 
647
 
 
648
        if (! (o_modes & ZZIP_FACTORY) && stream)
 
649
            zzip_file_close(stream);
 
650
 
 
651
        return fp;
 
652
    }
 
653
}
 
654
 
 
655
/**                                                        
 
656
 * This function will => open(2) a real/zipped file
 
657
 *
 
658
 * It has some magic functionality builtin - it will first try to open
 
659
 * the given <em>filename</em> as a normal file. If it does not
 
660
 * exist, the given path to the filename (if any) is split into
 
661
 * its directory-part and the file-part. A ".zip" extension is
 
662
 * then added to the directory-part to create the name of a
 
663
 * zip-archive. That zip-archive (if it exists) is being searched
 
664
 * for the file-part, and if found a zzip-handle is returned. 
 
665
 * 
 
666
 * Note that if the file is found in the normal fs-directory the
 
667
 * returned structure is mostly empty and the => zzip_read call will
 
668
 * use the libc => read to obtain data. Otherwise a => zzip_file_open 
 
669
 * is performed and any error mapped to => errno(3).
 
670
 * 
 
671
 * There was a possibility to transfer zziplib-specific openmodes
 
672
 * through o_flags but you should please not use them anymore and
 
673
 * look into => zzip_open_ext_io to submit them down. This function
 
674
 * is shallow in that it just extracts the zzipflags and calls 
 
675
 * * <code>zzip_open_ext_io(filename, o_flags, zzipflags|0664, 0, 0) </code>
 
676
 * you must stop using this extra functionality (not well known anyway) 
 
677
 * since zzip_open might be later usable to open files for writing 
 
678
 * in which case the _EXTRAFLAGS will get in conflict.
 
679
 *
 
680
 * compare with  => open(2) and => zzip_fopen
 
681
 */
 
682
ZZIP_FILE *
 
683
zzip_open(zzip_char_t * filename, int o_flags)
 
684
{
 
685
    /* backward compatibility */
 
686
    int o_modes = 0664;
 
687
 
 
688
    if (o_flags & ZZIP_CASEINSENSITIVE)
 
689
        {  o_flags ^= ZZIP_CASEINSENSITIVE; o_modes |= ZZIP_CASELESS; }
 
690
    if (o_flags & ZZIP_IGNOREPATH)
 
691
        {  o_flags ^= ZZIP_IGNOREPATH;      o_modes |= ZZIP_NOPATHS; }
 
692
    return zzip_open_ext_io(filename, o_flags, o_modes, 0, 0);
 
693
}
 
694
 
 
695
/* ZZIP_ONLYZIP won't work on platforms with sizeof(int) == 16bit */
 
696
#if ZZIP_SIZEOF_INT+0 == 2
 
697
#undef ZZIP_ONLYZIP
 
698
#endif
 
699
 
 
700
/** => zzip_open
 
701
 *
 
702
 * This function uses explicit ext and io instead of the internal 
 
703
 * defaults, setting them to zero is equivalent to => zzip_open
 
704
 * 
 
705
 * note that the two flag types have been split into an o_flags
 
706
 * (for fcntl-like openflags) and o_modes where the latter shall
 
707
 * carry the zzip_flags and possibly accessmodes for unix filesystems.
 
708
 * Since this version of zziplib can not write zipfiles, it is not
 
709
 * yet used for anything else than zzip-specific modeflags.
 
710
 *
 
711
 * This function returns a new zzip-handle (use => zzip_close to return
 
712
 * it). On error this function will return null setting => errno(3).
 
713
 */
 
714
ZZIP_FILE *
 
715
zzip_open_ext_io(zzip_char_t * filename, int o_flags, int o_modes,
 
716
                 zzip_strings_t * ext, zzip_plugin_io_t io)
 
717
{
 
718
    return zzip_open_shared_io(0, filename, o_flags, o_modes, ext, io);
 
719
}
 
720
 
 
721
/** => zzip_open
 
722
 * 
 
723
 * This function takes an extra stream argument - if a handle has been
 
724
 * then ext/io can be left null and the new stream handle will pick up 
 
725
 * the ext/io. This should be used only in specific environment however 
 
726
 * since => zzip_file_real does not store any ext-sequence.
 
727
 *
 
728
 * The benefit for this function comes in when the old file handle
 
729
 * was openened from a file within a zip archive. When the new file
 
730
 * is in the same zip archive then the internal zzip_dir structures
 
731
 * will be shared. It is even quicker, as no check needs to be done
 
732
 * anymore trying to guess the zip archive place in the filesystem,
 
733
 * here we just check whether the zip archive's filepath is a prefix
 
734
 * part of the filename to be opened. 
 
735
 *
 
736
 * Note that this function is also used by => zzip_freopen that
 
737
 * will unshare the old handle, thereby possibly closing the handle.
 
738
 *
 
739
 * This function returns a new zzip-handle (use => zzip_close to return
 
740
 * it). On error this function will return null setting => errno(3).
 
741
 */
 
742
ZZIP_FILE *
 
743
zzip_open_shared_io(ZZIP_FILE * stream,
 
744
                    zzip_char_t * filename, int o_flags, int o_modes,
 
745
                    zzip_strings_t * ext, zzip_plugin_io_t io)
 
746
{
 
747
    if (stream && stream->dir)
 
748
    {
 
749
        if (! ext)
 
750
            ext = stream->dir->fileext;
 
751
        if (! io)
 
752
            io = stream->dir->io;
 
753
    }
 
754
    if (! io)
 
755
        io = zzip_get_default_io();
 
756
 
 
757
    if (o_modes & (ZZIP_PREFERZIP | ZZIP_ONLYZIP))
 
758
        goto try_zzip;
 
759
  try_real:
 
760
    /* prefer an existing real file */
 
761
    {
 
762
        zzip_plugin_io_t os = (o_modes & ZZIP_ALLOWREAL)
 
763
            ? zzip_get_default_io() : io;
 
764
        int fd = os->fd.open(filename, o_flags);        /* io->fd.open */
 
765
 
 
766
        if (fd != -1)
 
767
        {
 
768
            ZZIP_FILE *fp = calloc(1, sizeof(ZZIP_FILE));
 
769
 
 
770
            if (! fp)
 
771
                { os->fd.close(fd); return 0; }  /* io->fd.close */
 
772
 
 
773
            fp->fd = fd;
 
774
            fp->io = os;
 
775
            return fp;
 
776
        }
 
777
        if (o_modes & ZZIP_PREFERZIP)
 
778
            return 0;
 
779
    }
 
780
  try_zzip:
 
781
 
 
782
    /* if the user had it in place of a normal xopen, then
 
783
     * we better defend this lib against illegal usage */
 
784
    if (o_flags & (O_CREAT | O_WRONLY))
 
785
        { errno = EINVAL; return 0; }
 
786
    if (o_flags & (O_RDWR))
 
787
        { o_flags ^= O_RDWR; o_flags |= O_RDONLY; }
 
788
 
 
789
    /* this is just for backward compatibility -and strictly needed to
 
790
     * prepare ourselves for more options and more options later on... */
 
791
    /*# if (o_modes & ZZIP_CASELESS) { o_flags |= ZZIP_CASEINSENSITIVE; } */
 
792
    /*# if (o_modes & ZZIP_NOPATHS)  { o_flags |= ZZIP_IGNOREPATH; } */
 
793
 
 
794
    /* see if we can open a file that is a zip file */
 
795
    {
 
796
        char basename[PATH_MAX];
 
797
        char *p;
 
798
        int filename_len = strlen(filename);
 
799
 
 
800
        if (filename_len >= PATH_MAX)
 
801
            { errno = ENAMETOOLONG; return 0; }
 
802
        memcpy(basename, filename, filename_len + 1);
 
803
 
 
804
        /* see if we can share the same zip directory */
 
805
        if (stream && stream->dir && stream->dir->realname)
 
806
        {
 
807
            zzip_size_t len = strlen(stream->dir->realname);
 
808
 
 
809
            if (! memcmp(filename, stream->dir->realname, len) &&
 
810
                filename[len] == '/' && filename[len + 1])
 
811
            {
 
812
                ZZIP_FILE *fp =
 
813
                    zzip_file_open(stream->dir, filename + len + 1, o_modes);
 
814
                if (! fp)
 
815
                    { errno = zzip_errno (stream->dir->errcode); }
 
816
                return fp;
 
817
            }
 
818
        }
 
819
 
 
820
        /* per each slash in filename, check if it there is a zzip around */
 
821
        while ((p = strrchr(basename, '/')))
 
822
        {
 
823
            zzip_error_t e = 0;
 
824
            ZZIP_DIR *dir;
 
825
            ZZIP_FILE *fp;
 
826
            int fd;
 
827
 
 
828
            *p = '\0';
 
829
            /* i.e. cut at path separator == possible zipfile basename */
 
830
            fd = __zzip_try_open(basename, o_flags | O_RDONLY | O_BINARY,
 
831
                                 ext, io);
 
832
            if (fd == -1)
 
833
                { continue; }
 
834
 
 
835
            /* found zip-file ....  now try to parse it */
 
836
            dir = zzip_dir_fdopen_ext_io(fd, &e, ext, io);
 
837
            if (e)
 
838
                { errno = zzip_errno(e); io->fd.close(fd); return 0; }
 
839
 
 
840
            /* (p - basename) is the lenghtof zzip_dir part of the filename */
 
841
            fp = zzip_file_open(dir, filename + (p - basename) + 1, o_modes);
 
842
            if (! fp)
 
843
                { errno = zzip_errno(dir->errcode); }
 
844
            else
 
845
                { if (! dir->realname) dir->realname = strdup (basename); }
 
846
 
 
847
            zzip_dir_close(dir);
 
848
            /* note: since (fp) is attached that (dir) will survive */
 
849
            /* but (dir) is implicitly closed on next zzip_close(fp) */
 
850
 
 
851
            return fp;
 
852
        }
 
853
 
 
854
        if (o_modes & ZZIP_PREFERZIP)
 
855
            goto try_real;
 
856
        else
 
857
            { errno = ENOENT; return 0; }
 
858
    }
 
859
}
 
860
 
 
861
#if defined ZZIP_LARGEFILE_RENAME && defined EOVERFLOW && defined PIC
 
862
#undef zzip_open_shared_io      /* zzip_open_shared_io64 */
 
863
#undef zzip_open_ext_io         /* zzip_open_ext_io64 */
 
864
#undef zzip_opendir_ext_io      /* zzip_opendir_ext_io64 */
 
865
 
 
866
ZZIP_FILE *zzip_open_shared_io(ZZIP_FILE * stream,
 
867
                               zzip_char_t * name, int o_flags,
 
868
                               int o_modes, zzip_strings_t * ext,
 
869
                               zzip_plugin_io_t io);
 
870
ZZIP_FILE *zzip_open_ext_io(zzip_char_t * name, int o_flags,
 
871
                            int o_modes, zzip_strings_t * ext,
 
872
                            zzip_plugin_io_t io);
 
873
ZZIP_DIR *zzip_opendir_ext_io(zzip_char_t * name, int o_modes,
 
874
                              zzip_strings_t * ext, zzip_plugin_io_t io);
 
875
 
 
876
/* DLL compatibility layer - so that 32bit code can link with this lib too */
 
877
 
 
878
ZZIP_FILE *
 
879
zzip_open_shared_io(ZZIP_FILE * stream,
 
880
                    zzip_char_t * name, int o_flags,
 
881
                    int o_modes, zzip_strings_t * ext, zzip_plugin_io_t io)
 
882
{
 
883
    if (! io)
 
884
        return zzip_open_shared_io64(stream, name, o_flags, o_modes, ext, io);
 
885
    errno = EOVERFLOW;
 
886
    return NULL;
 
887
}
 
888
 
 
889
ZZIP_FILE *
 
890
zzip_open_ext_io(zzip_char_t * name, int o_flags, int o_modes,
 
891
                 zzip_strings_t * ext, zzip_plugin_io_t io)
 
892
{
 
893
    if (! io)
 
894
        return zzip_open_ext_io64(name, o_flags, o_modes, ext, io);
 
895
    errno = EOVERFLOW;
 
896
    return NULL;
 
897
}
 
898
 
 
899
ZZIP_DIR *
 
900
zzip_opendir_ext_io(zzip_char_t * name, int o_modes,
 
901
                    zzip_strings_t * ext, zzip_plugin_io_t io)
 
902
{
 
903
    if (! io)
 
904
        return zzip_opendir_ext_io64(name, o_modes, ext, io);
 
905
    else
 
906
        { errno = EOVERFLOW; return NULL; }
 
907
}
 
908
 
 
909
#endif /* ZZIP_LARGEFILE_RENAME && EOVERFLOW && PIC */
 
910
 
 
911
/* ------------------------------------------------------------------- */
 
912
 
 
913
/**                                                                
 
914
 * This function will rewind a real/zipped file. 
 
915
 *
 
916
 * It seeks to the beginning of this file's data in the zip, 
 
917
 * or the beginning of the file for a stat'fd.
 
918
 */
 
919
int
 
920
zzip_rewind(ZZIP_FILE * fp)
 
921
{
 
922
    ZZIP_DIR *dir;
 
923
    int err;
 
924
 
 
925
    if (! fp)
 
926
        return -1;
 
927
 
 
928
    if (! fp->dir)
 
929
    {                           /* stat fd */
 
930
        fp->io->fd.seeks(fp->fd, 0, SEEK_SET);
 
931
        return 0;
 
932
    }
 
933
 
 
934
    dir = fp->dir;
 
935
    /*
 
936
     * If this is other handle than previous, save current seek pointer
 
937
     */
 
938
    if (dir->currentfp != fp)
 
939
    {
 
940
        if (zzip_file_saveoffset(dir->currentfp) < 0)
 
941
            { dir->errcode = ZZIP_DIR_SEEK; return -1; }
 
942
        else
 
943
            { dir->currentfp = fp; }
 
944
    }
 
945
 
 
946
    /* seek to beginning of this file */
 
947
    if (fp->io->fd.seeks(dir->fd, fp->dataoffset, SEEK_SET) < 0)
 
948
        return -1;
 
949
 
 
950
    /* reset the inflate init stuff */
 
951
    fp->restlen = fp->usize;
 
952
    fp->offset = fp->dataoffset;
 
953
 
 
954
    if (fp->method)
 
955
    {                           /* method == 8, deflate */
 
956
        err = inflateReset(&fp->d_stream);
 
957
        if (err != Z_OK)
 
958
            goto error;
 
959
 
 
960
        /* start over at next inflate with a fresh read() */
 
961
        fp->d_stream.avail_in = 0;
 
962
        fp->crestlen = fp->csize;
 
963
    }
 
964
 
 
965
    return 0;
 
966
 
 
967
  error:
 
968
    if (fp)
 
969
        zzip_file_close(fp);
 
970
    return err;
 
971
}
 
972
 
 
973
/**  
 
974
 * This function will perform a => lseek(2) operation on a real/zipped file
 
975
 *
 
976
 * It will try to seek to the offset specified by offset, relative to whence, 
 
977
 * which is one of SEEK_SET, SEEK_CUR or SEEK_END.
 
978
 * 
 
979
 * If the file-handle is wrapping a stat'able file then it will actually just
 
980
 * perform a normal => lseek(2)-call. Otherwise the relative offset
 
981
 * is calculated, negative offsets are transformed into positive ones
 
982
 * by rewinding the file, and then data is read until the offset is
 
983
 * reached.  This can make the function terribly slow, but this is
 
984
 * how gzio implements it, so I'm not sure there is a better way
 
985
 * without using the internals of the algorithm.
 
986
 */
 
987
zzip_off_t
 
988
zzip_seek(ZZIP_FILE * fp, zzip_off_t offset, int whence)
 
989
{
 
990
    zzip_off_t cur_pos, rel_ofs, read_size, ofs;
 
991
    ZZIP_DIR *dir;
 
992
 
 
993
    if (! fp)
 
994
        return -1;
 
995
 
 
996
    if (! fp->dir)
 
997
    {                           /* stat fd */
 
998
        return fp->io->fd.seeks(fp->fd, offset, whence);
 
999
    }
 
1000
 
 
1001
    cur_pos = zzip_tell(fp);
 
1002
 
 
1003
    /* calculate relative offset */
 
1004
    switch (whence)
 
1005
    {
 
1006
    case SEEK_SET:             /* from beginning */
 
1007
        rel_ofs = offset - cur_pos;
 
1008
        break;
 
1009
    case SEEK_CUR:             /* from current */
 
1010
        rel_ofs = offset;
 
1011
        break;
 
1012
    case SEEK_END:             /* from end */
 
1013
        rel_ofs = fp->usize + offset - cur_pos;
 
1014
        break;
 
1015
    default:                   /* something wrong */
 
1016
        return -1;
 
1017
    }
 
1018
 
 
1019
    if (rel_ofs == 0)
 
1020
        return cur_pos;         /* don't have to move */
 
1021
 
 
1022
    if (rel_ofs < 0)
 
1023
    {                           /* convert backward into forward */
 
1024
        if (zzip_rewind(fp) == -1)
 
1025
            return -1;
 
1026
 
 
1027
        read_size = cur_pos + rel_ofs;
 
1028
        cur_pos = 0;
 
1029
    } else
 
1030
    {                           /* amount to read is positive relative offset */
 
1031
        read_size = rel_ofs;
 
1032
    }
 
1033
 
 
1034
    if (read_size < 0)          /* bad offset, before beginning of file */
 
1035
        return -1;
 
1036
 
 
1037
    if (read_size + cur_pos > (zzip_off_t) fp->usize)   /* bad offset, past EOF */
 
1038
        return -1;
 
1039
 
 
1040
    if (read_size == 0)         /* nothing to read */
 
1041
        return cur_pos;
 
1042
 
 
1043
    dir = fp->dir;
 
1044
    /*
 
1045
     * If this is other handle than previous, save current seek pointer
 
1046
     * and read the file position of `this' handle.
 
1047
     */
 
1048
    if (dir->currentfp != fp)
 
1049
    {
 
1050
        if (zzip_file_saveoffset(dir->currentfp) < 0
 
1051
            || dir->currentfp->io->fd.seeks(dir->fd, fp->offset, SEEK_SET) < 0)
 
1052
            { dir->errcode = ZZIP_DIR_SEEK; return -1; }
 
1053
        else
 
1054
            { dir->currentfp = fp; }
 
1055
    }
 
1056
 
 
1057
    if (fp->method == 0)
 
1058
    {                           /* unstore, just lseek relatively */
 
1059
        ofs = fp->io->fd.tells(dir->fd);
 
1060
        ofs = fp->io->fd.seeks(dir->fd, read_size, SEEK_CUR);
 
1061
        if (ofs > 0)
 
1062
        {                       /* readjust from beginning of file */
 
1063
            ofs -= fp->dataoffset;
 
1064
            fp->restlen = fp->usize - ofs;
 
1065
        }
 
1066
        return ofs;
 
1067
    } else
 
1068
    {                           /* method == 8, inflate */
 
1069
        char *buf;
 
1070
 
 
1071
        /*FIXME: use a static buffer! */
 
1072
        buf = (char *) malloc(ZZIP_32K);
 
1073
        if (! buf)
 
1074
            return -1;
 
1075
 
 
1076
        while (read_size > 0)
 
1077
        {
 
1078
            zzip_off_t size = ZZIP_32K;
 
1079
 
 
1080
            if (read_size < size /*32K */ )
 
1081
                size = read_size;
 
1082
 
 
1083
            size = zzip_file_read(fp, buf, (zzip_size_t) size);
 
1084
            if (size <= 0)
 
1085
                { free(buf); return -1; }
 
1086
 
 
1087
            read_size -= size;
 
1088
        }
 
1089
 
 
1090
        free(buf);
 
1091
    }
 
1092
 
 
1093
    return zzip_tell(fp);
 
1094
}
 
1095
 
 
1096
/**                                                                  
 
1097
 * This function will => tell(2) the current position in a real/zipped file
 
1098
 *
 
1099
 * It will return the current offset within the real/zipped file, 
 
1100
 * measured in uncompressed bytes for the zipped-file case.
 
1101
 *
 
1102
 * If the file-handle is wrapping a stat'able file then it will actually just
 
1103
 * perform a normal => tell(2)-call, otherwise the offset is
 
1104
 * calculated from the amount of data left and the total uncompressed
 
1105
 * size;
 
1106
 */
 
1107
zzip_off_t
 
1108
zzip_tell(ZZIP_FILE * fp)
 
1109
{
 
1110
    if (! fp)
 
1111
        return -1;
 
1112
 
 
1113
    if (! fp->dir)               /* stat fd */
 
1114
        return fp->io->fd.tells(fp->fd);
 
1115
 
 
1116
    /* current uncompressed offset is uncompressed size - data left */
 
1117
    return (fp->usize - fp->restlen);
 
1118
}
 
1119
 
 
1120
/* 
 
1121
 * Local variables:
 
1122
 * c-file-style: "stroustrup"
 
1123
 * End:
 
1124
 */