summaryrefslogtreecommitdiff
path: root/libdex/ZipArchive.h
blob: bf4edf972a313adb039696247c329ccc86e5dd5f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Read-only access to Zip archives, with minimal heap allocation.
 */
#ifndef _LIBDEX_ZIPARCHIVE
#define _LIBDEX_ZIPARCHIVE

#include "SysUtil.h"
#include "DexFile.h"            // need DEX_INLINE


/*
 * Trivial typedef to ensure that ZipEntry is not treated as a simple
 * integer.  We use NULL to indicate an invalid value.
 */
typedef void* ZipEntry;

/*
 * One entry in the hash table.
 */
typedef struct ZipHashEntry {
    const char*     name;
    unsigned short  nameLen;
    //unsigned int    hash;
} ZipHashEntry;

/*
 * Read-only Zip archive.
 *
 * We want "open" and "find entry by name" to be fast operations, and
 * we want to use as little memory as possible.  We memory-map the zip
 * central directory, and load a hash table with pointers to the filenames
 * (which aren't null-terminated).  The other fields are at a fixed offset
 * from the filename, so we don't need to extract those (but we do need
 * to byte-read and endian-swap them every time we want them).
 *
 * It's possible that somebody has handed us a massive (~1GB) zip archive,
 * so we can't expect to mmap the entire file.
 *
 * To speed comparisons when doing a lookup by name, we could make the mapping
 * "private" (copy-on-write) and null-terminate the filenames after verifying
 * the record structure.  However, this requires a private mapping of
 * every page that the Central Directory touches.  Easier to tuck a copy
 * of the string length into the hash table entry.
 */
typedef struct ZipArchive {
    /* open Zip archive */
    int         mFd;

    /* mapped central directory area */
    off_t       mDirectoryOffset;
    MemMapping  mDirectoryMap;

    /* number of entries in the Zip archive */
    int         mNumEntries;

    /*
     * We know how many entries are in the Zip archive, so we can have a
     * fixed-size hash table.  We probe on collisions.
     */
    int         mHashTableSize;
    ZipHashEntry* mHashTable;
} ZipArchive;

/* Zip compression methods we support */
enum {
    kCompressStored     = 0,        // no compression
    kCompressDeflated   = 8,        // standard deflate
};


/*
 * Open a Zip archive.
 *
 * On success, returns 0 and populates "pArchive".  Returns nonzero errno
 * value on failure.
 */
int dexZipOpenArchive(const char* fileName, ZipArchive* pArchive);

/*
 * Like dexZipOpenArchive, but takes a file descriptor open for reading
 * at the start of the file.  The descriptor must be mappable (this does
 * not allow access to a stream).
 *
 * "debugFileName" will appear in error messages, but is not otherwise used.
 */
int dexZipPrepArchive(int fd, const char* debugFileName, ZipArchive* pArchive);

/*
 * Close archive, releasing resources associated with it.
 *
 * Depending on the implementation this could unmap pages used by classes
 * stored in a Jar.  This should only be done after unloading classes.
 */
void dexZipCloseArchive(ZipArchive* pArchive);

/*
 * Return the archive's file descriptor.
 */
DEX_INLINE int dexZipGetArchiveFd(const ZipArchive* pArchive) {
    return pArchive->mFd;
}

/*
 * Find an entry in the Zip archive, by name.  Returns NULL if the entry
 * was not found.
 */
ZipEntry dexZipFindEntry(const ZipArchive* pArchive,
    const char* entryName);

/*
 * Retrieve one or more of the "interesting" fields.  Non-NULL pointers
 * are filled in.
 *
 * Returns 0 on success.
 */
int dexZipGetEntryInfo(const ZipArchive* pArchive, ZipEntry entry,
    int* pMethod, size_t* pUncompLen, size_t* pCompLen, off_t* pOffset,
    long* pModWhen, long* pCrc32);

/*
 * Simple accessors.
 */
DEX_INLINE long dexGetZipEntryOffset(const ZipArchive* pArchive,
    const ZipEntry entry)
{
    off_t val = 0;
    dexZipGetEntryInfo(pArchive, entry, NULL, NULL, NULL, &val, NULL, NULL);
    return (long) val;
}
DEX_INLINE size_t dexGetZipEntryUncompLen(const ZipArchive* pArchive,
    const ZipEntry entry)
{
    size_t val = 0;
    dexZipGetEntryInfo(pArchive, entry, NULL, &val, NULL, NULL, NULL, NULL);
    return val;
}
DEX_INLINE long dexGetZipEntryModTime(const ZipArchive* pArchive,
    const ZipEntry entry)
{
    long val = 0;
    dexZipGetEntryInfo(pArchive, entry, NULL, NULL, NULL, NULL, &val, NULL);
    return val;
}
DEX_INLINE long dexGetZipEntryCrc32(const ZipArchive* pArchive,
    const ZipEntry entry)
{
    long val = 0;
    dexZipGetEntryInfo(pArchive, entry, NULL, NULL, NULL, NULL, NULL, &val);
    return val;
}

/*
 * Uncompress and write an entry to a file descriptor.
 *
 * Returns 0 on success.
 */
int dexZipExtractEntryToFile(const ZipArchive* pArchive,
    const ZipEntry entry, int fd);

/*
 * Utility function to compute a CRC-32.
 */
u4 dexInitCrc32(void);
u4 dexComputeCrc32(u4 crc, const void* buf, size_t len);

#endif /*_LIBDEX_ZIPARCHIVE*/