Moved androidfw back to frameworks/base

Change-Id: Idd57bbbc86c936cbfd60e02f8ac8d4f8fbc94592
This commit is contained in:
Adam Lesinski 2014-01-27 10:29:16 -08:00
parent a9d5701b03
commit 809af3aa03
31 changed files with 0 additions and 16662 deletions

View File

@ -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 <stdio.h>
#include <sys/types.h>
#include <utils/Compat.h>
#include <utils/Errors.h>
#include <utils/FileMap.h>
#include <utils/String8.h>
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

View File

@ -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 <androidfw/misc.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/SortedVector.h>
#include <sys/types.h>
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<FileInfo>* 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<FileInfo>* list) { mFileInfo = list; }
SortedVector<FileInfo>* mFileInfo;
};
}; // namespace android
#endif // __LIBS_ASSETDIR_H

View File

@ -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 <androidfw/Asset.h>
#include <androidfw/AssetDir.h>
#include <androidfw/ZipFileRO.h>
#include <utils/KeyedVector.h>
#include <utils/SortedVector.h>
#include <utils/String16.h>
#include <utils/String8.h>
#include <utils/threads.h>
#include <utils/Vector.h>
/*
* 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<String8>* 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<AssetDir::FileInfo>* pMergedInfo,
const asset_path& path, const char* rootDir, const char* dirName);
SortedVector<AssetDir::FileInfo>* scanDirLocked(const String8& path);
bool scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
const asset_path& path, const char* rootDir, const char* dirName);
void mergeInfoLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
const SortedVector<AssetDir::FileInfo>* pContents);
void loadFileNameCacheLocked(void);
void fncScanLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
const char* dirName);
bool fncScanAndMergeDirLocked(
SortedVector<AssetDir::FileInfo>* 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<SharedZip> 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<String8, wp<SharedZip> > 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<String8> mZipPath;
mutable Vector<sp<SharedZip> > mZipFile;
};
// Protect all internal state.
mutable Mutex mLock;
ZipSet mZipSet;
Vector<asset_path> 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<AssetDir::FileInfo> mCache;
};
}; // namespace android
#endif // __LIBS_ASSETMANAGER_H

View File

@ -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 <utils/Errors.h>
#include <utils/String8.h>
#include <utils/KeyedVector.h>
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<String8,FileRec> 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

View File

@ -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 <cutils/log.h>
#include <stddef.h>
#include <stdint.h>
#include <binder/Parcel.h>
#include <utils/String8.h>
#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<char*>(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<uint8_t*>(mData) + offset;
}
inline uint32_t offsetFromPtr(void* ptr) {
return static_cast<uint8_t*>(ptr) - static_cast<uint8_t*>(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

View File

@ -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 <stdint.h>
#include <strings.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
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_ */

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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 <unistd.h>
#include <inttypes.h>
#include <zlib.h>
#include <utils/Compat.h>
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

View File

@ -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 <utils/Compat.h>
#include <utils/Errors.h>
#include <utils/FileMap.h>
#include <utils/threads.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
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*/

View File

@ -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 <stdio.h>
#include <time.h>
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*/

View File

@ -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 <sys/types.h>
//
// 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

View File

@ -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

View File

@ -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 <androidfw/Asset.h>
#include <androidfw/StreamingZipInflater.h>
#include <androidfw/ZipFileRO.h>
#include <androidfw/ZipUtils.h>
#include <utils/Atomic.h>
#include <utils/FileMap.h>
#include <utils/Log.h>
#include <utils/threads.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <memory.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
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;
}

View File

@ -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 <androidfw/AssetDir.h>
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<FileInfo>* 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
}

File diff suppressed because it is too large Load Diff

View File

@ -1,382 +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 "backup_data"
#include <androidfw/BackupHelpers.h>
#include <utils/ByteOrder.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <cutils/log.h>
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

File diff suppressed because it is too large Load Diff

View File

