/*
* 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_