1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * Read-only access to Zip archives, with minimal heap allocation.
19 */
20 #ifndef _LIBDEX_ZIPARCHIVE
21 #define _LIBDEX_ZIPARCHIVE
22
23 #include "SysUtil.h"
24 #include "DexFile.h" // need DEX_INLINE
25
26
27 /*
28 * Trivial typedef to ensure that ZipEntry is not treated as a simple
29 * integer. We use NULL to indicate an invalid value.
30 */
31 typedef void* ZipEntry;
32
33 /*
34 * One entry in the hash table.
35 */
36 typedef struct ZipHashEntry {
37 const char* name;
38 unsigned short nameLen;
39 //unsigned int hash;
40 } ZipHashEntry;
41
42 /*
43 * Read-only Zip archive.
44 *
45 * We want "open" and "find entry by name" to be fast operations, and
46 * we want to use as little memory as possible. We memory-map the zip
47 * central directory, and load a hash table with pointers to the filenames
48 * (which aren't null-terminated). The other fields are at a fixed offset
49 * from the filename, so we don't need to extract those (but we do need
50 * to byte-read and endian-swap them every time we want them).
51 *
52 * It's possible that somebody has handed us a massive (~1GB) zip archive,
53 * so we can't expect to mmap the entire file.
54 *
55 * To speed comparisons when doing a lookup by name, we could make the mapping
56 * "private" (copy-on-write) and null-terminate the filenames after verifying
57 * the record structure. However, this requires a private mapping of
58 * every page that the Central Directory touches. Easier to tuck a copy
59 * of the string length into the hash table entry.
60 */
61 typedef struct ZipArchive {
62 /* open Zip archive */
63 int mFd;
64
65 /* mapped central directory area */
66 off_t mDirectoryOffset;
67 MemMapping mDirectoryMap;
68
69 /* number of entries in the Zip archive */
70 int mNumEntries;
71
72 /*
73 * We know how many entries are in the Zip archive, so we can have a
74 * fixed-size hash table. We probe on collisions.
75 */
76 int mHashTableSize;
77 ZipHashEntry* mHashTable;
78 } ZipArchive;
79
80 /* Zip compression methods we support */
81 enum {
82 kCompressStored = 0, // no compression
83 kCompressDeflated = 8, // standard deflate
84 };
85
86
87 /*
88 * Open a Zip archive.
89 *
90 * On success, returns 0 and populates "pArchive". Returns nonzero errno
91 * value on failure.
92 */
93 int dexZipOpenArchive(const char* fileName, ZipArchive* pArchive);
94
95 /*
96 * Like dexZipOpenArchive, but takes a file descriptor open for reading
97 * at the start of the file. The descriptor must be mappable (this does
98 * not allow access to a stream).
99 *
100 * "debugFileName" will appear in error messages, but is not otherwise used.
101 */
102 int dexZipPrepArchive(int fd, const char* debugFileName, ZipArchive* pArchive);
103
104 /*
105 * Close archive, releasing resources associated with it.
106 *
107 * Depending on the implementation this could unmap pages used by classes
108 * stored in a Jar. This should only be done after unloading classes.
109 */
110 void dexZipCloseArchive(ZipArchive* pArchive);
111
112 /*
113 * Return the archive's file descriptor.
114 */
dexZipGetArchiveFd(const ZipArchive * pArchive)115 DEX_INLINE int dexZipGetArchiveFd(const ZipArchive* pArchive) {
116 return pArchive->mFd;
117 }
118
119 /*
120 * Find an entry in the Zip archive, by name. Returns NULL if the entry
121 * was not found.
122 */
123 ZipEntry dexZipFindEntry(const ZipArchive* pArchive,
124 const char* entryName);
125
126 /*
127 * Retrieve one or more of the "interesting" fields. Non-NULL pointers
128 * are filled in.
129 *
130 * Returns 0 on success.
131 */
132 int dexZipGetEntryInfo(const ZipArchive* pArchive, ZipEntry entry,
133 int* pMethod, size_t* pUncompLen, size_t* pCompLen, off_t* pOffset,
134 long* pModWhen, long* pCrc32);
135
136 /*
137 * Simple accessors.
138 */
dexGetZipEntryOffset(const ZipArchive * pArchive,const ZipEntry entry)139 DEX_INLINE long dexGetZipEntryOffset(const ZipArchive* pArchive,
140 const ZipEntry entry)
141 {
142 off_t val = 0;
143 dexZipGetEntryInfo(pArchive, entry, NULL, NULL, NULL, &val, NULL, NULL);
144 return (long) val;
145 }
dexGetZipEntryUncompLen(const ZipArchive * pArchive,const ZipEntry entry)146 DEX_INLINE size_t dexGetZipEntryUncompLen(const ZipArchive* pArchive,
147 const ZipEntry entry)
148 {
149 size_t val = 0;
150 dexZipGetEntryInfo(pArchive, entry, NULL, &val, NULL, NULL, NULL, NULL);
151 return val;
152 }
dexGetZipEntryModTime(const ZipArchive * pArchive,const ZipEntry entry)153 DEX_INLINE long dexGetZipEntryModTime(const ZipArchive* pArchive,
154 const ZipEntry entry)
155 {
156 long val = 0;
157 dexZipGetEntryInfo(pArchive, entry, NULL, NULL, NULL, NULL, &val, NULL);
158 return val;
159 }
dexGetZipEntryCrc32(const ZipArchive * pArchive,const ZipEntry entry)160 DEX_INLINE long dexGetZipEntryCrc32(const ZipArchive* pArchive,
161 const ZipEntry entry)
162 {
163 long val = 0;
164 dexZipGetEntryInfo(pArchive, entry, NULL, NULL, NULL, NULL, NULL, &val);
165 return val;
166 }
167
168 /*
169 * Uncompress and write an entry to a file descriptor.
170 *
171 * Returns 0 on success.
172 */
173 int dexZipExtractEntryToFile(const ZipArchive* pArchive,
174 const ZipEntry entry, int fd);
175
176 /*
177 * Utility function to compute a CRC-32.
178 */
179 u4 dexInitCrc32(void);
180 u4 dexComputeCrc32(u4 crc, const void* buf, size_t len);
181
182 #endif /*_LIBDEX_ZIPARCHIVE*/
183