11f5762e646bed2290934280464832782766ee68eMathias Agopian/* 21f5762e646bed2290934280464832782766ee68eMathias Agopian * Copyright (C) 2007 The Android Open Source Project 31f5762e646bed2290934280464832782766ee68eMathias Agopian * 41f5762e646bed2290934280464832782766ee68eMathias Agopian * Licensed under the Apache License, Version 2.0 (the "License"); 51f5762e646bed2290934280464832782766ee68eMathias Agopian * you may not use this file except in compliance with the License. 61f5762e646bed2290934280464832782766ee68eMathias Agopian * You may obtain a copy of the License at 71f5762e646bed2290934280464832782766ee68eMathias Agopian * 81f5762e646bed2290934280464832782766ee68eMathias Agopian * http://www.apache.org/licenses/LICENSE-2.0 91f5762e646bed2290934280464832782766ee68eMathias Agopian * 101f5762e646bed2290934280464832782766ee68eMathias Agopian * Unless required by applicable law or agreed to in writing, software 111f5762e646bed2290934280464832782766ee68eMathias Agopian * distributed under the License is distributed on an "AS IS" BASIS, 121f5762e646bed2290934280464832782766ee68eMathias Agopian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131f5762e646bed2290934280464832782766ee68eMathias Agopian * See the License for the specific language governing permissions and 141f5762e646bed2290934280464832782766ee68eMathias Agopian * limitations under the License. 151f5762e646bed2290934280464832782766ee68eMathias Agopian */ 161f5762e646bed2290934280464832782766ee68eMathias Agopian 171f5762e646bed2290934280464832782766ee68eMathias Agopian/* 181f5762e646bed2290934280464832782766ee68eMathias Agopian * Read-only access to Zip archives, with minimal heap allocation. 191f5762e646bed2290934280464832782766ee68eMathias Agopian * 201f5762e646bed2290934280464832782766ee68eMathias Agopian * This is similar to the more-complete ZipFile class, but no attempt 211f5762e646bed2290934280464832782766ee68eMathias Agopian * has been made to make them interchangeable. This class operates under 221f5762e646bed2290934280464832782766ee68eMathias Agopian * a very different set of assumptions and constraints. 231f5762e646bed2290934280464832782766ee68eMathias Agopian * 241f5762e646bed2290934280464832782766ee68eMathias Agopian * One such assumption is that if you're getting file descriptors for 251f5762e646bed2290934280464832782766ee68eMathias Agopian * use with this class as a child of a fork() operation, you must be on 261f5762e646bed2290934280464832782766ee68eMathias Agopian * a pread() to guarantee correct operation. This is because pread() can 271f5762e646bed2290934280464832782766ee68eMathias Agopian * atomically read at a file offset without worrying about a lock around an 281f5762e646bed2290934280464832782766ee68eMathias Agopian * lseek() + read() pair. 291f5762e646bed2290934280464832782766ee68eMathias Agopian */ 301f5762e646bed2290934280464832782766ee68eMathias Agopian#ifndef __LIBS_ZIPFILERO_H 311f5762e646bed2290934280464832782766ee68eMathias Agopian#define __LIBS_ZIPFILERO_H 321f5762e646bed2290934280464832782766ee68eMathias Agopian 331f5762e646bed2290934280464832782766ee68eMathias Agopian#include <utils/Compat.h> 341f5762e646bed2290934280464832782766ee68eMathias Agopian#include <utils/Errors.h> 351f5762e646bed2290934280464832782766ee68eMathias Agopian#include <utils/FileMap.h> 361f5762e646bed2290934280464832782766ee68eMathias Agopian#include <utils/threads.h> 371f5762e646bed2290934280464832782766ee68eMathias Agopian 381f5762e646bed2290934280464832782766ee68eMathias Agopian#include <stdio.h> 391f5762e646bed2290934280464832782766ee68eMathias Agopian#include <stdlib.h> 401f5762e646bed2290934280464832782766ee68eMathias Agopian#include <unistd.h> 411f5762e646bed2290934280464832782766ee68eMathias Agopian#include <time.h> 421f5762e646bed2290934280464832782766ee68eMathias Agopian 431f5762e646bed2290934280464832782766ee68eMathias Agopiannamespace android { 441f5762e646bed2290934280464832782766ee68eMathias Agopian 451f5762e646bed2290934280464832782766ee68eMathias Agopian/* 461f5762e646bed2290934280464832782766ee68eMathias Agopian * Trivial typedef to ensure that ZipEntryRO is not treated as a simple 471f5762e646bed2290934280464832782766ee68eMathias Agopian * integer. We use NULL to indicate an invalid value. 481f5762e646bed2290934280464832782766ee68eMathias Agopian */ 491f5762e646bed2290934280464832782766ee68eMathias Agopiantypedef void* ZipEntryRO; 501f5762e646bed2290934280464832782766ee68eMathias Agopian 511f5762e646bed2290934280464832782766ee68eMathias Agopian/* 521f5762e646bed2290934280464832782766ee68eMathias Agopian * Open a Zip archive for reading. 531f5762e646bed2290934280464832782766ee68eMathias Agopian * 541f5762e646bed2290934280464832782766ee68eMathias Agopian * We want "open" and "find entry by name" to be fast operations, and we 551f5762e646bed2290934280464832782766ee68eMathias Agopian * want to use as little memory as possible. We memory-map the file, 561f5762e646bed2290934280464832782766ee68eMathias Agopian * and load a hash table with pointers to the filenames (which aren't 571f5762e646bed2290934280464832782766ee68eMathias Agopian * null-terminated). The other fields are at a fixed offset from the 581f5762e646bed2290934280464832782766ee68eMathias Agopian * filename, so we don't need to extract those (but we do need to byte-read 591f5762e646bed2290934280464832782766ee68eMathias Agopian * and endian-swap them every time we want them). 601f5762e646bed2290934280464832782766ee68eMathias Agopian * 611f5762e646bed2290934280464832782766ee68eMathias Agopian * To speed comparisons when doing a lookup by name, we could make the mapping 621f5762e646bed2290934280464832782766ee68eMathias Agopian * "private" (copy-on-write) and null-terminate the filenames after verifying 631f5762e646bed2290934280464832782766ee68eMathias Agopian * the record structure. However, this requires a private mapping of 641f5762e646bed2290934280464832782766ee68eMathias Agopian * every page that the Central Directory touches. Easier to tuck a copy 651f5762e646bed2290934280464832782766ee68eMathias Agopian * of the string length into the hash table entry. 661f5762e646bed2290934280464832782766ee68eMathias Agopian * 671f5762e646bed2290934280464832782766ee68eMathias Agopian * NOTE: If this is used on file descriptors inherited from a fork() operation, 681f5762e646bed2290934280464832782766ee68eMathias Agopian * you must be on a platform that implements pread() to guarantee correctness 691f5762e646bed2290934280464832782766ee68eMathias Agopian * on the shared file descriptors. 701f5762e646bed2290934280464832782766ee68eMathias Agopian */ 711f5762e646bed2290934280464832782766ee68eMathias Agopianclass ZipFileRO { 721f5762e646bed2290934280464832782766ee68eMathias Agopianpublic: 731f5762e646bed2290934280464832782766ee68eMathias Agopian ZipFileRO() 741f5762e646bed2290934280464832782766ee68eMathias Agopian : mFd(-1), mFileName(NULL), mFileLength(-1), 751f5762e646bed2290934280464832782766ee68eMathias Agopian mDirectoryMap(NULL), 761f5762e646bed2290934280464832782766ee68eMathias Agopian mNumEntries(-1), mDirectoryOffset(-1), 771f5762e646bed2290934280464832782766ee68eMathias Agopian mHashTableSize(-1), mHashTable(NULL) 781f5762e646bed2290934280464832782766ee68eMathias Agopian {} 791f5762e646bed2290934280464832782766ee68eMathias Agopian 801f5762e646bed2290934280464832782766ee68eMathias Agopian ~ZipFileRO(); 811f5762e646bed2290934280464832782766ee68eMathias Agopian 821f5762e646bed2290934280464832782766ee68eMathias Agopian /* 831f5762e646bed2290934280464832782766ee68eMathias Agopian * Open an archive. 841f5762e646bed2290934280464832782766ee68eMathias Agopian */ 851f5762e646bed2290934280464832782766ee68eMathias Agopian status_t open(const char* zipFileName); 861f5762e646bed2290934280464832782766ee68eMathias Agopian 871f5762e646bed2290934280464832782766ee68eMathias Agopian /* 881f5762e646bed2290934280464832782766ee68eMathias Agopian * Find an entry, by name. Returns the entry identifier, or NULL if 891f5762e646bed2290934280464832782766ee68eMathias Agopian * not found. 901f5762e646bed2290934280464832782766ee68eMathias Agopian * 911f5762e646bed2290934280464832782766ee68eMathias Agopian * If two entries have the same name, one will be chosen at semi-random. 921f5762e646bed2290934280464832782766ee68eMathias Agopian */ 931f5762e646bed2290934280464832782766ee68eMathias Agopian ZipEntryRO findEntryByName(const char* fileName) const; 941f5762e646bed2290934280464832782766ee68eMathias Agopian 951f5762e646bed2290934280464832782766ee68eMathias Agopian /* 961f5762e646bed2290934280464832782766ee68eMathias Agopian * Return the #of entries in the Zip archive. 971f5762e646bed2290934280464832782766ee68eMathias Agopian */ 981f5762e646bed2290934280464832782766ee68eMathias Agopian int getNumEntries(void) const { 991f5762e646bed2290934280464832782766ee68eMathias Agopian return mNumEntries; 1001f5762e646bed2290934280464832782766ee68eMathias Agopian } 1011f5762e646bed2290934280464832782766ee68eMathias Agopian 1021f5762e646bed2290934280464832782766ee68eMathias Agopian /* 1031f5762e646bed2290934280464832782766ee68eMathias Agopian * Return the Nth entry. Zip file entries are not stored in sorted 1041f5762e646bed2290934280464832782766ee68eMathias Agopian * order, and updated entries may appear at the end, so anyone walking 1051f5762e646bed2290934280464832782766ee68eMathias Agopian * the archive needs to avoid making ordering assumptions. We take 1061f5762e646bed2290934280464832782766ee68eMathias Agopian * that further by returning the Nth non-empty entry in the hash table 1071f5762e646bed2290934280464832782766ee68eMathias Agopian * rather than the Nth entry in the archive. 1081f5762e646bed2290934280464832782766ee68eMathias Agopian * 1091f5762e646bed2290934280464832782766ee68eMathias Agopian * Valid values are [0..numEntries). 1101f5762e646bed2290934280464832782766ee68eMathias Agopian * 1111f5762e646bed2290934280464832782766ee68eMathias Agopian * [This is currently O(n). If it needs to be fast we can allocate an 1121f5762e646bed2290934280464832782766ee68eMathias Agopian * additional data structure or provide an iterator interface.] 1131f5762e646bed2290934280464832782766ee68eMathias Agopian */ 1141f5762e646bed2290934280464832782766ee68eMathias Agopian ZipEntryRO findEntryByIndex(int idx) const; 1151f5762e646bed2290934280464832782766ee68eMathias Agopian 1161f5762e646bed2290934280464832782766ee68eMathias Agopian /* 1171f5762e646bed2290934280464832782766ee68eMathias Agopian * Copy the filename into the supplied buffer. Returns 0 on success, 1181f5762e646bed2290934280464832782766ee68eMathias Agopian * -1 if "entry" is invalid, or the filename length if it didn't fit. The 1191f5762e646bed2290934280464832782766ee68eMathias Agopian * length, and the returned string, include the null-termination. 1201f5762e646bed2290934280464832782766ee68eMathias Agopian */ 1211f5762e646bed2290934280464832782766ee68eMathias Agopian int getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen) const; 1221f5762e646bed2290934280464832782766ee68eMathias Agopian 1231f5762e646bed2290934280464832782766ee68eMathias Agopian /* 1241f5762e646bed2290934280464832782766ee68eMathias Agopian * Get the vital stats for an entry. Pass in NULL pointers for anything 1251f5762e646bed2290934280464832782766ee68eMathias Agopian * you don't need. 1261f5762e646bed2290934280464832782766ee68eMathias Agopian * 1271f5762e646bed2290934280464832782766ee68eMathias Agopian * "*pOffset" holds the Zip file offset of the entry's data. 1281f5762e646bed2290934280464832782766ee68eMathias Agopian * 1291f5762e646bed2290934280464832782766ee68eMathias Agopian * Returns "false" if "entry" is bogus or if the data in the Zip file 1301f5762e646bed2290934280464832782766ee68eMathias Agopian * appears to be bad. 1311f5762e646bed2290934280464832782766ee68eMathias Agopian */ 1321f5762e646bed2290934280464832782766ee68eMathias Agopian bool getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen, 1331f5762e646bed2290934280464832782766ee68eMathias Agopian size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const; 1341f5762e646bed2290934280464832782766ee68eMathias Agopian 1351f5762e646bed2290934280464832782766ee68eMathias Agopian /* 1361f5762e646bed2290934280464832782766ee68eMathias Agopian * Create a new FileMap object that maps a subset of the archive. For 1371f5762e646bed2290934280464832782766ee68eMathias Agopian * an uncompressed entry this effectively provides a pointer to the 1381f5762e646bed2290934280464832782766ee68eMathias Agopian * actual data, for a compressed entry this provides the input buffer 1391f5762e646bed2290934280464832782766ee68eMathias Agopian * for inflate(). 1401f5762e646bed2290934280464832782766ee68eMathias Agopian */ 1411f5762e646bed2290934280464832782766ee68eMathias Agopian FileMap* createEntryFileMap(ZipEntryRO entry) const; 1421f5762e646bed2290934280464832782766ee68eMathias Agopian 1431f5762e646bed2290934280464832782766ee68eMathias Agopian /* 1441f5762e646bed2290934280464832782766ee68eMathias Agopian * Uncompress the data into a buffer. Depending on the compression 1451f5762e646bed2290934280464832782766ee68eMathias Agopian * format, this is either an "inflate" operation or a memcpy. 1461f5762e646bed2290934280464832782766ee68eMathias Agopian * 1471f5762e646bed2290934280464832782766ee68eMathias Agopian * Use "uncompLen" from getEntryInfo() to determine the required 1481f5762e646bed2290934280464832782766ee68eMathias Agopian * buffer size. 1491f5762e646bed2290934280464832782766ee68eMathias Agopian * 1501f5762e646bed2290934280464832782766ee68eMathias Agopian * Returns "true" on success. 1511f5762e646bed2290934280464832782766ee68eMathias Agopian */ 1521f5762e646bed2290934280464832782766ee68eMathias Agopian bool uncompressEntry(ZipEntryRO entry, void* buffer) const; 1531f5762e646bed2290934280464832782766ee68eMathias Agopian 1541f5762e646bed2290934280464832782766ee68eMathias Agopian /* 1551f5762e646bed2290934280464832782766ee68eMathias Agopian * Uncompress the data to an open file descriptor. 1561f5762e646bed2290934280464832782766ee68eMathias Agopian */ 1571f5762e646bed2290934280464832782766ee68eMathias Agopian bool uncompressEntry(ZipEntryRO entry, int fd) const; 1581f5762e646bed2290934280464832782766ee68eMathias Agopian 1591f5762e646bed2290934280464832782766ee68eMathias Agopian /* Zip compression methods we support */ 1601f5762e646bed2290934280464832782766ee68eMathias Agopian enum { 1611f5762e646bed2290934280464832782766ee68eMathias Agopian kCompressStored = 0, // no compression 1621f5762e646bed2290934280464832782766ee68eMathias Agopian kCompressDeflated = 8, // standard deflate 1631f5762e646bed2290934280464832782766ee68eMathias Agopian }; 1641f5762e646bed2290934280464832782766ee68eMathias Agopian 1651f5762e646bed2290934280464832782766ee68eMathias Agopian /* 1661f5762e646bed2290934280464832782766ee68eMathias Agopian * Utility function: uncompress deflated data, buffer to buffer. 1671f5762e646bed2290934280464832782766ee68eMathias Agopian */ 1681f5762e646bed2290934280464832782766ee68eMathias Agopian static bool inflateBuffer(void* outBuf, const void* inBuf, 1691f5762e646bed2290934280464832782766ee68eMathias Agopian size_t uncompLen, size_t compLen); 1701f5762e646bed2290934280464832782766ee68eMathias Agopian 1711f5762e646bed2290934280464832782766ee68eMathias Agopian /* 1721f5762e646bed2290934280464832782766ee68eMathias Agopian * Utility function: uncompress deflated data, buffer to fd. 1731f5762e646bed2290934280464832782766ee68eMathias Agopian */ 1741f5762e646bed2290934280464832782766ee68eMathias Agopian static bool inflateBuffer(int fd, const void* inBuf, 1751f5762e646bed2290934280464832782766ee68eMathias Agopian size_t uncompLen, size_t compLen); 1761f5762e646bed2290934280464832782766ee68eMathias Agopian 1771f5762e646bed2290934280464832782766ee68eMathias Agopian /* 1781f5762e646bed2290934280464832782766ee68eMathias Agopian * Utility function to convert ZIP's time format to a timespec struct. 1791f5762e646bed2290934280464832782766ee68eMathias Agopian */ 1801f5762e646bed2290934280464832782766ee68eMathias Agopian static inline void zipTimeToTimespec(long when, struct tm* timespec) { 1811f5762e646bed2290934280464832782766ee68eMathias Agopian const long date = when >> 16; 1821f5762e646bed2290934280464832782766ee68eMathias Agopian timespec->tm_year = ((date >> 9) & 0x7F) + 80; // Zip is years since 1980 1831f5762e646bed2290934280464832782766ee68eMathias Agopian timespec->tm_mon = (date >> 5) & 0x0F; 1841f5762e646bed2290934280464832782766ee68eMathias Agopian timespec->tm_mday = date & 0x1F; 1851f5762e646bed2290934280464832782766ee68eMathias Agopian 1861f5762e646bed2290934280464832782766ee68eMathias Agopian timespec->tm_hour = (when >> 11) & 0x1F; 1871f5762e646bed2290934280464832782766ee68eMathias Agopian timespec->tm_min = (when >> 5) & 0x3F; 1881f5762e646bed2290934280464832782766ee68eMathias Agopian timespec->tm_sec = (when & 0x1F) << 1; 1891f5762e646bed2290934280464832782766ee68eMathias Agopian } 1901f5762e646bed2290934280464832782766ee68eMathias Agopian 1911f5762e646bed2290934280464832782766ee68eMathias Agopian /* 1921f5762e646bed2290934280464832782766ee68eMathias Agopian * Some basic functions for raw data manipulation. "LE" means 1931f5762e646bed2290934280464832782766ee68eMathias Agopian * Little Endian. 1941f5762e646bed2290934280464832782766ee68eMathias Agopian */ 1951f5762e646bed2290934280464832782766ee68eMathias Agopian static inline unsigned short get2LE(const unsigned char* buf) { 1961f5762e646bed2290934280464832782766ee68eMathias Agopian return buf[0] | (buf[1] << 8); 1971f5762e646bed2290934280464832782766ee68eMathias Agopian } 1981f5762e646bed2290934280464832782766ee68eMathias Agopian static inline unsigned long get4LE(const unsigned char* buf) { 1991f5762e646bed2290934280464832782766ee68eMathias Agopian return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); 2001f5762e646bed2290934280464832782766ee68eMathias Agopian } 2011f5762e646bed2290934280464832782766ee68eMathias Agopian 2021f5762e646bed2290934280464832782766ee68eMathias Agopianprivate: 2031f5762e646bed2290934280464832782766ee68eMathias Agopian /* these are private and not defined */ 2041f5762e646bed2290934280464832782766ee68eMathias Agopian ZipFileRO(const ZipFileRO& src); 2051f5762e646bed2290934280464832782766ee68eMathias Agopian ZipFileRO& operator=(const ZipFileRO& src); 2061f5762e646bed2290934280464832782766ee68eMathias Agopian 2071f5762e646bed2290934280464832782766ee68eMathias Agopian /* locate and parse the central directory */ 2081f5762e646bed2290934280464832782766ee68eMathias Agopian bool mapCentralDirectory(void); 2091f5762e646bed2290934280464832782766ee68eMathias Agopian 2101f5762e646bed2290934280464832782766ee68eMathias Agopian /* parse the archive, prepping internal structures */ 2111f5762e646bed2290934280464832782766ee68eMathias Agopian bool parseZipArchive(void); 2121f5762e646bed2290934280464832782766ee68eMathias Agopian 2131f5762e646bed2290934280464832782766ee68eMathias Agopian /* add a new entry to the hash table */ 2141f5762e646bed2290934280464832782766ee68eMathias Agopian void addToHash(const char* str, int strLen, unsigned int hash); 2151f5762e646bed2290934280464832782766ee68eMathias Agopian 2161f5762e646bed2290934280464832782766ee68eMathias Agopian /* compute string hash code */ 2171f5762e646bed2290934280464832782766ee68eMathias Agopian static unsigned int computeHash(const char* str, int len); 2181f5762e646bed2290934280464832782766ee68eMathias Agopian 2191f5762e646bed2290934280464832782766ee68eMathias Agopian /* convert a ZipEntryRO back to a hash table index */ 2201f5762e646bed2290934280464832782766ee68eMathias Agopian int entryToIndex(const ZipEntryRO entry) const; 2211f5762e646bed2290934280464832782766ee68eMathias Agopian 2221f5762e646bed2290934280464832782766ee68eMathias Agopian /* 2231f5762e646bed2290934280464832782766ee68eMathias Agopian * One entry in the hash table. 2241f5762e646bed2290934280464832782766ee68eMathias Agopian */ 2251f5762e646bed2290934280464832782766ee68eMathias Agopian typedef struct HashEntry { 2261f5762e646bed2290934280464832782766ee68eMathias Agopian const char* name; 2271f5762e646bed2290934280464832782766ee68eMathias Agopian unsigned short nameLen; 2281f5762e646bed2290934280464832782766ee68eMathias Agopian //unsigned int hash; 2291f5762e646bed2290934280464832782766ee68eMathias Agopian } HashEntry; 2301f5762e646bed2290934280464832782766ee68eMathias Agopian 2311f5762e646bed2290934280464832782766ee68eMathias Agopian /* open Zip archive */ 2321f5762e646bed2290934280464832782766ee68eMathias Agopian int mFd; 2331f5762e646bed2290934280464832782766ee68eMathias Agopian 2341f5762e646bed2290934280464832782766ee68eMathias Agopian /* Lock for handling the file descriptor (seeks, etc) */ 2351f5762e646bed2290934280464832782766ee68eMathias Agopian mutable Mutex mFdLock; 2361f5762e646bed2290934280464832782766ee68eMathias Agopian 2371f5762e646bed2290934280464832782766ee68eMathias Agopian /* zip file name */ 2381f5762e646bed2290934280464832782766ee68eMathias Agopian char* mFileName; 2391f5762e646bed2290934280464832782766ee68eMathias Agopian 2401f5762e646bed2290934280464832782766ee68eMathias Agopian /* length of file */ 2411f5762e646bed2290934280464832782766ee68eMathias Agopian size_t mFileLength; 2421f5762e646bed2290934280464832782766ee68eMathias Agopian 2431f5762e646bed2290934280464832782766ee68eMathias Agopian /* mapped file */ 2441f5762e646bed2290934280464832782766ee68eMathias Agopian FileMap* mDirectoryMap; 2451f5762e646bed2290934280464832782766ee68eMathias Agopian 2461f5762e646bed2290934280464832782766ee68eMathias Agopian /* number of entries in the Zip archive */ 2471f5762e646bed2290934280464832782766ee68eMathias Agopian int mNumEntries; 2481f5762e646bed2290934280464832782766ee68eMathias Agopian 2491f5762e646bed2290934280464832782766ee68eMathias Agopian /* CD directory offset in the Zip archive */ 2501f5762e646bed2290934280464832782766ee68eMathias Agopian off64_t mDirectoryOffset; 2511f5762e646bed2290934280464832782766ee68eMathias Agopian 2521f5762e646bed2290934280464832782766ee68eMathias Agopian /* 2531f5762e646bed2290934280464832782766ee68eMathias Agopian * We know how many entries are in the Zip archive, so we have a 2541f5762e646bed2290934280464832782766ee68eMathias Agopian * fixed-size hash table. We probe for an empty slot. 2551f5762e646bed2290934280464832782766ee68eMathias Agopian */ 2561f5762e646bed2290934280464832782766ee68eMathias Agopian int mHashTableSize; 2571f5762e646bed2290934280464832782766ee68eMathias Agopian HashEntry* mHashTable; 2581f5762e646bed2290934280464832782766ee68eMathias Agopian}; 2591f5762e646bed2290934280464832782766ee68eMathias Agopian 2601f5762e646bed2290934280464832782766ee68eMathias Agopian}; // namespace android 2611f5762e646bed2290934280464832782766ee68eMathias Agopian 2621f5762e646bed2290934280464832782766ee68eMathias Agopian#endif /*__LIBS_ZIPFILERO_H*/ 263