/* * 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_H_ #define LIBDEX_ZIPARCHIVE_H_ #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. */ struct ZipHashEntry { const char* name; unsigned short nameLen; }; /* * 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. */ 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; }; /* 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_H_