@ -1,352 +0,0 @@
/*
* Copyright (C) 2006-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.
*/
#undef LOG_TAG
#define LOG_TAG "CursorWindow"
#include <androidfw/CursorWindow.h>
#include <binder/Parcel.h>
#include <utils/Log.h>
#include <cutils/ashmem.h>
#include <sys/mman.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
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<Header*>(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<RowSlotChunk*>(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<FieldSlot*>(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<RowSlotChunk*>(
offsetToPtr(mHeader->firstChunkOffset));
while (chunkPos >= ROW_SLOT_CHUNK_NUM_ROWS) {
chunk = static_cast<RowSlotChunk*>(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<RowSlotChunk*>(
offsetToPtr(mHeader->firstChunkOffset));
while (chunkPos > ROW_SLOT_CHUNK_NUM_ROWS) {
chunk = static_cast<RowSlotChunk*>(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<RowSlotChunk*>(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<FieldSlot*>(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

View File

@ -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

View File

@ -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 <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define LOG_TAG "ObbFile"
#include <androidfw/ObbFile.h>
#include <utils/Compat.h>
#include <utils/Log.h>
//#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
* <unistd.h>. (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<char*>(scanBuf + kPackageNameOffset);
mPackageName = String8(const_cast<char*>(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;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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 <utils/Log.h>
#include <androidfw/StreamingZipInflater.h>
#include <utils/FileMap.h>
#include <string.h>
#include <stddef.h>
#include <assert.h>
#include <unistd.h>
#include <errno.h>
/*
* TEMP_FAILURE_RETRY is defined by some, but not all, versions of
* <unistd.h>. (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;
}

View File

@ -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 <androidfw/ZipFileRO.h>
#include <utils/Log.h>
#include <utils/Compat.h>
#include <utils/misc.h>
#include <utils/threads.h>
#include <ziparchive/zip_archive.h>
#include <zlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h>
/*
* 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;
}

View File

@ -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 <androidfw/ZipUtils.h>
#include <androidfw/ZipFileRO.h>
#include <utils/Log.h>
#include <utils/Compat.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <zlib.h>
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<typename T> 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<unsigned char*>(input)),
mInputSize(inputSize),
mBufferReturned(false)
{
}
long read(unsigned char** nextBuffer, long readSize) {
if (!mBufferReturned) {
mBufferReturned = true;
*nextBuffer = mInput;
return mInputSize;
}
*nextBuffer = NULL;
return 0;
}
unsigned char* mInput;
const size_t mInputSize;
bool mBufferReturned;
};
/*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf,
long uncompressedLen, long compressedLen)
{
FileReader reader(fp);
return ::inflateToBuffer<FileReader>(reader, buf,
uncompressedLen, compressedLen);
}
/*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf,
long uncompressedLen, long compressedLen)
{
FdReader reader(fd);
return ::inflateToBuffer<FdReader>(reader, buf,
uncompressedLen, compressedLen);
}
/*static*/ bool ZipUtils::inflateToBuffer(void* in, void* buf,
long uncompressedLen, long compressedLen)
{
BufferReader reader(in, compressedLen);
return ::inflateToBuffer<BufferReader>(reader, buf,
uncompressedLen, compressedLen);
}
/*
* Look at the contents of a gzip archive. We want to know where the
* data starts, and how long it will be after it is uncompressed.
*
* 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;
}

View File

@ -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 <androidfw/misc.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
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

View File

@ -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))

View File

@ -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 <androidfw/BackupHelpers.h>
#include <utils/Log.h>
#include <utils/String8.h>
#include <gtest/gtest.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
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;
}
}

View File

@ -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 <androidfw/ObbFile.h>
#include <utils/Log.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <gtest/gtest.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
namespace android {
#define TEST_FILENAME "/test.obb"
class ObbFileTest : public testing::Test {
protected:
sp<ObbFile> 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";
}
}

View File

@ -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 <utils/Log.h>
#include <androidfw/ZipUtils.h>
#include <gtest/gtest.h>
#include <fcntl.h>
#include <string.h>
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.";
}
}