* commit '336bf2fb497fece49a874da2ca2e11572446d1d1': Reimplement ZipFileRO in terms of libziparchive.
This commit is contained in:
@ -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);
|
||||
}
|
||||
|
@ -95,8 +95,7 @@ private:
|
||||
EGLDisplay mSurface;
|
||||
sp<SurfaceControl> mFlingerSurfaceControl;
|
||||
sp<Surface> mFlingerSurface;
|
||||
bool mAndroidAnimation;
|
||||
ZipFileRO mZip;
|
||||
ZipFileRO *mZip;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
* 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.
|
||||
* "open" and "find entry by name" are fast operations and use as little
|
||||
* memory as possible.
|
||||
*
|
||||
* 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;
|
||||
|
||||
|
||||
/*
|
||||
* Start iterating over the list of entries in the zip file. Requires
|
||||
* a matching call to endIteration with the same cookie.
|
||||
*/
|
||||
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 #of entries in the Zip archive.
|
||||
*/
|
||||
int getNumEntries(void) const {
|
||||
return mNumEntries;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.]
|
||||
*/
|
||||
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);
|
||||
ZipFileRO(ZipArchiveHandle handle, char* fileName) : mHandle(handle),
|
||||
mFileName(fileName)
|
||||
{
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -33,115 +33,13 @@
|
||||
|
||||
using namespace android;
|
||||
|
||||
/*
|
||||
* 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
|
||||
* "buf" must hold at least "uncompressedLen" bytes.
|
||||
*/
|
||||
/*static*/ bool ZipUtils::inflateToBuffer(int fd, 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 = 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);
|
||||
goto z_bail;
|
||||
}
|
||||
|
||||
compRemaining -= getSize;
|
||||
|
||||
zstream.next_in = readBuf;
|
||||
zstream.avail_in = getSize;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* output buffer holds all, so no need to write the output */
|
||||
} while (zerr == Z_OK);
|
||||
|
||||
assert(zerr == Z_STREAM_END); /* other errors should've been caught */
|
||||
|
||||
if ((long) zstream.total_out != uncompressedLen) {
|
||||
ALOGW("Size mismatch on inflated file (%ld vs %ld)\n",
|
||||
zstream.total_out, uncompressedLen);
|
||||
goto z_bail;
|
||||
}
|
||||
|
||||
// success!
|
||||
result = true;
|
||||
|
||||
z_bail:
|
||||
inflateEnd(&zstream); /* free up any allocated structures */
|
||||
|
||||
bail:
|
||||
delete[] readBuf;
|
||||
return result;
|
||||
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.
|
||||
@ -153,12 +51,11 @@ bail:
|
||||
* "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,
|
||||
/*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;
|
||||
@ -166,15 +63,12 @@ bail:
|
||||
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;
|
||||
@ -184,10 +78,10 @@ bail:
|
||||
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) {
|
||||
@ -212,17 +106,18 @@ bail:
|
||||
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);
|
||||
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 */
|
||||
@ -250,10 +145,100 @@ z_bail:
|
||||
inflateEnd(&zstream); /* free up any allocated structures */
|
||||
|
||||
bail:
|
||||
delete[] readBuf;
|
||||
return result;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
long read(unsigned char** nextBuffer, long readSize) {
|
||||
if (!mBufferReturned) {
|
||||
mBufferReturned = true;
|
||||
*nextBuffer = mInput;
|
||||
return mInputSize;
|
||||
}
|
||||
|
||||
*nextBuffer = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char* mInput;
|
||||
const size_t mInputSize;
|
||||
bool mBufferReturned;
|
||||
};
|
||||
|
||||
/*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf,
|
||||
long uncompressedLen, long compressedLen)
|
||||
{
|
||||
FileReader reader(fp);
|
||||
return ::inflateToBuffer<FileReader>(reader, buf,
|
||||
uncompressedLen, compressedLen);
|
||||
}
|
||||
|
||||
/*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf,
|
||||
long uncompressedLen, long compressedLen)
|
||||
{
|
||||
FdReader reader(fd);
|
||||
return ::inflateToBuffer<FdReader>(reader, buf,
|
||||
uncompressedLen, compressedLen);
|
||||
}
|
||||
|
||||
/*static*/ bool ZipUtils::inflateToBuffer(void* in, void* buf,
|
||||
long uncompressedLen, long compressedLen)
|
||||
{
|
||||
BufferReader reader(in, compressedLen);
|
||||
return ::inflateToBuffer<BufferReader>(reader, buf,
|
||||
uncompressedLen, compressedLen);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Look at the contents of a gzip archive. We want to know where the
|
||||
* data starts, and how long it will be after it is uncompressed.
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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 \
|
||||
|
@ -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.";
|
@ -50,7 +50,8 @@ LOCAL_STATIC_LIBRARIES := \
|
||||
libcutils \
|
||||
libexpat \
|
||||
libpng \
|
||||
liblog
|
||||
liblog \
|
||||
libziparchive-host
|
||||
|
||||
ifeq ($(HOST_OS),linux)
|
||||
LOCAL_LDLIBS += -lrt -ldl -lpthread
|
||||
|
Reference in New Issue
Block a user