M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
Hash.c \
SysUtil.c \
DirUtil.c \
Inlines.c \
Zip.c
LOCAL_C_INCLUDES += \
external/zlib \
external/safe-iop/include
LOCAL_MODULE := libminzip
LOCAL_CFLAGS += -Wall
include $(BUILD_STATIC_LIBRARY)
+357
View File
@@ -0,0 +1,357 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Some handy functions for manipulating bits and bytes.
*/
#ifndef _MINZIP_BITS
#define _MINZIP_BITS
#include "inline_magic.h"
#include <stdlib.h>
#include <string.h>
/*
* Get 1 byte. (Included to make the code more legible.)
*/
INLINE unsigned char get1(unsigned const char* pSrc)
{
return *pSrc;
}
/*
* Get 2 big-endian bytes.
*/
INLINE unsigned short get2BE(unsigned char const* pSrc)
{
unsigned short result;
result = *pSrc++ << 8;
result |= *pSrc++;
return result;
}
/*
* Get 4 big-endian bytes.
*/
INLINE unsigned int get4BE(unsigned char const* pSrc)
{
unsigned int result;
result = *pSrc++ << 24;
result |= *pSrc++ << 16;
result |= *pSrc++ << 8;
result |= *pSrc++;
return result;
}
/*
* Get 8 big-endian bytes.
*/
INLINE unsigned long long get8BE(unsigned char const* pSrc)
{
unsigned long long result;
result = (unsigned long long) *pSrc++ << 56;
result |= (unsigned long long) *pSrc++ << 48;
result |= (unsigned long long) *pSrc++ << 40;
result |= (unsigned long long) *pSrc++ << 32;
result |= (unsigned long long) *pSrc++ << 24;
result |= (unsigned long long) *pSrc++ << 16;
result |= (unsigned long long) *pSrc++ << 8;
result |= (unsigned long long) *pSrc++;
return result;
}
/*
* Get 2 little-endian bytes.
*/
INLINE unsigned short get2LE(unsigned char const* pSrc)
{
unsigned short result;
result = *pSrc++;
result |= *pSrc++ << 8;
return result;
}
/*
* Get 4 little-endian bytes.
*/
INLINE unsigned int get4LE(unsigned char const* pSrc)
{
unsigned int result;
result = *pSrc++;
result |= *pSrc++ << 8;
result |= *pSrc++ << 16;
result |= *pSrc++ << 24;
return result;
}
/*
* Get 8 little-endian bytes.
*/
INLINE unsigned long long get8LE(unsigned char const* pSrc)
{
unsigned long long result;
result = (unsigned long long) *pSrc++;
result |= (unsigned long long) *pSrc++ << 8;
result |= (unsigned long long) *pSrc++ << 16;
result |= (unsigned long long) *pSrc++ << 24;
result |= (unsigned long long) *pSrc++ << 32;
result |= (unsigned long long) *pSrc++ << 40;
result |= (unsigned long long) *pSrc++ << 48;
result |= (unsigned long long) *pSrc++ << 56;
return result;
}
/*
* Grab 1 byte and advance the data pointer.
*/
INLINE unsigned char read1(unsigned const char** ppSrc)
{
return *(*ppSrc)++;
}
/*
* Grab 2 big-endian bytes and advance the data pointer.
*/
INLINE unsigned short read2BE(unsigned char const** ppSrc)
{
unsigned short result;
result = *(*ppSrc)++ << 8;
result |= *(*ppSrc)++;
return result;
}
/*
* Grab 4 big-endian bytes and advance the data pointer.
*/
INLINE unsigned int read4BE(unsigned char const** ppSrc)
{
unsigned int result;
result = *(*ppSrc)++ << 24;
result |= *(*ppSrc)++ << 16;
result |= *(*ppSrc)++ << 8;
result |= *(*ppSrc)++;
return result;
}
/*
* Get 8 big-endian bytes.
*/
INLINE unsigned long long read8BE(unsigned char const** ppSrc)
{
unsigned long long result;
result = (unsigned long long) *(*ppSrc)++ << 56;
result |= (unsigned long long) *(*ppSrc)++ << 48;
result |= (unsigned long long) *(*ppSrc)++ << 40;
result |= (unsigned long long) *(*ppSrc)++ << 32;
result |= (unsigned long long) *(*ppSrc)++ << 24;
result |= (unsigned long long) *(*ppSrc)++ << 16;
result |= (unsigned long long) *(*ppSrc)++ << 8;
result |= (unsigned long long) *(*ppSrc)++;
return result;
}
/*
* Grab 2 little-endian bytes and advance the data pointer.
*/
INLINE unsigned short read2LE(unsigned char const** ppSrc)
{
unsigned short result;
result = *(*ppSrc)++;
result |= *(*ppSrc)++ << 8;
return result;
}
/*
* Grab 4 little-endian bytes and advance the data pointer.
*/
INLINE unsigned int read4LE(unsigned char const** ppSrc)
{
unsigned int result;
result = *(*ppSrc)++;
result |= *(*ppSrc)++ << 8;
result |= *(*ppSrc)++ << 16;
result |= *(*ppSrc)++ << 24;
return result;
}
/*
* Get 8 little-endian bytes.
*/
INLINE unsigned long long read8LE(unsigned char const** ppSrc)
{
unsigned long long result;
result = (unsigned long long) *(*ppSrc)++;
result |= (unsigned long long) *(*ppSrc)++ << 8;
result |= (unsigned long long) *(*ppSrc)++ << 16;
result |= (unsigned long long) *(*ppSrc)++ << 24;
result |= (unsigned long long) *(*ppSrc)++ << 32;
result |= (unsigned long long) *(*ppSrc)++ << 40;
result |= (unsigned long long) *(*ppSrc)++ << 48;
result |= (unsigned long long) *(*ppSrc)++ << 56;
return result;
}
/*
* Skip over a UTF-8 string.
*/
INLINE void skipUtf8String(unsigned char const** ppSrc)
{
unsigned int length = read4BE(ppSrc);
(*ppSrc) += length;
}
/*
* Read a UTF-8 string into a fixed-size buffer, and null-terminate it.
*
* Returns the length of the original string.
*/
INLINE int readUtf8String(unsigned char const** ppSrc, char* buf, size_t bufLen)
{
unsigned int length = read4BE(ppSrc);
size_t copyLen = (length < bufLen) ? length : bufLen-1;
memcpy(buf, *ppSrc, copyLen);
buf[copyLen] = '\0';
(*ppSrc) += length;
return length;
}
/*
* Read a UTF-8 string into newly-allocated storage, and null-terminate it.
*
* Returns the string and its length. (The latter is probably unnecessary
* for the way we're using UTF8.)
*/
INLINE char* readNewUtf8String(unsigned char const** ppSrc, size_t* pLength)
{
unsigned int length = read4BE(ppSrc);
char* buf;
buf = (char*) malloc(length+1);
memcpy(buf, *ppSrc, length);
buf[length] = '\0';
(*ppSrc) += length;
*pLength = length;
return buf;
}
/*
* Set 1 byte. (Included to make the code more legible.)
*/
INLINE void set1(unsigned char* buf, unsigned char val)
{
*buf = (unsigned char)(val);
}
/*
* Set 2 big-endian bytes.
*/
INLINE void set2BE(unsigned char* buf, unsigned short val)
{
*buf++ = (unsigned char)(val >> 8);
*buf = (unsigned char)(val);
}
/*
* Set 4 big-endian bytes.
*/
INLINE void set4BE(unsigned char* buf, unsigned int val)
{
*buf++ = (unsigned char)(val >> 24);
*buf++ = (unsigned char)(val >> 16);
*buf++ = (unsigned char)(val >> 8);
*buf = (unsigned char)(val);
}
/*
* Set 8 big-endian bytes.
*/
INLINE void set8BE(unsigned char* buf, unsigned long long val)
{
*buf++ = (unsigned char)(val >> 56);
*buf++ = (unsigned char)(val >> 48);
*buf++ = (unsigned char)(val >> 40);
*buf++ = (unsigned char)(val >> 32);
*buf++ = (unsigned char)(val >> 24);
*buf++ = (unsigned char)(val >> 16);
*buf++ = (unsigned char)(val >> 8);
*buf = (unsigned char)(val);
}
/*
* Set 2 little-endian bytes.
*/
INLINE void set2LE(unsigned char* buf, unsigned short val)
{
*buf++ = (unsigned char)(val);
*buf = (unsigned char)(val >> 8);
}
/*
* Set 4 little-endian bytes.
*/
INLINE void set4LE(unsigned char* buf, unsigned int val)
{
*buf++ = (unsigned char)(val);
*buf++ = (unsigned char)(val >> 8);
*buf++ = (unsigned char)(val >> 16);
*buf = (unsigned char)(val >> 24);
}
/*
* Set 8 little-endian bytes.
*/
INLINE void set8LE(unsigned char* buf, unsigned long long val)
{
*buf++ = (unsigned char)(val);
*buf++ = (unsigned char)(val >> 8);
*buf++ = (unsigned char)(val >> 16);
*buf++ = (unsigned char)(val >> 24);
*buf++ = (unsigned char)(val >> 32);
*buf++ = (unsigned char)(val >> 40);
*buf++ = (unsigned char)(val >> 48);
*buf = (unsigned char)(val >> 56);
}
/*
* Stuff a UTF-8 string into the buffer.
*/
INLINE void setUtf8String(unsigned char* buf, const unsigned char* str)
{
unsigned int strLen = strlen((const char*)str);
set4BE(buf, strLen);
memcpy(buf + sizeof(unsigned int), str, strLen);
}
#endif /*_MINZIP_BITS*/
+280
View File
@@ -0,0 +1,280 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#include <limits.h>
#include "DirUtil.h"
typedef enum { DMISSING, DDIR, DILLEGAL } DirStatus;
static DirStatus
getPathDirStatus(const char *path)
{
struct stat st;
int err;
err = stat(path, &st);
if (err == 0) {
/* Something's there; make sure it's a directory.
*/
if (S_ISDIR(st.st_mode)) {
return DDIR;
}
errno = ENOTDIR;
return DILLEGAL;
} else if (errno != ENOENT) {
/* Something went wrong, or something in the path
* is bad. Can't do anything in this situation.
*/
return DILLEGAL;
}
return DMISSING;
}
int
dirCreateHierarchy(const char *path, int mode,
const struct utimbuf *timestamp, bool stripFileName)
{
DirStatus ds;
/* Check for an empty string before we bother
* making any syscalls.
*/
if (path[0] == '\0') {
errno = ENOENT;
return -1;
}
/* Allocate a path that we can modify; stick a slash on
* the end to make things easier.
*/
size_t pathLen = strlen(path);
char *cpath = (char *)malloc(pathLen + 2);
if (cpath == NULL) {
errno = ENOMEM;
return -1;
}
memcpy(cpath, path, pathLen);
if (stripFileName) {
/* Strip everything after the last slash.
*/
char *c = cpath + pathLen - 1;
while (c != cpath && *c != '/') {
c--;
}
if (c == cpath) {
//xxx test this path
/* No directory component. Act like the path was empty.
*/
errno = ENOENT;
free(cpath);
return -1;
}
c[1] = '\0'; // Terminate after the slash we found.
} else {
/* Make sure that the path ends in a slash.
*/
cpath[pathLen] = '/';
cpath[pathLen + 1] = '\0';
}
/* See if it already exists.
*/
ds = getPathDirStatus(cpath);
if (ds == DDIR) {
return 0;
} else if (ds == DILLEGAL) {
return -1;
}
/* Walk up the path from the root and make each level.
* If a directory already exists, no big deal.
*/
char *p = cpath;
while (*p != '\0') {
/* Skip any slashes, watching out for the end of the string.
*/
while (*p != '\0' && *p == '/') {
p++;
}
if (*p == '\0') {
break;
}
/* Find the end of the next path component.
* We know that we'll see a slash before the NUL,
* because we added it, above.
*/
while (*p != '/') {
p++;
}
*p = '\0';
/* Check this part of the path and make a new directory
* if necessary.
*/
ds = getPathDirStatus(cpath);
if (ds == DILLEGAL) {
/* Could happen if some other process/thread is
* messing with the filesystem.
*/
free(cpath);
return -1;
} else if (ds == DMISSING) {
int err;
err = mkdir(cpath, mode);
if (err != 0) {
free(cpath);
return -1;
}
if (timestamp != NULL && utime(cpath, timestamp)) {
free(cpath);
return -1;
}
}
// else, this directory already exists.
/* Repair the path and continue.
*/
*p = '/';
}
free(cpath);
return 0;
}
int
dirUnlinkHierarchy(const char *path)
{
struct stat st;
DIR *dir;
struct dirent *de;
int fail = 0;
/* is it a file or directory? */
if (lstat(path, &st) < 0) {
return -1;
}
/* a file, so unlink it */
if (!S_ISDIR(st.st_mode)) {
return unlink(path);
}
/* a directory, so open handle */
dir = opendir(path);
if (dir == NULL) {
return -1;
}
/* recurse over components */
errno = 0;
while ((de = readdir(dir)) != NULL) {
//TODO: don't blow the stack
char dn[PATH_MAX];
if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, ".")) {
continue;
}
snprintf(dn, sizeof(dn), "%s/%s", path, de->d_name);
if (dirUnlinkHierarchy(dn) < 0) {
fail = 1;
break;
}
errno = 0;
}
/* in case readdir or unlink_recursive failed */
if (fail || errno < 0) {
int save = errno;
closedir(dir);
errno = save;
return -1;
}
/* close directory handle */
if (closedir(dir) < 0) {
return -1;
}
/* delete target directory */
return rmdir(path);
}
int
dirSetHierarchyPermissions(const char *path,
int uid, int gid, int dirMode, int fileMode)
{
struct stat st;
if (lstat(path, &st)) {
return -1;
}
/* ignore symlinks */
if (S_ISLNK(st.st_mode)) {
return 0;
}
/* directories and files get different permissions */
if (chown(path, uid, gid) ||
chmod(path, S_ISDIR(st.st_mode) ? dirMode : fileMode)) {
return -1;
}
/* recurse over directory components */
if (S_ISDIR(st.st_mode)) {
DIR *dir = opendir(path);
if (dir == NULL) {
return -1;
}
errno = 0;
const struct dirent *de;
while (errno == 0 && (de = readdir(dir)) != NULL) {
if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, ".")) {
continue;
}
char dn[PATH_MAX];
snprintf(dn, sizeof(dn), "%s/%s", path, de->d_name);
if (!dirSetHierarchyPermissions(dn, uid, gid, dirMode, fileMode)) {
errno = 0;
} else if (errno == 0) {
errno = -1;
}
}
if (errno != 0) {
int save = errno;
closedir(dir);
errno = save;
return -1;
}
if (closedir(dir)) {
return -1;
}
}
return 0;
}
+51
View File
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MINZIP_DIRUTIL_H_
#define MINZIP_DIRUTIL_H_
#include <stdbool.h>
#include <utime.h>
/* Like "mkdir -p", try to guarantee that all directories
* specified in path are present, creating as many directories
* as necessary. The specified mode is passed to all mkdir
* calls; no modifications are made to umask.
*
* If stripFileName is set, everything after the final '/'
* is stripped before creating the directory hierarchy.
*
* If timestamp is non-NULL, new directories will be timestamped accordingly.
*
* Returns 0 on success; returns -1 (and sets errno) on failure
* (usually if some element of path is not a directory).
*/
int dirCreateHierarchy(const char *path, int mode,
const struct utimbuf *timestamp, bool stripFileName);
/* rm -rf <path>
*/
int dirUnlinkHierarchy(const char *path);
/* chown -R <uid>:<gid> <path>
* chmod -R <mode> <path>
*
* Sets directories to <dirMode> and files to <fileMode>. Skips symlinks.
*/
int dirSetHierarchyPermissions(const char *path,
int uid, int gid, int dirMode, int fileMode);
#endif // MINZIP_DIRUTIL_H_
+390
View File
@@ -0,0 +1,390 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Hash table. The dominant calls are add and lookup, with removals
* happening very infrequently. We use probing, and don't worry much
* about tombstone removal.
*/
#include <stdlib.h>
#include <assert.h>
#define LOG_TAG "minzip"
#include "Log.h"
#include "Hash.h"
/* table load factor, i.e. how full can it get before we resize */
//#define LOAD_NUMER 3 // 75%
//#define LOAD_DENOM 4
#define LOAD_NUMER 5 // 62.5%
#define LOAD_DENOM 8
//#define LOAD_NUMER 1 // 50%
//#define LOAD_DENOM 2
/*
* Compute the capacity needed for a table to hold "size" elements.
*/
size_t mzHashSize(size_t size) {
return (size * LOAD_DENOM) / LOAD_NUMER +1;
}
/*
* Round up to the next highest power of 2.
*
* Found on http://graphics.stanford.edu/~seander/bithacks.html.
*/
unsigned int roundUpPower2(unsigned int val)
{
val--;
val |= val >> 1;
val |= val >> 2;
val |= val >> 4;
val |= val >> 8;
val |= val >> 16;
val++;
return val;
}
/*
* Create and initialize a hash table.
*/
HashTable* mzHashTableCreate(size_t initialSize, HashFreeFunc freeFunc)
{
HashTable* pHashTable;
assert(initialSize > 0);
pHashTable = (HashTable*) malloc(sizeof(*pHashTable));
if (pHashTable == NULL)
return NULL;
pHashTable->tableSize = roundUpPower2(initialSize);
pHashTable->numEntries = pHashTable->numDeadEntries = 0;
pHashTable->freeFunc = freeFunc;
pHashTable->pEntries =
(HashEntry*) calloc((size_t)pHashTable->tableSize, sizeof(HashTable));
if (pHashTable->pEntries == NULL) {
free(pHashTable);
return NULL;
}
return pHashTable;
}
/*
* Clear out all entries.
*/
void mzHashTableClear(HashTable* pHashTable)
{
HashEntry* pEnt;
int i;
pEnt = pHashTable->pEntries;
for (i = 0; i < pHashTable->tableSize; i++, pEnt++) {
if (pEnt->data == HASH_TOMBSTONE) {
// nuke entry
pEnt->data = NULL;
} else if (pEnt->data != NULL) {
// call free func then nuke entry
if (pHashTable->freeFunc != NULL)
(*pHashTable->freeFunc)(pEnt->data);
pEnt->data = NULL;
}
}
pHashTable->numEntries = 0;
pHashTable->numDeadEntries = 0;
}
/*
* Free the table.
*/
void mzHashTableFree(HashTable* pHashTable)
{
if (pHashTable == NULL)
return;
mzHashTableClear(pHashTable);
free(pHashTable->pEntries);
free(pHashTable);
}
#ifndef NDEBUG
/*
* Count up the number of tombstone entries in the hash table.
*/
static int countTombStones(HashTable* pHashTable)
{
int i, count;
for (count = i = 0; i < pHashTable->tableSize; i++) {
if (pHashTable->pEntries[i].data == HASH_TOMBSTONE)
count++;
}
return count;
}
#endif
/*
* Resize a hash table. We do this when adding an entry increased the
* size of the table beyond its comfy limit.
*
* This essentially requires re-inserting all elements into the new storage.
*
* If multiple threads can access the hash table, the table's lock should
* have been grabbed before issuing the "lookup+add" call that led to the
* resize, so we don't have a synchronization problem here.
*/
static bool resizeHash(HashTable* pHashTable, int newSize)
{
HashEntry* pNewEntries;
int i;
assert(countTombStones(pHashTable) == pHashTable->numDeadEntries);
//LOGI("before: dead=%d\n", pHashTable->numDeadEntries);
pNewEntries = (HashEntry*) calloc(newSize, sizeof(HashTable));
if (pNewEntries == NULL)
return false;
for (i = 0; i < pHashTable->tableSize; i++) {
void* data = pHashTable->pEntries[i].data;
if (data != NULL && data != HASH_TOMBSTONE) {
int hashValue = pHashTable->pEntries[i].hashValue;
int newIdx;
/* probe for new spot, wrapping around */
newIdx = hashValue & (newSize-1);
while (pNewEntries[newIdx].data != NULL)
newIdx = (newIdx + 1) & (newSize-1);
pNewEntries[newIdx].hashValue = hashValue;
pNewEntries[newIdx].data = data;
}
}
free(pHashTable->pEntries);
pHashTable->pEntries = pNewEntries;
pHashTable->tableSize = newSize;
pHashTable->numDeadEntries = 0;
assert(countTombStones(pHashTable) == 0);
return true;
}
/*
* Look up an entry.
*
* We probe on collisions, wrapping around the table.
*/
void* mzHashTableLookup(HashTable* pHashTable, unsigned int itemHash, void* item,
HashCompareFunc cmpFunc, bool doAdd)
{
HashEntry* pEntry;
HashEntry* pEnd;
void* result = NULL;
assert(pHashTable->tableSize > 0);
assert(item != HASH_TOMBSTONE);
assert(item != NULL);
/* jump to the first entry and probe for a match */
pEntry = &pHashTable->pEntries[itemHash & (pHashTable->tableSize-1)];
pEnd = &pHashTable->pEntries[pHashTable->tableSize];
while (pEntry->data != NULL) {
if (pEntry->data != HASH_TOMBSTONE &&
pEntry->hashValue == itemHash &&
(*cmpFunc)(pEntry->data, item) == 0)
{
/* match */
//LOGD("+++ match on entry %d\n", pEntry - pHashTable->pEntries);
break;
}
pEntry++;
if (pEntry == pEnd) { /* wrap around to start */
if (pHashTable->tableSize == 1)
break; /* edge case - single-entry table */
pEntry = pHashTable->pEntries;
}
//LOGI("+++ look probing %d...\n", pEntry - pHashTable->pEntries);
}
if (pEntry->data == NULL) {
if (doAdd) {
pEntry->hashValue = itemHash;
pEntry->data = item;
pHashTable->numEntries++;
/*
* We've added an entry. See if this brings us too close to full.
*/
if ((pHashTable->numEntries+pHashTable->numDeadEntries) * LOAD_DENOM
> pHashTable->tableSize * LOAD_NUMER)
{
if (!resizeHash(pHashTable, pHashTable->tableSize * 2)) {
/* don't really have a way to indicate failure */
LOGE("Dalvik hash resize failure\n");
abort();
}
/* note "pEntry" is now invalid */
} else {
//LOGW("okay %d/%d/%d\n",
// pHashTable->numEntries, pHashTable->tableSize,
// (pHashTable->tableSize * LOAD_NUMER) / LOAD_DENOM);
}
/* full table is bad -- search for nonexistent never halts */
assert(pHashTable->numEntries < pHashTable->tableSize);
result = item;
} else {
assert(result == NULL);
}
} else {
result = pEntry->data;
}
return result;
}
/*
* Remove an entry from the table.
*
* Does NOT invoke the "free" function on the item.
*/
bool mzHashTableRemove(HashTable* pHashTable, unsigned int itemHash, void* item)
{
HashEntry* pEntry;
HashEntry* pEnd;
assert(pHashTable->tableSize > 0);
/* jump to the first entry and probe for a match */
pEntry = &pHashTable->pEntries[itemHash & (pHashTable->tableSize-1)];
pEnd = &pHashTable->pEntries[pHashTable->tableSize];
while (pEntry->data != NULL) {
if (pEntry->data == item) {
//LOGI("+++ stepping on entry %d\n", pEntry - pHashTable->pEntries);
pEntry->data = HASH_TOMBSTONE;
pHashTable->numEntries--;
pHashTable->numDeadEntries++;
return true;
}
pEntry++;
if (pEntry == pEnd) { /* wrap around to start */
if (pHashTable->tableSize == 1)
break; /* edge case - single-entry table */
pEntry = pHashTable->pEntries;
}
//LOGI("+++ del probing %d...\n", pEntry - pHashTable->pEntries);
}
return false;
}
/*
* Execute a function on every entry in the hash table.
*
* If "func" returns a nonzero value, terminate early and return the value.
*/
int mzHashForeach(HashTable* pHashTable, HashForeachFunc func, void* arg)
{
int i, val;
for (i = 0; i < pHashTable->tableSize; i++) {
HashEntry* pEnt = &pHashTable->pEntries[i];
if (pEnt->data != NULL && pEnt->data != HASH_TOMBSTONE) {
val = (*func)(pEnt->data, arg);
if (val != 0)
return val;
}
}
return 0;
}
/*
* Look up an entry, counting the number of times we have to probe.
*
* Returns -1 if the entry wasn't found.
*/
int countProbes(HashTable* pHashTable, unsigned int itemHash, const void* item,
HashCompareFunc cmpFunc)
{
HashEntry* pEntry;
HashEntry* pEnd;
int count = 0;
assert(pHashTable->tableSize > 0);
assert(item != HASH_TOMBSTONE);
assert(item != NULL);
/* jump to the first entry and probe for a match */
pEntry = &pHashTable->pEntries[itemHash & (pHashTable->tableSize-1)];
pEnd = &pHashTable->pEntries[pHashTable->tableSize];
while (pEntry->data != NULL) {
if (pEntry->data != HASH_TOMBSTONE &&
pEntry->hashValue == itemHash &&
(*cmpFunc)(pEntry->data, item) == 0)
{
/* match */
break;
}
pEntry++;
if (pEntry == pEnd) { /* wrap around to start */
if (pHashTable->tableSize == 1)
break; /* edge case - single-entry table */
pEntry = pHashTable->pEntries;
}
count++;
}
if (pEntry->data == NULL)
return -1;
return count;
}
/*
* Evaluate the amount of probing required for the specified hash table.
*
* We do this by running through all entries in the hash table, computing
* the hash value and then doing a lookup.
*
* The caller should lock the table before calling here.
*/
void mzHashTableProbeCount(HashTable* pHashTable, HashCalcFunc calcFunc,
HashCompareFunc cmpFunc)
{
int numEntries, minProbe, maxProbe, totalProbe;
HashIter iter;
numEntries = maxProbe = totalProbe = 0;
minProbe = 65536*32767;
for (mzHashIterBegin(pHashTable, &iter); !mzHashIterDone(&iter);
mzHashIterNext(&iter))
{
const void* data = (const void*)mzHashIterData(&iter);
int count;
count = countProbes(pHashTable, (*calcFunc)(data), data, cmpFunc);
numEntries++;
if (count < minProbe)
minProbe = count;
if (count > maxProbe)
maxProbe = count;
totalProbe += count;
}
LOGI("Probe: min=%d max=%d, total=%d in %d (%d), avg=%.3f\n",
minProbe, maxProbe, totalProbe, numEntries, pHashTable->tableSize,
(float) totalProbe / (float) numEntries);
}
+186
View File
@@ -0,0 +1,186 @@
/*
* Copyright 2007 The Android Open Source Project
*
* General purpose hash table, used for finding classes, methods, etc.
*
* When the number of elements reaches 3/4 of the table's capacity, the
* table will be resized.
*/
#ifndef _MINZIP_HASH
#define _MINZIP_HASH
#include "inline_magic.h"
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
/* compute the hash of an item with a specific type */
typedef unsigned int (*HashCompute)(const void* item);
/*
* Compare a hash entry with a "loose" item after their hash values match.
* Returns { <0, 0, >0 } depending on ordering of items (same semantics
* as strcmp()).
*/
typedef int (*HashCompareFunc)(const void* tableItem, const void* looseItem);
/*
* This function will be used to free entries in the table. This can be
* NULL if no free is required, free(), or a custom function.
*/
typedef void (*HashFreeFunc)(void* ptr);
/*
* Used by mzHashForeach().
*/
typedef int (*HashForeachFunc)(void* data, void* arg);
/*
* One entry in the hash table. "data" values are expected to be (or have
* the same characteristics as) valid pointers. In particular, a NULL
* value for "data" indicates an empty slot, and HASH_TOMBSTONE indicates
* a no-longer-used slot that must be stepped over during probing.
*
* Attempting to add a NULL or tombstone value is an error.
*
* When an entry is released, we will call (HashFreeFunc)(entry->data).
*/
typedef struct HashEntry {
unsigned int hashValue;
void* data;
} HashEntry;
#define HASH_TOMBSTONE ((void*) 0xcbcacccd) // invalid ptr value
/*
* Expandable hash table.
*
* This structure should be considered opaque.
*/
typedef struct HashTable {
int tableSize; /* must be power of 2 */
int numEntries; /* current #of "live" entries */
int numDeadEntries; /* current #of tombstone entries */
HashEntry* pEntries; /* array on heap */
HashFreeFunc freeFunc;
} HashTable;
/*
* Create and initialize a HashTable structure, using "initialSize" as
* a basis for the initial capacity of the table. (The actual initial
* table size may be adjusted upward.) If you know exactly how many
* elements the table will hold, pass the result from mzHashSize() in.)
*
* Returns "false" if unable to allocate the table.
*/
HashTable* mzHashTableCreate(size_t initialSize, HashFreeFunc freeFunc);
/*
* Compute the capacity needed for a table to hold "size" elements. Use
* this when you know ahead of time how many elements the table will hold.
* Pass this value into mzHashTableCreate() to ensure that you can add
* all elements without needing to reallocate the table.
*/
size_t mzHashSize(size_t size);
/*
* Clear out a hash table, freeing the contents of any used entries.
*/
void mzHashTableClear(HashTable* pHashTable);
/*
* Free a hash table.
*/
void mzHashTableFree(HashTable* pHashTable);
/*
* Get #of entries in hash table.
*/
INLINE int mzHashTableNumEntries(HashTable* pHashTable) {
return pHashTable->numEntries;
}
/*
* Get total size of hash table (for memory usage calculations).
*/
INLINE int mzHashTableMemUsage(HashTable* pHashTable) {
return sizeof(HashTable) + pHashTable->tableSize * sizeof(HashEntry);
}
/*
* Look up an entry in the table, possibly adding it if it's not there.
*
* If "item" is not found, and "doAdd" is false, NULL is returned.
* Otherwise, a pointer to the found or added item is returned. (You can
* tell the difference by seeing if return value == item.)
*
* An "add" operation may cause the entire table to be reallocated.
*/
void* mzHashTableLookup(HashTable* pHashTable, unsigned int itemHash, void* item,
HashCompareFunc cmpFunc, bool doAdd);
/*
* Remove an item from the hash table, given its "data" pointer. Does not
* invoke the "free" function; just detaches it from the table.
*/
bool mzHashTableRemove(HashTable* pHashTable, unsigned int hash, void* item);
/*
* Execute "func" on every entry in the hash table.
*
* If "func" returns a nonzero value, terminate early and return the value.
*/
int mzHashForeach(HashTable* pHashTable, HashForeachFunc func, void* arg);
/*
* An alternative to mzHashForeach(), using an iterator.
*
* Use like this:
* HashIter iter;
* for (mzHashIterBegin(hashTable, &iter); !mzHashIterDone(&iter);
* mzHashIterNext(&iter))
* {
* MyData* data = (MyData*)mzHashIterData(&iter);
* }
*/
typedef struct HashIter {
void* data;
HashTable* pHashTable;
int idx;
} HashIter;
INLINE void mzHashIterNext(HashIter* pIter) {
int i = pIter->idx +1;
int lim = pIter->pHashTable->tableSize;
for ( ; i < lim; i++) {
void* data = pIter->pHashTable->pEntries[i].data;
if (data != NULL && data != HASH_TOMBSTONE)
break;
}
pIter->idx = i;
}
INLINE void mzHashIterBegin(HashTable* pHashTable, HashIter* pIter) {
pIter->pHashTable = pHashTable;
pIter->idx = -1;
mzHashIterNext(pIter);
}
INLINE bool mzHashIterDone(HashIter* pIter) {
return (pIter->idx >= pIter->pHashTable->tableSize);
}
INLINE void* mzHashIterData(HashIter* pIter) {
assert(pIter->idx >= 0 && pIter->idx < pIter->pHashTable->tableSize);
return pIter->pHashTable->pEntries[pIter->idx].data;
}
/*
* Evaluate hash table performance by examining the number of times we
* have to probe for an entry.
*
* The caller should lock the table beforehand.
*/
typedef unsigned int (*HashCalcFunc)(const void* item);
void mzHashTableProbeCount(HashTable* pHashTable, HashCalcFunc calcFunc,
HashCompareFunc cmpFunc);
#endif /*_MINZIP_HASH*/
+25
View File
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* Make sure that non-inlined versions of INLINED-marked functions
* exist so that debug builds (which don't generally do inlining)
* don't break.
*/
#define MINZIP_GENERATE_INLINES 1
#include "Bits.h"
#include "Hash.h"
#include "SysUtil.h"
#include "Zip.h"
+207
View File
@@ -0,0 +1,207 @@
//
// Copyright 2005 The Android Open Source Project
//
// C/C++ logging functions. See the logging documentation for API details.
//
// We'd like these to be available from C code (in case we import some from
// somewhere), so this has a C interface.
//
// The output will be correct when the log file is shared between multiple
// threads and/or multiple processes so long as the operating system
// supports O_APPEND. These calls have mutex-protected data structures
// and so are NOT reentrant. Do not use LOG in a signal handler.
//
#ifndef _MINZIP_LOG_H
#define _MINZIP_LOG_H
#include <stdio.h>
// ---------------------------------------------------------------------
/*
* Normally we strip LOGV (VERBOSE messages) from release builds.
* You can modify this (for example with "#define LOG_NDEBUG 0"
* at the top of your source file) to change that behavior.
*/
#ifndef LOG_NDEBUG
#ifdef NDEBUG
#define LOG_NDEBUG 1
#else
#define LOG_NDEBUG 0
#endif
#endif
/*
* This is the local tag used for the following simplified
* logging macros. You can change this preprocessor definition
* before using the other macros to change the tag.
*/
#ifndef LOG_TAG
#define LOG_TAG NULL
#endif
// ---------------------------------------------------------------------
/*
* Simplified macro to send a verbose log message using the current LOG_TAG.
*/
#ifndef LOGV
#if LOG_NDEBUG
#define LOGV(...) ((void)0)
#else
#define LOGV(...) ((void)LOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#endif
#endif
#define CONDITION(cond) (__builtin_expect((cond)!=0, 0))
#ifndef LOGV_IF
#if LOG_NDEBUG
#define LOGV_IF(cond, ...) ((void)0)
#else
#define LOGV_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)LOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
#endif
#define LOGVV LOGV
#define LOGVV_IF LOGV_IF
/*
* Simplified macro to send a debug log message using the current LOG_TAG.
*/
#ifndef LOGD
#define LOGD(...) ((void)LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#endif
#ifndef LOGD_IF
#define LOGD_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send an info log message using the current LOG_TAG.
*/
#ifndef LOGI
#define LOGI(...) ((void)LOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
#endif
#ifndef LOGI_IF
#define LOGI_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)LOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send a warning log message using the current LOG_TAG.
*/
#ifndef LOGW
#define LOGW(...) ((void)LOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
#endif
#ifndef LOGW_IF
#define LOGW_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)LOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Simplified macro to send an error log message using the current LOG_TAG.
*/
#ifndef LOGE
#define LOGE(...) ((void)LOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
#endif
#ifndef LOGE_IF
#define LOGE_IF(cond, ...) \
( (CONDITION(cond)) \
? ((void)LOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
: (void)0 )
#endif
/*
* Conditional based on whether the current LOG_TAG is enabled at
* verbose priority.
*/
#ifndef IF_LOGV
#if LOG_NDEBUG
#define IF_LOGV() if (false)
#else
#define IF_LOGV() IF_LOG(LOG_VERBOSE, LOG_TAG)
#endif
#endif
/*
* Conditional based on whether the current LOG_TAG is enabled at
* debug priority.
*/
#ifndef IF_LOGD
#define IF_LOGD() IF_LOG(LOG_DEBUG, LOG_TAG)
#endif
/*
* Conditional based on whether the current LOG_TAG is enabled at
* info priority.
*/
#ifndef IF_LOGI
#define IF_LOGI() IF_LOG(LOG_INFO, LOG_TAG)
#endif
/*
* Conditional based on whether the current LOG_TAG is enabled at
* warn priority.
*/
#ifndef IF_LOGW
#define IF_LOGW() IF_LOG(LOG_WARN, LOG_TAG)
#endif
/*
* Conditional based on whether the current LOG_TAG is enabled at
* error priority.
*/
#ifndef IF_LOGE
#define IF_LOGE() IF_LOG(LOG_ERROR, LOG_TAG)
#endif
// ---------------------------------------------------------------------
/*
* Basic log message macro.
*
* Example:
* LOG(LOG_WARN, NULL, "Failed with error %d", errno);
*
* The second argument may be NULL or "" to indicate the "global" tag.
*
* Non-gcc probably won't have __FUNCTION__. It's not vital. gcc also
* offers __PRETTY_FUNCTION__, which is rather more than we need.
*/
#ifndef LOG
#define LOG(priority, tag, ...) \
LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
#endif
/*
* Log macro that allows you to specify a number for the priority.
*/
#ifndef LOG_PRI
#define LOG_PRI(priority, tag, ...) \
printf(tag ": " __VA_ARGS__)
#endif
/*
* Conditional given a desired logging priority and tag.
*/
#ifndef IF_LOG
#define IF_LOG(priority, tag) \
if (1)
#endif
#endif // _MINZIP_LOG_H
+50
View File
@@ -0,0 +1,50 @@
AM_CFLAGS := -Wundef \
-Wstrict-prototypes \
-Wno-trigraphs \
-g -O0 \
-fno-inline \
-fno-short-enums \
-fpic \
-DNDEBUG
AM_CPPFLAGS := \
-I. \
-I$(WORKSPACE)/external/safe-iop/include
AM_LDFLAGS := -shared -version-info 1:0:0
c_sources := \
Hash.c \
SysUtil.c \
DirUtil.c \
Inlines.c \
Zip.c
h_sources := \
Bits.h \
DirUtil.h \
Hash.h \
Log.h \
SysUtil.h \
Zip.h \
inline_magic.h
required_libs := $(MINCRYPT_LIBS)
library_includedir := $(pkgincludedir)
library_include_HEADERS := $(h_sources)
lib_LTLIBRARIES := libminzip.la
libminzip_la_SOURCES := $(c_sources) $(h_sources)
if USE_GLIB
libminzip_la_CFLAGS := $(AM_CFLAGS) -DUSE_GLIB @GLIB_CFLAGS@
libminzip_la_CPPFLAGS := $(AM_CPPFLAGS) -DUSE_GLIB @GLIB_CFLAGS@
libminzip_la_LIBADD := -lm -lpthread @GLIB_LIBS@
libminzip_la_LDFLAGS := -all-static
else
libminzip_la_CFLAGS := $(AM_CFLAGS)
libminzip_la_CPPFLAGS := $(AM_CPPFLAGS)
libminzip_la_LIBADD := -lm -lpthread
libminzip_la_LDFLAGS := -all-static
endif
+212
View File
@@ -0,0 +1,212 @@
/*
* Copyright 2006 The Android Open Source Project
*
* System utilities.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <limits.h>
#include <errno.h>
#include <assert.h>
#define LOG_TAG "minzip"
#include "Log.h"
#include "SysUtil.h"
/*
* Having trouble finding a portable way to get this. sysconf(_SC_PAGE_SIZE)
* seems appropriate, but we don't have that on the device. Some systems
* have getpagesize(2), though the linux man page has some odd cautions.
*/
#define DEFAULT_PAGE_SIZE 4096
/*
* Create an anonymous shared memory segment large enough to hold "length"
* bytes. The actual segment may be larger because mmap() operates on
* page boundaries (usually 4K).
*/
static void* sysCreateAnonShmem(size_t length)
{
void* ptr;
ptr = mmap(NULL, length, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANON, -1, 0);
if (ptr == MAP_FAILED) {
LOGW("mmap(%d, RW, SHARED|ANON) failed: %s\n", (int) length,
strerror(errno));
return NULL;
}
return ptr;
}
static int getFileStartAndLength(int fd, off_t *start_, size_t *length_)
{
off_t start, end;
size_t length;
assert(start_ != NULL);
assert(length_ != NULL);
start = lseek(fd, 0L, SEEK_CUR);
end = lseek(fd, 0L, SEEK_END);
(void) lseek(fd, start, SEEK_SET);
if (start == (off_t) -1 || end == (off_t) -1) {
LOGE("could not determine length of file\n");
return -1;
}
length = end - start;
if (length == 0) {
LOGE("file is empty\n");
return -1;
}
*start_ = start;
*length_ = length;
return 0;
}
/*
* Pull the contents of a file into an new shared memory segment. We grab
* everything from fd's current offset on.
*
* We need to know the length ahead of time so we can allocate a segment
* of sufficient size.
*/
int sysLoadFileInShmem(int fd, MemMapping* pMap)
{
off_t start;
size_t length, actual;
void* memPtr;
assert(pMap != NULL);
if (getFileStartAndLength(fd, &start, &length) < 0)
return -1;
memPtr = sysCreateAnonShmem(length);
if (memPtr == NULL)
return -1;
actual = read(fd, memPtr, length);
if (actual != length) {
LOGE("only read %d of %d bytes\n", (int) actual, (int) length);
sysReleaseShmem(pMap);
return -1;
}
pMap->baseAddr = pMap->addr = memPtr;
pMap->baseLength = pMap->length = length;
return 0;
}
/*
* Map a file (from fd's current offset) into a shared, read-only memory
* segment. The file offset must be a multiple of the page size.
*
* On success, returns 0 and fills out "pMap". On failure, returns a nonzero
* value and does not disturb "pMap".
*/
int sysMapFileInShmem(int fd, MemMapping* pMap)
{
off_t start;
size_t length;
void* memPtr;
assert(pMap != NULL);
if (getFileStartAndLength(fd, &start, &length) < 0)
return -1;
memPtr = mmap(NULL, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, start);
if (memPtr == MAP_FAILED) {
LOGW("mmap(%d, R, FILE|SHARED, %d, %d) failed: %s\n", (int) length,
fd, (int) start, strerror(errno));
return -1;
}
pMap->baseAddr = pMap->addr = memPtr;
pMap->baseLength = pMap->length = length;
return 0;
}
/*
* Map part of a file (from fd's current offset) into a shared, read-only
* memory segment.
*
* On success, returns 0 and fills out "pMap". On failure, returns a nonzero
* value and does not disturb "pMap".
*/
int sysMapFileSegmentInShmem(int fd, off_t start, long length,
MemMapping* pMap)
{
off_t dummy;
size_t fileLength, actualLength;
off_t actualStart;
int adjust;
void* memPtr;
assert(pMap != NULL);
if (getFileStartAndLength(fd, &dummy, &fileLength) < 0)
return -1;
if (start + length > (long)fileLength) {
LOGW("bad segment: st=%d len=%ld flen=%d\n",
(int) start, length, (int) fileLength);
return -1;
}
/* adjust to be page-aligned */
adjust = start % DEFAULT_PAGE_SIZE;
actualStart = start - adjust;
actualLength = length + adjust;
memPtr = mmap(NULL, actualLength, PROT_READ, MAP_FILE | MAP_SHARED,
fd, actualStart);
if (memPtr == MAP_FAILED) {
LOGW("mmap(%d, R, FILE|SHARED, %d, %d) failed: %s\n",
(int) actualLength, fd, (int) actualStart, strerror(errno));
return -1;
}
pMap->baseAddr = memPtr;
pMap->baseLength = actualLength;
pMap->addr = (char*)memPtr + adjust;
pMap->length = length;
LOGVV("mmap seg (st=%d ln=%d): bp=%p bl=%d ad=%p ln=%d\n",
(int) start, (int) length,
pMap->baseAddr, (int) pMap->baseLength,
pMap->addr, (int) pMap->length);
return 0;
}
/*
* Release a memory mapping.
*/
void sysReleaseShmem(MemMapping* pMap)
{
if (pMap->baseAddr == NULL && pMap->baseLength == 0)
return;
if (munmap(pMap->baseAddr, pMap->baseLength) < 0) {
LOGW("munmap(%p, %d) failed: %s\n",
pMap->baseAddr, (int)pMap->baseLength, strerror(errno));
} else {
LOGV("munmap(%p, %d) succeeded\n", pMap->baseAddr, pMap->baseLength);
pMap->baseAddr = NULL;
pMap->baseLength = 0;
}
}
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright 2006 The Android Open Source Project
*
* System utilities.
*/
#ifndef _MINZIP_SYSUTIL
#define _MINZIP_SYSUTIL
#include "inline_magic.h"
#include <sys/types.h>
/*
* Use this to keep track of mapped segments.
*/
typedef struct MemMapping {
void* addr; /* start of data */
size_t length; /* length of data */
void* baseAddr; /* page-aligned base address */
size_t baseLength; /* length of mapping */
} MemMapping;
/* copy a map */
INLINE void sysCopyMap(MemMapping* dst, const MemMapping* src) {
*dst = *src;
}
/*
* Load a file into a new shared memory segment. All data from the current
* offset to the end of the file is pulled in.
*
* The segment is read-write, allowing VM fixups. (It should be modified
* to support .gz/.zip compressed data.)
*
* On success, "pMap" is filled in, and zero is returned.
*/
int sysLoadFileInShmem(int fd, MemMapping* pMap);
/*
* Map a file (from fd's current offset) into a shared,
* read-only memory segment.
*
* On success, "pMap" is filled in, and zero is returned.
*/
int sysMapFileInShmem(int fd, MemMapping* pMap);
/*
* Like sysMapFileInShmem, but on only part of a file.
*/
int sysMapFileSegmentInShmem(int fd, off_t start, long length,
MemMapping* pMap);
/*
* Release the pages associated with a shared memory segment.
*
* This does not free "pMap"; it just releases the memory.
*/
void sysReleaseShmem(MemMapping* pMap);
#endif /*_MINZIP_SYSUTIL*/
File diff suppressed because it is too large Load Diff
+213
View File
@@ -0,0 +1,213 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Simple Zip archive support.
*/
#ifndef _MINZIP_ZIP
#define _MINZIP_ZIP
#include "inline_magic.h"
#include <stdlib.h>
#include <utime.h>
#include "Hash.h"
#include "SysUtil.h"
/*
* One entry in the Zip archive. Treat this as opaque -- use accessors below.
*
* TODO: we're now keeping the pages mapped so we don't have to copy the
* filename. We can change the accessors to retrieve the various pieces
* directly from the source file instead of copying them out, for a very
* slight speed hit and a modest reduction in memory usage.
*/
typedef struct ZipEntry {
unsigned int fileNameLen;
const char* fileName; // not null-terminated
long offset;
long compLen;
long uncompLen;
int compression;
long modTime;
long crc32;
int versionMadeBy;
long externalFileAttributes;
} ZipEntry;
/*
* One Zip archive. Treat as opaque.
*/
typedef struct ZipArchive {
int fd;
unsigned int numEntries;
ZipEntry* pEntries;
HashTable* pHash; // maps file name to ZipEntry
MemMapping map;
} ZipArchive;
/*
* Represents a non-NUL-terminated string,
* which is how entry names are stored.
*/
typedef struct {
const char *str;
size_t len;
} UnterminatedString;
/*
* Open a Zip archive.
*
* On success, returns 0 and populates "pArchive". Returns nonzero errno
* value on failure.
*/
int mzOpenZipArchive(const char* fileName, ZipArchive* pArchive);
/*
* Close archive, releasing resources associated with it.
*
* Depending on the implementation this could unmap pages used by classes
* stored in a Jar. This should only be done after unloading classes.
*/
void mzCloseZipArchive(ZipArchive* pArchive);
/*
* Find an entry in the Zip archive, by name.
*/
const ZipEntry* mzFindZipEntry(const ZipArchive* pArchive,
const char* entryName);
/*
* Get the number of entries in the Zip archive.
*/
INLINE unsigned int mzZipEntryCount(const ZipArchive* pArchive) {
return pArchive->numEntries;
}
/*
* Get an entry by index. Returns NULL if the index is out-of-bounds.
*/
INLINE const ZipEntry*
mzGetZipEntryAt(const ZipArchive* pArchive, unsigned int index)
{
if (index < pArchive->numEntries) {
return pArchive->pEntries + index;
}
return NULL;
}
/*
* Get the index number of an entry in the archive.
*/
INLINE unsigned int
mzGetZipEntryIndex(const ZipArchive *pArchive, const ZipEntry *pEntry) {
return pEntry - pArchive->pEntries;
}
/*
* Simple accessors.
*/
INLINE UnterminatedString mzGetZipEntryFileName(const ZipEntry* pEntry) {
UnterminatedString ret;
ret.str = pEntry->fileName;
ret.len = pEntry->fileNameLen;
return ret;
}
INLINE long mzGetZipEntryOffset(const ZipEntry* pEntry) {
return pEntry->offset;
}
INLINE long mzGetZipEntryUncompLen(const ZipEntry* pEntry) {
return pEntry->uncompLen;
}
INLINE long mzGetZipEntryModTime(const ZipEntry* pEntry) {
return pEntry->modTime;
}
INLINE long mzGetZipEntryCrc32(const ZipEntry* pEntry) {
return pEntry->crc32;
}
bool mzIsZipEntrySymlink(const ZipEntry* pEntry);
/*
* Type definition for the callback function used by
* mzProcessZipEntryContents().
*/
typedef bool (*ProcessZipEntryContentsFunction)(const unsigned char *data,
int dataLen, void *cookie);
/*
* Stream the uncompressed data through the supplied function,
* passing cookie to it each time it gets called. processFunction
* may be called more than once.
*
* If processFunction returns false, the operation is abandoned and
* mzProcessZipEntryContents() immediately returns false.
*
* This is useful for calculating the hash of an entry's uncompressed contents.
*/
bool mzProcessZipEntryContents(const ZipArchive *pArchive,
const ZipEntry *pEntry, ProcessZipEntryContentsFunction processFunction,
void *cookie);
/*
* Read an entry into a buffer allocated by the caller.
*/
bool mzReadZipEntry(const ZipArchive* pArchive, const ZipEntry* pEntry,
char* buf, int bufLen);
/*
* Check the CRC on this entry; return true if it is correct.
* May do other internal checks as well.
*/
bool mzIsZipEntryIntact(const ZipArchive *pArchive, const ZipEntry *pEntry);
/*
* Inflate and write an entry to a file.
*/
bool mzExtractZipEntryToFile(const ZipArchive *pArchive,
const ZipEntry *pEntry, int fd);
/*
* Inflate and write an entry to a memory buffer, which must be long
* enough to hold mzGetZipEntryUncomplen(pEntry) bytes.
*/
bool mzExtractZipEntryToBuffer(const ZipArchive *pArchive,
const ZipEntry *pEntry, unsigned char* buffer);
/*
* Inflate all entries under zipDir to the directory specified by
* targetDir, which must exist and be a writable directory.
*
* The immediate children of zipDir will become the immediate
* children of targetDir; e.g., if the archive contains the entries
*
* a/b/c/one
* a/b/c/two
* a/b/c/d/three
*
* and mzExtractRecursive(a, "a/b/c", "/tmp", ...) is called, the resulting
* files will be
*
* /tmp/one
* /tmp/two
* /tmp/d/three
*
* flags is zero or more of the following:
*
* MZ_EXTRACT_FILES_ONLY - only unpack files, not directories or symlinks
* MZ_EXTRACT_DRY_RUN - don't do anything, but do invoke the callback
*
* If timestamp is non-NULL, file timestamps will be set accordingly.
*
* If callback is non-NULL, it will be invoked with each unpacked file.
*
* Returns true on success, false on failure.
*/
enum { MZ_EXTRACT_FILES_ONLY = 1, MZ_EXTRACT_DRY_RUN = 2 };
bool mzExtractRecursive(const ZipArchive *pArchive,
const char *zipDir, const char *targetDir,
int flags, const struct utimbuf *timestamp,
void (*callback)(const char *fn, void*), void *cookie);
#endif /*_MINZIP_ZIP*/
+26
View File
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MINZIP_INLINE_MAGIC_H_
#define MINZIP_INLINE_MAGIC_H_
#ifndef MINZIP_GENERATE_INLINES
#define INLINE extern __inline__
#else
#define INLINE
#endif
#endif // MINZIP_INLINE_MAGIC_H_