From 809af3aa03294a8de2cb9cfee6e2686a2bf99ac1 Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Mon, 27 Jan 2014 10:29:16 -0800 Subject: [PATCH] Moved androidfw back to frameworks/base Change-Id: Idd57bbbc86c936cbfd60e02f8ac8d4f8fbc94592 --- include/androidfw/Asset.h | 322 -- include/androidfw/AssetDir.h | 145 - include/androidfw/AssetManager.h | 374 -- include/androidfw/BackupHelpers.h | 169 - include/androidfw/CursorWindow.h | 193 - include/androidfw/ObbFile.h | 145 - include/androidfw/PowerManager.h | 33 - include/androidfw/ResourceTypes.h | 1605 --------- include/androidfw/StreamingZipInflater.h | 84 - include/androidfw/ZipFileRO.h | 170 - include/androidfw/ZipUtils.h | 83 - include/androidfw/misc.h | 49 - libs/androidfw/Android.mk | 96 - libs/androidfw/Asset.cpp | 897 ----- libs/androidfw/AssetDir.cpp | 66 - libs/androidfw/AssetManager.cpp | 2035 ----------- libs/androidfw/BackupData.cpp | 382 -- libs/androidfw/BackupHelpers.cpp | 1591 -------- libs/androidfw/CursorWindow.cpp | 352 -- libs/androidfw/MODULE_LICENSE_APACHE2 | 0 libs/androidfw/NOTICE | 190 - libs/androidfw/ObbFile.cpp | 345 -- libs/androidfw/ResourceTypes.cpp | 5796 ------------------------------ libs/androidfw/StreamingZipInflater.cpp | 242 -- libs/androidfw/ZipFileRO.cpp | 249 -- libs/androidfw/ZipUtils.cpp | 330 -- libs/androidfw/misc.cpp | 83 - libs/androidfw/tests/Android.mk | 32 - libs/androidfw/tests/BackupData_test.cpp | 438 --- libs/androidfw/tests/ObbFile_test.cpp | 102 - libs/androidfw/tests/ZipUtils_test.cpp | 64 - 31 files changed, 16662 deletions(-) delete mode 100644 include/androidfw/Asset.h delete mode 100644 include/androidfw/AssetDir.h delete mode 100644 include/androidfw/AssetManager.h delete mode 100644 include/androidfw/BackupHelpers.h delete mode 100644 include/androidfw/CursorWindow.h delete mode 100644 include/androidfw/ObbFile.h delete mode 100644 include/androidfw/PowerManager.h delete mode 100644 include/androidfw/ResourceTypes.h delete mode 100644 include/androidfw/StreamingZipInflater.h delete mode 100644 include/androidfw/ZipFileRO.h delete mode 100644 include/androidfw/ZipUtils.h delete mode 100644 include/androidfw/misc.h delete mode 100644 libs/androidfw/Android.mk delete mode 100644 libs/androidfw/Asset.cpp delete mode 100644 libs/androidfw/AssetDir.cpp delete mode 100644 libs/androidfw/AssetManager.cpp delete mode 100644 libs/androidfw/BackupData.cpp delete mode 100644 libs/androidfw/BackupHelpers.cpp delete mode 100644 libs/androidfw/CursorWindow.cpp delete mode 100644 libs/androidfw/MODULE_LICENSE_APACHE2 delete mode 100644 libs/androidfw/NOTICE delete mode 100644 libs/androidfw/ObbFile.cpp delete mode 100644 libs/androidfw/ResourceTypes.cpp delete mode 100644 libs/androidfw/StreamingZipInflater.cpp delete mode 100644 libs/androidfw/ZipFileRO.cpp delete mode 100644 libs/androidfw/ZipUtils.cpp delete mode 100644 libs/androidfw/misc.cpp delete mode 100644 libs/androidfw/tests/Android.mk delete mode 100644 libs/androidfw/tests/BackupData_test.cpp delete mode 100644 libs/androidfw/tests/ObbFile_test.cpp delete mode 100644 libs/androidfw/tests/ZipUtils_test.cpp diff --git a/include/androidfw/Asset.h b/include/androidfw/Asset.h deleted file mode 100644 index 1fe0e063c8..0000000000 --- a/include/androidfw/Asset.h +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (C) 2006 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. - */ - -// -// Class providing access to a read-only asset. Asset objects are NOT -// thread-safe, and should not be shared across threads. -// -#ifndef __LIBS_ASSET_H -#define __LIBS_ASSET_H - -#include -#include - -#include -#include -#include -#include - -namespace android { - -/* - * Instances of this class provide read-only operations on a byte stream. - * - * Access may be optimized for streaming, random, or whole buffer modes. All - * operations are supported regardless of how the file was opened, but some - * things will be less efficient. [pass that in??] - * - * "Asset" is the base class for all types of assets. The classes below - * provide most of the implementation. The AssetManager uses one of the - * static "create" functions defined here to create a new instance. - */ -class Asset { -public: - virtual ~Asset(void); - - static int32_t getGlobalCount(); - static String8 getAssetAllocations(); - - /* used when opening an asset */ - typedef enum AccessMode { - ACCESS_UNKNOWN = 0, - - /* read chunks, and seek forward and backward */ - ACCESS_RANDOM, - - /* read sequentially, with an occasional forward seek */ - ACCESS_STREAMING, - - /* caller plans to ask for a read-only buffer with all data */ - ACCESS_BUFFER, - } AccessMode; - - /* - * Read data from the current offset. Returns the actual number of - * bytes read, 0 on EOF, or -1 on error. - */ - virtual ssize_t read(void* buf, size_t count) = 0; - - /* - * Seek to the specified offset. "whence" uses the same values as - * lseek/fseek. Returns the new position on success, or (off64_t) -1 - * on failure. - */ - virtual off64_t seek(off64_t offset, int whence) = 0; - - /* - * Close the asset, freeing all associated resources. - */ - virtual void close(void) = 0; - - /* - * Get a pointer to a buffer with the entire contents of the file. - */ - virtual const void* getBuffer(bool wordAligned) = 0; - - /* - * Get the total amount of data that can be read. - */ - virtual off64_t getLength(void) const = 0; - - /* - * Get the total amount of data that can be read from the current position. - */ - virtual off64_t getRemainingLength(void) const = 0; - - /* - * Open a new file descriptor that can be used to read this asset. - * Returns -1 if you can not use the file descriptor (for example if the - * asset is compressed). - */ - virtual int openFileDescriptor(off64_t* outStart, off64_t* outLength) const = 0; - - /* - * Return whether this asset's buffer is allocated in RAM (not mmapped). - * Note: not virtual so it is safe to call even when being destroyed. - */ - virtual bool isAllocated(void) const { return false; } - - /* - * Get a string identifying the asset's source. This might be a full - * path, it might be a colon-separated list of identifiers. - * - * This is NOT intended to be used for anything except debug output. - * DO NOT try to parse this or use it to open a file. - */ - const char* getAssetSource(void) const { return mAssetSource.string(); } - -protected: - Asset(void); // constructor; only invoked indirectly - - /* handle common seek() housekeeping */ - off64_t handleSeek(off64_t offset, int whence, off64_t curPosn, off64_t maxPosn); - - /* set the asset source string */ - void setAssetSource(const String8& path) { mAssetSource = path; } - - AccessMode getAccessMode(void) const { return mAccessMode; } - -private: - /* these operations are not implemented */ - Asset(const Asset& src); - Asset& operator=(const Asset& src); - - /* AssetManager needs access to our "create" functions */ - friend class AssetManager; - - /* - * Create the asset from a named file on disk. - */ - static Asset* createFromFile(const char* fileName, AccessMode mode); - - /* - * Create the asset from a named, compressed file on disk (e.g. ".gz"). - */ - static Asset* createFromCompressedFile(const char* fileName, - AccessMode mode); - -#if 0 - /* - * Create the asset from a segment of an open file. This will fail - * if "offset" and "length" don't fit within the bounds of the file. - * - * The asset takes ownership of the file descriptor. - */ - static Asset* createFromFileSegment(int fd, off64_t offset, size_t length, - AccessMode mode); - - /* - * Create from compressed data. "fd" should be seeked to the start of - * the compressed data. This could be inside a gzip file or part of a - * Zip archive. - * - * The asset takes ownership of the file descriptor. - * - * This may not verify the validity of the compressed data until first - * use. - */ - static Asset* createFromCompressedData(int fd, off64_t offset, - int compressionMethod, size_t compressedLength, - size_t uncompressedLength, AccessMode mode); -#endif - - /* - * Create the asset from a memory-mapped file segment. - * - * The asset takes ownership of the FileMap. - */ - static Asset* createFromUncompressedMap(FileMap* dataMap, AccessMode mode); - - /* - * Create the asset from a memory-mapped file segment with compressed - * data. "method" is a Zip archive compression method constant. - * - * The asset takes ownership of the FileMap. - */ - static Asset* createFromCompressedMap(FileMap* dataMap, int method, - size_t uncompressedLen, AccessMode mode); - - - /* - * Create from a reference-counted chunk of shared memory. - */ - // TODO - - AccessMode mAccessMode; // how the asset was opened - String8 mAssetSource; // debug string - - Asset* mNext; // linked list. - Asset* mPrev; -}; - - -/* - * =========================================================================== - * - * Innards follow. Do not use these classes directly. - */ - -/* - * An asset based on an uncompressed file on disk. It may encompass the - * entire file or just a piece of it. Access is through fread/fseek. - */ -class _FileAsset : public Asset { -public: - _FileAsset(void); - virtual ~_FileAsset(void); - - /* - * Use a piece of an already-open file. - * - * On success, the object takes ownership of "fd". - */ - status_t openChunk(const char* fileName, int fd, off64_t offset, size_t length); - - /* - * Use a memory-mapped region. - * - * On success, the object takes ownership of "dataMap". - */ - status_t openChunk(FileMap* dataMap); - - /* - * Standard Asset interfaces. - */ - virtual ssize_t read(void* buf, size_t count); - virtual off64_t seek(off64_t offset, int whence); - virtual void close(void); - virtual const void* getBuffer(bool wordAligned); - virtual off64_t getLength(void) const { return mLength; } - virtual off64_t getRemainingLength(void) const { return mLength-mOffset; } - virtual int openFileDescriptor(off64_t* outStart, off64_t* outLength) const; - virtual bool isAllocated(void) const { return mBuf != NULL; } - -private: - off64_t mStart; // absolute file offset of start of chunk - off64_t mLength; // length of the chunk - off64_t mOffset; // current local offset, 0 == mStart - FILE* mFp; // for read/seek - char* mFileName; // for opening - - /* - * To support getBuffer() we either need to read the entire thing into - * a buffer or memory-map it. For small files it's probably best to - * just read them in. - */ - enum { kReadVsMapThreshold = 4096 }; - - FileMap* mMap; // for memory map - unsigned char* mBuf; // for read - - const void* ensureAlignment(FileMap* map); -}; - - -/* - * An asset based on compressed data in a file. - */ -class _CompressedAsset : public Asset { -public: - _CompressedAsset(void); - virtual ~_CompressedAsset(void); - - /* - * Use a piece of an already-open file. - * - * On success, the object takes ownership of "fd". - */ - status_t openChunk(int fd, off64_t offset, int compressionMethod, - size_t uncompressedLen, size_t compressedLen); - - /* - * Use a memory-mapped region. - * - * On success, the object takes ownership of "fd". - */ - status_t openChunk(FileMap* dataMap, int compressionMethod, - size_t uncompressedLen); - - /* - * Standard Asset interfaces. - */ - virtual ssize_t read(void* buf, size_t count); - virtual off64_t seek(off64_t offset, int whence); - virtual void close(void); - virtual const void* getBuffer(bool wordAligned); - virtual off64_t getLength(void) const { return mUncompressedLen; } - virtual off64_t getRemainingLength(void) const { return mUncompressedLen-mOffset; } - virtual int openFileDescriptor(off64_t* outStart, off64_t* outLength) const { return -1; } - virtual bool isAllocated(void) const { return mBuf != NULL; } - -private: - off64_t mStart; // offset to start of compressed data - off64_t mCompressedLen; // length of the compressed data - off64_t mUncompressedLen; // length of the uncompressed data - off64_t mOffset; // current offset, 0 == start of uncomp data - - FileMap* mMap; // for memory-mapped input - int mFd; // for file input - - class StreamingZipInflater* mZipInflater; // for streaming large compressed assets - - unsigned char* mBuf; // for getBuffer() -}; - -// need: shared mmap version? - -}; // namespace android - -#endif // __LIBS_ASSET_H diff --git a/include/androidfw/AssetDir.h b/include/androidfw/AssetDir.h deleted file mode 100644 index bd89d7d34b..0000000000 --- a/include/androidfw/AssetDir.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2006 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. - */ - -// -// Access a chunk of the asset hierarchy as if it were a single directory. -// -#ifndef __LIBS_ASSETDIR_H -#define __LIBS_ASSETDIR_H - -#include -#include -#include -#include -#include - -namespace android { - -/* - * This provides vector-style access to a directory. We do this rather - * than modeling opendir/readdir access because it's simpler and the - * nature of the operation requires us to have all data on hand anyway. - * - * The list of files will be sorted in ascending order by ASCII value. - * - * The contents are populated by our friend, the AssetManager. - */ -class AssetDir { -public: - AssetDir(void) - : mFileInfo(NULL) - {} - virtual ~AssetDir(void) { - delete mFileInfo; - } - - /* - * Vector-style access. - */ - size_t getFileCount(void) { return mFileInfo->size(); } - const String8& getFileName(int idx) { - return mFileInfo->itemAt(idx).getFileName(); - } - const String8& getSourceName(int idx) { - return mFileInfo->itemAt(idx).getSourceName(); - } - - /* - * Get the type of a file (usually regular or directory). - */ - FileType getFileType(int idx) { - return mFileInfo->itemAt(idx).getFileType(); - } - -private: - /* these operations are not implemented */ - AssetDir(const AssetDir& src); - const AssetDir& operator=(const AssetDir& src); - - friend class AssetManager; - - /* - * This holds information about files in the asset hierarchy. - */ - class FileInfo { - public: - FileInfo(void) {} - FileInfo(const String8& path) // useful for e.g. svect.indexOf - : mFileName(path), mFileType(kFileTypeUnknown) - {} - ~FileInfo(void) {} - FileInfo(const FileInfo& src) { - copyMembers(src); - } - const FileInfo& operator= (const FileInfo& src) { - if (this != &src) - copyMembers(src); - return *this; - } - - void copyMembers(const FileInfo& src) { - mFileName = src.mFileName; - mFileType = src.mFileType; - mSourceName = src.mSourceName; - } - - /* need this for SortedVector; must compare only on file name */ - bool operator< (const FileInfo& rhs) const { - return mFileName < rhs.mFileName; - } - - /* used by AssetManager */ - bool operator== (const FileInfo& rhs) const { - return mFileName == rhs.mFileName; - } - - void set(const String8& path, FileType type) { - mFileName = path; - mFileType = type; - } - - const String8& getFileName(void) const { return mFileName; } - void setFileName(const String8& path) { mFileName = path; } - - FileType getFileType(void) const { return mFileType; } - void setFileType(FileType type) { mFileType = type; } - - const String8& getSourceName(void) const { return mSourceName; } - void setSourceName(const String8& path) { mSourceName = path; } - - /* - * Handy utility for finding an entry in a sorted vector of FileInfo. - * Returns the index of the matching entry, or -1 if none found. - */ - static int findEntry(const SortedVector* pVector, - const String8& fileName); - - private: - String8 mFileName; // filename only - FileType mFileType; // regular, directory, etc - - String8 mSourceName; // currently debug-only - }; - - /* AssetManager uses this to initialize us */ - void setFileList(SortedVector* list) { mFileInfo = list; } - - SortedVector* mFileInfo; -}; - -}; // namespace android - -#endif // __LIBS_ASSETDIR_H diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h deleted file mode 100644 index a010957826..0000000000 --- a/include/androidfw/AssetManager.h +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright (C) 2006 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. - */ - -// -// Asset management class. AssetManager objects are thread-safe. -// -#ifndef __LIBS_ASSETMANAGER_H -#define __LIBS_ASSETMANAGER_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Native-app access is via the opaque typedef struct AAssetManager in the C namespace. - */ -#ifdef __cplusplus -extern "C" { -#endif - -struct AAssetManager { }; - -#ifdef __cplusplus -}; -#endif - - -/* - * Now the proper C++ android-namespace definitions - */ - -namespace android { - -class Asset; // fwd decl for things that include Asset.h first -class ResTable; -struct ResTable_config; - -/* - * Every application that uses assets needs one instance of this. A - * single instance may be shared across multiple threads, and a single - * thread may have more than one instance (the latter is discouraged). - * - * The purpose of the AssetManager is to create Asset objects. To do - * this efficiently it may cache information about the locations of - * files it has seen. This can be controlled with the "cacheMode" - * argument. - * - * The asset hierarchy may be examined like a filesystem, using - * AssetDir objects to peruse a single directory. - */ -class AssetManager : public AAssetManager { -public: - typedef enum CacheMode { - CACHE_UNKNOWN = 0, - CACHE_OFF, // don't try to cache file locations - CACHE_DEFER, // construct cache as pieces are needed - //CACHE_SCAN, // scan full(!) asset hierarchy at init() time - } CacheMode; - - AssetManager(CacheMode cacheMode = CACHE_OFF); - virtual ~AssetManager(void); - - static int32_t getGlobalCount(); - - /* - * Add a new source for assets. This can be called multiple times to - * look in multiple places for assets. It can be either a directory (for - * finding assets as raw files on the disk) or a ZIP file. This newly - * added asset path will be examined first when searching for assets, - * before any that were previously added. - * - * Returns "true" on success, "false" on failure. If 'cookie' is non-NULL, - * then on success, *cookie is set to the value corresponding to the - * newly-added asset source. - */ - bool addAssetPath(const String8& path, int32_t* cookie); - - /* - * Convenience for adding the standard system assets. Uses the - * ANDROID_ROOT environment variable to find them. - */ - bool addDefaultAssets(); - - /* - * Iterate over the asset paths in this manager. (Previously - * added via addAssetPath() and addDefaultAssets().) On first call, - * 'cookie' must be 0, resulting in the first cookie being returned. - * Each next cookie will be returned there-after, until -1 indicating - * the end has been reached. - */ - int32_t nextAssetPath(const int32_t cookie) const; - - /* - * Return an asset path in the manager. 'which' must be between 0 and - * countAssetPaths(). - */ - String8 getAssetPath(const int32_t cookie) const; - - /* - * Set the current locale and vendor. The locale can change during - * the lifetime of an AssetManager if the user updates the device's - * language setting. The vendor is less likely to change. - * - * Pass in NULL to indicate no preference. - */ - void setLocale(const char* locale); - void setVendor(const char* vendor); - - /* - * Choose screen orientation for resources values returned. - */ - void setConfiguration(const ResTable_config& config, const char* locale = NULL); - - void getConfiguration(ResTable_config* outConfig) const; - - typedef Asset::AccessMode AccessMode; // typing shortcut - - /* - * Open an asset. - * - * This will search through locale-specific and vendor-specific - * directories and packages to find the file. - * - * The object returned does not depend on the AssetManager. It should - * be freed by calling Asset::close(). - */ - Asset* open(const char* fileName, AccessMode mode); - - /* - * Open a non-asset file as an asset. - * - * This is for opening files that are included in an asset package - * but aren't assets. These sit outside the usual "locale/vendor" - * path hierarchy, and will not be seen by "AssetDir" or included - * in our filename cache. - */ - Asset* openNonAsset(const char* fileName, AccessMode mode); - - /* - * Explicit non-asset file. The file explicitly named by the cookie (the - * resource set to look in) and fileName will be opened and returned. - */ - Asset* openNonAsset(const int32_t cookie, const char* fileName, AccessMode mode); - - /* - * Open a directory within the asset hierarchy. - * - * The contents of the directory are an amalgam of vendor-specific, - * locale-specific, and generic assets stored loosely or in asset - * packages. Depending on the cache setting and previous accesses, - * this call may incur significant disk overhead. - * - * To open the top-level directory, pass in "". - */ - AssetDir* openDir(const char* dirName); - - /* - * Open a directory within a particular path of the asset manager. - * - * The contents of the directory are an amalgam of vendor-specific, - * locale-specific, and generic assets stored loosely or in asset - * packages. Depending on the cache setting and previous accesses, - * this call may incur significant disk overhead. - * - * To open the top-level directory, pass in "". - */ - AssetDir* openNonAssetDir(const int32_t cookie, const char* dirName); - - /* - * Get the type of a file in the asset hierarchy. They will either - * be "regular" or "directory". [Currently only works for "regular".] - * - * Can also be used as a quick test for existence of a file. - */ - FileType getFileType(const char* fileName); - - /* - * Return the complete resource table to find things in the package. - */ - const ResTable& getResources(bool required = true) const; - - /* - * Discard cached filename information. This only needs to be called - * if somebody has updated the set of "loose" files, and we want to - * discard our cached notion of what's where. - */ - void purge(void) { purgeFileNameCacheLocked(); } - - /* - * Return true if the files this AssetManager references are all - * up-to-date (have not been changed since it was created). If false - * is returned, you will need to create a new AssetManager to get - * the current data. - */ - bool isUpToDate(); - - /** - * Get the known locales for this asset manager object. - */ - void getLocales(Vector* locales) const; - -private: - struct asset_path - { - String8 path; - FileType type; - String8 idmap; - }; - - Asset* openInPathLocked(const char* fileName, AccessMode mode, - const asset_path& path); - Asset* openNonAssetInPathLocked(const char* fileName, AccessMode mode, - const asset_path& path); - Asset* openInLocaleVendorLocked(const char* fileName, AccessMode mode, - const asset_path& path, const char* locale, const char* vendor); - String8 createPathNameLocked(const asset_path& path, const char* locale, - const char* vendor); - String8 createPathNameLocked(const asset_path& path, const char* rootDir); - String8 createZipSourceNameLocked(const String8& zipFileName, - const String8& dirName, const String8& fileName); - - ZipFileRO* getZipFileLocked(const asset_path& path); - Asset* openAssetFromFileLocked(const String8& fileName, AccessMode mode); - Asset* openAssetFromZipLocked(const ZipFileRO* pZipFile, - const ZipEntryRO entry, AccessMode mode, const String8& entryName); - - bool scanAndMergeDirLocked(SortedVector* pMergedInfo, - const asset_path& path, const char* rootDir, const char* dirName); - SortedVector* scanDirLocked(const String8& path); - bool scanAndMergeZipLocked(SortedVector* pMergedInfo, - const asset_path& path, const char* rootDir, const char* dirName); - void mergeInfoLocked(SortedVector* pMergedInfo, - const SortedVector* pContents); - - void loadFileNameCacheLocked(void); - void fncScanLocked(SortedVector* pMergedInfo, - const char* dirName); - bool fncScanAndMergeDirLocked( - SortedVector* pMergedInfo, - const asset_path& path, const char* locale, const char* vendor, - const char* dirName); - void purgeFileNameCacheLocked(void); - - const ResTable* getResTable(bool required = true) const; - void setLocaleLocked(const char* locale); - void updateResourceParamsLocked() const; - - bool createIdmapFileLocked(const String8& originalPath, const String8& overlayPath, - const String8& idmapPath); - - bool isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath, - const String8& idmapPath); - - Asset* openIdmapLocked(const struct asset_path& ap) const; - - bool getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename, uint32_t* pCrc); - - class SharedZip : public RefBase { - public: - static sp get(const String8& path); - - ZipFileRO* getZip(); - - Asset* getResourceTableAsset(); - Asset* setResourceTableAsset(Asset* asset); - - ResTable* getResourceTable(); - ResTable* setResourceTable(ResTable* res); - - bool isUpToDate(); - - protected: - ~SharedZip(); - - private: - SharedZip(const String8& path, time_t modWhen); - SharedZip(); // <-- not implemented - - String8 mPath; - ZipFileRO* mZipFile; - time_t mModWhen; - - Asset* mResourceTableAsset; - ResTable* mResourceTable; - - static Mutex gLock; - static DefaultKeyedVector > gOpen; - }; - - /* - * Manage a set of Zip files. For each file we need a pointer to the - * ZipFile and a time_t with the file's modification date. - * - * We currently only have two zip files (current app, "common" app). - * (This was originally written for 8, based on app/locale/vendor.) - */ - class ZipSet { - public: - ZipSet(void); - ~ZipSet(void); - - /* - * Return a ZipFileRO structure for a ZipFileRO with the specified - * parameters. - */ - ZipFileRO* getZip(const String8& path); - - Asset* getZipResourceTableAsset(const String8& path); - Asset* setZipResourceTableAsset(const String8& path, Asset* asset); - - ResTable* getZipResourceTable(const String8& path); - ResTable* setZipResourceTable(const String8& path, ResTable* res); - - // generate path, e.g. "common/en-US-noogle.zip" - static String8 getPathName(const char* path); - - bool isUpToDate(); - - private: - void closeZip(int idx); - - int getIndex(const String8& zip) const; - mutable Vector mZipPath; - mutable Vector > mZipFile; - }; - - // Protect all internal state. - mutable Mutex mLock; - - ZipSet mZipSet; - - Vector mAssetPaths; - char* mLocale; - char* mVendor; - - mutable ResTable* mResources; - ResTable_config* mConfig; - - /* - * Cached data for "loose" files. This lets us avoid poking at the - * filesystem when searching for loose assets. Each entry is the - * "extended partial" path, e.g. "default/default/foo/bar.txt". The - * full set of files is present, including ".EXCLUDE" entries. - * - * We do not cache directory names. We don't retain the ".gz", - * because to our clients "foo" and "foo.gz" both look like "foo". - */ - CacheMode mCacheMode; // is the cache enabled? - bool mCacheValid; // clear when locale or vendor changes - SortedVector mCache; -}; - -}; // namespace android - -#endif // __LIBS_ASSETMANAGER_H diff --git a/include/androidfw/BackupHelpers.h b/include/androidfw/BackupHelpers.h deleted file mode 100644 index 1bb04a7123..0000000000 --- a/include/androidfw/BackupHelpers.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2009 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 _UTILS_BACKUP_HELPERS_H -#define _UTILS_BACKUP_HELPERS_H - -#include -#include -#include - -namespace android { - -enum { - BACKUP_HEADER_ENTITY_V1 = 0x61746144, // Data (little endian) -}; - -typedef struct { - int type; // BACKUP_HEADER_ENTITY_V1 - int keyLen; // length of the key name, not including the null terminator - int dataSize; // size of the data, not including the padding, -1 means delete -} entity_header_v1; - -struct SnapshotHeader { - int magic0; - int fileCount; - int magic1; - int totalSize; -}; - -struct FileState { - int modTime_sec; - int modTime_nsec; - int mode; - int size; - int crc32; - int nameLen; -}; - -struct FileRec { - String8 file; - bool deleted; - FileState s; -}; - - -/** - * Writes the data. - * - * If an error occurs, it poisons this object and all write calls will fail - * with the error that occurred. - */ -class BackupDataWriter -{ -public: - BackupDataWriter(int fd); - // does not close fd - ~BackupDataWriter(); - - status_t WriteEntityHeader(const String8& key, size_t dataSize); - - /* Note: WriteEntityData will write arbitrary data into the file without - * validation or a previously-supplied header. The full backup implementation - * uses it this way to generate a controlled binary stream that is not - * entity-structured. If the implementation here is changed, either this - * use case must remain valid, or the full backup implementation should be - * adjusted to use some other appropriate mechanism. - */ - status_t WriteEntityData(const void* data, size_t size); - - void SetKeyPrefix(const String8& keyPrefix); - -private: - explicit BackupDataWriter(); - status_t write_padding_for(int n); - - int m_fd; - status_t m_status; - ssize_t m_pos; - int m_entityCount; - String8 m_keyPrefix; -}; - -/** - * Reads the data. - * - * If an error occurs, it poisons this object and all write calls will fail - * with the error that occurred. - */ -class BackupDataReader -{ -public: - BackupDataReader(int fd); - // does not close fd - ~BackupDataReader(); - - status_t Status(); - status_t ReadNextHeader(bool* done, int* type); - - bool HasEntities(); - status_t ReadEntityHeader(String8* key, size_t* dataSize); - status_t SkipEntityData(); // must be called with the pointer at the beginning of the data. - ssize_t ReadEntityData(void* data, size_t size); - -private: - explicit BackupDataReader(); - status_t skip_padding(); - - int m_fd; - bool m_done; - status_t m_status; - ssize_t m_pos; - ssize_t m_dataEndPos; - int m_entityCount; - union { - int type; - entity_header_v1 entity; - } m_header; - String8 m_key; -}; - -int back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD, - char const* const* files, char const* const *keys, int fileCount); - -int write_tarfile(const String8& packageName, const String8& domain, - const String8& rootPath, const String8& filePath, BackupDataWriter* outputStream); - -class RestoreHelperBase -{ -public: - RestoreHelperBase(); - ~RestoreHelperBase(); - - status_t WriteFile(const String8& filename, BackupDataReader* in); - status_t WriteSnapshot(int fd); - -private: - void* m_buf; - bool m_loggedUnknownMetadata; - KeyedVector m_files; -}; - -#define TEST_BACKUP_HELPERS 1 - -#if TEST_BACKUP_HELPERS -int backup_helper_test_empty(); -int backup_helper_test_four(); -int backup_helper_test_files(); -int backup_helper_test_null_base(); -int backup_helper_test_missing_file(); -int backup_helper_test_data_writer(); -int backup_helper_test_data_reader(); -#endif - -} // namespace android - -#endif // _UTILS_BACKUP_HELPERS_H diff --git a/include/androidfw/CursorWindow.h b/include/androidfw/CursorWindow.h deleted file mode 100644 index 8a2979a375..0000000000 --- a/include/androidfw/CursorWindow.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2006 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 _ANDROID__DATABASE_WINDOW_H -#define _ANDROID__DATABASE_WINDOW_H - -#include -#include -#include - -#include -#include - -#if LOG_NDEBUG - -#define IF_LOG_WINDOW() if (false) -#define LOG_WINDOW(...) - -#else - -#define IF_LOG_WINDOW() IF_ALOG(LOG_DEBUG, "CursorWindow") -#define LOG_WINDOW(...) ALOG(LOG_DEBUG, "CursorWindow", __VA_ARGS__) - -#endif - -namespace android { - -/** - * This class stores a set of rows from a database in a buffer. The begining of the - * window has first chunk of RowSlots, which are offsets to the row directory, followed by - * an offset to the next chunk in a linked-list of additional chunk of RowSlots in case - * the pre-allocated chunk isn't big enough to refer to all rows. Each row directory has a - * FieldSlot per column, which has the size, offset, and type of the data for that field. - * Note that the data types come from sqlite3.h. - * - * Strings are stored in UTF-8. - */ -class CursorWindow { - CursorWindow(const String8& name, int ashmemFd, - void* data, size_t size, bool readOnly); - -public: - /* Field types. */ - enum { - FIELD_TYPE_NULL = 0, - FIELD_TYPE_INTEGER = 1, - FIELD_TYPE_FLOAT = 2, - FIELD_TYPE_STRING = 3, - FIELD_TYPE_BLOB = 4, - }; - - /* Opaque type that describes a field slot. */ - struct FieldSlot { - private: - int32_t type; - union { - double d; - int64_t l; - struct { - uint32_t offset; - uint32_t size; - } buffer; - } data; - - friend class CursorWindow; - } __attribute((packed)); - - ~CursorWindow(); - - static status_t create(const String8& name, size_t size, CursorWindow** outCursorWindow); - static status_t createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow); - - status_t writeToParcel(Parcel* parcel); - - inline String8 name() { return mName; } - inline size_t size() { return mSize; } - inline size_t freeSpace() { return mSize - mHeader->freeOffset; } - inline uint32_t getNumRows() { return mHeader->numRows; } - inline uint32_t getNumColumns() { return mHeader->numColumns; } - - status_t clear(); - status_t setNumColumns(uint32_t numColumns); - - /** - * Allocate a row slot and its directory. - * The row is initialized will null entries for each field. - */ - status_t allocRow(); - status_t freeLastRow(); - - status_t putBlob(uint32_t row, uint32_t column, const void* value, size_t size); - status_t putString(uint32_t row, uint32_t column, const char* value, size_t sizeIncludingNull); - status_t putLong(uint32_t row, uint32_t column, int64_t value); - status_t putDouble(uint32_t row, uint32_t column, double value); - status_t putNull(uint32_t row, uint32_t column); - - /** - * Gets the field slot at the specified row and column. - * Returns null if the requested row or column is not in the window. - */ - FieldSlot* getFieldSlot(uint32_t row, uint32_t column); - - inline int32_t getFieldSlotType(FieldSlot* fieldSlot) { - return fieldSlot->type; - } - - inline int64_t getFieldSlotValueLong(FieldSlot* fieldSlot) { - return fieldSlot->data.l; - } - - inline double getFieldSlotValueDouble(FieldSlot* fieldSlot) { - return fieldSlot->data.d; - } - - inline const char* getFieldSlotValueString(FieldSlot* fieldSlot, - size_t* outSizeIncludingNull) { - *outSizeIncludingNull = fieldSlot->data.buffer.size; - return static_cast(offsetToPtr(fieldSlot->data.buffer.offset)); - } - - inline const void* getFieldSlotValueBlob(FieldSlot* fieldSlot, size_t* outSize) { - *outSize = fieldSlot->data.buffer.size; - return offsetToPtr(fieldSlot->data.buffer.offset); - } - -private: - static const size_t ROW_SLOT_CHUNK_NUM_ROWS = 100; - - struct Header { - // Offset of the lowest unused byte in the window. - uint32_t freeOffset; - - // Offset of the first row slot chunk. - uint32_t firstChunkOffset; - - uint32_t numRows; - uint32_t numColumns; - }; - - struct RowSlot { - uint32_t offset; - }; - - struct RowSlotChunk { - RowSlot slots[ROW_SLOT_CHUNK_NUM_ROWS]; - uint32_t nextChunkOffset; - }; - - String8 mName; - int mAshmemFd; - void* mData; - size_t mSize; - bool mReadOnly; - Header* mHeader; - - inline void* offsetToPtr(uint32_t offset) { - return static_cast(mData) + offset; - } - - inline uint32_t offsetFromPtr(void* ptr) { - return static_cast(ptr) - static_cast(mData); - } - - /** - * Allocate a portion of the window. Returns the offset - * of the allocation, or 0 if there isn't enough space. - * If aligned is true, the allocation gets 4 byte alignment. - */ - uint32_t alloc(size_t size, bool aligned = false); - - RowSlot* getRowSlot(uint32_t row); - RowSlot* allocRowSlot(); - - status_t putBlobOrString(uint32_t row, uint32_t column, - const void* value, size_t size, int32_t type); -}; - -}; // namespace android - -#endif diff --git a/include/androidfw/ObbFile.h b/include/androidfw/ObbFile.h deleted file mode 100644 index 47559cdd0d..0000000000 --- a/include/androidfw/ObbFile.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2010 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 OBBFILE_H_ -#define OBBFILE_H_ - -#include -#include - -#include -#include - -namespace android { - -// OBB flags (bit 0) -#define OBB_OVERLAY (1 << 0) -#define OBB_SALTED (1 << 1) - -class ObbFile : public RefBase { -protected: - virtual ~ObbFile(); - -public: - ObbFile(); - - bool readFrom(const char* filename); - bool readFrom(int fd); - bool writeTo(const char* filename); - bool writeTo(int fd); - bool removeFrom(const char* filename); - bool removeFrom(int fd); - - const char* getFileName() const { - return mFileName; - } - - const String8 getPackageName() const { - return mPackageName; - } - - void setPackageName(String8 packageName) { - mPackageName = packageName; - } - - int32_t getVersion() const { - return mVersion; - } - - void setVersion(int32_t version) { - mVersion = version; - } - - int32_t getFlags() const { - return mFlags; - } - - void setFlags(int32_t flags) { - mFlags = flags; - } - - const unsigned char* getSalt(size_t* length) const { - if ((mFlags & OBB_SALTED) == 0) { - *length = 0; - return NULL; - } - - *length = sizeof(mSalt); - return mSalt; - } - - bool setSalt(const unsigned char* salt, size_t length) { - if (length != sizeof(mSalt)) { - return false; - } - - memcpy(mSalt, salt, sizeof(mSalt)); - mFlags |= OBB_SALTED; - return true; - } - - bool isOverlay() { - return (mFlags & OBB_OVERLAY) == OBB_OVERLAY; - } - - void setOverlay(bool overlay) { - if (overlay) { - mFlags |= OBB_OVERLAY; - } else { - mFlags &= ~OBB_OVERLAY; - } - } - - static inline uint32_t get4LE(const unsigned char* buf) { - return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); - } - - static inline void put4LE(unsigned char* buf, uint32_t val) { - buf[0] = val & 0xFF; - buf[1] = (val >> 8) & 0xFF; - buf[2] = (val >> 16) & 0xFF; - buf[3] = (val >> 24) & 0xFF; - } - -private: - /* Package name this ObbFile is associated with */ - String8 mPackageName; - - /* Package version this ObbFile is associated with */ - int32_t mVersion; - - /* Flags for this OBB type. */ - int32_t mFlags; - - /* Whether the file is salted. */ - bool mSalted; - - /* The encryption salt. */ - unsigned char mSalt[8]; - - const char* mFileName; - - size_t mFileSize; - - size_t mFooterStart; - - unsigned char* mReadBuf; - - bool parseObbFile(int fd); -}; - -} -#endif /* OBBFILE_H_ */ diff --git a/include/androidfw/PowerManager.h b/include/androidfw/PowerManager.h deleted file mode 100644 index ba98db07ca..0000000000 --- a/include/androidfw/PowerManager.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2010 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 _ANDROIDFW_POWER_MANAGER_H -#define _ANDROIDFW_POWER_MANAGER_H - - -namespace android { - -enum { - USER_ACTIVITY_EVENT_OTHER = 0, - USER_ACTIVITY_EVENT_BUTTON = 1, - USER_ACTIVITY_EVENT_TOUCH = 2, - - USER_ACTIVITY_EVENT_LAST = USER_ACTIVITY_EVENT_TOUCH, // Last valid event code. -}; - -} // namespace android - -#endif // _ANDROIDFW_POWER_MANAGER_H diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h deleted file mode 100644 index 5151b06aec..0000000000 --- a/include/androidfw/ResourceTypes.h +++ /dev/null @@ -1,1605 +0,0 @@ -/* - * Copyright (C) 2005 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. - */ - -// -// Definitions of resource data structures. -// -#ifndef _LIBS_UTILS_RESOURCE_TYPES_H -#define _LIBS_UTILS_RESOURCE_TYPES_H - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include - -namespace android { - -/** ******************************************************************** - * PNG Extensions - * - * New private chunks that may be placed in PNG images. - * - *********************************************************************** */ - -/** - * This chunk specifies how to split an image into segments for - * scaling. - * - * There are J horizontal and K vertical segments. These segments divide - * the image into J*K regions as follows (where J=4 and K=3): - * - * F0 S0 F1 S1 - * +-----+----+------+-------+ - * S2| 0 | 1 | 2 | 3 | - * +-----+----+------+-------+ - * | | | | | - * | | | | | - * F2| 4 | 5 | 6 | 7 | - * | | | | | - * | | | | | - * +-----+----+------+-------+ - * S3| 8 | 9 | 10 | 11 | - * +-----+----+------+-------+ - * - * Each horizontal and vertical segment is considered to by either - * stretchable (marked by the Sx labels) or fixed (marked by the Fy - * labels), in the horizontal or vertical axis, respectively. In the - * above example, the first is horizontal segment (F0) is fixed, the - * next is stretchable and then they continue to alternate. Note that - * the segment list for each axis can begin or end with a stretchable - * or fixed segment. - * - * The relative sizes of the stretchy segments indicates the relative - * amount of stretchiness of the regions bordered by the segments. For - * example, regions 3, 7 and 11 above will take up more horizontal space - * than regions 1, 5 and 9 since the horizontal segment associated with - * the first set of regions is larger than the other set of regions. The - * ratios of the amount of horizontal (or vertical) space taken by any - * two stretchable slices is exactly the ratio of their corresponding - * segment lengths. - * - * xDivs and yDivs point to arrays of horizontal and vertical pixel - * indices. The first pair of Divs (in either array) indicate the - * starting and ending points of the first stretchable segment in that - * axis. The next pair specifies the next stretchable segment, etc. So - * in the above example xDiv[0] and xDiv[1] specify the horizontal - * coordinates for the regions labeled 1, 5 and 9. xDiv[2] and - * xDiv[3] specify the coordinates for regions 3, 7 and 11. Note that - * the leftmost slices always start at x=0 and the rightmost slices - * always end at the end of the image. So, for example, the regions 0, - * 4 and 8 (which are fixed along the X axis) start at x value 0 and - * go to xDiv[0] and slices 2, 6 and 10 start at xDiv[1] and end at - * xDiv[2]. - * - * The array pointed to by the colors field lists contains hints for - * each of the regions. They are ordered according left-to-right and - * top-to-bottom as indicated above. For each segment that is a solid - * color the array entry will contain that color value; otherwise it - * will contain NO_COLOR. Segments that are completely transparent - * will always have the value TRANSPARENT_COLOR. - * - * The PNG chunk type is "npTc". - */ -struct Res_png_9patch -{ - Res_png_9patch() : wasDeserialized(false), xDivs(NULL), - yDivs(NULL), colors(NULL) { } - - int8_t wasDeserialized; - int8_t numXDivs; - int8_t numYDivs; - int8_t numColors; - - // These tell where the next section of a patch starts. - // For example, the first patch includes the pixels from - // 0 to xDivs[0]-1 and the second patch includes the pixels - // from xDivs[0] to xDivs[1]-1. - // Note: allocation/free of these pointers is left to the caller. - int32_t* xDivs; - int32_t* yDivs; - - int32_t paddingLeft, paddingRight; - int32_t paddingTop, paddingBottom; - - enum { - // The 9 patch segment is not a solid color. - NO_COLOR = 0x00000001, - - // The 9 patch segment is completely transparent. - TRANSPARENT_COLOR = 0x00000000 - }; - // Note: allocation/free of this pointer is left to the caller. - uint32_t* colors; - - // Convert data from device representation to PNG file representation. - void deviceToFile(); - // Convert data from PNG file representation to device representation. - void fileToDevice(); - // Serialize/Marshall the patch data into a newly malloc-ed block - void* serialize(); - // Serialize/Marshall the patch data - void serialize(void* outData); - // Deserialize/Unmarshall the patch data - static Res_png_9patch* deserialize(const void* data); - // Compute the size of the serialized data structure - size_t serializedSize(); -}; - -/** ******************************************************************** - * Base Types - * - * These are standard types that are shared between multiple specific - * resource types. - * - *********************************************************************** */ - -/** - * Header that appears at the front of every data chunk in a resource. - */ -struct ResChunk_header -{ - // Type identifier for this chunk. The meaning of this value depends - // on the containing chunk. - uint16_t type; - - // Size of the chunk header (in bytes). Adding this value to - // the address of the chunk allows you to find its associated data - // (if any). - uint16_t headerSize; - - // Total size of this chunk (in bytes). This is the chunkSize plus - // the size of any data associated with the chunk. Adding this value - // to the chunk allows you to completely skip its contents (including - // any child chunks). If this value is the same as chunkSize, there is - // no data associated with the chunk. - uint32_t size; -}; - -enum { - RES_NULL_TYPE = 0x0000, - RES_STRING_POOL_TYPE = 0x0001, - RES_TABLE_TYPE = 0x0002, - RES_XML_TYPE = 0x0003, - - // Chunk types in RES_XML_TYPE - RES_XML_FIRST_CHUNK_TYPE = 0x0100, - RES_XML_START_NAMESPACE_TYPE= 0x0100, - RES_XML_END_NAMESPACE_TYPE = 0x0101, - RES_XML_START_ELEMENT_TYPE = 0x0102, - RES_XML_END_ELEMENT_TYPE = 0x0103, - RES_XML_CDATA_TYPE = 0x0104, - RES_XML_LAST_CHUNK_TYPE = 0x017f, - // This contains a uint32_t array mapping strings in the string - // pool back to resource identifiers. It is optional. - RES_XML_RESOURCE_MAP_TYPE = 0x0180, - - // Chunk types in RES_TABLE_TYPE - RES_TABLE_PACKAGE_TYPE = 0x0200, - RES_TABLE_TYPE_TYPE = 0x0201, - RES_TABLE_TYPE_SPEC_TYPE = 0x0202 -}; - -/** - * Macros for building/splitting resource identifiers. - */ -#define Res_VALIDID(resid) (resid != 0) -#define Res_CHECKID(resid) ((resid&0xFFFF0000) != 0) -#define Res_MAKEID(package, type, entry) \ - (((package+1)<<24) | (((type+1)&0xFF)<<16) | (entry&0xFFFF)) -#define Res_GETPACKAGE(id) ((id>>24)-1) -#define Res_GETTYPE(id) (((id>>16)&0xFF)-1) -#define Res_GETENTRY(id) (id&0xFFFF) - -#define Res_INTERNALID(resid) ((resid&0xFFFF0000) != 0 && (resid&0xFF0000) == 0) -#define Res_MAKEINTERNAL(entry) (0x01000000 | (entry&0xFFFF)) -#define Res_MAKEARRAY(entry) (0x02000000 | (entry&0xFFFF)) - -#define Res_MAXPACKAGE 255 - -/** - * Representation of a value in a resource, supplying type - * information. - */ -struct Res_value -{ - // Number of bytes in this structure. - uint16_t size; - - // Always set to 0. - uint8_t res0; - - // Type of the data value. - enum { - // Contains no data. - TYPE_NULL = 0x00, - // The 'data' holds a ResTable_ref, a reference to another resource - // table entry. - TYPE_REFERENCE = 0x01, - // The 'data' holds an attribute resource identifier. - TYPE_ATTRIBUTE = 0x02, - // The 'data' holds an index into the containing resource table's - // global value string pool. - TYPE_STRING = 0x03, - // The 'data' holds a single-precision floating point number. - TYPE_FLOAT = 0x04, - // The 'data' holds a complex number encoding a dimension value, - // such as "100in". - TYPE_DIMENSION = 0x05, - // The 'data' holds a complex number encoding a fraction of a - // container. - TYPE_FRACTION = 0x06, - - // Beginning of integer flavors... - TYPE_FIRST_INT = 0x10, - - // The 'data' is a raw integer value of the form n..n. - TYPE_INT_DEC = 0x10, - // The 'data' is a raw integer value of the form 0xn..n. - TYPE_INT_HEX = 0x11, - // The 'data' is either 0 or 1, for input "false" or "true" respectively. - TYPE_INT_BOOLEAN = 0x12, - - // Beginning of color integer flavors... - TYPE_FIRST_COLOR_INT = 0x1c, - - // The 'data' is a raw integer value of the form #aarrggbb. - TYPE_INT_COLOR_ARGB8 = 0x1c, - // The 'data' is a raw integer value of the form #rrggbb. - TYPE_INT_COLOR_RGB8 = 0x1d, - // The 'data' is a raw integer value of the form #argb. - TYPE_INT_COLOR_ARGB4 = 0x1e, - // The 'data' is a raw integer value of the form #rgb. - TYPE_INT_COLOR_RGB4 = 0x1f, - - // ...end of integer flavors. - TYPE_LAST_COLOR_INT = 0x1f, - - // ...end of integer flavors. - TYPE_LAST_INT = 0x1f - }; - uint8_t dataType; - - // Structure of complex data values (TYPE_UNIT and TYPE_FRACTION) - enum { - // Where the unit type information is. This gives us 16 possible - // types, as defined below. - COMPLEX_UNIT_SHIFT = 0, - COMPLEX_UNIT_MASK = 0xf, - - // TYPE_DIMENSION: Value is raw pixels. - COMPLEX_UNIT_PX = 0, - // TYPE_DIMENSION: Value is Device Independent Pixels. - COMPLEX_UNIT_DIP = 1, - // TYPE_DIMENSION: Value is a Scaled device independent Pixels. - COMPLEX_UNIT_SP = 2, - // TYPE_DIMENSION: Value is in points. - COMPLEX_UNIT_PT = 3, - // TYPE_DIMENSION: Value is in inches. - COMPLEX_UNIT_IN = 4, - // TYPE_DIMENSION: Value is in millimeters. - COMPLEX_UNIT_MM = 5, - - // TYPE_FRACTION: A basic fraction of the overall size. - COMPLEX_UNIT_FRACTION = 0, - // TYPE_FRACTION: A fraction of the parent size. - COMPLEX_UNIT_FRACTION_PARENT = 1, - - // Where the radix information is, telling where the decimal place - // appears in the mantissa. This give us 4 possible fixed point - // representations as defined below. - COMPLEX_RADIX_SHIFT = 4, - COMPLEX_RADIX_MASK = 0x3, - - // The mantissa is an integral number -- i.e., 0xnnnnnn.0 - COMPLEX_RADIX_23p0 = 0, - // The mantissa magnitude is 16 bits -- i.e, 0xnnnn.nn - COMPLEX_RADIX_16p7 = 1, - // The mantissa magnitude is 8 bits -- i.e, 0xnn.nnnn - COMPLEX_RADIX_8p15 = 2, - // The mantissa magnitude is 0 bits -- i.e, 0x0.nnnnnn - COMPLEX_RADIX_0p23 = 3, - - // Where the actual value is. This gives us 23 bits of - // precision. The top bit is the sign. - COMPLEX_MANTISSA_SHIFT = 8, - COMPLEX_MANTISSA_MASK = 0xffffff - }; - - // The data for this item, as interpreted according to dataType. - uint32_t data; - - void copyFrom_dtoh(const Res_value& src); -}; - -/** - * This is a reference to a unique entry (a ResTable_entry structure) - * in a resource table. The value is structured as: 0xpptteeee, - * where pp is the package index, tt is the type index in that - * package, and eeee is the entry index in that type. The package - * and type values start at 1 for the first item, to help catch cases - * where they have not been supplied. - */ -struct ResTable_ref -{ - uint32_t ident; -}; - -/** - * Reference to a string in a string pool. - */ -struct ResStringPool_ref -{ - // Index into the string pool table (uint32_t-offset from the indices - // immediately after ResStringPool_header) at which to find the location - // of the string data in the pool. - uint32_t index; -}; - -/** ******************************************************************** - * String Pool - * - * A set of strings that can be references by others through a - * ResStringPool_ref. - * - *********************************************************************** */ - -/** - * Definition for a pool of strings. The data of this chunk is an - * array of uint32_t providing indices into the pool, relative to - * stringsStart. At stringsStart are all of the UTF-16 strings - * concatenated together; each starts with a uint16_t of the string's - * length and each ends with a 0x0000 terminator. If a string is > - * 32767 characters, the high bit of the length is set meaning to take - * those 15 bits as a high word and it will be followed by another - * uint16_t containing the low word. - * - * If styleCount is not zero, then immediately following the array of - * uint32_t indices into the string table is another array of indices - * into a style table starting at stylesStart. Each entry in the - * style table is an array of ResStringPool_span structures. - */ -struct ResStringPool_header -{ - struct ResChunk_header header; - - // Number of strings in this pool (number of uint32_t indices that follow - // in the data). - uint32_t stringCount; - - // Number of style span arrays in the pool (number of uint32_t indices - // follow the string indices). - uint32_t styleCount; - - // Flags. - enum { - // If set, the string index is sorted by the string values (based - // on strcmp16()). - SORTED_FLAG = 1<<0, - - // String pool is encoded in UTF-8 - UTF8_FLAG = 1<<8 - }; - uint32_t flags; - - // Index from header of the string data. - uint32_t stringsStart; - - // Index from header of the style data. - uint32_t stylesStart; -}; - -/** - * This structure defines a span of style information associated with - * a string in the pool. - */ -struct ResStringPool_span -{ - enum { - END = 0xFFFFFFFF - }; - - // This is the name of the span -- that is, the name of the XML - // tag that defined it. The special value END (0xFFFFFFFF) indicates - // the end of an array of spans. - ResStringPool_ref name; - - // The range of characters in the string that this span applies to. - uint32_t firstChar, lastChar; -}; - -/** - * Convenience class for accessing data in a ResStringPool resource. - */ -class ResStringPool -{ -public: - ResStringPool(); - ResStringPool(const void* data, size_t size, bool copyData=false); - ~ResStringPool(); - - status_t setTo(const void* data, size_t size, bool copyData=false); - - status_t getError() const; - - void uninit(); - - // Return string entry as UTF16; if the pool is UTF8, the string will - // be converted before returning. - inline const char16_t* stringAt(const ResStringPool_ref& ref, size_t* outLen) const { - return stringAt(ref.index, outLen); - } - const char16_t* stringAt(size_t idx, size_t* outLen) const; - - // Note: returns null if the string pool is not UTF8. - const char* string8At(size_t idx, size_t* outLen) const; - - // Return string whether the pool is UTF8 or UTF16. Does not allow you - // to distinguish null. - const String8 string8ObjectAt(size_t idx) const; - - const ResStringPool_span* styleAt(const ResStringPool_ref& ref) const; - const ResStringPool_span* styleAt(size_t idx) const; - - ssize_t indexOfString(const char16_t* str, size_t strLen) const; - - size_t size() const; - size_t styleCount() const; - size_t bytes() const; - - bool isSorted() const; - bool isUTF8() const; - -private: - status_t mError; - void* mOwnedData; - const ResStringPool_header* mHeader; - size_t mSize; - mutable Mutex mDecodeLock; - const uint32_t* mEntries; - const uint32_t* mEntryStyles; - const void* mStrings; - char16_t mutable** mCache; - uint32_t mStringPoolSize; // number of uint16_t - const uint32_t* mStyles; - uint32_t mStylePoolSize; // number of uint32_t -}; - -/** ******************************************************************** - * XML Tree - * - * Binary representation of an XML document. This is designed to - * express everything in an XML document, in a form that is much - * easier to parse on the device. - * - *********************************************************************** */ - -/** - * XML tree header. This appears at the front of an XML tree, - * describing its content. It is followed by a flat array of - * ResXMLTree_node structures; the hierarchy of the XML document - * is described by the occurrance of RES_XML_START_ELEMENT_TYPE - * and corresponding RES_XML_END_ELEMENT_TYPE nodes in the array. - */ -struct ResXMLTree_header -{ - struct ResChunk_header header; -}; - -/** - * Basic XML tree node. A single item in the XML document. Extended info - * about the node can be found after header.headerSize. - */ -struct ResXMLTree_node -{ - struct ResChunk_header header; - - // Line number in original source file at which this element appeared. - uint32_t lineNumber; - - // Optional XML comment that was associated with this element; -1 if none. - struct ResStringPool_ref comment; -}; - -/** - * Extended XML tree node for CDATA tags -- includes the CDATA string. - * Appears header.headerSize bytes after a ResXMLTree_node. - */ -struct ResXMLTree_cdataExt -{ - // The raw CDATA character data. - struct ResStringPool_ref data; - - // The typed value of the character data if this is a CDATA node. - struct Res_value typedData; -}; - -/** - * Extended XML tree node for namespace start/end nodes. - * Appears header.headerSize bytes after a ResXMLTree_node. - */ -struct ResXMLTree_namespaceExt -{ - // The prefix of the namespace. - struct ResStringPool_ref prefix; - - // The URI of the namespace. - struct ResStringPool_ref uri; -}; - -/** - * Extended XML tree node for element start/end nodes. - * Appears header.headerSize bytes after a ResXMLTree_node. - */ -struct ResXMLTree_endElementExt -{ - // String of the full namespace of this element. - struct ResStringPool_ref ns; - - // String name of this node if it is an ELEMENT; the raw - // character data if this is a CDATA node. - struct ResStringPool_ref name; -}; - -/** - * Extended XML tree node for start tags -- includes attribute - * information. - * Appears header.headerSize bytes after a ResXMLTree_node. - */ -struct ResXMLTree_attrExt -{ - // String of the full namespace of this element. - struct ResStringPool_ref ns; - - // String name of this node if it is an ELEMENT; the raw - // character data if this is a CDATA node. - struct ResStringPool_ref name; - - // Byte offset from the start of this structure where the attributes start. - uint16_t attributeStart; - - // Size of the ResXMLTree_attribute structures that follow. - uint16_t attributeSize; - - // Number of attributes associated with an ELEMENT. These are - // available as an array of ResXMLTree_attribute structures - // immediately following this node. - uint16_t attributeCount; - - // Index (1-based) of the "id" attribute. 0 if none. - uint16_t idIndex; - - // Index (1-based) of the "class" attribute. 0 if none. - uint16_t classIndex; - - // Index (1-based) of the "style" attribute. 0 if none. - uint16_t styleIndex; -}; - -struct ResXMLTree_attribute -{ - // Namespace of this attribute. - struct ResStringPool_ref ns; - - // Name of this attribute. - struct ResStringPool_ref name; - - // The original raw string value of this attribute. - struct ResStringPool_ref rawValue; - - // Processesd typed value of this attribute. - struct Res_value typedValue; -}; - -class ResXMLTree; - -class ResXMLParser -{ -public: - ResXMLParser(const ResXMLTree& tree); - - enum event_code_t { - BAD_DOCUMENT = -1, - START_DOCUMENT = 0, - END_DOCUMENT = 1, - - FIRST_CHUNK_CODE = RES_XML_FIRST_CHUNK_TYPE, - - START_NAMESPACE = RES_XML_START_NAMESPACE_TYPE, - END_NAMESPACE = RES_XML_END_NAMESPACE_TYPE, - START_TAG = RES_XML_START_ELEMENT_TYPE, - END_TAG = RES_XML_END_ELEMENT_TYPE, - TEXT = RES_XML_CDATA_TYPE - }; - - struct ResXMLPosition - { - event_code_t eventCode; - const ResXMLTree_node* curNode; - const void* curExt; - }; - - void restart(); - - const ResStringPool& getStrings() const; - - event_code_t getEventType() const; - // Note, unlike XmlPullParser, the first call to next() will return - // START_TAG of the first element. - event_code_t next(); - - // These are available for all nodes: - int32_t getCommentID() const; - const uint16_t* getComment(size_t* outLen) const; - uint32_t getLineNumber() const; - - // This is available for TEXT: - int32_t getTextID() const; - const uint16_t* getText(size_t* outLen) const; - ssize_t getTextValue(Res_value* outValue) const; - - // These are available for START_NAMESPACE and END_NAMESPACE: - int32_t getNamespacePrefixID() const; - const uint16_t* getNamespacePrefix(size_t* outLen) const; - int32_t getNamespaceUriID() const; - const uint16_t* getNamespaceUri(size_t* outLen) const; - - // These are available for START_TAG and END_TAG: - int32_t getElementNamespaceID() const; - const uint16_t* getElementNamespace(size_t* outLen) const; - int32_t getElementNameID() const; - const uint16_t* getElementName(size_t* outLen) const; - - // Remaining methods are for retrieving information about attributes - // associated with a START_TAG: - - size_t getAttributeCount() const; - - // Returns -1 if no namespace, -2 if idx out of range. - int32_t getAttributeNamespaceID(size_t idx) const; - const uint16_t* getAttributeNamespace(size_t idx, size_t* outLen) const; - - int32_t getAttributeNameID(size_t idx) const; - const uint16_t* getAttributeName(size_t idx, size_t* outLen) const; - uint32_t getAttributeNameResID(size_t idx) const; - - // These will work only if the underlying string pool is UTF-8. - const char* getAttributeNamespace8(size_t idx, size_t* outLen) const; - const char* getAttributeName8(size_t idx, size_t* outLen) const; - - int32_t getAttributeValueStringID(size_t idx) const; - const uint16_t* getAttributeStringValue(size_t idx, size_t* outLen) const; - - int32_t getAttributeDataType(size_t idx) const; - int32_t getAttributeData(size_t idx) const; - ssize_t getAttributeValue(size_t idx, Res_value* outValue) const; - - ssize_t indexOfAttribute(const char* ns, const char* attr) const; - ssize_t indexOfAttribute(const char16_t* ns, size_t nsLen, - const char16_t* attr, size_t attrLen) const; - - ssize_t indexOfID() const; - ssize_t indexOfClass() const; - ssize_t indexOfStyle() const; - - void getPosition(ResXMLPosition* pos) const; - void setPosition(const ResXMLPosition& pos); - -private: - friend class ResXMLTree; - - event_code_t nextNode(); - - const ResXMLTree& mTree; - event_code_t mEventCode; - const ResXMLTree_node* mCurNode; - const void* mCurExt; -}; - -/** - * Convenience class for accessing data in a ResXMLTree resource. - */ -class ResXMLTree : public ResXMLParser -{ -public: - ResXMLTree(); - ResXMLTree(const void* data, size_t size, bool copyData=false); - ~ResXMLTree(); - - status_t setTo(const void* data, size_t size, bool copyData=false); - - status_t getError() const; - - void uninit(); - -private: - friend class ResXMLParser; - - status_t validateNode(const ResXMLTree_node* node) const; - - status_t mError; - void* mOwnedData; - const ResXMLTree_header* mHeader; - size_t mSize; - const uint8_t* mDataEnd; - ResStringPool mStrings; - const uint32_t* mResIds; - size_t mNumResIds; - const ResXMLTree_node* mRootNode; - const void* mRootExt; - event_code_t mRootCode; -}; - -/** ******************************************************************** - * RESOURCE TABLE - * - *********************************************************************** */ - -/** - * Header for a resource table. Its data contains a series of - * additional chunks: - * * A ResStringPool_header containing all table values. This string pool - * contains all of the string values in the entire resource table (not - * the names of entries or type identifiers however). - * * One or more ResTable_package chunks. - * - * Specific entries within a resource table can be uniquely identified - * with a single integer as defined by the ResTable_ref structure. - */ -struct ResTable_header -{ - struct ResChunk_header header; - - // The number of ResTable_package structures. - uint32_t packageCount; -}; - -/** - * A collection of resource data types within a package. Followed by - * one or more ResTable_type and ResTable_typeSpec structures containing the - * entry values for each resource type. - */ -struct ResTable_package -{ - struct ResChunk_header header; - - // If this is a base package, its ID. Package IDs start - // at 1 (corresponding to the value of the package bits in a - // resource identifier). 0 means this is not a base package. - uint32_t id; - - // Actual name of this package, \0-terminated. - char16_t name[128]; - - // Offset to a ResStringPool_header defining the resource - // type symbol table. If zero, this package is inheriting from - // another base package (overriding specific values in it). - uint32_t typeStrings; - - // Last index into typeStrings that is for public use by others. - uint32_t lastPublicType; - - // Offset to a ResStringPool_header defining the resource - // key symbol table. If zero, this package is inheriting from - // another base package (overriding specific values in it). - uint32_t keyStrings; - - // Last index into keyStrings that is for public use by others. - uint32_t lastPublicKey; -}; - -/** - * Describes a particular resource configuration. - */ -struct ResTable_config -{ - // Number of bytes in this structure. - uint32_t size; - - union { - struct { - // Mobile country code (from SIM). 0 means "any". - uint16_t mcc; - // Mobile network code (from SIM). 0 means "any". - uint16_t mnc; - }; - uint32_t imsi; - }; - - union { - struct { - // \0\0 means "any". Otherwise, en, fr, etc. - char language[2]; - - // \0\0 means "any". Otherwise, US, CA, etc. - char country[2]; - }; - uint32_t locale; - }; - - enum { - ORIENTATION_ANY = ACONFIGURATION_ORIENTATION_ANY, - ORIENTATION_PORT = ACONFIGURATION_ORIENTATION_PORT, - ORIENTATION_LAND = ACONFIGURATION_ORIENTATION_LAND, - ORIENTATION_SQUARE = ACONFIGURATION_ORIENTATION_SQUARE, - }; - - enum { - TOUCHSCREEN_ANY = ACONFIGURATION_TOUCHSCREEN_ANY, - TOUCHSCREEN_NOTOUCH = ACONFIGURATION_TOUCHSCREEN_NOTOUCH, - TOUCHSCREEN_STYLUS = ACONFIGURATION_TOUCHSCREEN_STYLUS, - TOUCHSCREEN_FINGER = ACONFIGURATION_TOUCHSCREEN_FINGER, - }; - - enum { - DENSITY_DEFAULT = ACONFIGURATION_DENSITY_DEFAULT, - DENSITY_LOW = ACONFIGURATION_DENSITY_LOW, - DENSITY_MEDIUM = ACONFIGURATION_DENSITY_MEDIUM, - DENSITY_TV = ACONFIGURATION_DENSITY_TV, - DENSITY_HIGH = ACONFIGURATION_DENSITY_HIGH, - DENSITY_XHIGH = ACONFIGURATION_DENSITY_XHIGH, - DENSITY_XXHIGH = ACONFIGURATION_DENSITY_XXHIGH, - DENSITY_XXXHIGH = ACONFIGURATION_DENSITY_XXXHIGH, - DENSITY_NONE = ACONFIGURATION_DENSITY_NONE - }; - - union { - struct { - uint8_t orientation; - uint8_t touchscreen; - uint16_t density; - }; - uint32_t screenType; - }; - - enum { - KEYBOARD_ANY = ACONFIGURATION_KEYBOARD_ANY, - KEYBOARD_NOKEYS = ACONFIGURATION_KEYBOARD_NOKEYS, - KEYBOARD_QWERTY = ACONFIGURATION_KEYBOARD_QWERTY, - KEYBOARD_12KEY = ACONFIGURATION_KEYBOARD_12KEY, - }; - - enum { - NAVIGATION_ANY = ACONFIGURATION_NAVIGATION_ANY, - NAVIGATION_NONAV = ACONFIGURATION_NAVIGATION_NONAV, - NAVIGATION_DPAD = ACONFIGURATION_NAVIGATION_DPAD, - NAVIGATION_TRACKBALL = ACONFIGURATION_NAVIGATION_TRACKBALL, - NAVIGATION_WHEEL = ACONFIGURATION_NAVIGATION_WHEEL, - }; - - enum { - MASK_KEYSHIDDEN = 0x0003, - KEYSHIDDEN_ANY = ACONFIGURATION_KEYSHIDDEN_ANY, - KEYSHIDDEN_NO = ACONFIGURATION_KEYSHIDDEN_NO, - KEYSHIDDEN_YES = ACONFIGURATION_KEYSHIDDEN_YES, - KEYSHIDDEN_SOFT = ACONFIGURATION_KEYSHIDDEN_SOFT, - }; - - enum { - MASK_NAVHIDDEN = 0x000c, - SHIFT_NAVHIDDEN = 2, - NAVHIDDEN_ANY = ACONFIGURATION_NAVHIDDEN_ANY << SHIFT_NAVHIDDEN, - NAVHIDDEN_NO = ACONFIGURATION_NAVHIDDEN_NO << SHIFT_NAVHIDDEN, - NAVHIDDEN_YES = ACONFIGURATION_NAVHIDDEN_YES << SHIFT_NAVHIDDEN, - }; - - union { - struct { - uint8_t keyboard; - uint8_t navigation; - uint8_t inputFlags; - uint8_t inputPad0; - }; - uint32_t input; - }; - - enum { - SCREENWIDTH_ANY = 0 - }; - - enum { - SCREENHEIGHT_ANY = 0 - }; - - union { - struct { - uint16_t screenWidth; - uint16_t screenHeight; - }; - uint32_t screenSize; - }; - - enum { - SDKVERSION_ANY = 0 - }; - - enum { - MINORVERSION_ANY = 0 - }; - - union { - struct { - uint16_t sdkVersion; - // For now minorVersion must always be 0!!! Its meaning - // is currently undefined. - uint16_t minorVersion; - }; - uint32_t version; - }; - - enum { - // screenLayout bits for screen size class. - MASK_SCREENSIZE = 0x0f, - SCREENSIZE_ANY = ACONFIGURATION_SCREENSIZE_ANY, - SCREENSIZE_SMALL = ACONFIGURATION_SCREENSIZE_SMALL, - SCREENSIZE_NORMAL = ACONFIGURATION_SCREENSIZE_NORMAL, - SCREENSIZE_LARGE = ACONFIGURATION_SCREENSIZE_LARGE, - SCREENSIZE_XLARGE = ACONFIGURATION_SCREENSIZE_XLARGE, - - // screenLayout bits for wide/long screen variation. - MASK_SCREENLONG = 0x30, - SHIFT_SCREENLONG = 4, - SCREENLONG_ANY = ACONFIGURATION_SCREENLONG_ANY << SHIFT_SCREENLONG, - SCREENLONG_NO = ACONFIGURATION_SCREENLONG_NO << SHIFT_SCREENLONG, - SCREENLONG_YES = ACONFIGURATION_SCREENLONG_YES << SHIFT_SCREENLONG, - - // screenLayout bits for layout direction. - MASK_LAYOUTDIR = 0xC0, - SHIFT_LAYOUTDIR = 6, - LAYOUTDIR_ANY = ACONFIGURATION_LAYOUTDIR_ANY << SHIFT_LAYOUTDIR, - LAYOUTDIR_LTR = ACONFIGURATION_LAYOUTDIR_LTR << SHIFT_LAYOUTDIR, - LAYOUTDIR_RTL = ACONFIGURATION_LAYOUTDIR_RTL << SHIFT_LAYOUTDIR, - }; - - enum { - // uiMode bits for the mode type. - MASK_UI_MODE_TYPE = 0x0f, - UI_MODE_TYPE_ANY = ACONFIGURATION_UI_MODE_TYPE_ANY, - UI_MODE_TYPE_NORMAL = ACONFIGURATION_UI_MODE_TYPE_NORMAL, - UI_MODE_TYPE_DESK = ACONFIGURATION_UI_MODE_TYPE_DESK, - UI_MODE_TYPE_CAR = ACONFIGURATION_UI_MODE_TYPE_CAR, - UI_MODE_TYPE_TELEVISION = ACONFIGURATION_UI_MODE_TYPE_TELEVISION, - UI_MODE_TYPE_APPLIANCE = ACONFIGURATION_UI_MODE_TYPE_APPLIANCE, - - // uiMode bits for the night switch. - MASK_UI_MODE_NIGHT = 0x30, - SHIFT_UI_MODE_NIGHT = 4, - UI_MODE_NIGHT_ANY = ACONFIGURATION_UI_MODE_NIGHT_ANY << SHIFT_UI_MODE_NIGHT, - UI_MODE_NIGHT_NO = ACONFIGURATION_UI_MODE_NIGHT_NO << SHIFT_UI_MODE_NIGHT, - UI_MODE_NIGHT_YES = ACONFIGURATION_UI_MODE_NIGHT_YES << SHIFT_UI_MODE_NIGHT, - }; - - union { - struct { - uint8_t screenLayout; - uint8_t uiMode; - uint16_t smallestScreenWidthDp; - }; - uint32_t screenConfig; - }; - - union { - struct { - uint16_t screenWidthDp; - uint16_t screenHeightDp; - }; - uint32_t screenSizeDp; - }; - - void copyFromDeviceNoSwap(const ResTable_config& o); - - void copyFromDtoH(const ResTable_config& o); - - void swapHtoD(); - - int compare(const ResTable_config& o) const; - int compareLogical(const ResTable_config& o) const; - - // Flags indicating a set of config values. These flag constants must - // match the corresponding ones in android.content.pm.ActivityInfo and - // attrs_manifest.xml. - enum { - CONFIG_MCC = ACONFIGURATION_MCC, - CONFIG_MNC = ACONFIGURATION_MNC, - CONFIG_LOCALE = ACONFIGURATION_LOCALE, - CONFIG_TOUCHSCREEN = ACONFIGURATION_TOUCHSCREEN, - CONFIG_KEYBOARD = ACONFIGURATION_KEYBOARD, - CONFIG_KEYBOARD_HIDDEN = ACONFIGURATION_KEYBOARD_HIDDEN, - CONFIG_NAVIGATION = ACONFIGURATION_NAVIGATION, - CONFIG_ORIENTATION = ACONFIGURATION_ORIENTATION, - CONFIG_DENSITY = ACONFIGURATION_DENSITY, - CONFIG_SCREEN_SIZE = ACONFIGURATION_SCREEN_SIZE, - CONFIG_SMALLEST_SCREEN_SIZE = ACONFIGURATION_SMALLEST_SCREEN_SIZE, - CONFIG_VERSION = ACONFIGURATION_VERSION, - CONFIG_SCREEN_LAYOUT = ACONFIGURATION_SCREEN_LAYOUT, - CONFIG_UI_MODE = ACONFIGURATION_UI_MODE, - CONFIG_LAYOUTDIR = ACONFIGURATION_LAYOUTDIR, - }; - - // Compare two configuration, returning CONFIG_* flags set for each value - // that is different. - int diff(const ResTable_config& o) const; - - // Return true if 'this' is more specific than 'o'. - bool isMoreSpecificThan(const ResTable_config& o) const; - - // Return true if 'this' is a better match than 'o' for the 'requested' - // configuration. This assumes that match() has already been used to - // remove any configurations that don't match the requested configuration - // at all; if they are not first filtered, non-matching results can be - // considered better than matching ones. - // The general rule per attribute: if the request cares about an attribute - // (it normally does), if the two (this and o) are equal it's a tie. If - // they are not equal then one must be generic because only generic and - // '==requested' will pass the match() call. So if this is not generic, - // it wins. If this IS generic, o wins (return false). - bool isBetterThan(const ResTable_config& o, const ResTable_config* requested) const; - - // Return true if 'this' can be considered a match for the parameters in - // 'settings'. - // Note this is asymetric. A default piece of data will match every request - // but a request for the default should not match odd specifics - // (ie, request with no mcc should not match a particular mcc's data) - // settings is the requested settings - bool match(const ResTable_config& settings) const; - - void getLocale(char str[6]) const; - - String8 toString() const; -}; - -/** - * A specification of the resources defined by a particular type. - * - * There should be one of these chunks for each resource type. - * - * This structure is followed by an array of integers providing the set of - * configuration change flags (ResTable_config::CONFIG_*) that have multiple - * resources for that configuration. In addition, the high bit is set if that - * resource has been made public. - */ -struct ResTable_typeSpec -{ - struct ResChunk_header header; - - // The type identifier this chunk is holding. Type IDs start - // at 1 (corresponding to the value of the type bits in a - // resource identifier). 0 is invalid. - uint8_t id; - - // Must be 0. - uint8_t res0; - // Must be 0. - uint16_t res1; - - // Number of uint32_t entry configuration masks that follow. - uint32_t entryCount; - - enum { - // Additional flag indicating an entry is public. - SPEC_PUBLIC = 0x40000000 - }; -}; - -/** - * A collection of resource entries for a particular resource data - * type. Followed by an array of uint32_t defining the resource - * values, corresponding to the array of type strings in the - * ResTable_package::typeStrings string block. Each of these hold an - * index from entriesStart; a value of NO_ENTRY means that entry is - * not defined. - * - * There may be multiple of these chunks for a particular resource type, - * supply different configuration variations for the resource values of - * that type. - * - * It would be nice to have an additional ordered index of entries, so - * we can do a binary search if trying to find a resource by string name. - */ -struct ResTable_type -{ - struct ResChunk_header header; - - enum { - NO_ENTRY = 0xFFFFFFFF - }; - - // The type identifier this chunk is holding. Type IDs start - // at 1 (corresponding to the value of the type bits in a - // resource identifier). 0 is invalid. - uint8_t id; - - // Must be 0. - uint8_t res0; - // Must be 0. - uint16_t res1; - - // Number of uint32_t entry indices that follow. - uint32_t entryCount; - - // Offset from header where ResTable_entry data starts. - uint32_t entriesStart; - - // Configuration this collection of entries is designed for. - ResTable_config config; -}; - -/** - * This is the beginning of information about an entry in the resource - * table. It holds the reference to the name of this entry, and is - * immediately followed by one of: - * * A Res_value structure, if FLAG_COMPLEX is -not- set. - * * An array of ResTable_map structures, if FLAG_COMPLEX is set. - * These supply a set of name/value mappings of data. - */ -struct ResTable_entry -{ - // Number of bytes in this structure. - uint16_t size; - - enum { - // If set, this is a complex entry, holding a set of name/value - // mappings. It is followed by an array of ResTable_map structures. - FLAG_COMPLEX = 0x0001, - // If set, this resource has been declared public, so libraries - // are allowed to reference it. - FLAG_PUBLIC = 0x0002 - }; - uint16_t flags; - - // Reference into ResTable_package::keyStrings identifying this entry. - struct ResStringPool_ref key; -}; - -/** - * Extended form of a ResTable_entry for map entries, defining a parent map - * resource from which to inherit values. - */ -struct ResTable_map_entry : public ResTable_entry -{ - // Resource identifier of the parent mapping, or 0 if there is none. - ResTable_ref parent; - // Number of name/value pairs that follow for FLAG_COMPLEX. - uint32_t count; -}; - -/** - * A single name/value mapping that is part of a complex resource - * entry. - */ -struct ResTable_map -{ - // The resource identifier defining this mapping's name. For attribute - // resources, 'name' can be one of the following special resource types - // to supply meta-data about the attribute; for all other resource types - // it must be an attribute resource. - ResTable_ref name; - - // Special values for 'name' when defining attribute resources. - enum { - // This entry holds the attribute's type code. - ATTR_TYPE = Res_MAKEINTERNAL(0), - - // For integral attributes, this is the minimum value it can hold. - ATTR_MIN = Res_MAKEINTERNAL(1), - - // For integral attributes, this is the maximum value it can hold. - ATTR_MAX = Res_MAKEINTERNAL(2), - - // Localization of this resource is can be encouraged or required with - // an aapt flag if this is set - ATTR_L10N = Res_MAKEINTERNAL(3), - - // for plural support, see android.content.res.PluralRules#attrForQuantity(int) - ATTR_OTHER = Res_MAKEINTERNAL(4), - ATTR_ZERO = Res_MAKEINTERNAL(5), - ATTR_ONE = Res_MAKEINTERNAL(6), - ATTR_TWO = Res_MAKEINTERNAL(7), - ATTR_FEW = Res_MAKEINTERNAL(8), - ATTR_MANY = Res_MAKEINTERNAL(9) - - }; - - // Bit mask of allowed types, for use with ATTR_TYPE. - enum { - // No type has been defined for this attribute, use generic - // type handling. The low 16 bits are for types that can be - // handled generically; the upper 16 require additional information - // in the bag so can not be handled generically for TYPE_ANY. - TYPE_ANY = 0x0000FFFF, - - // Attribute holds a references to another resource. - TYPE_REFERENCE = 1<<0, - - // Attribute holds a generic string. - TYPE_STRING = 1<<1, - - // Attribute holds an integer value. ATTR_MIN and ATTR_MIN can - // optionally specify a constrained range of possible integer values. - TYPE_INTEGER = 1<<2, - - // Attribute holds a boolean integer. - TYPE_BOOLEAN = 1<<3, - - // Attribute holds a color value. - TYPE_COLOR = 1<<4, - - // Attribute holds a floating point value. - TYPE_FLOAT = 1<<5, - - // Attribute holds a dimension value, such as "20px". - TYPE_DIMENSION = 1<<6, - - // Attribute holds a fraction value, such as "20%". - TYPE_FRACTION = 1<<7, - - // Attribute holds an enumeration. The enumeration values are - // supplied as additional entries in the map. - TYPE_ENUM = 1<<16, - - // Attribute holds a bitmaks of flags. The flag bit values are - // supplied as additional entries in the map. - TYPE_FLAGS = 1<<17 - }; - - // Enum of localization modes, for use with ATTR_L10N. - enum { - L10N_NOT_REQUIRED = 0, - L10N_SUGGESTED = 1 - }; - - // This mapping's value. - Res_value value; -}; - -/** - * Convenience class for accessing data in a ResTable resource. - */ -class ResTable -{ -public: - ResTable(); - ResTable(const void* data, size_t size, void* cookie, - bool copyData=false); - ~ResTable(); - - status_t add(const void* data, size_t size, void* cookie, - bool copyData=false, const void* idmap = NULL); - status_t add(Asset* asset, void* cookie, - bool copyData=false, const void* idmap = NULL); - status_t add(ResTable* src); - - status_t getError() const; - - void uninit(); - - struct resource_name - { - const char16_t* package; - size_t packageLen; - const char16_t* type; - const char* type8; - size_t typeLen; - const char16_t* name; - const char* name8; - size_t nameLen; - }; - - bool getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const; - - /** - * Retrieve the value of a resource. If the resource is found, returns a - * value >= 0 indicating the table it is in (for use with - * getTableStringBlock() and getTableCookie()) and fills in 'outValue'. If - * not found, returns a negative error code. - * - * Note that this function does not do reference traversal. If you want - * to follow references to other resources to get the "real" value to - * use, you need to call resolveReference() after this function. - * - * @param resID The desired resoruce identifier. - * @param outValue Filled in with the resource data that was found. - * - * @return ssize_t Either a >= 0 table index or a negative error code. - */ - ssize_t getResource(uint32_t resID, Res_value* outValue, bool mayBeBag = false, - uint16_t density = 0, - uint32_t* outSpecFlags = NULL, - ResTable_config* outConfig = NULL) const; - - inline ssize_t getResource(const ResTable_ref& res, Res_value* outValue, - uint32_t* outSpecFlags=NULL) const { - return getResource(res.ident, outValue, false, 0, outSpecFlags, NULL); - } - - ssize_t resolveReference(Res_value* inOutValue, - ssize_t blockIndex, - uint32_t* outLastRef = NULL, - uint32_t* inoutTypeSpecFlags = NULL, - ResTable_config* outConfig = NULL) const; - - enum { - TMP_BUFFER_SIZE = 16 - }; - const char16_t* valueToString(const Res_value* value, size_t stringBlock, - char16_t tmpBuffer[TMP_BUFFER_SIZE], - size_t* outLen); - - struct bag_entry { - ssize_t stringBlock; - ResTable_map map; - }; - - /** - * Retrieve the bag of a resource. If the resoruce is found, returns the - * number of bags it contains and 'outBag' points to an array of their - * values. If not found, a negative error code is returned. - * - * Note that this function -does- do reference traversal of the bag data. - * - * @param resID The desired resource identifier. - * @param outBag Filled inm with a pointer to the bag mappings. - * - * @return ssize_t Either a >= 0 bag count of negative error code. - */ - ssize_t lockBag(uint32_t resID, const bag_entry** outBag) const; - - void unlockBag(const bag_entry* bag) const; - - void lock() const; - - ssize_t getBagLocked(uint32_t resID, const bag_entry** outBag, - uint32_t* outTypeSpecFlags=NULL) const; - - void unlock() const; - - class Theme { - public: - Theme(const ResTable& table); - ~Theme(); - - inline const ResTable& getResTable() const { return mTable; } - - status_t applyStyle(uint32_t resID, bool force=false); - status_t setTo(const Theme& other); - - /** - * Retrieve a value in the theme. If the theme defines this - * value, returns a value >= 0 indicating the table it is in - * (for use with getTableStringBlock() and getTableCookie) and - * fills in 'outValue'. If not found, returns a negative error - * code. - * - * Note that this function does not do reference traversal. If you want - * to follow references to other resources to get the "real" value to - * use, you need to call resolveReference() after this function. - * - * @param resID A resource identifier naming the desired theme - * attribute. - * @param outValue Filled in with the theme value that was - * found. - * - * @return ssize_t Either a >= 0 table index or a negative error code. - */ - ssize_t getAttribute(uint32_t resID, Res_value* outValue, - uint32_t* outTypeSpecFlags = NULL) const; - - /** - * This is like ResTable::resolveReference(), but also takes - * care of resolving attribute references to the theme. - */ - ssize_t resolveAttributeReference(Res_value* inOutValue, - ssize_t blockIndex, uint32_t* outLastRef = NULL, - uint32_t* inoutTypeSpecFlags = NULL, - ResTable_config* inoutConfig = NULL) const; - - void dumpToLog() const; - - private: - Theme(const Theme&); - Theme& operator=(const Theme&); - - struct theme_entry { - ssize_t stringBlock; - uint32_t typeSpecFlags; - Res_value value; - }; - struct type_info { - size_t numEntries; - theme_entry* entries; - }; - struct package_info { - size_t numTypes; - type_info types[]; - }; - - void free_package(package_info* pi); - package_info* copy_package(package_info* pi); - - const ResTable& mTable; - package_info* mPackages[Res_MAXPACKAGE]; - }; - - void setParameters(const ResTable_config* params); - void getParameters(ResTable_config* params) const; - - // Retrieve an identifier (which can be passed to getResource) - // for a given resource name. The 'name' can be fully qualified - // (:.) or the package or type components - // can be dropped if default values are supplied here. - // - // Returns 0 if no such resource was found, else a valid resource ID. - uint32_t identifierForName(const char16_t* name, size_t nameLen, - const char16_t* type = 0, size_t typeLen = 0, - const char16_t* defPackage = 0, - size_t defPackageLen = 0, - uint32_t* outTypeSpecFlags = NULL) const; - - static bool expandResourceRef(const uint16_t* refStr, size_t refLen, - String16* outPackage, - String16* outType, - String16* outName, - const String16* defType = NULL, - const String16* defPackage = NULL, - const char** outErrorMsg = NULL, - bool* outPublicOnly = NULL); - - static bool stringToInt(const char16_t* s, size_t len, Res_value* outValue); - static bool stringToFloat(const char16_t* s, size_t len, Res_value* outValue); - - // Used with stringToValue. - class Accessor - { - public: - inline virtual ~Accessor() { } - - virtual uint32_t getCustomResource(const String16& package, - const String16& type, - const String16& name) const = 0; - virtual uint32_t getCustomResourceWithCreation(const String16& package, - const String16& type, - const String16& name, - const bool createIfNeeded = false) = 0; - virtual uint32_t getRemappedPackage(uint32_t origPackage) const = 0; - virtual bool getAttributeType(uint32_t attrID, uint32_t* outType) = 0; - virtual bool getAttributeMin(uint32_t attrID, uint32_t* outMin) = 0; - virtual bool getAttributeMax(uint32_t attrID, uint32_t* outMax) = 0; - virtual bool getAttributeEnum(uint32_t attrID, - const char16_t* name, size_t nameLen, - Res_value* outValue) = 0; - virtual bool getAttributeFlags(uint32_t attrID, - const char16_t* name, size_t nameLen, - Res_value* outValue) = 0; - virtual uint32_t getAttributeL10N(uint32_t attrID) = 0; - virtual bool getLocalizationSetting() = 0; - virtual void reportError(void* accessorCookie, const char* fmt, ...) = 0; - }; - - // Convert a string to a resource value. Handles standard "@res", - // "#color", "123", and "0x1bd" types; performs escaping of strings. - // The resulting value is placed in 'outValue'; if it is a string type, - // 'outString' receives the string. If 'attrID' is supplied, the value is - // type checked against this attribute and it is used to perform enum - // evaluation. If 'acccessor' is supplied, it will be used to attempt to - // resolve resources that do not exist in this ResTable. If 'attrType' is - // supplied, the value will be type checked for this format if 'attrID' - // is not supplied or found. - bool stringToValue(Res_value* outValue, String16* outString, - const char16_t* s, size_t len, - bool preserveSpaces, bool coerceType, - uint32_t attrID = 0, - const String16* defType = NULL, - const String16* defPackage = NULL, - Accessor* accessor = NULL, - void* accessorCookie = NULL, - uint32_t attrType = ResTable_map::TYPE_ANY, - bool enforcePrivate = true) const; - - // Perform processing of escapes and quotes in a string. - static bool collectString(String16* outString, - const char16_t* s, size_t len, - bool preserveSpaces, - const char** outErrorMsg = NULL, - bool append = false); - - size_t getBasePackageCount() const; - const char16_t* getBasePackageName(size_t idx) const; - uint32_t getBasePackageId(size_t idx) const; - - // Return the number of resource tables that the object contains. - size_t getTableCount() const; - // Return the values string pool for the resource table at the given - // index. This string pool contains all of the strings for values - // contained in the resource table -- that is the item values themselves, - // but not the names their entries or types. - const ResStringPool* getTableStringBlock(size_t index) const; - // Return unique cookie identifier for the given resource table. - void* getTableCookie(size_t index) const; - - // Return the configurations (ResTable_config) that we know about - void getConfigurations(Vector* configs) const; - - void getLocales(Vector* locales) const; - - // Generate an idmap. - // - // Return value: on success: NO_ERROR; caller is responsible for free-ing - // outData (using free(3)). On failure, any status_t value other than - // NO_ERROR; the caller should not free outData. - status_t createIdmap(const ResTable& overlay, uint32_t originalCrc, uint32_t overlayCrc, - void** outData, size_t* outSize) const; - - enum { - IDMAP_HEADER_SIZE_BYTES = 3 * sizeof(uint32_t), - }; - // Retrieve idmap meta-data. - // - // This function only requires the idmap header (the first - // IDMAP_HEADER_SIZE_BYTES) bytes of an idmap file. - static bool getIdmapInfo(const void* idmap, size_t size, - uint32_t* pOriginalCrc, uint32_t* pOverlayCrc); - - void print(bool inclValues) const; - static String8 normalizeForOutput(const char* input); - -private: - struct Header; - struct Type; - struct Package; - struct PackageGroup; - struct bag_set; - - status_t add(const void* data, size_t size, void* cookie, - Asset* asset, bool copyData, const Asset* idmap); - - ssize_t getResourcePackageIndex(uint32_t resID) const; - ssize_t getEntry( - const Package* package, int typeIndex, int entryIndex, - const ResTable_config* config, - const ResTable_type** outType, const ResTable_entry** outEntry, - const Type** outTypeClass) const; - status_t parsePackage( - const ResTable_package* const pkg, const Header* const header, uint32_t idmap_id); - - void print_value(const Package* pkg, const Res_value& value) const; - - mutable Mutex mLock; - - status_t mError; - - ResTable_config mParams; - - // Array of all resource tables. - Vector mHeaders; - - // Array of packages in all resource tables. - Vector mPackageGroups; - - // Mapping from resource package IDs to indices into the internal - // package array. - uint8_t mPackageMap[256]; -}; - -} // namespace android - -#endif // _LIBS_UTILS_RESOURCE_TYPES_H diff --git a/include/androidfw/StreamingZipInflater.h b/include/androidfw/StreamingZipInflater.h deleted file mode 100644 index 3ace5d5a83..0000000000 --- a/include/androidfw/StreamingZipInflater.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2010 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 __LIBS_STREAMINGZIPINFLATER_H -#define __LIBS_STREAMINGZIPINFLATER_H - -#include -#include -#include - -#include - -namespace android { - -class StreamingZipInflater { -public: - static const size_t INPUT_CHUNK_SIZE = 64 * 1024; - static const size_t OUTPUT_CHUNK_SIZE = 64 * 1024; - - // Flavor that pages in the compressed data from a fd - StreamingZipInflater(int fd, off64_t compDataStart, size_t uncompSize, size_t compSize); - - // Flavor that gets the compressed data from an in-memory buffer - StreamingZipInflater(class FileMap* dataMap, size_t uncompSize); - - ~StreamingZipInflater(); - - // read 'count' bytes of uncompressed data from the current position. outBuf may - // be NULL, in which case the data is consumed and discarded. - ssize_t read(void* outBuf, size_t count); - - // seeking backwards requires uncompressing fom the beginning, so is very - // expensive. seeking forwards only requires uncompressing from the current - // position to the destination. - off64_t seekAbsolute(off64_t absoluteInputPosition); - -private: - void initInflateState(); - int readNextChunk(); - - // where to find the uncompressed data - int mFd; - off64_t mInFileStart; // where the compressed data lives in the file - class FileMap* mDataMap; - - z_stream mInflateState; - bool mStreamNeedsInit; - - // output invariants for this asset - uint8_t* mOutBuf; // output buf for decompressed bytes - size_t mOutBufSize; // allocated size of mOutBuf - size_t mOutTotalSize; // total uncompressed size of the blob - - // current output state bookkeeping - off64_t mOutCurPosition; // current position in total offset - size_t mOutLastDecoded; // last decoded byte + 1 in mOutbuf - size_t mOutDeliverable; // next undelivered byte of decoded output in mOutBuf - - // input invariants - uint8_t* mInBuf; - size_t mInBufSize; // allocated size of mInBuf; - size_t mInTotalSize; // total size of compressed data for this blob - - // input state bookkeeping - size_t mInNextChunkOffset; // offset from start of blob at which the next input chunk lies - // the z_stream contains state about input block consumption -}; - -} - -#endif diff --git a/include/androidfw/ZipFileRO.h b/include/androidfw/ZipFileRO.h deleted file mode 100644 index ad5be1232e..0000000000 --- a/include/androidfw/ZipFileRO.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * 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. - */ - -/* - * Read-only access to Zip archives, with minimal heap allocation. - * - * This is similar to the more-complete ZipFile class, but no attempt - * has been made to make them interchangeable. This class operates under - * a very different set of assumptions and constraints. - * - * One such assumption is that if you're getting file descriptors for - * use with this class as a child of a fork() operation, you must be on - * a pread() to guarantee correct operation. This is because pread() can - * atomically read at a file offset without worrying about a lock around an - * lseek() + read() pair. - */ -#ifndef __LIBS_ZIPFILERO_H -#define __LIBS_ZIPFILERO_H - -#include -#include -#include -#include - -#include -#include -#include -#include - -typedef void* ZipArchiveHandle; - -namespace android { - -/* - * Trivial typedef to ensure that ZipEntryRO is not treated as a simple - * integer. We use NULL to indicate an invalid value. - */ -typedef void* ZipEntryRO; - -/* - * Open a Zip archive for reading. - * - * Implemented as a thin wrapper over system/core/libziparchive. - * - * "open" and "find entry by name" are fast operations and use as little - * memory as possible. - * - * 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 - * on the shared file descriptors. - */ -class ZipFileRO { -public: - /* Zip compression methods we support */ - enum { - kCompressStored = 0, // no compression - kCompressDeflated = 8, // standard deflate - }; - - /* - * Open an archive. - */ - static ZipFileRO* open(const char* zipFileName); - - /* - * Find an entry, by name. Returns the entry identifier, or NULL if - * not found. - */ - 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(); - - /* - * Copy the filename into the supplied buffer. Returns 0 on success, - * -1 if "entry" is invalid, or the filename length if it didn't fit. The - * length, and the returned string, include the null-termination. - */ - int getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen) const; - - /* - * Get the vital stats for an entry. Pass in NULL pointers for anything - * you don't need. - * - * "*pOffset" holds the Zip file offset of the entry's data. - * - * Returns "false" if "entry" is bogus or if the data in the Zip file - * appears to be bad. - */ - bool getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen, - size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const; - - /* - * Create a new FileMap object that maps a subset of the archive. For - * an uncompressed entry this effectively provides a pointer to the - * actual data, for a compressed entry this provides the input buffer - * for inflate(). - */ - FileMap* createEntryFileMap(ZipEntryRO entry) const; - - /* - * Uncompress the data into a buffer. Depending on the compression - * format, this is either an "inflate" operation or a memcpy. - * - * Use "uncompLen" from getEntryInfo() to determine the required - * buffer size. - * - * Returns "true" on success. - */ - 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; - - ~ZipFileRO(); - -private: - /* these are private and not defined */ - ZipFileRO(const ZipFileRO& src); - ZipFileRO& operator=(const ZipFileRO& src); - - ZipFileRO(ZipArchiveHandle handle, char* fileName) : mHandle(handle), - mFileName(fileName) - { - } - - const ZipArchiveHandle mHandle; - char* mFileName; -}; - -}; // namespace android - -#endif /*__LIBS_ZIPFILERO_H*/ diff --git a/include/androidfw/ZipUtils.h b/include/androidfw/ZipUtils.h deleted file mode 100644 index 6bea25af80..0000000000 --- a/include/androidfw/ZipUtils.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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. - */ - -// -// Miscellaneous zip/gzip utility functions. -// -#ifndef __LIBS_ZIPUTILS_H -#define __LIBS_ZIPUTILS_H - -#include -#include - -namespace android { - -/* - * Container class for utility functions, primarily for namespace reasons. - */ -class ZipUtils { -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(void *in, void* buf, long uncompressedLen, - long compressedLen); - - /* - * Someday we might want to make this generic and handle bzip2 ".bz2" - * files too. - * - * We could declare gzip to be a sub-class of zip that has exactly - * one always-compressed entry, but we currently want to treat Zip - * and gzip as distinct, so there's no value. - * - * The zlib library has some gzip utilities, but it has no interface - * for extracting the uncompressed length of the file (you do *not* - * want to gzseek to the end). - * - * Pass in a seeked file pointer for the gzip file. If this is a gzip - * file, we set our return values appropriately and return "true" with - * the file seeked to the start of the compressed data. - */ - 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() {} -}; - -}; // namespace android - -#endif /*__LIBS_ZIPUTILS_H*/ diff --git a/include/androidfw/misc.h b/include/androidfw/misc.h deleted file mode 100644 index 5a5a0e2912..0000000000 --- a/include/androidfw/misc.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2005 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 - -// -// Handy utility functions and portability code. -// -#ifndef _LIBS_ANDROID_FW_MISC_H -#define _LIBS_ANDROID_FW_MISC_H - -namespace android { - -/* - * Some utility functions for working with files. These could be made - * part of a "File" class. - */ -typedef enum FileType { - kFileTypeUnknown = 0, - kFileTypeNonexistent, // i.e. ENOENT - kFileTypeRegular, - kFileTypeDirectory, - kFileTypeCharDev, - kFileTypeBlockDev, - kFileTypeFifo, - kFileTypeSymlink, - kFileTypeSocket, -} FileType; -/* get the file's type; follows symlinks */ -FileType getFileType(const char* fileName); -/* get the file's modification date; returns -1 w/errno set on failure */ -time_t getFileModDate(const char* fileName); - -}; // namespace android - -#endif // _LIBS_ANDROID_FW_MISC_H diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk deleted file mode 100644 index d21197e3a6..0000000000 --- a/libs/androidfw/Android.mk +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright (C) 2010 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. - -LOCAL_PATH:= $(call my-dir) - -# libandroidfw is partially built for the host (used by obbtool and others) -# These files are common to host and target builds. - -commonSources := \ - Asset.cpp \ - AssetDir.cpp \ - AssetManager.cpp \ - misc.cpp \ - ObbFile.cpp \ - ResourceTypes.cpp \ - StreamingZipInflater.cpp \ - ZipFileRO.cpp \ - ZipUtils.cpp - -deviceSources := \ - $(commonSources) \ - BackupData.cpp \ - BackupHelpers.cpp \ - CursorWindow.cpp - -hostSources := \ - $(commonSources) - -# For the host -# ===================================================== - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= $(hostSources) - -LOCAL_MODULE:= libandroidfw - -LOCAL_MODULE_TAGS := optional - -LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS - -LOCAL_C_INCLUDES := \ - external/zlib - -LOCAL_STATIC_LIBRARIES := liblog libziparchive-host libutils - -include $(BUILD_HOST_STATIC_LIBRARY) - - -# For the device -# ===================================================== - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= $(deviceSources) - -LOCAL_SHARED_LIBRARIES := \ - libbinder \ - liblog \ - libcutils \ - libutils \ - libz - -LOCAL_STATIC_LIBRARIES := libziparchive - -LOCAL_C_INCLUDES := \ - external/icu4c/common \ - external/zlib \ - system/core/include - -LOCAL_MODULE:= libandroidfw - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) - - -# Include subdirectory makefiles -# ============================================================ - -# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework -# team really wants is to build the stuff defined by this makefile. -ifeq (,$(ONE_SHOT_MAKEFILE)) -include $(call first-makefiles-under,$(LOCAL_PATH)) -endif diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp deleted file mode 100644 index ce6cc38b83..0000000000 --- a/libs/androidfw/Asset.cpp +++ /dev/null @@ -1,897 +0,0 @@ -/* - * Copyright (C) 2006 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. - */ - -// -// Provide access to a read-only asset. -// - -#define LOG_TAG "asset" -//#define NDEBUG 0 - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace android; - -#ifndef O_BINARY -# define O_BINARY 0 -#endif - -static Mutex gAssetLock; -static int32_t gCount = 0; -static Asset* gHead = NULL; -static Asset* gTail = NULL; - -int32_t Asset::getGlobalCount() -{ - AutoMutex _l(gAssetLock); - return gCount; -} - -String8 Asset::getAssetAllocations() -{ - AutoMutex _l(gAssetLock); - String8 res; - Asset* cur = gHead; - while (cur != NULL) { - if (cur->isAllocated()) { - res.append(" "); - res.append(cur->getAssetSource()); - off64_t size = (cur->getLength()+512)/1024; - char buf[64]; - sprintf(buf, ": %dK\n", (int)size); - res.append(buf); - } - cur = cur->mNext; - } - - return res; -} - -Asset::Asset(void) - : mAccessMode(ACCESS_UNKNOWN) -{ - AutoMutex _l(gAssetLock); - gCount++; - mNext = mPrev = NULL; - if (gTail == NULL) { - gHead = gTail = this; - } else { - mPrev = gTail; - gTail->mNext = this; - gTail = this; - } - //ALOGI("Creating Asset %p #%d\n", this, gCount); -} - -Asset::~Asset(void) -{ - AutoMutex _l(gAssetLock); - gCount--; - if (gHead == this) { - gHead = mNext; - } - if (gTail == this) { - gTail = mPrev; - } - if (mNext != NULL) { - mNext->mPrev = mPrev; - } - if (mPrev != NULL) { - mPrev->mNext = mNext; - } - mNext = mPrev = NULL; - //ALOGI("Destroying Asset in %p #%d\n", this, gCount); -} - -/* - * Create a new Asset from a file on disk. There is a fair chance that - * the file doesn't actually exist. - * - * We can use "mode" to decide how we want to go about it. - */ -/*static*/ Asset* Asset::createFromFile(const char* fileName, AccessMode mode) -{ - _FileAsset* pAsset; - status_t result; - off64_t length; - int fd; - - fd = open(fileName, O_RDONLY | O_BINARY); - if (fd < 0) - return NULL; - - /* - * Under Linux, the lseek fails if we actually opened a directory. To - * be correct we should test the file type explicitly, but since we - * always open things read-only it doesn't really matter, so there's - * no value in incurring the extra overhead of an fstat() call. - */ - // TODO(kroot): replace this with fstat despite the plea above. -#if 1 - length = lseek64(fd, 0, SEEK_END); - if (length < 0) { - ::close(fd); - return NULL; - } - (void) lseek64(fd, 0, SEEK_SET); -#else - struct stat st; - if (fstat(fd, &st) < 0) { - ::close(fd); - return NULL; - } - - if (!S_ISREG(st.st_mode)) { - ::close(fd); - return NULL; - } -#endif - - pAsset = new _FileAsset; - result = pAsset->openChunk(fileName, fd, 0, length); - if (result != NO_ERROR) { - delete pAsset; - return NULL; - } - - pAsset->mAccessMode = mode; - return pAsset; -} - - -/* - * Create a new Asset from a compressed file on disk. There is a fair chance - * that the file doesn't actually exist. - * - * We currently support gzip files. We might want to handle .bz2 someday. - */ -/*static*/ Asset* Asset::createFromCompressedFile(const char* fileName, - AccessMode mode) -{ - _CompressedAsset* pAsset; - status_t result; - off64_t fileLen; - bool scanResult; - long offset; - int method; - long uncompressedLen, compressedLen; - int fd; - - fd = open(fileName, O_RDONLY | O_BINARY); - if (fd < 0) - return NULL; - - fileLen = lseek(fd, 0, SEEK_END); - if (fileLen < 0) { - ::close(fd); - return NULL; - } - (void) lseek(fd, 0, SEEK_SET); - - /* want buffered I/O for the file scan; must dup so fclose() is safe */ - FILE* fp = fdopen(dup(fd), "rb"); - if (fp == NULL) { - ::close(fd); - return NULL; - } - - unsigned long crc32; - scanResult = ZipUtils::examineGzip(fp, &method, &uncompressedLen, - &compressedLen, &crc32); - offset = ftell(fp); - fclose(fp); - if (!scanResult) { - ALOGD("File '%s' is not in gzip format\n", fileName); - ::close(fd); - return NULL; - } - - pAsset = new _CompressedAsset; - result = pAsset->openChunk(fd, offset, method, uncompressedLen, - compressedLen); - if (result != NO_ERROR) { - delete pAsset; - return NULL; - } - - pAsset->mAccessMode = mode; - return pAsset; -} - - -#if 0 -/* - * Create a new Asset from part of an open file. - */ -/*static*/ Asset* Asset::createFromFileSegment(int fd, off64_t offset, - size_t length, AccessMode mode) -{ - _FileAsset* pAsset; - status_t result; - - pAsset = new _FileAsset; - result = pAsset->openChunk(NULL, fd, offset, length); - if (result != NO_ERROR) - return NULL; - - pAsset->mAccessMode = mode; - return pAsset; -} - -/* - * Create a new Asset from compressed data in an open file. - */ -/*static*/ Asset* Asset::createFromCompressedData(int fd, off64_t offset, - int compressionMethod, size_t uncompressedLen, size_t compressedLen, - AccessMode mode) -{ - _CompressedAsset* pAsset; - status_t result; - - pAsset = new _CompressedAsset; - result = pAsset->openChunk(fd, offset, compressionMethod, - uncompressedLen, compressedLen); - if (result != NO_ERROR) - return NULL; - - pAsset->mAccessMode = mode; - return pAsset; -} -#endif - -/* - * Create a new Asset from a memory mapping. - */ -/*static*/ Asset* Asset::createFromUncompressedMap(FileMap* dataMap, - AccessMode mode) -{ - _FileAsset* pAsset; - status_t result; - - pAsset = new _FileAsset; - result = pAsset->openChunk(dataMap); - if (result != NO_ERROR) - return NULL; - - pAsset->mAccessMode = mode; - return pAsset; -} - -/* - * Create a new Asset from compressed data in a memory mapping. - */ -/*static*/ Asset* Asset::createFromCompressedMap(FileMap* dataMap, - int method, size_t uncompressedLen, AccessMode mode) -{ - _CompressedAsset* pAsset; - status_t result; - - pAsset = new _CompressedAsset; - result = pAsset->openChunk(dataMap, method, uncompressedLen); - if (result != NO_ERROR) - return NULL; - - pAsset->mAccessMode = mode; - return pAsset; -} - - -/* - * Do generic seek() housekeeping. Pass in the offset/whence values from - * the seek request, along with the current chunk offset and the chunk - * length. - * - * Returns the new chunk offset, or -1 if the seek is illegal. - */ -off64_t Asset::handleSeek(off64_t offset, int whence, off64_t curPosn, off64_t maxPosn) -{ - off64_t newOffset; - - switch (whence) { - case SEEK_SET: - newOffset = offset; - break; - case SEEK_CUR: - newOffset = curPosn + offset; - break; - case SEEK_END: - newOffset = maxPosn + offset; - break; - default: - ALOGW("unexpected whence %d\n", whence); - // this was happening due to an off64_t size mismatch - assert(false); - return (off64_t) -1; - } - - if (newOffset < 0 || newOffset > maxPosn) { - ALOGW("seek out of range: want %ld, end=%ld\n", - (long) newOffset, (long) maxPosn); - return (off64_t) -1; - } - - return newOffset; -} - - -/* - * =========================================================================== - * _FileAsset - * =========================================================================== - */ - -/* - * Constructor. - */ -_FileAsset::_FileAsset(void) - : mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mMap(NULL), mBuf(NULL) -{ -} - -/* - * Destructor. Release resources. - */ -_FileAsset::~_FileAsset(void) -{ - close(); -} - -/* - * Operate on a chunk of an uncompressed file. - * - * Zero-length chunks are allowed. - */ -status_t _FileAsset::openChunk(const char* fileName, int fd, off64_t offset, size_t length) -{ - assert(mFp == NULL); // no reopen - assert(mMap == NULL); - assert(fd >= 0); - assert(offset >= 0); - - /* - * Seek to end to get file length. - */ - off64_t fileLength; - fileLength = lseek64(fd, 0, SEEK_END); - if (fileLength == (off64_t) -1) { - // probably a bad file descriptor - ALOGD("failed lseek (errno=%d)\n", errno); - return UNKNOWN_ERROR; - } - - if ((off64_t) (offset + length) > fileLength) { - ALOGD("start (%ld) + len (%ld) > end (%ld)\n", - (long) offset, (long) length, (long) fileLength); - return BAD_INDEX; - } - - /* after fdopen, the fd will be closed on fclose() */ - mFp = fdopen(fd, "rb"); - if (mFp == NULL) - return UNKNOWN_ERROR; - - mStart = offset; - mLength = length; - assert(mOffset == 0); - - /* seek the FILE* to the start of chunk */ - if (fseek(mFp, mStart, SEEK_SET) != 0) { - assert(false); - } - - mFileName = fileName != NULL ? strdup(fileName) : NULL; - - return NO_ERROR; -} - -/* - * Create the chunk from the map. - */ -status_t _FileAsset::openChunk(FileMap* dataMap) -{ - assert(mFp == NULL); // no reopen - assert(mMap == NULL); - assert(dataMap != NULL); - - mMap = dataMap; - mStart = -1; // not used - mLength = dataMap->getDataLength(); - assert(mOffset == 0); - - return NO_ERROR; -} - -/* - * Read a chunk of data. - */ -ssize_t _FileAsset::read(void* buf, size_t count) -{ - size_t maxLen; - size_t actual; - - assert(mOffset >= 0 && mOffset <= mLength); - - if (getAccessMode() == ACCESS_BUFFER) { - /* - * On first access, read or map the entire file. The caller has - * requested buffer access, either because they're going to be - * using the buffer or because what they're doing has appropriate - * performance needs and access patterns. - */ - if (mBuf == NULL) - getBuffer(false); - } - - /* adjust count if we're near EOF */ - maxLen = mLength - mOffset; - if (count > maxLen) - count = maxLen; - - if (!count) - return 0; - - if (mMap != NULL) { - /* copy from mapped area */ - //printf("map read\n"); - memcpy(buf, (char*)mMap->getDataPtr() + mOffset, count); - actual = count; - } else if (mBuf != NULL) { - /* copy from buffer */ - //printf("buf read\n"); - memcpy(buf, (char*)mBuf + mOffset, count); - actual = count; - } else { - /* read from the file */ - //printf("file read\n"); - if (ftell(mFp) != mStart + mOffset) { - ALOGE("Hosed: %ld != %ld+%ld\n", - ftell(mFp), (long) mStart, (long) mOffset); - assert(false); - } - - /* - * This returns 0 on error or eof. We need to use ferror() or feof() - * to tell the difference, but we don't currently have those on the - * device. However, we know how much data is *supposed* to be in the - * file, so if we don't read the full amount we know something is - * hosed. - */ - actual = fread(buf, 1, count, mFp); - if (actual == 0) // something failed -- I/O error? - return -1; - - assert(actual == count); - } - - mOffset += actual; - return actual; -} - -/* - * Seek to a new position. - */ -off64_t _FileAsset::seek(off64_t offset, int whence) -{ - off64_t newPosn; - off64_t actualOffset; - - // compute new position within chunk - newPosn = handleSeek(offset, whence, mOffset, mLength); - if (newPosn == (off64_t) -1) - return newPosn; - - actualOffset = mStart + newPosn; - - if (mFp != NULL) { - if (fseek(mFp, (long) actualOffset, SEEK_SET) != 0) - return (off64_t) -1; - } - - mOffset = actualOffset - mStart; - return mOffset; -} - -/* - * Close the asset. - */ -void _FileAsset::close(void) -{ - if (mMap != NULL) { - mMap->release(); - mMap = NULL; - } - if (mBuf != NULL) { - delete[] mBuf; - mBuf = NULL; - } - - if (mFileName != NULL) { - free(mFileName); - mFileName = NULL; - } - - if (mFp != NULL) { - // can only be NULL when called from destructor - // (otherwise we would never return this object) - fclose(mFp); - mFp = NULL; - } -} - -/* - * Return a read-only pointer to a buffer. - * - * We can either read the whole thing in or map the relevant piece of - * the source file. Ideally a map would be established at a higher - * level and we'd be using a different object, but we didn't, so we - * deal with it here. - */ -const void* _FileAsset::getBuffer(bool wordAligned) -{ - /* subsequent requests just use what we did previously */ - if (mBuf != NULL) - return mBuf; - if (mMap != NULL) { - if (!wordAligned) { - return mMap->getDataPtr(); - } - return ensureAlignment(mMap); - } - - assert(mFp != NULL); - - if (mLength < kReadVsMapThreshold) { - unsigned char* buf; - long allocLen; - - /* zero-length files are allowed; not sure about zero-len allocs */ - /* (works fine with gcc + x86linux) */ - allocLen = mLength; - if (mLength == 0) - allocLen = 1; - - buf = new unsigned char[allocLen]; - if (buf == NULL) { - ALOGE("alloc of %ld bytes failed\n", (long) allocLen); - return NULL; - } - - ALOGV("Asset %p allocating buffer size %d (smaller than threshold)", this, (int)allocLen); - if (mLength > 0) { - long oldPosn = ftell(mFp); - fseek(mFp, mStart, SEEK_SET); - if (fread(buf, 1, mLength, mFp) != (size_t) mLength) { - ALOGE("failed reading %ld bytes\n", (long) mLength); - delete[] buf; - return NULL; - } - fseek(mFp, oldPosn, SEEK_SET); - } - - ALOGV(" getBuffer: loaded into buffer\n"); - - mBuf = buf; - return mBuf; - } else { - FileMap* map; - - map = new FileMap; - if (!map->create(NULL, fileno(mFp), mStart, mLength, true)) { - map->release(); - return NULL; - } - - ALOGV(" getBuffer: mapped\n"); - - mMap = map; - if (!wordAligned) { - return mMap->getDataPtr(); - } - return ensureAlignment(mMap); - } -} - -int _FileAsset::openFileDescriptor(off64_t* outStart, off64_t* outLength) const -{ - if (mMap != NULL) { - const char* fname = mMap->getFileName(); - if (fname == NULL) { - fname = mFileName; - } - if (fname == NULL) { - return -1; - } - *outStart = mMap->getDataOffset(); - *outLength = mMap->getDataLength(); - return open(fname, O_RDONLY | O_BINARY); - } - if (mFileName == NULL) { - return -1; - } - *outStart = mStart; - *outLength = mLength; - return open(mFileName, O_RDONLY | O_BINARY); -} - -const void* _FileAsset::ensureAlignment(FileMap* map) -{ - void* data = map->getDataPtr(); - if ((((size_t)data)&0x3) == 0) { - // We can return this directly if it is aligned on a word - // boundary. - ALOGV("Returning aligned FileAsset %p (%s).", this, - getAssetSource()); - return data; - } - // If not aligned on a word boundary, then we need to copy it into - // our own buffer. - ALOGV("Copying FileAsset %p (%s) to buffer size %d to make it aligned.", this, - getAssetSource(), (int)mLength); - unsigned char* buf = new unsigned char[mLength]; - if (buf == NULL) { - ALOGE("alloc of %ld bytes failed\n", (long) mLength); - return NULL; - } - memcpy(buf, data, mLength); - mBuf = buf; - return buf; -} - -/* - * =========================================================================== - * _CompressedAsset - * =========================================================================== - */ - -/* - * Constructor. - */ -_CompressedAsset::_CompressedAsset(void) - : mStart(0), mCompressedLen(0), mUncompressedLen(0), mOffset(0), - mMap(NULL), mFd(-1), mZipInflater(NULL), mBuf(NULL) -{ -} - -/* - * Destructor. Release resources. - */ -_CompressedAsset::~_CompressedAsset(void) -{ - close(); -} - -/* - * Open a chunk of compressed data inside a file. - * - * This currently just sets up some values and returns. On the first - * read, we expand the entire file into a buffer and return data from it. - */ -status_t _CompressedAsset::openChunk(int fd, off64_t offset, - int compressionMethod, size_t uncompressedLen, size_t compressedLen) -{ - assert(mFd < 0); // no re-open - assert(mMap == NULL); - assert(fd >= 0); - assert(offset >= 0); - assert(compressedLen > 0); - - if (compressionMethod != ZipFileRO::kCompressDeflated) { - assert(false); - return UNKNOWN_ERROR; - } - - mStart = offset; - mCompressedLen = compressedLen; - mUncompressedLen = uncompressedLen; - assert(mOffset == 0); - mFd = fd; - assert(mBuf == NULL); - - if (uncompressedLen > StreamingZipInflater::OUTPUT_CHUNK_SIZE) { - mZipInflater = new StreamingZipInflater(mFd, offset, uncompressedLen, compressedLen); - } - - return NO_ERROR; -} - -/* - * Open a chunk of compressed data in a mapped region. - * - * Nothing is expanded until the first read call. - */ -status_t _CompressedAsset::openChunk(FileMap* dataMap, int compressionMethod, - size_t uncompressedLen) -{ - assert(mFd < 0); // no re-open - assert(mMap == NULL); - assert(dataMap != NULL); - - if (compressionMethod != ZipFileRO::kCompressDeflated) { - assert(false); - return UNKNOWN_ERROR; - } - - mMap = dataMap; - mStart = -1; // not used - mCompressedLen = dataMap->getDataLength(); - mUncompressedLen = uncompressedLen; - assert(mOffset == 0); - - if (uncompressedLen > StreamingZipInflater::OUTPUT_CHUNK_SIZE) { - mZipInflater = new StreamingZipInflater(dataMap, uncompressedLen); - } - return NO_ERROR; -} - -/* - * Read data from a chunk of compressed data. - * - * [For now, that's just copying data out of a buffer.] - */ -ssize_t _CompressedAsset::read(void* buf, size_t count) -{ - size_t maxLen; - size_t actual; - - assert(mOffset >= 0 && mOffset <= mUncompressedLen); - - /* If we're relying on a streaming inflater, go through that */ - if (mZipInflater) { - actual = mZipInflater->read(buf, count); - } else { - if (mBuf == NULL) { - if (getBuffer(false) == NULL) - return -1; - } - assert(mBuf != NULL); - - /* adjust count if we're near EOF */ - maxLen = mUncompressedLen - mOffset; - if (count > maxLen) - count = maxLen; - - if (!count) - return 0; - - /* copy from buffer */ - //printf("comp buf read\n"); - memcpy(buf, (char*)mBuf + mOffset, count); - actual = count; - } - - mOffset += actual; - return actual; -} - -/* - * Handle a seek request. - * - * If we're working in a streaming mode, this is going to be fairly - * expensive, because it requires plowing through a bunch of compressed - * data. - */ -off64_t _CompressedAsset::seek(off64_t offset, int whence) -{ - off64_t newPosn; - - // compute new position within chunk - newPosn = handleSeek(offset, whence, mOffset, mUncompressedLen); - if (newPosn == (off64_t) -1) - return newPosn; - - if (mZipInflater) { - mZipInflater->seekAbsolute(newPosn); - } - mOffset = newPosn; - return mOffset; -} - -/* - * Close the asset. - */ -void _CompressedAsset::close(void) -{ - if (mMap != NULL) { - mMap->release(); - mMap = NULL; - } - - delete[] mBuf; - mBuf = NULL; - - delete mZipInflater; - mZipInflater = NULL; - - if (mFd > 0) { - ::close(mFd); - mFd = -1; - } -} - -/* - * Get a pointer to a read-only buffer of data. - * - * The first time this is called, we expand the compressed data into a - * buffer. - */ -const void* _CompressedAsset::getBuffer(bool) -{ - unsigned char* buf = NULL; - - if (mBuf != NULL) - return mBuf; - - /* - * Allocate a buffer and read the file into it. - */ - buf = new unsigned char[mUncompressedLen]; - if (buf == NULL) { - ALOGW("alloc %ld bytes failed\n", (long) mUncompressedLen); - goto bail; - } - - if (mMap != NULL) { - if (!ZipUtils::inflateToBuffer(mMap->getDataPtr(), buf, - mUncompressedLen, mCompressedLen)) - goto bail; - } else { - assert(mFd >= 0); - - /* - * Seek to the start of the compressed data. - */ - if (lseek(mFd, mStart, SEEK_SET) != mStart) - goto bail; - - /* - * Expand the data into it. - */ - if (!ZipUtils::inflateToBuffer(mFd, buf, mUncompressedLen, - mCompressedLen)) - goto bail; - } - - /* - * Success - now that we have the full asset in RAM we - * no longer need the streaming inflater - */ - delete mZipInflater; - mZipInflater = NULL; - - mBuf = buf; - buf = NULL; - -bail: - delete[] buf; - return mBuf; -} - diff --git a/libs/androidfw/AssetDir.cpp b/libs/androidfw/AssetDir.cpp deleted file mode 100644 index 475f521c11..0000000000 --- a/libs/androidfw/AssetDir.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2006 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. - */ - -// -// Provide access to a virtual directory in "asset space". Most of the -// implementation is in the header file or in friend functions in -// AssetManager. -// -#include - -using namespace android; - - -/* - * Find a matching entry in a vector of FileInfo. Because it's sorted, we - * can use a binary search. - * - * Assumes the vector is sorted in ascending order. - */ -/*static*/ int AssetDir::FileInfo::findEntry(const SortedVector* pVector, - const String8& fileName) -{ - FileInfo tmpInfo; - - tmpInfo.setFileName(fileName); - return pVector->indexOf(tmpInfo); - -#if 0 // don't need this after all (uses 1/2 compares of SortedVector though) - int lo, hi, cur; - - lo = 0; - hi = pVector->size() -1; - while (lo <= hi) { - int cmp; - - cur = (hi + lo) / 2; - cmp = strcmp(pVector->itemAt(cur).getFileName(), fileName); - if (cmp == 0) { - /* match, bail */ - return cur; - } else if (cmp < 0) { - /* too low */ - lo = cur + 1; - } else { - /* too high */ - hi = cur -1; - } - } - - return -1; -#endif -} - diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp deleted file mode 100644 index 785e5d4ae3..0000000000 --- a/libs/androidfw/AssetManager.cpp +++ /dev/null @@ -1,2035 +0,0 @@ -/* - * Copyright (C) 2006 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. - */ - -// -// Provide access to read-only assets. -// - -#define LOG_TAG "asset" -#define ATRACE_TAG ATRACE_TAG_RESOURCES -//#define LOG_NDEBUG 0 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_ANDROID_OS -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#ifndef TEMP_FAILURE_RETRY -/* Used to retry syscalls that can return EINTR. */ -#define TEMP_FAILURE_RETRY(exp) ({ \ - typeof (exp) _rc; \ - do { \ - _rc = (exp); \ - } while (_rc == -1 && errno == EINTR); \ - _rc; }) -#endif - -#ifdef HAVE_ANDROID_OS -#define MY_TRACE_BEGIN(x) ATRACE_BEGIN(x) -#define MY_TRACE_END() ATRACE_END() -#else -#define MY_TRACE_BEGIN(x) -#define MY_TRACE_END() -#endif - -using namespace android; - -/* - * Names for default app, locale, and vendor. We might want to change - * these to be an actual locale, e.g. always use en-US as the default. - */ -static const char* kDefaultLocale = "default"; -static const char* kDefaultVendor = "default"; -static const char* kAssetsRoot = "assets"; -static const char* kAppZipName = NULL; //"classes.jar"; -static const char* kSystemAssets = "framework/framework-res.apk"; -static const char* kIdmapCacheDir = "resource-cache"; - -static const char* kExcludeExtension = ".EXCLUDE"; - -static Asset* const kExcludedAsset = (Asset*) 0xd000000d; - -static volatile int32_t gCount = 0; - -namespace { - // Transform string /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap - String8 idmapPathForPackagePath(const String8& pkgPath) - { - const char* root = getenv("ANDROID_DATA"); - LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set"); - String8 path(root); - path.appendPath(kIdmapCacheDir); - - char buf[256]; // 256 chars should be enough for anyone... - strncpy(buf, pkgPath.string(), 255); - buf[255] = '\0'; - char* filename = buf; - while (*filename && *filename == '/') { - ++filename; - } - char* p = filename; - while (*p) { - if (*p == '/') { - *p = '@'; - } - ++p; - } - path.appendPath(filename); - path.append("@idmap"); - - return path; - } - - /* - * Like strdup(), but uses C++ "new" operator instead of malloc. - */ - static char* strdupNew(const char* str) - { - char* newStr; - int len; - - if (str == NULL) - return NULL; - - len = strlen(str); - newStr = new char[len+1]; - memcpy(newStr, str, len+1); - - return newStr; - } -} - -/* - * =========================================================================== - * AssetManager - * =========================================================================== - */ - -int32_t AssetManager::getGlobalCount() -{ - return gCount; -} - -AssetManager::AssetManager(CacheMode cacheMode) - : mLocale(NULL), mVendor(NULL), - mResources(NULL), mConfig(new ResTable_config), - mCacheMode(cacheMode), mCacheValid(false) -{ - int count = android_atomic_inc(&gCount)+1; - //ALOGI("Creating AssetManager %p #%d\n", this, count); - memset(mConfig, 0, sizeof(ResTable_config)); -} - -AssetManager::~AssetManager(void) -{ - int count = android_atomic_dec(&gCount); - //ALOGI("Destroying AssetManager in %p #%d\n", this, count); - - delete mConfig; - delete mResources; - - // don't have a String class yet, so make sure we clean up - delete[] mLocale; - delete[] mVendor; -} - -bool AssetManager::addAssetPath(const String8& path, int32_t* cookie) -{ - AutoMutex _l(mLock); - - asset_path ap; - - String8 realPath(path); - if (kAppZipName) { - realPath.appendPath(kAppZipName); - } - ap.type = ::getFileType(realPath.string()); - if (ap.type == kFileTypeRegular) { - ap.path = realPath; - } else { - ap.path = path; - ap.type = ::getFileType(path.string()); - if (ap.type != kFileTypeDirectory && ap.type != kFileTypeRegular) { - ALOGW("Asset path %s is neither a directory nor file (type=%d).", - path.string(), (int)ap.type); - return false; - } - } - - // Skip if we have it already. - for (size_t i=0; i(i+1); - } - return true; - } - } - - ALOGV("In %p Asset %s path: %s", this, - ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string()); - - mAssetPaths.add(ap); - - // new paths are always added at the end - if (cookie) { - *cookie = static_cast(mAssetPaths.size()); - } - - // add overlay packages for /system/framework; apps are handled by the - // (Java) package manager - if (strncmp(path.string(), "/system/framework/", 18) == 0) { - // When there is an environment variable for /vendor, this - // should be changed to something similar to how ANDROID_ROOT - // and ANDROID_DATA are used in this file. - String8 overlayPath("/vendor/overlay/framework/"); - overlayPath.append(path.getPathLeaf()); - if (TEMP_FAILURE_RETRY(access(overlayPath.string(), R_OK)) == 0) { - asset_path oap; - oap.path = overlayPath; - oap.type = ::getFileType(overlayPath.string()); - bool addOverlay = (oap.type == kFileTypeRegular); // only .apks supported as overlay - if (addOverlay) { - oap.idmap = idmapPathForPackagePath(overlayPath); - - if (isIdmapStaleLocked(ap.path, oap.path, oap.idmap)) { - addOverlay = createIdmapFileLocked(ap.path, oap.path, oap.idmap); - } - } - if (addOverlay) { - mAssetPaths.add(oap); - } else { - ALOGW("failed to add overlay package %s\n", overlayPath.string()); - } - } - } - - return true; -} - -bool AssetManager::isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath, - const String8& idmapPath) -{ - struct stat st; - if (TEMP_FAILURE_RETRY(stat(idmapPath.string(), &st)) == -1) { - if (errno == ENOENT) { - return true; // non-existing idmap is always stale - } else { - ALOGW("failed to stat file %s: %s\n", idmapPath.string(), strerror(errno)); - return false; - } - } - if (st.st_size < ResTable::IDMAP_HEADER_SIZE_BYTES) { - ALOGW("file %s has unexpectedly small size=%zd\n", idmapPath.string(), (size_t)st.st_size); - return false; - } - int fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_RDONLY)); - if (fd == -1) { - ALOGW("failed to open file %s: %s\n", idmapPath.string(), strerror(errno)); - return false; - } - char buf[ResTable::IDMAP_HEADER_SIZE_BYTES]; - ssize_t bytesLeft = ResTable::IDMAP_HEADER_SIZE_BYTES; - for (;;) { - ssize_t r = TEMP_FAILURE_RETRY(read(fd, buf + ResTable::IDMAP_HEADER_SIZE_BYTES - bytesLeft, - bytesLeft)); - if (r < 0) { - TEMP_FAILURE_RETRY(close(fd)); - return false; - } - bytesLeft -= r; - if (bytesLeft == 0) { - break; - } - } - TEMP_FAILURE_RETRY(close(fd)); - - uint32_t cachedOriginalCrc, cachedOverlayCrc; - if (!ResTable::getIdmapInfo(buf, ResTable::IDMAP_HEADER_SIZE_BYTES, - &cachedOriginalCrc, &cachedOverlayCrc)) { - return false; - } - - uint32_t actualOriginalCrc, actualOverlayCrc; - if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &actualOriginalCrc)) { - return false; - } - if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &actualOverlayCrc)) { - return false; - } - return cachedOriginalCrc != actualOriginalCrc || cachedOverlayCrc != actualOverlayCrc; -} - -bool AssetManager::getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename, - uint32_t* pCrc) -{ - asset_path ap; - ap.path = zipPath; - const ZipFileRO* zip = getZipFileLocked(ap); - if (zip == NULL) { - return false; - } - const ZipEntryRO entry = zip->findEntryByName(entryFilename); - if (entry == NULL) { - return false; - } - - 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, - const String8& idmapPath) -{ - ALOGD("%s: originalPath=%s overlayPath=%s idmapPath=%s\n", - __FUNCTION__, originalPath.string(), overlayPath.string(), idmapPath.string()); - ResTable tables[2]; - const String8* paths[2] = { &originalPath, &overlayPath }; - uint32_t originalCrc, overlayCrc; - bool retval = false; - ssize_t offset = 0; - int fd = 0; - uint32_t* data = NULL; - size_t size; - - for (int i = 0; i < 2; ++i) { - asset_path ap; - ap.type = kFileTypeRegular; - ap.path = *paths[i]; - Asset* ass = openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap); - if (ass == NULL) { - ALOGW("failed to find resources.arsc in %s\n", ap.path.string()); - goto error; - } - tables[i].add(ass, (void*)1, false); - } - - if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &originalCrc)) { - ALOGW("failed to retrieve crc for resources.arsc in %s\n", originalPath.string()); - goto error; - } - if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &overlayCrc)) { - ALOGW("failed to retrieve crc for resources.arsc in %s\n", overlayPath.string()); - goto error; - } - - if (tables[0].createIdmap(tables[1], originalCrc, overlayCrc, - (void**)&data, &size) != NO_ERROR) { - ALOGW("failed to generate idmap data for file %s\n", idmapPath.string()); - goto error; - } - - // This should be abstracted (eg replaced by a stand-alone - // application like dexopt, triggered by something equivalent to - // installd). - fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_WRONLY | O_CREAT | O_TRUNC, 0644)); - if (fd == -1) { - ALOGW("failed to write idmap file %s (open: %s)\n", idmapPath.string(), strerror(errno)); - goto error_free; - } - for (;;) { - ssize_t written = TEMP_FAILURE_RETRY(write(fd, data + offset, size)); - if (written < 0) { - ALOGW("failed to write idmap file %s (write: %s)\n", idmapPath.string(), - strerror(errno)); - goto error_close; - } - size -= (size_t)written; - offset += written; - if (size == 0) { - break; - } - } - - retval = true; -error_close: - TEMP_FAILURE_RETRY(close(fd)); -error_free: - free(data); -error: - return retval; -} - -bool AssetManager::addDefaultAssets() -{ - const char* root = getenv("ANDROID_ROOT"); - LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_ROOT not set"); - - String8 path(root); - path.appendPath(kSystemAssets); - - return addAssetPath(path, NULL); -} - -int32_t AssetManager::nextAssetPath(const int32_t cookie) const -{ - AutoMutex _l(mLock); - const size_t next = static_cast(cookie) + 1; - return next > mAssetPaths.size() ? -1 : next; -} - -String8 AssetManager::getAssetPath(const int32_t cookie) const -{ - AutoMutex _l(mLock); - const size_t which = static_cast(cookie) - 1; - if (which < mAssetPaths.size()) { - return mAssetPaths[which].path; - } - return String8(); -} - -/* - * Set the current locale. Use NULL to indicate no locale. - * - * Close and reopen Zip archives as appropriate, and reset cached - * information in the locale-specific sections of the tree. - */ -void AssetManager::setLocale(const char* locale) -{ - AutoMutex _l(mLock); - setLocaleLocked(locale); -} - -void AssetManager::setLocaleLocked(const char* locale) -{ - if (mLocale != NULL) { - /* previously set, purge cached data */ - purgeFileNameCacheLocked(); - //mZipSet.purgeLocale(); - delete[] mLocale; - } - mLocale = strdupNew(locale); - - updateResourceParamsLocked(); -} - -/* - * Set the current vendor. Use NULL to indicate no vendor. - * - * Close and reopen Zip archives as appropriate, and reset cached - * information in the vendor-specific sections of the tree. - */ -void AssetManager::setVendor(const char* vendor) -{ - AutoMutex _l(mLock); - - if (mVendor != NULL) { - /* previously set, purge cached data */ - purgeFileNameCacheLocked(); - //mZipSet.purgeVendor(); - delete[] mVendor; - } - mVendor = strdupNew(vendor); -} - -void AssetManager::setConfiguration(const ResTable_config& config, const char* locale) -{ - AutoMutex _l(mLock); - *mConfig = config; - if (locale) { - setLocaleLocked(locale); - } else if (config.language[0] != 0) { - char spec[9]; - spec[0] = config.language[0]; - spec[1] = config.language[1]; - if (config.country[0] != 0) { - spec[2] = '_'; - spec[3] = config.country[0]; - spec[4] = config.country[1]; - spec[5] = 0; - } else { - spec[3] = 0; - } - setLocaleLocked(spec); - } else { - updateResourceParamsLocked(); - } -} - -void AssetManager::getConfiguration(ResTable_config* outConfig) const -{ - AutoMutex _l(mLock); - *outConfig = *mConfig; -} - -/* - * Open an asset. - * - * The data could be; - * - In a file on disk (assetBase + fileName). - * - In a compressed file on disk (assetBase + fileName.gz). - * - In a Zip archive, uncompressed or compressed. - * - * It can be in a number of different directories and Zip archives. - * The search order is: - * - [appname] - * - locale + vendor - * - "default" + vendor - * - locale + "default" - * - "default + "default" - * - "common" - * - (same as above) - * - * To find a particular file, we have to try up to eight paths with - * all three forms of data. - * - * We should probably reject requests for "illegal" filenames, e.g. those - * with illegal characters or "../" backward relative paths. - */ -Asset* AssetManager::open(const char* fileName, AccessMode mode) -{ - AutoMutex _l(mLock); - - LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager"); - - - if (mCacheMode != CACHE_OFF && !mCacheValid) - loadFileNameCacheLocked(); - - String8 assetName(kAssetsRoot); - assetName.appendPath(fileName); - - /* - * For each top-level asset path, search for the asset. - */ - - size_t i = mAssetPaths.size(); - while (i > 0) { - i--; - ALOGV("Looking for asset '%s' in '%s'\n", - assetName.string(), mAssetPaths.itemAt(i).path.string()); - Asset* pAsset = openNonAssetInPathLocked(assetName.string(), mode, mAssetPaths.itemAt(i)); - if (pAsset != NULL) { - return pAsset != kExcludedAsset ? pAsset : NULL; - } - } - - return NULL; -} - -/* - * Open a non-asset file as if it were an asset. - * - * The "fileName" is the partial path starting from the application - * name. - */ -Asset* AssetManager::openNonAsset(const char* fileName, AccessMode mode) -{ - AutoMutex _l(mLock); - - LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager"); - - - if (mCacheMode != CACHE_OFF && !mCacheValid) - loadFileNameCacheLocked(); - - /* - * For each top-level asset path, search for the asset. - */ - - size_t i = mAssetPaths.size(); - while (i > 0) { - i--; - ALOGV("Looking for non-asset '%s' in '%s'\n", fileName, mAssetPaths.itemAt(i).path.string()); - Asset* pAsset = openNonAssetInPathLocked( - fileName, mode, mAssetPaths.itemAt(i)); - if (pAsset != NULL) { - return pAsset != kExcludedAsset ? pAsset : NULL; - } - } - - return NULL; -} - -Asset* AssetManager::openNonAsset(const int32_t cookie, const char* fileName, AccessMode mode) -{ - const size_t which = static_cast(cookie) - 1; - - AutoMutex _l(mLock); - - LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager"); - - if (mCacheMode != CACHE_OFF && !mCacheValid) - loadFileNameCacheLocked(); - - if (which < mAssetPaths.size()) { - ALOGV("Looking for non-asset '%s' in '%s'\n", fileName, - mAssetPaths.itemAt(which).path.string()); - Asset* pAsset = openNonAssetInPathLocked( - fileName, mode, mAssetPaths.itemAt(which)); - if (pAsset != NULL) { - return pAsset != kExcludedAsset ? pAsset : NULL; - } - } - - return NULL; -} - -/* - * Get the type of a file in the asset namespace. - * - * This currently only works for regular files. All others (including - * directories) will return kFileTypeNonexistent. - */ -FileType AssetManager::getFileType(const char* fileName) -{ - Asset* pAsset = NULL; - - /* - * Open the asset. This is less efficient than simply finding the - * file, but it's not too bad (we don't uncompress or mmap data until - * the first read() call). - */ - pAsset = open(fileName, Asset::ACCESS_STREAMING); - delete pAsset; - - if (pAsset == NULL) - return kFileTypeNonexistent; - else - return kFileTypeRegular; -} - -const ResTable* AssetManager::getResTable(bool required) const -{ - ResTable* rt = mResources; - if (rt) { - return rt; - } - - // Iterate through all asset packages, collecting resources from each. - - AutoMutex _l(mLock); - - if (mResources != NULL) { - return mResources; - } - - if (required) { - LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager"); - } - - if (mCacheMode != CACHE_OFF && !mCacheValid) - const_cast(this)->loadFileNameCacheLocked(); - - const size_t N = mAssetPaths.size(); - for (size_t i=0; i(this)-> - mZipSet.getZipResourceTable(ap.path); - } - if (sharedRes == NULL) { - ass = const_cast(this)-> - mZipSet.getZipResourceTableAsset(ap.path); - if (ass == NULL) { - ALOGV("loading resource table %s\n", ap.path.string()); - ass = const_cast(this)-> - openNonAssetInPathLocked("resources.arsc", - Asset::ACCESS_BUFFER, - ap); - if (ass != NULL && ass != kExcludedAsset) { - ass = const_cast(this)-> - mZipSet.setZipResourceTableAsset(ap.path, ass); - } - } - - if (i == 0 && ass != NULL) { - // If this is the first resource table in the asset - // manager, then we are going to cache it so that we - // can quickly copy it out for others. - ALOGV("Creating shared resources for %s", ap.path.string()); - sharedRes = new ResTable(); - sharedRes->add(ass, (void*)(i+1), false, idmap); - sharedRes = const_cast(this)-> - mZipSet.setZipResourceTable(ap.path, sharedRes); - } - } - } else { - ALOGV("loading resource table %s\n", ap.path.string()); - ass = const_cast(this)-> - openNonAssetInPathLocked("resources.arsc", - Asset::ACCESS_BUFFER, - ap); - shared = false; - } - if ((ass != NULL || sharedRes != NULL) && ass != kExcludedAsset) { - if (rt == NULL) { - mResources = rt = new ResTable(); - updateResourceParamsLocked(); - } - ALOGV("Installing resource asset %p in to table %p\n", ass, mResources); - if (sharedRes != NULL) { - ALOGV("Copying existing resources for %s", ap.path.string()); - rt->add(sharedRes); - } else { - ALOGV("Parsing resources for %s", ap.path.string()); - rt->add(ass, (void*)(i+1), !shared, idmap); - } - - if (!shared) { - delete ass; - } - } - if (idmap != NULL) { - delete idmap; - } - MY_TRACE_END(); - } - - if (required && !rt) ALOGW("Unable to find resources file resources.arsc"); - if (!rt) { - mResources = rt = new ResTable(); - } - return rt; -} - -void AssetManager::updateResourceParamsLocked() const -{ - ResTable* res = mResources; - if (!res) { - return; - } - - size_t llen = mLocale ? strlen(mLocale) : 0; - mConfig->language[0] = 0; - mConfig->language[1] = 0; - mConfig->country[0] = 0; - mConfig->country[1] = 0; - if (llen >= 2) { - mConfig->language[0] = mLocale[0]; - mConfig->language[1] = mLocale[1]; - } - if (llen >= 5) { - mConfig->country[0] = mLocale[3]; - mConfig->country[1] = mLocale[4]; - } - mConfig->size = sizeof(*mConfig); - - res->setParameters(mConfig); -} - -Asset* AssetManager::openIdmapLocked(const struct asset_path& ap) const -{ - Asset* ass = NULL; - if (ap.idmap.size() != 0) { - ass = const_cast(this)-> - openAssetFromFileLocked(ap.idmap, Asset::ACCESS_BUFFER); - if (ass) { - ALOGV("loading idmap %s\n", ap.idmap.string()); - } else { - ALOGW("failed to load idmap %s\n", ap.idmap.string()); - } - } - return ass; -} - -const ResTable& AssetManager::getResources(bool required) const -{ - const ResTable* rt = getResTable(required); - return *rt; -} - -bool AssetManager::isUpToDate() -{ - AutoMutex _l(mLock); - return mZipSet.isUpToDate(); -} - -void AssetManager::getLocales(Vector* locales) const -{ - ResTable* res = mResources; - if (res != NULL) { - res->getLocales(locales); - } -} - -/* - * Open a non-asset file as if it were an asset, searching for it in the - * specified app. - * - * Pass in a NULL values for "appName" if the common app directory should - * be used. - */ -Asset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode mode, - const asset_path& ap) -{ - Asset* pAsset = NULL; - - /* look at the filesystem on disk */ - if (ap.type == kFileTypeDirectory) { - String8 path(ap.path); - path.appendPath(fileName); - - pAsset = openAssetFromFileLocked(path, mode); - - if (pAsset == NULL) { - /* try again, this time with ".gz" */ - path.append(".gz"); - pAsset = openAssetFromFileLocked(path, mode); - } - - if (pAsset != NULL) { - //printf("FOUND NA '%s' on disk\n", fileName); - pAsset->setAssetSource(path); - } - - /* look inside the zip file */ - } else { - String8 path(fileName); - - /* check the appropriate Zip file */ - ZipFileRO* pZip = getZipFileLocked(ap); - if (pZip != NULL) { - //printf("GOT zip, checking NA '%s'\n", (const char*) path); - 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); - } - } - - if (pAsset != NULL) { - /* create a "source" name, for debug/display */ - pAsset->setAssetSource( - createZipSourceNameLocked(ZipSet::getPathName(ap.path.string()), String8(""), - String8(fileName))); - } - } - - return pAsset; -} - -/* - * Open an asset, searching for it in the directory hierarchy for the - * specified app. - * - * Pass in a NULL values for "appName" if the common app directory should - * be used. - */ -Asset* AssetManager::openInPathLocked(const char* fileName, AccessMode mode, - const asset_path& ap) -{ - Asset* pAsset = NULL; - - /* - * Try various combinations of locale and vendor. - */ - if (mLocale != NULL && mVendor != NULL) - pAsset = openInLocaleVendorLocked(fileName, mode, ap, mLocale, mVendor); - if (pAsset == NULL && mVendor != NULL) - pAsset = openInLocaleVendorLocked(fileName, mode, ap, NULL, mVendor); - if (pAsset == NULL && mLocale != NULL) - pAsset = openInLocaleVendorLocked(fileName, mode, ap, mLocale, NULL); - if (pAsset == NULL) - pAsset = openInLocaleVendorLocked(fileName, mode, ap, NULL, NULL); - - return pAsset; -} - -/* - * Open an asset, searching for it in the directory hierarchy for the - * specified locale and vendor. - * - * We also search in "app.jar". - * - * Pass in NULL values for "appName", "locale", and "vendor" if the - * defaults should be used. - */ -Asset* AssetManager::openInLocaleVendorLocked(const char* fileName, AccessMode mode, - const asset_path& ap, const char* locale, const char* vendor) -{ - Asset* pAsset = NULL; - - if (ap.type == kFileTypeDirectory) { - if (mCacheMode == CACHE_OFF) { - /* look at the filesystem on disk */ - String8 path(createPathNameLocked(ap, locale, vendor)); - path.appendPath(fileName); - - String8 excludeName(path); - excludeName.append(kExcludeExtension); - if (::getFileType(excludeName.string()) != kFileTypeNonexistent) { - /* say no more */ - //printf("+++ excluding '%s'\n", (const char*) excludeName); - return kExcludedAsset; - } - - pAsset = openAssetFromFileLocked(path, mode); - - if (pAsset == NULL) { - /* try again, this time with ".gz" */ - path.append(".gz"); - pAsset = openAssetFromFileLocked(path, mode); - } - - if (pAsset != NULL) - pAsset->setAssetSource(path); - } else { - /* find in cache */ - String8 path(createPathNameLocked(ap, locale, vendor)); - path.appendPath(fileName); - - AssetDir::FileInfo tmpInfo; - bool found = false; - - String8 excludeName(path); - excludeName.append(kExcludeExtension); - - if (mCache.indexOf(excludeName) != NAME_NOT_FOUND) { - /* go no farther */ - //printf("+++ Excluding '%s'\n", (const char*) excludeName); - return kExcludedAsset; - } - - /* - * File compression extensions (".gz") don't get stored in the - * name cache, so we have to try both here. - */ - if (mCache.indexOf(path) != NAME_NOT_FOUND) { - found = true; - pAsset = openAssetFromFileLocked(path, mode); - if (pAsset == NULL) { - /* try again, this time with ".gz" */ - path.append(".gz"); - pAsset = openAssetFromFileLocked(path, mode); - } - } - - if (pAsset != NULL) - pAsset->setAssetSource(path); - - /* - * Don't continue the search into the Zip files. Our cached info - * said it was a file on disk; to be consistent with openDir() - * we want to return the loose asset. If the cached file gets - * removed, we fail. - * - * The alternative is to update our cache when files get deleted, - * or make some sort of "best effort" promise, but for now I'm - * taking the hard line. - */ - if (found) { - if (pAsset == NULL) - ALOGD("Expected file not found: '%s'\n", path.string()); - return pAsset; - } - } - } - - /* - * Either it wasn't found on disk or on the cached view of the disk. - * Dig through the currently-opened set of Zip files. If caching - * is disabled, the Zip file may get reopened. - */ - if (pAsset == NULL && ap.type == kFileTypeRegular) { - String8 path; - - path.appendPath((locale != NULL) ? locale : kDefaultLocale); - path.appendPath((vendor != NULL) ? vendor : kDefaultVendor); - path.appendPath(fileName); - - /* check the appropriate Zip file */ - ZipFileRO* pZip = getZipFileLocked(ap); - if (pZip != NULL) { - //printf("GOT zip, checking '%s'\n", (const char*) path); - 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); - } - } - - if (pAsset != NULL) { - /* create a "source" name, for debug/display */ - pAsset->setAssetSource(createZipSourceNameLocked(ZipSet::getPathName(ap.path.string()), - String8(""), String8(fileName))); - } - } - - return pAsset; -} - -/* - * Create a "source name" for a file from a Zip archive. - */ -String8 AssetManager::createZipSourceNameLocked(const String8& zipFileName, - const String8& dirName, const String8& fileName) -{ - String8 sourceName("zip:"); - sourceName.append(zipFileName); - sourceName.append(":"); - if (dirName.length() > 0) { - sourceName.appendPath(dirName); - } - sourceName.appendPath(fileName); - return sourceName; -} - -/* - * Create a path to a loose asset (asset-base/app/locale/vendor). - */ -String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* locale, - const char* vendor) -{ - String8 path(ap.path); - path.appendPath((locale != NULL) ? locale : kDefaultLocale); - path.appendPath((vendor != NULL) ? vendor : kDefaultVendor); - return path; -} - -/* - * Create a path to a loose asset (asset-base/app/rootDir). - */ -String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* rootDir) -{ - String8 path(ap.path); - if (rootDir != NULL) path.appendPath(rootDir); - return path; -} - -/* - * Return a pointer to one of our open Zip archives. Returns NULL if no - * matching Zip file exists. - * - * Right now we have 2 possible Zip files (1 each in app/"common"). - * - * If caching is set to CACHE_OFF, to get the expected behavior we - * need to reopen the Zip file on every request. That would be silly - * and expensive, so instead we just check the file modification date. - * - * Pass in NULL values for "appName", "locale", and "vendor" if the - * generics should be used. - */ -ZipFileRO* AssetManager::getZipFileLocked(const asset_path& ap) -{ - ALOGV("getZipFileLocked() in %p\n", this); - - return mZipSet.getZip(ap.path); -} - -/* - * Try to open an asset from a file on disk. - * - * If the file is compressed with gzip, we seek to the start of the - * deflated data and pass that in (just like we would for a Zip archive). - * - * For uncompressed data, we may already have an mmap()ed version sitting - * around. If so, we want to hand that to the Asset instead. - * - * This returns NULL if the file doesn't exist, couldn't be opened, or - * claims to be a ".gz" but isn't. - */ -Asset* AssetManager::openAssetFromFileLocked(const String8& pathName, - AccessMode mode) -{ - Asset* pAsset = NULL; - - if (strcasecmp(pathName.getPathExtension().string(), ".gz") == 0) { - //printf("TRYING '%s'\n", (const char*) pathName); - pAsset = Asset::createFromCompressedFile(pathName.string(), mode); - } else { - //printf("TRYING '%s'\n", (const char*) pathName); - pAsset = Asset::createFromFile(pathName.string(), mode); - } - - return pAsset; -} - -/* - * Given an entry in a Zip archive, create a new Asset object. - * - * If the entry is uncompressed, we may want to create or share a - * slice of shared memory. - */ -Asset* AssetManager::openAssetFromZipLocked(const ZipFileRO* pZipFile, - const ZipEntryRO entry, AccessMode mode, const String8& entryName) -{ - Asset* pAsset = NULL; - - // TODO: look for previously-created shared memory slice? - int method; - size_t uncompressedLen; - - //printf("USING Zip '%s'\n", pEntry->getFileName()); - - //pZipFile->getEntryInfo(entry, &method, &uncompressedLen, &compressedLen, - // &offset); - if (!pZipFile->getEntryInfo(entry, &method, &uncompressedLen, NULL, NULL, - NULL, NULL)) - { - ALOGW("getEntryInfo failed\n"); - return NULL; - } - - FileMap* dataMap = pZipFile->createEntryFileMap(entry); - if (dataMap == NULL) { - ALOGW("create map from entry failed\n"); - return NULL; - } - - if (method == ZipFileRO::kCompressStored) { - pAsset = Asset::createFromUncompressedMap(dataMap, mode); - ALOGV("Opened uncompressed entry %s in zip %s mode %d: %p", entryName.string(), - dataMap->getFileName(), mode, pAsset); - } else { - pAsset = Asset::createFromCompressedMap(dataMap, method, - uncompressedLen, mode); - ALOGV("Opened compressed entry %s in zip %s mode %d: %p", entryName.string(), - dataMap->getFileName(), mode, pAsset); - } - if (pAsset == NULL) { - /* unexpected */ - ALOGW("create from segment failed\n"); - } - - return pAsset; -} - - - -/* - * Open a directory in the asset namespace. - * - * An "asset directory" is simply the combination of all files in all - * locations, with ".gz" stripped for loose files. With app, locale, and - * vendor defined, we have 8 directories and 2 Zip archives to scan. - * - * Pass in "" for the root dir. - */ -AssetDir* AssetManager::openDir(const char* dirName) -{ - AutoMutex _l(mLock); - - AssetDir* pDir = NULL; - SortedVector* pMergedInfo = NULL; - - LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager"); - assert(dirName != NULL); - - //printf("+++ openDir(%s) in '%s'\n", dirName, (const char*) mAssetBase); - - if (mCacheMode != CACHE_OFF && !mCacheValid) - loadFileNameCacheLocked(); - - pDir = new AssetDir; - - /* - * Scan the various directories, merging what we find into a single - * vector. We want to scan them in reverse priority order so that - * the ".EXCLUDE" processing works correctly. Also, if we decide we - * want to remember where the file is coming from, we'll get the right - * version. - * - * We start with Zip archives, then do loose files. - */ - pMergedInfo = new SortedVector; - - size_t i = mAssetPaths.size(); - while (i > 0) { - i--; - const asset_path& ap = mAssetPaths.itemAt(i); - if (ap.type == kFileTypeRegular) { - ALOGV("Adding directory %s from zip %s", dirName, ap.path.string()); - scanAndMergeZipLocked(pMergedInfo, ap, kAssetsRoot, dirName); - } else { - ALOGV("Adding directory %s from dir %s", dirName, ap.path.string()); - scanAndMergeDirLocked(pMergedInfo, ap, kAssetsRoot, dirName); - } - } - -#if 0 - printf("FILE LIST:\n"); - for (i = 0; i < (size_t) pMergedInfo->size(); i++) { - printf(" %d: (%d) '%s'\n", i, - pMergedInfo->itemAt(i).getFileType(), - (const char*) pMergedInfo->itemAt(i).getFileName()); - } -#endif - - pDir->setFileList(pMergedInfo); - return pDir; -} - -/* - * Open a directory in the non-asset namespace. - * - * An "asset directory" is simply the combination of all files in all - * locations, with ".gz" stripped for loose files. With app, locale, and - * vendor defined, we have 8 directories and 2 Zip archives to scan. - * - * Pass in "" for the root dir. - */ -AssetDir* AssetManager::openNonAssetDir(const int32_t cookie, const char* dirName) -{ - AutoMutex _l(mLock); - - AssetDir* pDir = NULL; - SortedVector* pMergedInfo = NULL; - - LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager"); - assert(dirName != NULL); - - //printf("+++ openDir(%s) in '%s'\n", dirName, (const char*) mAssetBase); - - if (mCacheMode != CACHE_OFF && !mCacheValid) - loadFileNameCacheLocked(); - - pDir = new AssetDir; - - pMergedInfo = new SortedVector; - - const size_t which = static_cast(cookie) - 1; - - if (which < mAssetPaths.size()) { - const asset_path& ap = mAssetPaths.itemAt(which); - if (ap.type == kFileTypeRegular) { - ALOGV("Adding directory %s from zip %s", dirName, ap.path.string()); - scanAndMergeZipLocked(pMergedInfo, ap, NULL, dirName); - } else { - ALOGV("Adding directory %s from dir %s", dirName, ap.path.string()); - scanAndMergeDirLocked(pMergedInfo, ap, NULL, dirName); - } - } - -#if 0 - printf("FILE LIST:\n"); - for (i = 0; i < (size_t) pMergedInfo->size(); i++) { - printf(" %d: (%d) '%s'\n", i, - pMergedInfo->itemAt(i).getFileType(), - (const char*) pMergedInfo->itemAt(i).getFileName()); - } -#endif - - pDir->setFileList(pMergedInfo); - return pDir; -} - -/* - * Scan the contents of the specified directory and merge them into the - * "pMergedInfo" vector, removing previous entries if we find "exclude" - * directives. - * - * Returns "false" if we found nothing to contribute. - */ -bool AssetManager::scanAndMergeDirLocked(SortedVector* pMergedInfo, - const asset_path& ap, const char* rootDir, const char* dirName) -{ - SortedVector* pContents; - String8 path; - - assert(pMergedInfo != NULL); - - //printf("scanAndMergeDir: %s %s %s %s\n", appName, locale, vendor,dirName); - - if (mCacheValid) { - int i, start, count; - - pContents = new SortedVector; - - /* - * Get the basic partial path and find it in the cache. That's - * the start point for the search. - */ - path = createPathNameLocked(ap, rootDir); - if (dirName[0] != '\0') - path.appendPath(dirName); - - start = mCache.indexOf(path); - if (start == NAME_NOT_FOUND) { - //printf("+++ not found in cache: dir '%s'\n", (const char*) path); - delete pContents; - return false; - } - - /* - * The match string looks like "common/default/default/foo/bar/". - * The '/' on the end ensures that we don't match on the directory - * itself or on ".../foo/barfy/". - */ - path.append("/"); - - count = mCache.size(); - - /* - * Pick out the stuff in the current dir by examining the pathname. - * It needs to match the partial pathname prefix, and not have a '/' - * (fssep) anywhere after the prefix. - */ - for (i = start+1; i < count; i++) { - if (mCache[i].getFileName().length() > path.length() && - strncmp(mCache[i].getFileName().string(), path.string(), path.length()) == 0) - { - const char* name = mCache[i].getFileName().string(); - // XXX THIS IS BROKEN! Looks like we need to store the full - // path prefix separately from the file path. - if (strchr(name + path.length(), '/') == NULL) { - /* grab it, reducing path to just the filename component */ - AssetDir::FileInfo tmp = mCache[i]; - tmp.setFileName(tmp.getFileName().getPathLeaf()); - pContents->add(tmp); - } - } else { - /* no longer in the dir or its subdirs */ - break; - } - - } - } else { - path = createPathNameLocked(ap, rootDir); - if (dirName[0] != '\0') - path.appendPath(dirName); - pContents = scanDirLocked(path); - if (pContents == NULL) - return false; - } - - // if we wanted to do an incremental cache fill, we would do it here - - /* - * Process "exclude" directives. If we find a filename that ends with - * ".EXCLUDE", we look for a matching entry in the "merged" set, and - * remove it if we find it. We also delete the "exclude" entry. - */ - int i, count, exclExtLen; - - count = pContents->size(); - exclExtLen = strlen(kExcludeExtension); - for (i = 0; i < count; i++) { - const char* name; - int nameLen; - - name = pContents->itemAt(i).getFileName().string(); - nameLen = strlen(name); - if (nameLen > exclExtLen && - strcmp(name + (nameLen - exclExtLen), kExcludeExtension) == 0) - { - String8 match(name, nameLen - exclExtLen); - int matchIdx; - - matchIdx = AssetDir::FileInfo::findEntry(pMergedInfo, match); - if (matchIdx > 0) { - ALOGV("Excluding '%s' [%s]\n", - pMergedInfo->itemAt(matchIdx).getFileName().string(), - pMergedInfo->itemAt(matchIdx).getSourceName().string()); - pMergedInfo->removeAt(matchIdx); - } else { - //printf("+++ no match on '%s'\n", (const char*) match); - } - - ALOGD("HEY: size=%d removing %d\n", (int)pContents->size(), i); - pContents->removeAt(i); - i--; // adjust "for" loop - count--; // and loop limit - } - } - - mergeInfoLocked(pMergedInfo, pContents); - - delete pContents; - - return true; -} - -/* - * Scan the contents of the specified directory, and stuff what we find - * into a newly-allocated vector. - * - * Files ending in ".gz" will have their extensions removed. - * - * We should probably think about skipping files with "illegal" names, - * e.g. illegal characters (/\:) or excessive length. - * - * Returns NULL if the specified directory doesn't exist. - */ -SortedVector* AssetManager::scanDirLocked(const String8& path) -{ - SortedVector* pContents = NULL; - DIR* dir; - struct dirent* entry; - FileType fileType; - - ALOGV("Scanning dir '%s'\n", path.string()); - - dir = opendir(path.string()); - if (dir == NULL) - return NULL; - - pContents = new SortedVector; - - while (1) { - entry = readdir(dir); - if (entry == NULL) - break; - - if (strcmp(entry->d_name, ".") == 0 || - strcmp(entry->d_name, "..") == 0) - continue; - -#ifdef _DIRENT_HAVE_D_TYPE - if (entry->d_type == DT_REG) - fileType = kFileTypeRegular; - else if (entry->d_type == DT_DIR) - fileType = kFileTypeDirectory; - else - fileType = kFileTypeUnknown; -#else - // stat the file - fileType = ::getFileType(path.appendPathCopy(entry->d_name).string()); -#endif - - if (fileType != kFileTypeRegular && fileType != kFileTypeDirectory) - continue; - - AssetDir::FileInfo info; - info.set(String8(entry->d_name), fileType); - if (strcasecmp(info.getFileName().getPathExtension().string(), ".gz") == 0) - info.setFileName(info.getFileName().getBasePath()); - info.setSourceName(path.appendPathCopy(info.getFileName())); - pContents->add(info); - } - - closedir(dir); - return pContents; -} - -/* - * Scan the contents out of the specified Zip archive, and merge what we - * find into "pMergedInfo". If the Zip archive in question doesn't exist, - * we return immediately. - * - * Returns "false" if we found nothing to contribute. - */ -bool AssetManager::scanAndMergeZipLocked(SortedVector* pMergedInfo, - const asset_path& ap, const char* rootDir, const char* baseDirName) -{ - ZipFileRO* pZip; - Vector dirs; - AssetDir::FileInfo info; - SortedVector contents; - String8 sourceName, zipName, dirName; - - pZip = mZipSet.getZip(ap.path); - if (pZip == NULL) { - ALOGW("Failure opening zip %s\n", ap.path.string()); - return false; - } - - zipName = ZipSet::getPathName(ap.path.string()); - - /* convert "sounds" to "rootDir/sounds" */ - if (rootDir != NULL) dirName = rootDir; - dirName.appendPath(baseDirName); - - /* - * Scan through the list of files, looking for a match. The files in - * the Zip table of contents are not in sorted order, so we have to - * process the entire list. We're looking for a string that begins - * with the characters in "dirName", is followed by a '/', and has no - * subsequent '/' in the stuff that follows. - * - * What makes this especially fun is that directories are not stored - * explicitly in Zip archives, so we have to infer them from context. - * When we see "sounds/foo.wav" we have to leave a note to ourselves - * to insert a directory called "sounds" into the list. We store - * these in temporary vector so that we only return each one once. - * - * Name comparisons are case-sensitive to match UNIX filesystem - * semantics. - */ - int dirNameLen = dirName.length(); - void *iterationCookie; - if (!pZip->startIteration(&iterationCookie)) { - ALOGW("ZipFileRO::startIteration returned false"); - return false; - } - - ZipEntryRO entry; - while ((entry = pZip->nextEntry(iterationCookie)) != NULL) { - char nameBuf[256]; - - if (pZip->getEntryFileName(entry, nameBuf, sizeof(nameBuf)) != 0) { - // TODO: fix this if we expect to have long names - ALOGE("ARGH: name too long?\n"); - continue; - } - //printf("Comparing %s in %s?\n", nameBuf, dirName.string()); - if (dirNameLen == 0 || - (strncmp(nameBuf, dirName.string(), dirNameLen) == 0 && - nameBuf[dirNameLen] == '/')) - { - const char* cp; - const char* nextSlash; - - cp = nameBuf + dirNameLen; - if (dirNameLen != 0) - cp++; // advance past the '/' - - nextSlash = strchr(cp, '/'); -//xxx this may break if there are bare directory entries - if (nextSlash == NULL) { - /* this is a file in the requested directory */ - - info.set(String8(nameBuf).getPathLeaf(), kFileTypeRegular); - - info.setSourceName( - createZipSourceNameLocked(zipName, dirName, info.getFileName())); - - contents.add(info); - //printf("FOUND: file '%s'\n", info.getFileName().string()); - } else { - /* this is a subdir; add it if we don't already have it*/ - String8 subdirName(cp, nextSlash - cp); - size_t j; - size_t N = dirs.size(); - - for (j = 0; j < N; j++) { - if (subdirName == dirs[j]) { - break; - } - } - if (j == N) { - dirs.add(subdirName); - } - - //printf("FOUND: dir '%s'\n", subdirName.string()); - } - } - } - - pZip->endIteration(iterationCookie); - - /* - * Add the set of unique directories. - */ - for (int i = 0; i < (int) dirs.size(); i++) { - info.set(dirs[i], kFileTypeDirectory); - info.setSourceName( - createZipSourceNameLocked(zipName, dirName, info.getFileName())); - contents.add(info); - } - - mergeInfoLocked(pMergedInfo, &contents); - - return true; -} - - -/* - * Merge two vectors of FileInfo. - * - * The merged contents will be stuffed into *pMergedInfo. - * - * If an entry for a file exists in both "pMergedInfo" and "pContents", - * we use the newer "pContents" entry. - */ -void AssetManager::mergeInfoLocked(SortedVector* pMergedInfo, - const SortedVector* pContents) -{ - /* - * Merge what we found in this directory with what we found in - * other places. - * - * Two basic approaches: - * (1) Create a new array that holds the unique values of the two - * arrays. - * (2) Take the elements from pContents and shove them into pMergedInfo. - * - * Because these are vectors of complex objects, moving elements around - * inside the vector requires constructing new objects and allocating - * storage for members. With approach #1, we're always adding to the - * end, whereas with #2 we could be inserting multiple elements at the - * front of the vector. Approach #1 requires a full copy of the - * contents of pMergedInfo, but approach #2 requires the same copy for - * every insertion at the front of pMergedInfo. - * - * (We should probably use a SortedVector interface that allows us to - * just stuff items in, trusting us to maintain the sort order.) - */ - SortedVector* pNewSorted; - int mergeMax, contMax; - int mergeIdx, contIdx; - - pNewSorted = new SortedVector; - mergeMax = pMergedInfo->size(); - contMax = pContents->size(); - mergeIdx = contIdx = 0; - - while (mergeIdx < mergeMax || contIdx < contMax) { - if (mergeIdx == mergeMax) { - /* hit end of "merge" list, copy rest of "contents" */ - pNewSorted->add(pContents->itemAt(contIdx)); - contIdx++; - } else if (contIdx == contMax) { - /* hit end of "cont" list, copy rest of "merge" */ - pNewSorted->add(pMergedInfo->itemAt(mergeIdx)); - mergeIdx++; - } else if (pMergedInfo->itemAt(mergeIdx) == pContents->itemAt(contIdx)) - { - /* items are identical, add newer and advance both indices */ - pNewSorted->add(pContents->itemAt(contIdx)); - mergeIdx++; - contIdx++; - } else if (pMergedInfo->itemAt(mergeIdx) < pContents->itemAt(contIdx)) - { - /* "merge" is lower, add that one */ - pNewSorted->add(pMergedInfo->itemAt(mergeIdx)); - mergeIdx++; - } else { - /* "cont" is lower, add that one */ - assert(pContents->itemAt(contIdx) < pMergedInfo->itemAt(mergeIdx)); - pNewSorted->add(pContents->itemAt(contIdx)); - contIdx++; - } - } - - /* - * Overwrite the "merged" list with the new stuff. - */ - *pMergedInfo = *pNewSorted; - delete pNewSorted; - -#if 0 // for Vector, rather than SortedVector - int i, j; - for (i = pContents->size() -1; i >= 0; i--) { - bool add = true; - - for (j = pMergedInfo->size() -1; j >= 0; j--) { - /* case-sensitive comparisons, to behave like UNIX fs */ - if (strcmp(pContents->itemAt(i).mFileName, - pMergedInfo->itemAt(j).mFileName) == 0) - { - /* match, don't add this entry */ - add = false; - break; - } - } - - if (add) - pMergedInfo->add(pContents->itemAt(i)); - } -#endif -} - - -/* - * Load all files into the file name cache. We want to do this across - * all combinations of { appname, locale, vendor }, performing a recursive - * directory traversal. - * - * This is not the most efficient data structure. Also, gathering the - * information as we needed it (file-by-file or directory-by-directory) - * would be faster. However, on the actual device, 99% of the files will - * live in Zip archives, so this list will be very small. The trouble - * is that we have to check the "loose" files first, so it's important - * that we don't beat the filesystem silly looking for files that aren't - * there. - * - * Note on thread safety: this is the only function that causes updates - * to mCache, and anybody who tries to use it will call here if !mCacheValid, - * so we need to employ a mutex here. - */ -void AssetManager::loadFileNameCacheLocked(void) -{ - assert(!mCacheValid); - assert(mCache.size() == 0); - -#ifdef DO_TIMINGS // need to link against -lrt for this now - DurationTimer timer; - timer.start(); -#endif - - fncScanLocked(&mCache, ""); - -#ifdef DO_TIMINGS - timer.stop(); - ALOGD("Cache scan took %.3fms\n", - timer.durationUsecs() / 1000.0); -#endif - -#if 0 - int i; - printf("CACHED FILE LIST (%d entries):\n", mCache.size()); - for (i = 0; i < (int) mCache.size(); i++) { - printf(" %d: (%d) '%s'\n", i, - mCache.itemAt(i).getFileType(), - (const char*) mCache.itemAt(i).getFileName()); - } -#endif - - mCacheValid = true; -} - -/* - * Scan up to 8 versions of the specified directory. - */ -void AssetManager::fncScanLocked(SortedVector* pMergedInfo, - const char* dirName) -{ - size_t i = mAssetPaths.size(); - while (i > 0) { - i--; - const asset_path& ap = mAssetPaths.itemAt(i); - fncScanAndMergeDirLocked(pMergedInfo, ap, NULL, NULL, dirName); - if (mLocale != NULL) - fncScanAndMergeDirLocked(pMergedInfo, ap, mLocale, NULL, dirName); - if (mVendor != NULL) - fncScanAndMergeDirLocked(pMergedInfo, ap, NULL, mVendor, dirName); - if (mLocale != NULL && mVendor != NULL) - fncScanAndMergeDirLocked(pMergedInfo, ap, mLocale, mVendor, dirName); - } -} - -/* - * Recursively scan this directory and all subdirs. - * - * This is similar to scanAndMergeDir, but we don't remove the .EXCLUDE - * files, and we prepend the extended partial path to the filenames. - */ -bool AssetManager::fncScanAndMergeDirLocked( - SortedVector* pMergedInfo, - const asset_path& ap, const char* locale, const char* vendor, - const char* dirName) -{ - SortedVector* pContents; - String8 partialPath; - String8 fullPath; - - // XXX This is broken -- the filename cache needs to hold the base - // asset path separately from its filename. - - partialPath = createPathNameLocked(ap, locale, vendor); - if (dirName[0] != '\0') { - partialPath.appendPath(dirName); - } - - fullPath = partialPath; - pContents = scanDirLocked(fullPath); - if (pContents == NULL) { - return false; // directory did not exist - } - - /* - * Scan all subdirectories of the current dir, merging what we find - * into "pMergedInfo". - */ - for (int i = 0; i < (int) pContents->size(); i++) { - if (pContents->itemAt(i).getFileType() == kFileTypeDirectory) { - String8 subdir(dirName); - subdir.appendPath(pContents->itemAt(i).getFileName()); - - fncScanAndMergeDirLocked(pMergedInfo, ap, locale, vendor, subdir.string()); - } - } - - /* - * To be consistent, we want entries for the root directory. If - * we're the root, add one now. - */ - if (dirName[0] == '\0') { - AssetDir::FileInfo tmpInfo; - - tmpInfo.set(String8(""), kFileTypeDirectory); - tmpInfo.setSourceName(createPathNameLocked(ap, locale, vendor)); - pContents->add(tmpInfo); - } - - /* - * We want to prepend the extended partial path to every entry in - * "pContents". It's the same value for each entry, so this will - * not change the sorting order of the vector contents. - */ - for (int i = 0; i < (int) pContents->size(); i++) { - const AssetDir::FileInfo& info = pContents->itemAt(i); - pContents->editItemAt(i).setFileName(partialPath.appendPathCopy(info.getFileName())); - } - - mergeInfoLocked(pMergedInfo, pContents); - return true; -} - -/* - * Trash the cache. - */ -void AssetManager::purgeFileNameCacheLocked(void) -{ - mCacheValid = false; - mCache.clear(); -} - -/* - * =========================================================================== - * AssetManager::SharedZip - * =========================================================================== - */ - - -Mutex AssetManager::SharedZip::gLock; -DefaultKeyedVector > AssetManager::SharedZip::gOpen; - -AssetManager::SharedZip::SharedZip(const String8& path, time_t modWhen) - : mPath(path), mZipFile(NULL), mModWhen(modWhen), - mResourceTableAsset(NULL), mResourceTable(NULL) -{ - //ALOGI("Creating SharedZip %p %s\n", this, (const char*)mPath); - ALOGV("+++ opening zip '%s'\n", mPath.string()); - mZipFile = ZipFileRO::open(mPath.string()); - if (mZipFile == NULL) { - ALOGD("failed to open Zip archive '%s'\n", mPath.string()); - } -} - -sp AssetManager::SharedZip::get(const String8& path) -{ - AutoMutex _l(gLock); - time_t modWhen = getFileModDate(path); - sp zip = gOpen.valueFor(path).promote(); - if (zip != NULL && zip->mModWhen == modWhen) { - return zip; - } - zip = new SharedZip(path, modWhen); - gOpen.add(path, zip); - return zip; - -} - -ZipFileRO* AssetManager::SharedZip::getZip() -{ - return mZipFile; -} - -Asset* AssetManager::SharedZip::getResourceTableAsset() -{ - ALOGV("Getting from SharedZip %p resource asset %p\n", this, mResourceTableAsset); - return mResourceTableAsset; -} - -Asset* AssetManager::SharedZip::setResourceTableAsset(Asset* asset) -{ - { - AutoMutex _l(gLock); - if (mResourceTableAsset == NULL) { - mResourceTableAsset = asset; - // This is not thread safe the first time it is called, so - // do it here with the global lock held. - asset->getBuffer(true); - return asset; - } - } - delete asset; - return mResourceTableAsset; -} - -ResTable* AssetManager::SharedZip::getResourceTable() -{ - ALOGV("Getting from SharedZip %p resource table %p\n", this, mResourceTable); - return mResourceTable; -} - -ResTable* AssetManager::SharedZip::setResourceTable(ResTable* res) -{ - { - AutoMutex _l(gLock); - if (mResourceTable == NULL) { - mResourceTable = res; - return res; - } - } - delete res; - return mResourceTable; -} - -bool AssetManager::SharedZip::isUpToDate() -{ - time_t modWhen = getFileModDate(mPath.string()); - return mModWhen == modWhen; -} - -AssetManager::SharedZip::~SharedZip() -{ - //ALOGI("Destroying SharedZip %p %s\n", this, (const char*)mPath); - if (mResourceTable != NULL) { - delete mResourceTable; - } - if (mResourceTableAsset != NULL) { - delete mResourceTableAsset; - } - if (mZipFile != NULL) { - delete mZipFile; - ALOGV("Closed '%s'\n", mPath.string()); - } -} - -/* - * =========================================================================== - * AssetManager::ZipSet - * =========================================================================== - */ - -/* - * Constructor. - */ -AssetManager::ZipSet::ZipSet(void) -{ -} - -/* - * Destructor. Close any open archives. - */ -AssetManager::ZipSet::~ZipSet(void) -{ - size_t N = mZipFile.size(); - for (size_t i = 0; i < N; i++) - closeZip(i); -} - -/* - * Close a Zip file and reset the entry. - */ -void AssetManager::ZipSet::closeZip(int idx) -{ - mZipFile.editItemAt(idx) = NULL; -} - - -/* - * Retrieve the appropriate Zip file from the set. - */ -ZipFileRO* AssetManager::ZipSet::getZip(const String8& path) -{ - int idx = getIndex(path); - sp zip = mZipFile[idx]; - if (zip == NULL) { - zip = SharedZip::get(path); - mZipFile.editItemAt(idx) = zip; - } - return zip->getZip(); -} - -Asset* AssetManager::ZipSet::getZipResourceTableAsset(const String8& path) -{ - int idx = getIndex(path); - sp zip = mZipFile[idx]; - if (zip == NULL) { - zip = SharedZip::get(path); - mZipFile.editItemAt(idx) = zip; - } - return zip->getResourceTableAsset(); -} - -Asset* AssetManager::ZipSet::setZipResourceTableAsset(const String8& path, - Asset* asset) -{ - int idx = getIndex(path); - sp zip = mZipFile[idx]; - // doesn't make sense to call before previously accessing. - return zip->setResourceTableAsset(asset); -} - -ResTable* AssetManager::ZipSet::getZipResourceTable(const String8& path) -{ - int idx = getIndex(path); - sp zip = mZipFile[idx]; - if (zip == NULL) { - zip = SharedZip::get(path); - mZipFile.editItemAt(idx) = zip; - } - return zip->getResourceTable(); -} - -ResTable* AssetManager::ZipSet::setZipResourceTable(const String8& path, - ResTable* res) -{ - int idx = getIndex(path); - sp zip = mZipFile[idx]; - // doesn't make sense to call before previously accessing. - return zip->setResourceTable(res); -} - -/* - * Generate the partial pathname for the specified archive. The caller - * gets to prepend the asset root directory. - * - * Returns something like "common/en-US-noogle.jar". - */ -/*static*/ String8 AssetManager::ZipSet::getPathName(const char* zipPath) -{ - return String8(zipPath); -} - -bool AssetManager::ZipSet::isUpToDate() -{ - const size_t N = mZipFile.size(); - for (size_t i=0; iisUpToDate()) { - return false; - } - } - return true; -} - -/* - * Compute the zip file's index. - * - * "appName", "locale", and "vendor" should be set to NULL to indicate the - * default directory. - */ -int AssetManager::ZipSet::getIndex(const String8& zip) const -{ - const size_t N = mZipPath.size(); - for (size_t i=0; i -#include - -#include -#include -#include - -#include - -namespace android { - -static const bool DEBUG = false; - -/* - * File Format (v1): - * - * All ints are stored little-endian. - * - * - An app_header_v1 struct. - * - The name of the package, utf-8, null terminated, padded to 4-byte boundary. - * - A sequence of zero or more key/value paires (entities), each with - * - A entity_header_v1 struct - * - The key, utf-8, null terminated, padded to 4-byte boundary. - * - The value, padded to 4 byte boundary - */ - -const static int ROUND_UP[4] = { 0, 3, 2, 1 }; - -static inline size_t -round_up(size_t n) -{ - return n + ROUND_UP[n % 4]; -} - -static inline size_t -padding_extra(size_t n) -{ - return ROUND_UP[n % 4]; -} - -BackupDataWriter::BackupDataWriter(int fd) - :m_fd(fd), - m_status(NO_ERROR), - m_pos(0), - m_entityCount(0) -{ -} - -BackupDataWriter::~BackupDataWriter() -{ -} - -// Pad out anything they've previously written to the next 4 byte boundary. -status_t -BackupDataWriter::write_padding_for(int n) -{ - ssize_t amt; - ssize_t paddingSize; - - paddingSize = padding_extra(n); - if (paddingSize > 0) { - uint32_t padding = 0xbcbcbcbc; - if (DEBUG) ALOGI("writing %d padding bytes for %d", paddingSize, n); - amt = write(m_fd, &padding, paddingSize); - if (amt != paddingSize) { - m_status = errno; - return m_status; - } - m_pos += amt; - } - return NO_ERROR; -} - -status_t -BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize) -{ - if (m_status != NO_ERROR) { - return m_status; - } - - ssize_t amt; - - amt = write_padding_for(m_pos); - if (amt != 0) { - return amt; - } - - String8 k; - if (m_keyPrefix.length() > 0) { - k = m_keyPrefix; - k += ":"; - k += key; - } else { - k = key; - } - if (DEBUG) { - ALOGD("Writing header: prefix='%s' key='%s' dataSize=%d", m_keyPrefix.string(), - key.string(), dataSize); - } - - entity_header_v1 header; - ssize_t keyLen; - - keyLen = k.length(); - - header.type = tolel(BACKUP_HEADER_ENTITY_V1); - header.keyLen = tolel(keyLen); - header.dataSize = tolel(dataSize); - - if (DEBUG) ALOGI("writing entity header, %d bytes", sizeof(entity_header_v1)); - amt = write(m_fd, &header, sizeof(entity_header_v1)); - if (amt != sizeof(entity_header_v1)) { - m_status = errno; - return m_status; - } - m_pos += amt; - - if (DEBUG) ALOGI("writing entity header key, %d bytes", keyLen+1); - amt = write(m_fd, k.string(), keyLen+1); - if (amt != keyLen+1) { - m_status = errno; - return m_status; - } - m_pos += amt; - - amt = write_padding_for(keyLen+1); - - m_entityCount++; - - return amt; -} - -status_t -BackupDataWriter::WriteEntityData(const void* data, size_t size) -{ - if (DEBUG) ALOGD("Writing data: size=%lu", (unsigned long) size); - - if (m_status != NO_ERROR) { - if (DEBUG) { - ALOGD("Not writing data - stream in error state %d (%s)", m_status, strerror(m_status)); - } - return m_status; - } - - // We don't write padding here, because they're allowed to call this several - // times with smaller buffers. We write it at the end of WriteEntityHeader - // instead. - ssize_t amt = write(m_fd, data, size); - if (amt != (ssize_t)size) { - m_status = errno; - if (DEBUG) ALOGD("write returned error %d (%s)", m_status, strerror(m_status)); - return m_status; - } - m_pos += amt; - return NO_ERROR; -} - -void -BackupDataWriter::SetKeyPrefix(const String8& keyPrefix) -{ - m_keyPrefix = keyPrefix; -} - - -BackupDataReader::BackupDataReader(int fd) - :m_fd(fd), - m_done(false), - m_status(NO_ERROR), - m_pos(0), - m_entityCount(0) -{ - memset(&m_header, 0, sizeof(m_header)); -} - -BackupDataReader::~BackupDataReader() -{ -} - -status_t -BackupDataReader::Status() -{ - return m_status; -} - -#define CHECK_SIZE(actual, expected) \ - do { \ - if ((actual) != (expected)) { \ - if ((actual) == 0) { \ - m_status = EIO; \ - m_done = true; \ - } else { \ - m_status = errno; \ - ALOGD("CHECK_SIZE(a=%ld e=%ld) failed at line %d m_status='%s'", \ - long(actual), long(expected), __LINE__, strerror(m_status)); \ - } \ - return m_status; \ - } \ - } while(0) -#define SKIP_PADDING() \ - do { \ - status_t err = skip_padding(); \ - if (err != NO_ERROR) { \ - ALOGD("SKIP_PADDING FAILED at line %d", __LINE__); \ - m_status = err; \ - return err; \ - } \ - } while(0) - -status_t -BackupDataReader::ReadNextHeader(bool* done, int* type) -{ - *done = m_done; - if (m_status != NO_ERROR) { - return m_status; - } - - int amt; - - amt = skip_padding(); - if (amt == EIO) { - *done = m_done = true; - return NO_ERROR; - } - else if (amt != NO_ERROR) { - return amt; - } - amt = read(m_fd, &m_header, sizeof(m_header)); - *done = m_done = (amt == 0); - if (*done) { - return NO_ERROR; - } - CHECK_SIZE(amt, sizeof(m_header)); - m_pos += sizeof(m_header); - if (type) { - *type = m_header.type; - } - - // validate and fix up the fields. - m_header.type = fromlel(m_header.type); - switch (m_header.type) - { - case BACKUP_HEADER_ENTITY_V1: - { - m_header.entity.keyLen = fromlel(m_header.entity.keyLen); - if (m_header.entity.keyLen <= 0) { - ALOGD("Entity header at %d has keyLen<=0: 0x%08x\n", (int)m_pos, - (int)m_header.entity.keyLen); - m_status = EINVAL; - } - m_header.entity.dataSize = fromlel(m_header.entity.dataSize); - m_entityCount++; - - // read the rest of the header (filename) - size_t size = m_header.entity.keyLen; - char* buf = m_key.lockBuffer(size); - if (buf == NULL) { - m_status = ENOMEM; - return m_status; - } - int amt = read(m_fd, buf, size+1); - CHECK_SIZE(amt, (int)size+1); - m_key.unlockBuffer(size); - m_pos += size+1; - SKIP_PADDING(); - m_dataEndPos = m_pos + m_header.entity.dataSize; - - break; - } - default: - ALOGD("Chunk header at %d has invalid type: 0x%08x", - (int)(m_pos - sizeof(m_header)), (int)m_header.type); - m_status = EINVAL; - } - - return m_status; -} - -bool -BackupDataReader::HasEntities() -{ - return m_status == NO_ERROR && m_header.type == BACKUP_HEADER_ENTITY_V1; -} - -status_t -BackupDataReader::ReadEntityHeader(String8* key, size_t* dataSize) -{ - if (m_status != NO_ERROR) { - return m_status; - } - if (m_header.type != BACKUP_HEADER_ENTITY_V1) { - return EINVAL; - } - *key = m_key; - *dataSize = m_header.entity.dataSize; - return NO_ERROR; -} - -status_t -BackupDataReader::SkipEntityData() -{ - if (m_status != NO_ERROR) { - return m_status; - } - if (m_header.type != BACKUP_HEADER_ENTITY_V1) { - return EINVAL; - } - if (m_header.entity.dataSize > 0) { - int pos = lseek(m_fd, m_dataEndPos, SEEK_SET); - if (pos == -1) { - return errno; - } - m_pos = pos; - } - SKIP_PADDING(); - return NO_ERROR; -} - -ssize_t -BackupDataReader::ReadEntityData(void* data, size_t size) -{ - if (m_status != NO_ERROR) { - return -1; - } - int remaining = m_dataEndPos - m_pos; - //ALOGD("ReadEntityData size=%d m_pos=0x%x m_dataEndPos=0x%x remaining=%d\n", - // size, m_pos, m_dataEndPos, remaining); - if (remaining <= 0) { - return 0; - } - if (((int)size) > remaining) { - size = remaining; - } - //ALOGD(" reading %d bytes", size); - int amt = read(m_fd, data, size); - if (amt < 0) { - m_status = errno; - return -1; - } - if (amt == 0) { - m_status = EIO; - m_done = true; - } - m_pos += amt; - return amt; -} - -status_t -BackupDataReader::skip_padding() -{ - ssize_t amt; - ssize_t paddingSize; - - paddingSize = padding_extra(m_pos); - if (paddingSize > 0) { - uint32_t padding; - amt = read(m_fd, &padding, paddingSize); - CHECK_SIZE(amt, paddingSize); - m_pos += amt; - } - return NO_ERROR; -} - - -} // namespace android diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp deleted file mode 100644 index b8d3f48e33..0000000000 --- a/libs/androidfw/BackupHelpers.cpp +++ /dev/null @@ -1,1591 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -#define LOG_TAG "file_backup_helper" - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include // for utimes -#include -#include -#include -#include -#include -#include - -#include - -namespace android { - -#define MAGIC0 0x70616e53 // Snap -#define MAGIC1 0x656c6946 // File - -/* - * File entity data format (v1): - * - * - 4-byte version number of the metadata, little endian (0x00000001 for v1) - * - 12 bytes of metadata - * - the file data itself - * - * i.e. a 16-byte metadata header followed by the raw file data. If the - * restore code does not recognize the metadata version, it can still - * interpret the file data itself correctly. - * - * file_metadata_v1: - * - * - 4 byte version number === 0x00000001 (little endian) - * - 4-byte access mode (little-endian) - * - undefined (8 bytes) - */ - -struct file_metadata_v1 { - int version; - int mode; - int undefined_1; - int undefined_2; -}; - -const static int CURRENT_METADATA_VERSION = 1; - -#if 1 -#define LOGP(f, x...) -#else -#if TEST_BACKUP_HELPERS -#define LOGP(f, x...) printf(f "\n", x) -#else -#define LOGP(x...) ALOGD(x) -#endif -#endif - -const static int ROUND_UP[4] = { 0, 3, 2, 1 }; - -static inline int -round_up(int n) -{ - return n + ROUND_UP[n % 4]; -} - -static int -read_snapshot_file(int fd, KeyedVector* snapshot) -{ - int bytesRead = 0; - int amt; - SnapshotHeader header; - - amt = read(fd, &header, sizeof(header)); - if (amt != sizeof(header)) { - return errno; - } - bytesRead += amt; - - if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) { - ALOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1); - return 1; - } - - for (int i=0; iadd(String8(filename, file.nameLen), file); - } - bytesRead += amt; - if (filename != filenameBuf) { - free(filename); - } - if (amt != nameBufSize) { - ALOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead); - return 1; - } - } - - if (header.totalSize != bytesRead) { - ALOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n", - header.totalSize, bytesRead); - return 1; - } - - return 0; -} - -static int -write_snapshot_file(int fd, const KeyedVector& snapshot) -{ - int fileCount = 0; - int bytesWritten = sizeof(SnapshotHeader); - // preflight size - const int N = snapshot.size(); - for (int i=0; iWriteEntityHeader(key, -1); -} - -static int -write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key, - char const* realFilename) -{ - LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode); - - const int bufsize = 4*1024; - int err; - int amt; - int fileSize; - int bytesLeft; - file_metadata_v1 metadata; - - char* buf = (char*)malloc(bufsize); - int crc = crc32(0L, Z_NULL, 0); - - - fileSize = lseek(fd, 0, SEEK_END); - lseek(fd, 0, SEEK_SET); - - if (sizeof(metadata) != 16) { - ALOGE("ERROR: metadata block is the wrong size!"); - } - - bytesLeft = fileSize + sizeof(metadata); - err = dataStream->WriteEntityHeader(key, bytesLeft); - if (err != 0) { - free(buf); - return err; - } - - // store the file metadata first - metadata.version = tolel(CURRENT_METADATA_VERSION); - metadata.mode = tolel(mode); - metadata.undefined_1 = metadata.undefined_2 = 0; - err = dataStream->WriteEntityData(&metadata, sizeof(metadata)); - if (err != 0) { - free(buf); - return err; - } - bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now - - // now store the file content - while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) { - bytesLeft -= amt; - if (bytesLeft < 0) { - amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised. - } - err = dataStream->WriteEntityData(buf, amt); - if (err != 0) { - free(buf); - return err; - } - } - if (bytesLeft != 0) { - if (bytesLeft > 0) { - // Pad out the space we promised in the buffer. We can't corrupt the buffer, - // even though the data we're sending is probably bad. - memset(buf, 0, bufsize); - while (bytesLeft > 0) { - amt = bytesLeft < bufsize ? bytesLeft : bufsize; - bytesLeft -= amt; - err = dataStream->WriteEntityData(buf, amt); - if (err != 0) { - free(buf); - return err; - } - } - } - ALOGE("write_update_file size mismatch for %s. expected=%d actual=%d." - " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft); - } - - free(buf); - return NO_ERROR; -} - -static int -write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename) -{ - int err; - struct stat st; - - err = stat(realFilename, &st); - if (err < 0) { - return errno; - } - - int fd = open(realFilename, O_RDONLY); - if (fd == -1) { - return errno; - } - - err = write_update_file(dataStream, fd, st.st_mode, key, realFilename); - close(fd); - return err; -} - -static int -compute_crc32(int fd) -{ - const int bufsize = 4*1024; - int amt; - - char* buf = (char*)malloc(bufsize); - int crc = crc32(0L, Z_NULL, 0); - - lseek(fd, 0, SEEK_SET); - - while ((amt = read(fd, buf, bufsize)) != 0) { - crc = crc32(crc, (Bytef*)buf, amt); - } - - free(buf); - return crc; -} - -int -back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD, - char const* const* files, char const* const* keys, int fileCount) -{ - int err; - KeyedVector oldSnapshot; - KeyedVector newSnapshot; - - if (oldSnapshotFD != -1) { - err = read_snapshot_file(oldSnapshotFD, &oldSnapshot); - if (err != 0) { - // On an error, treat this as a full backup. - oldSnapshot.clear(); - } - } - - for (int i=0; i= 0) { - LOGP("back_up_files key already in use '%s'", key.string()); - return -1; - } - } - newSnapshot.add(key, r); - } - - int n = 0; - int N = oldSnapshot.size(); - int m = 0; - - while (nWriteEntityHeader(p, -1); - n++; - } - else if (cmp > 0) { - // file added - LOGP("file added: %s", g.file.string()); - write_update_file(dataStream, q, g.file.string()); - m++; - } - else { - // both files exist, check them - const FileState& f = oldSnapshot.valueAt(n); - - int fd = open(g.file.string(), O_RDONLY); - if (fd < 0) { - // We can't open the file. Don't report it as a delete either. Let the - // server keep the old version. Maybe they'll be able to deal with it - // on restore. - LOGP("Unable to open file %s - skipping", g.file.string()); - } else { - g.s.crc32 = compute_crc32(fd); - - LOGP("%s", q.string()); - LOGP(" new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x", - f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32); - LOGP(" old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x", - g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32); - if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec - || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) { - write_update_file(dataStream, fd, g.s.mode, p, g.file.string()); - } - - close(fd); - } - n++; - m++; - } - } - - // these were deleted - while (nWriteEntityHeader(oldSnapshot.keyAt(n), -1); - n++; - } - - // these were added - while (m 9) len++; - if (len > 99) len++; - if (len > 999) len++; - // since PATH_MAX is 4096 we don't expect to have to generate any single - // header entry longer than 9999 characters - - return sprintf(buf, "%d %s=%s\n", len, key, value); -} - -// Wire format to the backup manager service is chunked: each chunk is prefixed by -// a 4-byte count of its size. A chunk size of zero (four zero bytes) indicates EOD. -void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t size) { - uint32_t chunk_size_no = htonl(size); - writer->WriteEntityData(&chunk_size_no, 4); - if (size != 0) writer->WriteEntityData(buffer, size); -} - -int write_tarfile(const String8& packageName, const String8& domain, - const String8& rootpath, const String8& filepath, BackupDataWriter* writer) -{ - // In the output stream everything is stored relative to the root - const char* relstart = filepath.string() + rootpath.length(); - if (*relstart == '/') relstart++; // won't be true when path == rootpath - String8 relpath(relstart); - - // If relpath is empty, it means this is the top of one of the standard named - // domain directories, so we should just skip it - if (relpath.length() == 0) { - return 0; - } - - // Too long a name for the ustar format? - // "apps/" + packagename + '/' + domainpath < 155 chars - // relpath < 100 chars - bool needExtended = false; - if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) { - needExtended = true; - } - - // Non-7bit-clean path also means needing pax extended format - if (!needExtended) { - for (size_t i = 0; i < filepath.length(); i++) { - if ((filepath[i] & 0x80) != 0) { - needExtended = true; - break; - } - } - } - - int err = 0; - struct stat64 s; - if (lstat64(filepath.string(), &s) != 0) { - err = errno; - ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string()); - return err; - } - - String8 fullname; // for pax later on - String8 prefix; - - const int isdir = S_ISDIR(s.st_mode); - if (isdir) s.st_size = 0; // directories get no actual data in the tar stream - - // !!! TODO: use mmap when possible to avoid churning the buffer cache - // !!! TODO: this will break with symlinks; need to use readlink(2) - int fd = open(filepath.string(), O_RDONLY); - if (fd < 0) { - err = errno; - ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string()); - return err; - } - - // read/write up to this much at a time. - const size_t BUFSIZE = 32 * 1024; - char* buf = (char *)calloc(1,BUFSIZE); - char* paxHeader = buf + 512; // use a different chunk of it as separate scratch - char* paxData = buf + 1024; - - if (buf == NULL) { - ALOGE("Out of mem allocating transfer buffer"); - err = ENOMEM; - goto done; - } - - // Magic fields for the ustar file format - strcat(buf + 257, "ustar"); - strcat(buf + 263, "00"); - - // [ 265 : 32 ] user name, ignored on restore - // [ 297 : 32 ] group name, ignored on restore - - // [ 100 : 8 ] file mode - snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT); - - // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time - // [ 116 : 8 ] gid -- ignored in Android format - snprintf(buf + 108, 8, "0%lo", s.st_uid); - snprintf(buf + 116, 8, "0%lo", s.st_gid); - - // [ 124 : 12 ] file size in bytes - if (s.st_size > 077777777777LL) { - // very large files need a pax extended size header - needExtended = true; - } - snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size); - - // [ 136 : 12 ] last mod time as a UTC time_t - snprintf(buf + 136, 12, "%0lo", s.st_mtime); - - // [ 156 : 1 ] link/file type - uint8_t type; - if (isdir) { - type = '5'; // tar magic: '5' == directory - } else if (S_ISREG(s.st_mode)) { - type = '0'; // tar magic: '0' == normal file - } else { - ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string()); - goto cleanup; - } - buf[156] = type; - - // [ 157 : 100 ] name of linked file [not implemented] - - { - // Prefix and main relative path. Path lengths have been preflighted. - if (packageName.length() > 0) { - prefix = "apps/"; - prefix += packageName; - } - if (domain.length() > 0) { - prefix.appendPath(domain); - } - - // pax extended means we don't put in a prefix field, and put a different - // string in the basic name field. We can also construct the full path name - // out of the substrings we've now built. - fullname = prefix; - fullname.appendPath(relpath); - - // ustar: - // [ 0 : 100 ]; file name/path - // [ 345 : 155 ] filename path prefix - // We only use the prefix area if fullname won't fit in the path - if (fullname.length() > 100) { - strncpy(buf, relpath.string(), 100); - strncpy(buf + 345, prefix.string(), 155); - } else { - strncpy(buf, fullname.string(), 100); - } - } - - // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used - - ALOGI(" Name: %s", fullname.string()); - - // If we're using a pax extended header, build & write that here; lengths are - // already preflighted - if (needExtended) { - char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal - char* p = paxData; - - // construct the pax extended header data block - memset(paxData, 0, BUFSIZE - (paxData - buf)); - int len; - - // size header -- calc len in digits by actually rendering the number - // to a string - brute force but simple - snprintf(sizeStr, sizeof(sizeStr), "%lld", s.st_size); - p += write_pax_header_entry(p, "size", sizeStr); - - // fullname was generated above with the ustar paths - p += write_pax_header_entry(p, "path", fullname.string()); - - // Now we know how big the pax data is - int paxLen = p - paxData; - - // Now build the pax *header* templated on the ustar header - memcpy(paxHeader, buf, 512); - - String8 leaf = fullname.getPathLeaf(); - memset(paxHeader, 0, 100); // rewrite the name area - snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string()); - memset(paxHeader + 345, 0, 155); // rewrite the prefix area - strncpy(paxHeader + 345, prefix.string(), 155); - - paxHeader[156] = 'x'; // mark it as a pax extended header - - // [ 124 : 12 ] size of pax extended header data - memset(paxHeader + 124, 0, 12); - snprintf(paxHeader + 124, 12, "%011o", p - paxData); - - // Checksum and write the pax block header - calc_tar_checksum(paxHeader); - send_tarfile_chunk(writer, paxHeader, 512); - - // Now write the pax data itself - int paxblocks = (paxLen + 511) / 512; - send_tarfile_chunk(writer, paxData, 512 * paxblocks); - } - - // Checksum and write the 512-byte ustar file header block to the output - calc_tar_checksum(buf); - send_tarfile_chunk(writer, buf, 512); - - // Now write the file data itself, for real files. We honor tar's convention that - // only full 512-byte blocks are sent to write(). - if (!isdir) { - off64_t toWrite = s.st_size; - while (toWrite > 0) { - size_t toRead = (toWrite < BUFSIZE) ? toWrite : BUFSIZE; - ssize_t nRead = read(fd, buf, toRead); - if (nRead < 0) { - err = errno; - ALOGE("Unable to read file [%s], err=%d (%s)", filepath.string(), - err, strerror(err)); - break; - } else if (nRead == 0) { - ALOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite, - filepath.string()); - err = EIO; - break; - } - - // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This - // depends on the OS guarantee that for ordinary files, read() will never return - // less than the number of bytes requested. - ssize_t partial = (nRead+512) % 512; - if (partial > 0) { - ssize_t remainder = 512 - partial; - memset(buf + nRead, 0, remainder); - nRead += remainder; - } - send_tarfile_chunk(writer, buf, nRead); - toWrite -= nRead; - } - } - -cleanup: - free(buf); -done: - close(fd); - return err; -} -// end tarfile - - - -#define RESTORE_BUF_SIZE (8*1024) - -RestoreHelperBase::RestoreHelperBase() -{ - m_buf = malloc(RESTORE_BUF_SIZE); - m_loggedUnknownMetadata = false; -} - -RestoreHelperBase::~RestoreHelperBase() -{ - free(m_buf); -} - -status_t -RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in) -{ - ssize_t err; - size_t dataSize; - String8 key; - int fd; - void* buf = m_buf; - ssize_t amt; - int mode; - int crc; - struct stat st; - FileRec r; - - err = in->ReadEntityHeader(&key, &dataSize); - if (err != NO_ERROR) { - return err; - } - - // Get the metadata block off the head of the file entity and use that to - // set up the output file - file_metadata_v1 metadata; - amt = in->ReadEntityData(&metadata, sizeof(metadata)); - if (amt != sizeof(metadata)) { - ALOGW("Could not read metadata for %s -- %ld / %s", filename.string(), - (long)amt, strerror(errno)); - return EIO; - } - metadata.version = fromlel(metadata.version); - metadata.mode = fromlel(metadata.mode); - if (metadata.version > CURRENT_METADATA_VERSION) { - if (!m_loggedUnknownMetadata) { - m_loggedUnknownMetadata = true; - ALOGW("Restoring file with unsupported metadata version %d (currently %d)", - metadata.version, CURRENT_METADATA_VERSION); - } - } - mode = metadata.mode; - - // Write the file and compute the crc - crc = crc32(0L, Z_NULL, 0); - fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode); - if (fd == -1) { - ALOGW("Could not open file %s -- %s", filename.string(), strerror(errno)); - return errno; - } - - while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) { - err = write(fd, buf, amt); - if (err != amt) { - close(fd); - ALOGW("Error '%s' writing '%s'", strerror(errno), filename.string()); - return errno; - } - crc = crc32(crc, (Bytef*)buf, amt); - } - - close(fd); - - // Record for the snapshot - err = stat(filename.string(), &st); - if (err != 0) { - ALOGW("Error stating file that we just created %s", filename.string()); - return errno; - } - - r.file = filename; - r.deleted = false; - r.s.modTime_sec = st.st_mtime; - r.s.modTime_nsec = 0; // workaround sim breakage - //r.s.modTime_nsec = st.st_mtime_nsec; - r.s.mode = st.st_mode; - r.s.size = st.st_size; - r.s.crc32 = crc; - - m_files.add(key, r); - - return NO_ERROR; -} - -status_t -RestoreHelperBase::WriteSnapshot(int fd) -{ - return write_snapshot_file(fd, m_files);; -} - -#if TEST_BACKUP_HELPERS - -#define SCRATCH_DIR "/data/backup_helper_test/" - -static int -write_text_file(const char* path, const char* data) -{ - int amt; - int fd; - int len; - - fd = creat(path, 0666); - if (fd == -1) { - fprintf(stderr, "creat %s failed\n", path); - return errno; - } - - len = strlen(data); - amt = write(fd, data, len); - if (amt != len) { - fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path); - return errno; - } - - close(fd); - - return 0; -} - -static int -compare_file(const char* path, const unsigned char* data, int len) -{ - int fd; - int amt; - - fd = open(path, O_RDONLY); - if (fd == -1) { - fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path); - return errno; - } - - unsigned char* contents = (unsigned char*)malloc(len); - if (contents == NULL) { - fprintf(stderr, "malloc(%d) failed\n", len); - return ENOMEM; - } - - bool sizesMatch = true; - amt = lseek(fd, 0, SEEK_END); - if (amt != len) { - fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt); - sizesMatch = false; - } - lseek(fd, 0, SEEK_SET); - - int readLen = amt < len ? amt : len; - amt = read(fd, contents, readLen); - if (amt != readLen) { - fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt); - } - - bool contentsMatch = true; - for (int i=0; i snapshot; - const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap"; - - system("rm -r " SCRATCH_DIR); - mkdir(SCRATCH_DIR, 0777); - - // write - fd = creat(filename, 0666); - if (fd == -1) { - fprintf(stderr, "error creating %s\n", filename); - return 1; - } - - err = write_snapshot_file(fd, snapshot); - - close(fd); - - if (err != 0) { - fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err)); - return err; - } - - static const unsigned char correct_data[] = { - 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00, - 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00 - }; - - err = compare_file(filename, correct_data, sizeof(correct_data)); - if (err != 0) { - return err; - } - - // read - fd = open(filename, O_RDONLY); - if (fd == -1) { - fprintf(stderr, "error opening for read %s\n", filename); - return 1; - } - - KeyedVector readSnapshot; - err = read_snapshot_file(fd, &readSnapshot); - if (err != 0) { - fprintf(stderr, "read_snapshot_file failed %d\n", err); - return err; - } - - if (readSnapshot.size() != 0) { - fprintf(stderr, "readSnapshot should be length 0\n"); - return 1; - } - - return 0; -} - -int -backup_helper_test_four() -{ - int err; - int fd; - KeyedVector snapshot; - const char* filename = SCRATCH_DIR "backup_helper_test_four.snap"; - - system("rm -r " SCRATCH_DIR); - mkdir(SCRATCH_DIR, 0777); - - // write - fd = creat(filename, 0666); - if (fd == -1) { - fprintf(stderr, "error opening %s\n", filename); - return 1; - } - - String8 filenames[4]; - FileState states[4]; - FileRec r; - r.deleted = false; - - states[0].modTime_sec = 0xfedcba98; - states[0].modTime_nsec = 0xdeadbeef; - states[0].mode = 0777; // decimal 511, hex 0x000001ff - states[0].size = 0xababbcbc; - states[0].crc32 = 0x12345678; - states[0].nameLen = -12; - r.s = states[0]; - filenames[0] = String8("bytes_of_padding"); - snapshot.add(filenames[0], r); - - states[1].modTime_sec = 0x93400031; - states[1].modTime_nsec = 0xdeadbeef; - states[1].mode = 0666; // decimal 438, hex 0x000001b6 - states[1].size = 0x88557766; - states[1].crc32 = 0x22334422; - states[1].nameLen = -1; - r.s = states[1]; - filenames[1] = String8("bytes_of_padding3"); - snapshot.add(filenames[1], r); - - states[2].modTime_sec = 0x33221144; - states[2].modTime_nsec = 0xdeadbeef; - states[2].mode = 0744; // decimal 484, hex 0x000001e4 - states[2].size = 0x11223344; - states[2].crc32 = 0x01122334; - states[2].nameLen = 0; - r.s = states[2]; - filenames[2] = String8("bytes_of_padding_2"); - snapshot.add(filenames[2], r); - - states[3].modTime_sec = 0x33221144; - states[3].modTime_nsec = 0xdeadbeef; - states[3].mode = 0755; // decimal 493, hex 0x000001ed - states[3].size = 0x11223344; - states[3].crc32 = 0x01122334; - states[3].nameLen = 0; - r.s = states[3]; - filenames[3] = String8("bytes_of_padding__1"); - snapshot.add(filenames[3], r); - - err = write_snapshot_file(fd, snapshot); - - close(fd); - - if (err != 0) { - fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err)); - return err; - } - - static const unsigned char correct_data[] = { - // header - 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00, - 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00, - - // bytes_of_padding - 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde, - 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab, - 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00, - 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66, - 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, - - // bytes_of_padding3 - 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde, - 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88, - 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, - 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66, - 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, - 0x33, 0xab, 0xab, 0xab, - - // bytes of padding2 - 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde, - 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11, - 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00, - 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66, - 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, - 0x5f, 0x32, 0xab, 0xab, - - // bytes of padding3 - 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde, - 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11, - 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00, - 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66, - 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, - 0x5f, 0x5f, 0x31, 0xab - }; - - err = compare_file(filename, correct_data, sizeof(correct_data)); - if (err != 0) { - return err; - } - - // read - fd = open(filename, O_RDONLY); - if (fd == -1) { - fprintf(stderr, "error opening for read %s\n", filename); - return 1; - } - - - KeyedVector readSnapshot; - err = read_snapshot_file(fd, &readSnapshot); - if (err != 0) { - fprintf(stderr, "read_snapshot_file failed %d\n", err); - return err; - } - - if (readSnapshot.size() != 4) { - fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size()); - return 1; - } - - bool matched = true; - for (size_t i=0; i -#include -#include - -#include -#include - -#include -#include -#include - -namespace android { - -CursorWindow::CursorWindow(const String8& name, int ashmemFd, - void* data, size_t size, bool readOnly) : - mName(name), mAshmemFd(ashmemFd), mData(data), mSize(size), mReadOnly(readOnly) { - mHeader = static_cast(mData); -} - -CursorWindow::~CursorWindow() { - ::munmap(mData, mSize); - ::close(mAshmemFd); -} - -status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) { - String8 ashmemName("CursorWindow: "); - ashmemName.append(name); - - status_t result; - int ashmemFd = ashmem_create_region(ashmemName.string(), size); - if (ashmemFd < 0) { - result = -errno; - } else { - result = ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE); - if (result >= 0) { - void* data = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0); - if (data == MAP_FAILED) { - result = -errno; - } else { - result = ashmem_set_prot_region(ashmemFd, PROT_READ); - if (result >= 0) { - CursorWindow* window = new CursorWindow(name, ashmemFd, - data, size, false /*readOnly*/); - result = window->clear(); - if (!result) { - LOG_WINDOW("Created new CursorWindow: freeOffset=%d, " - "numRows=%d, numColumns=%d, mSize=%d, mData=%p", - window->mHeader->freeOffset, - window->mHeader->numRows, - window->mHeader->numColumns, - window->mSize, window->mData); - *outCursorWindow = window; - return OK; - } - delete window; - } - } - ::munmap(data, size); - } - ::close(ashmemFd); - } - *outCursorWindow = NULL; - return result; -} - -status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow) { - String8 name = parcel->readString8(); - - status_t result; - int ashmemFd = parcel->readFileDescriptor(); - if (ashmemFd == int(BAD_TYPE)) { - result = BAD_TYPE; - } else { - ssize_t size = ashmem_get_size_region(ashmemFd); - if (size < 0) { - result = UNKNOWN_ERROR; - } else { - int dupAshmemFd = ::dup(ashmemFd); - if (dupAshmemFd < 0) { - result = -errno; - } else { - void* data = ::mmap(NULL, size, PROT_READ, MAP_SHARED, dupAshmemFd, 0); - if (data == MAP_FAILED) { - result = -errno; - } else { - CursorWindow* window = new CursorWindow(name, dupAshmemFd, - data, size, true /*readOnly*/); - LOG_WINDOW("Created CursorWindow from parcel: freeOffset=%d, " - "numRows=%d, numColumns=%d, mSize=%d, mData=%p", - window->mHeader->freeOffset, - window->mHeader->numRows, - window->mHeader->numColumns, - window->mSize, window->mData); - *outCursorWindow = window; - return OK; - } - ::close(dupAshmemFd); - } - } - } - *outCursorWindow = NULL; - return result; -} - -status_t CursorWindow::writeToParcel(Parcel* parcel) { - status_t status = parcel->writeString8(mName); - if (!status) { - status = parcel->writeDupFileDescriptor(mAshmemFd); - } - return status; -} - -status_t CursorWindow::clear() { - if (mReadOnly) { - return INVALID_OPERATION; - } - - mHeader->freeOffset = sizeof(Header) + sizeof(RowSlotChunk); - mHeader->firstChunkOffset = sizeof(Header); - mHeader->numRows = 0; - mHeader->numColumns = 0; - - RowSlotChunk* firstChunk = static_cast(offsetToPtr(mHeader->firstChunkOffset)); - firstChunk->nextChunkOffset = 0; - return OK; -} - -status_t CursorWindow::setNumColumns(uint32_t numColumns) { - if (mReadOnly) { - return INVALID_OPERATION; - } - - uint32_t cur = mHeader->numColumns; - if ((cur > 0 || mHeader->numRows > 0) && cur != numColumns) { - ALOGE("Trying to go from %d columns to %d", cur, numColumns); - return INVALID_OPERATION; - } - mHeader->numColumns = numColumns; - return OK; -} - -status_t CursorWindow::allocRow() { - if (mReadOnly) { - return INVALID_OPERATION; - } - - // Fill in the row slot - RowSlot* rowSlot = allocRowSlot(); - if (rowSlot == NULL) { - return NO_MEMORY; - } - - // Allocate the slots for the field directory - size_t fieldDirSize = mHeader->numColumns * sizeof(FieldSlot); - uint32_t fieldDirOffset = alloc(fieldDirSize, true /*aligned*/); - if (!fieldDirOffset) { - mHeader->numRows--; - LOG_WINDOW("The row failed, so back out the new row accounting " - "from allocRowSlot %d", mHeader->numRows); - return NO_MEMORY; - } - FieldSlot* fieldDir = static_cast(offsetToPtr(fieldDirOffset)); - memset(fieldDir, 0, fieldDirSize); - - LOG_WINDOW("Allocated row %u, rowSlot is at offset %u, fieldDir is %d bytes at offset %u\n", - mHeader->numRows - 1, offsetFromPtr(rowSlot), fieldDirSize, fieldDirOffset); - rowSlot->offset = fieldDirOffset; - return OK; -} - -status_t CursorWindow::freeLastRow() { - if (mReadOnly) { - return INVALID_OPERATION; - } - - if (mHeader->numRows > 0) { - mHeader->numRows--; - } - return OK; -} - -uint32_t CursorWindow::alloc(size_t size, bool aligned) { - uint32_t padding; - if (aligned) { - // 4 byte alignment - padding = (~mHeader->freeOffset + 1) & 3; - } else { - padding = 0; - } - - uint32_t offset = mHeader->freeOffset + padding; - uint32_t nextFreeOffset = offset + size; - if (nextFreeOffset > mSize) { - ALOGW("Window is full: requested allocation %d bytes, " - "free space %d bytes, window size %d bytes", - size, freeSpace(), mSize); - return 0; - } - - mHeader->freeOffset = nextFreeOffset; - return offset; -} - -CursorWindow::RowSlot* CursorWindow::getRowSlot(uint32_t row) { - uint32_t chunkPos = row; - RowSlotChunk* chunk = static_cast( - offsetToPtr(mHeader->firstChunkOffset)); - while (chunkPos >= ROW_SLOT_CHUNK_NUM_ROWS) { - chunk = static_cast(offsetToPtr(chunk->nextChunkOffset)); - chunkPos -= ROW_SLOT_CHUNK_NUM_ROWS; - } - return &chunk->slots[chunkPos]; -} - -CursorWindow::RowSlot* CursorWindow::allocRowSlot() { - uint32_t chunkPos = mHeader->numRows; - RowSlotChunk* chunk = static_cast( - offsetToPtr(mHeader->firstChunkOffset)); - while (chunkPos > ROW_SLOT_CHUNK_NUM_ROWS) { - chunk = static_cast(offsetToPtr(chunk->nextChunkOffset)); - chunkPos -= ROW_SLOT_CHUNK_NUM_ROWS; - } - if (chunkPos == ROW_SLOT_CHUNK_NUM_ROWS) { - if (!chunk->nextChunkOffset) { - chunk->nextChunkOffset = alloc(sizeof(RowSlotChunk), true /*aligned*/); - if (!chunk->nextChunkOffset) { - return NULL; - } - } - chunk = static_cast(offsetToPtr(chunk->nextChunkOffset)); - chunk->nextChunkOffset = 0; - chunkPos = 0; - } - mHeader->numRows += 1; - return &chunk->slots[chunkPos]; -} - -CursorWindow::FieldSlot* CursorWindow::getFieldSlot(uint32_t row, uint32_t column) { - if (row >= mHeader->numRows || column >= mHeader->numColumns) { - ALOGE("Failed to read row %d, column %d from a CursorWindow which " - "has %d rows, %d columns.", - row, column, mHeader->numRows, mHeader->numColumns); - return NULL; - } - RowSlot* rowSlot = getRowSlot(row); - if (!rowSlot) { - ALOGE("Failed to find rowSlot for row %d.", row); - return NULL; - } - FieldSlot* fieldDir = static_cast(offsetToPtr(rowSlot->offset)); - return &fieldDir[column]; -} - -status_t CursorWindow::putBlob(uint32_t row, uint32_t column, const void* value, size_t size) { - return putBlobOrString(row, column, value, size, FIELD_TYPE_BLOB); -} - -status_t CursorWindow::putString(uint32_t row, uint32_t column, const char* value, - size_t sizeIncludingNull) { - return putBlobOrString(row, column, value, sizeIncludingNull, FIELD_TYPE_STRING); -} - -status_t CursorWindow::putBlobOrString(uint32_t row, uint32_t column, - const void* value, size_t size, int32_t type) { - if (mReadOnly) { - return INVALID_OPERATION; - } - - FieldSlot* fieldSlot = getFieldSlot(row, column); - if (!fieldSlot) { - return BAD_VALUE; - } - - uint32_t offset = alloc(size); - if (!offset) { - return NO_MEMORY; - } - - memcpy(offsetToPtr(offset), value, size); - - fieldSlot->type = type; - fieldSlot->data.buffer.offset = offset; - fieldSlot->data.buffer.size = size; - return OK; -} - -status_t CursorWindow::putLong(uint32_t row, uint32_t column, int64_t value) { - if (mReadOnly) { - return INVALID_OPERATION; - } - - FieldSlot* fieldSlot = getFieldSlot(row, column); - if (!fieldSlot) { - return BAD_VALUE; - } - - fieldSlot->type = FIELD_TYPE_INTEGER; - fieldSlot->data.l = value; - return OK; -} - -status_t CursorWindow::putDouble(uint32_t row, uint32_t column, double value) { - if (mReadOnly) { - return INVALID_OPERATION; - } - - FieldSlot* fieldSlot = getFieldSlot(row, column); - if (!fieldSlot) { - return BAD_VALUE; - } - - fieldSlot->type = FIELD_TYPE_FLOAT; - fieldSlot->data.d = value; - return OK; -} - -status_t CursorWindow::putNull(uint32_t row, uint32_t column) { - if (mReadOnly) { - return INVALID_OPERATION; - } - - FieldSlot* fieldSlot = getFieldSlot(row, column); - if (!fieldSlot) { - return BAD_VALUE; - } - - fieldSlot->type = FIELD_TYPE_NULL; - fieldSlot->data.buffer.offset = 0; - fieldSlot->data.buffer.size = 0; - return OK; -} - -}; // namespace android diff --git a/libs/androidfw/MODULE_LICENSE_APACHE2 b/libs/androidfw/MODULE_LICENSE_APACHE2 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libs/androidfw/NOTICE b/libs/androidfw/NOTICE deleted file mode 100644 index c5b1efa7aa..0000000000 --- a/libs/androidfw/NOTICE +++ /dev/null @@ -1,190 +0,0 @@ - - Copyright (c) 2005-2008, The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - - 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. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - diff --git a/libs/androidfw/ObbFile.cpp b/libs/androidfw/ObbFile.cpp deleted file mode 100644 index ec59f0666c..0000000000 --- a/libs/androidfw/ObbFile.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (C) 2010 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 -#include -#include -#include -#include -#include - -#define LOG_TAG "ObbFile" - -#include -#include -#include - -//#define DEBUG 1 - -#define kFooterTagSize 8 /* last two 32-bit integers */ - -#define kFooterMinSize 33 /* 32-bit signature version (4 bytes) - * 32-bit package version (4 bytes) - * 32-bit flags (4 bytes) - * 64-bit salt (8 bytes) - * 32-bit package name size (4 bytes) - * >=1-character package name (1 byte) - * 32-bit footer size (4 bytes) - * 32-bit footer marker (4 bytes) - */ - -#define kMaxBufSize 32768 /* Maximum file read buffer */ - -#define kSignature 0x01059983U /* ObbFile signature */ - -#define kSigVersion 1 /* We only know about signature version 1 */ - -/* offsets in version 1 of the header */ -#define kPackageVersionOffset 4 -#define kFlagsOffset 8 -#define kSaltOffset 12 -#define kPackageNameLenOffset 20 -#define kPackageNameOffset 24 - -/* - * TEMP_FAILURE_RETRY is defined by some, but not all, versions of - * . (Alas, it is not as standard as we'd hoped!) So, if it's - * not already defined, then define it here. - */ -#ifndef TEMP_FAILURE_RETRY -/* Used to retry syscalls that can return EINTR. */ -#define TEMP_FAILURE_RETRY(exp) ({ \ - typeof (exp) _rc; \ - do { \ - _rc = (exp); \ - } while (_rc == -1 && errno == EINTR); \ - _rc; }) -#endif - - -namespace android { - -ObbFile::ObbFile() - : mPackageName("") - , mVersion(-1) - , mFlags(0) -{ - memset(mSalt, 0, sizeof(mSalt)); -} - -ObbFile::~ObbFile() { -} - -bool ObbFile::readFrom(const char* filename) -{ - int fd; - bool success = false; - - fd = ::open(filename, O_RDONLY); - if (fd < 0) { - ALOGW("couldn't open file %s: %s", filename, strerror(errno)); - goto out; - } - success = readFrom(fd); - close(fd); - - if (!success) { - ALOGW("failed to read from %s (fd=%d)\n", filename, fd); - } - -out: - return success; -} - -bool ObbFile::readFrom(int fd) -{ - if (fd < 0) { - ALOGW("attempt to read from invalid fd\n"); - return false; - } - - return parseObbFile(fd); -} - -bool ObbFile::parseObbFile(int fd) -{ - off64_t fileLength = lseek64(fd, 0, SEEK_END); - - if (fileLength < kFooterMinSize) { - if (fileLength < 0) { - ALOGW("error seeking in ObbFile: %s\n", strerror(errno)); - } else { - ALOGW("file is only %lld (less than %d minimum)\n", fileLength, kFooterMinSize); - } - return false; - } - - ssize_t actual; - size_t footerSize; - - { - lseek64(fd, fileLength - kFooterTagSize, SEEK_SET); - - char footer[kFooterTagSize]; - actual = TEMP_FAILURE_RETRY(read(fd, footer, kFooterTagSize)); - if (actual != kFooterTagSize) { - ALOGW("couldn't read footer signature: %s\n", strerror(errno)); - return false; - } - - unsigned int fileSig = get4LE((unsigned char*)footer + sizeof(int32_t)); - if (fileSig != kSignature) { - ALOGW("footer didn't match magic string (expected 0x%08x; got 0x%08x)\n", - kSignature, fileSig); - return false; - } - - footerSize = get4LE((unsigned char*)footer); - if (footerSize > (size_t)fileLength - kFooterTagSize - || footerSize > kMaxBufSize) { - ALOGW("claimed footer size is too large (0x%08zx; file size is 0x%08llx)\n", - footerSize, fileLength); - return false; - } - - if (footerSize < (kFooterMinSize - kFooterTagSize)) { - ALOGW("claimed footer size is too small (0x%zx; minimum size is 0x%x)\n", - footerSize, kFooterMinSize - kFooterTagSize); - return false; - } - } - - off64_t fileOffset = fileLength - footerSize - kFooterTagSize; - if (lseek64(fd, fileOffset, SEEK_SET) != fileOffset) { - ALOGW("seek %lld failed: %s\n", fileOffset, strerror(errno)); - return false; - } - - mFooterStart = fileOffset; - - char* scanBuf = (char*)malloc(footerSize); - if (scanBuf == NULL) { - ALOGW("couldn't allocate scanBuf: %s\n", strerror(errno)); - return false; - } - - actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, footerSize)); - // readAmount is guaranteed to be less than kMaxBufSize - if (actual != (ssize_t)footerSize) { - ALOGI("couldn't read ObbFile footer: %s\n", strerror(errno)); - free(scanBuf); - return false; - } - -#ifdef DEBUG - for (int i = 0; i < footerSize; ++i) { - ALOGI("char: 0x%02x\n", scanBuf[i]); - } -#endif - - uint32_t sigVersion = get4LE((unsigned char*)scanBuf); - if (sigVersion != kSigVersion) { - ALOGW("Unsupported ObbFile version %d\n", sigVersion); - free(scanBuf); - return false; - } - - mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset); - mFlags = (int32_t) get4LE((unsigned char*)scanBuf + kFlagsOffset); - - memcpy(&mSalt, (unsigned char*)scanBuf + kSaltOffset, sizeof(mSalt)); - - size_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset); - if (packageNameLen == 0 - || packageNameLen > (footerSize - kPackageNameOffset)) { - ALOGW("bad ObbFile package name length (0x%04zx; 0x%04zx possible)\n", - packageNameLen, footerSize - kPackageNameOffset); - free(scanBuf); - return false; - } - - char* packageName = reinterpret_cast(scanBuf + kPackageNameOffset); - mPackageName = String8(const_cast(packageName), packageNameLen); - - free(scanBuf); - -#ifdef DEBUG - ALOGI("Obb scan succeeded: packageName=%s, version=%d\n", mPackageName.string(), mVersion); -#endif - - return true; -} - -bool ObbFile::writeTo(const char* filename) -{ - int fd; - bool success = false; - - fd = ::open(filename, O_WRONLY); - if (fd < 0) { - goto out; - } - success = writeTo(fd); - close(fd); - -out: - if (!success) { - ALOGW("failed to write to %s: %s\n", filename, strerror(errno)); - } - return success; -} - -bool ObbFile::writeTo(int fd) -{ - if (fd < 0) { - return false; - } - - lseek64(fd, 0, SEEK_END); - - if (mPackageName.size() == 0 || mVersion == -1) { - ALOGW("tried to write uninitialized ObbFile data\n"); - return false; - } - - unsigned char intBuf[sizeof(uint32_t)+1]; - memset(&intBuf, 0, sizeof(intBuf)); - - put4LE(intBuf, kSigVersion); - if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { - ALOGW("couldn't write signature version: %s\n", strerror(errno)); - return false; - } - - put4LE(intBuf, mVersion); - if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { - ALOGW("couldn't write package version\n"); - return false; - } - - put4LE(intBuf, mFlags); - if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { - ALOGW("couldn't write package version\n"); - return false; - } - - if (write(fd, mSalt, sizeof(mSalt)) != (ssize_t)sizeof(mSalt)) { - ALOGW("couldn't write salt: %s\n", strerror(errno)); - return false; - } - - size_t packageNameLen = mPackageName.size(); - put4LE(intBuf, packageNameLen); - if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { - ALOGW("couldn't write package name length: %s\n", strerror(errno)); - return false; - } - - if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) { - ALOGW("couldn't write package name: %s\n", strerror(errno)); - return false; - } - - put4LE(intBuf, kPackageNameOffset + packageNameLen); - if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { - ALOGW("couldn't write footer size: %s\n", strerror(errno)); - return false; - } - - put4LE(intBuf, kSignature); - if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { - ALOGW("couldn't write footer magic signature: %s\n", strerror(errno)); - return false; - } - - return true; -} - -bool ObbFile::removeFrom(const char* filename) -{ - int fd; - bool success = false; - - fd = ::open(filename, O_RDWR); - if (fd < 0) { - goto out; - } - success = removeFrom(fd); - close(fd); - -out: - if (!success) { - ALOGW("failed to remove signature from %s: %s\n", filename, strerror(errno)); - } - return success; -} - -bool ObbFile::removeFrom(int fd) -{ - if (fd < 0) { - return false; - } - - if (!readFrom(fd)) { - return false; - } - - ftruncate(fd, mFooterStart); - - return true; -} - -} diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp deleted file mode 100644 index 1cc3563e0f..0000000000 --- a/libs/androidfw/ResourceTypes.cpp +++ /dev/null @@ -1,5796 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "ResourceType" -//#define LOG_NDEBUG 0 - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#ifndef INT32_MAX -#define INT32_MAX ((int32_t)(2147483647)) -#endif - -#define STRING_POOL_NOISY(x) //x -#define XML_NOISY(x) //x -#define TABLE_NOISY(x) //x -#define TABLE_GETENTRY(x) //x -#define TABLE_SUPER_NOISY(x) //x -#define LOAD_TABLE_NOISY(x) //x -#define TABLE_THEME(x) //x - -namespace android { - -#ifdef HAVE_WINSOCK -#undef nhtol -#undef htonl - -#ifdef HAVE_LITTLE_ENDIAN -#define ntohl(x) ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) ) -#define htonl(x) ntohl(x) -#define ntohs(x) ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) ) -#define htons(x) ntohs(x) -#else -#define ntohl(x) (x) -#define htonl(x) (x) -#define ntohs(x) (x) -#define htons(x) (x) -#endif -#endif - -#define IDMAP_MAGIC 0x706d6469 -// size measured in sizeof(uint32_t) -#define IDMAP_HEADER_SIZE (ResTable::IDMAP_HEADER_SIZE_BYTES / sizeof(uint32_t)) - -static void printToLogFunc(void* cookie, const char* txt) -{ - ALOGV("%s", txt); -} - -// Standard C isspace() is only required to look at the low byte of its input, so -// produces incorrect results for UTF-16 characters. For safety's sake, assume that -// any high-byte UTF-16 code point is not whitespace. -inline int isspace16(char16_t c) { - return (c < 0x0080 && isspace(c)); -} - -// range checked; guaranteed to NUL-terminate within the stated number of available slots -// NOTE: if this truncates the dst string due to running out of space, no attempt is -// made to avoid splitting surrogate pairs. -static void strcpy16_dtoh(uint16_t* dst, const uint16_t* src, size_t avail) -{ - uint16_t* last = dst + avail - 1; - while (*src && (dst < last)) { - char16_t s = dtohs(*src); - *dst++ = s; - src++; - } - *dst = 0; -} - -static status_t validate_chunk(const ResChunk_header* chunk, - size_t minSize, - const uint8_t* dataEnd, - const char* name) -{ - const uint16_t headerSize = dtohs(chunk->headerSize); - const uint32_t size = dtohl(chunk->size); - - if (headerSize >= minSize) { - if (headerSize <= size) { - if (((headerSize|size)&0x3) == 0) { - if ((ssize_t)size <= (dataEnd-((const uint8_t*)chunk))) { - return NO_ERROR; - } - ALOGW("%s data size %p extends beyond resource end %p.", - name, (void*)size, - (void*)(dataEnd-((const uint8_t*)chunk))); - return BAD_TYPE; - } - ALOGW("%s size 0x%x or headerSize 0x%x is not on an integer boundary.", - name, (int)size, (int)headerSize); - return BAD_TYPE; - } - ALOGW("%s size %p is smaller than header size %p.", - name, (void*)size, (void*)(int)headerSize); - return BAD_TYPE; - } - ALOGW("%s header size %p is too small.", - name, (void*)(int)headerSize); - return BAD_TYPE; -} - -inline void Res_value::copyFrom_dtoh(const Res_value& src) -{ - size = dtohs(src.size); - res0 = src.res0; - dataType = src.dataType; - data = dtohl(src.data); -} - -void Res_png_9patch::deviceToFile() -{ - for (int i = 0; i < numXDivs; i++) { - xDivs[i] = htonl(xDivs[i]); - } - for (int i = 0; i < numYDivs; i++) { - yDivs[i] = htonl(yDivs[i]); - } - paddingLeft = htonl(paddingLeft); - paddingRight = htonl(paddingRight); - paddingTop = htonl(paddingTop); - paddingBottom = htonl(paddingBottom); - for (int i=0; ixDivs, numXDivs * sizeof(int32_t)); - data += numXDivs * sizeof(int32_t); - memmove(data, this->yDivs, numYDivs * sizeof(int32_t)); - data += numYDivs * sizeof(int32_t); - memmove(data, this->colors, numColors * sizeof(uint32_t)); -} - -static void deserializeInternal(const void* inData, Res_png_9patch* outData) { - char* patch = (char*) inData; - if (inData != outData) { - memmove(&outData->wasDeserialized, patch, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors - memmove(&outData->paddingLeft, patch + 12, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors - } - outData->wasDeserialized = true; - char* data = (char*)outData; - data += sizeof(Res_png_9patch); - outData->xDivs = (int32_t*) data; - data += outData->numXDivs * sizeof(int32_t); - outData->yDivs = (int32_t*) data; - data += outData->numYDivs * sizeof(int32_t); - outData->colors = (uint32_t*) data; -} - -static bool assertIdmapHeader(const uint32_t* map, size_t sizeBytes) -{ - if (sizeBytes < ResTable::IDMAP_HEADER_SIZE_BYTES) { - ALOGW("idmap assertion failed: size=%d bytes\n", (int)sizeBytes); - return false; - } - if (*map != htodl(IDMAP_MAGIC)) { // htodl: map data expected to be in correct endianess - ALOGW("idmap assertion failed: invalid magic found (is 0x%08x, expected 0x%08x)\n", - *map, htodl(IDMAP_MAGIC)); - return false; - } - return true; -} - -static status_t idmapLookup(const uint32_t* map, size_t sizeBytes, uint32_t key, uint32_t* outValue) -{ - // see README for details on the format of map - if (!assertIdmapHeader(map, sizeBytes)) { - return UNKNOWN_ERROR; - } - map = map + IDMAP_HEADER_SIZE; // skip ahead to data segment - // size of data block, in uint32_t - const size_t size = (sizeBytes - ResTable::IDMAP_HEADER_SIZE_BYTES) / sizeof(uint32_t); - const uint32_t type = Res_GETTYPE(key) + 1; // add one, idmap stores "public" type id - const uint32_t entry = Res_GETENTRY(key); - const uint32_t typeCount = *map; - - if (type > typeCount) { - ALOGW("Resource ID map: type=%d exceeds number of types=%d\n", type, typeCount); - return UNKNOWN_ERROR; - } - if (typeCount > size) { - ALOGW("Resource ID map: number of types=%d exceeds size of map=%d\n", typeCount, (int)size); - return UNKNOWN_ERROR; - } - const uint32_t typeOffset = map[type]; - if (typeOffset == 0) { - *outValue = 0; - return NO_ERROR; - } - if (typeOffset + 1 > size) { - ALOGW("Resource ID map: type offset=%d exceeds reasonable value, size of map=%d\n", - typeOffset, (int)size); - return UNKNOWN_ERROR; - } - const uint32_t entryCount = map[typeOffset]; - const uint32_t entryOffset = map[typeOffset + 1]; - if (entryCount == 0 || entry < entryOffset || entry - entryOffset > entryCount - 1) { - *outValue = 0; - return NO_ERROR; - } - const uint32_t index = typeOffset + 2 + entry - entryOffset; - if (index > size) { - ALOGW("Resource ID map: entry index=%d exceeds size of map=%d\n", index, (int)size); - *outValue = 0; - return NO_ERROR; - } - *outValue = map[index]; - - return NO_ERROR; -} - -static status_t getIdmapPackageId(const uint32_t* map, size_t mapSize, uint32_t *outId) -{ - if (!assertIdmapHeader(map, mapSize)) { - return UNKNOWN_ERROR; - } - const uint32_t* p = map + IDMAP_HEADER_SIZE + 1; - while (*p == 0) { - ++p; - } - *outId = (map[*p + IDMAP_HEADER_SIZE + 2] >> 24) & 0x000000ff; - return NO_ERROR; -} - -Res_png_9patch* Res_png_9patch::deserialize(const void* inData) -{ - if (sizeof(void*) != sizeof(int32_t)) { - ALOGE("Cannot deserialize on non 32-bit system\n"); - return NULL; - } - deserializeInternal(inData, (Res_png_9patch*) inData); - return (Res_png_9patch*) inData; -} - -// -------------------------------------------------------------------- -// -------------------------------------------------------------------- -// -------------------------------------------------------------------- - -ResStringPool::ResStringPool() - : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL) -{ -} - -ResStringPool::ResStringPool(const void* data, size_t size, bool copyData) - : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL) -{ - setTo(data, size, copyData); -} - -ResStringPool::~ResStringPool() -{ - uninit(); -} - -status_t ResStringPool::setTo(const void* data, size_t size, bool copyData) -{ - if (!data || !size) { - return (mError=BAD_TYPE); - } - - uninit(); - - const bool notDeviceEndian = htods(0xf0) != 0xf0; - - if (copyData || notDeviceEndian) { - mOwnedData = malloc(size); - if (mOwnedData == NULL) { - return (mError=NO_MEMORY); - } - memcpy(mOwnedData, data, size); - data = mOwnedData; - } - - mHeader = (const ResStringPool_header*)data; - - if (notDeviceEndian) { - ResStringPool_header* h = const_cast(mHeader); - h->header.headerSize = dtohs(mHeader->header.headerSize); - h->header.type = dtohs(mHeader->header.type); - h->header.size = dtohl(mHeader->header.size); - h->stringCount = dtohl(mHeader->stringCount); - h->styleCount = dtohl(mHeader->styleCount); - h->flags = dtohl(mHeader->flags); - h->stringsStart = dtohl(mHeader->stringsStart); - h->stylesStart = dtohl(mHeader->stylesStart); - } - - if (mHeader->header.headerSize > mHeader->header.size - || mHeader->header.size > size) { - ALOGW("Bad string block: header size %d or total size %d is larger than data size %d\n", - (int)mHeader->header.headerSize, (int)mHeader->header.size, (int)size); - return (mError=BAD_TYPE); - } - mSize = mHeader->header.size; - mEntries = (const uint32_t*) - (((const uint8_t*)data)+mHeader->header.headerSize); - - if (mHeader->stringCount > 0) { - if ((mHeader->stringCount*sizeof(uint32_t) < mHeader->stringCount) // uint32 overflow? - || (mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t))) - > size) { - ALOGW("Bad string block: entry of %d items extends past data size %d\n", - (int)(mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t))), - (int)size); - return (mError=BAD_TYPE); - } - - size_t charSize; - if (mHeader->flags&ResStringPool_header::UTF8_FLAG) { - charSize = sizeof(uint8_t); - } else { - charSize = sizeof(char16_t); - } - - mStrings = (const void*) - (((const uint8_t*)data)+mHeader->stringsStart); - if (mHeader->stringsStart >= (mHeader->header.size-sizeof(uint16_t))) { - ALOGW("Bad string block: string pool starts at %d, after total size %d\n", - (int)mHeader->stringsStart, (int)mHeader->header.size); - return (mError=BAD_TYPE); - } - if (mHeader->styleCount == 0) { - mStringPoolSize = - (mHeader->header.size-mHeader->stringsStart)/charSize; - } else { - // check invariant: styles starts before end of data - if (mHeader->stylesStart >= (mHeader->header.size-sizeof(uint16_t))) { - ALOGW("Bad style block: style block starts at %d past data size of %d\n", - (int)mHeader->stylesStart, (int)mHeader->header.size); - return (mError=BAD_TYPE); - } - // check invariant: styles follow the strings - if (mHeader->stylesStart <= mHeader->stringsStart) { - ALOGW("Bad style block: style block starts at %d, before strings at %d\n", - (int)mHeader->stylesStart, (int)mHeader->stringsStart); - return (mError=BAD_TYPE); - } - mStringPoolSize = - (mHeader->stylesStart-mHeader->stringsStart)/charSize; - } - - // check invariant: stringCount > 0 requires a string pool to exist - if (mStringPoolSize == 0) { - ALOGW("Bad string block: stringCount is %d but pool size is 0\n", (int)mHeader->stringCount); - return (mError=BAD_TYPE); - } - - if (notDeviceEndian) { - size_t i; - uint32_t* e = const_cast(mEntries); - for (i=0; istringCount; i++) { - e[i] = dtohl(mEntries[i]); - } - if (!(mHeader->flags&ResStringPool_header::UTF8_FLAG)) { - const char16_t* strings = (const char16_t*)mStrings; - char16_t* s = const_cast(strings); - for (i=0; iflags&ResStringPool_header::UTF8_FLAG && - ((uint8_t*)mStrings)[mStringPoolSize-1] != 0) || - (!mHeader->flags&ResStringPool_header::UTF8_FLAG && - ((char16_t*)mStrings)[mStringPoolSize-1] != 0)) { - ALOGW("Bad string block: last string is not 0-terminated\n"); - return (mError=BAD_TYPE); - } - } else { - mStrings = NULL; - mStringPoolSize = 0; - } - - if (mHeader->styleCount > 0) { - mEntryStyles = mEntries + mHeader->stringCount; - // invariant: integer overflow in calculating mEntryStyles - if (mEntryStyles < mEntries) { - ALOGW("Bad string block: integer overflow finding styles\n"); - return (mError=BAD_TYPE); - } - - if (((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader) > (int)size) { - ALOGW("Bad string block: entry of %d styles extends past data size %d\n", - (int)((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader), - (int)size); - return (mError=BAD_TYPE); - } - mStyles = (const uint32_t*) - (((const uint8_t*)data)+mHeader->stylesStart); - if (mHeader->stylesStart >= mHeader->header.size) { - ALOGW("Bad string block: style pool starts %d, after total size %d\n", - (int)mHeader->stylesStart, (int)mHeader->header.size); - return (mError=BAD_TYPE); - } - mStylePoolSize = - (mHeader->header.size-mHeader->stylesStart)/sizeof(uint32_t); - - if (notDeviceEndian) { - size_t i; - uint32_t* e = const_cast(mEntryStyles); - for (i=0; istyleCount; i++) { - e[i] = dtohl(mEntryStyles[i]); - } - uint32_t* s = const_cast(mStyles); - for (i=0; istringCount; x++) { - if (mCache[x] != NULL) { - free(mCache[x]); - mCache[x] = NULL; - } - } - free(mCache); - mCache = NULL; - } - if (mOwnedData) { - free(mOwnedData); - mOwnedData = NULL; - } -} - -/** - * Strings in UTF-16 format have length indicated by a length encoded in the - * stored data. It is either 1 or 2 characters of length data. This allows a - * maximum length of 0x7FFFFFF (2147483647 bytes), but if you're storing that - * much data in a string, you're abusing them. - * - * If the high bit is set, then there are two characters or 4 bytes of length - * data encoded. In that case, drop the high bit of the first character and - * add it together with the next character. - */ -static inline size_t -decodeLength(const char16_t** str) -{ - size_t len = **str; - if ((len & 0x8000) != 0) { - (*str)++; - len = ((len & 0x7FFF) << 16) | **str; - } - (*str)++; - return len; -} - -/** - * Strings in UTF-8 format have length indicated by a length encoded in the - * stored data. It is either 1 or 2 characters of length data. This allows a - * maximum length of 0x7FFF (32767 bytes), but you should consider storing - * text in another way if you're using that much data in a single string. - * - * If the high bit is set, then there are two characters or 2 bytes of length - * data encoded. In that case, drop the high bit of the first character and - * add it together with the next character. - */ -static inline size_t -decodeLength(const uint8_t** str) -{ - size_t len = **str; - if ((len & 0x80) != 0) { - (*str)++; - len = ((len & 0x7F) << 8) | **str; - } - (*str)++; - return len; -} - -const uint16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const -{ - if (mError == NO_ERROR && idx < mHeader->stringCount) { - const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0; - const uint32_t off = mEntries[idx]/(isUTF8?sizeof(char):sizeof(char16_t)); - if (off < (mStringPoolSize-1)) { - if (!isUTF8) { - const char16_t* strings = (char16_t*)mStrings; - const char16_t* str = strings+off; - - *u16len = decodeLength(&str); - if ((uint32_t)(str+*u16len-strings) < mStringPoolSize) { - return str; - } else { - ALOGW("Bad string block: string #%d extends to %d, past end at %d\n", - (int)idx, (int)(str+*u16len-strings), (int)mStringPoolSize); - } - } else { - const uint8_t* strings = (uint8_t*)mStrings; - const uint8_t* u8str = strings+off; - - *u16len = decodeLength(&u8str); - size_t u8len = decodeLength(&u8str); - - // encLen must be less than 0x7FFF due to encoding. - if ((uint32_t)(u8str+u8len-strings) < mStringPoolSize) { - AutoMutex lock(mDecodeLock); - - if (mCache == NULL) { -#ifndef HAVE_ANDROID_OS - STRING_POOL_NOISY(ALOGI("CREATING STRING CACHE OF %d bytes", - mHeader->stringCount*sizeof(char16_t**))); -#else - // We do not want to be in this case when actually running Android. - ALOGW("CREATING STRING CACHE OF %d bytes", - mHeader->stringCount*sizeof(char16_t**)); -#endif - mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**)); - if (mCache == NULL) { - ALOGW("No memory trying to allocate decode cache table of %d bytes\n", - (int)(mHeader->stringCount*sizeof(char16_t**))); - return NULL; - } - } - - if (mCache[idx] != NULL) { - return mCache[idx]; - } - - ssize_t actualLen = utf8_to_utf16_length(u8str, u8len); - if (actualLen < 0 || (size_t)actualLen != *u16len) { - ALOGW("Bad string block: string #%lld decoded length is not correct " - "%lld vs %llu\n", - (long long)idx, (long long)actualLen, (long long)*u16len); - return NULL; - } - - char16_t *u16str = (char16_t *)calloc(*u16len+1, sizeof(char16_t)); - if (!u16str) { - ALOGW("No memory when trying to allocate decode cache for string #%d\n", - (int)idx); - return NULL; - } - - STRING_POOL_NOISY(ALOGI("Caching UTF8 string: %s", u8str)); - utf8_to_utf16(u8str, u8len, u16str); - mCache[idx] = u16str; - return u16str; - } else { - ALOGW("Bad string block: string #%lld extends to %lld, past end at %lld\n", - (long long)idx, (long long)(u8str+u8len-strings), - (long long)mStringPoolSize); - } - } - } else { - ALOGW("Bad string block: string #%d entry is at %d, past end at %d\n", - (int)idx, (int)(off*sizeof(uint16_t)), - (int)(mStringPoolSize*sizeof(uint16_t))); - } - } - return NULL; -} - -const char* ResStringPool::string8At(size_t idx, size_t* outLen) const -{ - if (mError == NO_ERROR && idx < mHeader->stringCount) { - if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) == 0) { - return NULL; - } - const uint32_t off = mEntries[idx]/sizeof(char); - if (off < (mStringPoolSize-1)) { - const uint8_t* strings = (uint8_t*)mStrings; - const uint8_t* str = strings+off; - *outLen = decodeLength(&str); - size_t encLen = decodeLength(&str); - if ((uint32_t)(str+encLen-strings) < mStringPoolSize) { - return (const char*)str; - } else { - ALOGW("Bad string block: string #%d extends to %d, past end at %d\n", - (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize); - } - } else { - ALOGW("Bad string block: string #%d entry is at %d, past end at %d\n", - (int)idx, (int)(off*sizeof(uint16_t)), - (int)(mStringPoolSize*sizeof(uint16_t))); - } - } - return NULL; -} - -const String8 ResStringPool::string8ObjectAt(size_t idx) const -{ - size_t len; - const char *str = (const char*)string8At(idx, &len); - if (str != NULL) { - return String8(str); - } - return String8(stringAt(idx, &len)); -} - -const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const -{ - return styleAt(ref.index); -} - -const ResStringPool_span* ResStringPool::styleAt(size_t idx) const -{ - if (mError == NO_ERROR && idx < mHeader->styleCount) { - const uint32_t off = (mEntryStyles[idx]/sizeof(uint32_t)); - if (off < mStylePoolSize) { - return (const ResStringPool_span*)(mStyles+off); - } else { - ALOGW("Bad string block: style #%d entry is at %d, past end at %d\n", - (int)idx, (int)(off*sizeof(uint32_t)), - (int)(mStylePoolSize*sizeof(uint32_t))); - } - } - return NULL; -} - -ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const -{ - if (mError != NO_ERROR) { - return mError; - } - - size_t len; - - if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) { - STRING_POOL_NOISY(ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string())); - - // The string pool contains UTF 8 strings; we don't want to cause - // temporary UTF-16 strings to be created as we search. - if (mHeader->flags&ResStringPool_header::SORTED_FLAG) { - // Do a binary search for the string... this is a little tricky, - // because the strings are sorted with strzcmp16(). So to match - // the ordering, we need to convert strings in the pool to UTF-16. - // But we don't want to hit the cache, so instead we will have a - // local temporary allocation for the conversions. - char16_t* convBuffer = (char16_t*)malloc(strLen+4); - ssize_t l = 0; - ssize_t h = mHeader->stringCount-1; - - ssize_t mid; - while (l <= h) { - mid = l + (h - l)/2; - const uint8_t* s = (const uint8_t*)string8At(mid, &len); - int c; - if (s != NULL) { - char16_t* end = utf8_to_utf16_n(s, len, convBuffer, strLen+3); - *end = 0; - c = strzcmp16(convBuffer, end-convBuffer, str, strLen); - } else { - c = -1; - } - STRING_POOL_NOISY(ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n", - (const char*)s, c, (int)l, (int)mid, (int)h)); - if (c == 0) { - STRING_POOL_NOISY(ALOGI("MATCH!")); - free(convBuffer); - return mid; - } else if (c < 0) { - l = mid + 1; - } else { - h = mid - 1; - } - } - free(convBuffer); - } else { - // It is unusual to get the ID from an unsorted string block... - // most often this happens because we want to get IDs for style - // span tags; since those always appear at the end of the string - // block, start searching at the back. - String8 str8(str, strLen); - const size_t str8Len = str8.size(); - for (int i=mHeader->stringCount-1; i>=0; i--) { - const char* s = string8At(i, &len); - STRING_POOL_NOISY(ALOGI("Looking at %s, i=%d\n", - String8(s).string(), - i)); - if (s && str8Len == len && memcmp(s, str8.string(), str8Len) == 0) { - STRING_POOL_NOISY(ALOGI("MATCH!")); - return i; - } - } - } - - } else { - STRING_POOL_NOISY(ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string())); - - if (mHeader->flags&ResStringPool_header::SORTED_FLAG) { - // Do a binary search for the string... - ssize_t l = 0; - ssize_t h = mHeader->stringCount-1; - - ssize_t mid; - while (l <= h) { - mid = l + (h - l)/2; - const char16_t* s = stringAt(mid, &len); - int c = s ? strzcmp16(s, len, str, strLen) : -1; - STRING_POOL_NOISY(ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n", - String8(s).string(), - c, (int)l, (int)mid, (int)h)); - if (c == 0) { - STRING_POOL_NOISY(ALOGI("MATCH!")); - return mid; - } else if (c < 0) { - l = mid + 1; - } else { - h = mid - 1; - } - } - } else { - // It is unusual to get the ID from an unsorted string block... - // most often this happens because we want to get IDs for style - // span tags; since those always appear at the end of the string - // block, start searching at the back. - for (int i=mHeader->stringCount-1; i>=0; i--) { - const char16_t* s = stringAt(i, &len); - STRING_POOL_NOISY(ALOGI("Looking at %s, i=%d\n", - String8(s).string(), - i)); - if (s && strLen == len && strzcmp16(s, len, str, strLen) == 0) { - STRING_POOL_NOISY(ALOGI("MATCH!")); - return i; - } - } - } - } - - return NAME_NOT_FOUND; -} - -size_t ResStringPool::size() const -{ - return (mError == NO_ERROR) ? mHeader->stringCount : 0; -} - -size_t ResStringPool::styleCount() const -{ - return (mError == NO_ERROR) ? mHeader->styleCount : 0; -} - -size_t ResStringPool::bytes() const -{ - return (mError == NO_ERROR) ? mHeader->header.size : 0; -} - -bool ResStringPool::isSorted() const -{ - return (mHeader->flags&ResStringPool_header::SORTED_FLAG)!=0; -} - -bool ResStringPool::isUTF8() const -{ - return (mHeader->flags&ResStringPool_header::UTF8_FLAG)!=0; -} - -// -------------------------------------------------------------------- -// -------------------------------------------------------------------- -// -------------------------------------------------------------------- - -ResXMLParser::ResXMLParser(const ResXMLTree& tree) - : mTree(tree), mEventCode(BAD_DOCUMENT) -{ -} - -void ResXMLParser::restart() -{ - mCurNode = NULL; - mEventCode = mTree.mError == NO_ERROR ? START_DOCUMENT : BAD_DOCUMENT; -} -const ResStringPool& ResXMLParser::getStrings() const -{ - return mTree.mStrings; -} - -ResXMLParser::event_code_t ResXMLParser::getEventType() const -{ - return mEventCode; -} - -ResXMLParser::event_code_t ResXMLParser::next() -{ - if (mEventCode == START_DOCUMENT) { - mCurNode = mTree.mRootNode; - mCurExt = mTree.mRootExt; - return (mEventCode=mTree.mRootCode); - } else if (mEventCode >= FIRST_CHUNK_CODE) { - return nextNode(); - } - return mEventCode; -} - -int32_t ResXMLParser::getCommentID() const -{ - return mCurNode != NULL ? dtohl(mCurNode->comment.index) : -1; -} - -const uint16_t* ResXMLParser::getComment(size_t* outLen) const -{ - int32_t id = getCommentID(); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -uint32_t ResXMLParser::getLineNumber() const -{ - return mCurNode != NULL ? dtohl(mCurNode->lineNumber) : -1; -} - -int32_t ResXMLParser::getTextID() const -{ - if (mEventCode == TEXT) { - return dtohl(((const ResXMLTree_cdataExt*)mCurExt)->data.index); - } - return -1; -} - -const uint16_t* ResXMLParser::getText(size_t* outLen) const -{ - int32_t id = getTextID(); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -ssize_t ResXMLParser::getTextValue(Res_value* outValue) const -{ - if (mEventCode == TEXT) { - outValue->copyFrom_dtoh(((const ResXMLTree_cdataExt*)mCurExt)->typedData); - return sizeof(Res_value); - } - return BAD_TYPE; -} - -int32_t ResXMLParser::getNamespacePrefixID() const -{ - if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) { - return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->prefix.index); - } - return -1; -} - -const uint16_t* ResXMLParser::getNamespacePrefix(size_t* outLen) const -{ - int32_t id = getNamespacePrefixID(); - //printf("prefix=%d event=%p\n", id, mEventCode); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -int32_t ResXMLParser::getNamespaceUriID() const -{ - if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) { - return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->uri.index); - } - return -1; -} - -const uint16_t* ResXMLParser::getNamespaceUri(size_t* outLen) const -{ - int32_t id = getNamespaceUriID(); - //printf("uri=%d event=%p\n", id, mEventCode); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -int32_t ResXMLParser::getElementNamespaceID() const -{ - if (mEventCode == START_TAG) { - return dtohl(((const ResXMLTree_attrExt*)mCurExt)->ns.index); - } - if (mEventCode == END_TAG) { - return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->ns.index); - } - return -1; -} - -const uint16_t* ResXMLParser::getElementNamespace(size_t* outLen) const -{ - int32_t id = getElementNamespaceID(); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -int32_t ResXMLParser::getElementNameID() const -{ - if (mEventCode == START_TAG) { - return dtohl(((const ResXMLTree_attrExt*)mCurExt)->name.index); - } - if (mEventCode == END_TAG) { - return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->name.index); - } - return -1; -} - -const uint16_t* ResXMLParser::getElementName(size_t* outLen) const -{ - int32_t id = getElementNameID(); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -size_t ResXMLParser::getAttributeCount() const -{ - if (mEventCode == START_TAG) { - return dtohs(((const ResXMLTree_attrExt*)mCurExt)->attributeCount); - } - return 0; -} - -int32_t ResXMLParser::getAttributeNamespaceID(size_t idx) const -{ - if (mEventCode == START_TAG) { - const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; - if (idx < dtohs(tag->attributeCount)) { - const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) - (((const uint8_t*)tag) - + dtohs(tag->attributeStart) - + (dtohs(tag->attributeSize)*idx)); - return dtohl(attr->ns.index); - } - } - return -2; -} - -const uint16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen) const -{ - int32_t id = getAttributeNamespaceID(idx); - //printf("attribute namespace=%d idx=%d event=%p\n", id, idx, mEventCode); - //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id)); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -const char* ResXMLParser::getAttributeNamespace8(size_t idx, size_t* outLen) const -{ - int32_t id = getAttributeNamespaceID(idx); - //printf("attribute namespace=%d idx=%d event=%p\n", id, idx, mEventCode); - //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id)); - return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL; -} - -int32_t ResXMLParser::getAttributeNameID(size_t idx) const -{ - if (mEventCode == START_TAG) { - const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; - if (idx < dtohs(tag->attributeCount)) { - const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) - (((const uint8_t*)tag) - + dtohs(tag->attributeStart) - + (dtohs(tag->attributeSize)*idx)); - return dtohl(attr->name.index); - } - } - return -1; -} - -const uint16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const -{ - int32_t id = getAttributeNameID(idx); - //printf("attribute name=%d idx=%d event=%p\n", id, idx, mEventCode); - //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id)); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -const char* ResXMLParser::getAttributeName8(size_t idx, size_t* outLen) const -{ - int32_t id = getAttributeNameID(idx); - //printf("attribute name=%d idx=%d event=%p\n", id, idx, mEventCode); - //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id)); - return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL; -} - -uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const -{ - int32_t id = getAttributeNameID(idx); - if (id >= 0 && (size_t)id < mTree.mNumResIds) { - return dtohl(mTree.mResIds[id]); - } - return 0; -} - -int32_t ResXMLParser::getAttributeValueStringID(size_t idx) const -{ - if (mEventCode == START_TAG) { - const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; - if (idx < dtohs(tag->attributeCount)) { - const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) - (((const uint8_t*)tag) - + dtohs(tag->attributeStart) - + (dtohs(tag->attributeSize)*idx)); - return dtohl(attr->rawValue.index); - } - } - return -1; -} - -const uint16_t* ResXMLParser::getAttributeStringValue(size_t idx, size_t* outLen) const -{ - int32_t id = getAttributeValueStringID(idx); - //XML_NOISY(printf("getAttributeValue 0x%x=0x%x\n", idx, id)); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -int32_t ResXMLParser::getAttributeDataType(size_t idx) const -{ - if (mEventCode == START_TAG) { - const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; - if (idx < dtohs(tag->attributeCount)) { - const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) - (((const uint8_t*)tag) - + dtohs(tag->attributeStart) - + (dtohs(tag->attributeSize)*idx)); - return attr->typedValue.dataType; - } - } - return Res_value::TYPE_NULL; -} - -int32_t ResXMLParser::getAttributeData(size_t idx) const -{ - if (mEventCode == START_TAG) { - const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; - if (idx < dtohs(tag->attributeCount)) { - const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) - (((const uint8_t*)tag) - + dtohs(tag->attributeStart) - + (dtohs(tag->attributeSize)*idx)); - return dtohl(attr->typedValue.data); - } - } - return 0; -} - -ssize_t ResXMLParser::getAttributeValue(size_t idx, Res_value* outValue) const -{ - if (mEventCode == START_TAG) { - const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; - if (idx < dtohs(tag->attributeCount)) { - const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) - (((const uint8_t*)tag) - + dtohs(tag->attributeStart) - + (dtohs(tag->attributeSize)*idx)); - outValue->copyFrom_dtoh(attr->typedValue); - return sizeof(Res_value); - } - } - return BAD_TYPE; -} - -ssize_t ResXMLParser::indexOfAttribute(const char* ns, const char* attr) const -{ - String16 nsStr(ns != NULL ? ns : ""); - String16 attrStr(attr); - return indexOfAttribute(ns ? nsStr.string() : NULL, ns ? nsStr.size() : 0, - attrStr.string(), attrStr.size()); -} - -ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen, - const char16_t* attr, size_t attrLen) const -{ - if (mEventCode == START_TAG) { - if (attr == NULL) { - return NAME_NOT_FOUND; - } - const size_t N = getAttributeCount(); - if (mTree.mStrings.isUTF8()) { - String8 ns8, attr8; - if (ns != NULL) { - ns8 = String8(ns, nsLen); - } - attr8 = String8(attr, attrLen); - STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF8 %s (%d) / %s (%d)", ns8.string(), nsLen, - attr8.string(), attrLen)); - for (size_t i=0; i ns=%s, curNs=%s\n", - // String8(ns).string(), String8(curNs).string()); - if (memcmp(ns8.string(), curNs, nsLen) == 0) { - STRING_POOL_NOISY(ALOGI(" FOUND!")); - return i; - } - } - } - } - } else { - STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF16 %s (%d) / %s (%d)", - String8(ns, nsLen).string(), nsLen, - String8(attr, attrLen).string(), attrLen)); - for (size_t i=0; i ns=%s, curNs=%s\n", - // String8(ns).string(), String8(curNs).string()); - if (memcmp(ns, curNs, nsLen*sizeof(char16_t)) == 0) { - STRING_POOL_NOISY(ALOGI(" FOUND!")); - return i; - } - } - } - } - } - } - - return NAME_NOT_FOUND; -} - -ssize_t ResXMLParser::indexOfID() const -{ - if (mEventCode == START_TAG) { - const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->idIndex); - if (idx > 0) return (idx-1); - } - return NAME_NOT_FOUND; -} - -ssize_t ResXMLParser::indexOfClass() const -{ - if (mEventCode == START_TAG) { - const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->classIndex); - if (idx > 0) return (idx-1); - } - return NAME_NOT_FOUND; -} - -ssize_t ResXMLParser::indexOfStyle() const -{ - if (mEventCode == START_TAG) { - const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->styleIndex); - if (idx > 0) return (idx-1); - } - return NAME_NOT_FOUND; -} - -ResXMLParser::event_code_t ResXMLParser::nextNode() -{ - if (mEventCode < 0) { - return mEventCode; - } - - do { - const ResXMLTree_node* next = (const ResXMLTree_node*) - (((const uint8_t*)mCurNode) + dtohl(mCurNode->header.size)); - //ALOGW("Next node: prev=%p, next=%p\n", mCurNode, next); - - if (((const uint8_t*)next) >= mTree.mDataEnd) { - mCurNode = NULL; - return (mEventCode=END_DOCUMENT); - } - - if (mTree.validateNode(next) != NO_ERROR) { - mCurNode = NULL; - return (mEventCode=BAD_DOCUMENT); - } - - mCurNode = next; - const uint16_t headerSize = dtohs(next->header.headerSize); - const uint32_t totalSize = dtohl(next->header.size); - mCurExt = ((const uint8_t*)next) + headerSize; - size_t minExtSize = 0; - event_code_t eventCode = (event_code_t)dtohs(next->header.type); - switch ((mEventCode=eventCode)) { - case RES_XML_START_NAMESPACE_TYPE: - case RES_XML_END_NAMESPACE_TYPE: - minExtSize = sizeof(ResXMLTree_namespaceExt); - break; - case RES_XML_START_ELEMENT_TYPE: - minExtSize = sizeof(ResXMLTree_attrExt); - break; - case RES_XML_END_ELEMENT_TYPE: - minExtSize = sizeof(ResXMLTree_endElementExt); - break; - case RES_XML_CDATA_TYPE: - minExtSize = sizeof(ResXMLTree_cdataExt); - break; - default: - ALOGW("Unknown XML block: header type %d in node at %d\n", - (int)dtohs(next->header.type), - (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader))); - continue; - } - - if ((totalSize-headerSize) < minExtSize) { - ALOGW("Bad XML block: header type 0x%x in node at 0x%x has size %d, need %d\n", - (int)dtohs(next->header.type), - (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)), - (int)(totalSize-headerSize), (int)minExtSize); - return (mEventCode=BAD_DOCUMENT); - } - - //printf("CurNode=%p, CurExt=%p, headerSize=%d, minExtSize=%d\n", - // mCurNode, mCurExt, headerSize, minExtSize); - - return eventCode; - } while (true); -} - -void ResXMLParser::getPosition(ResXMLParser::ResXMLPosition* pos) const -{ - pos->eventCode = mEventCode; - pos->curNode = mCurNode; - pos->curExt = mCurExt; -} - -void ResXMLParser::setPosition(const ResXMLParser::ResXMLPosition& pos) -{ - mEventCode = pos.eventCode; - mCurNode = pos.curNode; - mCurExt = pos.curExt; -} - - -// -------------------------------------------------------------------- - -static volatile int32_t gCount = 0; - -ResXMLTree::ResXMLTree() - : ResXMLParser(*this) - , mError(NO_INIT), mOwnedData(NULL) -{ - //ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1); - restart(); -} - -ResXMLTree::ResXMLTree(const void* data, size_t size, bool copyData) - : ResXMLParser(*this) - , mError(NO_INIT), mOwnedData(NULL) -{ - //ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1); - setTo(data, size, copyData); -} - -ResXMLTree::~ResXMLTree() -{ - //ALOGI("Destroying ResXMLTree in %p #%d\n", this, android_atomic_dec(&gCount)-1); - uninit(); -} - -status_t ResXMLTree::setTo(const void* data, size_t size, bool copyData) -{ - uninit(); - mEventCode = START_DOCUMENT; - - if (!data || !size) { - return (mError=BAD_TYPE); - } - - if (copyData) { - mOwnedData = malloc(size); - if (mOwnedData == NULL) { - return (mError=NO_MEMORY); - } - memcpy(mOwnedData, data, size); - data = mOwnedData; - } - - mHeader = (const ResXMLTree_header*)data; - mSize = dtohl(mHeader->header.size); - if (dtohs(mHeader->header.headerSize) > mSize || mSize > size) { - ALOGW("Bad XML block: header size %d or total size %d is larger than data size %d\n", - (int)dtohs(mHeader->header.headerSize), - (int)dtohl(mHeader->header.size), (int)size); - mError = BAD_TYPE; - restart(); - return mError; - } - mDataEnd = ((const uint8_t*)mHeader) + mSize; - - mStrings.uninit(); - mRootNode = NULL; - mResIds = NULL; - mNumResIds = 0; - - // First look for a couple interesting chunks: the string block - // and first XML node. - const ResChunk_header* chunk = - (const ResChunk_header*)(((const uint8_t*)mHeader) + dtohs(mHeader->header.headerSize)); - const ResChunk_header* lastChunk = chunk; - while (((const uint8_t*)chunk) < (mDataEnd-sizeof(ResChunk_header)) && - ((const uint8_t*)chunk) < (mDataEnd-dtohl(chunk->size))) { - status_t err = validate_chunk(chunk, sizeof(ResChunk_header), mDataEnd, "XML"); - if (err != NO_ERROR) { - mError = err; - goto done; - } - const uint16_t type = dtohs(chunk->type); - const size_t size = dtohl(chunk->size); - XML_NOISY(printf("Scanning @ %p: type=0x%x, size=0x%x\n", - (void*)(((uint32_t)chunk)-((uint32_t)mHeader)), type, size)); - if (type == RES_STRING_POOL_TYPE) { - mStrings.setTo(chunk, size); - } else if (type == RES_XML_RESOURCE_MAP_TYPE) { - mResIds = (const uint32_t*) - (((const uint8_t*)chunk)+dtohs(chunk->headerSize)); - mNumResIds = (dtohl(chunk->size)-dtohs(chunk->headerSize))/sizeof(uint32_t); - } else if (type >= RES_XML_FIRST_CHUNK_TYPE - && type <= RES_XML_LAST_CHUNK_TYPE) { - if (validateNode((const ResXMLTree_node*)chunk) != NO_ERROR) { - mError = BAD_TYPE; - goto done; - } - mCurNode = (const ResXMLTree_node*)lastChunk; - if (nextNode() == BAD_DOCUMENT) { - mError = BAD_TYPE; - goto done; - } - mRootNode = mCurNode; - mRootExt = mCurExt; - mRootCode = mEventCode; - break; - } else { - XML_NOISY(printf("Skipping unknown chunk!\n")); - } - lastChunk = chunk; - chunk = (const ResChunk_header*) - (((const uint8_t*)chunk) + size); - } - - if (mRootNode == NULL) { - ALOGW("Bad XML block: no root element node found\n"); - mError = BAD_TYPE; - goto done; - } - - mError = mStrings.getError(); - -done: - restart(); - return mError; -} - -status_t ResXMLTree::getError() const -{ - return mError; -} - -void ResXMLTree::uninit() -{ - mError = NO_INIT; - mStrings.uninit(); - if (mOwnedData) { - free(mOwnedData); - mOwnedData = NULL; - } - restart(); -} - -status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const -{ - const uint16_t eventCode = dtohs(node->header.type); - - status_t err = validate_chunk( - &node->header, sizeof(ResXMLTree_node), - mDataEnd, "ResXMLTree_node"); - - if (err >= NO_ERROR) { - // Only perform additional validation on START nodes - if (eventCode != RES_XML_START_ELEMENT_TYPE) { - return NO_ERROR; - } - - const uint16_t headerSize = dtohs(node->header.headerSize); - const uint32_t size = dtohl(node->header.size); - const ResXMLTree_attrExt* attrExt = (const ResXMLTree_attrExt*) - (((const uint8_t*)node) + headerSize); - // check for sensical values pulled out of the stream so far... - if ((size >= headerSize + sizeof(ResXMLTree_attrExt)) - && ((void*)attrExt > (void*)node)) { - const size_t attrSize = ((size_t)dtohs(attrExt->attributeSize)) - * dtohs(attrExt->attributeCount); - if ((dtohs(attrExt->attributeStart)+attrSize) <= (size-headerSize)) { - return NO_ERROR; - } - ALOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n", - (unsigned int)(dtohs(attrExt->attributeStart)+attrSize), - (unsigned int)(size-headerSize)); - } - else { - ALOGW("Bad XML start block: node header size 0x%x, size 0x%x\n", - (unsigned int)headerSize, (unsigned int)size); - } - return BAD_TYPE; - } - - return err; - -#if 0 - const bool isStart = dtohs(node->header.type) == RES_XML_START_ELEMENT_TYPE; - - const uint16_t headerSize = dtohs(node->header.headerSize); - const uint32_t size = dtohl(node->header.size); - - if (headerSize >= (isStart ? sizeof(ResXMLTree_attrNode) : sizeof(ResXMLTree_node))) { - if (size >= headerSize) { - if (((const uint8_t*)node) <= (mDataEnd-size)) { - if (!isStart) { - return NO_ERROR; - } - if ((((size_t)dtohs(node->attributeSize))*dtohs(node->attributeCount)) - <= (size-headerSize)) { - return NO_ERROR; - } - ALOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n", - ((int)dtohs(node->attributeSize))*dtohs(node->attributeCount), - (int)(size-headerSize)); - return BAD_TYPE; - } - ALOGW("Bad XML block: node at 0x%x extends beyond data end 0x%x\n", - (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)), (int)mSize); - return BAD_TYPE; - } - ALOGW("Bad XML block: node at 0x%x header size 0x%x smaller than total size 0x%x\n", - (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)), - (int)headerSize, (int)size); - return BAD_TYPE; - } - ALOGW("Bad XML block: node at 0x%x header size 0x%x too small\n", - (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)), - (int)headerSize); - return BAD_TYPE; -#endif -} - -// -------------------------------------------------------------------- -// -------------------------------------------------------------------- -// -------------------------------------------------------------------- - -void ResTable_config::copyFromDeviceNoSwap(const ResTable_config& o) { - const size_t size = dtohl(o.size); - if (size >= sizeof(ResTable_config)) { - *this = o; - } else { - memcpy(this, &o, size); - memset(((uint8_t*)this)+size, 0, sizeof(ResTable_config)-size); - } -} - -void ResTable_config::copyFromDtoH(const ResTable_config& o) { - copyFromDeviceNoSwap(o); - size = sizeof(ResTable_config); - mcc = dtohs(mcc); - mnc = dtohs(mnc); - density = dtohs(density); - screenWidth = dtohs(screenWidth); - screenHeight = dtohs(screenHeight); - sdkVersion = dtohs(sdkVersion); - minorVersion = dtohs(minorVersion); - smallestScreenWidthDp = dtohs(smallestScreenWidthDp); - screenWidthDp = dtohs(screenWidthDp); - screenHeightDp = dtohs(screenHeightDp); -} - -void ResTable_config::swapHtoD() { - size = htodl(size); - mcc = htods(mcc); - mnc = htods(mnc); - density = htods(density); - screenWidth = htods(screenWidth); - screenHeight = htods(screenHeight); - sdkVersion = htods(sdkVersion); - minorVersion = htods(minorVersion); - smallestScreenWidthDp = htods(smallestScreenWidthDp); - screenWidthDp = htods(screenWidthDp); - screenHeightDp = htods(screenHeightDp); -} - -int ResTable_config::compare(const ResTable_config& o) const { - int32_t diff = (int32_t)(imsi - o.imsi); - if (diff != 0) return diff; - diff = (int32_t)(locale - o.locale); - if (diff != 0) return diff; - diff = (int32_t)(screenType - o.screenType); - if (diff != 0) return diff; - diff = (int32_t)(input - o.input); - if (diff != 0) return diff; - diff = (int32_t)(screenSize - o.screenSize); - if (diff != 0) return diff; - diff = (int32_t)(version - o.version); - if (diff != 0) return diff; - diff = (int32_t)(screenLayout - o.screenLayout); - if (diff != 0) return diff; - diff = (int32_t)(uiMode - o.uiMode); - if (diff != 0) return diff; - diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp); - if (diff != 0) return diff; - diff = (int32_t)(screenSizeDp - o.screenSizeDp); - return (int)diff; -} - -int ResTable_config::compareLogical(const ResTable_config& o) const { - if (mcc != o.mcc) { - return mcc < o.mcc ? -1 : 1; - } - if (mnc != o.mnc) { - return mnc < o.mnc ? -1 : 1; - } - if (language[0] != o.language[0]) { - return language[0] < o.language[0] ? -1 : 1; - } - if (language[1] != o.language[1]) { - return language[1] < o.language[1] ? -1 : 1; - } - if (country[0] != o.country[0]) { - return country[0] < o.country[0] ? -1 : 1; - } - if (country[1] != o.country[1]) { - return country[1] < o.country[1] ? -1 : 1; - } - if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) { - return (screenLayout & MASK_LAYOUTDIR) < (o.screenLayout & MASK_LAYOUTDIR) ? -1 : 1; - } - if (smallestScreenWidthDp != o.smallestScreenWidthDp) { - return smallestScreenWidthDp < o.smallestScreenWidthDp ? -1 : 1; - } - if (screenWidthDp != o.screenWidthDp) { - return screenWidthDp < o.screenWidthDp ? -1 : 1; - } - if (screenHeightDp != o.screenHeightDp) { - return screenHeightDp < o.screenHeightDp ? -1 : 1; - } - if (screenWidth != o.screenWidth) { - return screenWidth < o.screenWidth ? -1 : 1; - } - if (screenHeight != o.screenHeight) { - return screenHeight < o.screenHeight ? -1 : 1; - } - if (density != o.density) { - return density < o.density ? -1 : 1; - } - if (orientation != o.orientation) { - return orientation < o.orientation ? -1 : 1; - } - if (touchscreen != o.touchscreen) { - return touchscreen < o.touchscreen ? -1 : 1; - } - if (input != o.input) { - return input < o.input ? -1 : 1; - } - if (screenLayout != o.screenLayout) { - return screenLayout < o.screenLayout ? -1 : 1; - } - if (uiMode != o.uiMode) { - return uiMode < o.uiMode ? -1 : 1; - } - if (version != o.version) { - return version < o.version ? -1 : 1; - } - return 0; -} - -int ResTable_config::diff(const ResTable_config& o) const { - int diffs = 0; - if (mcc != o.mcc) diffs |= CONFIG_MCC; - if (mnc != o.mnc) diffs |= CONFIG_MNC; - if (locale != o.locale) diffs |= CONFIG_LOCALE; - if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION; - if (density != o.density) diffs |= CONFIG_DENSITY; - if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN; - if (((inputFlags^o.inputFlags)&(MASK_KEYSHIDDEN|MASK_NAVHIDDEN)) != 0) - diffs |= CONFIG_KEYBOARD_HIDDEN; - if (keyboard != o.keyboard) diffs |= CONFIG_KEYBOARD; - if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION; - if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE; - if (version != o.version) diffs |= CONFIG_VERSION; - if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) diffs |= CONFIG_LAYOUTDIR; - if ((screenLayout & ~MASK_LAYOUTDIR) != (o.screenLayout & ~MASK_LAYOUTDIR)) diffs |= CONFIG_SCREEN_LAYOUT; - if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE; - if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE; - if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE; - return diffs; -} - -bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const { - // The order of the following tests defines the importance of one - // configuration parameter over another. Those tests first are more - // important, trumping any values in those following them. - if (imsi || o.imsi) { - if (mcc != o.mcc) { - if (!mcc) return false; - if (!o.mcc) return true; - } - - if (mnc != o.mnc) { - if (!mnc) return false; - if (!o.mnc) return true; - } - } - - if (locale || o.locale) { - if (language[0] != o.language[0]) { - if (!language[0]) return false; - if (!o.language[0]) return true; - } - - if (country[0] != o.country[0]) { - if (!country[0]) return false; - if (!o.country[0]) return true; - } - } - - if (screenLayout || o.screenLayout) { - if (((screenLayout^o.screenLayout) & MASK_LAYOUTDIR) != 0) { - if (!(screenLayout & MASK_LAYOUTDIR)) return false; - if (!(o.screenLayout & MASK_LAYOUTDIR)) return true; - } - } - - if (smallestScreenWidthDp || o.smallestScreenWidthDp) { - if (smallestScreenWidthDp != o.smallestScreenWidthDp) { - if (!smallestScreenWidthDp) return false; - if (!o.smallestScreenWidthDp) return true; - } - } - - if (screenSizeDp || o.screenSizeDp) { - if (screenWidthDp != o.screenWidthDp) { - if (!screenWidthDp) return false; - if (!o.screenWidthDp) return true; - } - - if (screenHeightDp != o.screenHeightDp) { - if (!screenHeightDp) return false; - if (!o.screenHeightDp) return true; - } - } - - if (screenLayout || o.screenLayout) { - if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0) { - if (!(screenLayout & MASK_SCREENSIZE)) return false; - if (!(o.screenLayout & MASK_SCREENSIZE)) return true; - } - if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0) { - if (!(screenLayout & MASK_SCREENLONG)) return false; - if (!(o.screenLayout & MASK_SCREENLONG)) return true; - } - } - - if (orientation != o.orientation) { - if (!orientation) return false; - if (!o.orientation) return true; - } - - if (uiMode || o.uiMode) { - if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0) { - if (!(uiMode & MASK_UI_MODE_TYPE)) return false; - if (!(o.uiMode & MASK_UI_MODE_TYPE)) return true; - } - if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0) { - if (!(uiMode & MASK_UI_MODE_NIGHT)) return false; - if (!(o.uiMode & MASK_UI_MODE_NIGHT)) return true; - } - } - - // density is never 'more specific' - // as the default just equals 160 - - if (touchscreen != o.touchscreen) { - if (!touchscreen) return false; - if (!o.touchscreen) return true; - } - - if (input || o.input) { - if (((inputFlags^o.inputFlags) & MASK_KEYSHIDDEN) != 0) { - if (!(inputFlags & MASK_KEYSHIDDEN)) return false; - if (!(o.inputFlags & MASK_KEYSHIDDEN)) return true; - } - - if (((inputFlags^o.inputFlags) & MASK_NAVHIDDEN) != 0) { - if (!(inputFlags & MASK_NAVHIDDEN)) return false; - if (!(o.inputFlags & MASK_NAVHIDDEN)) return true; - } - - if (keyboard != o.keyboard) { - if (!keyboard) return false; - if (!o.keyboard) return true; - } - - if (navigation != o.navigation) { - if (!navigation) return false; - if (!o.navigation) return true; - } - } - - if (screenSize || o.screenSize) { - if (screenWidth != o.screenWidth) { - if (!screenWidth) return false; - if (!o.screenWidth) return true; - } - - if (screenHeight != o.screenHeight) { - if (!screenHeight) return false; - if (!o.screenHeight) return true; - } - } - - if (version || o.version) { - if (sdkVersion != o.sdkVersion) { - if (!sdkVersion) return false; - if (!o.sdkVersion) return true; - } - - if (minorVersion != o.minorVersion) { - if (!minorVersion) return false; - if (!o.minorVersion) return true; - } - } - return false; -} - -bool ResTable_config::isBetterThan(const ResTable_config& o, - const ResTable_config* requested) const { - if (requested) { - if (imsi || o.imsi) { - if ((mcc != o.mcc) && requested->mcc) { - return (mcc); - } - - if ((mnc != o.mnc) && requested->mnc) { - return (mnc); - } - } - - if (locale || o.locale) { - if ((language[0] != o.language[0]) && requested->language[0]) { - return (language[0]); - } - - if ((country[0] != o.country[0]) && requested->country[0]) { - return (country[0]); - } - } - - if (screenLayout || o.screenLayout) { - if (((screenLayout^o.screenLayout) & MASK_LAYOUTDIR) != 0 - && (requested->screenLayout & MASK_LAYOUTDIR)) { - int myLayoutDir = screenLayout & MASK_LAYOUTDIR; - int oLayoutDir = o.screenLayout & MASK_LAYOUTDIR; - return (myLayoutDir > oLayoutDir); - } - } - - if (smallestScreenWidthDp || o.smallestScreenWidthDp) { - // The configuration closest to the actual size is best. - // We assume that larger configs have already been filtered - // out at this point. That means we just want the largest one. - if (smallestScreenWidthDp != o.smallestScreenWidthDp) { - return smallestScreenWidthDp > o.smallestScreenWidthDp; - } - } - - if (screenSizeDp || o.screenSizeDp) { - // "Better" is based on the sum of the difference between both - // width and height from the requested dimensions. We are - // assuming the invalid configs (with smaller dimens) have - // already been filtered. Note that if a particular dimension - // is unspecified, we will end up with a large value (the - // difference between 0 and the requested dimension), which is - // good since we will prefer a config that has specified a - // dimension value. - int myDelta = 0, otherDelta = 0; - if (requested->screenWidthDp) { - myDelta += requested->screenWidthDp - screenWidthDp; - otherDelta += requested->screenWidthDp - o.screenWidthDp; - } - if (requested->screenHeightDp) { - myDelta += requested->screenHeightDp - screenHeightDp; - otherDelta += requested->screenHeightDp - o.screenHeightDp; - } - //ALOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d", - // screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp, - // requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta); - if (myDelta != otherDelta) { - return myDelta < otherDelta; - } - } - - if (screenLayout || o.screenLayout) { - if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0 - && (requested->screenLayout & MASK_SCREENSIZE)) { - // A little backwards compatibility here: undefined is - // considered equivalent to normal. But only if the - // requested size is at least normal; otherwise, small - // is better than the default. - int mySL = (screenLayout & MASK_SCREENSIZE); - int oSL = (o.screenLayout & MASK_SCREENSIZE); - int fixedMySL = mySL; - int fixedOSL = oSL; - if ((requested->screenLayout & MASK_SCREENSIZE) >= SCREENSIZE_NORMAL) { - if (fixedMySL == 0) fixedMySL = SCREENSIZE_NORMAL; - if (fixedOSL == 0) fixedOSL = SCREENSIZE_NORMAL; - } - // For screen size, the best match is the one that is - // closest to the requested screen size, but not over - // (the not over part is dealt with in match() below). - if (fixedMySL == fixedOSL) { - // If the two are the same, but 'this' is actually - // undefined, then the other is really a better match. - if (mySL == 0) return false; - return true; - } - if (fixedMySL != fixedOSL) { - return fixedMySL > fixedOSL; - } - } - if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0 - && (requested->screenLayout & MASK_SCREENLONG)) { - return (screenLayout & MASK_SCREENLONG); - } - } - - if ((orientation != o.orientation) && requested->orientation) { - return (orientation); - } - - if (uiMode || o.uiMode) { - if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0 - && (requested->uiMode & MASK_UI_MODE_TYPE)) { - return (uiMode & MASK_UI_MODE_TYPE); - } - if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0 - && (requested->uiMode & MASK_UI_MODE_NIGHT)) { - return (uiMode & MASK_UI_MODE_NIGHT); - } - } - - if (screenType || o.screenType) { - if (density != o.density) { - // density is tough. Any density is potentially useful - // because the system will scale it. Scaling down - // is generally better than scaling up. - // Default density counts as 160dpi (the system default) - // TODO - remove 160 constants - int h = (density?density:160); - int l = (o.density?o.density:160); - bool bImBigger = true; - if (l > h) { - int t = h; - h = l; - l = t; - bImBigger = false; - } - - int reqValue = (requested->density?requested->density:160); - if (reqValue >= h) { - // requested value higher than both l and h, give h - return bImBigger; - } - if (l >= reqValue) { - // requested value lower than both l and h, give l - return !bImBigger; - } - // saying that scaling down is 2x better than up - if (((2 * l) - reqValue) * h > reqValue * reqValue) { - return !bImBigger; - } else { - return bImBigger; - } - } - - if ((touchscreen != o.touchscreen) && requested->touchscreen) { - return (touchscreen); - } - } - - if (input || o.input) { - const int keysHidden = inputFlags & MASK_KEYSHIDDEN; - const int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN; - if (keysHidden != oKeysHidden) { - const int reqKeysHidden = - requested->inputFlags & MASK_KEYSHIDDEN; - if (reqKeysHidden) { - - if (!keysHidden) return false; - if (!oKeysHidden) return true; - // For compatibility, we count KEYSHIDDEN_NO as being - // the same as KEYSHIDDEN_SOFT. Here we disambiguate - // these by making an exact match more specific. - if (reqKeysHidden == keysHidden) return true; - if (reqKeysHidden == oKeysHidden) return false; - } - } - - const int navHidden = inputFlags & MASK_NAVHIDDEN; - const int oNavHidden = o.inputFlags & MASK_NAVHIDDEN; - if (navHidden != oNavHidden) { - const int reqNavHidden = - requested->inputFlags & MASK_NAVHIDDEN; - if (reqNavHidden) { - - if (!navHidden) return false; - if (!oNavHidden) return true; - } - } - - if ((keyboard != o.keyboard) && requested->keyboard) { - return (keyboard); - } - - if ((navigation != o.navigation) && requested->navigation) { - return (navigation); - } - } - - if (screenSize || o.screenSize) { - // "Better" is based on the sum of the difference between both - // width and height from the requested dimensions. We are - // assuming the invalid configs (with smaller sizes) have - // already been filtered. Note that if a particular dimension - // is unspecified, we will end up with a large value (the - // difference between 0 and the requested dimension), which is - // good since we will prefer a config that has specified a - // size value. - int myDelta = 0, otherDelta = 0; - if (requested->screenWidth) { - myDelta += requested->screenWidth - screenWidth; - otherDelta += requested->screenWidth - o.screenWidth; - } - if (requested->screenHeight) { - myDelta += requested->screenHeight - screenHeight; - otherDelta += requested->screenHeight - o.screenHeight; - } - if (myDelta != otherDelta) { - return myDelta < otherDelta; - } - } - - if (version || o.version) { - if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) { - return (sdkVersion > o.sdkVersion); - } - - if ((minorVersion != o.minorVersion) && - requested->minorVersion) { - return (minorVersion); - } - } - - return false; - } - return isMoreSpecificThan(o); -} - -bool ResTable_config::match(const ResTable_config& settings) const { - if (imsi != 0) { - if (mcc != 0 && mcc != settings.mcc) { - return false; - } - if (mnc != 0 && mnc != settings.mnc) { - return false; - } - } - if (locale != 0) { - if (language[0] != 0 - && (language[0] != settings.language[0] - || language[1] != settings.language[1])) { - return false; - } - if (country[0] != 0 - && (country[0] != settings.country[0] - || country[1] != settings.country[1])) { - return false; - } - } - if (screenConfig != 0) { - const int layoutDir = screenLayout&MASK_LAYOUTDIR; - const int setLayoutDir = settings.screenLayout&MASK_LAYOUTDIR; - if (layoutDir != 0 && layoutDir != setLayoutDir) { - return false; - } - - const int screenSize = screenLayout&MASK_SCREENSIZE; - const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE; - // Any screen sizes for larger screens than the setting do not - // match. - if (screenSize != 0 && screenSize > setScreenSize) { - return false; - } - - const int screenLong = screenLayout&MASK_SCREENLONG; - const int setScreenLong = settings.screenLayout&MASK_SCREENLONG; - if (screenLong != 0 && screenLong != setScreenLong) { - return false; - } - - const int uiModeType = uiMode&MASK_UI_MODE_TYPE; - const int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE; - if (uiModeType != 0 && uiModeType != setUiModeType) { - return false; - } - - const int uiModeNight = uiMode&MASK_UI_MODE_NIGHT; - const int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT; - if (uiModeNight != 0 && uiModeNight != setUiModeNight) { - return false; - } - - if (smallestScreenWidthDp != 0 - && smallestScreenWidthDp > settings.smallestScreenWidthDp) { - return false; - } - } - if (screenSizeDp != 0) { - if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) { - //ALOGI("Filtering out width %d in requested %d", screenWidthDp, settings.screenWidthDp); - return false; - } - if (screenHeightDp != 0 && screenHeightDp > settings.screenHeightDp) { - //ALOGI("Filtering out height %d in requested %d", screenHeightDp, settings.screenHeightDp); - return false; - } - } - if (screenType != 0) { - if (orientation != 0 && orientation != settings.orientation) { - return false; - } - // density always matches - we can scale it. See isBetterThan - if (touchscreen != 0 && touchscreen != settings.touchscreen) { - return false; - } - } - if (input != 0) { - const int keysHidden = inputFlags&MASK_KEYSHIDDEN; - const int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN; - if (keysHidden != 0 && keysHidden != setKeysHidden) { - // For compatibility, we count a request for KEYSHIDDEN_NO as also - // matching the more recent KEYSHIDDEN_SOFT. Basically - // KEYSHIDDEN_NO means there is some kind of keyboard available. - //ALOGI("Matching keysHidden: have=%d, config=%d\n", keysHidden, setKeysHidden); - if (keysHidden != KEYSHIDDEN_NO || setKeysHidden != KEYSHIDDEN_SOFT) { - //ALOGI("No match!"); - return false; - } - } - const int navHidden = inputFlags&MASK_NAVHIDDEN; - const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN; - if (navHidden != 0 && navHidden != setNavHidden) { - return false; - } - if (keyboard != 0 && keyboard != settings.keyboard) { - return false; - } - if (navigation != 0 && navigation != settings.navigation) { - return false; - } - } - if (screenSize != 0) { - if (screenWidth != 0 && screenWidth > settings.screenWidth) { - return false; - } - if (screenHeight != 0 && screenHeight > settings.screenHeight) { - return false; - } - } - if (version != 0) { - if (sdkVersion != 0 && sdkVersion > settings.sdkVersion) { - return false; - } - if (minorVersion != 0 && minorVersion != settings.minorVersion) { - return false; - } - } - return true; -} - -void ResTable_config::getLocale(char str[6]) const { - memset(str, 0, 6); - if (language[0]) { - str[0] = language[0]; - str[1] = language[1]; - if (country[0]) { - str[2] = '_'; - str[3] = country[0]; - str[4] = country[1]; - } - } -} - -String8 ResTable_config::toString() const { - String8 res; - - if (mcc != 0) { - if (res.size() > 0) res.append("-"); - res.appendFormat("%dmcc", dtohs(mcc)); - } - if (mnc != 0) { - if (res.size() > 0) res.append("-"); - res.appendFormat("%dmnc", dtohs(mnc)); - } - if (language[0] != 0) { - if (res.size() > 0) res.append("-"); - res.append(language, 2); - } - if (country[0] != 0) { - if (res.size() > 0) res.append("-"); - res.append(country, 2); - } - if ((screenLayout&MASK_LAYOUTDIR) != 0) { - if (res.size() > 0) res.append("-"); - switch (screenLayout&ResTable_config::MASK_LAYOUTDIR) { - case ResTable_config::LAYOUTDIR_LTR: - res.append("ldltr"); - break; - case ResTable_config::LAYOUTDIR_RTL: - res.append("ldrtl"); - break; - default: - res.appendFormat("layoutDir=%d", - dtohs(screenLayout&ResTable_config::MASK_LAYOUTDIR)); - break; - } - } - if (smallestScreenWidthDp != 0) { - if (res.size() > 0) res.append("-"); - res.appendFormat("sw%ddp", dtohs(smallestScreenWidthDp)); - } - if (screenWidthDp != 0) { - if (res.size() > 0) res.append("-"); - res.appendFormat("w%ddp", dtohs(screenWidthDp)); - } - if (screenHeightDp != 0) { - if (res.size() > 0) res.append("-"); - res.appendFormat("h%ddp", dtohs(screenHeightDp)); - } - if ((screenLayout&MASK_SCREENSIZE) != SCREENSIZE_ANY) { - if (res.size() > 0) res.append("-"); - switch (screenLayout&ResTable_config::MASK_SCREENSIZE) { - case ResTable_config::SCREENSIZE_SMALL: - res.append("small"); - break; - case ResTable_config::SCREENSIZE_NORMAL: - res.append("normal"); - break; - case ResTable_config::SCREENSIZE_LARGE: - res.append("large"); - break; - case ResTable_config::SCREENSIZE_XLARGE: - res.append("xlarge"); - break; - default: - res.appendFormat("screenLayoutSize=%d", - dtohs(screenLayout&ResTable_config::MASK_SCREENSIZE)); - break; - } - } - if ((screenLayout&MASK_SCREENLONG) != 0) { - if (res.size() > 0) res.append("-"); - switch (screenLayout&ResTable_config::MASK_SCREENLONG) { - case ResTable_config::SCREENLONG_NO: - res.append("notlong"); - break; - case ResTable_config::SCREENLONG_YES: - res.append("long"); - break; - default: - res.appendFormat("screenLayoutLong=%d", - dtohs(screenLayout&ResTable_config::MASK_SCREENLONG)); - break; - } - } - if (orientation != ORIENTATION_ANY) { - if (res.size() > 0) res.append("-"); - switch (orientation) { - case ResTable_config::ORIENTATION_PORT: - res.append("port"); - break; - case ResTable_config::ORIENTATION_LAND: - res.append("land"); - break; - case ResTable_config::ORIENTATION_SQUARE: - res.append("square"); - break; - default: - res.appendFormat("orientation=%d", dtohs(orientation)); - break; - } - } - if ((uiMode&MASK_UI_MODE_TYPE) != UI_MODE_TYPE_ANY) { - if (res.size() > 0) res.append("-"); - switch (uiMode&ResTable_config::MASK_UI_MODE_TYPE) { - case ResTable_config::UI_MODE_TYPE_DESK: - res.append("desk"); - break; - case ResTable_config::UI_MODE_TYPE_CAR: - res.append("car"); - break; - case ResTable_config::UI_MODE_TYPE_TELEVISION: - res.append("television"); - break; - case ResTable_config::UI_MODE_TYPE_APPLIANCE: - res.append("appliance"); - break; - default: - res.appendFormat("uiModeType=%d", - dtohs(screenLayout&ResTable_config::MASK_UI_MODE_TYPE)); - break; - } - } - if ((uiMode&MASK_UI_MODE_NIGHT) != 0) { - if (res.size() > 0) res.append("-"); - switch (uiMode&ResTable_config::MASK_UI_MODE_NIGHT) { - case ResTable_config::UI_MODE_NIGHT_NO: - res.append("notnight"); - break; - case ResTable_config::UI_MODE_NIGHT_YES: - res.append("night"); - break; - default: - res.appendFormat("uiModeNight=%d", - dtohs(uiMode&MASK_UI_MODE_NIGHT)); - break; - } - } - if (density != DENSITY_DEFAULT) { - if (res.size() > 0) res.append("-"); - switch (density) { - case ResTable_config::DENSITY_LOW: - res.append("ldpi"); - break; - case ResTable_config::DENSITY_MEDIUM: - res.append("mdpi"); - break; - case ResTable_config::DENSITY_TV: - res.append("tvdpi"); - break; - case ResTable_config::DENSITY_HIGH: - res.append("hdpi"); - break; - case ResTable_config::DENSITY_XHIGH: - res.append("xhdpi"); - break; - case ResTable_config::DENSITY_XXHIGH: - res.append("xxhdpi"); - break; - case ResTable_config::DENSITY_NONE: - res.append("nodpi"); - break; - default: - res.appendFormat("%ddpi", dtohs(density)); - break; - } - } - if (touchscreen != TOUCHSCREEN_ANY) { - if (res.size() > 0) res.append("-"); - switch (touchscreen) { - case ResTable_config::TOUCHSCREEN_NOTOUCH: - res.append("notouch"); - break; - case ResTable_config::TOUCHSCREEN_FINGER: - res.append("finger"); - break; - case ResTable_config::TOUCHSCREEN_STYLUS: - res.append("stylus"); - break; - default: - res.appendFormat("touchscreen=%d", dtohs(touchscreen)); - break; - } - } - if (keyboard != KEYBOARD_ANY) { - if (res.size() > 0) res.append("-"); - switch (keyboard) { - case ResTable_config::KEYBOARD_NOKEYS: - res.append("nokeys"); - break; - case ResTable_config::KEYBOARD_QWERTY: - res.append("qwerty"); - break; - case ResTable_config::KEYBOARD_12KEY: - res.append("12key"); - break; - default: - res.appendFormat("keyboard=%d", dtohs(keyboard)); - break; - } - } - if ((inputFlags&MASK_KEYSHIDDEN) != 0) { - if (res.size() > 0) res.append("-"); - switch (inputFlags&MASK_KEYSHIDDEN) { - case ResTable_config::KEYSHIDDEN_NO: - res.append("keysexposed"); - break; - case ResTable_config::KEYSHIDDEN_YES: - res.append("keyshidden"); - break; - case ResTable_config::KEYSHIDDEN_SOFT: - res.append("keyssoft"); - break; - } - } - if (navigation != NAVIGATION_ANY) { - if (res.size() > 0) res.append("-"); - switch (navigation) { - case ResTable_config::NAVIGATION_NONAV: - res.append("nonav"); - break; - case ResTable_config::NAVIGATION_DPAD: - res.append("dpad"); - break; - case ResTable_config::NAVIGATION_TRACKBALL: - res.append("trackball"); - break; - case ResTable_config::NAVIGATION_WHEEL: - res.append("wheel"); - break; - default: - res.appendFormat("navigation=%d", dtohs(navigation)); - break; - } - } - if ((inputFlags&MASK_NAVHIDDEN) != 0) { - if (res.size() > 0) res.append("-"); - switch (inputFlags&MASK_NAVHIDDEN) { - case ResTable_config::NAVHIDDEN_NO: - res.append("navsexposed"); - break; - case ResTable_config::NAVHIDDEN_YES: - res.append("navhidden"); - break; - default: - res.appendFormat("inputFlagsNavHidden=%d", - dtohs(inputFlags&MASK_NAVHIDDEN)); - break; - } - } - if (screenSize != 0) { - if (res.size() > 0) res.append("-"); - res.appendFormat("%dx%d", dtohs(screenWidth), dtohs(screenHeight)); - } - if (version != 0) { - if (res.size() > 0) res.append("-"); - res.appendFormat("v%d", dtohs(sdkVersion)); - if (minorVersion != 0) { - res.appendFormat(".%d", dtohs(minorVersion)); - } - } - - return res; -} - -// -------------------------------------------------------------------- -// -------------------------------------------------------------------- -// -------------------------------------------------------------------- - -struct ResTable::Header -{ - Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL), - resourceIDMap(NULL), resourceIDMapSize(0) { } - - ~Header() - { - free(resourceIDMap); - } - - ResTable* const owner; - void* ownedData; - const ResTable_header* header; - size_t size; - const uint8_t* dataEnd; - size_t index; - void* cookie; - - ResStringPool values; - uint32_t* resourceIDMap; - size_t resourceIDMapSize; -}; - -struct ResTable::Type -{ - Type(const Header* _header, const Package* _package, size_t count) - : header(_header), package(_package), entryCount(count), - typeSpec(NULL), typeSpecFlags(NULL) { } - const Header* const header; - const Package* const package; - const size_t entryCount; - const ResTable_typeSpec* typeSpec; - const uint32_t* typeSpecFlags; - Vector configs; -}; - -struct ResTable::Package -{ - Package(ResTable* _owner, const Header* _header, const ResTable_package* _package) - : owner(_owner), header(_header), package(_package) { } - ~Package() - { - size_t i = types.size(); - while (i > 0) { - i--; - delete types[i]; - } - } - - ResTable* const owner; - const Header* const header; - const ResTable_package* const package; - Vector types; - - ResStringPool typeStrings; - ResStringPool keyStrings; - - const Type* getType(size_t idx) const { - return idx < types.size() ? types[idx] : NULL; - } -}; - -// A group of objects describing a particular resource package. -// The first in 'package' is always the root object (from the resource -// table that defined the package); the ones after are skins on top of it. -struct ResTable::PackageGroup -{ - PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id) - : owner(_owner), name(_name), id(_id), typeCount(0), bags(NULL) { } - ~PackageGroup() { - clearBagCache(); - const size_t N = packages.size(); - for (size_t i=0; iowner == owner) { - delete pkg; - } - } - } - - void clearBagCache() { - if (bags) { - TABLE_NOISY(printf("bags=%p\n", bags)); - Package* pkg = packages[0]; - TABLE_NOISY(printf("typeCount=%x\n", typeCount)); - for (size_t i=0; igetType(i); - if (type != NULL) { - bag_set** typeBags = bags[i]; - TABLE_NOISY(printf("typeBags=%p\n", typeBags)); - if (typeBags) { - TABLE_NOISY(printf("type->entryCount=%x\n", type->entryCount)); - const size_t N = type->entryCount; - for (size_t j=0; j packages; - - // This is for finding typeStrings and other common package stuff. - Package* basePackage; - - // For quick access. - size_t typeCount; - - // Computed attribute bags, first indexed by the type and second - // by the entry in that type. - bag_set*** bags; -}; - -struct ResTable::bag_set -{ - size_t numAttrs; // number in array - size_t availAttrs; // total space in array - uint32_t typeSpecFlags; - // Followed by 'numAttr' bag_entry structures. -}; - -ResTable::Theme::Theme(const ResTable& table) - : mTable(table) -{ - memset(mPackages, 0, sizeof(mPackages)); -} - -ResTable::Theme::~Theme() -{ - for (size_t i=0; inumTypes; j++) { - theme_entry* te = pi->types[j].entries; - if (te != NULL) { - free(te); - } - } - free(pi); -} - -ResTable::Theme::package_info* ResTable::Theme::copy_package(package_info* pi) -{ - package_info* newpi = (package_info*)malloc( - sizeof(package_info) + (pi->numTypes*sizeof(type_info))); - newpi->numTypes = pi->numTypes; - for (size_t j=0; jnumTypes; j++) { - size_t cnt = pi->types[j].numEntries; - newpi->types[j].numEntries = cnt; - theme_entry* te = pi->types[j].entries; - if (te != NULL) { - theme_entry* newte = (theme_entry*)malloc(cnt*sizeof(theme_entry)); - newpi->types[j].entries = newte; - memcpy(newte, te, cnt*sizeof(theme_entry)); - } else { - newpi->types[j].entries = NULL; - } - } - return newpi; -} - -status_t ResTable::Theme::applyStyle(uint32_t resID, bool force) -{ - const bag_entry* bag; - uint32_t bagTypeSpecFlags = 0; - mTable.lock(); - const ssize_t N = mTable.getBagLocked(resID, &bag, &bagTypeSpecFlags); - TABLE_NOISY(ALOGV("Applying style 0x%08x to theme %p, count=%d", resID, this, N)); - if (N < 0) { - mTable.unlock(); - return N; - } - - uint32_t curPackage = 0xffffffff; - ssize_t curPackageIndex = 0; - package_info* curPI = NULL; - uint32_t curType = 0xffffffff; - size_t numEntries = 0; - theme_entry* curEntries = NULL; - - const bag_entry* end = bag + N; - while (bag < end) { - const uint32_t attrRes = bag->map.name.ident; - const uint32_t p = Res_GETPACKAGE(attrRes); - const uint32_t t = Res_GETTYPE(attrRes); - const uint32_t e = Res_GETENTRY(attrRes); - - if (curPackage != p) { - const ssize_t pidx = mTable.getResourcePackageIndex(attrRes); - if (pidx < 0) { - ALOGE("Style contains key with bad package: 0x%08x\n", attrRes); - bag++; - continue; - } - curPackage = p; - curPackageIndex = pidx; - curPI = mPackages[pidx]; - if (curPI == NULL) { - PackageGroup* const grp = mTable.mPackageGroups[pidx]; - int cnt = grp->typeCount; - curPI = (package_info*)malloc( - sizeof(package_info) + (cnt*sizeof(type_info))); - curPI->numTypes = cnt; - memset(curPI->types, 0, cnt*sizeof(type_info)); - mPackages[pidx] = curPI; - } - curType = 0xffffffff; - } - if (curType != t) { - if (t >= curPI->numTypes) { - ALOGE("Style contains key with bad type: 0x%08x\n", attrRes); - bag++; - continue; - } - curType = t; - curEntries = curPI->types[t].entries; - if (curEntries == NULL) { - PackageGroup* const grp = mTable.mPackageGroups[curPackageIndex]; - const Type* type = grp->packages[0]->getType(t); - int cnt = type != NULL ? type->entryCount : 0; - curEntries = (theme_entry*)malloc(cnt*sizeof(theme_entry)); - memset(curEntries, Res_value::TYPE_NULL, cnt*sizeof(theme_entry)); - curPI->types[t].numEntries = cnt; - curPI->types[t].entries = curEntries; - } - numEntries = curPI->types[t].numEntries; - } - if (e >= numEntries) { - ALOGE("Style contains key with bad entry: 0x%08x\n", attrRes); - bag++; - continue; - } - theme_entry* curEntry = curEntries + e; - TABLE_NOISY(ALOGV("Attr 0x%08x: type=0x%x, data=0x%08x; curType=0x%x", - attrRes, bag->map.value.dataType, bag->map.value.data, - curEntry->value.dataType)); - if (force || curEntry->value.dataType == Res_value::TYPE_NULL) { - curEntry->stringBlock = bag->stringBlock; - curEntry->typeSpecFlags |= bagTypeSpecFlags; - curEntry->value = bag->map.value; - } - - bag++; - } - - mTable.unlock(); - - //ALOGI("Applying style 0x%08x (force=%d) theme %p...\n", resID, force, this); - //dumpToLog(); - - return NO_ERROR; -} - -status_t ResTable::Theme::setTo(const Theme& other) -{ - //ALOGI("Setting theme %p from theme %p...\n", this, &other); - //dumpToLog(); - //other.dumpToLog(); - - if (&mTable == &other.mTable) { - for (size_t i=0; i= 0) { - const package_info* const pi = mPackages[p]; - TABLE_THEME(ALOGI("Found package: %p", pi)); - if (pi != NULL) { - TABLE_THEME(ALOGI("Desired type index is %ld in avail %d", t, pi->numTypes)); - if (t < pi->numTypes) { - const type_info& ti = pi->types[t]; - TABLE_THEME(ALOGI("Desired entry index is %ld in avail %d", e, ti.numEntries)); - if (e < ti.numEntries) { - const theme_entry& te = ti.entries[e]; - if (outTypeSpecFlags != NULL) { - *outTypeSpecFlags |= te.typeSpecFlags; - } - TABLE_THEME(ALOGI("Theme value: type=0x%x, data=0x%08x", - te.value.dataType, te.value.data)); - const uint8_t type = te.value.dataType; - if (type == Res_value::TYPE_ATTRIBUTE) { - if (cnt > 0) { - cnt--; - resID = te.value.data; - continue; - } - ALOGW("Too many attribute references, stopped at: 0x%08x\n", resID); - return BAD_INDEX; - } else if (type != Res_value::TYPE_NULL) { - *outValue = te.value; - return te.stringBlock; - } - return BAD_INDEX; - } - } - } - } - break; - - } while (true); - - return BAD_INDEX; -} - -ssize_t ResTable::Theme::resolveAttributeReference(Res_value* inOutValue, - ssize_t blockIndex, uint32_t* outLastRef, - uint32_t* inoutTypeSpecFlags, ResTable_config* inoutConfig) const -{ - //printf("Resolving type=0x%x\n", inOutValue->dataType); - if (inOutValue->dataType == Res_value::TYPE_ATTRIBUTE) { - uint32_t newTypeSpecFlags; - blockIndex = getAttribute(inOutValue->data, inOutValue, &newTypeSpecFlags); - TABLE_THEME(ALOGI("Resolving attr reference: blockIndex=%d, type=0x%x, data=%p\n", - (int)blockIndex, (int)inOutValue->dataType, (void*)inOutValue->data)); - if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newTypeSpecFlags; - //printf("Retrieved attribute new type=0x%x\n", inOutValue->dataType); - if (blockIndex < 0) { - return blockIndex; - } - } - return mTable.resolveReference(inOutValue, blockIndex, outLastRef, - inoutTypeSpecFlags, inoutConfig); -} - -void ResTable::Theme::dumpToLog() const -{ - ALOGI("Theme %p:\n", this); - for (size_t i=0; inumTypes; j++) { - type_info& ti = pi->types[j]; - if (ti.numEntries == 0) continue; - - ALOGI(" Type #0x%02x:\n", (int)(j+1)); - for (size_t k=0; k(idmap)); -} - -status_t ResTable::add(Asset* asset, void* cookie, bool copyData, const void* idmap) -{ - const void* data = asset->getBuffer(true); - if (data == NULL) { - ALOGW("Unable to get buffer of resource asset file"); - return UNKNOWN_ERROR; - } - size_t size = (size_t)asset->getLength(); - return add(data, size, cookie, asset, copyData, reinterpret_cast(idmap)); -} - -status_t ResTable::add(ResTable* src) -{ - mError = src->mError; - - for (size_t i=0; imHeaders.size(); i++) { - mHeaders.add(src->mHeaders[i]); - } - - for (size_t i=0; imPackageGroups.size(); i++) { - PackageGroup* srcPg = src->mPackageGroups[i]; - PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id); - for (size_t j=0; jpackages.size(); j++) { - pg->packages.add(srcPg->packages[j]); - } - pg->basePackage = srcPg->basePackage; - pg->typeCount = srcPg->typeCount; - mPackageGroups.add(pg); - } - - memcpy(mPackageMap, src->mPackageMap, sizeof(mPackageMap)); - - return mError; -} - -status_t ResTable::add(const void* data, size_t size, void* cookie, - Asset* asset, bool copyData, const Asset* idmap) -{ - if (!data) return NO_ERROR; - Header* header = new Header(this); - header->index = mHeaders.size(); - header->cookie = cookie; - if (idmap != NULL) { - const size_t idmap_size = idmap->getLength(); - const void* idmap_data = const_cast(idmap)->getBuffer(true); - header->resourceIDMap = (uint32_t*)malloc(idmap_size); - if (header->resourceIDMap == NULL) { - delete header; - return (mError = NO_MEMORY); - } - memcpy((void*)header->resourceIDMap, idmap_data, idmap_size); - header->resourceIDMapSize = idmap_size; - } - mHeaders.add(header); - - const bool notDeviceEndian = htods(0xf0) != 0xf0; - - LOAD_TABLE_NOISY( - ALOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%p, asset=%p, copy=%d " - "idmap=%p\n", data, size, cookie, asset, copyData, idmap)); - - if (copyData || notDeviceEndian) { - header->ownedData = malloc(size); - if (header->ownedData == NULL) { - return (mError=NO_MEMORY); - } - memcpy(header->ownedData, data, size); - data = header->ownedData; - } - - header->header = (const ResTable_header*)data; - header->size = dtohl(header->header->header.size); - //ALOGI("Got size 0x%x, again size 0x%x, raw size 0x%x\n", header->size, - // dtohl(header->header->header.size), header->header->header.size); - LOAD_TABLE_NOISY(ALOGV("Loading ResTable @%p:\n", header->header)); - LOAD_TABLE_NOISY(printHexData(2, header->header, header->size < 256 ? header->size : 256, - 16, 16, 0, false, printToLogFunc)); - if (dtohs(header->header->header.headerSize) > header->size - || header->size > size) { - ALOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n", - (int)dtohs(header->header->header.headerSize), - (int)header->size, (int)size); - return (mError=BAD_TYPE); - } - if (((dtohs(header->header->header.headerSize)|header->size)&0x3) != 0) { - ALOGW("Bad resource table: header size 0x%x or total size 0x%x is not on an integer boundary\n", - (int)dtohs(header->header->header.headerSize), - (int)header->size); - return (mError=BAD_TYPE); - } - header->dataEnd = ((const uint8_t*)header->header) + header->size; - - // Iterate through all chunks. - size_t curPackage = 0; - - const ResChunk_header* chunk = - (const ResChunk_header*)(((const uint8_t*)header->header) - + dtohs(header->header->header.headerSize)); - while (((const uint8_t*)chunk) <= (header->dataEnd-sizeof(ResChunk_header)) && - ((const uint8_t*)chunk) <= (header->dataEnd-dtohl(chunk->size))) { - status_t err = validate_chunk(chunk, sizeof(ResChunk_header), header->dataEnd, "ResTable"); - if (err != NO_ERROR) { - return (mError=err); - } - TABLE_NOISY(ALOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n", - dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size), - (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)))); - const size_t csize = dtohl(chunk->size); - const uint16_t ctype = dtohs(chunk->type); - if (ctype == RES_STRING_POOL_TYPE) { - if (header->values.getError() != NO_ERROR) { - // Only use the first string chunk; ignore any others that - // may appear. - status_t err = header->values.setTo(chunk, csize); - if (err != NO_ERROR) { - return (mError=err); - } - } else { - ALOGW("Multiple string chunks found in resource table."); - } - } else if (ctype == RES_TABLE_PACKAGE_TYPE) { - if (curPackage >= dtohl(header->header->packageCount)) { - ALOGW("More package chunks were found than the %d declared in the header.", - dtohl(header->header->packageCount)); - return (mError=BAD_TYPE); - } - uint32_t idmap_id = 0; - if (idmap != NULL) { - uint32_t tmp; - if (getIdmapPackageId(header->resourceIDMap, - header->resourceIDMapSize, - &tmp) == NO_ERROR) { - idmap_id = tmp; - } - } - if (parsePackage((ResTable_package*)chunk, header, idmap_id) != NO_ERROR) { - return mError; - } - curPackage++; - } else { - ALOGW("Unknown chunk type %p in table at %p.\n", - (void*)(int)(ctype), - (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))); - } - chunk = (const ResChunk_header*) - (((const uint8_t*)chunk) + csize); - } - - if (curPackage < dtohl(header->header->packageCount)) { - ALOGW("Fewer package chunks (%d) were found than the %d declared in the header.", - (int)curPackage, dtohl(header->header->packageCount)); - return (mError=BAD_TYPE); - } - mError = header->values.getError(); - if (mError != NO_ERROR) { - ALOGW("No string values found in resource table!"); - } - - TABLE_NOISY(ALOGV("Returning from add with mError=%d\n", mError)); - return mError; -} - -status_t ResTable::getError() const -{ - return mError; -} - -void ResTable::uninit() -{ - mError = NO_INIT; - size_t N = mPackageGroups.size(); - for (size_t i=0; iowner == this) { - if (header->ownedData) { - free(header->ownedData); - } - delete header; - } - } - - mPackageGroups.clear(); - mHeaders.clear(); -} - -bool ResTable::getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const -{ - if (mError != NO_ERROR) { - return false; - } - - const ssize_t p = getResourcePackageIndex(resID); - const int t = Res_GETTYPE(resID); - const int e = Res_GETENTRY(resID); - - if (p < 0) { - if (Res_GETPACKAGE(resID)+1 == 0) { - ALOGW("No package identifier when getting name for resource number 0x%08x", resID); - } else { - ALOGW("No known package when getting name for resource number 0x%08x", resID); - } - return false; - } - if (t < 0) { - ALOGW("No type identifier when getting name for resource number 0x%08x", resID); - return false; - } - - const PackageGroup* const grp = mPackageGroups[p]; - if (grp == NULL) { - ALOGW("Bad identifier when getting name for resource number 0x%08x", resID); - return false; - } - if (grp->packages.size() > 0) { - const Package* const package = grp->packages[0]; - - const ResTable_type* type; - const ResTable_entry* entry; - ssize_t offset = getEntry(package, t, e, NULL, &type, &entry, NULL); - if (offset <= 0) { - return false; - } - - outName->package = grp->name.string(); - outName->packageLen = grp->name.size(); - if (allowUtf8) { - outName->type8 = grp->basePackage->typeStrings.string8At(t, &outName->typeLen); - outName->name8 = grp->basePackage->keyStrings.string8At( - dtohl(entry->key.index), &outName->nameLen); - } else { - outName->type8 = NULL; - outName->name8 = NULL; - } - if (outName->type8 == NULL) { - outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen); - // If we have a bad index for some reason, we should abort. - if (outName->type == NULL) { - return false; - } - } - if (outName->name8 == NULL) { - outName->name = grp->basePackage->keyStrings.stringAt( - dtohl(entry->key.index), &outName->nameLen); - // If we have a bad index for some reason, we should abort. - if (outName->name == NULL) { - return false; - } - } - - return true; - } - - return false; -} - -ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag, uint16_t density, - uint32_t* outSpecFlags, ResTable_config* outConfig) const -{ - if (mError != NO_ERROR) { - return mError; - } - - const ssize_t p = getResourcePackageIndex(resID); - const int t = Res_GETTYPE(resID); - const int e = Res_GETENTRY(resID); - - if (p < 0) { - if (Res_GETPACKAGE(resID)+1 == 0) { - ALOGW("No package identifier when getting value for resource number 0x%08x", resID); - } else { - ALOGW("No known package when getting value for resource number 0x%08x", resID); - } - return BAD_INDEX; - } - if (t < 0) { - ALOGW("No type identifier when getting value for resource number 0x%08x", resID); - return BAD_INDEX; - } - - const Res_value* bestValue = NULL; - const Package* bestPackage = NULL; - ResTable_config bestItem; - memset(&bestItem, 0, sizeof(bestItem)); // make the compiler shut up - - if (outSpecFlags != NULL) *outSpecFlags = 0; - - // Look through all resource packages, starting with the most - // recently added. - const PackageGroup* const grp = mPackageGroups[p]; - if (grp == NULL) { - ALOGW("Bad identifier when getting value for resource number 0x%08x", resID); - return BAD_INDEX; - } - - // Allow overriding density - const ResTable_config* desiredConfig = &mParams; - ResTable_config* overrideConfig = NULL; - if (density > 0) { - overrideConfig = (ResTable_config*) malloc(sizeof(ResTable_config)); - if (overrideConfig == NULL) { - ALOGE("Couldn't malloc ResTable_config for overrides: %s", strerror(errno)); - return BAD_INDEX; - } - memcpy(overrideConfig, &mParams, sizeof(ResTable_config)); - overrideConfig->density = density; - desiredConfig = overrideConfig; - } - - ssize_t rc = BAD_VALUE; - size_t ip = grp->packages.size(); - while (ip > 0) { - ip--; - int T = t; - int E = e; - - const Package* const package = grp->packages[ip]; - if (package->header->resourceIDMap) { - uint32_t overlayResID = 0x0; - status_t retval = idmapLookup(package->header->resourceIDMap, - package->header->resourceIDMapSize, - resID, &overlayResID); - if (retval == NO_ERROR && overlayResID != 0x0) { - // for this loop iteration, this is the type and entry we really want - ALOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID); - T = Res_GETTYPE(overlayResID); - E = Res_GETENTRY(overlayResID); - } else { - // resource not present in overlay package, continue with the next package - continue; - } - } - - const ResTable_type* type; - const ResTable_entry* entry; - const Type* typeClass; - ssize_t offset = getEntry(package, T, E, desiredConfig, &type, &entry, &typeClass); - if (offset <= 0) { - // No {entry, appropriate config} pair found in package. If this - // package is an overlay package (ip != 0), this simply means the - // overlay package did not specify a default. - // Non-overlay packages are still required to provide a default. - if (offset < 0 && ip == 0) { - ALOGW("Failure getting entry for 0x%08x (t=%d e=%d) in package %zd (error %d)\n", - resID, T, E, ip, (int)offset); - rc = offset; - goto out; - } - continue; - } - - if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) != 0) { - if (!mayBeBag) { - ALOGW("Requesting resource %p failed because it is complex\n", - (void*)resID); - } - continue; - } - - TABLE_NOISY(aout << "Resource type data: " - << HexDump(type, dtohl(type->header.size)) << endl); - - if ((size_t)offset > (dtohl(type->header.size)-sizeof(Res_value))) { - ALOGW("ResTable_item at %d is beyond type chunk data %d", - (int)offset, dtohl(type->header.size)); - rc = BAD_TYPE; - goto out; - } - - const Res_value* item = - (const Res_value*)(((const uint8_t*)type) + offset); - ResTable_config thisConfig; - thisConfig.copyFromDtoH(type->config); - - if (outSpecFlags != NULL) { - if (typeClass->typeSpecFlags != NULL) { - *outSpecFlags |= dtohl(typeClass->typeSpecFlags[E]); - } else { - *outSpecFlags = -1; - } - } - - if (bestPackage != NULL && - (bestItem.isMoreSpecificThan(thisConfig) || bestItem.diff(thisConfig) == 0)) { - // Discard thisConfig not only if bestItem is more specific, but also if the two configs - // are identical (diff == 0), or overlay packages will not take effect. - continue; - } - - bestItem = thisConfig; - bestValue = item; - bestPackage = package; - } - - TABLE_NOISY(printf("Found result: package %p\n", bestPackage)); - - if (bestValue) { - outValue->size = dtohs(bestValue->size); - outValue->res0 = bestValue->res0; - outValue->dataType = bestValue->dataType; - outValue->data = dtohl(bestValue->data); - if (outConfig != NULL) { - *outConfig = bestItem; - } - TABLE_NOISY(size_t len; - printf("Found value: pkg=%d, type=%d, str=%s, int=%d\n", - bestPackage->header->index, - outValue->dataType, - outValue->dataType == bestValue->TYPE_STRING - ? String8(bestPackage->header->values.stringAt( - outValue->data, &len)).string() - : "", - outValue->data)); - rc = bestPackage->header->index; - goto out; - } - -out: - if (overrideConfig != NULL) { - free(overrideConfig); - } - - return rc; -} - -ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex, - uint32_t* outLastRef, uint32_t* inoutTypeSpecFlags, - ResTable_config* outConfig) const -{ - int count=0; - while (blockIndex >= 0 && value->dataType == value->TYPE_REFERENCE - && value->data != 0 && count < 20) { - if (outLastRef) *outLastRef = value->data; - uint32_t lastRef = value->data; - uint32_t newFlags = 0; - const ssize_t newIndex = getResource(value->data, value, true, 0, &newFlags, - outConfig); - if (newIndex == BAD_INDEX) { - return BAD_INDEX; - } - TABLE_THEME(ALOGI("Resolving reference %p: newIndex=%d, type=0x%x, data=%p\n", - (void*)lastRef, (int)newIndex, (int)value->dataType, (void*)value->data)); - //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex); - if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newFlags; - if (newIndex < 0) { - // This can fail if the resource being referenced is a style... - // in this case, just return the reference, and expect the - // caller to deal with. - return blockIndex; - } - blockIndex = newIndex; - count++; - } - return blockIndex; -} - -const char16_t* ResTable::valueToString( - const Res_value* value, size_t stringBlock, - char16_t tmpBuffer[TMP_BUFFER_SIZE], size_t* outLen) -{ - if (!value) { - return NULL; - } - if (value->dataType == value->TYPE_STRING) { - return getTableStringBlock(stringBlock)->stringAt(value->data, outLen); - } - // XXX do int to string conversions. - return NULL; -} - -ssize_t ResTable::lockBag(uint32_t resID, const bag_entry** outBag) const -{ - mLock.lock(); - ssize_t err = getBagLocked(resID, outBag); - if (err < NO_ERROR) { - //printf("*** get failed! unlocking\n"); - mLock.unlock(); - } - return err; -} - -void ResTable::unlockBag(const bag_entry* bag) const -{ - //printf("<<< unlockBag %p\n", this); - mLock.unlock(); -} - -void ResTable::lock() const -{ - mLock.lock(); -} - -void ResTable::unlock() const -{ - mLock.unlock(); -} - -ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag, - uint32_t* outTypeSpecFlags) const -{ - if (mError != NO_ERROR) { - return mError; - } - - const ssize_t p = getResourcePackageIndex(resID); - const int t = Res_GETTYPE(resID); - const int e = Res_GETENTRY(resID); - - if (p < 0) { - ALOGW("Invalid package identifier when getting bag for resource number 0x%08x", resID); - return BAD_INDEX; - } - if (t < 0) { - ALOGW("No type identifier when getting bag for resource number 0x%08x", resID); - return BAD_INDEX; - } - - //printf("Get bag: id=0x%08x, p=%d, t=%d\n", resID, p, t); - PackageGroup* const grp = mPackageGroups[p]; - if (grp == NULL) { - ALOGW("Bad identifier when getting bag for resource number 0x%08x", resID); - return false; - } - - if (t >= (int)grp->typeCount) { - ALOGW("Type identifier 0x%x is larger than type count 0x%x", - t+1, (int)grp->typeCount); - return BAD_INDEX; - } - - const Package* const basePackage = grp->packages[0]; - - const Type* const typeConfigs = basePackage->getType(t); - - const size_t NENTRY = typeConfigs->entryCount; - if (e >= (int)NENTRY) { - ALOGW("Entry identifier 0x%x is larger than entry count 0x%x", - e, (int)typeConfigs->entryCount); - return BAD_INDEX; - } - - // First see if we've already computed this bag... - if (grp->bags) { - bag_set** typeSet = grp->bags[t]; - if (typeSet) { - bag_set* set = typeSet[e]; - if (set) { - if (set != (bag_set*)0xFFFFFFFF) { - if (outTypeSpecFlags != NULL) { - *outTypeSpecFlags = set->typeSpecFlags; - } - *outBag = (bag_entry*)(set+1); - //ALOGI("Found existing bag for: %p\n", (void*)resID); - return set->numAttrs; - } - ALOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.", - resID); - return BAD_INDEX; - } - } - } - - // Bag not found, we need to compute it! - if (!grp->bags) { - grp->bags = (bag_set***)calloc(grp->typeCount, sizeof(bag_set*)); - if (!grp->bags) return NO_MEMORY; - } - - bag_set** typeSet = grp->bags[t]; - if (!typeSet) { - typeSet = (bag_set**)calloc(NENTRY, sizeof(bag_set*)); - if (!typeSet) return NO_MEMORY; - grp->bags[t] = typeSet; - } - - // Mark that we are currently working on this one. - typeSet[e] = (bag_set*)0xFFFFFFFF; - - // This is what we are building. - bag_set* set = NULL; - - TABLE_NOISY(ALOGI("Building bag: %p\n", (void*)resID)); - - ResTable_config bestConfig; - memset(&bestConfig, 0, sizeof(bestConfig)); - - // Now collect all bag attributes from all packages. - size_t ip = grp->packages.size(); - while (ip > 0) { - ip--; - int T = t; - int E = e; - - const Package* const package = grp->packages[ip]; - if (package->header->resourceIDMap) { - uint32_t overlayResID = 0x0; - status_t retval = idmapLookup(package->header->resourceIDMap, - package->header->resourceIDMapSize, - resID, &overlayResID); - if (retval == NO_ERROR && overlayResID != 0x0) { - // for this loop iteration, this is the type and entry we really want - ALOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID); - T = Res_GETTYPE(overlayResID); - E = Res_GETENTRY(overlayResID); - } else { - // resource not present in overlay package, continue with the next package - continue; - } - } - - const ResTable_type* type; - const ResTable_entry* entry; - const Type* typeClass; - ALOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, T, E); - ssize_t offset = getEntry(package, T, E, &mParams, &type, &entry, &typeClass); - ALOGV("Resulting offset=%d\n", offset); - if (offset <= 0) { - // No {entry, appropriate config} pair found in package. If this - // package is an overlay package (ip != 0), this simply means the - // overlay package did not specify a default. - // Non-overlay packages are still required to provide a default. - if (offset < 0 && ip == 0) { - if (set) free(set); - return offset; - } - continue; - } - - if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) == 0) { - ALOGW("Skipping entry %p in package table %d because it is not complex!\n", - (void*)resID, (int)ip); - continue; - } - - if (set != NULL && !type->config.isBetterThan(bestConfig, NULL)) { - continue; - } - bestConfig = type->config; - if (set) { - free(set); - set = NULL; - } - - const uint16_t entrySize = dtohs(entry->size); - const uint32_t parent = entrySize >= sizeof(ResTable_map_entry) - ? dtohl(((const ResTable_map_entry*)entry)->parent.ident) : 0; - const uint32_t count = entrySize >= sizeof(ResTable_map_entry) - ? dtohl(((const ResTable_map_entry*)entry)->count) : 0; - - size_t N = count; - - TABLE_NOISY(ALOGI("Found map: size=%p parent=%p count=%d\n", - entrySize, parent, count)); - - // If this map inherits from another, we need to start - // with its parent's values. Otherwise start out empty. - TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n", - entrySize, parent)); - if (parent) { - const bag_entry* parentBag; - uint32_t parentTypeSpecFlags = 0; - const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags); - const size_t NT = ((NP >= 0) ? NP : 0) + N; - set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT); - if (set == NULL) { - return NO_MEMORY; - } - if (NP > 0) { - memcpy(set+1, parentBag, NP*sizeof(bag_entry)); - set->numAttrs = NP; - TABLE_NOISY(ALOGI("Initialized new bag with %d inherited attributes.\n", NP)); - } else { - TABLE_NOISY(ALOGI("Initialized new bag with no inherited attributes.\n")); - set->numAttrs = 0; - } - set->availAttrs = NT; - set->typeSpecFlags = parentTypeSpecFlags; - } else { - set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N); - if (set == NULL) { - return NO_MEMORY; - } - set->numAttrs = 0; - set->availAttrs = N; - set->typeSpecFlags = 0; - } - - if (typeClass->typeSpecFlags != NULL) { - set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[E]); - } else { - set->typeSpecFlags = -1; - } - - // Now merge in the new attributes... - ssize_t curOff = offset; - const ResTable_map* map; - bag_entry* entries = (bag_entry*)(set+1); - size_t curEntry = 0; - uint32_t pos = 0; - TABLE_NOISY(ALOGI("Starting with set %p, entries=%p, avail=%d\n", - set, entries, set->availAttrs)); - while (pos < count) { - TABLE_NOISY(printf("Now at %p\n", (void*)curOff)); - - if ((size_t)curOff > (dtohl(type->header.size)-sizeof(ResTable_map))) { - ALOGW("ResTable_map at %d is beyond type chunk data %d", - (int)curOff, dtohl(type->header.size)); - return BAD_TYPE; - } - map = (const ResTable_map*)(((const uint8_t*)type) + curOff); - N++; - - const uint32_t newName = htodl(map->name.ident); - bool isInside; - uint32_t oldName = 0; - while ((isInside=(curEntry < set->numAttrs)) - && (oldName=entries[curEntry].map.name.ident) < newName) { - TABLE_NOISY(printf("#%d: Keeping existing attribute: 0x%08x\n", - curEntry, entries[curEntry].map.name.ident)); - curEntry++; - } - - if ((!isInside) || oldName != newName) { - // This is a new attribute... figure out what to do with it. - if (set->numAttrs >= set->availAttrs) { - // Need to alloc more memory... - const size_t newAvail = set->availAttrs+N; - set = (bag_set*)realloc(set, - sizeof(bag_set) - + sizeof(bag_entry)*newAvail); - if (set == NULL) { - return NO_MEMORY; - } - set->availAttrs = newAvail; - entries = (bag_entry*)(set+1); - TABLE_NOISY(printf("Reallocated set %p, entries=%p, avail=%d\n", - set, entries, set->availAttrs)); - } - if (isInside) { - // Going in the middle, need to make space. - memmove(entries+curEntry+1, entries+curEntry, - sizeof(bag_entry)*(set->numAttrs-curEntry)); - set->numAttrs++; - } - TABLE_NOISY(printf("#%d: Inserting new attribute: 0x%08x\n", - curEntry, newName)); - } else { - TABLE_NOISY(printf("#%d: Replacing existing attribute: 0x%08x\n", - curEntry, oldName)); - } - - bag_entry* cur = entries+curEntry; - - cur->stringBlock = package->header->index; - cur->map.name.ident = newName; - cur->map.value.copyFrom_dtoh(map->value); - TABLE_NOISY(printf("Setting entry #%d %p: block=%d, name=0x%08x, type=%d, data=0x%08x\n", - curEntry, cur, cur->stringBlock, cur->map.name.ident, - cur->map.value.dataType, cur->map.value.data)); - - // On to the next! - curEntry++; - pos++; - const size_t size = dtohs(map->value.size); - curOff += size + sizeof(*map)-sizeof(map->value); - }; - if (curEntry > set->numAttrs) { - set->numAttrs = curEntry; - } - } - - // And this is it... - typeSet[e] = set; - if (set) { - if (outTypeSpecFlags != NULL) { - *outTypeSpecFlags = set->typeSpecFlags; - } - *outBag = (bag_entry*)(set+1); - TABLE_NOISY(ALOGI("Returning %d attrs\n", set->numAttrs)); - return set->numAttrs; - } - return BAD_INDEX; -} - -void ResTable::setParameters(const ResTable_config* params) -{ - mLock.lock(); - TABLE_GETENTRY(ALOGI("Setting parameters: %s\n", params->toString().string())); - mParams = *params; - for (size_t i=0; iclearBagCache(); - } - mLock.unlock(); -} - -void ResTable::getParameters(ResTable_config* params) const -{ - mLock.lock(); - *params = mParams; - mLock.unlock(); -} - -struct id_name_map { - uint32_t id; - size_t len; - char16_t name[6]; -}; - -const static id_name_map ID_NAMES[] = { - { ResTable_map::ATTR_TYPE, 5, { '^', 't', 'y', 'p', 'e' } }, - { ResTable_map::ATTR_L10N, 5, { '^', 'l', '1', '0', 'n' } }, - { ResTable_map::ATTR_MIN, 4, { '^', 'm', 'i', 'n' } }, - { ResTable_map::ATTR_MAX, 4, { '^', 'm', 'a', 'x' } }, - { ResTable_map::ATTR_OTHER, 6, { '^', 'o', 't', 'h', 'e', 'r' } }, - { ResTable_map::ATTR_ZERO, 5, { '^', 'z', 'e', 'r', 'o' } }, - { ResTable_map::ATTR_ONE, 4, { '^', 'o', 'n', 'e' } }, - { ResTable_map::ATTR_TWO, 4, { '^', 't', 'w', 'o' } }, - { ResTable_map::ATTR_FEW, 4, { '^', 'f', 'e', 'w' } }, - { ResTable_map::ATTR_MANY, 5, { '^', 'm', 'a', 'n', 'y' } }, -}; - -uint32_t ResTable::identifierForName(const char16_t* name, size_t nameLen, - const char16_t* type, size_t typeLen, - const char16_t* package, - size_t packageLen, - uint32_t* outTypeSpecFlags) const -{ - TABLE_SUPER_NOISY(printf("Identifier for name: error=%d\n", mError)); - - // Check for internal resource identifier as the very first thing, so - // that we will always find them even when there are no resources. - if (name[0] == '^') { - const int N = (sizeof(ID_NAMES)/sizeof(ID_NAMES[0])); - size_t len; - for (int i=0; ilen; - if (len != nameLen) { - continue; - } - for (size_t j=1; jname[j] != name[j]) { - goto nope; - } - } - if (outTypeSpecFlags) { - *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC; - } - return m->id; -nope: - ; - } - if (nameLen > 7) { - if (name[1] == 'i' && name[2] == 'n' - && name[3] == 'd' && name[4] == 'e' && name[5] == 'x' - && name[6] == '_') { - int index = atoi(String8(name + 7, nameLen - 7).string()); - if (Res_CHECKID(index)) { - ALOGW("Array resource index: %d is too large.", - index); - return 0; - } - if (outTypeSpecFlags) { - *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC; - } - return Res_MAKEARRAY(index); - } - } - return 0; - } - - if (mError != NO_ERROR) { - return 0; - } - - bool fakePublic = false; - - // Figure out the package and type we are looking in... - - const char16_t* packageEnd = NULL; - const char16_t* typeEnd = NULL; - const char16_t* const nameEnd = name+nameLen; - const char16_t* p = name; - while (p < nameEnd) { - if (*p == ':') packageEnd = p; - else if (*p == '/') typeEnd = p; - p++; - } - if (*name == '@') { - name++; - if (*name == '*') { - fakePublic = true; - name++; - } - } - if (name >= nameEnd) { - return 0; - } - - if (packageEnd) { - package = name; - packageLen = packageEnd-name; - name = packageEnd+1; - } else if (!package) { - return 0; - } - - if (typeEnd) { - type = name; - typeLen = typeEnd-name; - name = typeEnd+1; - } else if (!type) { - return 0; - } - - if (name >= nameEnd) { - return 0; - } - nameLen = nameEnd-name; - - TABLE_NOISY(printf("Looking for identifier: type=%s, name=%s, package=%s\n", - String8(type, typeLen).string(), - String8(name, nameLen).string(), - String8(package, packageLen).string())); - - const size_t NG = mPackageGroups.size(); - for (size_t ig=0; igname.string(), group->name.size())) { - TABLE_NOISY(printf("Skipping package group: %s\n", String8(group->name).string())); - continue; - } - - const ssize_t ti = group->basePackage->typeStrings.indexOfString(type, typeLen); - if (ti < 0) { - TABLE_NOISY(printf("Type not found in package %s\n", String8(group->name).string())); - continue; - } - - const ssize_t ei = group->basePackage->keyStrings.indexOfString(name, nameLen); - if (ei < 0) { - TABLE_NOISY(printf("Name not found in package %s\n", String8(group->name).string())); - continue; - } - - TABLE_NOISY(printf("Search indices: type=%d, name=%d\n", ti, ei)); - - const Type* const typeConfigs = group->packages[0]->getType(ti); - if (typeConfigs == NULL || typeConfigs->configs.size() <= 0) { - TABLE_NOISY(printf("Expected type structure not found in package %s for idnex %d\n", - String8(group->name).string(), ti)); - } - - size_t NTC = typeConfigs->configs.size(); - for (size_t tci=0; tciconfigs[tci]; - const uint32_t typeOffset = dtohl(ty->entriesStart); - - const uint8_t* const end = ((const uint8_t*)ty) + dtohl(ty->header.size); - const uint32_t* const eindex = (const uint32_t*) - (((const uint8_t*)ty) + dtohs(ty->header.headerSize)); - - const size_t NE = dtohl(ty->entryCount); - for (size_t i=0; i (dtohl(ty->header.size)-sizeof(ResTable_entry))) { - ALOGW("ResTable_entry at %d is beyond type chunk data %d", - offset, dtohl(ty->header.size)); - return 0; - } - if ((offset&0x3) != 0) { - ALOGW("ResTable_entry at %d (pkg=%d type=%d ent=%d) is not on an integer boundary when looking for %s:%s/%s", - (int)offset, (int)group->id, (int)ti+1, (int)i, - String8(package, packageLen).string(), - String8(type, typeLen).string(), - String8(name, nameLen).string()); - return 0; - } - - const ResTable_entry* const entry = (const ResTable_entry*) - (((const uint8_t*)ty) + offset); - if (dtohs(entry->size) < sizeof(*entry)) { - ALOGW("ResTable_entry size %d is too small", dtohs(entry->size)); - return BAD_TYPE; - } - - TABLE_SUPER_NOISY(printf("Looking at entry #%d: want str %d, have %d\n", - i, ei, dtohl(entry->key.index))); - if (dtohl(entry->key.index) == (size_t)ei) { - if (outTypeSpecFlags) { - *outTypeSpecFlags = typeConfigs->typeSpecFlags[i]; - if (fakePublic) { - *outTypeSpecFlags |= ResTable_typeSpec::SPEC_PUBLIC; - } - } - return Res_MAKEID(group->id-1, ti, i); - } - } - } - } - - return 0; -} - -bool ResTable::expandResourceRef(const uint16_t* refStr, size_t refLen, - String16* outPackage, - String16* outType, - String16* outName, - const String16* defType, - const String16* defPackage, - const char** outErrorMsg, - bool* outPublicOnly) -{ - const char16_t* packageEnd = NULL; - const char16_t* typeEnd = NULL; - const char16_t* p = refStr; - const char16_t* const end = p + refLen; - while (p < end) { - if (*p == ':') packageEnd = p; - else if (*p == '/') { - typeEnd = p; - break; - } - p++; - } - p = refStr; - if (*p == '@') p++; - - if (outPublicOnly != NULL) { - *outPublicOnly = true; - } - if (*p == '*') { - p++; - if (outPublicOnly != NULL) { - *outPublicOnly = false; - } - } - - if (packageEnd) { - *outPackage = String16(p, packageEnd-p); - p = packageEnd+1; - } else { - if (!defPackage) { - if (outErrorMsg) { - *outErrorMsg = "No resource package specified"; - } - return false; - } - *outPackage = *defPackage; - } - if (typeEnd) { - *outType = String16(p, typeEnd-p); - p = typeEnd+1; - } else { - if (!defType) { - if (outErrorMsg) { - *outErrorMsg = "No resource type specified"; - } - return false; - } - *outType = *defType; - } - *outName = String16(p, end-p); - if(**outPackage == 0) { - if(outErrorMsg) { - *outErrorMsg = "Resource package cannot be an empty string"; - } - return false; - } - if(**outType == 0) { - if(outErrorMsg) { - *outErrorMsg = "Resource type cannot be an empty string"; - } - return false; - } - if(**outName == 0) { - if(outErrorMsg) { - *outErrorMsg = "Resource id cannot be an empty string"; - } - return false; - } - return true; -} - -static uint32_t get_hex(char c, bool* outError) -{ - if (c >= '0' && c <= '9') { - return c - '0'; - } else if (c >= 'a' && c <= 'f') { - return c - 'a' + 0xa; - } else if (c >= 'A' && c <= 'F') { - return c - 'A' + 0xa; - } - *outError = true; - return 0; -} - -struct unit_entry -{ - const char* name; - size_t len; - uint8_t type; - uint32_t unit; - float scale; -}; - -static const unit_entry unitNames[] = { - { "px", strlen("px"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PX, 1.0f }, - { "dip", strlen("dip"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f }, - { "dp", strlen("dp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f }, - { "sp", strlen("sp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_SP, 1.0f }, - { "pt", strlen("pt"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PT, 1.0f }, - { "in", strlen("in"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_IN, 1.0f }, - { "mm", strlen("mm"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_MM, 1.0f }, - { "%", strlen("%"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION, 1.0f/100 }, - { "%p", strlen("%p"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION_PARENT, 1.0f/100 }, - { NULL, 0, 0, 0, 0 } -}; - -static bool parse_unit(const char* str, Res_value* outValue, - float* outScale, const char** outEnd) -{ - const char* end = str; - while (*end != 0 && !isspace((unsigned char)*end)) { - end++; - } - const size_t len = end-str; - - const char* realEnd = end; - while (*realEnd != 0 && isspace((unsigned char)*realEnd)) { - realEnd++; - } - if (*realEnd != 0) { - return false; - } - - const unit_entry* cur = unitNames; - while (cur->name) { - if (len == cur->len && strncmp(cur->name, str, len) == 0) { - outValue->dataType = cur->type; - outValue->data = cur->unit << Res_value::COMPLEX_UNIT_SHIFT; - *outScale = cur->scale; - *outEnd = end; - //printf("Found unit %s for %s\n", cur->name, str); - return true; - } - cur++; - } - - return false; -} - - -bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue) -{ - while (len > 0 && isspace16(*s)) { - s++; - len--; - } - - if (len <= 0) { - return false; - } - - size_t i = 0; - int32_t val = 0; - bool neg = false; - - if (*s == '-') { - neg = true; - i++; - } - - if (s[i] < '0' || s[i] > '9') { - return false; - } - - // Decimal or hex? - if (s[i] == '0' && s[i+1] == 'x') { - if (outValue) - outValue->dataType = outValue->TYPE_INT_HEX; - i += 2; - bool error = false; - while (i < len && !error) { - val = (val*16) + get_hex(s[i], &error); - i++; - } - if (error) { - return false; - } - } else { - if (outValue) - outValue->dataType = outValue->TYPE_INT_DEC; - while (i < len) { - if (s[i] < '0' || s[i] > '9') { - return false; - } - val = (val*10) + s[i]-'0'; - i++; - } - } - - if (neg) val = -val; - - while (i < len && isspace16(s[i])) { - i++; - } - - if (i == len) { - if (outValue) - outValue->data = val; - return true; - } - - return false; -} - -bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue) -{ - while (len > 0 && isspace16(*s)) { - s++; - len--; - } - - if (len <= 0) { - return false; - } - - char buf[128]; - int i=0; - while (len > 0 && *s != 0 && i < 126) { - if (*s > 255) { - return false; - } - buf[i++] = *s++; - len--; - } - - if (len > 0) { - return false; - } - if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') { - return false; - } - - buf[i] = 0; - const char* end; - float f = strtof(buf, (char**)&end); - - if (*end != 0 && !isspace((unsigned char)*end)) { - // Might be a unit... - float scale; - if (parse_unit(end, outValue, &scale, &end)) { - f *= scale; - const bool neg = f < 0; - if (neg) f = -f; - uint64_t bits = (uint64_t)(f*(1<<23)+.5f); - uint32_t radix; - uint32_t shift; - if ((bits&0x7fffff) == 0) { - // Always use 23p0 if there is no fraction, just to make - // things easier to read. - radix = Res_value::COMPLEX_RADIX_23p0; - shift = 23; - } else if ((bits&0xffffffffff800000LL) == 0) { - // Magnitude is zero -- can fit in 0 bits of precision. - radix = Res_value::COMPLEX_RADIX_0p23; - shift = 0; - } else if ((bits&0xffffffff80000000LL) == 0) { - // Magnitude can fit in 8 bits of precision. - radix = Res_value::COMPLEX_RADIX_8p15; - shift = 8; - } else if ((bits&0xffffff8000000000LL) == 0) { - // Magnitude can fit in 16 bits of precision. - radix = Res_value::COMPLEX_RADIX_16p7; - shift = 16; - } else { - // Magnitude needs entire range, so no fractional part. - radix = Res_value::COMPLEX_RADIX_23p0; - shift = 23; - } - int32_t mantissa = (int32_t)( - (bits>>shift) & Res_value::COMPLEX_MANTISSA_MASK); - if (neg) { - mantissa = (-mantissa) & Res_value::COMPLEX_MANTISSA_MASK; - } - outValue->data |= - (radix<data); - return true; - } - return false; - } - - while (*end != 0 && isspace((unsigned char)*end)) { - end++; - } - - if (*end == 0) { - if (outValue) { - outValue->dataType = outValue->TYPE_FLOAT; - *(float*)(&outValue->data) = f; - return true; - } - } - - return false; -} - -bool ResTable::stringToValue(Res_value* outValue, String16* outString, - const char16_t* s, size_t len, - bool preserveSpaces, bool coerceType, - uint32_t attrID, - const String16* defType, - const String16* defPackage, - Accessor* accessor, - void* accessorCookie, - uint32_t attrType, - bool enforcePrivate) const -{ - bool localizationSetting = accessor != NULL && accessor->getLocalizationSetting(); - const char* errorMsg = NULL; - - outValue->size = sizeof(Res_value); - outValue->res0 = 0; - - // First strip leading/trailing whitespace. Do this before handling - // escapes, so they can be used to force whitespace into the string. - if (!preserveSpaces) { - while (len > 0 && isspace16(*s)) { - s++; - len--; - } - while (len > 0 && isspace16(s[len-1])) { - len--; - } - // If the string ends with '\', then we keep the space after it. - if (len > 0 && s[len-1] == '\\' && s[len] != 0) { - len++; - } - } - - //printf("Value for: %s\n", String8(s, len).string()); - - uint32_t l10nReq = ResTable_map::L10N_NOT_REQUIRED; - uint32_t attrMin = 0x80000000, attrMax = 0x7fffffff; - bool fromAccessor = false; - if (attrID != 0 && !Res_INTERNALID(attrID)) { - const ssize_t p = getResourcePackageIndex(attrID); - const bag_entry* bag; - ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1; - //printf("For attr 0x%08x got bag of %d\n", attrID, cnt); - if (cnt >= 0) { - while (cnt > 0) { - //printf("Entry 0x%08x = 0x%08x\n", bag->map.name.ident, bag->map.value.data); - switch (bag->map.name.ident) { - case ResTable_map::ATTR_TYPE: - attrType = bag->map.value.data; - break; - case ResTable_map::ATTR_MIN: - attrMin = bag->map.value.data; - break; - case ResTable_map::ATTR_MAX: - attrMax = bag->map.value.data; - break; - case ResTable_map::ATTR_L10N: - l10nReq = bag->map.value.data; - break; - } - bag++; - cnt--; - } - unlockBag(bag); - } else if (accessor && accessor->getAttributeType(attrID, &attrType)) { - fromAccessor = true; - if (attrType == ResTable_map::TYPE_ENUM - || attrType == ResTable_map::TYPE_FLAGS - || attrType == ResTable_map::TYPE_INTEGER) { - accessor->getAttributeMin(attrID, &attrMin); - accessor->getAttributeMax(attrID, &attrMax); - } - if (localizationSetting) { - l10nReq = accessor->getAttributeL10N(attrID); - } - } - } - - const bool canStringCoerce = - coerceType && (attrType&ResTable_map::TYPE_STRING) != 0; - - if (*s == '@') { - outValue->dataType = outValue->TYPE_REFERENCE; - - // Note: we don't check attrType here because the reference can - // be to any other type; we just need to count on the client making - // sure the referenced type is correct. - - //printf("Looking up ref: %s\n", String8(s, len).string()); - - // It's a reference! - if (len == 5 && s[1]=='n' && s[2]=='u' && s[3]=='l' && s[4]=='l') { - outValue->data = 0; - return true; - } else { - bool createIfNotFound = false; - const char16_t* resourceRefName; - int resourceNameLen; - if (len > 2 && s[1] == '+') { - createIfNotFound = true; - resourceRefName = s + 2; - resourceNameLen = len - 2; - } else if (len > 2 && s[1] == '*') { - enforcePrivate = false; - resourceRefName = s + 2; - resourceNameLen = len - 2; - } else { - createIfNotFound = false; - resourceRefName = s + 1; - resourceNameLen = len - 1; - } - String16 package, type, name; - if (!expandResourceRef(resourceRefName,resourceNameLen, &package, &type, &name, - defType, defPackage, &errorMsg)) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, errorMsg); - } - return false; - } - - uint32_t specFlags = 0; - uint32_t rid = identifierForName(name.string(), name.size(), type.string(), - type.size(), package.string(), package.size(), &specFlags); - if (rid != 0) { - if (enforcePrivate) { - if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Resource is not public."); - } - return false; - } - } - if (!accessor) { - outValue->data = rid; - return true; - } - rid = Res_MAKEID( - accessor->getRemappedPackage(Res_GETPACKAGE(rid)), - Res_GETTYPE(rid), Res_GETENTRY(rid)); - TABLE_NOISY(printf("Incl %s:%s/%s: 0x%08x\n", - String8(package).string(), String8(type).string(), - String8(name).string(), rid)); - outValue->data = rid; - return true; - } - - if (accessor) { - uint32_t rid = accessor->getCustomResourceWithCreation(package, type, name, - createIfNotFound); - if (rid != 0) { - TABLE_NOISY(printf("Pckg %s:%s/%s: 0x%08x\n", - String8(package).string(), String8(type).string(), - String8(name).string(), rid)); - outValue->data = rid; - return true; - } - } - } - - if (accessor != NULL) { - accessor->reportError(accessorCookie, "No resource found that matches the given name"); - } - return false; - } - - // if we got to here, and localization is required and it's not a reference, - // complain and bail. - if (l10nReq == ResTable_map::L10N_SUGGESTED) { - if (localizationSetting) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "This attribute must be localized."); - } - } - } - - if (*s == '#') { - // It's a color! Convert to an integer of the form 0xaarrggbb. - uint32_t color = 0; - bool error = false; - if (len == 4) { - outValue->dataType = outValue->TYPE_INT_COLOR_RGB4; - color |= 0xFF000000; - color |= get_hex(s[1], &error) << 20; - color |= get_hex(s[1], &error) << 16; - color |= get_hex(s[2], &error) << 12; - color |= get_hex(s[2], &error) << 8; - color |= get_hex(s[3], &error) << 4; - color |= get_hex(s[3], &error); - } else if (len == 5) { - outValue->dataType = outValue->TYPE_INT_COLOR_ARGB4; - color |= get_hex(s[1], &error) << 28; - color |= get_hex(s[1], &error) << 24; - color |= get_hex(s[2], &error) << 20; - color |= get_hex(s[2], &error) << 16; - color |= get_hex(s[3], &error) << 12; - color |= get_hex(s[3], &error) << 8; - color |= get_hex(s[4], &error) << 4; - color |= get_hex(s[4], &error); - } else if (len == 7) { - outValue->dataType = outValue->TYPE_INT_COLOR_RGB8; - color |= 0xFF000000; - color |= get_hex(s[1], &error) << 20; - color |= get_hex(s[2], &error) << 16; - color |= get_hex(s[3], &error) << 12; - color |= get_hex(s[4], &error) << 8; - color |= get_hex(s[5], &error) << 4; - color |= get_hex(s[6], &error); - } else if (len == 9) { - outValue->dataType = outValue->TYPE_INT_COLOR_ARGB8; - color |= get_hex(s[1], &error) << 28; - color |= get_hex(s[2], &error) << 24; - color |= get_hex(s[3], &error) << 20; - color |= get_hex(s[4], &error) << 16; - color |= get_hex(s[5], &error) << 12; - color |= get_hex(s[6], &error) << 8; - color |= get_hex(s[7], &error) << 4; - color |= get_hex(s[8], &error); - } else { - error = true; - } - if (!error) { - if ((attrType&ResTable_map::TYPE_COLOR) == 0) { - if (!canStringCoerce) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, - "Color types not allowed"); - } - return false; - } - } else { - outValue->data = color; - //printf("Color input=%s, output=0x%x\n", String8(s, len).string(), color); - return true; - } - } else { - if ((attrType&ResTable_map::TYPE_COLOR) != 0) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Color value not valid --" - " must be #rgb, #argb, #rrggbb, or #aarrggbb"); - } - #if 0 - fprintf(stderr, "%s: Color ID %s value %s is not valid\n", - "Resource File", //(const char*)in->getPrintableSource(), - String8(*curTag).string(), - String8(s, len).string()); - #endif - return false; - } - } - } - - if (*s == '?') { - outValue->dataType = outValue->TYPE_ATTRIBUTE; - - // Note: we don't check attrType here because the reference can - // be to any other type; we just need to count on the client making - // sure the referenced type is correct. - - //printf("Looking up attr: %s\n", String8(s, len).string()); - - static const String16 attr16("attr"); - String16 package, type, name; - if (!expandResourceRef(s+1, len-1, &package, &type, &name, - &attr16, defPackage, &errorMsg)) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, errorMsg); - } - return false; - } - - //printf("Pkg: %s, Type: %s, Name: %s\n", - // String8(package).string(), String8(type).string(), - // String8(name).string()); - uint32_t specFlags = 0; - uint32_t rid = - identifierForName(name.string(), name.size(), - type.string(), type.size(), - package.string(), package.size(), &specFlags); - if (rid != 0) { - if (enforcePrivate) { - if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Attribute is not public."); - } - return false; - } - } - if (!accessor) { - outValue->data = rid; - return true; - } - rid = Res_MAKEID( - accessor->getRemappedPackage(Res_GETPACKAGE(rid)), - Res_GETTYPE(rid), Res_GETENTRY(rid)); - //printf("Incl %s:%s/%s: 0x%08x\n", - // String8(package).string(), String8(type).string(), - // String8(name).string(), rid); - outValue->data = rid; - return true; - } - - if (accessor) { - uint32_t rid = accessor->getCustomResource(package, type, name); - if (rid != 0) { - //printf("Mine %s:%s/%s: 0x%08x\n", - // String8(package).string(), String8(type).string(), - // String8(name).string(), rid); - outValue->data = rid; - return true; - } - } - - if (accessor != NULL) { - accessor->reportError(accessorCookie, "No resource found that matches the given name"); - } - return false; - } - - if (stringToInt(s, len, outValue)) { - if ((attrType&ResTable_map::TYPE_INTEGER) == 0) { - // If this type does not allow integers, but does allow floats, - // fall through on this error case because the float type should - // be able to accept any integer value. - if (!canStringCoerce && (attrType&ResTable_map::TYPE_FLOAT) == 0) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Integer types not allowed"); - } - return false; - } - } else { - if (((int32_t)outValue->data) < ((int32_t)attrMin) - || ((int32_t)outValue->data) > ((int32_t)attrMax)) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Integer value out of range"); - } - return false; - } - return true; - } - } - - if (stringToFloat(s, len, outValue)) { - if (outValue->dataType == Res_value::TYPE_DIMENSION) { - if ((attrType&ResTable_map::TYPE_DIMENSION) != 0) { - return true; - } - if (!canStringCoerce) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Dimension types not allowed"); - } - return false; - } - } else if (outValue->dataType == Res_value::TYPE_FRACTION) { - if ((attrType&ResTable_map::TYPE_FRACTION) != 0) { - return true; - } - if (!canStringCoerce) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Fraction types not allowed"); - } - return false; - } - } else if ((attrType&ResTable_map::TYPE_FLOAT) == 0) { - if (!canStringCoerce) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Float types not allowed"); - } - return false; - } - } else { - return true; - } - } - - if (len == 4) { - if ((s[0] == 't' || s[0] == 'T') && - (s[1] == 'r' || s[1] == 'R') && - (s[2] == 'u' || s[2] == 'U') && - (s[3] == 'e' || s[3] == 'E')) { - if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) { - if (!canStringCoerce) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Boolean types not allowed"); - } - return false; - } - } else { - outValue->dataType = outValue->TYPE_INT_BOOLEAN; - outValue->data = (uint32_t)-1; - return true; - } - } - } - - if (len == 5) { - if ((s[0] == 'f' || s[0] == 'F') && - (s[1] == 'a' || s[1] == 'A') && - (s[2] == 'l' || s[2] == 'L') && - (s[3] == 's' || s[3] == 'S') && - (s[4] == 'e' || s[4] == 'E')) { - if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) { - if (!canStringCoerce) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Boolean types not allowed"); - } - return false; - } - } else { - outValue->dataType = outValue->TYPE_INT_BOOLEAN; - outValue->data = 0; - return true; - } - } - } - - if ((attrType&ResTable_map::TYPE_ENUM) != 0) { - const ssize_t p = getResourcePackageIndex(attrID); - const bag_entry* bag; - ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1; - //printf("Got %d for enum\n", cnt); - if (cnt >= 0) { - resource_name rname; - while (cnt > 0) { - if (!Res_INTERNALID(bag->map.name.ident)) { - //printf("Trying attr #%08x\n", bag->map.name.ident); - if (getResourceName(bag->map.name.ident, false, &rname)) { - #if 0 - printf("Matching %s against %s (0x%08x)\n", - String8(s, len).string(), - String8(rname.name, rname.nameLen).string(), - bag->map.name.ident); - #endif - if (strzcmp16(s, len, rname.name, rname.nameLen) == 0) { - outValue->dataType = bag->map.value.dataType; - outValue->data = bag->map.value.data; - unlockBag(bag); - return true; - } - } - - } - bag++; - cnt--; - } - unlockBag(bag); - } - - if (fromAccessor) { - if (accessor->getAttributeEnum(attrID, s, len, outValue)) { - return true; - } - } - } - - if ((attrType&ResTable_map::TYPE_FLAGS) != 0) { - const ssize_t p = getResourcePackageIndex(attrID); - const bag_entry* bag; - ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1; - //printf("Got %d for flags\n", cnt); - if (cnt >= 0) { - bool failed = false; - resource_name rname; - outValue->dataType = Res_value::TYPE_INT_HEX; - outValue->data = 0; - const char16_t* end = s + len; - const char16_t* pos = s; - while (pos < end && !failed) { - const char16_t* start = pos; - pos++; - while (pos < end && *pos != '|') { - pos++; - } - //printf("Looking for: %s\n", String8(start, pos-start).string()); - const bag_entry* bagi = bag; - ssize_t i; - for (i=0; imap.name.ident)) { - //printf("Trying attr #%08x\n", bagi->map.name.ident); - if (getResourceName(bagi->map.name.ident, false, &rname)) { - #if 0 - printf("Matching %s against %s (0x%08x)\n", - String8(start,pos-start).string(), - String8(rname.name, rname.nameLen).string(), - bagi->map.name.ident); - #endif - if (strzcmp16(start, pos-start, rname.name, rname.nameLen) == 0) { - outValue->data |= bagi->map.value.data; - break; - } - } - } - } - if (i >= cnt) { - // Didn't find this flag identifier. - failed = true; - } - if (pos < end) { - pos++; - } - } - unlockBag(bag); - if (!failed) { - //printf("Final flag value: 0x%lx\n", outValue->data); - return true; - } - } - - - if (fromAccessor) { - if (accessor->getAttributeFlags(attrID, s, len, outValue)) { - //printf("Final flag value: 0x%lx\n", outValue->data); - return true; - } - } - } - - if ((attrType&ResTable_map::TYPE_STRING) == 0) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "String types not allowed"); - } - return false; - } - - // Generic string handling... - outValue->dataType = outValue->TYPE_STRING; - if (outString) { - bool failed = collectString(outString, s, len, preserveSpaces, &errorMsg); - if (accessor != NULL) { - accessor->reportError(accessorCookie, errorMsg); - } - return failed; - } - - return true; -} - -bool ResTable::collectString(String16* outString, - const char16_t* s, size_t len, - bool preserveSpaces, - const char** outErrorMsg, - bool append) -{ - String16 tmp; - - char quoted = 0; - const char16_t* p = s; - while (p < (s+len)) { - while (p < (s+len)) { - const char16_t c = *p; - if (c == '\\') { - break; - } - if (!preserveSpaces) { - if (quoted == 0 && isspace16(c) - && (c != ' ' || isspace16(*(p+1)))) { - break; - } - if (c == '"' && (quoted == 0 || quoted == '"')) { - break; - } - if (c == '\'' && (quoted == 0 || quoted == '\'')) { - /* - * In practice, when people write ' instead of \' - * in a string, they are doing it by accident - * instead of really meaning to use ' as a quoting - * character. Warn them so they don't lose it. - */ - if (outErrorMsg) { - *outErrorMsg = "Apostrophe not preceded by \\"; - } - return false; - } - } - p++; - } - if (p < (s+len)) { - if (p > s) { - tmp.append(String16(s, p-s)); - } - if (!preserveSpaces && (*p == '"' || *p == '\'')) { - if (quoted == 0) { - quoted = *p; - } else { - quoted = 0; - } - p++; - } else if (!preserveSpaces && isspace16(*p)) { - // Space outside of a quote -- consume all spaces and - // leave a single plain space char. - tmp.append(String16(" ")); - p++; - while (p < (s+len) && isspace16(*p)) { - p++; - } - } else if (*p == '\\') { - p++; - if (p < (s+len)) { - switch (*p) { - case 't': - tmp.append(String16("\t")); - break; - case 'n': - tmp.append(String16("\n")); - break; - case '#': - tmp.append(String16("#")); - break; - case '@': - tmp.append(String16("@")); - break; - case '?': - tmp.append(String16("?")); - break; - case '"': - tmp.append(String16("\"")); - break; - case '\'': - tmp.append(String16("'")); - break; - case '\\': - tmp.append(String16("\\")); - break; - case 'u': - { - char16_t chr = 0; - int i = 0; - while (i < 4 && p[1] != 0) { - p++; - i++; - int c; - if (*p >= '0' && *p <= '9') { - c = *p - '0'; - } else if (*p >= 'a' && *p <= 'f') { - c = *p - 'a' + 10; - } else if (*p >= 'A' && *p <= 'F') { - c = *p - 'A' + 10; - } else { - if (outErrorMsg) { - *outErrorMsg = "Bad character in \\u unicode escape sequence"; - } - return false; - } - chr = (chr<<4) | c; - } - tmp.append(String16(&chr, 1)); - } break; - default: - // ignore unknown escape chars. - break; - } - p++; - } - } - len -= (p-s); - s = p; - } - } - - if (tmp.size() != 0) { - if (len > 0) { - tmp.append(String16(s, len)); - } - if (append) { - outString->append(tmp); - } else { - outString->setTo(tmp); - } - } else { - if (append) { - outString->append(String16(s, len)); - } else { - outString->setTo(s, len); - } - } - - return true; -} - -size_t ResTable::getBasePackageCount() const -{ - if (mError != NO_ERROR) { - return 0; - } - return mPackageGroups.size(); -} - -const char16_t* ResTable::getBasePackageName(size_t idx) const -{ - if (mError != NO_ERROR) { - return 0; - } - LOG_FATAL_IF(idx >= mPackageGroups.size(), - "Requested package index %d past package count %d", - (int)idx, (int)mPackageGroups.size()); - return mPackageGroups[idx]->name.string(); -} - -uint32_t ResTable::getBasePackageId(size_t idx) const -{ - if (mError != NO_ERROR) { - return 0; - } - LOG_FATAL_IF(idx >= mPackageGroups.size(), - "Requested package index %d past package count %d", - (int)idx, (int)mPackageGroups.size()); - return mPackageGroups[idx]->id; -} - -size_t ResTable::getTableCount() const -{ - return mHeaders.size(); -} - -const ResStringPool* ResTable::getTableStringBlock(size_t index) const -{ - return &mHeaders[index]->values; -} - -void* ResTable::getTableCookie(size_t index) const -{ - return mHeaders[index]->cookie; -} - -void ResTable::getConfigurations(Vector* configs) const -{ - const size_t I = mPackageGroups.size(); - for (size_t i=0; ipackages.size(); - for (size_t j=0; jpackages[j]; - const size_t K = package->types.size(); - for (size_t k=0; ktypes[k]; - if (type == NULL) continue; - const size_t L = type->configs.size(); - for (size_t l=0; lconfigs[l]; - const ResTable_config* cfg = &config->config; - // only insert unique - const size_t M = configs->size(); - size_t m; - for (m=0; madd(*cfg); - } - } - } - } - } -} - -void ResTable::getLocales(Vector* locales) const -{ - Vector configs; - ALOGV("calling getConfigurations"); - getConfigurations(&configs); - ALOGV("called getConfigurations size=%d", (int)configs.size()); - const size_t I = configs.size(); - for (size_t i=0; isize(); - size_t j; - for (j=0; jadd(String8(locale)); - } - } -} - -ssize_t ResTable::getEntry( - const Package* package, int typeIndex, int entryIndex, - const ResTable_config* config, - const ResTable_type** outType, const ResTable_entry** outEntry, - const Type** outTypeClass) const -{ - ALOGV("Getting entry from package %p\n", package); - const ResTable_package* const pkg = package->package; - - const Type* allTypes = package->getType(typeIndex); - ALOGV("allTypes=%p\n", allTypes); - if (allTypes == NULL) { - ALOGV("Skipping entry type index 0x%02x because type is NULL!\n", typeIndex); - return 0; - } - - if ((size_t)entryIndex >= allTypes->entryCount) { - ALOGW("getEntry failing because entryIndex %d is beyond type entryCount %d", - entryIndex, (int)allTypes->entryCount); - return BAD_TYPE; - } - - const ResTable_type* type = NULL; - uint32_t offset = ResTable_type::NO_ENTRY; - ResTable_config bestConfig; - memset(&bestConfig, 0, sizeof(bestConfig)); // make the compiler shut up - - const size_t NT = allTypes->configs.size(); - for (size_t i=0; iconfigs[i]; - if (thisType == NULL) continue; - - ResTable_config thisConfig; - thisConfig.copyFromDtoH(thisType->config); - - TABLE_GETENTRY(ALOGI("Match entry 0x%x in type 0x%x (sz 0x%x): %s\n", - entryIndex, typeIndex+1, dtohl(thisType->config.size), - thisConfig.toString().string())); - - // Check to make sure this one is valid for the current parameters. - if (config && !thisConfig.match(*config)) { - TABLE_GETENTRY(ALOGI("Does not match config!\n")); - continue; - } - - // Check if there is the desired entry in this type. - - const uint8_t* const end = ((const uint8_t*)thisType) - + dtohl(thisType->header.size); - const uint32_t* const eindex = (const uint32_t*) - (((const uint8_t*)thisType) + dtohs(thisType->header.headerSize)); - - uint32_t thisOffset = dtohl(eindex[entryIndex]); - if (thisOffset == ResTable_type::NO_ENTRY) { - TABLE_GETENTRY(ALOGI("Skipping because it is not defined!\n")); - continue; - } - - if (type != NULL) { - // Check if this one is less specific than the last found. If so, - // we will skip it. We check starting with things we most care - // about to those we least care about. - if (!thisConfig.isBetterThan(bestConfig, config)) { - TABLE_GETENTRY(ALOGI("This config is worse than last!\n")); - continue; - } - } - - type = thisType; - offset = thisOffset; - bestConfig = thisConfig; - TABLE_GETENTRY(ALOGI("Best entry so far -- using it!\n")); - if (!config) break; - } - - if (type == NULL) { - TABLE_GETENTRY(ALOGI("No value found for requested entry!\n")); - return BAD_INDEX; - } - - offset += dtohl(type->entriesStart); - TABLE_NOISY(aout << "Looking in resource table " << package->header->header - << ", typeOff=" - << (void*)(((const char*)type)-((const char*)package->header->header)) - << ", offset=" << (void*)offset << endl); - - if (offset > (dtohl(type->header.size)-sizeof(ResTable_entry))) { - ALOGW("ResTable_entry at 0x%x is beyond type chunk data 0x%x", - offset, dtohl(type->header.size)); - return BAD_TYPE; - } - if ((offset&0x3) != 0) { - ALOGW("ResTable_entry at 0x%x is not on an integer boundary", - offset); - return BAD_TYPE; - } - - const ResTable_entry* const entry = (const ResTable_entry*) - (((const uint8_t*)type) + offset); - if (dtohs(entry->size) < sizeof(*entry)) { - ALOGW("ResTable_entry size 0x%x is too small", dtohs(entry->size)); - return BAD_TYPE; - } - - *outType = type; - *outEntry = entry; - if (outTypeClass != NULL) { - *outTypeClass = allTypes; - } - return offset + dtohs(entry->size); -} - -status_t ResTable::parsePackage(const ResTable_package* const pkg, - const Header* const header, uint32_t idmap_id) -{ - const uint8_t* base = (const uint8_t*)pkg; - status_t err = validate_chunk(&pkg->header, sizeof(*pkg), - header->dataEnd, "ResTable_package"); - if (err != NO_ERROR) { - return (mError=err); - } - - const size_t pkgSize = dtohl(pkg->header.size); - - if (dtohl(pkg->typeStrings) >= pkgSize) { - ALOGW("ResTable_package type strings at %p are past chunk size %p.", - (void*)dtohl(pkg->typeStrings), (void*)pkgSize); - return (mError=BAD_TYPE); - } - if ((dtohl(pkg->typeStrings)&0x3) != 0) { - ALOGW("ResTable_package type strings at %p is not on an integer boundary.", - (void*)dtohl(pkg->typeStrings)); - return (mError=BAD_TYPE); - } - if (dtohl(pkg->keyStrings) >= pkgSize) { - ALOGW("ResTable_package key strings at %p are past chunk size %p.", - (void*)dtohl(pkg->keyStrings), (void*)pkgSize); - return (mError=BAD_TYPE); - } - if ((dtohl(pkg->keyStrings)&0x3) != 0) { - ALOGW("ResTable_package key strings at %p is not on an integer boundary.", - (void*)dtohl(pkg->keyStrings)); - return (mError=BAD_TYPE); - } - - Package* package = NULL; - PackageGroup* group = NULL; - uint32_t id = idmap_id != 0 ? idmap_id : dtohl(pkg->id); - // If at this point id == 0, pkg is an overlay package without a - // corresponding idmap. During regular usage, overlay packages are - // always loaded alongside their idmaps, but during idmap creation - // the package is temporarily loaded by itself. - if (id < 256) { - - package = new Package(this, header, pkg); - if (package == NULL) { - return (mError=NO_MEMORY); - } - - size_t idx = mPackageMap[id]; - if (idx == 0) { - idx = mPackageGroups.size()+1; - - char16_t tmpName[sizeof(pkg->name)/sizeof(char16_t)]; - strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(char16_t)); - group = new PackageGroup(this, String16(tmpName), id); - if (group == NULL) { - delete package; - return (mError=NO_MEMORY); - } - - err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings), - header->dataEnd-(base+dtohl(pkg->typeStrings))); - if (err != NO_ERROR) { - delete group; - delete package; - return (mError=err); - } - err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings), - header->dataEnd-(base+dtohl(pkg->keyStrings))); - if (err != NO_ERROR) { - delete group; - delete package; - return (mError=err); - } - - //printf("Adding new package id %d at index %d\n", id, idx); - err = mPackageGroups.add(group); - if (err < NO_ERROR) { - return (mError=err); - } - group->basePackage = package; - - mPackageMap[id] = (uint8_t)idx; - } else { - group = mPackageGroups.itemAt(idx-1); - if (group == NULL) { - return (mError=UNKNOWN_ERROR); - } - } - err = group->packages.add(package); - if (err < NO_ERROR) { - return (mError=err); - } - } else { - LOG_ALWAYS_FATAL("Package id out of range"); - return NO_ERROR; - } - - - // Iterate through all chunks. - size_t curPackage = 0; - - const ResChunk_header* chunk = - (const ResChunk_header*)(((const uint8_t*)pkg) - + dtohs(pkg->header.headerSize)); - const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size); - while (((const uint8_t*)chunk) <= (endPos-sizeof(ResChunk_header)) && - ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) { - TABLE_NOISY(ALOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n", - dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size), - (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)))); - const size_t csize = dtohl(chunk->size); - const uint16_t ctype = dtohs(chunk->type); - if (ctype == RES_TABLE_TYPE_SPEC_TYPE) { - const ResTable_typeSpec* typeSpec = (const ResTable_typeSpec*)(chunk); - err = validate_chunk(&typeSpec->header, sizeof(*typeSpec), - endPos, "ResTable_typeSpec"); - if (err != NO_ERROR) { - return (mError=err); - } - - const size_t typeSpecSize = dtohl(typeSpec->header.size); - - LOAD_TABLE_NOISY(printf("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n", - (void*)(base-(const uint8_t*)chunk), - dtohs(typeSpec->header.type), - dtohs(typeSpec->header.headerSize), - (void*)typeSize)); - // look for block overrun or int overflow when multiplying by 4 - if ((dtohl(typeSpec->entryCount) > (INT32_MAX/sizeof(uint32_t)) - || dtohs(typeSpec->header.headerSize)+(sizeof(uint32_t)*dtohl(typeSpec->entryCount)) - > typeSpecSize)) { - ALOGW("ResTable_typeSpec entry index to %p extends beyond chunk end %p.", - (void*)(dtohs(typeSpec->header.headerSize) - +(sizeof(uint32_t)*dtohl(typeSpec->entryCount))), - (void*)typeSpecSize); - return (mError=BAD_TYPE); - } - - if (typeSpec->id == 0) { - ALOGW("ResTable_type has an id of 0."); - return (mError=BAD_TYPE); - } - - while (package->types.size() < typeSpec->id) { - package->types.add(NULL); - } - Type* t = package->types[typeSpec->id-1]; - if (t == NULL) { - t = new Type(header, package, dtohl(typeSpec->entryCount)); - package->types.editItemAt(typeSpec->id-1) = t; - } else if (dtohl(typeSpec->entryCount) != t->entryCount) { - ALOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d", - (int)dtohl(typeSpec->entryCount), (int)t->entryCount); - return (mError=BAD_TYPE); - } - t->typeSpecFlags = (const uint32_t*)( - ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize)); - t->typeSpec = typeSpec; - - } else if (ctype == RES_TABLE_TYPE_TYPE) { - const ResTable_type* type = (const ResTable_type*)(chunk); - err = validate_chunk(&type->header, sizeof(*type)-sizeof(ResTable_config)+4, - endPos, "ResTable_type"); - if (err != NO_ERROR) { - return (mError=err); - } - - const size_t typeSize = dtohl(type->header.size); - - LOAD_TABLE_NOISY(printf("Type off %p: type=0x%x, headerSize=0x%x, size=%p\n", - (void*)(base-(const uint8_t*)chunk), - dtohs(type->header.type), - dtohs(type->header.headerSize), - (void*)typeSize)); - if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*dtohl(type->entryCount)) - > typeSize) { - ALOGW("ResTable_type entry index to %p extends beyond chunk end %p.", - (void*)(dtohs(type->header.headerSize) - +(sizeof(uint32_t)*dtohl(type->entryCount))), - (void*)typeSize); - return (mError=BAD_TYPE); - } - if (dtohl(type->entryCount) != 0 - && dtohl(type->entriesStart) > (typeSize-sizeof(ResTable_entry))) { - ALOGW("ResTable_type entriesStart at %p extends beyond chunk end %p.", - (void*)dtohl(type->entriesStart), (void*)typeSize); - return (mError=BAD_TYPE); - } - if (type->id == 0) { - ALOGW("ResTable_type has an id of 0."); - return (mError=BAD_TYPE); - } - - while (package->types.size() < type->id) { - package->types.add(NULL); - } - Type* t = package->types[type->id-1]; - if (t == NULL) { - t = new Type(header, package, dtohl(type->entryCount)); - package->types.editItemAt(type->id-1) = t; - } else if (dtohl(type->entryCount) != t->entryCount) { - ALOGW("ResTable_type entry count inconsistent: given %d, previously %d", - (int)dtohl(type->entryCount), (int)t->entryCount); - return (mError=BAD_TYPE); - } - - TABLE_GETENTRY( - ResTable_config thisConfig; - thisConfig.copyFromDtoH(type->config); - ALOGI("Adding config to type %d: %s\n", - type->id, thisConfig.toString().string())); - t->configs.add(type); - } else { - status_t err = validate_chunk(chunk, sizeof(ResChunk_header), - endPos, "ResTable_package:unknown"); - if (err != NO_ERROR) { - return (mError=err); - } - } - chunk = (const ResChunk_header*) - (((const uint8_t*)chunk) + csize); - } - - if (group->typeCount == 0) { - group->typeCount = package->types.size(); - } - - return NO_ERROR; -} - -status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, uint32_t overlayCrc, - void** outData, size_t* outSize) const -{ - // see README for details on the format of map - if (mPackageGroups.size() == 0) { - return UNKNOWN_ERROR; - } - if (mPackageGroups[0]->packages.size() == 0) { - return UNKNOWN_ERROR; - } - - Vector > map; - const PackageGroup* pg = mPackageGroups[0]; - const Package* pkg = pg->packages[0]; - size_t typeCount = pkg->types.size(); - // starting size is header + first item (number of types in map) - *outSize = (IDMAP_HEADER_SIZE + 1) * sizeof(uint32_t); - const String16 overlayPackage(overlay.mPackageGroups[0]->packages[0]->package->name); - const uint32_t pkg_id = pkg->package->id << 24; - - for (size_t typeIndex = 0; typeIndex < typeCount; ++typeIndex) { - ssize_t first = -1; - ssize_t last = -1; - const Type* typeConfigs = pkg->getType(typeIndex); - ssize_t mapIndex = map.add(); - if (mapIndex < 0) { - return NO_MEMORY; - } - Vector& vector = map.editItemAt(mapIndex); - for (size_t entryIndex = 0; entryIndex < typeConfigs->entryCount; ++entryIndex) { - uint32_t resID = pkg_id - | (0x00ff0000 & ((typeIndex+1)<<16)) - | (0x0000ffff & (entryIndex)); - resource_name resName; - if (!this->getResourceName(resID, true, &resName)) { - ALOGW("idmap: resource 0x%08x has spec but lacks values, skipping\n", resID); - // add dummy value, or trimming leading/trailing zeroes later will fail - vector.push(0); - continue; - } - - const String16 overlayType(resName.type, resName.typeLen); - const String16 overlayName(resName.name, resName.nameLen); - uint32_t overlayResID = overlay.identifierForName(overlayName.string(), - overlayName.size(), - overlayType.string(), - overlayType.size(), - overlayPackage.string(), - overlayPackage.size()); - if (overlayResID != 0) { - overlayResID = pkg_id | (0x00ffffff & overlayResID); - last = Res_GETENTRY(resID); - if (first == -1) { - first = Res_GETENTRY(resID); - } - } - vector.push(overlayResID); -#if 0 - if (overlayResID != 0) { - ALOGD("%s/%s 0x%08x -> 0x%08x\n", - String8(String16(resName.type)).string(), - String8(String16(resName.name)).string(), - resID, overlayResID); - } -#endif - } - - if (first != -1) { - // shave off trailing entries which lack overlay values - const size_t last_past_one = last + 1; - if (last_past_one < vector.size()) { - vector.removeItemsAt(last_past_one, vector.size() - last_past_one); - } - // shave off leading entries which lack overlay values - vector.removeItemsAt(0, first); - // store offset to first overlaid resource ID of this type - vector.insertAt((uint32_t)first, 0, 1); - // reserve space for number and offset of entries, and the actual entries - *outSize += (2 + vector.size()) * sizeof(uint32_t); - } else { - // no entries of current type defined in overlay package - vector.clear(); - // reserve space for type offset - *outSize += 1 * sizeof(uint32_t); - } - } - - if ((*outData = malloc(*outSize)) == NULL) { - return NO_MEMORY; - } - uint32_t* data = (uint32_t*)*outData; - *data++ = htodl(IDMAP_MAGIC); - *data++ = htodl(originalCrc); - *data++ = htodl(overlayCrc); - const size_t mapSize = map.size(); - *data++ = htodl(mapSize); - size_t offset = mapSize; - for (size_t i = 0; i < mapSize; ++i) { - const Vector& vector = map.itemAt(i); - const size_t N = vector.size(); - if (N == 0) { - *data++ = htodl(0); - } else { - offset++; - *data++ = htodl(offset); - offset += N; - } - } - for (size_t i = 0; i < mapSize; ++i) { - const Vector& vector = map.itemAt(i); - const size_t N = vector.size(); - if (N == 0) { - continue; - } - if (N == 1) { // vector expected to hold (offset) + (N > 0 entries) - ALOGW("idmap: type %d supposedly has entries, but no entries found\n", i); - return UNKNOWN_ERROR; - } - *data++ = htodl(N - 1); // do not count the offset (which is vector's first element) - for (size_t j = 0; j < N; ++j) { - const uint32_t& overlayResID = vector.itemAt(j); - *data++ = htodl(overlayResID); - } - } - - return NO_ERROR; -} - -bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes, - uint32_t* pOriginalCrc, uint32_t* pOverlayCrc) -{ - const uint32_t* map = (const uint32_t*)idmap; - if (!assertIdmapHeader(map, sizeBytes)) { - return false; - } - *pOriginalCrc = map[1]; - *pOverlayCrc = map[2]; - return true; -} - - -#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string()) - -#define CHAR16_ARRAY_EQ(constant, var, len) \ - ((len == (sizeof(constant)/sizeof(constant[0]))) && (0 == memcmp((var), (constant), (len)))) - -static void print_complex(uint32_t complex, bool isFraction) -{ - const float MANTISSA_MULT = - 1.0f / (1<>Res_value::COMPLEX_RADIX_SHIFT) - & Res_value::COMPLEX_RADIX_MASK]; - printf("%f", value); - - if (!isFraction) { - switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) { - case Res_value::COMPLEX_UNIT_PX: printf("px"); break; - case Res_value::COMPLEX_UNIT_DIP: printf("dp"); break; - case Res_value::COMPLEX_UNIT_SP: printf("sp"); break; - case Res_value::COMPLEX_UNIT_PT: printf("pt"); break; - case Res_value::COMPLEX_UNIT_IN: printf("in"); break; - case Res_value::COMPLEX_UNIT_MM: printf("mm"); break; - default: printf(" (unknown unit)"); break; - } - } else { - switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) { - case Res_value::COMPLEX_UNIT_FRACTION: printf("%%"); break; - case Res_value::COMPLEX_UNIT_FRACTION_PARENT: printf("%%p"); break; - default: printf(" (unknown unit)"); break; - } - } -} - -// Normalize a string for output -String8 ResTable::normalizeForOutput( const char *input ) -{ - String8 ret; - char buff[2]; - buff[1] = '\0'; - - while (*input != '\0') { - switch (*input) { - // All interesting characters are in the ASCII zone, so we are making our own lives - // easier by scanning the string one byte at a time. - case '\\': - ret += "\\\\"; - break; - case '\n': - ret += "\\n"; - break; - case '"': - ret += "\\\""; - break; - default: - buff[0] = *input; - ret += buff; - break; - } - - input++; - } - - return ret; -} - -void ResTable::print_value(const Package* pkg, const Res_value& value) const -{ - if (value.dataType == Res_value::TYPE_NULL) { - printf("(null)\n"); - } else if (value.dataType == Res_value::TYPE_REFERENCE) { - printf("(reference) 0x%08x\n", value.data); - } else if (value.dataType == Res_value::TYPE_ATTRIBUTE) { - printf("(attribute) 0x%08x\n", value.data); - } else if (value.dataType == Res_value::TYPE_STRING) { - size_t len; - const char* str8 = pkg->header->values.string8At( - value.data, &len); - if (str8 != NULL) { - printf("(string8) \"%s\"\n", normalizeForOutput(str8).string()); - } else { - const char16_t* str16 = pkg->header->values.stringAt( - value.data, &len); - if (str16 != NULL) { - printf("(string16) \"%s\"\n", - normalizeForOutput(String8(str16, len).string()).string()); - } else { - printf("(string) null\n"); - } - } - } else if (value.dataType == Res_value::TYPE_FLOAT) { - printf("(float) %g\n", *(const float*)&value.data); - } else if (value.dataType == Res_value::TYPE_DIMENSION) { - printf("(dimension) "); - print_complex(value.data, false); - printf("\n"); - } else if (value.dataType == Res_value::TYPE_FRACTION) { - printf("(fraction) "); - print_complex(value.data, true); - printf("\n"); - } else if (value.dataType >= Res_value::TYPE_FIRST_COLOR_INT - || value.dataType <= Res_value::TYPE_LAST_COLOR_INT) { - printf("(color) #%08x\n", value.data); - } else if (value.dataType == Res_value::TYPE_INT_BOOLEAN) { - printf("(boolean) %s\n", value.data ? "true" : "false"); - } else if (value.dataType >= Res_value::TYPE_FIRST_INT - || value.dataType <= Res_value::TYPE_LAST_INT) { - printf("(int) 0x%08x or %d\n", value.data, value.data); - } else { - printf("(unknown type) t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)\n", - (int)value.dataType, (int)value.data, - (int)value.size, (int)value.res0); - } -} - -void ResTable::print(bool inclValues) const -{ - if (mError != 0) { - printf("mError=0x%x (%s)\n", mError, strerror(mError)); - } -#if 0 - printf("mParams=%c%c-%c%c,\n", - mParams.language[0], mParams.language[1], - mParams.country[0], mParams.country[1]); -#endif - size_t pgCount = mPackageGroups.size(); - printf("Package Groups (%d)\n", (int)pgCount); - for (size_t pgIndex=0; pgIndexid, (int)pg->packages.size(), - String8(pg->name).string()); - - size_t pkgCount = pg->packages.size(); - for (size_t pkgIndex=0; pkgIndexpackages[pkgIndex]; - size_t typeCount = pkg->types.size(); - printf(" Package %d id=%d name=%s typeCount=%d\n", (int)pkgIndex, - pkg->package->id, String8(String16(pkg->package->name)).string(), - (int)typeCount); - for (size_t typeIndex=0; typeIndexgetType(typeIndex); - if (typeConfigs == NULL) { - printf(" type %d NULL\n", (int)typeIndex); - continue; - } - const size_t NTC = typeConfigs->configs.size(); - printf(" type %d configCount=%d entryCount=%d\n", - (int)typeIndex, (int)NTC, (int)typeConfigs->entryCount); - if (typeConfigs->typeSpecFlags != NULL) { - for (size_t entryIndex=0; entryIndexentryCount; entryIndex++) { - uint32_t resID = (0xff000000 & ((pkg->package->id)<<24)) - | (0x00ff0000 & ((typeIndex+1)<<16)) - | (0x0000ffff & (entryIndex)); - resource_name resName; - if (this->getResourceName(resID, true, &resName)) { - String8 type8; - String8 name8; - if (resName.type8 != NULL) { - type8 = String8(resName.type8, resName.typeLen); - } else { - type8 = String8(resName.type, resName.typeLen); - } - if (resName.name8 != NULL) { - name8 = String8(resName.name8, resName.nameLen); - } else { - name8 = String8(resName.name, resName.nameLen); - } - printf(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n", - resID, - CHAR16_TO_CSTR(resName.package, resName.packageLen), - type8.string(), name8.string(), - dtohl(typeConfigs->typeSpecFlags[entryIndex])); - } else { - printf(" INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID); - } - } - } - for (size_t configIndex=0; configIndexconfigs[configIndex]; - if ((((uint64_t)type)&0x3) != 0) { - printf(" NON-INTEGER ResTable_type ADDRESS: %p\n", type); - continue; - } - String8 configStr = type->config.toString(); - printf(" config %s:\n", configStr.size() > 0 - ? configStr.string() : "(default)"); - size_t entryCount = dtohl(type->entryCount); - uint32_t entriesStart = dtohl(type->entriesStart); - if ((entriesStart&0x3) != 0) { - printf(" NON-INTEGER ResTable_type entriesStart OFFSET: %p\n", (void*)entriesStart); - continue; - } - uint32_t typeSize = dtohl(type->header.size); - if ((typeSize&0x3) != 0) { - printf(" NON-INTEGER ResTable_type header.size: %p\n", (void*)typeSize); - continue; - } - for (size_t entryIndex=0; entryIndexheader.size); - const uint32_t* const eindex = (const uint32_t*) - (((const uint8_t*)type) + dtohs(type->header.headerSize)); - - uint32_t thisOffset = dtohl(eindex[entryIndex]); - if (thisOffset == ResTable_type::NO_ENTRY) { - continue; - } - - uint32_t resID = (0xff000000 & ((pkg->package->id)<<24)) - | (0x00ff0000 & ((typeIndex+1)<<16)) - | (0x0000ffff & (entryIndex)); - resource_name resName; - if (this->getResourceName(resID, true, &resName)) { - String8 type8; - String8 name8; - if (resName.type8 != NULL) { - type8 = String8(resName.type8, resName.typeLen); - } else { - type8 = String8(resName.type, resName.typeLen); - } - if (resName.name8 != NULL) { - name8 = String8(resName.name8, resName.nameLen); - } else { - name8 = String8(resName.name, resName.nameLen); - } - printf(" resource 0x%08x %s:%s/%s: ", resID, - CHAR16_TO_CSTR(resName.package, resName.packageLen), - type8.string(), name8.string()); - } else { - printf(" INVALID RESOURCE 0x%08x: ", resID); - } - if ((thisOffset&0x3) != 0) { - printf("NON-INTEGER OFFSET: %p\n", (void*)thisOffset); - continue; - } - if ((thisOffset+sizeof(ResTable_entry)) > typeSize) { - printf("OFFSET OUT OF BOUNDS: %p+%p (size is %p)\n", - (void*)entriesStart, (void*)thisOffset, - (void*)typeSize); - continue; - } - - const ResTable_entry* ent = (const ResTable_entry*) - (((const uint8_t*)type) + entriesStart + thisOffset); - if (((entriesStart + thisOffset)&0x3) != 0) { - printf("NON-INTEGER ResTable_entry OFFSET: %p\n", - (void*)(entriesStart + thisOffset)); - continue; - } - - uint16_t esize = dtohs(ent->size); - if ((esize&0x3) != 0) { - printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void*)esize); - continue; - } - if ((thisOffset+esize) > typeSize) { - printf("ResTable_entry OUT OF BOUNDS: %p+%p+%p (size is %p)\n", - (void*)entriesStart, (void*)thisOffset, - (void*)esize, (void*)typeSize); - continue; - } - - const Res_value* valuePtr = NULL; - const ResTable_map_entry* bagPtr = NULL; - Res_value value; - if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) { - printf(""); - bagPtr = (const ResTable_map_entry*)ent; - } else { - valuePtr = (const Res_value*) - (((const uint8_t*)ent) + esize); - value.copyFrom_dtoh(*valuePtr); - printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)", - (int)value.dataType, (int)value.data, - (int)value.size, (int)value.res0); - } - - if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) { - printf(" (PUBLIC)"); - } - printf("\n"); - - if (inclValues) { - if (valuePtr != NULL) { - printf(" "); - print_value(pkg, value); - } else if (bagPtr != NULL) { - const int N = dtohl(bagPtr->count); - const uint8_t* baseMapPtr = (const uint8_t*)ent; - size_t mapOffset = esize; - const ResTable_map* mapPtr = (ResTable_map*)(baseMapPtr+mapOffset); - printf(" Parent=0x%08x, Count=%d\n", - dtohl(bagPtr->parent.ident), N); - for (int i=0; iname.ident)); - value.copyFrom_dtoh(mapPtr->value); - print_value(pkg, value); - const size_t size = dtohs(mapPtr->value.size); - mapOffset += size + sizeof(*mapPtr)-sizeof(mapPtr->value); - mapPtr = (ResTable_map*)(baseMapPtr+mapOffset); - } - } - } - } - } - } - } - } -} - -} // namespace android diff --git a/libs/androidfw/StreamingZipInflater.cpp b/libs/androidfw/StreamingZipInflater.cpp deleted file mode 100644 index 1dfec23cbe..0000000000 --- a/libs/androidfw/StreamingZipInflater.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "szipinf" -#include - -#include -#include -#include -#include -#include -#include -#include - -/* - * TEMP_FAILURE_RETRY is defined by some, but not all, versions of - * . (Alas, it is not as standard as we'd hoped!) So, if it's - * not already defined, then define it here. - */ -#ifndef TEMP_FAILURE_RETRY -/* Used to retry syscalls that can return EINTR. */ -#define TEMP_FAILURE_RETRY(exp) ({ \ - typeof (exp) _rc; \ - do { \ - _rc = (exp); \ - } while (_rc == -1 && errno == EINTR); \ - _rc; }) -#endif - -static inline size_t min_of(size_t a, size_t b) { return (a < b) ? a : b; } - -using namespace android; - -/* - * Streaming access to compressed asset data in an open fd - */ -StreamingZipInflater::StreamingZipInflater(int fd, off64_t compDataStart, - size_t uncompSize, size_t compSize) { - mFd = fd; - mDataMap = NULL; - mInFileStart = compDataStart; - mOutTotalSize = uncompSize; - mInTotalSize = compSize; - - mInBufSize = StreamingZipInflater::INPUT_CHUNK_SIZE; - mInBuf = new uint8_t[mInBufSize]; - - mOutBufSize = StreamingZipInflater::OUTPUT_CHUNK_SIZE; - mOutBuf = new uint8_t[mOutBufSize]; - - initInflateState(); -} - -/* - * Streaming access to compressed data held in an mmapped region of memory - */ -StreamingZipInflater::StreamingZipInflater(FileMap* dataMap, size_t uncompSize) { - mFd = -1; - mDataMap = dataMap; - mOutTotalSize = uncompSize; - mInTotalSize = dataMap->getDataLength(); - - mInBuf = (uint8_t*) dataMap->getDataPtr(); - mInBufSize = mInTotalSize; - - mOutBufSize = StreamingZipInflater::OUTPUT_CHUNK_SIZE; - mOutBuf = new uint8_t[mOutBufSize]; - - initInflateState(); -} - -StreamingZipInflater::~StreamingZipInflater() { - // tear down the in-flight zip state just in case - ::inflateEnd(&mInflateState); - - if (mDataMap == NULL) { - delete [] mInBuf; - } - delete [] mOutBuf; -} - -void StreamingZipInflater::initInflateState() { - ALOGV("Initializing inflate state"); - - memset(&mInflateState, 0, sizeof(mInflateState)); - mInflateState.zalloc = Z_NULL; - mInflateState.zfree = Z_NULL; - mInflateState.opaque = Z_NULL; - mInflateState.next_in = (Bytef*)mInBuf; - mInflateState.next_out = (Bytef*) mOutBuf; - mInflateState.avail_out = mOutBufSize; - mInflateState.data_type = Z_UNKNOWN; - - mOutLastDecoded = mOutDeliverable = mOutCurPosition = 0; - mInNextChunkOffset = 0; - mStreamNeedsInit = true; - - if (mDataMap == NULL) { - ::lseek(mFd, mInFileStart, SEEK_SET); - mInflateState.avail_in = 0; // set when a chunk is read in - } else { - mInflateState.avail_in = mInBufSize; - } -} - -/* - * Basic approach: - * - * 1. If we have undelivered uncompressed data, send it. At this point - * either we've satisfied the request, or we've exhausted the available - * output data in mOutBuf. - * - * 2. While we haven't sent enough data to satisfy the request: - * 0. if the request is for more data than exists, bail. - * a. if there is no input data to decode, read some into the input buffer - * and readjust the z_stream input pointers - * b. point the output to the start of the output buffer and decode what we can - * c. deliver whatever output data we can - */ -ssize_t StreamingZipInflater::read(void* outBuf, size_t count) { - uint8_t* dest = (uint8_t*) outBuf; - size_t bytesRead = 0; - size_t toRead = min_of(count, size_t(mOutTotalSize - mOutCurPosition)); - while (toRead > 0) { - // First, write from whatever we already have decoded and ready to go - size_t deliverable = min_of(toRead, mOutLastDecoded - mOutDeliverable); - if (deliverable > 0) { - if (outBuf != NULL) memcpy(dest, mOutBuf + mOutDeliverable, deliverable); - mOutDeliverable += deliverable; - mOutCurPosition += deliverable; - dest += deliverable; - bytesRead += deliverable; - toRead -= deliverable; - } - - // need more data? time to decode some. - if (toRead > 0) { - // if we don't have any data to decode, read some in. If we're working - // from mmapped data this won't happen, because the clipping to total size - // will prevent reading off the end of the mapped input chunk. - if ((mInflateState.avail_in == 0) && (mDataMap == NULL)) { - int err = readNextChunk(); - if (err < 0) { - ALOGE("Unable to access asset data: %d", err); - if (!mStreamNeedsInit) { - ::inflateEnd(&mInflateState); - initInflateState(); - } - return -1; - } - } - // we know we've drained whatever is in the out buffer now, so just - // start from scratch there, reading all the input we have at present. - mInflateState.next_out = (Bytef*) mOutBuf; - mInflateState.avail_out = mOutBufSize; - - /* - ALOGV("Inflating to outbuf: avail_in=%u avail_out=%u next_in=%p next_out=%p", - mInflateState.avail_in, mInflateState.avail_out, - mInflateState.next_in, mInflateState.next_out); - */ - int result = Z_OK; - if (mStreamNeedsInit) { - ALOGV("Initializing zlib to inflate"); - result = inflateInit2(&mInflateState, -MAX_WBITS); - mStreamNeedsInit = false; - } - if (result == Z_OK) result = ::inflate(&mInflateState, Z_SYNC_FLUSH); - if (result < 0) { - // Whoops, inflation failed - ALOGE("Error inflating asset: %d", result); - ::inflateEnd(&mInflateState); - initInflateState(); - return -1; - } else { - if (result == Z_STREAM_END) { - // we know we have to have reached the target size here and will - // not try to read any further, so just wind things up. - ::inflateEnd(&mInflateState); - } - - // Note how much data we got, and off we go - mOutDeliverable = 0; - mOutLastDecoded = mOutBufSize - mInflateState.avail_out; - } - } - } - return bytesRead; -} - -int StreamingZipInflater::readNextChunk() { - assert(mDataMap == NULL); - - if (mInNextChunkOffset < mInTotalSize) { - size_t toRead = min_of(mInBufSize, mInTotalSize - mInNextChunkOffset); - if (toRead > 0) { - ssize_t didRead = TEMP_FAILURE_RETRY(::read(mFd, mInBuf, toRead)); - //ALOGV("Reading input chunk, size %08x didread %08x", toRead, didRead); - if (didRead < 0) { - ALOGE("Error reading asset data: %s", strerror(errno)); - return didRead; - } else { - mInNextChunkOffset += didRead; - mInflateState.next_in = (Bytef*) mInBuf; - mInflateState.avail_in = didRead; - } - } - } - return 0; -} - -// seeking backwards requires uncompressing fom the beginning, so is very -// expensive. seeking forwards only requires uncompressing from the current -// position to the destination. -off64_t StreamingZipInflater::seekAbsolute(off64_t absoluteInputPosition) { - if (absoluteInputPosition < mOutCurPosition) { - // rewind and reprocess the data from the beginning - if (!mStreamNeedsInit) { - ::inflateEnd(&mInflateState); - } - initInflateState(); - read(NULL, absoluteInputPosition); - } else if (absoluteInputPosition > mOutCurPosition) { - read(NULL, absoluteInputPosition - mOutCurPosition); - } - // else if the target position *is* our current position, do nothing - return absoluteInputPosition; -} diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp deleted file mode 100644 index 1ab18ad056..0000000000 --- a/libs/androidfw/ZipFileRO.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/* - * 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. - */ - -// -// Read-only access to Zip archives, with minimal heap allocation. -// -#define LOG_TAG "zipro" -//#define LOG_NDEBUG 0 -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -/* - * We must open binary files using open(path, ... | O_BINARY) under Windows. - * Otherwise strange read errors will happen. - */ -#ifndef O_BINARY -# define O_BINARY 0 -#endif - -using namespace android; - -class _ZipEntryRO { -public: - ZipEntry entry; - ZipEntryName name; - void *cookie; - - _ZipEntryRO() : cookie(NULL) { - } - -private: - _ZipEntryRO(const _ZipEntryRO& other); - _ZipEntryRO& operator=(const _ZipEntryRO& other); -}; - -ZipFileRO::~ZipFileRO() { - CloseArchive(mHandle); - free(mFileName); -} - -/* - * Open the specified file read-only. We memory-map the entire thing and - * close the file before returning. - */ -/* static */ ZipFileRO* ZipFileRO::open(const char* zipFileName) -{ - ZipArchiveHandle handle; - const int32_t error = OpenArchive(zipFileName, &handle); - if (error) { - ALOGW("Error opening archive %s: %s", zipFileName, ErrorCodeString(error)); - return NULL; - } - - return new ZipFileRO(handle, strdup(zipFileName)); -} - - -ZipEntryRO ZipFileRO::findEntryByName(const char* entryName) const -{ - _ZipEntryRO* data = new _ZipEntryRO; - const int32_t error = FindEntry(mHandle, entryName, &(data->entry)); - if (error) { - delete data; - return NULL; - } - - data->name.name = entryName; - data->name.name_length = strlen(entryName); - - return (ZipEntryRO) data; -} - -/* - * Get the useful fields from the zip entry. - * - * Returns "false" if the offsets to the fields or the contents of the fields - * appear to be bogus. - */ -bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen, - size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const -{ - const _ZipEntryRO* zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); - const ZipEntry& ze = zipEntry->entry; - - if (pMethod != NULL) { - *pMethod = ze.method; - } - if (pUncompLen != NULL) { - *pUncompLen = ze.uncompressed_length; - } - if (pCompLen != NULL) { - *pCompLen = ze.compressed_length; - } - if (pOffset != NULL) { - *pOffset = ze.offset; - } - if (pModWhen != NULL) { - *pModWhen = ze.mod_time; - } - if (pCrc32 != NULL) { - *pCrc32 = ze.crc32; - } - - return true; -} - -bool ZipFileRO::startIteration(void** cookie) -{ - _ZipEntryRO* ze = new _ZipEntryRO; - int32_t error = StartIteration(mHandle, &(ze->cookie), NULL /* prefix */); - if (error) { - ALOGW("Could not start iteration over %s: %s", mFileName, ErrorCodeString(error)); - delete ze; - return false; - } - - *cookie = ze; - return true; -} - -ZipEntryRO ZipFileRO::nextEntry(void* cookie) -{ - _ZipEntryRO* ze = reinterpret_cast<_ZipEntryRO*>(cookie); - int32_t error = Next(ze->cookie, &(ze->entry), &(ze->name)); - if (error) { - if (error != -1) { - ALOGW("Error iteration over %s: %s", mFileName, ErrorCodeString(error)); - } - return NULL; - } - - return &(ze->entry); -} - -void ZipFileRO::endIteration(void* cookie) -{ - delete reinterpret_cast<_ZipEntryRO*>(cookie); -} - -void ZipFileRO::releaseEntry(ZipEntryRO entry) const -{ - delete reinterpret_cast<_ZipEntryRO*>(entry); -} - -/* - * Copy the entry's filename to the buffer. - */ -int ZipFileRO::getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen) - const -{ - const _ZipEntryRO* zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); - const uint16_t requiredSize = zipEntry->name.name_length + 1; - - if (bufLen < requiredSize) { - ALOGW("Buffer too short, requires %d bytes for entry name", requiredSize); - return requiredSize; - } - - memcpy(buffer, zipEntry->name.name, requiredSize - 1); - buffer[requiredSize - 1] = '\0'; - - return 0; -} - -/* - * Create a new FileMap object that spans the data in "entry". - */ -FileMap* ZipFileRO::createEntryFileMap(ZipEntryRO entry) const -{ - const _ZipEntryRO *zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); - const ZipEntry& ze = zipEntry->entry; - int fd = GetFileDescriptor(mHandle); - size_t actualLen = 0; - - if (ze.method == kCompressStored) { - actualLen = ze.uncompressed_length; - } else { - actualLen = ze.compressed_length; - } - - FileMap* newMap = new FileMap(); - if (!newMap->create(mFileName, fd, ze.offset, actualLen, true)) { - newMap->release(); - return NULL; - } - - return newMap; -} - -/* - * Uncompress an entry, in its entirety, into the provided output buffer. - * - * This doesn't verify the data's CRC, which might be useful for - * uncompressed data. The caller should be able to manage it. - */ -bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer, size_t size) const -{ - _ZipEntryRO *zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); - const int32_t error = ExtractToMemory(mHandle, &(zipEntry->entry), - (uint8_t*) buffer, size); - if (error) { - ALOGW("ExtractToMemory failed with %s", ErrorCodeString(error)); - return false; - } - - return true; -} - -/* - * Uncompress an entry, in its entirety, to an open file descriptor. - * - * This doesn't verify the data's CRC, but probably should. - */ -bool ZipFileRO::uncompressEntry(ZipEntryRO entry, int fd) const -{ - _ZipEntryRO *zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); - const int32_t error = ExtractEntryToFile(mHandle, &(zipEntry->entry), fd); - if (error) { - ALOGW("ExtractToMemory failed with %s", ErrorCodeString(error)); - return false; - } - - return true; -} diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp deleted file mode 100644 index e9ac2fe25f..0000000000 --- a/libs/androidfw/ZipUtils.cpp +++ /dev/null @@ -1,330 +0,0 @@ -/* - * 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. - */ - -// -// Misc zip/gzip utility functions. -// - -#define LOG_TAG "ziputil" - -#include -#include -#include -#include - -#include -#include -#include - -#include - -using namespace android; - -static inline unsigned long get4LE(const unsigned char* buf) { - return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); -} - - -static const unsigned long kReadBufSize = 32768; - -/* - * Utility function that expands zip/gzip "deflate" compressed data - * into a buffer. - * - * (This is a clone of the previous function, but it takes a FILE* instead - * of an fd. We could pass fileno(fd) to the above, but we can run into - * trouble when "fp" has a different notion of what fd's file position is.) - * - * "fp" is an open file positioned at the start of the "deflate" data - * "buf" must hold at least "uncompressedLen" bytes. - */ -/*static*/ template bool inflateToBuffer(T& reader, void* buf, - long uncompressedLen, long compressedLen) -{ - bool result = false; - - z_stream zstream; - int zerr; - unsigned long compRemaining; - - assert(uncompressedLen >= 0); - assert(compressedLen >= 0); - - 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); - - 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 -= nextSize; - - zstream.next_in = nextBuffer; - zstream.avail_in = nextSize; - } - - /* 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: - 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(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(reader, buf, - uncompressedLen, compressedLen); -} - -/*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf, - long uncompressedLen, long compressedLen) -{ - FdReader reader(fd); - return ::inflateToBuffer(reader, buf, - uncompressedLen, compressedLen); -} - -/*static*/ bool ZipUtils::inflateToBuffer(void* in, void* buf, - long uncompressedLen, long compressedLen) -{ - BufferReader reader(in, compressedLen); - return ::inflateToBuffer(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. - * - * We expect to find the CRC and length as the last 8 bytes on the file. - * This is a pretty reasonable thing to expect for locally-compressed - * files, but there's a small chance that some extra padding got thrown - * on (the man page talks about compressed data written to tape). We - * don't currently deal with that here. If "gzip -l" whines, we're going - * to fail too. - * - * On exit, "fp" is pointing at the start of the compressed data. - */ -/*static*/ bool ZipUtils::examineGzip(FILE* fp, int* pCompressionMethod, - long* pUncompressedLen, long* pCompressedLen, unsigned long* pCRC32) -{ - enum { // flags - FTEXT = 0x01, - FHCRC = 0x02, - FEXTRA = 0x04, - FNAME = 0x08, - FCOMMENT = 0x10, - }; - int ic; - int method, flags; - int i; - - ic = getc(fp); - if (ic != 0x1f || getc(fp) != 0x8b) - return false; // not gzip - method = getc(fp); - flags = getc(fp); - - /* quick sanity checks */ - if (method == EOF || flags == EOF) - return false; - if (method != ZipFileRO::kCompressDeflated) - return false; - - /* skip over 4 bytes of mod time, 1 byte XFL, 1 byte OS */ - for (i = 0; i < 6; i++) - (void) getc(fp); - /* consume "extra" field, if present */ - if ((flags & FEXTRA) != 0) { - int len; - - len = getc(fp); - len |= getc(fp) << 8; - while (len-- && getc(fp) != EOF) - ; - } - /* consume filename, if present */ - if ((flags & FNAME) != 0) { - do { - ic = getc(fp); - } while (ic != 0 && ic != EOF); - } - /* consume comment, if present */ - if ((flags & FCOMMENT) != 0) { - do { - ic = getc(fp); - } while (ic != 0 && ic != EOF); - } - /* consume 16-bit header CRC, if present */ - if ((flags & FHCRC) != 0) { - (void) getc(fp); - (void) getc(fp); - } - - if (feof(fp) || ferror(fp)) - return false; - - /* seek to the end; CRC and length are in the last 8 bytes */ - long curPosn = ftell(fp); - unsigned char buf[8]; - fseek(fp, -8, SEEK_END); - *pCompressedLen = ftell(fp) - curPosn; - - if (fread(buf, 1, 8, fp) != 8) - return false; - /* seek back to start of compressed data */ - fseek(fp, curPosn, SEEK_SET); - - *pCompressionMethod = method; - *pCRC32 = get4LE(&buf[0]); - *pUncompressedLen = get4LE(&buf[4]); - - return true; -} diff --git a/libs/androidfw/misc.cpp b/libs/androidfw/misc.cpp deleted file mode 100644 index 29686efe37..0000000000 --- a/libs/androidfw/misc.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2005 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. - */ - -#define LOG_TAG "misc" - -// -// Miscellaneous utility functions. -// -#include - -#include -#include -#include -#include - -using namespace android; - -namespace android { - -/* - * Get a file's type. - */ -FileType getFileType(const char* fileName) -{ - struct stat sb; - - if (stat(fileName, &sb) < 0) { - if (errno == ENOENT || errno == ENOTDIR) - return kFileTypeNonexistent; - else { - fprintf(stderr, "getFileType got errno=%d on '%s'\n", - errno, fileName); - return kFileTypeUnknown; - } - } else { - if (S_ISREG(sb.st_mode)) - return kFileTypeRegular; - else if (S_ISDIR(sb.st_mode)) - return kFileTypeDirectory; - else if (S_ISCHR(sb.st_mode)) - return kFileTypeCharDev; - else if (S_ISBLK(sb.st_mode)) - return kFileTypeBlockDev; - else if (S_ISFIFO(sb.st_mode)) - return kFileTypeFifo; -#ifdef HAVE_SYMLINKS - else if (S_ISLNK(sb.st_mode)) - return kFileTypeSymlink; - else if (S_ISSOCK(sb.st_mode)) - return kFileTypeSocket; -#endif - else - return kFileTypeUnknown; - } -} - -/* - * Get a file's modification date. - */ -time_t getFileModDate(const char* fileName) -{ - struct stat sb; - - if (stat(fileName, &sb) < 0) - return (time_t) -1; - - return sb.st_mtime; -} - -}; // namespace android diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk deleted file mode 100644 index 6e6522c149..0000000000 --- a/libs/androidfw/tests/Android.mk +++ /dev/null @@ -1,32 +0,0 @@ -# Build the unit tests. -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -# Build the unit tests. -test_src_files := \ - BackupData_test.cpp \ - ObbFile_test.cpp \ - ZipUtils_test.cpp - -shared_libraries := \ - libandroidfw \ - libcutils \ - libutils \ - libui \ - libstlport - -static_libraries := \ - libgtest \ - libgtest_main - -$(foreach file,$(test_src_files), \ - $(eval include $(CLEAR_VARS)) \ - $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ - $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ - $(eval LOCAL_SRC_FILES := $(file)) \ - $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ - $(eval include $(BUILD_NATIVE_TEST)) \ -) - -# Build the manual test programs. -include $(call all-makefiles-under, $(LOCAL_PATH)) diff --git a/libs/androidfw/tests/BackupData_test.cpp b/libs/androidfw/tests/BackupData_test.cpp deleted file mode 100644 index 17f91ca9e4..0000000000 --- a/libs/androidfw/tests/BackupData_test.cpp +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#define LOG_TAG "ObbFile_test" -#include -#include -#include - -#include - -#include -#include -#include -#include - -namespace android { - -#define TEST_FILENAME "/test.bd" - -// keys of different lengths to test padding -#define KEY1 "key1" -#define KEY2 "key2a" -#define KEY3 "key3bc" -#define KEY4 "key4def" - -// payloads of different lengths to test padding -#define DATA1 "abcdefg" -#define DATA2 "hijklmnopq" -#define DATA3 "rstuvwxyz" -// KEY4 is only ever deleted - -class BackupDataTest : public testing::Test { -protected: - char* m_external_storage; - char* m_filename; - String8 mKey1; - String8 mKey2; - String8 mKey3; - String8 mKey4; - - virtual void SetUp() { - m_external_storage = getenv("EXTERNAL_STORAGE"); - - const int totalLen = strlen(m_external_storage) + strlen(TEST_FILENAME) + 1; - m_filename = new char[totalLen]; - snprintf(m_filename, totalLen, "%s%s", m_external_storage, TEST_FILENAME); - - ::unlink(m_filename); - int fd = ::open(m_filename, O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); - if (fd < 0) { - FAIL() << "Couldn't create " << m_filename << " for writing"; - } - mKey1 = String8(KEY1); - mKey2 = String8(KEY2); - mKey3 = String8(KEY3); - mKey4 = String8(KEY4); - } - - virtual void TearDown() { - } -}; - -TEST_F(BackupDataTest, WriteAndReadSingle) { - int fd = ::open(m_filename, O_WRONLY); - BackupDataWriter* writer = new BackupDataWriter(fd); - - EXPECT_EQ(NO_ERROR, writer->WriteEntityHeader(mKey1, sizeof(DATA1))) - << "WriteEntityHeader returned an error"; - EXPECT_EQ(NO_ERROR, writer->WriteEntityData(DATA1, sizeof(DATA1))) - << "WriteEntityData returned an error"; - - ::close(fd); - fd = ::open(m_filename, O_RDONLY); - BackupDataReader* reader = new BackupDataReader(fd); - EXPECT_EQ(NO_ERROR, reader->Status()) - << "Reader ctor failed"; - - bool done; - int type; - reader->ReadNextHeader(&done, &type); - EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type) - << "wrong type from ReadNextHeader"; - - String8 key; - size_t dataSize; - EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize)) - << "ReadEntityHeader returned an error"; - EXPECT_EQ(mKey1, key) - << "wrong key from ReadEntityHeader"; - EXPECT_EQ(sizeof(DATA1), dataSize) - << "wrong size from ReadEntityHeader"; - - char* dataBytes = new char[dataSize]; - EXPECT_EQ((int) dataSize, reader->ReadEntityData(dataBytes, dataSize)) - << "ReadEntityData returned an error"; - for (unsigned int i = 0; i < sizeof(DATA1); i++) { - EXPECT_EQ(DATA1[i], dataBytes[i]) - << "data character " << i << " should be equal"; - } - delete dataBytes; - delete writer; - delete reader; -} - -TEST_F(BackupDataTest, WriteAndReadMultiple) { - int fd = ::open(m_filename, O_WRONLY); - BackupDataWriter* writer = new BackupDataWriter(fd); - writer->WriteEntityHeader(mKey1, sizeof(DATA1)); - writer->WriteEntityData(DATA1, sizeof(DATA1)); - writer->WriteEntityHeader(mKey2, sizeof(DATA2)); - writer->WriteEntityData(DATA2, sizeof(DATA2)); - - ::close(fd); - fd = ::open(m_filename, O_RDONLY); - BackupDataReader* reader = new BackupDataReader(fd); - - bool done; - int type; - String8 key; - size_t dataSize; - char* dataBytes; - // read first entity - reader->ReadNextHeader(&done, &type); - reader->ReadEntityHeader(&key, &dataSize); - dataBytes = new char[dataSize]; - reader->ReadEntityData(dataBytes, dataSize); - delete dataBytes; - - // read and verify second entity - reader->ReadNextHeader(&done, &type); - EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type) - << "wrong type from ReadNextHeader"; - - EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize)) - << "ReadEntityHeader returned an error on second entity"; - EXPECT_EQ(mKey2, key) - << "wrong key from ReadEntityHeader on second entity"; - EXPECT_EQ(sizeof(DATA2), dataSize) - << "wrong size from ReadEntityHeader on second entity"; - - dataBytes = new char[dataSize]; - EXPECT_EQ((int)dataSize, reader->ReadEntityData(dataBytes, dataSize)) - << "ReadEntityData returned an error on second entity"; - for (unsigned int i = 0; i < sizeof(DATA2); i++) { - EXPECT_EQ(DATA2[i], dataBytes[i]) - << "data character " << i << " should be equal"; - } - delete dataBytes; - delete writer; - delete reader; -} - -TEST_F(BackupDataTest, SkipEntity) { - int fd = ::open(m_filename, O_WRONLY); - BackupDataWriter* writer = new BackupDataWriter(fd); - writer->WriteEntityHeader(mKey1, sizeof(DATA1)); - writer->WriteEntityData(DATA1, sizeof(DATA1)); - writer->WriteEntityHeader(mKey2, sizeof(DATA2)); - writer->WriteEntityData(DATA2, sizeof(DATA2)); - writer->WriteEntityHeader(mKey3, sizeof(DATA3)); - writer->WriteEntityData(DATA3, sizeof(DATA3)); - - ::close(fd); - fd = ::open(m_filename, O_RDONLY); - BackupDataReader* reader = new BackupDataReader(fd); - - bool done; - int type; - String8 key; - size_t dataSize; - char* dataBytes; - // read first entity - reader->ReadNextHeader(&done, &type); - reader->ReadEntityHeader(&key, &dataSize); - dataBytes = new char[dataSize]; - reader->ReadEntityData(dataBytes, dataSize); - delete dataBytes; - - // skip second entity - reader->ReadNextHeader(&done, &type); - reader->ReadEntityHeader(&key, &dataSize); - reader->SkipEntityData(); - - // read and verify third entity - reader->ReadNextHeader(&done, &type); - EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type) - << "wrong type from ReadNextHeader after skip"; - - EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize)) - << "ReadEntityHeader returned an error on third entity"; - EXPECT_EQ(mKey3, key) - << "wrong key from ReadEntityHeader on third entity"; - EXPECT_EQ(sizeof(DATA3), dataSize) - << "wrong size from ReadEntityHeader on third entity"; - - dataBytes = new char[dataSize]; - EXPECT_EQ((int) dataSize, reader->ReadEntityData(dataBytes, dataSize)) - << "ReadEntityData returned an error on third entity"; - for (unsigned int i = 0; i < sizeof(DATA3); i++) { - EXPECT_EQ(DATA3[i], dataBytes[i]) - << "data character " << i << " should be equal"; - } - delete dataBytes; - delete writer; - delete reader; -} - -TEST_F(BackupDataTest, DeleteEntity) { - int fd = ::open(m_filename, O_WRONLY); - BackupDataWriter* writer = new BackupDataWriter(fd); - writer->WriteEntityHeader(mKey1, sizeof(DATA1)); - writer->WriteEntityData(DATA1, sizeof(DATA1)); - writer->WriteEntityHeader(mKey2, -1); - - ::close(fd); - fd = ::open(m_filename, O_RDONLY); - BackupDataReader* reader = new BackupDataReader(fd); - - bool done; - int type; - String8 key; - size_t dataSize; - char* dataBytes; - // read first entity - reader->ReadNextHeader(&done, &type); - reader->ReadEntityHeader(&key, &dataSize); - dataBytes = new char[dataSize]; - reader->ReadEntityData(dataBytes, dataSize); - delete dataBytes; - - // read and verify deletion - reader->ReadNextHeader(&done, &type); - EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type) - << "wrong type from ReadNextHeader on deletion"; - - EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize)) - << "ReadEntityHeader returned an error on second entity"; - EXPECT_EQ(mKey2, key) - << "wrong key from ReadEntityHeader on second entity"; - EXPECT_EQ(-1, (int) dataSize) - << "not recognizing deletion on second entity"; - - delete writer; - delete reader; -} - -TEST_F(BackupDataTest, EneityAfterDelete) { - int fd = ::open(m_filename, O_WRONLY); - BackupDataWriter* writer = new BackupDataWriter(fd); - writer->WriteEntityHeader(mKey1, sizeof(DATA1)); - writer->WriteEntityData(DATA1, sizeof(DATA1)); - writer->WriteEntityHeader(mKey2, -1); - writer->WriteEntityHeader(mKey3, sizeof(DATA3)); - writer->WriteEntityData(DATA3, sizeof(DATA3)); - - ::close(fd); - fd = ::open(m_filename, O_RDONLY); - BackupDataReader* reader = new BackupDataReader(fd); - - bool done; - int type; - String8 key; - size_t dataSize; - char* dataBytes; - // read first entity - reader->ReadNextHeader(&done, &type); - reader->ReadEntityHeader(&key, &dataSize); - dataBytes = new char[dataSize]; - reader->ReadEntityData(dataBytes, dataSize); - delete dataBytes; - - // read and verify deletion - reader->ReadNextHeader(&done, &type); - EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type) - << "wrong type from ReadNextHeader on deletion"; - - EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize)) - << "ReadEntityHeader returned an error on second entity"; - EXPECT_EQ(mKey2, key) - << "wrong key from ReadEntityHeader on second entity"; - EXPECT_EQ(-1, (int)dataSize) - << "not recognizing deletion on second entity"; - - // read and verify third entity - reader->ReadNextHeader(&done, &type); - EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type) - << "wrong type from ReadNextHeader after deletion"; - - EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize)) - << "ReadEntityHeader returned an error on third entity"; - EXPECT_EQ(mKey3, key) - << "wrong key from ReadEntityHeader on third entity"; - EXPECT_EQ(sizeof(DATA3), dataSize) - << "wrong size from ReadEntityHeader on third entity"; - - dataBytes = new char[dataSize]; - EXPECT_EQ((int) dataSize, reader->ReadEntityData(dataBytes, dataSize)) - << "ReadEntityData returned an error on third entity"; - for (unsigned int i = 0; i < sizeof(DATA3); i++) { - EXPECT_EQ(DATA3[i], dataBytes[i]) - << "data character " << i << " should be equal"; - } - delete dataBytes; - delete writer; - delete reader; -} - -TEST_F(BackupDataTest, OnlyDeleteEntities) { - int fd = ::open(m_filename, O_WRONLY); - BackupDataWriter* writer = new BackupDataWriter(fd); - writer->WriteEntityHeader(mKey1, -1); - writer->WriteEntityHeader(mKey2, -1); - writer->WriteEntityHeader(mKey3, -1); - writer->WriteEntityHeader(mKey4, -1); - - ::close(fd); - fd = ::open(m_filename, O_RDONLY); - BackupDataReader* reader = new BackupDataReader(fd); - - bool done; - int type; - String8 key; - size_t dataSize; - // read and verify first deletion - reader->ReadNextHeader(&done, &type); - EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type) - << "wrong type from ReadNextHeader first deletion"; - - EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize)) - << "ReadEntityHeader returned an error on first entity"; - EXPECT_EQ(mKey1, key) - << "wrong key from ReadEntityHeader on first entity"; - EXPECT_EQ(-1, (int) dataSize) - << "not recognizing deletion on first entity"; - - // read and verify second deletion - reader->ReadNextHeader(&done, &type); - EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type) - << "wrong type from ReadNextHeader second deletion"; - - EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize)) - << "ReadEntityHeader returned an error on second entity"; - EXPECT_EQ(mKey2, key) - << "wrong key from ReadEntityHeader on second entity"; - EXPECT_EQ(-1, (int) dataSize) - << "not recognizing deletion on second entity"; - - // read and verify third deletion - reader->ReadNextHeader(&done, &type); - EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type) - << "wrong type from ReadNextHeader third deletion"; - - EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize)) - << "ReadEntityHeader returned an error on third entity"; - EXPECT_EQ(mKey3, key) - << "wrong key from ReadEntityHeader on third entity"; - EXPECT_EQ(-1, (int) dataSize) - << "not recognizing deletion on third entity"; - - // read and verify fourth deletion - reader->ReadNextHeader(&done, &type); - EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type) - << "wrong type from ReadNextHeader fourth deletion"; - - EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize)) - << "ReadEntityHeader returned an error on fourth entity"; - EXPECT_EQ(mKey4, key) - << "wrong key from ReadEntityHeader on fourth entity"; - EXPECT_EQ(-1, (int) dataSize) - << "not recognizing deletion on fourth entity"; - - delete writer; - delete reader; -} - -TEST_F(BackupDataTest, ReadDeletedEntityData) { - int fd = ::open(m_filename, O_WRONLY); - BackupDataWriter* writer = new BackupDataWriter(fd); - writer->WriteEntityHeader(mKey1, -1); - writer->WriteEntityHeader(mKey2, -1); - - ::close(fd); - fd = ::open(m_filename, O_RDONLY); - BackupDataReader* reader = new BackupDataReader(fd); - - bool done; - int type; - String8 key; - size_t dataSize; - // read and verify first deletion - reader->ReadNextHeader(&done, &type); - EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type) - << "wrong type from ReadNextHeader first deletion"; - - EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize)) - << "ReadEntityHeader returned an error on first entity"; - EXPECT_EQ(mKey1, key) - << "wrong key from ReadEntityHeader on first entity"; - EXPECT_EQ(-1, (int) dataSize) - << "not recognizing deletion on first entity"; - - // erroneously try to read first entity data - char* dataBytes = new char[10]; - dataBytes[0] = 'A'; - EXPECT_EQ(NO_ERROR, reader->ReadEntityData(dataBytes, dataSize)); - // expect dataBytes to be unmodofied - EXPECT_EQ('A', dataBytes[0]); - - // read and verify second deletion - reader->ReadNextHeader(&done, &type); - EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type) - << "wrong type from ReadNextHeader second deletion"; - - EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize)) - << "ReadEntityHeader returned an error on second entity"; - EXPECT_EQ(mKey2, key) - << "wrong key from ReadEntityHeader on second entity"; - EXPECT_EQ(-1, (int) dataSize) - << "not recognizing deletion on second entity"; - - delete writer; - delete reader; -} - -} diff --git a/libs/androidfw/tests/ObbFile_test.cpp b/libs/androidfw/tests/ObbFile_test.cpp deleted file mode 100644 index 2c9f65067c..0000000000 --- a/libs/androidfw/tests/ObbFile_test.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#define LOG_TAG "ObbFile_test" -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -namespace android { - -#define TEST_FILENAME "/test.obb" - -class ObbFileTest : public testing::Test { -protected: - sp mObbFile; - char* mExternalStorage; - char* mFileName; - - virtual void SetUp() { - mObbFile = new ObbFile(); - mExternalStorage = getenv("EXTERNAL_STORAGE"); - - const int totalLen = strlen(mExternalStorage) + strlen(TEST_FILENAME) + 1; - mFileName = new char[totalLen]; - snprintf(mFileName, totalLen, "%s%s", mExternalStorage, TEST_FILENAME); - - int fd = ::open(mFileName, O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); - if (fd < 0) { - FAIL() << "Couldn't create " << mFileName << " for tests"; - } - } - - virtual void TearDown() { - } -}; - -TEST_F(ObbFileTest, ReadFailure) { - EXPECT_FALSE(mObbFile->readFrom(-1)) - << "No failure on invalid file descriptor"; -} - -TEST_F(ObbFileTest, WriteThenRead) { - const char* packageName = "com.example.obbfile"; - const int32_t versionNum = 1; - - mObbFile->setPackageName(String8(packageName)); - mObbFile->setVersion(versionNum); -#define SALT_SIZE 8 - unsigned char salt[SALT_SIZE] = {0x01, 0x10, 0x55, 0xAA, 0xFF, 0x00, 0x5A, 0xA5}; - EXPECT_TRUE(mObbFile->setSalt(salt, SALT_SIZE)) - << "Salt should be successfully set"; - - EXPECT_TRUE(mObbFile->writeTo(mFileName)) - << "couldn't write to fake .obb file"; - - mObbFile = new ObbFile(); - - EXPECT_TRUE(mObbFile->readFrom(mFileName)) - << "couldn't read from fake .obb file"; - - EXPECT_EQ(versionNum, mObbFile->getVersion()) - << "version didn't come out the same as it went in"; - const char* currentPackageName = mObbFile->getPackageName().string(); - EXPECT_STREQ(packageName, currentPackageName) - << "package name didn't come out the same as it went in"; - - size_t saltLen; - const unsigned char* newSalt = mObbFile->getSalt(&saltLen); - - EXPECT_EQ(sizeof(salt), saltLen) - << "salt sizes were not the same"; - - for (int i = 0; i < sizeof(salt); i++) { - EXPECT_EQ(salt[i], newSalt[i]) - << "salt character " << i << " should be equal"; - } - EXPECT_TRUE(memcmp(newSalt, salt, sizeof(salt)) == 0) - << "salts should be the same"; -} - -} diff --git a/libs/androidfw/tests/ZipUtils_test.cpp b/libs/androidfw/tests/ZipUtils_test.cpp deleted file mode 100644 index c6038b597f..0000000000 --- a/libs/androidfw/tests/ZipUtils_test.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2011 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. - */ - -#define LOG_TAG "ZipUtils_test" -#include -#include - -#include - -#include -#include - -namespace android { - -class ZipUtilsTest : public testing::Test { -protected: - virtual void SetUp() { - } - - virtual void TearDown() { - } -}; - -TEST_F(ZipUtilsTest, ZipTimeConvertSuccess) { - struct tm t; - - // 2011-06-29 14:40:40 - long when = 0x3EDD7514; - - ZipUtils::zipTimeToTimespec(when, &t); - - EXPECT_EQ(2011, t.tm_year + 1900) - << "Year was improperly converted."; - - EXPECT_EQ(6, t.tm_mon) - << "Month was improperly converted."; - - EXPECT_EQ(29, t.tm_mday) - << "Day was improperly converted."; - - EXPECT_EQ(14, t.tm_hour) - << "Hour was improperly converted."; - - EXPECT_EQ(40, t.tm_min) - << "Minute was improperly converted."; - - EXPECT_EQ(40, t.tm_sec) - << "Second was improperly converted."; -} - -} -- 2.11.0