summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNarayan Kamath <narayan@google.com>2013-12-03 13:16:03 +0000
committerNarayan Kamath <narayan@google.com>2013-12-09 16:23:16 +0000
commitafd31e08299008fdc5c2813f21b2573f29dc53df (patch)
tree7f83dd8f1e7ed71d4fe8ce280841e43ce275ac6d
parent6e2d0c1d91f644ab50e0c0b7cae4306262a4ca41 (diff)
downloadframeworks_base-afd31e08299008fdc5c2813f21b2573f29dc53df.zip
frameworks_base-afd31e08299008fdc5c2813f21b2573f29dc53df.tar.gz
frameworks_base-afd31e08299008fdc5c2813f21b2573f29dc53df.tar.bz2
Reimplement ZipFileRO in terms of libziparchive.
This lets us share zip archive processing code with both the runtime (Art, dalvik) and critical java code (StrictJarFile). This change also moves several utility methods to ZipUtils and dedups code across several zip inflation methods. One of the side effects of this change is that several processing loops are now O(n) instead of O(n^2). bug: 10193060 Change-Id: I3c7188496837a47246c4f342e45485a70fef3169
-rw-r--r--cmds/bootanimation/BootAnimation.cpp98
-rw-r--r--cmds/bootanimation/BootAnimation.h3
-rw-r--r--core/jni/com_android_internal_content_NativeLibraryHelper.cpp32
-rw-r--r--include/androidfw/ZipFileRO.h172
-rw-r--r--include/androidfw/ZipUtils.h18
-rw-r--r--libs/androidfw/Android.mk6
-rw-r--r--libs/androidfw/Asset.cpp4
-rw-r--r--libs/androidfw/AssetManager.cpp44
-rw-r--r--libs/androidfw/ZipFileRO.cpp954
-rw-r--r--libs/androidfw/ZipUtils.cpp233
-rw-r--r--libs/androidfw/tests/Android.mk2
-rw-r--r--libs/androidfw/tests/ZipUtils_test.cpp (renamed from libs/androidfw/tests/ZipFileRO_test.cpp)10
-rw-r--r--tools/aapt/Android.mk3
13 files changed, 386 insertions, 1193 deletions
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 0f610e9..7b4e6ee 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -63,14 +63,19 @@ extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
namespace android {
+static const int ANIM_ENTRY_NAME_MAX = 256;
+
// ---------------------------------------------------------------------------
-BootAnimation::BootAnimation() : Thread(false)
+BootAnimation::BootAnimation() : Thread(false), mZip(NULL)
{
mSession = new SurfaceComposerClient();
}
BootAnimation::~BootAnimation() {
+ if (mZip != NULL) {
+ delete mZip;
+ }
}
void BootAnimation::onFirstRef() {
@@ -86,7 +91,7 @@ sp<SurfaceComposerClient> BootAnimation::session() const {
}
-void BootAnimation::binderDied(const wp<IBinder>& who)
+void BootAnimation::binderDied(const wp<IBinder>&)
{
// woah, surfaceflinger died!
ALOGD("SurfaceFlinger died, exiting...");
@@ -268,8 +273,6 @@ status_t BootAnimation::readyToRun() {
mFlingerSurfaceControl = control;
mFlingerSurface = s;
- mAndroidAnimation = true;
-
// If the device has encryption turned on or is in process
// of being encrypted we show the encrypted boot animation.
char decrypt[PROPERTY_VALUE_MAX];
@@ -277,16 +280,17 @@ status_t BootAnimation::readyToRun() {
bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);
+ ZipFileRO* zipFile = NULL;
if ((encryptedAnimation &&
(access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&
- (mZip.open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE) == NO_ERROR)) ||
+ ((zipFile = ZipFileRO::open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE)) != NULL)) ||
((access(USER_BOOTANIMATION_FILE, R_OK) == 0) &&
- (mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR)) ||
+ ((zipFile = ZipFileRO::open(USER_BOOTANIMATION_FILE)) != NULL)) ||
((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
- (mZip.open(SYSTEM_BOOTANIMATION_FILE) == NO_ERROR))) {
- mAndroidAnimation = false;
+ ((zipFile = ZipFileRO::open(SYSTEM_BOOTANIMATION_FILE)) != NULL))) {
+ mZip = zipFile;
}
return NO_ERROR;
@@ -295,7 +299,9 @@ status_t BootAnimation::readyToRun() {
bool BootAnimation::threadLoop()
{
bool r;
- if (mAndroidAnimation) {
+ // We have no bootanimation file, so we use the stock android logo
+ // animation.
+ if (mZip == NULL) {
r = android();
} else {
r = movie();
@@ -392,11 +398,14 @@ void BootAnimation::checkExit() {
bool BootAnimation::movie()
{
- ZipFileRO& zip(mZip);
+ ZipEntryRO desc = mZip->findEntryByName("desc.txt");
+ ALOGE_IF(!desc, "couldn't find desc.txt");
+ if (!desc) {
+ return false;
+ }
- size_t numEntries = zip.getNumEntries();
- ZipEntryRO desc = zip.findEntryByName("desc.txt");
- FileMap* descMap = zip.createEntryFileMap(desc);
+ FileMap* descMap = mZip->createEntryFileMap(desc);
+ mZip->releaseEntry(desc);
ALOGE_IF(!descMap, "descMap is null");
if (!descMap) {
return false;
@@ -415,7 +424,7 @@ bool BootAnimation::movie()
String8 line(s, endl - s);
const char* l = line.string();
int fps, width, height, count, pause;
- char path[256];
+ char path[ANIM_ENTRY_NAME_MAX];
char pathType;
if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {
//LOGD("> w=%d, h=%d, fps=%d", width, height, fps);
@@ -438,28 +447,37 @@ bool BootAnimation::movie()
// read all the data structures
const size_t pcount = animation.parts.size();
- for (size_t i=0 ; i<numEntries ; i++) {
- char name[256];
- ZipEntryRO entry = zip.findEntryByIndex(i);
- if (zip.getEntryFileName(entry, name, 256) == 0) {
- const String8 entryName(name);
- const String8 path(entryName.getPathDir());
- const String8 leaf(entryName.getPathLeaf());
- if (leaf.size() > 0) {
- for (int j=0 ; j<pcount ; j++) {
- if (path == animation.parts[j].path) {
- int method;
- // supports only stored png files
- if (zip.getEntryInfo(entry, &method, 0, 0, 0, 0, 0)) {
- if (method == ZipFileRO::kCompressStored) {
- FileMap* map = zip.createEntryFileMap(entry);
- if (map) {
- Animation::Frame frame;
- frame.name = leaf;
- frame.map = map;
- Animation::Part& part(animation.parts.editItemAt(j));
- part.frames.add(frame);
- }
+ void *cookie = NULL;
+ if (!mZip->startIteration(&cookie)) {
+ return false;
+ }
+
+ ZipEntryRO entry;
+ char name[ANIM_ENTRY_NAME_MAX];
+ while ((entry = mZip->nextEntry(cookie)) != NULL) {
+ const int foundEntryName = mZip->getEntryFileName(entry, name, ANIM_ENTRY_NAME_MAX);
+ if (foundEntryName > ANIM_ENTRY_NAME_MAX || foundEntryName == -1) {
+ ALOGE("Error fetching entry file name");
+ continue;
+ }
+
+ const String8 entryName(name);
+ const String8 path(entryName.getPathDir());
+ const String8 leaf(entryName.getPathLeaf());
+ if (leaf.size() > 0) {
+ for (size_t j=0 ; j<pcount ; j++) {
+ if (path == animation.parts[j].path) {
+ int method;
+ // supports only stored png files
+ if (mZip->getEntryInfo(entry, &method, NULL, NULL, NULL, NULL, NULL)) {
+ if (method == ZipFileRO::kCompressStored) {
+ FileMap* map = mZip->createEntryFileMap(entry);
+ if (map) {
+ Animation::Frame frame;
+ frame.name = leaf;
+ frame.map = map;
+ Animation::Part& part(animation.parts.editItemAt(j));
+ part.frames.add(frame);
}
}
}
@@ -468,6 +486,8 @@ bool BootAnimation::movie()
}
}
+ mZip->endIteration(cookie);
+
// clear screen
glShadeModel(GL_FLAT);
glDisable(GL_DITHER);
@@ -494,7 +514,7 @@ bool BootAnimation::movie()
Region clearReg(Rect(mWidth, mHeight));
clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height));
- for (int i=0 ; i<pcount ; i++) {
+ for (size_t i=0 ; i<pcount ; i++) {
const Animation::Part& part(animation.parts[i]);
const size_t fcount = part.frames.size();
glBindTexture(GL_TEXTURE_2D, 0);
@@ -504,7 +524,7 @@ bool BootAnimation::movie()
if(exitPending() && !part.playUntilComplete)
break;
- for (int j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
+ for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
const Animation::Frame& frame(part.frames[j]);
nsecs_t lastFrame = systemTime();
@@ -564,7 +584,7 @@ bool BootAnimation::movie()
// free the textures for this part
if (part.count != 1) {
- for (int j=0 ; j<fcount ; j++) {
+ for (size_t j=0 ; j<fcount ; j++) {
const Animation::Frame& frame(part.frames[j]);
glDeleteTextures(1, &frame.tid);
}
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index fa908eb..22963c2 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -95,8 +95,7 @@ private:
EGLDisplay mSurface;
sp<SurfaceControl> mFlingerSurfaceControl;
sp<Surface> mFlingerSurface;
- bool mAndroidAnimation;
- ZipFileRO mZip;
+ ZipFileRO *mZip;
};
// ---------------------------------------------------------------------------
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index bf5accd..00da0f7 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -21,7 +21,9 @@
#include <utils/Log.h>
#include <androidfw/ZipFileRO.h>
+#include <androidfw/ZipUtils.h>
#include <ScopedUtfChars.h>
+#include <UniquePtr.h>
#include <zlib.h>
@@ -143,7 +145,7 @@ isFileDifferent(const char* filePath, size_t fileSize, time_t modifiedTime,
}
static install_status_t
-sumFiles(JNIEnv* env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char* fileName)
+sumFiles(JNIEnv*, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char*)
{
size_t* total = (size_t*) arg;
size_t uncompLen;
@@ -178,7 +180,7 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr
return INSTALL_FAILED_INVALID_APK;
} else {
struct tm t;
- ZipFileRO::zipTimeToTimespec(when, &t);
+ ZipUtils::zipTimeToTimespec(when, &t);
modTime = mktime(&t);
}
@@ -273,26 +275,25 @@ iterateOverNativeFiles(JNIEnv *env, jstring javaFilePath, jstring javaCpuAbi, js
ScopedUtfChars cpuAbi(env, javaCpuAbi);
ScopedUtfChars cpuAbi2(env, javaCpuAbi2);
- ZipFileRO zipFile;
-
- if (zipFile.open(filePath.c_str()) != NO_ERROR) {
+ UniquePtr<ZipFileRO> zipFile(ZipFileRO::open(filePath.c_str()));
+ if (zipFile.get() == NULL) {
ALOGI("Couldn't open APK %s\n", filePath.c_str());
return INSTALL_FAILED_INVALID_APK;
}
- const int N = zipFile.getNumEntries();
-
char fileName[PATH_MAX];
bool hasPrimaryAbi = false;
- for (int i = 0; i < N; i++) {
- const ZipEntryRO entry = zipFile.findEntryByIndex(i);
- if (entry == NULL) {
- continue;
- }
+ void* cookie = NULL;
+ if (!zipFile->startIteration(&cookie)) {
+ ALOGI("Couldn't iterate over APK%s\n", filePath.c_str());
+ return INSTALL_FAILED_INVALID_APK;
+ }
+ ZipEntryRO entry = NULL;
+ while ((entry = zipFile->nextEntry(cookie)) != NULL) {
// Make sure this entry has a filename.
- if (zipFile.getEntryFileName(entry, fileName, sizeof(fileName))) {
+ if (zipFile->getEntryFileName(entry, fileName, sizeof(fileName))) {
continue;
}
@@ -346,15 +347,18 @@ iterateOverNativeFiles(JNIEnv *env, jstring javaFilePath, jstring javaCpuAbi, js
&& isFilenameSafe(lastSlash + 1))
|| !strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) {
- install_status_t ret = callFunc(env, callArg, &zipFile, entry, lastSlash + 1);
+ install_status_t ret = callFunc(env, callArg, zipFile.get(), entry, lastSlash + 1);
if (ret != INSTALL_SUCCEEDED) {
ALOGV("Failure for entry %s", lastSlash + 1);
+ zipFile->endIteration(cookie);
return ret;
}
}
}
+ zipFile->endIteration(cookie);
+
return INSTALL_SUCCEEDED;
}
diff --git a/include/androidfw/ZipFileRO.h b/include/androidfw/ZipFileRO.h
index 547e36a..ad5be12 100644
--- a/include/androidfw/ZipFileRO.h
+++ b/include/androidfw/ZipFileRO.h
@@ -40,6 +40,8 @@
#include <unistd.h>
#include <time.h>
+typedef void* ZipArchiveHandle;
+
namespace android {
/*
@@ -51,18 +53,13 @@ typedef void* ZipEntryRO;
/*
* Open a Zip archive for reading.
*
- * 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 file,
- * 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).
+ * Implemented as a thin wrapper over system/core/libziparchive.
+ *
+ * "open" and "find entry by name" are fast operations and use as little
+ * memory as possible.
*
- * 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.
+ * We also support fast iteration over all entries in the file (with a
+ * stable, but unspecified iteration order).
*
* NOTE: If this is used on file descriptors inherited from a fork() operation,
* you must be on a platform that implements pread() to guarantee correctness
@@ -70,48 +67,44 @@ typedef void* ZipEntryRO;
*/
class ZipFileRO {
public:
- ZipFileRO()
- : mFd(-1), mFileName(NULL), mFileLength(-1),
- mDirectoryMap(NULL),
- mNumEntries(-1), mDirectoryOffset(-1),
- mHashTableSize(-1), mHashTable(NULL)
- {}
-
- ~ZipFileRO();
+ /* Zip compression methods we support */
+ enum {
+ kCompressStored = 0, // no compression
+ kCompressDeflated = 8, // standard deflate
+ };
/*
* Open an archive.
*/
- status_t open(const char* zipFileName);
+ static ZipFileRO* open(const char* zipFileName);
/*
* Find an entry, by name. Returns the entry identifier, or NULL if
* not found.
- *
- * If two entries have the same name, one will be chosen at semi-random.
*/
- ZipEntryRO findEntryByName(const char* fileName) const;
+ ZipEntryRO findEntryByName(const char* entryName) const;
+
/*
- * Return the #of entries in the Zip archive.
+ * Start iterating over the list of entries in the zip file. Requires
+ * a matching call to endIteration with the same cookie.
*/
- int getNumEntries(void) const {
- return mNumEntries;
- }
+ bool startIteration(void** cookie);
+
+ /**
+ * Return the next entry in iteration order, or NULL if there are no more
+ * entries in this archive.
+ */
+ ZipEntryRO nextEntry(void* cookie);
+
+ void endIteration(void* cookie);
+
+ void releaseEntry(ZipEntryRO entry) const;
/*
- * Return the Nth entry. Zip file entries are not stored in sorted
- * order, and updated entries may appear at the end, so anyone walking
- * the archive needs to avoid making ordering assumptions. We take
- * that further by returning the Nth non-empty entry in the hash table
- * rather than the Nth entry in the archive.
- *
- * Valid values are [0..numEntries).
- *
- * [This is currently O(n). If it needs to be fast we can allocate an
- * additional data structure or provide an iterator interface.]
+ * Return the #of entries in the Zip archive.
*/
- ZipEntryRO findEntryByIndex(int idx) const;
+ int getNumEntries();
/*
* Copy the filename into the supplied buffer. Returns 0 on success,
@@ -149,112 +142,27 @@ public:
*
* Returns "true" on success.
*/
- bool uncompressEntry(ZipEntryRO entry, void* buffer) const;
+ bool uncompressEntry(ZipEntryRO entry, void* buffer, size_t size) const;
/*
* Uncompress the data to an open file descriptor.
*/
bool uncompressEntry(ZipEntryRO entry, int fd) const;
- /* Zip compression methods we support */
- enum {
- kCompressStored = 0, // no compression
- kCompressDeflated = 8, // standard deflate
- };
-
- /*
- * Utility function: uncompress deflated data, buffer to buffer.
- */
- static bool inflateBuffer(void* outBuf, const void* inBuf,
- size_t uncompLen, size_t compLen);
-
- /*
- * Utility function: uncompress deflated data, buffer to fd.
- */
- static bool inflateBuffer(int fd, const void* inBuf,
- size_t uncompLen, size_t compLen);
-
- /*
- * Utility function to convert ZIP's time format to a timespec struct.
- */
- static inline void zipTimeToTimespec(long when, struct tm* timespec) {
- const long date = when >> 16;
- timespec->tm_year = ((date >> 9) & 0x7F) + 80; // Zip is years since 1980
- timespec->tm_mon = (date >> 5) & 0x0F;
- timespec->tm_mday = date & 0x1F;
-
- timespec->tm_hour = (when >> 11) & 0x1F;
- timespec->tm_min = (when >> 5) & 0x3F;
- timespec->tm_sec = (when & 0x1F) << 1;
- }
-
- /*
- * Some basic functions for raw data manipulation. "LE" means
- * Little Endian.
- */
- static inline unsigned short get2LE(const unsigned char* buf) {
- return buf[0] | (buf[1] << 8);
- }
- static inline unsigned long get4LE(const unsigned char* buf) {
- return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
- }
+ ~ZipFileRO();
private:
- /* these are private and not defined */
+ /* these are private and not defined */
ZipFileRO(const ZipFileRO& src);
ZipFileRO& operator=(const ZipFileRO& src);
- /* locate and parse the central directory */
- bool mapCentralDirectory(void);
-
- /* parse the archive, prepping internal structures */
- bool parseZipArchive(void);
-
- /* add a new entry to the hash table */
- void addToHash(const char* str, int strLen, unsigned int hash);
-
- /* compute string hash code */
- static unsigned int computeHash(const char* str, int len);
-
- /* convert a ZipEntryRO back to a hash table index */
- int entryToIndex(const ZipEntryRO entry) const;
-
- /*
- * One entry in the hash table.
- */
- typedef struct HashEntry {
- const char* name;
- unsigned short nameLen;
- //unsigned int hash;
- } HashEntry;
-
- /* open Zip archive */
- int mFd;
-
- /* Lock for handling the file descriptor (seeks, etc) */
- mutable Mutex mFdLock;
-
- /* zip file name */
- char* mFileName;
-
- /* length of file */
- size_t mFileLength;
-
- /* mapped file */
- FileMap* mDirectoryMap;
-
- /* number of entries in the Zip archive */
- int mNumEntries;
-
- /* CD directory offset in the Zip archive */
- off64_t mDirectoryOffset;
+ ZipFileRO(ZipArchiveHandle handle, char* fileName) : mHandle(handle),
+ mFileName(fileName)
+ {
+ }
- /*
- * We know how many entries are in the Zip archive, so we have a
- * fixed-size hash table. We probe for an empty slot.
- */
- int mHashTableSize;
- HashEntry* mHashTable;
+ const ZipArchiveHandle mHandle;
+ char* mFileName;
};
}; // namespace android
diff --git a/include/androidfw/ZipUtils.h b/include/androidfw/ZipUtils.h
index 42c42b6..6bea25a 100644
--- a/include/androidfw/ZipUtils.h
+++ b/include/androidfw/ZipUtils.h
@@ -21,6 +21,7 @@
#define __LIBS_ZIPUTILS_H
#include <stdio.h>
+#include <time.h>
namespace android {
@@ -33,9 +34,11 @@ public:
* General utility function for uncompressing "deflate" data from a file
* to a buffer.
*/
+ static bool inflateToBuffer(FILE* fp, void* buf, long uncompressedLen,
+ long compressedLen);
static bool inflateToBuffer(int fd, void* buf, long uncompressedLen,
long compressedLen);
- static bool inflateToBuffer(FILE* fp, void* buf, long uncompressedLen,
+ static bool inflateToBuffer(void *in, void* buf, long uncompressedLen,
long compressedLen);
/*
@@ -57,6 +60,19 @@ public:
static bool examineGzip(FILE* fp, int* pCompressionMethod,
long* pUncompressedLen, long* pCompressedLen, unsigned long* pCRC32);
+ /*
+ * Utility function to convert ZIP's time format to a timespec struct.
+ */
+ static inline void zipTimeToTimespec(long when, struct tm* timespec) {
+ const long date = when >> 16;
+ timespec->tm_year = ((date >> 9) & 0x7F) + 80; // Zip is years since 1980
+ timespec->tm_mon = (date >> 5) & 0x0F;
+ timespec->tm_mday = date & 0x1F;
+
+ timespec->tm_hour = (when >> 11) & 0x1F;
+ timespec->tm_min = (when >> 5) & 0x3F;
+ timespec->tm_sec = (when & 0x1F) << 1;
+ }
private:
ZipUtils() {}
~ZipUtils() {}
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index d80612b..ba13d51 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -54,6 +54,7 @@ LOCAL_C_INCLUDES := \
external/zlib
LOCAL_STATIC_LIBRARIES := liblog
+LOCAL_WHOLE_STATIC_LIBRARIES := libziparchive-host
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -72,9 +73,12 @@ LOCAL_SHARED_LIBRARIES := \
libutils \
libz
+LOCAL_STATIC_LIBRARIES := libziparchive
+
LOCAL_C_INCLUDES := \
external/icu4c/common \
- external/zlib
+ external/zlib \
+ system/core/include
LOCAL_MODULE:= libandroidfw
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
index cb7628d..ce6cc38 100644
--- a/libs/androidfw/Asset.cpp
+++ b/libs/androidfw/Asset.cpp
@@ -843,7 +843,7 @@ void _CompressedAsset::close(void)
* The first time this is called, we expand the compressed data into a
* buffer.
*/
-const void* _CompressedAsset::getBuffer(bool wordAligned)
+const void* _CompressedAsset::getBuffer(bool)
{
unsigned char* buf = NULL;
@@ -860,7 +860,7 @@ const void* _CompressedAsset::getBuffer(bool wordAligned)
}
if (mMap != NULL) {
- if (!ZipFileRO::inflateBuffer(buf, mMap->getDataPtr(),
+ if (!ZipUtils::inflateToBuffer(mMap->getDataPtr(), buf,
mUncompressedLen, mCompressedLen))
goto bail;
} else {
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 1066715..503c030 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -305,10 +305,11 @@ bool AssetManager::getZipEntryCrcLocked(const String8& zipPath, const char* entr
if (entry == NULL) {
return false;
}
- if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, (long*)pCrc)) {
- return false;
- }
- return true;
+
+ const bool gotInfo = zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, (long*)pCrc);
+ zip->releaseEntry(entry);
+
+ return gotInfo;
}
bool AssetManager::createIdmapFileLocked(const String8& originalPath, const String8& overlayPath,
@@ -821,16 +822,14 @@ Asset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode m
String8 path(fileName);
/* check the appropriate Zip file */
- ZipFileRO* pZip;
- ZipEntryRO entry;
-
- pZip = getZipFileLocked(ap);
+ ZipFileRO* pZip = getZipFileLocked(ap);
if (pZip != NULL) {
//printf("GOT zip, checking NA '%s'\n", (const char*) path);
- entry = pZip->findEntryByName(path.string());
+ ZipEntryRO entry = pZip->findEntryByName(path.string());
if (entry != NULL) {
//printf("FOUND NA in Zip file for %s\n", appName ? appName : kAppCommon);
pAsset = openAssetFromZipLocked(pZip, entry, mode, path);
+ pZip->releaseEntry(entry);
}
}
@@ -975,17 +974,15 @@ Asset* AssetManager::openInLocaleVendorLocked(const char* fileName, AccessMode m
path.appendPath(fileName);
/* check the appropriate Zip file */
- ZipFileRO* pZip;
- ZipEntryRO entry;
-
- pZip = getZipFileLocked(ap);
+ ZipFileRO* pZip = getZipFileLocked(ap);
if (pZip != NULL) {
//printf("GOT zip, checking '%s'\n", (const char*) path);
- entry = pZip->findEntryByName(path.string());
+ ZipEntryRO entry = pZip->findEntryByName(path.string());
if (entry != NULL) {
//printf("FOUND in Zip file for %s/%s-%s\n",
// appName, locale, vendor);
pAsset = openAssetFromZipLocked(pZip, entry, mode, path);
+ pZip->releaseEntry(entry);
}
}
@@ -1487,11 +1484,16 @@ bool AssetManager::scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMerg
* semantics.
*/
int dirNameLen = dirName.length();
- for (int i = 0; i < pZip->getNumEntries(); i++) {
- ZipEntryRO entry;
+ void *iterationCookie;
+ if (!pZip->startIteration(&iterationCookie)) {
+ ALOGW("ZipFileRO::startIteration returned false");
+ return false;
+ }
+
+ ZipEntryRO entry;
+ while ((entry = pZip->nextEntry(iterationCookie)) != NULL) {
char nameBuf[256];
- entry = pZip->findEntryByIndex(i);
if (pZip->getEntryFileName(entry, nameBuf, sizeof(nameBuf)) != 0) {
// TODO: fix this if we expect to have long names
ALOGE("ARGH: name too long?\n");
@@ -1541,6 +1543,8 @@ bool AssetManager::scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMerg
}
}
+ pZip->endIteration(iterationCookie);
+
/*
* Add the set of unique directories.
*/
@@ -1814,12 +1818,10 @@ AssetManager::SharedZip::SharedZip(const String8& path, time_t modWhen)
mResourceTableAsset(NULL), mResourceTable(NULL)
{
//ALOGI("Creating SharedZip %p %s\n", this, (const char*)mPath);
- mZipFile = new ZipFileRO;
ALOGV("+++ opening zip '%s'\n", mPath.string());
- if (mZipFile->open(mPath.string()) != NO_ERROR) {
+ mZipFile = ZipFileRO::open(mPath.string());
+ if (mZipFile == NULL) {
ALOGD("failed to open Zip archive '%s'\n", mPath.string());
- delete mZipFile;
- mZipFile = NULL;
}
}
diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp
index ec5f95c..1ab18ad 100644
--- a/libs/androidfw/ZipFileRO.cpp
+++ b/libs/androidfw/ZipFileRO.cpp
@@ -24,6 +24,7 @@
#include <utils/Compat.h>
#include <utils/misc.h>
#include <utils/threads.h>
+#include <ziparchive/zip_archive.h>
#include <zlib.h>
@@ -43,619 +44,127 @@
using namespace android;
-/*
- * Zip file constants.
- */
-#define kEOCDSignature 0x06054b50
-#define kEOCDLen 22
-#define kEOCDDiskNumber 4 // number of the current disk
-#define kEOCDDiskNumberForCD 6 // disk number with the Central Directory
-#define kEOCDNumEntries 8 // offset to #of entries in file
-#define kEOCDTotalNumEntries 10 // offset to total #of entries in spanned archives
-#define kEOCDSize 12 // size of the central directory
-#define kEOCDFileOffset 16 // offset to central directory
-#define kEOCDCommentSize 20 // offset to the length of the file comment
-
-#define kMaxCommentLen 65535 // longest possible in ushort
-#define kMaxEOCDSearch (kMaxCommentLen + kEOCDLen)
-
-#define kLFHSignature 0x04034b50
-#define kLFHLen 30 // excluding variable-len fields
-#define kLFHGPBFlags 6 // offset to GPB flags
-#define kLFHNameLen 26 // offset to filename length
-#define kLFHExtraLen 28 // offset to extra length
-
-#define kCDESignature 0x02014b50
-#define kCDELen 46 // excluding variable-len fields
-#define kCDEGPBFlags 8 // offset to GPB flags
-#define kCDEMethod 10 // offset to compression method
-#define kCDEModWhen 12 // offset to modification timestamp
-#define kCDECRC 16 // offset to entry CRC
-#define kCDECompLen 20 // offset to compressed length
-#define kCDEUncompLen 24 // offset to uncompressed length
-#define kCDENameLen 28 // offset to filename length
-#define kCDEExtraLen 30 // offset to extra length
-#define kCDECommentLen 32 // offset to comment length
-#define kCDELocalOffset 42 // offset to local hdr
-
-/* General Purpose Bit Flag */
-#define kGPFEncryptedFlag (1 << 0)
-#define kGPFUnsupportedMask (kGPFEncryptedFlag)
+class _ZipEntryRO {
+public:
+ ZipEntry entry;
+ ZipEntryName name;
+ void *cookie;
-/*
- * The values we return for ZipEntryRO use 0 as an invalid value, so we
- * want to adjust the hash table index by a fixed amount. Using a large
- * value helps insure that people don't mix & match arguments, e.g. to
- * findEntryByIndex().
- */
-#define kZipEntryAdj 10000
+ _ZipEntryRO() : cookie(NULL) {
+ }
-ZipFileRO::~ZipFileRO() {
- free(mHashTable);
- if (mDirectoryMap)
- mDirectoryMap->release();
- if (mFd >= 0)
- TEMP_FAILURE_RETRY(close(mFd));
- if (mFileName)
- free(mFileName);
-}
+private:
+ _ZipEntryRO(const _ZipEntryRO& other);
+ _ZipEntryRO& operator=(const _ZipEntryRO& other);
+};
-/*
- * Convert a ZipEntryRO to a hash table index, verifying that it's in a
- * valid range.
- */
-int ZipFileRO::entryToIndex(const ZipEntryRO entry) const
-{
- long ent = ((intptr_t) entry) - kZipEntryAdj;
- if (ent < 0 || ent >= mHashTableSize || mHashTable[ent].name == NULL) {
- ALOGW("Invalid ZipEntryRO %p (%ld)\n", entry, ent);
- return -1;
- }
- return ent;
+ZipFileRO::~ZipFileRO() {
+ CloseArchive(mHandle);
+ free(mFileName);
}
-
/*
* Open the specified file read-only. We memory-map the entire thing and
* close the file before returning.
*/
-status_t ZipFileRO::open(const char* zipFileName)
+/* static */ ZipFileRO* ZipFileRO::open(const char* zipFileName)
{
- int fd = -1;
-
- assert(mDirectoryMap == NULL);
-
- /*
- * Open and map the specified file.
- */
- fd = TEMP_FAILURE_RETRY(::open(zipFileName, O_RDONLY | O_BINARY));
- if (fd < 0) {
- ALOGW("Unable to open zip '%s': %s\n", zipFileName, strerror(errno));
- return NAME_NOT_FOUND;
- }
-
- mFileLength = lseek64(fd, 0, SEEK_END);
- if (mFileLength < kEOCDLen) {
- TEMP_FAILURE_RETRY(close(fd));
- return UNKNOWN_ERROR;
- }
-
- if (mFileName != NULL) {
- free(mFileName);
+ ZipArchiveHandle handle;
+ const int32_t error = OpenArchive(zipFileName, &handle);
+ if (error) {
+ ALOGW("Error opening archive %s: %s", zipFileName, ErrorCodeString(error));
+ return NULL;
}
- mFileName = strdup(zipFileName);
- mFd = fd;
+ return new ZipFileRO(handle, strdup(zipFileName));
+}
- /*
- * Find the Central Directory and store its size and number of entries.
- */
- if (!mapCentralDirectory()) {
- goto bail;
- }
- /*
- * Verify Central Directory and create data structures for fast access.
- */
- if (!parseZipArchive()) {
- goto bail;
+ZipEntryRO ZipFileRO::findEntryByName(const char* entryName) const
+{
+ _ZipEntryRO* data = new _ZipEntryRO;
+ const int32_t error = FindEntry(mHandle, entryName, &(data->entry));
+ if (error) {
+ delete data;
+ return NULL;
}
- return OK;
+ data->name.name = entryName;
+ data->name.name_length = strlen(entryName);
-bail:
- free(mFileName);
- mFileName = NULL;
- TEMP_FAILURE_RETRY(close(fd));
- return UNKNOWN_ERROR;
+ return (ZipEntryRO) data;
}
/*
- * Parse the Zip archive, verifying its contents and initializing internal
- * data structures.
+ * Get the useful fields from the zip entry.
+ *
+ * Returns "false" if the offsets to the fields or the contents of the fields
+ * appear to be bogus.
*/
-bool ZipFileRO::mapCentralDirectory(void)
+bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen,
+ size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const
{
- ssize_t readAmount = kMaxEOCDSearch;
- if (readAmount > (ssize_t) mFileLength)
- readAmount = mFileLength;
-
- if (readAmount < kEOCDSize) {
- ALOGW("File too short to be a zip file");
- return false;
- }
-
- unsigned char* scanBuf = (unsigned char*) malloc(readAmount);
- if (scanBuf == NULL) {
- ALOGW("couldn't allocate scanBuf: %s", strerror(errno));
- free(scanBuf);
- return false;
- }
-
- /*
- * Make sure this is a Zip archive.
- */
- if (lseek64(mFd, 0, SEEK_SET) != 0) {
- ALOGW("seek to start failed: %s", strerror(errno));
- free(scanBuf);
- return false;
- }
-
- ssize_t actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, sizeof(int32_t)));
- if (actual != (ssize_t) sizeof(int32_t)) {
- ALOGI("couldn't read first signature from zip archive: %s", strerror(errno));
- free(scanBuf);
- return false;
- }
-
- unsigned int header = get4LE(scanBuf);
- if (header != kLFHSignature) {
- ALOGV("Not a Zip archive (found 0x%08x)\n", header);
- free(scanBuf);
- return false;
- }
+ const _ZipEntryRO* zipEntry = reinterpret_cast<_ZipEntryRO*>(entry);
+ const ZipEntry& ze = zipEntry->entry;
- /*
- * Perform the traditional EOCD snipe hunt.
- *
- * We're searching for the End of Central Directory magic number,
- * which appears at the start of the EOCD block. It's followed by
- * 18 bytes of EOCD stuff and up to 64KB of archive comment. We
- * need to read the last part of the file into a buffer, dig through
- * it to find the magic number, parse some values out, and use those
- * to determine the extent of the CD.
- *
- * We start by pulling in the last part of the file.
- */
- off64_t searchStart = mFileLength - readAmount;
-
- if (lseek64(mFd, searchStart, SEEK_SET) != searchStart) {
- ALOGW("seek %ld failed: %s\n", (long) searchStart, strerror(errno));
- free(scanBuf);
- return false;
- }
- actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, readAmount));
- if (actual != (ssize_t) readAmount) {
- ALOGW("Zip: read " ZD ", expected " ZD ". Failed: %s\n",
- (ZD_TYPE) actual, (ZD_TYPE) readAmount, strerror(errno));
- free(scanBuf);
- return false;
- }
-
- /*
- * Scan backward for the EOCD magic. In an archive without a trailing
- * comment, we'll find it on the first try. (We may want to consider
- * doing an initial minimal read; if we don't find it, retry with a
- * second read as above.)
- */
- int i;
- for (i = readAmount - kEOCDLen; i >= 0; i--) {
- if (scanBuf[i] == 0x50 && get4LE(&scanBuf[i]) == kEOCDSignature) {
- ALOGV("+++ Found EOCD at buf+%d\n", i);
- break;
- }
+ if (pMethod != NULL) {
+ *pMethod = ze.method;
}
- if (i < 0) {
- ALOGD("Zip: EOCD not found, %s is not zip\n", mFileName);
- free(scanBuf);
- return false;
+ if (pUncompLen != NULL) {
+ *pUncompLen = ze.uncompressed_length;
}
-
- off64_t eocdOffset = searchStart + i;
- const unsigned char* eocdPtr = scanBuf + i;
-
- assert(eocdOffset < mFileLength);
-
- /*
- * Grab the CD offset and size, and the number of entries in the
- * archive. After that, we can release our EOCD hunt buffer.
- */
- unsigned int diskNumber = get2LE(eocdPtr + kEOCDDiskNumber);
- unsigned int diskWithCentralDir = get2LE(eocdPtr + kEOCDDiskNumberForCD);
- unsigned int numEntries = get2LE(eocdPtr + kEOCDNumEntries);
- unsigned int totalNumEntries = get2LE(eocdPtr + kEOCDTotalNumEntries);
- unsigned int centralDirSize = get4LE(eocdPtr + kEOCDSize);
- unsigned int centralDirOffset = get4LE(eocdPtr + kEOCDFileOffset);
- unsigned int commentSize = get2LE(eocdPtr + kEOCDCommentSize);
- free(scanBuf);
-
- // Verify that they look reasonable.
- if ((long long) centralDirOffset + (long long) centralDirSize > (long long) eocdOffset) {
- ALOGW("bad offsets (dir %ld, size %u, eocd %ld)\n",
- (long) centralDirOffset, centralDirSize, (long) eocdOffset);
- return false;
+ if (pCompLen != NULL) {
+ *pCompLen = ze.compressed_length;
}
- if (numEntries == 0) {
- ALOGW("empty archive?\n");
- return false;
- } else if (numEntries != totalNumEntries || diskNumber != 0 || diskWithCentralDir != 0) {
- ALOGW("spanned archives not supported");
- return false;
- }
-
- // Check to see if comment is a sane size
- if ((commentSize > (mFileLength - kEOCDLen))
- || (eocdOffset > (mFileLength - kEOCDLen) - commentSize)) {
- ALOGW("comment size runs off end of file");
- return false;
+ if (pOffset != NULL) {
+ *pOffset = ze.offset;
}
-
- ALOGV("+++ numEntries=%d dirSize=%d dirOffset=%d\n",
- numEntries, centralDirSize, centralDirOffset);
-
- mDirectoryMap = new FileMap();
- if (mDirectoryMap == NULL) {
- ALOGW("Unable to create directory map: %s", strerror(errno));
- return false;
+ if (pModWhen != NULL) {
+ *pModWhen = ze.mod_time;
}
-
- if (!mDirectoryMap->create(mFileName, mFd, centralDirOffset, centralDirSize, true)) {
- ALOGW("Unable to map '%s' (" ZD " to " ZD "): %s\n", mFileName,
- (ZD_TYPE) centralDirOffset, (ZD_TYPE) (centralDirOffset + centralDirSize), strerror(errno));
- return false;
+ if (pCrc32 != NULL) {
+ *pCrc32 = ze.crc32;
}
- mNumEntries = numEntries;
- mDirectoryOffset = centralDirOffset;
-
return true;
}
-
-/*
- * Round up to the next highest power of 2.
- *
- * Found on http://graphics.stanford.edu/~seander/bithacks.html.
- */
-static unsigned int roundUpPower2(unsigned int val)
+bool ZipFileRO::startIteration(void** cookie)
{
- val--;
- val |= val >> 1;
- val |= val >> 2;
- val |= val >> 4;
- val |= val >> 8;
- val |= val >> 16;
- val++;
-
- return val;
-}
-
-bool ZipFileRO::parseZipArchive(void)
-{
- bool result = false;
- const unsigned char* cdPtr = (const unsigned char*) mDirectoryMap->getDataPtr();
- size_t cdLength = mDirectoryMap->getDataLength();
- int numEntries = mNumEntries;
-
- /*
- * Create hash table. We have a minimum 75% load factor, possibly as
- * low as 50% after we round off to a power of 2.
- */
- mHashTableSize = roundUpPower2(1 + (numEntries * 4) / 3);
- mHashTable = (HashEntry*) calloc(mHashTableSize, sizeof(HashEntry));
-
- /*
- * Walk through the central directory, adding entries to the hash
- * table.
- */
- const unsigned char* ptr = cdPtr;
- for (int i = 0; i < numEntries; i++) {
- if (get4LE(ptr) != kCDESignature) {
- ALOGW("Missed a central dir sig (at %d)\n", i);
- goto bail;
- }
- if (ptr + kCDELen > cdPtr + cdLength) {
- ALOGW("Ran off the end (at %d)\n", i);
- goto bail;
- }
-
- long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset);
- if (localHdrOffset >= mDirectoryOffset) {
- ALOGW("bad LFH offset %ld at entry %d\n", localHdrOffset, i);
- goto bail;
- }
-
- unsigned int gpbf = get2LE(ptr + kCDEGPBFlags);
- if ((gpbf & kGPFUnsupportedMask) != 0) {
- ALOGW("Invalid General Purpose Bit Flag: %d", gpbf);
- goto bail;
- }
-
- unsigned int nameLen = get2LE(ptr + kCDENameLen);
- unsigned int extraLen = get2LE(ptr + kCDEExtraLen);
- unsigned int commentLen = get2LE(ptr + kCDECommentLen);
-
- const char *name = (const char *) ptr + kCDELen;
-
- /* Check name for NULL characters */
- if (memchr(name, 0, nameLen) != NULL) {
- ALOGW("Filename contains NUL byte");
- goto bail;
- }
-
- /* add the CDE filename to the hash table */
- unsigned int hash = computeHash(name, nameLen);
- addToHash(name, nameLen, hash);
-
- /* We don't care about the comment or extra data. */
- ptr += kCDELen + nameLen + extraLen + commentLen;
- if ((size_t)(ptr - cdPtr) > cdLength) {
- ALOGW("bad CD advance (%d vs " ZD ") at entry %d\n",
- (int) (ptr - cdPtr), (ZD_TYPE) cdLength, i);
- goto bail;
- }
+ _ZipEntryRO* ze = new _ZipEntryRO;
+ int32_t error = StartIteration(mHandle, &(ze->cookie), NULL /* prefix */);
+ if (error) {
+ ALOGW("Could not start iteration over %s: %s", mFileName, ErrorCodeString(error));
+ delete ze;
+ return false;
}
- ALOGV("+++ zip good scan %d entries\n", numEntries);
- result = true;
-
-bail:
- return result;
-}
-
-/*
- * Simple string hash function for non-null-terminated strings.
- */
-/*static*/ unsigned int ZipFileRO::computeHash(const char* str, int len)
-{
- unsigned int hash = 0;
- while (len--)
- hash = hash * 31 + *str++;
-
- return hash;
+ *cookie = ze;
+ return true;
}
-/*
- * Add a new entry to the hash table.
- */
-void ZipFileRO::addToHash(const char* str, int strLen, unsigned int hash)
+ZipEntryRO ZipFileRO::nextEntry(void* cookie)
{
- int ent = hash & (mHashTableSize-1);
-
- /*
- * We over-allocate the table, so we're guaranteed to find an empty slot.
- */
- while (mHashTable[ent].name != NULL)
- ent = (ent + 1) & (mHashTableSize-1);
-
- mHashTable[ent].name = str;
- mHashTable[ent].nameLen = strLen;
-}
-
-/*
- * Find a matching entry.
- *
- * Returns NULL if not found.
- */
-ZipEntryRO ZipFileRO::findEntryByName(const char* fileName) const
-{
- /*
- * If the ZipFileRO instance is not initialized, the entry number will
- * end up being garbage since mHashTableSize is -1.
- */
- if (mHashTableSize <= 0) {
- return NULL;
- }
-
- int nameLen = strlen(fileName);
- unsigned int hash = computeHash(fileName, nameLen);
- int ent = hash & (mHashTableSize-1);
-
- while (mHashTable[ent].name != NULL) {
- if (mHashTable[ent].nameLen == nameLen &&
- memcmp(mHashTable[ent].name, fileName, nameLen) == 0)
- {
- /* match */
- return (ZipEntryRO)(long)(ent + kZipEntryAdj);
+ _ZipEntryRO* ze = reinterpret_cast<_ZipEntryRO*>(cookie);
+ int32_t error = Next(ze->cookie, &(ze->entry), &(ze->name));
+ if (error) {
+ if (error != -1) {
+ ALOGW("Error iteration over %s: %s", mFileName, ErrorCodeString(error));
}
-
- ent = (ent + 1) & (mHashTableSize-1);
+ return NULL;
}
- return NULL;
+ return &(ze->entry);
}
-/*
- * Find the Nth entry.
- *
- * This currently involves walking through the sparse hash table, counting
- * non-empty entries. If we need to speed this up we can either allocate
- * a parallel lookup table or (perhaps better) provide an iterator interface.
- */
-ZipEntryRO ZipFileRO::findEntryByIndex(int idx) const
+void ZipFileRO::endIteration(void* cookie)
{
- if (idx < 0 || idx >= mNumEntries) {
- ALOGW("Invalid index %d\n", idx);
- return NULL;
- }
-
- for (int ent = 0; ent < mHashTableSize; ent++) {
- if (mHashTable[ent].name != NULL) {
- if (idx-- == 0)
- return (ZipEntryRO) (intptr_t)(ent + kZipEntryAdj);
- }
- }
-
- return NULL;
+ delete reinterpret_cast<_ZipEntryRO*>(cookie);
}
-/*
- * Get the useful fields from the zip entry.
- *
- * Returns "false" if the offsets to the fields or the contents of the fields
- * appear to be bogus.
- */
-bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen,
- size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const
+void ZipFileRO::releaseEntry(ZipEntryRO entry) const
{
- bool ret = false;
-
- const int ent = entryToIndex(entry);
- if (ent < 0) {
- ALOGW("cannot find entry");
- return false;
- }
-
- HashEntry hashEntry = mHashTable[ent];
-
- /*
- * Recover the start of the central directory entry from the filename
- * pointer. The filename is the first entry past the fixed-size data,
- * so we can just subtract back from that.
- */
- const unsigned char* ptr = (const unsigned char*) hashEntry.name;
- off64_t cdOffset = mDirectoryOffset;
-
- ptr -= kCDELen;
-
- int method = get2LE(ptr + kCDEMethod);
- if (pMethod != NULL)
- *pMethod = method;
-
- if (pModWhen != NULL)
- *pModWhen = get4LE(ptr + kCDEModWhen);
- if (pCrc32 != NULL)
- *pCrc32 = get4LE(ptr + kCDECRC);
-
- size_t compLen = get4LE(ptr + kCDECompLen);
- if (pCompLen != NULL)
- *pCompLen = compLen;
- size_t uncompLen = get4LE(ptr + kCDEUncompLen);
- if (pUncompLen != NULL)
- *pUncompLen = uncompLen;
-
- /*
- * If requested, determine the offset of the start of the data. All we
- * have is the offset to the Local File Header, which is variable size,
- * so we have to read the contents of the struct to figure out where
- * the actual data starts.
- *
- * We also need to make sure that the lengths are not so large that
- * somebody trying to map the compressed or uncompressed data runs
- * off the end of the mapped region.
- *
- * Note we don't verify compLen/uncompLen if they don't request the
- * dataOffset, because dataOffset is expensive to determine. However,
- * if they don't have the file offset, they're not likely to be doing
- * anything with the contents.
- */
- if (pOffset != NULL) {
- long localHdrOffset = get4LE(ptr + kCDELocalOffset);
- if (localHdrOffset + kLFHLen >= cdOffset) {
- ALOGE("ERROR: bad local hdr offset in zip\n");
- return false;
- }
-
- unsigned char lfhBuf[kLFHLen];
-
-#ifdef HAVE_PREAD
- /*
- * This file descriptor might be from zygote's preloaded assets,
- * so we need to do an pread64() instead of a lseek64() + read() to
- * guarantee atomicity across the processes with the shared file
- * descriptors.
- */
- ssize_t actual =
- TEMP_FAILURE_RETRY(pread64(mFd, lfhBuf, sizeof(lfhBuf), localHdrOffset));
-
- if (actual != sizeof(lfhBuf)) {
- ALOGW("failed reading lfh from offset %ld\n", localHdrOffset);
- return false;
- }
-
- if (get4LE(lfhBuf) != kLFHSignature) {
- ALOGW("didn't find signature at start of lfh; wanted: offset=%ld data=0x%08x; "
- "got: data=0x%08lx\n",
- localHdrOffset, kLFHSignature, get4LE(lfhBuf));
- return false;
- }
-#else /* HAVE_PREAD */
- /*
- * For hosts don't have pread64() we cannot guarantee atomic reads from
- * an offset in a file. Android should never run on those platforms.
- * File descriptors inherited from a fork() share file offsets and
- * there would be nothing to protect from two different processes
- * calling lseek64() concurrently.
- */
-
- {
- AutoMutex _l(mFdLock);
-
- if (lseek64(mFd, localHdrOffset, SEEK_SET) != localHdrOffset) {
- ALOGW("failed seeking to lfh at offset %ld\n", localHdrOffset);
- return false;
- }
-
- ssize_t actual =
- TEMP_FAILURE_RETRY(read(mFd, lfhBuf, sizeof(lfhBuf)));
- if (actual != sizeof(lfhBuf)) {
- ALOGW("failed reading lfh from offset %ld\n", localHdrOffset);
- return false;
- }
-
- if (get4LE(lfhBuf) != kLFHSignature) {
- off64_t actualOffset = lseek64(mFd, 0, SEEK_CUR);
- ALOGW("didn't find signature at start of lfh; wanted: offset=%ld data=0x%08x; "
- "got: offset=" ZD " data=0x%08lx\n",
- localHdrOffset, kLFHSignature, (ZD_TYPE) actualOffset, get4LE(lfhBuf));
- return false;
- }
- }
-#endif /* HAVE_PREAD */
-
- unsigned int gpbf = get2LE(lfhBuf + kLFHGPBFlags);
- if ((gpbf & kGPFUnsupportedMask) != 0) {
- ALOGW("Invalid General Purpose Bit Flag: %d", gpbf);
- return false;
- }
-
- off64_t dataOffset = localHdrOffset + kLFHLen
- + get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen);
- if (dataOffset >= cdOffset) {
- ALOGW("bad data offset %ld in zip\n", (long) dataOffset);
- return false;
- }
-
- /* check lengths */
- if ((dataOffset >= cdOffset) || (compLen > (cdOffset - dataOffset))) {
- ALOGW("bad compressed length in zip (%ld + " ZD " > %ld)\n",
- (long) dataOffset, (ZD_TYPE) compLen, (long) cdOffset);
- return false;
- }
-
- if (method == kCompressStored &&
- ((dataOffset >= cdOffset) ||
- (uncompLen > (cdOffset - dataOffset))))
- {
- ALOGE("ERROR: bad uncompressed length in zip (%ld + " ZD " > %ld)\n",
- (long) dataOffset, (ZD_TYPE) uncompLen, (long) cdOffset);
- return false;
- }
-
- *pOffset = dataOffset;
- }
-
- return true;
+ delete reinterpret_cast<_ZipEntryRO*>(entry);
}
/*
@@ -664,16 +173,17 @@ bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen,
int ZipFileRO::getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen)
const
{
- int ent = entryToIndex(entry);
- if (ent < 0)
- return -1;
+ const _ZipEntryRO* zipEntry = reinterpret_cast<_ZipEntryRO*>(entry);
+ const uint16_t requiredSize = zipEntry->name.name_length + 1;
- int nameLen = mHashTable[ent].nameLen;
- if (bufLen < nameLen+1)
- return nameLen+1;
+ if (bufLen < requiredSize) {
+ ALOGW("Buffer too short, requires %d bytes for entry name", requiredSize);
+ return requiredSize;
+ }
+
+ memcpy(buffer, zipEntry->name.name, requiredSize - 1);
+ buffer[requiredSize - 1] = '\0';
- memcpy(buffer, mHashTable[ent].name, nameLen);
- buffer[nameLen] = '\0';
return 0;
}
@@ -682,32 +192,19 @@ int ZipFileRO::getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen)
*/
FileMap* ZipFileRO::createEntryFileMap(ZipEntryRO entry) const
{
- /*
- * TODO: the efficient way to do this is to modify FileMap to allow
- * sub-regions of a file to be mapped. A reference-counting scheme
- * can manage the base memory mapping. For now, we just create a brand
- * new mapping off of the Zip archive file descriptor.
- */
-
- FileMap* newMap;
- int method;
- size_t uncompLen;
- size_t compLen;
- off64_t offset;
-
- if (!getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL)) {
- return NULL;
- }
+ const _ZipEntryRO *zipEntry = reinterpret_cast<_ZipEntryRO*>(entry);
+ const ZipEntry& ze = zipEntry->entry;
+ int fd = GetFileDescriptor(mHandle);
+ size_t actualLen = 0;
- size_t actualLen;
- if (method == kCompressStored) {
- actualLen = uncompLen;
+ if (ze.method == kCompressStored) {
+ actualLen = ze.uncompressed_length;
} else {
- actualLen = compLen;
+ actualLen = ze.compressed_length;
}
- newMap = new FileMap();
- if (!newMap->create(mFileName, mFd, offset, actualLen, true)) {
+ FileMap* newMap = new FileMap();
+ if (!newMap->create(mFileName, fd, ze.offset, actualLen, true)) {
newMap->release();
return NULL;
}
@@ -721,64 +218,17 @@ FileMap* ZipFileRO::createEntryFileMap(ZipEntryRO entry) const
* This doesn't verify the data's CRC, which might be useful for
* uncompressed data. The caller should be able to manage it.
*/
-bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer) const
+bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer, size_t size) const
{
- const size_t kSequentialMin = 32768;
- bool result = false;
- int ent = entryToIndex(entry);
- if (ent < 0) {
+ _ZipEntryRO *zipEntry = reinterpret_cast<_ZipEntryRO*>(entry);
+ const int32_t error = ExtractToMemory(mHandle, &(zipEntry->entry),
+ (uint8_t*) buffer, size);
+ if (error) {
+ ALOGW("ExtractToMemory failed with %s", ErrorCodeString(error));
return false;
}
- int method;
- size_t uncompLen, compLen;
- off64_t offset;
- const unsigned char* ptr;
- FileMap *file;
-
- if (!getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL)) {
- goto bail;
- }
-
- file = createEntryFileMap(entry);
- if (file == NULL) {
- goto bail;
- }
-
- ptr = (const unsigned char*) file->getDataPtr();
-
- /*
- * Experiment with madvise hint. When we want to uncompress a file,
- * we pull some stuff out of the central dir entry and then hit a
- * bunch of compressed or uncompressed data sequentially. The CDE
- * visit will cause a limited amount of read-ahead because it's at
- * the end of the file. We could end up doing lots of extra disk
- * access if the file we're prying open is small. Bottom line is we
- * probably don't want to turn MADV_SEQUENTIAL on and leave it on.
- *
- * So, if the compressed size of the file is above a certain minimum
- * size, temporarily boost the read-ahead in the hope that the extra
- * pair of system calls are negated by a reduction in page faults.
- */
- if (compLen > kSequentialMin)
- file->advise(FileMap::SEQUENTIAL);
-
- if (method == kCompressStored) {
- memcpy(buffer, ptr, uncompLen);
- } else {
- if (!inflateBuffer(buffer, ptr, uncompLen, compLen))
- goto unmap;
- }
-
- if (compLen > kSequentialMin)
- file->advise(FileMap::NORMAL);
-
- result = true;
-
-unmap:
- file->release();
-bail:
- return result;
+ return true;
}
/*
@@ -788,208 +238,12 @@ bail:
*/
bool ZipFileRO::uncompressEntry(ZipEntryRO entry, int fd) const
{
- bool result = false;
- int ent = entryToIndex(entry);
- if (ent < 0) {
+ _ZipEntryRO *zipEntry = reinterpret_cast<_ZipEntryRO*>(entry);
+ const int32_t error = ExtractEntryToFile(mHandle, &(zipEntry->entry), fd);
+ if (error) {
+ ALOGW("ExtractToMemory failed with %s", ErrorCodeString(error));
return false;
}
- int method;
- size_t uncompLen, compLen;
- off64_t offset;
- const unsigned char* ptr;
- FileMap *file;
-
- if (!getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL)) {
- goto bail;
- }
-
- file = createEntryFileMap(entry);
- if (file == NULL) {
- goto bail;
- }
-
- ptr = (const unsigned char*) file->getDataPtr();
-
- if (method == kCompressStored) {
- ssize_t actual = TEMP_FAILURE_RETRY(write(fd, ptr, uncompLen));
- if (actual < 0) {
- ALOGE("Write failed: %s\n", strerror(errno));
- goto unmap;
- } else if ((size_t) actual != uncompLen) {
- ALOGE("Partial write during uncompress (" ZD " of " ZD ")\n",
- (ZD_TYPE) actual, (ZD_TYPE) uncompLen);
- goto unmap;
- } else {
- ALOGI("+++ successful write\n");
- }
- } else {
- if (!inflateBuffer(fd, ptr, uncompLen, compLen)) {
- goto unmap;
- }
- }
-
- result = true;
-
-unmap:
- file->release();
-bail:
- return result;
-}
-
-/*
- * Uncompress "deflate" data from one buffer to another.
- */
-/*static*/ bool ZipFileRO::inflateBuffer(void* outBuf, const void* inBuf,
- size_t uncompLen, size_t compLen)
-{
- bool result = false;
- z_stream zstream;
- int zerr;
-
- /*
- * Initialize the zlib stream struct.
- */
- memset(&zstream, 0, sizeof(zstream));
- zstream.zalloc = Z_NULL;
- zstream.zfree = Z_NULL;
- zstream.opaque = Z_NULL;
- zstream.next_in = (Bytef*)inBuf;
- zstream.avail_in = compLen;
- zstream.next_out = (Bytef*) outBuf;
- zstream.avail_out = uncompLen;
- zstream.data_type = Z_UNKNOWN;
-
- /*
- * Use the undocumented "negative window bits" feature to tell zlib
- * that there's no zlib header waiting for it.
- */
- zerr = inflateInit2(&zstream, -MAX_WBITS);
- if (zerr != Z_OK) {
- if (zerr == Z_VERSION_ERROR) {
- ALOGE("Installed zlib is not compatible with linked version (%s)\n",
- ZLIB_VERSION);
- } else {
- ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
- }
- goto bail;
- }
-
- /*
- * Expand data.
- */
- zerr = inflate(&zstream, Z_FINISH);
- if (zerr != Z_STREAM_END) {
- ALOGW("Zip inflate failed, zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)\n",
- zerr, zstream.next_in, zstream.avail_in,
- zstream.next_out, zstream.avail_out);
- goto z_bail;
- }
-
- /* paranoia */
- if (zstream.total_out != uncompLen) {
- ALOGW("Size mismatch on inflated file (%ld vs " ZD ")\n",
- zstream.total_out, (ZD_TYPE) uncompLen);
- goto z_bail;
- }
-
- result = true;
-
-z_bail:
- inflateEnd(&zstream); /* free up any allocated structures */
-
-bail:
- return result;
-}
-
-/*
- * Uncompress "deflate" data from one buffer to an open file descriptor.
- */
-/*static*/ bool ZipFileRO::inflateBuffer(int fd, const void* inBuf,
- size_t uncompLen, size_t compLen)
-{
- bool result = false;
- const size_t kWriteBufSize = 32768;
- unsigned char writeBuf[kWriteBufSize];
- z_stream zstream;
- int zerr;
-
- /*
- * Initialize the zlib stream struct.
- */
- memset(&zstream, 0, sizeof(zstream));
- zstream.zalloc = Z_NULL;
- zstream.zfree = Z_NULL;
- zstream.opaque = Z_NULL;
- zstream.next_in = (Bytef*)inBuf;
- zstream.avail_in = compLen;
- zstream.next_out = (Bytef*) writeBuf;
- zstream.avail_out = sizeof(writeBuf);
- zstream.data_type = Z_UNKNOWN;
-
- /*
- * Use the undocumented "negative window bits" feature to tell zlib
- * that there's no zlib header waiting for it.
- */
- zerr = inflateInit2(&zstream, -MAX_WBITS);
- if (zerr != Z_OK) {
- if (zerr == Z_VERSION_ERROR) {
- ALOGE("Installed zlib is not compatible with linked version (%s)\n",
- ZLIB_VERSION);
- } else {
- ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
- }
- goto bail;
- }
-
- /*
- * Loop while we have more to do.
- */
- do {
- /*
- * Expand data.
- */
- zerr = inflate(&zstream, Z_NO_FLUSH);
- if (zerr != Z_OK && zerr != Z_STREAM_END) {
- ALOGW("zlib inflate: zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)\n",
- zerr, zstream.next_in, zstream.avail_in,
- zstream.next_out, zstream.avail_out);
- goto z_bail;
- }
-
- /* write when we're full or when we're done */
- if (zstream.avail_out == 0 ||
- (zerr == Z_STREAM_END && zstream.avail_out != sizeof(writeBuf)))
- {
- long writeSize = zstream.next_out - writeBuf;
- int cc = TEMP_FAILURE_RETRY(write(fd, writeBuf, writeSize));
- if (cc < 0) {
- ALOGW("write failed in inflate: %s", strerror(errno));
- goto z_bail;
- } else if (cc != (int) writeSize) {
- ALOGW("write failed in inflate (%d vs %ld)", cc, writeSize);
- goto z_bail;
- }
-
- zstream.next_out = writeBuf;
- zstream.avail_out = sizeof(writeBuf);
- }
- } while (zerr == Z_OK);
-
- assert(zerr == Z_STREAM_END); /* other errors should've been caught */
-
- /* paranoia */
- if (zstream.total_out != uncompLen) {
- ALOGW("Size mismatch on inflated file (%ld vs " ZD ")\n",
- zstream.total_out, (ZD_TYPE) uncompLen);
- goto z_bail;
- }
-
- result = true;
-
-z_bail:
- inflateEnd(&zstream); /* free up any allocated structures */
-
-bail:
- return result;
+ return true;
}
diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp
index 997eb7d..e9ac2fe 100644
--- a/libs/androidfw/ZipUtils.cpp
+++ b/libs/androidfw/ZipUtils.cpp
@@ -33,19 +33,29 @@
using namespace android;
+static inline unsigned long get4LE(const unsigned char* buf) {
+ return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+}
+
+
+static const unsigned long kReadBufSize = 32768;
+
/*
* Utility function that expands zip/gzip "deflate" compressed data
* into a buffer.
*
- * "fd" is an open file positioned at the start of the "deflate" data
+ * (This is a clone of the previous function, but it takes a FILE* instead
+ * of an fd. We could pass fileno(fd) to the above, but we can run into
+ * trouble when "fp" has a different notion of what fd's file position is.)
+ *
+ * "fp" is an open file positioned at the start of the "deflate" data
* "buf" must hold at least "uncompressedLen" bytes.
*/
-/*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf,
+/*static*/ template<typename T> bool inflateToBuffer(T& reader, void* buf,
long uncompressedLen, long compressedLen)
{
bool result = false;
- const unsigned long kReadBufSize = 32768;
- unsigned char* readBuf = NULL;
+
z_stream zstream;
int zerr;
unsigned long compRemaining;
@@ -53,15 +63,12 @@ using namespace android;
assert(uncompressedLen >= 0);
assert(compressedLen >= 0);
- readBuf = new unsigned char[kReadBufSize];
- if (readBuf == NULL)
- goto bail;
compRemaining = compressedLen;
/*
* Initialize the zlib stream.
*/
- memset(&zstream, 0, sizeof(zstream));
+ memset(&zstream, 0, sizeof(zstream));
zstream.zalloc = Z_NULL;
zstream.zfree = Z_NULL;
zstream.opaque = Z_NULL;
@@ -71,10 +78,10 @@ using namespace android;
zstream.avail_out = uncompressedLen;
zstream.data_type = Z_UNKNOWN;
- /*
- * Use the undocumented "negative window bits" feature to tell zlib
- * that there's no zlib header waiting for it.
- */
+ /*
+ * Use the undocumented "negative window bits" feature to tell zlib
+ * that there's no zlib header waiting for it.
+ */
zerr = inflateInit2(&zstream, -MAX_WBITS);
if (zerr != Z_OK) {
if (zerr == Z_VERSION_ERROR) {
@@ -99,18 +106,18 @@ using namespace android;
ALOGV("+++ reading %ld bytes (%ld left)\n",
getSize, compRemaining);
- int cc = TEMP_FAILURE_RETRY(read(fd, readBuf, getSize));
- if (cc < 0) {
- ALOGW("inflate read failed: %s", strerror(errno));
- } else if (cc != (int) getSize) {
- ALOGW("inflate read failed (%d vs %ld)", cc, getSize);
+ unsigned char* nextBuffer = NULL;
+ const unsigned long nextSize = reader.read(&nextBuffer, getSize);
+
+ if (nextSize < getSize || nextBuffer == NULL) {
+ ALOGD("inflate read failed (%ld vs %ld)\n", nextSize, getSize);
goto z_bail;
}
- compRemaining -= getSize;
+ compRemaining -= nextSize;
- zstream.next_in = readBuf;
- zstream.avail_in = getSize;
+ zstream.next_in = nextBuffer;
+ zstream.avail_in = nextSize;
}
/* uncompress the data */
@@ -138,121 +145,99 @@ z_bail:
inflateEnd(&zstream); /* free up any allocated structures */
bail:
- delete[] readBuf;
return result;
}
-/*
- * Utility function that expands zip/gzip "deflate" compressed data
- * into a buffer.
- *
- * (This is a clone of the previous function, but it takes a FILE* instead
- * of an fd. We could pass fileno(fd) to the above, but we can run into
- * trouble when "fp" has a different notion of what fd's file position is.)
- *
- * "fp" is an open file positioned at the start of the "deflate" data
- * "buf" must hold at least "uncompressedLen" bytes.
- */
-/*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf,
- long uncompressedLen, long compressedLen)
-{
- bool result = false;
- const unsigned long kReadBufSize = 32768;
- unsigned char* readBuf = NULL;
- z_stream zstream;
- int zerr;
- unsigned long compRemaining;
-
- assert(uncompressedLen >= 0);
- assert(compressedLen >= 0);
-
- readBuf = new unsigned char[kReadBufSize];
- if (readBuf == NULL)
- goto bail;
- compRemaining = compressedLen;
-
- /*
- * Initialize the zlib stream.
- */
- memset(&zstream, 0, sizeof(zstream));
- zstream.zalloc = Z_NULL;
- zstream.zfree = Z_NULL;
- zstream.opaque = Z_NULL;
- zstream.next_in = NULL;
- zstream.avail_in = 0;
- zstream.next_out = (Bytef*) buf;
- zstream.avail_out = uncompressedLen;
- zstream.data_type = Z_UNKNOWN;
-
- /*
- * Use the undocumented "negative window bits" feature to tell zlib
- * that there's no zlib header waiting for it.
- */
- zerr = inflateInit2(&zstream, -MAX_WBITS);
- if (zerr != Z_OK) {
- if (zerr == Z_VERSION_ERROR) {
- ALOGE("Installed zlib is not compatible with linked version (%s)\n",
- ZLIB_VERSION);
- } else {
- ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
- }
- goto bail;
+class FileReader {
+public:
+ FileReader(FILE* fp) :
+ mFp(fp), mReadBuf(new unsigned char[kReadBufSize])
+ {
+ }
+
+ ~FileReader() {
+ delete[] mReadBuf;
+ }
+
+ long read(unsigned char** nextBuffer, long readSize) const {
+ *nextBuffer = mReadBuf;
+ return fread(mReadBuf, 1, readSize, mFp);
+ }
+
+ FILE* mFp;
+ unsigned char* mReadBuf;
+};
+
+class FdReader {
+public:
+ FdReader(int fd) :
+ mFd(fd), mReadBuf(new unsigned char[kReadBufSize])
+ {
+ }
+
+ ~FdReader() {
+ delete[] mReadBuf;
+ }
+
+ long read(unsigned char** nextBuffer, long readSize) const {
+ *nextBuffer = mReadBuf;
+ return TEMP_FAILURE_RETRY(::read(mFd, mReadBuf, readSize));
+ }
+
+ int mFd;
+ unsigned char* mReadBuf;
+};
+
+class BufferReader {
+public:
+ BufferReader(void* input, size_t inputSize) :
+ mInput(reinterpret_cast<unsigned char*>(input)),
+ mInputSize(inputSize),
+ mBufferReturned(false)
+ {
}
- /*
- * Loop while we have data.
- */
- do {
- unsigned long getSize;
-
- /* read as much as we can */
- if (zstream.avail_in == 0) {
- getSize = (compRemaining > kReadBufSize) ?
- kReadBufSize : compRemaining;
- ALOGV("+++ reading %ld bytes (%ld left)\n",
- getSize, compRemaining);
-
- int cc = fread(readBuf, 1, getSize, fp);
- if (cc != (int) getSize) {
- ALOGD("inflate read failed (%d vs %ld)\n",
- cc, getSize);
- goto z_bail;
- }
-
- compRemaining -= getSize;
-
- zstream.next_in = readBuf;
- zstream.avail_in = getSize;
+ long read(unsigned char** nextBuffer, long readSize) {
+ if (!mBufferReturned) {
+ mBufferReturned = true;
+ *nextBuffer = mInput;
+ return mInputSize;
}
- /* uncompress the data */
- zerr = inflate(&zstream, Z_NO_FLUSH);
- if (zerr != Z_OK && zerr != Z_STREAM_END) {
- ALOGD("zlib inflate call failed (zerr=%d)\n", zerr);
- goto z_bail;
- }
+ *nextBuffer = NULL;
+ return 0;
+ }
- /* output buffer holds all, so no need to write the output */
- } while (zerr == Z_OK);
+ unsigned char* mInput;
+ const size_t mInputSize;
+ bool mBufferReturned;
+};
- assert(zerr == Z_STREAM_END); /* other errors should've been caught */
+/*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf,
+ long uncompressedLen, long compressedLen)
+{
+ FileReader reader(fp);
+ return ::inflateToBuffer<FileReader>(reader, buf,
+ uncompressedLen, compressedLen);
+}
- if ((long) zstream.total_out != uncompressedLen) {
- ALOGW("Size mismatch on inflated file (%ld vs %ld)\n",
- zstream.total_out, uncompressedLen);
- goto z_bail;
- }
+/*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf,
+ long uncompressedLen, long compressedLen)
+{
+ FdReader reader(fd);
+ return ::inflateToBuffer<FdReader>(reader, buf,
+ uncompressedLen, compressedLen);
+}
- // success!
- result = true;
+/*static*/ bool ZipUtils::inflateToBuffer(void* in, void* buf,
+ long uncompressedLen, long compressedLen)
+{
+ BufferReader reader(in, compressedLen);
+ return ::inflateToBuffer<BufferReader>(reader, buf,
+ uncompressedLen, compressedLen);
+}
-z_bail:
- inflateEnd(&zstream); /* free up any allocated structures */
-bail:
- delete[] readBuf;
- return result;
-}
/*
* Look at the contents of a gzip archive. We want to know where the
@@ -338,8 +323,8 @@ bail:
fseek(fp, curPosn, SEEK_SET);
*pCompressionMethod = method;
- *pCRC32 = ZipFileRO::get4LE(&buf[0]);
- *pUncompressedLen = ZipFileRO::get4LE(&buf[4]);
+ *pCRC32 = get4LE(&buf[0]);
+ *pUncompressedLen = get4LE(&buf[4]);
return true;
}
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index 0522212..3c55375 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -5,7 +5,7 @@ include $(CLEAR_VARS)
# Build the unit tests.
test_src_files := \
ObbFile_test.cpp \
- ZipFileRO_test.cpp
+ ZipUtils_test.cpp
shared_libraries := \
libandroidfw \
diff --git a/libs/androidfw/tests/ZipFileRO_test.cpp b/libs/androidfw/tests/ZipUtils_test.cpp
index cb9c721..c6038b5 100644
--- a/libs/androidfw/tests/ZipFileRO_test.cpp
+++ b/libs/androidfw/tests/ZipUtils_test.cpp
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-#define LOG_TAG "ZipFileRO_test"
+#define LOG_TAG "ZipUtils_test"
#include <utils/Log.h>
-#include <androidfw/ZipFileRO.h>
+#include <androidfw/ZipUtils.h>
#include <gtest/gtest.h>
@@ -25,7 +25,7 @@
namespace android {
-class ZipFileROTest : public testing::Test {
+class ZipUtilsTest : public testing::Test {
protected:
virtual void SetUp() {
}
@@ -34,13 +34,13 @@ protected:
}
};
-TEST_F(ZipFileROTest, ZipTimeConvertSuccess) {
+TEST_F(ZipUtilsTest, ZipTimeConvertSuccess) {
struct tm t;
// 2011-06-29 14:40:40
long when = 0x3EDD7514;
- ZipFileRO::zipTimeToTimespec(when, &t);
+ ZipUtils::zipTimeToTimespec(when, &t);
EXPECT_EQ(2011, t.tm_year + 1900)
<< "Year was improperly converted.";
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 452c60a..2949f8e 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -50,7 +50,8 @@ LOCAL_STATIC_LIBRARIES := \
libcutils \
libexpat \
libpng \
- liblog
+ liblog \
+ libziparchive-host
ifeq ($(HOST_OS),linux)
LOCAL_LDLIBS += -lrt -ldl -lpthread