diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:45 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:45 -0800 |
commit | d83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /libs/utils | |
parent | 076357b8567458d4b6dfdcf839ef751634cd2bfb (diff) | |
download | frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.zip frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.gz frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'libs/utils')
54 files changed, 0 insertions, 23454 deletions
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk deleted file mode 100644 index cdb8ca2..0000000 --- a/libs/utils/Android.mk +++ /dev/null @@ -1,156 +0,0 @@ -# Copyright (C) 2008 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH:= $(call my-dir) - -# libutils is a little unique: It's built twice, once for the host -# and once for the device. - -commonSources:= \ - Asset.cpp \ - AssetDir.cpp \ - AssetManager.cpp \ - BufferedTextOutput.cpp \ - CallStack.cpp \ - Debug.cpp \ - FileMap.cpp \ - RefBase.cpp \ - ResourceTypes.cpp \ - SharedBuffer.cpp \ - Static.cpp \ - StopWatch.cpp \ - String8.cpp \ - String16.cpp \ - SystemClock.cpp \ - TextOutput.cpp \ - Threads.cpp \ - TimerProbe.cpp \ - Timers.cpp \ - VectorImpl.cpp \ - ZipFileCRO.cpp \ - ZipFileRO.cpp \ - ZipUtils.cpp \ - misc.cpp \ - ported.cpp \ - LogSocket.cpp - -# -# The cpp files listed here do not belong in the device -# build. Consult with the swetland before even thinking about -# putting them in commonSources. -# -# They're used by the simulator runtime and by host-side tools like -# aapt and the simulator front-end. -# -hostSources:= \ - InetAddress.cpp \ - Pipe.cpp \ - Socket.cpp \ - ZipEntry.cpp \ - ZipFile.cpp - -# For the host -# ===================================================== - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= $(commonSources) $(hostSources) - -ifeq ($(HOST_OS),linux) -# Use the futex based mutex and condition variable -# implementation from android-arm because it's shared mem safe - LOCAL_SRC_FILES += \ - futex_synchro.c \ - executablepath_linux.cpp -endif -ifeq ($(HOST_OS),darwin) - LOCAL_SRC_FILES += \ - executablepath_darwin.cpp -endif - -LOCAL_MODULE:= libutils - -LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS) -LOCAL_C_INCLUDES += external/zlib - -ifeq ($(HOST_OS),windows) -ifeq ($(strip $(USE_CYGWIN),),) -# Under MinGW, ctype.h doesn't need multi-byte support -LOCAL_CFLAGS += -DMB_CUR_MAX=1 -endif -endif - -include $(BUILD_HOST_STATIC_LIBRARY) - - - -# For the device -# ===================================================== -include $(CLEAR_VARS) - - -# we have the common sources, plus some device-specific stuff -LOCAL_SRC_FILES:= \ - $(commonSources) \ - Binder.cpp \ - BpBinder.cpp \ - IInterface.cpp \ - IMemory.cpp \ - IPCThreadState.cpp \ - MemoryDealer.cpp \ - MemoryBase.cpp \ - MemoryHeapBase.cpp \ - MemoryHeapPmem.cpp \ - Parcel.cpp \ - ProcessState.cpp \ - IPermissionController.cpp \ - IServiceManager.cpp \ - Unicode.cpp - -ifeq ($(TARGET_SIMULATOR),true) -LOCAL_SRC_FILES += $(hostSources) -endif - -ifeq ($(TARGET_OS),linux) -# Use the futex based mutex and condition variable -# implementation from android-arm because it's shared mem safe -LOCAL_SRC_FILES += futex_synchro.c -LOCAL_LDLIBS += -lrt -ldl -endif - -LOCAL_C_INCLUDES += \ - external/zlib \ - external/icu4c/common -LOCAL_LDLIBS += -lpthread - -LOCAL_SHARED_LIBRARIES := \ - libz \ - liblog \ - libcutils - -ifneq ($(TARGET_SIMULATOR),true) -ifeq ($(TARGET_OS)-$(TARGET_ARCH),linux-x86) -# This is needed on x86 to bring in dl_iterate_phdr for CallStack.cpp -LOCAL_SHARED_LIBRARIES += \ - libdl -endif # linux-x86 -endif # sim - -LOCAL_MODULE:= libutils - -#LOCAL_CFLAGS+= -#LOCAL_LDFLAGS:= - -include $(BUILD_SHARED_LIBRARY) - diff --git a/libs/utils/Asset.cpp b/libs/utils/Asset.cpp deleted file mode 100644 index 91203dd..0000000 --- a/libs/utils/Asset.cpp +++ /dev/null @@ -1,813 +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 <utils/Asset.h> -#include <utils/Atomic.h> -#include <utils/FileMap.h> -#include <utils/ZipUtils.h> -#include <utils/ZipFileRO.h> -#include <utils/Log.h> - -#include <string.h> -#include <memory.h> -#include <fcntl.h> -#include <errno.h> -#include <assert.h> - -using namespace android; - -#ifndef O_BINARY -# define O_BINARY 0 -#endif - -static volatile int32_t gCount = 0; - -int32_t Asset::getGlobalCount() -{ - return gCount; -} - -Asset::Asset(void) - : mAccessMode(ACCESS_UNKNOWN) -{ - int count = android_atomic_inc(&gCount)+1; - //LOGI("Creating Asset %p #%d\n", this, count); -} - -Asset::~Asset(void) -{ - int count = android_atomic_dec(&gCount); - //LOGI("Destroying Asset in %p #%d\n", this, count); -} - -/* - * 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; - off_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. - */ - length = lseek(fd, 0, SEEK_END); - if (length < 0) { - ::close(fd); - return NULL; - } - (void) lseek(fd, 0, SEEK_SET); - - 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; - off_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) { - LOGD("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, off_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, off_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. - */ -off_t Asset::handleSeek(off_t offset, int whence, off_t curPosn, off_t maxPosn) -{ - off_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: - LOGW("unexpected whence %d\n", whence); - // this was happening due to an off_t size mismatch - assert(false); - return (off_t) -1; - } - - if (newOffset < 0 || newOffset > maxPosn) { - LOGW("seek out of range: want %ld, end=%ld\n", - (long) newOffset, (long) maxPosn); - return (off_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, off_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. - */ - off_t fileLength; - fileLength = lseek(fd, 0, SEEK_END); - if (fileLength == (off_t) -1) { - // probably a bad file descriptor - LOGD("failed lseek (errno=%d)\n", errno); - return UNKNOWN_ERROR; - } - - if ((off_t) (offset + length) > fileLength) { - LOGD("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) { - LOGE("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. - */ -off_t _FileAsset::seek(off_t offset, int whence) -{ - off_t newPosn; - long actualOffset; - - // compute new position within chunk - newPosn = handleSeek(offset, whence, mOffset, mLength); - if (newPosn == (off_t) -1) - return newPosn; - - actualOffset = (long) (mStart + newPosn); - - if (mFp != NULL) { - if (fseek(mFp, (long) actualOffset, SEEK_SET) != 0) - return (off_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) { - LOGE("alloc of %ld bytes failed\n", (long) allocLen); - return NULL; - } - - LOGV("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) { - LOGE("failed reading %ld bytes\n", (long) mLength); - delete[] buf; - return NULL; - } - fseek(mFp, oldPosn, SEEK_SET); - } - - LOGV(" 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; - } - - LOGV(" getBuffer: mapped\n"); - - mMap = map; - if (!wordAligned) { - return mMap->getDataPtr(); - } - return ensureAlignment(mMap); - } -} - -int _FileAsset::openFileDescriptor(off_t* outStart, off_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. - return data; - } - // If not aligned on a word boundary, then we need to copy it into - // our own buffer. - LOGV("Copying FileAsset %p to buffer size %d to make it aligned.", this, (int)mLength); - unsigned char* buf = new unsigned char[mLength]; - if (buf == NULL) { - LOGE("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), 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, off_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); - - 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); - - 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); - - // TODO: if mAccessMode == ACCESS_STREAMING, use zlib more cleverly - - 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. - */ -off_t _CompressedAsset::seek(off_t offset, int whence) -{ - off_t newPosn; - - // compute new position within chunk - newPosn = handleSeek(offset, whence, mOffset, mUncompressedLen); - if (newPosn == (off_t) -1) - return newPosn; - - mOffset = newPosn; - return mOffset; -} - -/* - * Close the asset. - */ -void _CompressedAsset::close(void) -{ - if (mMap != NULL) { - mMap->release(); - mMap = NULL; - } - if (mBuf != NULL) { - delete[] mBuf; - mBuf = 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 wordAligned) -{ - unsigned char* buf = NULL; - - if (mBuf != NULL) - return mBuf; - - if (mUncompressedLen > UNCOMPRESS_DATA_MAX) { - LOGD("Data exceeds UNCOMPRESS_DATA_MAX (%ld vs %d)\n", - (long) mUncompressedLen, UNCOMPRESS_DATA_MAX); - goto bail; - } - - /* - * Allocate a buffer and read the file into it. - */ - buf = new unsigned char[mUncompressedLen]; - if (buf == NULL) { - LOGW("alloc %ld bytes failed\n", (long) mUncompressedLen); - goto bail; - } - - if (mMap != NULL) { - if (!ZipFileRO::inflateBuffer(buf, mMap->getDataPtr(), - 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! */ - mBuf = buf; - buf = NULL; - -bail: - delete[] buf; - return mBuf; -} - diff --git a/libs/utils/AssetDir.cpp b/libs/utils/AssetDir.cpp deleted file mode 100644 index c5f664e..0000000 --- a/libs/utils/AssetDir.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// Provide access to a virtual directory in "asset space". Most of the -// implementation is in the header file or in friend functions in -// AssetManager. -// -#include <utils/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 -} - diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp deleted file mode 100644 index 447b801..0000000 --- a/libs/utils/AssetManager.cpp +++ /dev/null @@ -1,1637 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// Provide access to read-only assets. -// - -#define LOG_TAG "asset" -//#define LOG_NDEBUG 0 - -#include <utils/AssetManager.h> -#include <utils/AssetDir.h> -#include <utils/Asset.h> -#include <utils/Atomic.h> -#include <utils/String8.h> -#include <utils/ResourceTypes.h> -#include <utils/String8.h> -#include <utils/ZipFileRO.h> -#include <utils/Log.h> -#include <utils/Timers.h> -#include <utils/threads.h> - -#include <dirent.h> -#include <errno.h> -#include <assert.h> - -using namespace android; - -/* - * Names for default app, locale, and vendor. We might want to change - * these to be an actual locale, e.g. always use en-US as the default. - */ -static const char* kDefaultLocale = "default"; -static const char* kDefaultVendor = "default"; -static const char* kAssetsRoot = "assets"; -static const char* kAppZipName = NULL; //"classes.jar"; -static const char* kSystemAssets = "framework/framework-res.apk"; - -static const char* kExcludeExtension = ".EXCLUDE"; - -static Asset* const kExcludedAsset = (Asset*) 0xd000000d; - -static volatile int32_t gCount = 0; - - -/* - * =========================================================================== - * AssetManager - * =========================================================================== - */ - -int32_t AssetManager::getGlobalCount() -{ - return gCount; -} - -AssetManager::AssetManager(CacheMode cacheMode) - : mLocale(NULL), mVendor(NULL), - mResources(NULL), mConfig(new ResTable_config), - mCacheMode(cacheMode), mCacheValid(false) -{ - int count = android_atomic_inc(&gCount)+1; - //LOGI("Creating AssetManager %p #%d\n", this, count); - memset(mConfig, 0, sizeof(ResTable_config)); -} - -AssetManager::~AssetManager(void) -{ - int count = android_atomic_dec(&gCount); - //LOGI("Destroying AssetManager in %p #%d\n", this, count); - - delete mConfig; - delete mResources; - - // don't have a String class yet, so make sure we clean up - delete[] mLocale; - delete[] mVendor; -} - -bool AssetManager::addAssetPath(const String8& path, void** cookie) -{ - AutoMutex _l(mLock); - - asset_path ap; - - String8 realPath(path); - if (kAppZipName) { - realPath.appendPath(kAppZipName); - } - ap.type = ::getFileType(realPath.string()); - if (ap.type == kFileTypeRegular) { - ap.path = realPath; - } else { - ap.path = path; - ap.type = ::getFileType(path.string()); - if (ap.type != kFileTypeDirectory && ap.type != kFileTypeRegular) { - LOGW("Asset path %s is neither a directory nor file (type=%d).", - path.string(), (int)ap.type); - return false; - } - } - - // Skip if we have it already. - for (size_t i=0; i<mAssetPaths.size(); i++) { - if (mAssetPaths[i].path == ap.path) { - if (cookie) { - *cookie = (void*)(i+1); - } - return true; - } - } - - LOGV("In %p Asset %s path: %s", this, - ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string()); - - mAssetPaths.add(ap); - - // new paths are always added at the end - if (cookie) { - *cookie = (void*)mAssetPaths.size(); - } - - return true; -} - -bool AssetManager::addDefaultAssets() -{ - const char* root = getenv("ANDROID_ROOT"); - LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_ROOT not set"); - - String8 path(root); - path.appendPath(kSystemAssets); - - return addAssetPath(path, NULL); -} - -void* AssetManager::nextAssetPath(void* cookie) const -{ - AutoMutex _l(mLock); - size_t next = ((size_t)cookie)+1; - return next > mAssetPaths.size() ? NULL : (void*)next; -} - -String8 AssetManager::getAssetPath(void* cookie) const -{ - AutoMutex _l(mLock); - const size_t which = ((size_t)cookie)-1; - if (which < mAssetPaths.size()) { - return mAssetPaths[which].path; - } - return String8(); -} - -/* - * Set the current locale. Use NULL to indicate no locale. - * - * Close and reopen Zip archives as appropriate, and reset cached - * information in the locale-specific sections of the tree. - */ -void AssetManager::setLocale(const char* locale) -{ - AutoMutex _l(mLock); - setLocaleLocked(locale); -} - -void AssetManager::setLocaleLocked(const char* locale) -{ - if (mLocale != NULL) { - /* previously set, purge cached data */ - purgeFileNameCacheLocked(); - //mZipSet.purgeLocale(); - delete[] mLocale; - } - mLocale = strdupNew(locale); - - updateResourceParamsLocked(); -} - -/* - * Set the current vendor. Use NULL to indicate no vendor. - * - * Close and reopen Zip archives as appropriate, and reset cached - * information in the vendor-specific sections of the tree. - */ -void AssetManager::setVendor(const char* vendor) -{ - AutoMutex _l(mLock); - - if (mVendor != NULL) { - /* previously set, purge cached data */ - purgeFileNameCacheLocked(); - //mZipSet.purgeVendor(); - delete[] mVendor; - } - mVendor = strdupNew(vendor); -} - -void AssetManager::setConfiguration(const ResTable_config& config, const char* locale) -{ - AutoMutex _l(mLock); - *mConfig = config; - if (locale) { - setLocaleLocked(locale); - } else if (config.language[0] != 0) { - char spec[9]; - spec[0] = config.language[0]; - spec[1] = config.language[1]; - if (config.country[0] != 0) { - spec[2] = '_'; - spec[3] = config.country[0]; - spec[4] = config.country[1]; - spec[5] = 0; - } else { - spec[3] = 0; - } - setLocaleLocked(spec); - } else { - updateResourceParamsLocked(); - } -} - -/* - * Open an asset. - * - * The data could be; - * - In a file on disk (assetBase + fileName). - * - In a compressed file on disk (assetBase + fileName.gz). - * - In a Zip archive, uncompressed or compressed. - * - * It can be in a number of different directories and Zip archives. - * The search order is: - * - [appname] - * - locale + vendor - * - "default" + vendor - * - locale + "default" - * - "default + "default" - * - "common" - * - (same as above) - * - * To find a particular file, we have to try up to eight paths with - * all three forms of data. - * - * We should probably reject requests for "illegal" filenames, e.g. those - * with illegal characters or "../" backward relative paths. - */ -Asset* AssetManager::open(const char* fileName, AccessMode mode) -{ - AutoMutex _l(mLock); - - LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager"); - - - if (mCacheMode != CACHE_OFF && !mCacheValid) - loadFileNameCacheLocked(); - - String8 assetName(kAssetsRoot); - assetName.appendPath(fileName); - - /* - * For each top-level asset path, search for the asset. - */ - - size_t i = mAssetPaths.size(); - while (i > 0) { - i--; - LOGV("Looking for asset '%s' in '%s'\n", - assetName.string(), mAssetPaths.itemAt(i).path.string()); - Asset* pAsset = openNonAssetInPathLocked(assetName.string(), mode, mAssetPaths.itemAt(i)); - if (pAsset != NULL) { - return pAsset != kExcludedAsset ? pAsset : NULL; - } - } - - return NULL; -} - -/* - * Open a non-asset file as if it were an asset. - * - * The "fileName" is the partial path starting from the application - * name. - */ -Asset* AssetManager::openNonAsset(const char* fileName, AccessMode mode) -{ - AutoMutex _l(mLock); - - LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager"); - - - if (mCacheMode != CACHE_OFF && !mCacheValid) - loadFileNameCacheLocked(); - - /* - * For each top-level asset path, search for the asset. - */ - - size_t i = mAssetPaths.size(); - while (i > 0) { - i--; - LOGV("Looking for non-asset '%s' in '%s'\n", fileName, mAssetPaths.itemAt(i).path.string()); - Asset* pAsset = openNonAssetInPathLocked( - fileName, mode, mAssetPaths.itemAt(i)); - if (pAsset != NULL) { - return pAsset != kExcludedAsset ? pAsset : NULL; - } - } - - return NULL; -} - -Asset* AssetManager::openNonAsset(void* cookie, const char* fileName, AccessMode mode) -{ - const size_t which = ((size_t)cookie)-1; - - AutoMutex _l(mLock); - - LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager"); - - - if (mCacheMode != CACHE_OFF && !mCacheValid) - loadFileNameCacheLocked(); - - if (which < mAssetPaths.size()) { - LOGV("Looking for non-asset '%s' in '%s'\n", fileName, - mAssetPaths.itemAt(which).path.string()); - Asset* pAsset = openNonAssetInPathLocked( - fileName, mode, mAssetPaths.itemAt(which)); - if (pAsset != NULL) { - return pAsset != kExcludedAsset ? pAsset : NULL; - } - } - - return NULL; -} - -/* - * Get the type of a file in the asset namespace. - * - * This currently only works for regular files. All others (including - * directories) will return kFileTypeNonexistent. - */ -FileType AssetManager::getFileType(const char* fileName) -{ - Asset* pAsset = NULL; - - /* - * Open the asset. This is less efficient than simply finding the - * file, but it's not too bad (we don't uncompress or mmap data until - * the first read() call). - */ - pAsset = open(fileName, Asset::ACCESS_STREAMING); - delete pAsset; - - if (pAsset == NULL) - return kFileTypeNonexistent; - else - return kFileTypeRegular; -} - -const ResTable* AssetManager::getResTable(bool required) const -{ - ResTable* rt = mResources; - if (rt) { - return rt; - } - - // Iterate through all asset packages, collecting resources from each. - - AutoMutex _l(mLock); - - if (mResources != NULL) { - return mResources; - } - - if (required) { - LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager"); - } - - if (mCacheMode != CACHE_OFF && !mCacheValid) - const_cast<AssetManager*>(this)->loadFileNameCacheLocked(); - - const size_t N = mAssetPaths.size(); - for (size_t i=0; i<N; i++) { - Asset* ass = NULL; - bool shared = true; - const asset_path& ap = mAssetPaths.itemAt(i); - LOGV("Looking for resource asset in '%s'\n", ap.path.string()); - if (ap.type != kFileTypeDirectory) { - ass = const_cast<AssetManager*>(this)-> - mZipSet.getZipResourceTable(ap.path); - if (ass == NULL) { - LOGV("loading resource table %s\n", ap.path.string()); - ass = const_cast<AssetManager*>(this)-> - openNonAssetInPathLocked("resources.arsc", - Asset::ACCESS_BUFFER, - ap); - if (ass != NULL && ass != kExcludedAsset) { - ass = const_cast<AssetManager*>(this)-> - mZipSet.setZipResourceTable(ap.path, ass); - } - } - } else { - LOGV("loading resource table %s\n", ap.path.string()); - Asset* ass = const_cast<AssetManager*>(this)-> - openNonAssetInPathLocked("resources.arsc", - Asset::ACCESS_BUFFER, - ap); - shared = false; - } - if (ass != NULL && ass != kExcludedAsset) { - if (rt == NULL) { - mResources = rt = new ResTable(); - updateResourceParamsLocked(); - } - LOGV("Installing resource asset %p in to table %p\n", ass, mResources); - rt->add(ass, (void*)(i+1), !shared); - - if (!shared) { - delete ass; - } - } - } - - if (required && !rt) LOGW("Unable to find resources file resources.arsc"); - if (!rt) { - mResources = rt = new ResTable(); - } - return rt; -} - -void AssetManager::updateResourceParamsLocked() const -{ - ResTable* res = mResources; - if (!res) { - return; - } - - size_t llen = mLocale ? strlen(mLocale) : 0; - mConfig->language[0] = 0; - mConfig->language[1] = 0; - mConfig->country[0] = 0; - mConfig->country[1] = 0; - if (llen >= 2) { - mConfig->language[0] = mLocale[0]; - mConfig->language[1] = mLocale[1]; - } - if (llen >= 5) { - mConfig->country[0] = mLocale[3]; - mConfig->country[1] = mLocale[4]; - } - mConfig->size = sizeof(*mConfig); - - res->setParameters(mConfig); -} - -const ResTable& AssetManager::getResources(bool required) const -{ - const ResTable* rt = getResTable(required); - return *rt; -} - -bool AssetManager::isUpToDate() -{ - AutoMutex _l(mLock); - return mZipSet.isUpToDate(); -} - -void AssetManager::getLocales(Vector<String8>* locales) const -{ - ResTable* res = mResources; - if (res != NULL) { - res->getLocales(locales); - } -} - -/* - * Open a non-asset file as if it were an asset, searching for it in the - * specified app. - * - * Pass in a NULL values for "appName" if the common app directory should - * be used. - */ -Asset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode mode, - const asset_path& ap) -{ - Asset* pAsset = NULL; - - /* look at the filesystem on disk */ - if (ap.type == kFileTypeDirectory) { - String8 path(ap.path); - path.appendPath(fileName); - - pAsset = openAssetFromFileLocked(path, mode); - - if (pAsset == NULL) { - /* try again, this time with ".gz" */ - path.append(".gz"); - pAsset = openAssetFromFileLocked(path, mode); - } - - if (pAsset != NULL) { - //printf("FOUND NA '%s' on disk\n", fileName); - pAsset->setAssetSource(path); - } - - /* look inside the zip file */ - } else { - String8 path(fileName); - - /* check the appropriate Zip file */ - ZipFileRO* pZip; - ZipEntryRO entry; - - pZip = getZipFileLocked(ap); - if (pZip != NULL) { - //printf("GOT zip, checking NA '%s'\n", (const char*) path); - entry = pZip->findEntryByName(path.string()); - if (entry != NULL) { - //printf("FOUND NA in Zip file for %s\n", appName ? appName : kAppCommon); - pAsset = openAssetFromZipLocked(pZip, entry, mode, path); - } - } - - if (pAsset != NULL) { - /* create a "source" name, for debug/display */ - pAsset->setAssetSource( - createZipSourceNameLocked(ZipSet::getPathName(ap.path.string()), String8(""), - String8(fileName))); - } - } - - return pAsset; -} - -/* - * Open an asset, searching for it in the directory hierarchy for the - * specified app. - * - * Pass in a NULL values for "appName" if the common app directory should - * be used. - */ -Asset* AssetManager::openInPathLocked(const char* fileName, AccessMode mode, - const asset_path& ap) -{ - Asset* pAsset = NULL; - - /* - * Try various combinations of locale and vendor. - */ - if (mLocale != NULL && mVendor != NULL) - pAsset = openInLocaleVendorLocked(fileName, mode, ap, mLocale, mVendor); - if (pAsset == NULL && mVendor != NULL) - pAsset = openInLocaleVendorLocked(fileName, mode, ap, NULL, mVendor); - if (pAsset == NULL && mLocale != NULL) - pAsset = openInLocaleVendorLocked(fileName, mode, ap, mLocale, NULL); - if (pAsset == NULL) - pAsset = openInLocaleVendorLocked(fileName, mode, ap, NULL, NULL); - - return pAsset; -} - -/* - * Open an asset, searching for it in the directory hierarchy for the - * specified locale and vendor. - * - * We also search in "app.jar". - * - * Pass in NULL values for "appName", "locale", and "vendor" if the - * defaults should be used. - */ -Asset* AssetManager::openInLocaleVendorLocked(const char* fileName, AccessMode mode, - const asset_path& ap, const char* locale, const char* vendor) -{ - Asset* pAsset = NULL; - - if (ap.type == kFileTypeDirectory) { - if (mCacheMode == CACHE_OFF) { - /* look at the filesystem on disk */ - String8 path(createPathNameLocked(ap, locale, vendor)); - path.appendPath(fileName); - - String8 excludeName(path); - excludeName.append(kExcludeExtension); - if (::getFileType(excludeName.string()) != kFileTypeNonexistent) { - /* say no more */ - //printf("+++ excluding '%s'\n", (const char*) excludeName); - return kExcludedAsset; - } - - pAsset = openAssetFromFileLocked(path, mode); - - if (pAsset == NULL) { - /* try again, this time with ".gz" */ - path.append(".gz"); - pAsset = openAssetFromFileLocked(path, mode); - } - - if (pAsset != NULL) - pAsset->setAssetSource(path); - } else { - /* find in cache */ - String8 path(createPathNameLocked(ap, locale, vendor)); - path.appendPath(fileName); - - AssetDir::FileInfo tmpInfo; - bool found = false; - - String8 excludeName(path); - excludeName.append(kExcludeExtension); - - if (mCache.indexOf(excludeName) != NAME_NOT_FOUND) { - /* go no farther */ - //printf("+++ Excluding '%s'\n", (const char*) excludeName); - return kExcludedAsset; - } - - /* - * File compression extensions (".gz") don't get stored in the - * name cache, so we have to try both here. - */ - if (mCache.indexOf(path) != NAME_NOT_FOUND) { - found = true; - pAsset = openAssetFromFileLocked(path, mode); - if (pAsset == NULL) { - /* try again, this time with ".gz" */ - path.append(".gz"); - pAsset = openAssetFromFileLocked(path, mode); - } - } - - if (pAsset != NULL) - pAsset->setAssetSource(path); - - /* - * Don't continue the search into the Zip files. Our cached info - * said it was a file on disk; to be consistent with openDir() - * we want to return the loose asset. If the cached file gets - * removed, we fail. - * - * The alternative is to update our cache when files get deleted, - * or make some sort of "best effort" promise, but for now I'm - * taking the hard line. - */ - if (found) { - if (pAsset == NULL) - LOGD("Expected file not found: '%s'\n", path.string()); - return pAsset; - } - } - } - - /* - * Either it wasn't found on disk or on the cached view of the disk. - * Dig through the currently-opened set of Zip files. If caching - * is disabled, the Zip file may get reopened. - */ - if (pAsset == NULL && ap.type == kFileTypeRegular) { - String8 path; - - path.appendPath((locale != NULL) ? locale : kDefaultLocale); - path.appendPath((vendor != NULL) ? vendor : kDefaultVendor); - path.appendPath(fileName); - - /* check the appropriate Zip file */ - ZipFileRO* pZip; - ZipEntryRO entry; - - pZip = getZipFileLocked(ap); - if (pZip != NULL) { - //printf("GOT zip, checking '%s'\n", (const char*) path); - entry = pZip->findEntryByName(path.string()); - if (entry != NULL) { - //printf("FOUND in Zip file for %s/%s-%s\n", - // appName, locale, vendor); - pAsset = openAssetFromZipLocked(pZip, entry, mode, path); - } - } - - if (pAsset != NULL) { - /* create a "source" name, for debug/display */ - pAsset->setAssetSource(createZipSourceNameLocked(ZipSet::getPathName(ap.path.string()), - String8(""), String8(fileName))); - } - } - - return pAsset; -} - -/* - * Create a "source name" for a file from a Zip archive. - */ -String8 AssetManager::createZipSourceNameLocked(const String8& zipFileName, - const String8& dirName, const String8& fileName) -{ - String8 sourceName("zip:"); - sourceName.append(zipFileName); - sourceName.append(":"); - if (dirName.length() > 0) { - sourceName.appendPath(dirName); - } - sourceName.appendPath(fileName); - return sourceName; -} - -/* - * Create a path to a loose asset (asset-base/app/locale/vendor). - */ -String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* locale, - const char* vendor) -{ - String8 path(ap.path); - path.appendPath((locale != NULL) ? locale : kDefaultLocale); - path.appendPath((vendor != NULL) ? vendor : kDefaultVendor); - return path; -} - -/* - * Create a path to a loose asset (asset-base/app/rootDir). - */ -String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* rootDir) -{ - String8 path(ap.path); - if (rootDir != NULL) path.appendPath(rootDir); - return path; -} - -/* - * Return a pointer to one of our open Zip archives. Returns NULL if no - * matching Zip file exists. - * - * Right now we have 2 possible Zip files (1 each in app/"common"). - * - * If caching is set to CACHE_OFF, to get the expected behavior we - * need to reopen the Zip file on every request. That would be silly - * and expensive, so instead we just check the file modification date. - * - * Pass in NULL values for "appName", "locale", and "vendor" if the - * generics should be used. - */ -ZipFileRO* AssetManager::getZipFileLocked(const asset_path& ap) -{ - LOGV("getZipFileLocked() in %p\n", this); - - return mZipSet.getZip(ap.path); -} - -/* - * Try to open an asset from a file on disk. - * - * If the file is compressed with gzip, we seek to the start of the - * deflated data and pass that in (just like we would for a Zip archive). - * - * For uncompressed data, we may already have an mmap()ed version sitting - * around. If so, we want to hand that to the Asset instead. - * - * This returns NULL if the file doesn't exist, couldn't be opened, or - * claims to be a ".gz" but isn't. - */ -Asset* AssetManager::openAssetFromFileLocked(const String8& pathName, - AccessMode mode) -{ - Asset* pAsset = NULL; - - if (strcasecmp(pathName.getPathExtension().string(), ".gz") == 0) { - //printf("TRYING '%s'\n", (const char*) pathName); - pAsset = Asset::createFromCompressedFile(pathName.string(), mode); - } else { - //printf("TRYING '%s'\n", (const char*) pathName); - pAsset = Asset::createFromFile(pathName.string(), mode); - } - - return pAsset; -} - -/* - * Given an entry in a Zip archive, create a new Asset object. - * - * If the entry is uncompressed, we may want to create or share a - * slice of shared memory. - */ -Asset* AssetManager::openAssetFromZipLocked(const ZipFileRO* pZipFile, - const ZipEntryRO entry, AccessMode mode, const String8& entryName) -{ - Asset* pAsset = NULL; - - // TODO: look for previously-created shared memory slice? - int method; - long uncompressedLen; - - //printf("USING Zip '%s'\n", pEntry->getFileName()); - - //pZipFile->getEntryInfo(entry, &method, &uncompressedLen, &compressedLen, - // &offset); - if (!pZipFile->getEntryInfo(entry, &method, &uncompressedLen, NULL, NULL, - NULL, NULL)) - { - LOGW("getEntryInfo failed\n"); - return NULL; - } - - FileMap* dataMap = pZipFile->createEntryFileMap(entry); - if (dataMap == NULL) { - LOGW("create map from entry failed\n"); - return NULL; - } - - if (method == ZipFileRO::kCompressStored) { - pAsset = Asset::createFromUncompressedMap(dataMap, mode); - LOGV("Opened uncompressed entry %s in zip %s mode %d: %p", entryName.string(), - dataMap->getFileName(), mode, pAsset); - } else { - pAsset = Asset::createFromCompressedMap(dataMap, method, - uncompressedLen, mode); - LOGV("Opened compressed entry %s in zip %s mode %d: %p", entryName.string(), - dataMap->getFileName(), mode, pAsset); - } - if (pAsset == NULL) { - /* unexpected */ - LOGW("create from segment failed\n"); - } - - return pAsset; -} - - - -/* - * Open a directory in the asset namespace. - * - * An "asset directory" is simply the combination of all files in all - * locations, with ".gz" stripped for loose files. With app, locale, and - * vendor defined, we have 8 directories and 2 Zip archives to scan. - * - * Pass in "" for the root dir. - */ -AssetDir* AssetManager::openDir(const char* dirName) -{ - AutoMutex _l(mLock); - - AssetDir* pDir = NULL; - SortedVector<AssetDir::FileInfo>* pMergedInfo = NULL; - - LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager"); - assert(dirName != NULL); - - //printf("+++ openDir(%s) in '%s'\n", dirName, (const char*) mAssetBase); - - if (mCacheMode != CACHE_OFF && !mCacheValid) - loadFileNameCacheLocked(); - - pDir = new AssetDir; - - /* - * Scan the various directories, merging what we find into a single - * vector. We want to scan them in reverse priority order so that - * the ".EXCLUDE" processing works correctly. Also, if we decide we - * want to remember where the file is coming from, we'll get the right - * version. - * - * We start with Zip archives, then do loose files. - */ - pMergedInfo = new SortedVector<AssetDir::FileInfo>; - - size_t i = mAssetPaths.size(); - while (i > 0) { - i--; - const asset_path& ap = mAssetPaths.itemAt(i); - if (ap.type == kFileTypeRegular) { - LOGV("Adding directory %s from zip %s", dirName, ap.path.string()); - scanAndMergeZipLocked(pMergedInfo, ap, kAssetsRoot, dirName); - } else { - LOGV("Adding directory %s from dir %s", dirName, ap.path.string()); - scanAndMergeDirLocked(pMergedInfo, ap, kAssetsRoot, dirName); - } - } - -#if 0 - printf("FILE LIST:\n"); - for (i = 0; i < (size_t) pMergedInfo->size(); i++) { - printf(" %d: (%d) '%s'\n", i, - pMergedInfo->itemAt(i).getFileType(), - (const char*) pMergedInfo->itemAt(i).getFileName()); - } -#endif - - pDir->setFileList(pMergedInfo); - return pDir; -} - -/* - * Scan the contents of the specified directory and merge them into the - * "pMergedInfo" vector, removing previous entries if we find "exclude" - * directives. - * - * Returns "false" if we found nothing to contribute. - */ -bool AssetManager::scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo, - const asset_path& ap, const char* rootDir, const char* dirName) -{ - SortedVector<AssetDir::FileInfo>* pContents; - String8 path; - - assert(pMergedInfo != NULL); - - //printf("scanAndMergeDir: %s %s %s %s\n", appName, locale, vendor,dirName); - - if (mCacheValid) { - int i, start, count; - - pContents = new SortedVector<AssetDir::FileInfo>; - - /* - * Get the basic partial path and find it in the cache. That's - * the start point for the search. - */ - path = createPathNameLocked(ap, rootDir); - if (dirName[0] != '\0') - path.appendPath(dirName); - - start = mCache.indexOf(path); - if (start == NAME_NOT_FOUND) { - //printf("+++ not found in cache: dir '%s'\n", (const char*) path); - delete pContents; - return false; - } - - /* - * The match string looks like "common/default/default/foo/bar/". - * The '/' on the end ensures that we don't match on the directory - * itself or on ".../foo/barfy/". - */ - path.append("/"); - - count = mCache.size(); - - /* - * Pick out the stuff in the current dir by examining the pathname. - * It needs to match the partial pathname prefix, and not have a '/' - * (fssep) anywhere after the prefix. - */ - for (i = start+1; i < count; i++) { - if (mCache[i].getFileName().length() > path.length() && - strncmp(mCache[i].getFileName().string(), path.string(), path.length()) == 0) - { - const char* name = mCache[i].getFileName().string(); - // XXX THIS IS BROKEN! Looks like we need to store the full - // path prefix separately from the file path. - if (strchr(name + path.length(), '/') == NULL) { - /* grab it, reducing path to just the filename component */ - AssetDir::FileInfo tmp = mCache[i]; - tmp.setFileName(tmp.getFileName().getPathLeaf()); - pContents->add(tmp); - } - } else { - /* no longer in the dir or its subdirs */ - break; - } - - } - } else { - path = createPathNameLocked(ap, rootDir); - if (dirName[0] != '\0') - path.appendPath(dirName); - pContents = scanDirLocked(path); - if (pContents == NULL) - return false; - } - - // if we wanted to do an incremental cache fill, we would do it here - - /* - * Process "exclude" directives. If we find a filename that ends with - * ".EXCLUDE", we look for a matching entry in the "merged" set, and - * remove it if we find it. We also delete the "exclude" entry. - */ - int i, count, exclExtLen; - - count = pContents->size(); - exclExtLen = strlen(kExcludeExtension); - for (i = 0; i < count; i++) { - const char* name; - int nameLen; - - name = pContents->itemAt(i).getFileName().string(); - nameLen = strlen(name); - if (nameLen > exclExtLen && - strcmp(name + (nameLen - exclExtLen), kExcludeExtension) == 0) - { - String8 match(name, nameLen - exclExtLen); - int matchIdx; - - matchIdx = AssetDir::FileInfo::findEntry(pMergedInfo, match); - if (matchIdx > 0) { - LOGV("Excluding '%s' [%s]\n", - pMergedInfo->itemAt(matchIdx).getFileName().string(), - pMergedInfo->itemAt(matchIdx).getSourceName().string()); - pMergedInfo->removeAt(matchIdx); - } else { - //printf("+++ no match on '%s'\n", (const char*) match); - } - - LOGD("HEY: size=%d removing %d\n", (int)pContents->size(), i); - pContents->removeAt(i); - i--; // adjust "for" loop - count--; // and loop limit - } - } - - mergeInfoLocked(pMergedInfo, pContents); - - delete pContents; - - return true; -} - -/* - * Scan the contents of the specified directory, and stuff what we find - * into a newly-allocated vector. - * - * Files ending in ".gz" will have their extensions removed. - * - * We should probably think about skipping files with "illegal" names, - * e.g. illegal characters (/\:) or excessive length. - * - * Returns NULL if the specified directory doesn't exist. - */ -SortedVector<AssetDir::FileInfo>* AssetManager::scanDirLocked(const String8& path) -{ - SortedVector<AssetDir::FileInfo>* pContents = NULL; - DIR* dir; - struct dirent* entry; - FileType fileType; - - LOGV("Scanning dir '%s'\n", path.string()); - - dir = opendir(path.string()); - if (dir == NULL) - return NULL; - - pContents = new SortedVector<AssetDir::FileInfo>; - - while (1) { - entry = readdir(dir); - if (entry == NULL) - break; - - if (strcmp(entry->d_name, ".") == 0 || - strcmp(entry->d_name, "..") == 0) - continue; - -#ifdef _DIRENT_HAVE_D_TYPE - if (entry->d_type == DT_REG) - fileType = kFileTypeRegular; - else if (entry->d_type == DT_DIR) - fileType = kFileTypeDirectory; - else - fileType = kFileTypeUnknown; -#else - // stat the file - fileType = ::getFileType(path.appendPathCopy(entry->d_name).string()); -#endif - - if (fileType != kFileTypeRegular && fileType != kFileTypeDirectory) - continue; - - AssetDir::FileInfo info; - info.set(String8(entry->d_name), fileType); - if (strcasecmp(info.getFileName().getPathExtension().string(), ".gz") == 0) - info.setFileName(info.getFileName().getBasePath()); - info.setSourceName(path.appendPathCopy(info.getFileName())); - pContents->add(info); - } - - closedir(dir); - return pContents; -} - -/* - * Scan the contents out of the specified Zip archive, and merge what we - * find into "pMergedInfo". If the Zip archive in question doesn't exist, - * we return immediately. - * - * Returns "false" if we found nothing to contribute. - */ -bool AssetManager::scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo, - const asset_path& ap, const char* rootDir, const char* baseDirName) -{ - ZipFileRO* pZip; - Vector<String8> dirs; - AssetDir::FileInfo info; - SortedVector<AssetDir::FileInfo> contents; - String8 sourceName, zipName, dirName; - - pZip = mZipSet.getZip(ap.path); - if (pZip == NULL) { - LOGW("Failure opening zip %s\n", ap.path.string()); - return false; - } - - zipName = ZipSet::getPathName(ap.path.string()); - - /* convert "sounds" to "rootDir/sounds" */ - if (rootDir != NULL) dirName = rootDir; - dirName.appendPath(baseDirName); - - /* - * Scan through the list of files, looking for a match. The files in - * the Zip table of contents are not in sorted order, so we have to - * process the entire list. We're looking for a string that begins - * with the characters in "dirName", is followed by a '/', and has no - * subsequent '/' in the stuff that follows. - * - * What makes this especially fun is that directories are not stored - * explicitly in Zip archives, so we have to infer them from context. - * When we see "sounds/foo.wav" we have to leave a note to ourselves - * to insert a directory called "sounds" into the list. We store - * these in temporary vector so that we only return each one once. - * - * Name comparisons are case-sensitive to match UNIX filesystem - * semantics. - */ - int dirNameLen = dirName.length(); - for (int i = 0; i < pZip->getNumEntries(); i++) { - ZipEntryRO entry; - char nameBuf[256]; - - entry = pZip->findEntryByIndex(i); - if (pZip->getEntryFileName(entry, nameBuf, sizeof(nameBuf)) != 0) { - // TODO: fix this if we expect to have long names - LOGE("ARGH: name too long?\n"); - continue; - } - if (dirNameLen == 0 || - (strncmp(nameBuf, dirName.string(), dirNameLen) == 0 && - nameBuf[dirNameLen] == '/')) - { - const char* cp; - const char* nextSlash; - - cp = nameBuf + dirNameLen; - if (dirNameLen != 0) - cp++; // advance past the '/' - - nextSlash = strchr(cp, '/'); -//xxx this may break if there are bare directory entries - if (nextSlash == NULL) { - /* this is a file in the requested directory */ - - info.set(String8(nameBuf).getPathLeaf(), kFileTypeRegular); - - info.setSourceName( - createZipSourceNameLocked(zipName, dirName, info.getFileName())); - - contents.add(info); - //printf("FOUND: file '%s'\n", (const char*) info.mFileName); - } else { - /* this is a subdir; add it if we don't already have it*/ - String8 subdirName(cp, nextSlash - cp); - size_t j; - size_t N = dirs.size(); - - for (j = 0; j < N; j++) { - if (subdirName == dirs[j]) { - break; - } - } - if (j == N) { - dirs.add(subdirName); - } - - //printf("FOUND: dir '%s'\n", (const char*) subdirName); - } - } - } - - /* - * Add the set of unique directories. - */ - for (int i = 0; i < (int) dirs.size(); i++) { - info.set(dirs[i], kFileTypeDirectory); - info.setSourceName( - createZipSourceNameLocked(zipName, dirName, info.getFileName())); - contents.add(info); - } - - mergeInfoLocked(pMergedInfo, &contents); - - return true; -} - - -/* - * Merge two vectors of FileInfo. - * - * The merged contents will be stuffed into *pMergedInfo. - * - * If an entry for a file exists in both "pMergedInfo" and "pContents", - * we use the newer "pContents" entry. - */ -void AssetManager::mergeInfoLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo, - const SortedVector<AssetDir::FileInfo>* pContents) -{ - /* - * Merge what we found in this directory with what we found in - * other places. - * - * Two basic approaches: - * (1) Create a new array that holds the unique values of the two - * arrays. - * (2) Take the elements from pContents and shove them into pMergedInfo. - * - * Because these are vectors of complex objects, moving elements around - * inside the vector requires constructing new objects and allocating - * storage for members. With approach #1, we're always adding to the - * end, whereas with #2 we could be inserting multiple elements at the - * front of the vector. Approach #1 requires a full copy of the - * contents of pMergedInfo, but approach #2 requires the same copy for - * every insertion at the front of pMergedInfo. - * - * (We should probably use a SortedVector interface that allows us to - * just stuff items in, trusting us to maintain the sort order.) - */ - SortedVector<AssetDir::FileInfo>* pNewSorted; - int mergeMax, contMax; - int mergeIdx, contIdx; - - pNewSorted = new SortedVector<AssetDir::FileInfo>; - mergeMax = pMergedInfo->size(); - contMax = pContents->size(); - mergeIdx = contIdx = 0; - - while (mergeIdx < mergeMax || contIdx < contMax) { - if (mergeIdx == mergeMax) { - /* hit end of "merge" list, copy rest of "contents" */ - pNewSorted->add(pContents->itemAt(contIdx)); - contIdx++; - } else if (contIdx == contMax) { - /* hit end of "cont" list, copy rest of "merge" */ - pNewSorted->add(pMergedInfo->itemAt(mergeIdx)); - mergeIdx++; - } else if (pMergedInfo->itemAt(mergeIdx) == pContents->itemAt(contIdx)) - { - /* items are identical, add newer and advance both indices */ - pNewSorted->add(pContents->itemAt(contIdx)); - mergeIdx++; - contIdx++; - } else if (pMergedInfo->itemAt(mergeIdx) < pContents->itemAt(contIdx)) - { - /* "merge" is lower, add that one */ - pNewSorted->add(pMergedInfo->itemAt(mergeIdx)); - mergeIdx++; - } else { - /* "cont" is lower, add that one */ - assert(pContents->itemAt(contIdx) < pMergedInfo->itemAt(mergeIdx)); - pNewSorted->add(pContents->itemAt(contIdx)); - contIdx++; - } - } - - /* - * Overwrite the "merged" list with the new stuff. - */ - *pMergedInfo = *pNewSorted; - delete pNewSorted; - -#if 0 // for Vector, rather than SortedVector - int i, j; - for (i = pContents->size() -1; i >= 0; i--) { - bool add = true; - - for (j = pMergedInfo->size() -1; j >= 0; j--) { - /* case-sensitive comparisons, to behave like UNIX fs */ - if (strcmp(pContents->itemAt(i).mFileName, - pMergedInfo->itemAt(j).mFileName) == 0) - { - /* match, don't add this entry */ - add = false; - break; - } - } - - if (add) - pMergedInfo->add(pContents->itemAt(i)); - } -#endif -} - - -/* - * Load all files into the file name cache. We want to do this across - * all combinations of { appname, locale, vendor }, performing a recursive - * directory traversal. - * - * This is not the most efficient data structure. Also, gathering the - * information as we needed it (file-by-file or directory-by-directory) - * would be faster. However, on the actual device, 99% of the files will - * live in Zip archives, so this list will be very small. The trouble - * is that we have to check the "loose" files first, so it's important - * that we don't beat the filesystem silly looking for files that aren't - * there. - * - * Note on thread safety: this is the only function that causes updates - * to mCache, and anybody who tries to use it will call here if !mCacheValid, - * so we need to employ a mutex here. - */ -void AssetManager::loadFileNameCacheLocked(void) -{ - assert(!mCacheValid); - assert(mCache.size() == 0); - -#ifdef DO_TIMINGS // need to link against -lrt for this now - DurationTimer timer; - timer.start(); -#endif - - fncScanLocked(&mCache, ""); - -#ifdef DO_TIMINGS - timer.stop(); - LOGD("Cache scan took %.3fms\n", - timer.durationUsecs() / 1000.0); -#endif - -#if 0 - int i; - printf("CACHED FILE LIST (%d entries):\n", mCache.size()); - for (i = 0; i < (int) mCache.size(); i++) { - printf(" %d: (%d) '%s'\n", i, - mCache.itemAt(i).getFileType(), - (const char*) mCache.itemAt(i).getFileName()); - } -#endif - - mCacheValid = true; -} - -/* - * Scan up to 8 versions of the specified directory. - */ -void AssetManager::fncScanLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo, - const char* dirName) -{ - size_t i = mAssetPaths.size(); - while (i > 0) { - i--; - const asset_path& ap = mAssetPaths.itemAt(i); - fncScanAndMergeDirLocked(pMergedInfo, ap, NULL, NULL, dirName); - if (mLocale != NULL) - fncScanAndMergeDirLocked(pMergedInfo, ap, mLocale, NULL, dirName); - if (mVendor != NULL) - fncScanAndMergeDirLocked(pMergedInfo, ap, NULL, mVendor, dirName); - if (mLocale != NULL && mVendor != NULL) - fncScanAndMergeDirLocked(pMergedInfo, ap, mLocale, mVendor, dirName); - } -} - -/* - * Recursively scan this directory and all subdirs. - * - * This is similar to scanAndMergeDir, but we don't remove the .EXCLUDE - * files, and we prepend the extended partial path to the filenames. - */ -bool AssetManager::fncScanAndMergeDirLocked( - SortedVector<AssetDir::FileInfo>* pMergedInfo, - const asset_path& ap, const char* locale, const char* vendor, - const char* dirName) -{ - SortedVector<AssetDir::FileInfo>* pContents; - String8 partialPath; - String8 fullPath; - - // XXX This is broken -- the filename cache needs to hold the base - // asset path separately from its filename. - - partialPath = createPathNameLocked(ap, locale, vendor); - if (dirName[0] != '\0') { - partialPath.appendPath(dirName); - } - - fullPath = partialPath; - pContents = scanDirLocked(fullPath); - if (pContents == NULL) { - return false; // directory did not exist - } - - /* - * Scan all subdirectories of the current dir, merging what we find - * into "pMergedInfo". - */ - for (int i = 0; i < (int) pContents->size(); i++) { - if (pContents->itemAt(i).getFileType() == kFileTypeDirectory) { - String8 subdir(dirName); - subdir.appendPath(pContents->itemAt(i).getFileName()); - - fncScanAndMergeDirLocked(pMergedInfo, ap, locale, vendor, subdir.string()); - } - } - - /* - * To be consistent, we want entries for the root directory. If - * we're the root, add one now. - */ - if (dirName[0] == '\0') { - AssetDir::FileInfo tmpInfo; - - tmpInfo.set(String8(""), kFileTypeDirectory); - tmpInfo.setSourceName(createPathNameLocked(ap, locale, vendor)); - pContents->add(tmpInfo); - } - - /* - * We want to prepend the extended partial path to every entry in - * "pContents". It's the same value for each entry, so this will - * not change the sorting order of the vector contents. - */ - for (int i = 0; i < (int) pContents->size(); i++) { - const AssetDir::FileInfo& info = pContents->itemAt(i); - pContents->editItemAt(i).setFileName(partialPath.appendPathCopy(info.getFileName())); - } - - mergeInfoLocked(pMergedInfo, pContents); - return true; -} - -/* - * Trash the cache. - */ -void AssetManager::purgeFileNameCacheLocked(void) -{ - mCacheValid = false; - mCache.clear(); -} - -/* - * =========================================================================== - * AssetManager::SharedZip - * =========================================================================== - */ - - -Mutex AssetManager::SharedZip::gLock; -DefaultKeyedVector<String8, wp<AssetManager::SharedZip> > AssetManager::SharedZip::gOpen; - -AssetManager::SharedZip::SharedZip(const String8& path, time_t modWhen) - : mPath(path), mZipFile(NULL), mModWhen(modWhen), mResourceTableAsset(NULL) -{ - //LOGI("Creating SharedZip %p %s\n", this, (const char*)mPath); - mZipFile = new ZipFileRO; - LOGV("+++ opening zip '%s'\n", mPath.string()); - if (mZipFile->open(mPath.string()) != NO_ERROR) { - LOGD("failed to open Zip archive '%s'\n", mPath.string()); - delete mZipFile; - mZipFile = NULL; - } -} - -sp<AssetManager::SharedZip> AssetManager::SharedZip::get(const String8& path) -{ - AutoMutex _l(gLock); - time_t modWhen = getFileModDate(path); - sp<SharedZip> zip = gOpen.valueFor(path).promote(); - if (zip != NULL && zip->mModWhen == modWhen) { - return zip; - } - zip = new SharedZip(path, modWhen); - gOpen.add(path, zip); - return zip; - -} - -ZipFileRO* AssetManager::SharedZip::getZip() -{ - return mZipFile; -} - -Asset* AssetManager::SharedZip::getResourceTableAsset() -{ - LOGV("Getting from SharedZip %p resource asset %p\n", this, mResourceTableAsset); - return mResourceTableAsset; -} - -Asset* AssetManager::SharedZip::setResourceTableAsset(Asset* asset) -{ - { - AutoMutex _l(gLock); - if (mResourceTableAsset == NULL) { - mResourceTableAsset = asset; - // This is not thread safe the first time it is called, so - // do it here with the global lock held. - asset->getBuffer(true); - return asset; - } - } - delete asset; - return mResourceTableAsset; -} - -bool AssetManager::SharedZip::isUpToDate() -{ - time_t modWhen = getFileModDate(mPath.string()); - return mModWhen == modWhen; -} - -AssetManager::SharedZip::~SharedZip() -{ - //LOGI("Destroying SharedZip %p %s\n", this, (const char*)mPath); - if (mResourceTableAsset != NULL) { - delete mResourceTableAsset; - } - if (mZipFile != NULL) { - delete mZipFile; - LOGV("Closed '%s'\n", mPath.string()); - } -} - -/* - * =========================================================================== - * AssetManager::ZipSet - * =========================================================================== - */ - -/* - * Constructor. - */ -AssetManager::ZipSet::ZipSet(void) -{ -} - -/* - * Destructor. Close any open archives. - */ -AssetManager::ZipSet::~ZipSet(void) -{ - size_t N = mZipFile.size(); - for (size_t i = 0; i < N; i++) - closeZip(i); -} - -/* - * Close a Zip file and reset the entry. - */ -void AssetManager::ZipSet::closeZip(int idx) -{ - mZipFile.editItemAt(idx) = NULL; -} - - -/* - * Retrieve the appropriate Zip file from the set. - */ -ZipFileRO* AssetManager::ZipSet::getZip(const String8& path) -{ - int idx = getIndex(path); - sp<SharedZip> zip = mZipFile[idx]; - if (zip == NULL) { - zip = SharedZip::get(path); - mZipFile.editItemAt(idx) = zip; - } - return zip->getZip(); -} - -Asset* AssetManager::ZipSet::getZipResourceTable(const String8& path) -{ - int idx = getIndex(path); - sp<SharedZip> zip = mZipFile[idx]; - if (zip == NULL) { - zip = SharedZip::get(path); - mZipFile.editItemAt(idx) = zip; - } - return zip->getResourceTableAsset(); -} - -Asset* AssetManager::ZipSet::setZipResourceTable(const String8& path, - Asset* asset) -{ - int idx = getIndex(path); - sp<SharedZip> zip = mZipFile[idx]; - // doesn't make sense to call before previously accessing. - return zip->setResourceTableAsset(asset); -} - -/* - * Generate the partial pathname for the specified archive. The caller - * gets to prepend the asset root directory. - * - * Returns something like "common/en-US-noogle.jar". - */ -/*static*/ String8 AssetManager::ZipSet::getPathName(const char* zipPath) -{ - return String8(zipPath); -} - -bool AssetManager::ZipSet::isUpToDate() -{ - const size_t N = mZipFile.size(); - for (size_t i=0; i<N; i++) { - if (mZipFile[i] != NULL && !mZipFile[i]->isUpToDate()) { - return false; - } - } - return true; -} - -/* - * Compute the zip file's index. - * - * "appName", "locale", and "vendor" should be set to NULL to indicate the - * default directory. - */ -int AssetManager::ZipSet::getIndex(const String8& zip) const -{ - const size_t N = mZipPath.size(); - for (size_t i=0; i<N; i++) { - if (mZipPath[i] == zip) { - return i; - } - } - - mZipPath.add(zip); - mZipFile.add(NULL); - - return mZipPath.size()-1; -} - diff --git a/libs/utils/Binder.cpp b/libs/utils/Binder.cpp deleted file mode 100644 index 37e4685..0000000 --- a/libs/utils/Binder.cpp +++ /dev/null @@ -1,242 +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 <utils/Binder.h> - -#include <utils/Atomic.h> -#include <utils/BpBinder.h> -#include <utils/IInterface.h> -#include <utils/Parcel.h> - -#include <stdio.h> - -namespace android { - -// --------------------------------------------------------------------------- - -sp<IInterface> IBinder::queryLocalInterface(const String16& descriptor) -{ - return NULL; -} - -BBinder* IBinder::localBinder() -{ - return NULL; -} - -BpBinder* IBinder::remoteBinder() -{ - return NULL; -} - -bool IBinder::checkSubclass(const void* /*subclassID*/) const -{ - return false; -} - -// --------------------------------------------------------------------------- - -class BBinder::Extras -{ -public: - Mutex mLock; - BpBinder::ObjectManager mObjects; -}; - -// --------------------------------------------------------------------------- - -BBinder::BBinder() - : mExtras(NULL) -{ -} - -bool BBinder::isBinderAlive() const -{ - return true; -} - -status_t BBinder::pingBinder() -{ - return NO_ERROR; -} - -String16 BBinder::getInterfaceDescriptor() const -{ - LOGW("reached BBinder::getInterfaceDescriptor (this=%p)", this); - return String16(); -} - -status_t BBinder::transact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - data.setDataPosition(0); - - status_t err = NO_ERROR; - switch (code) { - case PING_TRANSACTION: - reply->writeInt32(pingBinder()); - break; - default: - err = onTransact(code, data, reply, flags); - break; - } - - if (reply != NULL) { - reply->setDataPosition(0); - } - - return err; -} - -status_t BBinder::linkToDeath( - const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags) -{ - return INVALID_OPERATION; -} - -status_t BBinder::unlinkToDeath( - const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags, - wp<DeathRecipient>* outRecipient) -{ - return INVALID_OPERATION; -} - -status_t BBinder::dump(int fd, const Vector<String16>& args) -{ - return NO_ERROR; -} - -void BBinder::attachObject( - const void* objectID, void* object, void* cleanupCookie, - object_cleanup_func func) -{ - Extras* e = mExtras; - - if (!e) { - e = new Extras; - if (android_atomic_cmpxchg(0, reinterpret_cast<int32_t>(e), - reinterpret_cast<volatile int32_t*>(&mExtras)) != 0) { - delete e; - e = mExtras; - } - if (e == 0) return; // out of memory - } - - AutoMutex _l(e->mLock); - e->mObjects.attach(objectID, object, cleanupCookie, func); -} - -void* BBinder::findObject(const void* objectID) const -{ - Extras* e = mExtras; - if (!e) return NULL; - - AutoMutex _l(e->mLock); - return e->mObjects.find(objectID); -} - -void BBinder::detachObject(const void* objectID) -{ - Extras* e = mExtras; - if (!e) return; - - AutoMutex _l(e->mLock); - e->mObjects.detach(objectID); -} - -BBinder* BBinder::localBinder() -{ - return this; -} - -BBinder::~BBinder() -{ - if (mExtras) delete mExtras; -} - - -status_t BBinder::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch (code) { - case INTERFACE_TRANSACTION: - reply->writeString16(getInterfaceDescriptor()); - return NO_ERROR; - - case DUMP_TRANSACTION: { - int fd = data.readFileDescriptor(); - int argc = data.readInt32(); - Vector<String16> args; - for (int i = 0; i < argc && data.dataAvail() > 0; i++) { - args.add(data.readString16()); - } - return dump(fd, args); - } - default: - return UNKNOWN_TRANSACTION; - } -} - -// --------------------------------------------------------------------------- - -enum { - // This is used to transfer ownership of the remote binder from - // the BpRefBase object holding it (when it is constructed), to the - // owner of the BpRefBase object when it first acquires that BpRefBase. - kRemoteAcquired = 0x00000001 -}; - -BpRefBase::BpRefBase(const sp<IBinder>& o) - : mRemote(o.get()), mRefs(NULL), mState(0) -{ - extendObjectLifetime(OBJECT_LIFETIME_WEAK); - - if (mRemote) { - mRemote->incStrong(this); // Removed on first IncStrong(). - mRefs = mRemote->createWeak(this); // Held for our entire lifetime. - } -} - -BpRefBase::~BpRefBase() -{ - if (mRemote) { - if (!(mState&kRemoteAcquired)) { - mRemote->decStrong(this); - } - mRefs->decWeak(this); - } -} - -void BpRefBase::onFirstRef() -{ - android_atomic_or(kRemoteAcquired, &mState); -} - -void BpRefBase::onLastStrongRef(const void* id) -{ - if (mRemote) { - mRemote->decStrong(this); - } -} - -bool BpRefBase::onIncStrongAttempted(uint32_t flags, const void* id) -{ - return mRemote ? mRefs->attemptIncStrong(this) : false; -} - -// --------------------------------------------------------------------------- - -}; // namespace android diff --git a/libs/utils/BpBinder.cpp b/libs/utils/BpBinder.cpp deleted file mode 100644 index 69ab195..0000000 --- a/libs/utils/BpBinder.cpp +++ /dev/null @@ -1,348 +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 "BpBinder" -//#define LOG_NDEBUG 0 - -#include <utils/BpBinder.h> - -#include <utils/IPCThreadState.h> -#include <utils/Log.h> - -#include <stdio.h> - -//#undef LOGV -//#define LOGV(...) fprintf(stderr, __VA_ARGS__) - -namespace android { - -// --------------------------------------------------------------------------- - -BpBinder::ObjectManager::ObjectManager() -{ -} - -BpBinder::ObjectManager::~ObjectManager() -{ - kill(); -} - -void BpBinder::ObjectManager::attach( - const void* objectID, void* object, void* cleanupCookie, - IBinder::object_cleanup_func func) -{ - entry_t e; - e.object = object; - e.cleanupCookie = cleanupCookie; - e.func = func; - - if (mObjects.indexOfKey(objectID) >= 0) { - LOGE("Trying to attach object ID %p to binder ObjectManager %p with object %p, but object ID already in use", - objectID, this, object); - return; - } - - mObjects.add(objectID, e); -} - -void* BpBinder::ObjectManager::find(const void* objectID) const -{ - const ssize_t i = mObjects.indexOfKey(objectID); - if (i < 0) return NULL; - return mObjects.valueAt(i).object; -} - -void BpBinder::ObjectManager::detach(const void* objectID) -{ - mObjects.removeItem(objectID); -} - -void BpBinder::ObjectManager::kill() -{ - const size_t N = mObjects.size(); - LOGV("Killing %d objects in manager %p", N, this); - for (size_t i=0; i<N; i++) { - const entry_t& e = mObjects.valueAt(i); - if (e.func != NULL) { - e.func(mObjects.keyAt(i), e.object, e.cleanupCookie); - } - } - - mObjects.clear(); -} - -// --------------------------------------------------------------------------- - -BpBinder::BpBinder(int32_t handle) - : mHandle(handle) - , mAlive(1) - , mObitsSent(0) - , mObituaries(NULL) -{ - LOGV("Creating BpBinder %p handle %d\n", this, mHandle); - - extendObjectLifetime(OBJECT_LIFETIME_WEAK); - IPCThreadState::self()->incWeakHandle(handle); -} - -String16 BpBinder::getInterfaceDescriptor() const -{ - String16 res; - Parcel send, reply; - status_t err = const_cast<BpBinder*>(this)->transact( - INTERFACE_TRANSACTION, send, &reply); - if (err == NO_ERROR) { - res = reply.readString16(); - } - return res; -} - -bool BpBinder::isBinderAlive() const -{ - return mAlive != 0; -} - -status_t BpBinder::pingBinder() -{ - Parcel send; - Parcel reply; - status_t err = transact(PING_TRANSACTION, send, &reply); - if (err != NO_ERROR) return err; - if (reply.dataSize() < sizeof(status_t)) return NOT_ENOUGH_DATA; - return (status_t)reply.readInt32(); -} - -status_t BpBinder::dump(int fd, const Vector<String16>& args) -{ - Parcel send; - Parcel reply; - send.writeFileDescriptor(fd); - const size_t numArgs = args.size(); - send.writeInt32(numArgs); - for (size_t i = 0; i < numArgs; i++) { - send.writeString16(args[i]); - } - status_t err = transact(DUMP_TRANSACTION, send, &reply); - return err; -} - -status_t BpBinder::transact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - // Once a binder has died, it will never come back to life. - if (mAlive) { - status_t status = IPCThreadState::self()->transact( - mHandle, code, data, reply, flags); - if (status == DEAD_OBJECT) mAlive = 0; - return status; - } - - return DEAD_OBJECT; -} - -status_t BpBinder::linkToDeath( - const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags) -{ - Obituary ob; - ob.recipient = recipient; - ob.cookie = cookie; - ob.flags = flags; - - LOG_ALWAYS_FATAL_IF(recipient == NULL, - "linkToDeath(): recipient must be non-NULL"); - - { - AutoMutex _l(mLock); - - if (!mObitsSent) { - if (!mObituaries) { - mObituaries = new Vector<Obituary>; - if (!mObituaries) { - return NO_MEMORY; - } - LOGV("Requesting death notification: %p handle %d\n", this, mHandle); - getWeakRefs()->incWeak(this); - IPCThreadState* self = IPCThreadState::self(); - self->requestDeathNotification(mHandle, this); - self->flushCommands(); - } - ssize_t res = mObituaries->add(ob); - return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res; - } - } - - return DEAD_OBJECT; -} - -status_t BpBinder::unlinkToDeath( - const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags, - wp<DeathRecipient>* outRecipient) -{ - AutoMutex _l(mLock); - - if (mObitsSent) { - return DEAD_OBJECT; - } - - const size_t N = mObituaries ? mObituaries->size() : 0; - for (size_t i=0; i<N; i++) { - const Obituary& obit = mObituaries->itemAt(i); - if ((obit.recipient == recipient - || (recipient == NULL && obit.cookie == cookie)) - && obit.flags == flags) { - const uint32_t allFlags = obit.flags|flags; - if (outRecipient != NULL) { - *outRecipient = mObituaries->itemAt(i).recipient; - } - mObituaries->removeAt(i); - if (mObituaries->size() == 0) { - LOGV("Clearing death notification: %p handle %d\n", this, mHandle); - IPCThreadState* self = IPCThreadState::self(); - self->clearDeathNotification(mHandle, this); - self->flushCommands(); - delete mObituaries; - mObituaries = NULL; - } - return NO_ERROR; - } - } - - return NAME_NOT_FOUND; -} - -void BpBinder::sendObituary() -{ - LOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n", - this, mHandle, mObitsSent ? "true" : "false"); - - mAlive = 0; - if (mObitsSent) return; - - mLock.lock(); - Vector<Obituary>* obits = mObituaries; - if(obits != NULL) { - LOGV("Clearing sent death notification: %p handle %d\n", this, mHandle); - IPCThreadState* self = IPCThreadState::self(); - self->clearDeathNotification(mHandle, this); - self->flushCommands(); - mObituaries = NULL; - } - mObitsSent = 1; - mLock.unlock(); - - LOGV("Reporting death of proxy %p for %d recipients\n", - this, obits ? obits->size() : 0); - - if (obits != NULL) { - const size_t N = obits->size(); - for (size_t i=0; i<N; i++) { - reportOneDeath(obits->itemAt(i)); - } - - delete obits; - } -} - -void BpBinder::reportOneDeath(const Obituary& obit) -{ - sp<DeathRecipient> recipient = obit.recipient.promote(); - LOGV("Reporting death to recipient: %p\n", recipient.get()); - if (recipient == NULL) return; - - recipient->binderDied(this); -} - - -void BpBinder::attachObject( - const void* objectID, void* object, void* cleanupCookie, - object_cleanup_func func) -{ - AutoMutex _l(mLock); - LOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects); - mObjects.attach(objectID, object, cleanupCookie, func); -} - -void* BpBinder::findObject(const void* objectID) const -{ - AutoMutex _l(mLock); - return mObjects.find(objectID); -} - -void BpBinder::detachObject(const void* objectID) -{ - AutoMutex _l(mLock); - mObjects.detach(objectID); -} - -BpBinder* BpBinder::remoteBinder() -{ - return this; -} - -BpBinder::~BpBinder() -{ - LOGV("Destroying BpBinder %p handle %d\n", this, mHandle); - - IPCThreadState* ipc = IPCThreadState::self(); - - mLock.lock(); - Vector<Obituary>* obits = mObituaries; - if(obits != NULL) { - if (ipc) ipc->clearDeathNotification(mHandle, this); - mObituaries = NULL; - } - mLock.unlock(); - - if (obits != NULL) { - // XXX Should we tell any remaining DeathRecipient - // objects that the last strong ref has gone away, so they - // are no longer linked? - delete obits; - } - - if (ipc) { - ipc->expungeHandle(mHandle, this); - ipc->decWeakHandle(mHandle); - } -} - -void BpBinder::onFirstRef() -{ - LOGV("onFirstRef BpBinder %p handle %d\n", this, mHandle); - IPCThreadState* ipc = IPCThreadState::self(); - if (ipc) ipc->incStrongHandle(mHandle); -} - -void BpBinder::onLastStrongRef(const void* id) -{ - LOGV("onLastStrongRef BpBinder %p handle %d\n", this, mHandle); - IF_LOGV() { - printRefs(); - } - IPCThreadState* ipc = IPCThreadState::self(); - if (ipc) ipc->decStrongHandle(mHandle); -} - -bool BpBinder::onIncStrongAttempted(uint32_t flags, const void* id) -{ - LOGV("onIncStrongAttempted BpBinder %p handle %d\n", this, mHandle); - IPCThreadState* ipc = IPCThreadState::self(); - return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false; -} - -// --------------------------------------------------------------------------- - -}; // namespace android diff --git a/libs/utils/BufferedTextOutput.cpp b/libs/utils/BufferedTextOutput.cpp deleted file mode 100644 index 989662e..0000000 --- a/libs/utils/BufferedTextOutput.cpp +++ /dev/null @@ -1,279 +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. - */ - -#include <utils/BufferedTextOutput.h> - -#include <utils/Atomic.h> -#include <utils/Debug.h> -#include <utils/Log.h> -#include <utils/RefBase.h> -#include <utils/Vector.h> -#include <cutils/threads.h> - -#include <private/utils/Static.h> - -#include <stdio.h> -#include <stdlib.h> - -// --------------------------------------------------------------------------- - -namespace android { - -struct BufferedTextOutput::BufferState : public RefBase -{ - BufferState(int32_t _seq) - : seq(_seq) - , buffer(NULL) - , bufferPos(0) - , bufferSize(0) - , atFront(true) - , indent(0) - , bundle(0) { - } - ~BufferState() { - free(buffer); - } - - status_t append(const char* txt, size_t len) { - if ((len+bufferPos) > bufferSize) { - void* b = realloc(buffer, ((len+bufferPos)*3)/2); - if (!b) return NO_MEMORY; - buffer = (char*)b; - } - memcpy(buffer+bufferPos, txt, len); - bufferPos += len; - return NO_ERROR; - } - - void restart() { - bufferPos = 0; - atFront = true; - if (bufferSize > 256) { - void* b = realloc(buffer, 256); - if (b) { - buffer = (char*)b; - bufferSize = 256; - } - } - } - - const int32_t seq; - char* buffer; - size_t bufferPos; - size_t bufferSize; - bool atFront; - int32_t indent; - int32_t bundle; -}; - -struct BufferedTextOutput::ThreadState -{ - Vector<sp<BufferedTextOutput::BufferState> > states; -}; - -static mutex_t gMutex; - -static thread_store_t tls; - -BufferedTextOutput::ThreadState* BufferedTextOutput::getThreadState() -{ - ThreadState* ts = (ThreadState*) thread_store_get( &tls ); - if (ts) return ts; - ts = new ThreadState; - thread_store_set( &tls, ts, threadDestructor ); - return ts; -} - -void BufferedTextOutput::threadDestructor(void *st) -{ - delete ((ThreadState*)st); -} - -static volatile int32_t gSequence = 0; - -static volatile int32_t gFreeBufferIndex = -1; - -static int32_t allocBufferIndex() -{ - int32_t res = -1; - - mutex_lock(&gMutex); - - if (gFreeBufferIndex >= 0) { - res = gFreeBufferIndex; - gFreeBufferIndex = gTextBuffers[res]; - gTextBuffers.editItemAt(res) = -1; - - } else { - res = gTextBuffers.size(); - gTextBuffers.add(-1); - } - - mutex_unlock(&gMutex); - - return res; -} - -static void freeBufferIndex(int32_t idx) -{ - mutex_lock(&gMutex); - gTextBuffers.editItemAt(idx) = gFreeBufferIndex; - gFreeBufferIndex = idx; - mutex_unlock(&gMutex); -} - -// --------------------------------------------------------------------------- - -BufferedTextOutput::BufferedTextOutput(uint32_t flags) - : mFlags(flags) - , mSeq(android_atomic_inc(&gSequence)) - , mIndex(allocBufferIndex()) -{ - mGlobalState = new BufferState(mSeq); - if (mGlobalState) mGlobalState->incStrong(this); -} - -BufferedTextOutput::~BufferedTextOutput() -{ - if (mGlobalState) mGlobalState->decStrong(this); - freeBufferIndex(mIndex); -} - -status_t BufferedTextOutput::print(const char* txt, size_t len) -{ - //printf("BufferedTextOutput: printing %d\n", len); - - AutoMutex _l(mLock); - BufferState* b = getBuffer(); - - const char* const end = txt+len; - - status_t err; - - while (txt < end) { - // Find the next line. - const char* first = txt; - while (txt < end && *txt != '\n') txt++; - - // Include this and all following empty lines. - while (txt < end && *txt == '\n') txt++; - - // Special cases for first data on a line. - if (b->atFront) { - if (b->indent > 0) { - // If this is the start of a line, add the indent. - const char* prefix = stringForIndent(b->indent); - err = b->append(prefix, strlen(prefix)); - if (err != NO_ERROR) return err; - - } else if (*(txt-1) == '\n' && !b->bundle) { - // Fast path: if we are not indenting or bundling, and - // have been given one or more complete lines, just write - // them out without going through the buffer. - - // Slurp up all of the lines. - const char* lastLine = txt+1; - while (txt < end) { - if (*txt++ == '\n') lastLine = txt; - } - struct iovec vec; - vec.iov_base = (void*)first; - vec.iov_len = lastLine-first; - //printf("Writing %d bytes of data!\n", vec.iov_len); - writeLines(vec, 1); - txt = lastLine; - continue; - } - } - - // Append the new text to the buffer. - err = b->append(first, txt-first); - if (err != NO_ERROR) return err; - b->atFront = *(txt-1) == '\n'; - - // If we have finished a line and are not bundling, write - // it out. - //printf("Buffer is now %d bytes\n", b->bufferPos); - if (b->atFront && !b->bundle) { - struct iovec vec; - vec.iov_base = b->buffer; - vec.iov_len = b->bufferPos; - //printf("Writing %d bytes of data!\n", vec.iov_len); - writeLines(vec, 1); - b->restart(); - } - } - - return NO_ERROR; -} - -void BufferedTextOutput::moveIndent(int delta) -{ - AutoMutex _l(mLock); - BufferState* b = getBuffer(); - b->indent += delta; - if (b->indent < 0) b->indent = 0; -} - -void BufferedTextOutput::pushBundle() -{ - AutoMutex _l(mLock); - BufferState* b = getBuffer(); - b->bundle++; -} - -void BufferedTextOutput::popBundle() -{ - AutoMutex _l(mLock); - BufferState* b = getBuffer(); - b->bundle--; - LOG_FATAL_IF(b->bundle < 0, - "TextOutput::popBundle() called more times than pushBundle()"); - if (b->bundle < 0) b->bundle = 0; - - if (b->bundle == 0) { - // Last bundle, write out data if it is complete. If it is not - // complete, don't write until the last line is done... this may - // or may not be the write thing to do, but it's the easiest. - if (b->bufferPos > 0 && b->atFront) { - struct iovec vec; - vec.iov_base = b->buffer; - vec.iov_len = b->bufferPos; - writeLines(vec, 1); - b->restart(); - } - } -} - -BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const -{ - if ((mFlags&MULTITHREADED) != 0) { - ThreadState* ts = getThreadState(); - if (ts) { - while (ts->states.size() <= (size_t)mIndex) ts->states.add(NULL); - BufferState* bs = ts->states[mIndex].get(); - if (bs != NULL && bs->seq == mSeq) return bs; - - ts->states.editItemAt(mIndex) = new BufferState(mIndex); - bs = ts->states[mIndex].get(); - if (bs != NULL) return bs; - } - } - - return mGlobalState; -} - -}; // namespace android diff --git a/libs/utils/CallStack.cpp b/libs/utils/CallStack.cpp deleted file mode 100644 index 26fb22a..0000000 --- a/libs/utils/CallStack.cpp +++ /dev/null @@ -1,335 +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. - */ - -#define LOG_TAG "CallStack" - -#include <string.h> -#include <stdlib.h> -#include <stdio.h> - -#if HAVE_DLADDR -#include <dlfcn.h> -#endif - -#if HAVE_CXXABI -#include <cxxabi.h> -#endif - -#include <unwind.h> - -#include <utils/Log.h> -#include <utils/Errors.h> -#include <utils/CallStack.h> -#include <utils/threads.h> - - -/*****************************************************************************/ -namespace android { - - -typedef struct { - size_t count; - size_t ignore; - const void** addrs; -} stack_crawl_state_t; - -static -_Unwind_Reason_Code trace_function(_Unwind_Context *context, void *arg) -{ - stack_crawl_state_t* state = (stack_crawl_state_t*)arg; - if (state->count) { - void* ip = (void*)_Unwind_GetIP(context); - if (ip) { - if (state->ignore) { - state->ignore--; - } else { - state->addrs[0] = ip; - state->addrs++; - state->count--; - } - } - } - return _URC_NO_REASON; -} - -static -int backtrace(const void** addrs, size_t ignore, size_t size) -{ - stack_crawl_state_t state; - state.count = size; - state.ignore = ignore; - state.addrs = addrs; - _Unwind_Backtrace(trace_function, (void*)&state); - return size - state.count; -} - -/*****************************************************************************/ - -static -const char *lookup_symbol(const void* addr, void **offset, char* name, size_t bufSize) -{ -#if HAVE_DLADDR - Dl_info info; - if (dladdr(addr, &info)) { - *offset = info.dli_saddr; - return info.dli_sname; - } -#endif - return NULL; -} - -static -int32_t linux_gcc_demangler(const char *mangled_name, char *unmangled_name, size_t buffersize) -{ - size_t out_len = 0; -#if HAVE_CXXABI - int status = 0; - char *demangled = abi::__cxa_demangle(mangled_name, 0, &out_len, &status); - if (status == 0) { - // OK - if (out_len < buffersize) memcpy(unmangled_name, demangled, out_len); - else out_len = 0; - free(demangled); - } else { - out_len = 0; - } -#endif - return out_len; -} - -/*****************************************************************************/ - -class MapInfo { - struct mapinfo { - struct mapinfo *next; - uint64_t start; - uint64_t end; - char name[]; - }; - - const char *map_to_name(uint64_t pc, const char* def) { - mapinfo* mi = getMapInfoList(); - while(mi) { - if ((pc >= mi->start) && (pc < mi->end)) - return mi->name; - mi = mi->next; - } - return def; - } - - mapinfo *parse_maps_line(char *line) { - mapinfo *mi; - int len = strlen(line); - if (len < 1) return 0; - line[--len] = 0; - if (len < 50) return 0; - if (line[20] != 'x') return 0; - mi = (mapinfo*)malloc(sizeof(mapinfo) + (len - 47)); - if (mi == 0) return 0; - mi->start = strtoull(line, 0, 16); - mi->end = strtoull(line + 9, 0, 16); - mi->next = 0; - strcpy(mi->name, line + 49); - return mi; - } - - mapinfo* getMapInfoList() { - Mutex::Autolock _l(mLock); - if (milist == 0) { - char data[1024]; - FILE *fp; - sprintf(data, "/proc/%d/maps", getpid()); - fp = fopen(data, "r"); - if (fp) { - while(fgets(data, 1024, fp)) { - mapinfo *mi = parse_maps_line(data); - if(mi) { - mi->next = milist; - milist = mi; - } - } - fclose(fp); - } - } - return milist; - } - mapinfo* milist; - Mutex mLock; - static MapInfo sMapInfo; - -public: - MapInfo() - : milist(0) { - } - - ~MapInfo() { - while (milist) { - mapinfo *next = milist->next; - free(milist); - milist = next; - } - } - - static const char *mapAddressToName(const void* pc, const char* def) { - return sMapInfo.map_to_name((uint64_t)pc, def); - } - -}; - -/*****************************************************************************/ - -MapInfo MapInfo::sMapInfo; - -/*****************************************************************************/ - -CallStack::CallStack() - : mCount(0) -{ -} - -CallStack::CallStack(const CallStack& rhs) - : mCount(rhs.mCount) -{ - if (mCount) { - memcpy(mStack, rhs.mStack, mCount*sizeof(void*)); - } -} - -CallStack::~CallStack() -{ -} - -CallStack& CallStack::operator = (const CallStack& rhs) -{ - mCount = rhs.mCount; - if (mCount) { - memcpy(mStack, rhs.mStack, mCount*sizeof(void*)); - } - return *this; -} - -bool CallStack::operator == (const CallStack& rhs) const { - if (mCount != rhs.mCount) - return false; - return !mCount || (memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) == 0); -} - -bool CallStack::operator != (const CallStack& rhs) const { - return !operator == (rhs); -} - -bool CallStack::operator < (const CallStack& rhs) const { - if (mCount != rhs.mCount) - return mCount < rhs.mCount; - return memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) < 0; -} - -bool CallStack::operator >= (const CallStack& rhs) const { - return !operator < (rhs); -} - -bool CallStack::operator > (const CallStack& rhs) const { - if (mCount != rhs.mCount) - return mCount > rhs.mCount; - return memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) > 0; -} - -bool CallStack::operator <= (const CallStack& rhs) const { - return !operator > (rhs); -} - -const void* CallStack::operator [] (int index) const { - if (index >= int(mCount)) - return 0; - return mStack[index]; -} - - -void CallStack::clear() -{ - mCount = 0; -} - -void CallStack::update(int32_t ignoreDepth, int32_t maxDepth) -{ - if (maxDepth > MAX_DEPTH) - maxDepth = MAX_DEPTH; - mCount = backtrace(mStack, ignoreDepth, maxDepth); -} - -// Return the stack frame name on the designated level -String8 CallStack::toStringSingleLevel(const char* prefix, int32_t level) const -{ - String8 res; - char namebuf[1024]; - char tmp[256]; - char tmp1[32]; - char tmp2[32]; - void *offs; - - const void* ip = mStack[level]; - if (!ip) return res; - - if (prefix) res.append(prefix); - snprintf(tmp1, 32, "#%02d ", level); - res.append(tmp1); - - const char* name = lookup_symbol(ip, &offs, namebuf, sizeof(namebuf)); - if (name) { - if (linux_gcc_demangler(name, tmp, 256) != 0) - name = tmp; - snprintf(tmp1, 32, "0x%p: <", ip); - snprintf(tmp2, 32, ">+0x%p", offs); - res.append(tmp1); - res.append(name); - res.append(tmp2); - } else { - name = MapInfo::mapAddressToName(ip, "<unknown>"); - snprintf(tmp, 256, "pc %p %s", ip, name); - res.append(tmp); - } - res.append("\n"); - - return res; -} - -// Dump a stack trace to the log -void CallStack::dump(const char* prefix) const -{ - /* - * Sending a single long log may be truncated since the stack levels can - * get very deep. So we request function names of each frame individually. - */ - for (int i=0; i<int(mCount); i++) { - LOGD("%s", toStringSingleLevel(prefix, i).string()); - } -} - -// Return a string (possibly very long) containing the complete stack trace -String8 CallStack::toString(const char* prefix) const -{ - String8 res; - - for (int i=0; i<int(mCount); i++) { - res.append(toStringSingleLevel(prefix, i).string()); - } - - return res; -} - -/*****************************************************************************/ - -}; // namespace android diff --git a/libs/utils/Debug.cpp b/libs/utils/Debug.cpp deleted file mode 100644 index f7988ec..0000000 --- a/libs/utils/Debug.cpp +++ /dev/null @@ -1,318 +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 <utils/Debug.h> - -#include <utils/misc.h> - -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> - -namespace android { - -// --------------------------------------------------------------------- - -static const char indentStr[] = -" " -" "; - -const char* stringForIndent(int32_t indentLevel) -{ - ssize_t off = sizeof(indentStr)-1-(indentLevel*2); - return indentStr + (off < 0 ? 0 : off); -} - -// --------------------------------------------------------------------- - -static void defaultPrintFunc(void* cookie, const char* txt) -{ - printf("%s", txt); -} - -// --------------------------------------------------------------------- - -static inline int isident(int c) -{ - return isalnum(c) || c == '_'; -} - -static inline bool isasciitype(char c) -{ - if( c >= ' ' && c < 127 && c != '\'' && c != '\\' ) return true; - return false; -} - -static inline char makehexdigit(uint32_t val) -{ - return "0123456789abcdef"[val&0xF]; -} - -static char* appendhexnum(uint32_t val, char* out) -{ - for( int32_t i=28; i>=0; i-=4 ) { - *out++ = makehexdigit( val>>i ); - } - *out = 0; - return out; -} - -static inline char makeupperhexdigit(uint32_t val) -{ - return "0123456789ABCDEF"[val&0xF]; -} - -static char* appendupperhexnum(uint32_t val, char* out) -{ - for( int32_t i=28; i>=0; i-=4 ) { - *out++ = makeupperhexdigit( val>>i ); - } - *out = 0; - return out; -} - -static char* appendcharornum(char c, char* out, bool skipzero = true) -{ - if (skipzero && c == 0) return out; - - if (isasciitype(c)) { - *out++ = c; - return out; - } - - *out++ = '\\'; - *out++ = 'x'; - *out++ = makehexdigit(c>>4); - *out++ = makehexdigit(c); - return out; -} - -static char* typetostring(uint32_t type, char* out, - bool fullContext = true, - bool strict = false) -{ - char* pos = out; - char c[4]; - c[0] = (char)((type>>24)&0xFF); - c[1] = (char)((type>>16)&0xFF); - c[2] = (char)((type>>8)&0xFF); - c[3] = (char)(type&0xFF); - bool valid; - if( !strict ) { - // now even less strict! - // valid = isasciitype(c[3]); - valid = true; - int32_t i = 0; - bool zero = true; - while (valid && i<3) { - if (c[i] == 0) { - if (!zero) valid = false; - } else { - zero = false; - //if (!isasciitype(c[i])) valid = false; - } - i++; - } - // if all zeros, not a valid type code. - if (zero) valid = false; - } else { - valid = isident(c[3]) ? true : false; - int32_t i = 0; - bool zero = true; - while (valid && i<3) { - if (c[i] == 0) { - if (!zero) valid = false; - } else { - zero = false; - if (!isident(c[i])) valid = false; - } - i++; - } - } - if( valid && (!fullContext || c[0] != '0' || c[1] != 'x') ) { - if( fullContext ) *pos++ = '\''; - pos = appendcharornum(c[0], pos); - pos = appendcharornum(c[1], pos); - pos = appendcharornum(c[2], pos); - pos = appendcharornum(c[3], pos); - if( fullContext ) *pos++ = '\''; - *pos = 0; - return pos; - } - - if( fullContext ) { - *pos++ = '0'; - *pos++ = 'x'; - } - return appendhexnum(type, pos); -} - -void printTypeCode(uint32_t typeCode, debugPrintFunc func, void* cookie) -{ - char buffer[32]; - char* end = typetostring(typeCode, buffer); - *end = 0; - func ? (*func)(cookie, buffer) : defaultPrintFunc(cookie, buffer); -} - -void printHexData(int32_t indent, const void *buf, size_t length, - size_t bytesPerLine, int32_t singleLineBytesCutoff, - size_t alignment, bool cStyle, - debugPrintFunc func, void* cookie) -{ - if (alignment == 0) { - if (bytesPerLine >= 16) alignment = 4; - else if (bytesPerLine >= 8) alignment = 2; - else alignment = 1; - } - if (func == NULL) func = defaultPrintFunc; - - size_t offset; - - unsigned char *pos = (unsigned char *)buf; - - if (pos == NULL) { - if (singleLineBytesCutoff < 0) func(cookie, "\n"); - func(cookie, "(NULL)"); - return; - } - - if (length == 0) { - if (singleLineBytesCutoff < 0) func(cookie, "\n"); - func(cookie, "(empty)"); - return; - } - - if ((int32_t)length < 0) { - if (singleLineBytesCutoff < 0) func(cookie, "\n"); - char buf[64]; - sprintf(buf, "(bad length: %d)", length); - func(cookie, buf); - return; - } - - char buffer[256]; - static const size_t maxBytesPerLine = (sizeof(buffer)-1-11-4)/(3+1); - - if (bytesPerLine > maxBytesPerLine) bytesPerLine = maxBytesPerLine; - - const bool oneLine = (int32_t)length <= singleLineBytesCutoff; - bool newLine = false; - if (cStyle) { - indent++; - func(cookie, "{\n"); - newLine = true; - } else if (!oneLine) { - func(cookie, "\n"); - newLine = true; - } - - for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) { - long remain = length; - - char* c = buffer; - if (!oneLine && !cStyle) { - sprintf(c, "0x%08x: ", (int)offset); - c += 12; - } - - size_t index; - size_t word; - - for (word = 0; word < bytesPerLine; ) { - -#ifdef HAVE_LITTLE_ENDIAN - const size_t startIndex = word+(alignment-(alignment?1:0)); - const ssize_t dir = -1; -#else - const size_t startIndex = word; - const ssize_t dir = 1; -#endif - - for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) { - - if (!cStyle) { - if (index == 0 && word > 0 && alignment > 0) { - *c++ = ' '; - } - - if (remain-- > 0) { - const unsigned char val = *(pos+startIndex+(index*dir)); - *c++ = makehexdigit(val>>4); - *c++ = makehexdigit(val); - } else if (!oneLine) { - *c++ = ' '; - *c++ = ' '; - } - } else { - if (remain > 0) { - if (index == 0 && word > 0) { - *c++ = ','; - *c++ = ' '; - } - if (index == 0) { - *c++ = '0'; - *c++ = 'x'; - } - const unsigned char val = *(pos+startIndex+(index*dir)); - *c++ = makehexdigit(val>>4); - *c++ = makehexdigit(val); - remain--; - } - } - } - - word += index; - } - - if (!cStyle) { - remain = length; - *c++ = ' '; - *c++ = '\''; - for (index = 0; index < bytesPerLine; index++) { - - if (remain-- > 0) { - const unsigned char val = pos[index]; - *c++ = (val >= ' ' && val < 127) ? val : '.'; - } else if (!oneLine) { - *c++ = ' '; - } - } - - *c++ = '\''; - if (length > bytesPerLine) *c++ = '\n'; - } else { - if (remain > 0) *c++ = ','; - *c++ = '\n'; - } - - if (newLine && indent) func(cookie, stringForIndent(indent)); - *c = 0; - func(cookie, buffer); - newLine = true; - - if (length <= bytesPerLine) break; - length -= bytesPerLine; - } - - if (cStyle) { - if (indent > 0) func(cookie, stringForIndent(indent-1)); - func(cookie, "};"); - } -} - -}; // namespace android - diff --git a/libs/utils/FileMap.cpp b/libs/utils/FileMap.cpp deleted file mode 100644 index e1ba9b2..0000000 --- a/libs/utils/FileMap.cpp +++ /dev/null @@ -1,222 +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. - */ - -// -// Shared file mapping class. -// - -#define LOG_TAG "filemap" - -#include <utils/FileMap.h> -#include <utils/Log.h> - -#include <stdio.h> -#include <stdlib.h> - -#ifdef HAVE_POSIX_FILEMAP -#include <sys/mman.h> -#endif - -#include <string.h> -#include <memory.h> -#include <errno.h> -#include <assert.h> - -using namespace android; - -/*static*/ long FileMap::mPageSize = -1; - - -/* - * Constructor. Create an empty object. - */ -FileMap::FileMap(void) - : mRefCount(1), mFileName(NULL), mBasePtr(NULL), mBaseLength(0), - mDataPtr(NULL), mDataLength(0) -{ -} - -/* - * Destructor. - */ -FileMap::~FileMap(void) -{ - assert(mRefCount == 0); - - //printf("+++ removing FileMap %p %u\n", mDataPtr, mDataLength); - - mRefCount = -100; // help catch double-free - if (mFileName != NULL) { - free(mFileName); - } -#ifdef HAVE_POSIX_FILEMAP - if (munmap(mBasePtr, mBaseLength) != 0) { - LOGD("munmap(%p, %d) failed\n", mBasePtr, (int) mBaseLength); - } -#endif -#ifdef HAVE_WIN32_FILEMAP - if ( UnmapViewOfFile(mBasePtr) == 0) { - LOGD("UnmapViewOfFile(%p) failed, error = %ld\n", mBasePtr, - GetLastError() ); - } - CloseHandle(mFileMapping); - CloseHandle(mFileHandle); -#endif -} - - -/* - * Create a new mapping on an open file. - * - * Closing the file descriptor does not unmap the pages, so we don't - * claim ownership of the fd. - * - * Returns "false" on failure. - */ -bool FileMap::create(const char* origFileName, int fd, off_t offset, size_t length, bool readOnly) -{ -#ifdef HAVE_WIN32_FILEMAP - int adjust; - off_t adjOffset; - size_t adjLength; - - if (mPageSize == -1) { - SYSTEM_INFO si; - - GetSystemInfo( &si ); - mPageSize = si.dwAllocationGranularity; - } - - DWORD protect = readOnly ? PAGE_READONLY : PAGE_READWRITE; - - mFileHandle = (HANDLE) _get_osfhandle(fd); - mFileMapping = CreateFileMapping( mFileHandle, NULL, protect, 0, 0, NULL); - if (mFileMapping == NULL) { - LOGE("CreateFileMapping(%p, %lx) failed with error %ld\n", - mFileHandle, protect, GetLastError() ); - return false; - } - - adjust = offset % mPageSize; - adjOffset = offset - adjust; - adjLength = length + adjust; - - mBasePtr = MapViewOfFile( mFileMapping, - readOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, - 0, - (DWORD)(adjOffset), - adjLength ); - if (mBasePtr == NULL) { - LOGE("MapViewOfFile(%ld, %ld) failed with error %ld\n", - adjOffset, adjLength, GetLastError() ); - CloseHandle(mFileMapping); - mFileMapping = INVALID_HANDLE_VALUE; - return false; - } -#endif -#ifdef HAVE_POSIX_FILEMAP - int prot, flags, adjust; - off_t adjOffset; - size_t adjLength; - - void* ptr; - - assert(mRefCount == 1); - assert(fd >= 0); - assert(offset >= 0); - assert(length > 0); - - /* init on first use */ - if (mPageSize == -1) { -#if NOT_USING_KLIBC - mPageSize = sysconf(_SC_PAGESIZE); - if (mPageSize == -1) { - LOGE("could not get _SC_PAGESIZE\n"); - return false; - } -#else - /* this holds for Linux, Darwin, Cygwin, and doesn't pain the ARM */ - mPageSize = 4096; -#endif - } - - adjust = offset % mPageSize; -try_again: - adjOffset = offset - adjust; - adjLength = length + adjust; - - flags = MAP_SHARED; - prot = PROT_READ; - if (!readOnly) - prot |= PROT_WRITE; - - ptr = mmap(NULL, adjLength, prot, flags, fd, adjOffset); - if (ptr == MAP_FAILED) { - // Cygwin does not seem to like file mapping files from an offset. - // So if we fail, try again with offset zero - if (adjOffset > 0) { - adjust = offset; - goto try_again; - } - - LOGE("mmap(%ld,%ld) failed: %s\n", - (long) adjOffset, (long) adjLength, strerror(errno)); - return false; - } - mBasePtr = ptr; -#endif /* HAVE_POSIX_FILEMAP */ - - mFileName = origFileName != NULL ? strdup(origFileName) : NULL; - mBaseLength = adjLength; - mDataOffset = offset; - mDataPtr = (char*) mBasePtr + adjust; - mDataLength = length; - - assert(mBasePtr != NULL); - - LOGV("MAP: base %p/%d data %p/%d\n", - mBasePtr, (int) mBaseLength, mDataPtr, (int) mDataLength); - - return true; -} - -/* - * Provide guidance to the system. - */ -int FileMap::advise(MapAdvice advice) -{ -#if HAVE_MADVISE - int cc, sysAdvice; - - switch (advice) { - case NORMAL: sysAdvice = MADV_NORMAL; break; - case RANDOM: sysAdvice = MADV_RANDOM; break; - case SEQUENTIAL: sysAdvice = MADV_SEQUENTIAL; break; - case WILLNEED: sysAdvice = MADV_WILLNEED; break; - case DONTNEED: sysAdvice = MADV_DONTNEED; break; - default: - assert(false); - return -1; - } - - cc = madvise(mBasePtr, mBaseLength, sysAdvice); - if (cc != 0) - LOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno)); - return cc; -#else - return -1; -#endif // HAVE_MADVISE -} diff --git a/libs/utils/IDataConnection.cpp b/libs/utils/IDataConnection.cpp deleted file mode 100644 index c6d49aa..0000000 --- a/libs/utils/IDataConnection.cpp +++ /dev/null @@ -1,89 +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. - */ - -#include <stdint.h> -#include <sys/types.h> - -#include <utils/Parcel.h> - -#include <utils/IDataConnection.h> - -namespace android { - -// --------------------------------------------------------------------------- - -enum -{ - CONNECT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, - DISCONNECT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1 -}; - -class BpDataConnection : public BpInterface<IDataConnection> -{ -public: - BpDataConnection::BpDataConnection(const sp<IBinder>& impl) - : BpInterface<IDataConnection>(impl) - { - } - - virtual void connect() - { - Parcel data, reply; - data.writeInterfaceToken(IDataConnection::descriptor()); - remote()->transact(CONNECT_TRANSACTION, data, &reply); - } - - virtual void disconnect() - { - Parcel data, reply; - remote()->transact(DISCONNECT_TRANSACTION, data, &reply); - } -}; - -IMPLEMENT_META_INTERFACE(DataConnection, "android.utils.IDataConnection"); - -#define CHECK_INTERFACE(interface, data, reply) \ - do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ - LOGW("Call incorrectly routed to " #interface); \ - return PERMISSION_DENIED; \ - } } while (0) - -status_t BnDataConnection::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch(code) - { - case CONNECT_TRANSACTION: - { - CHECK_INTERFACE(IDataConnection, data, reply); - connect(); - return NO_ERROR; - } - - case DISCONNECT_TRANSACTION: - { - CHECK_INTERFACE(IDataConnection, data, reply); - disconnect(); - return NO_ERROR; - } - - default: - return BBinder::onTransact(code, data, reply, flags); - } -} - -// ---------------------------------------------------------------------------- - -}; // namespace android diff --git a/libs/utils/IInterface.cpp b/libs/utils/IInterface.cpp deleted file mode 100644 index 6ea8178..0000000 --- a/libs/utils/IInterface.cpp +++ /dev/null @@ -1,35 +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 <utils/IInterface.h> - -namespace android { - -// --------------------------------------------------------------------------- - -sp<IBinder> IInterface::asBinder() -{ - return this ? onAsBinder() : NULL; -} - -sp<const IBinder> IInterface::asBinder() const -{ - return this ? const_cast<IInterface*>(this)->onAsBinder() : NULL; -} - -// --------------------------------------------------------------------------- - -}; // namespace android diff --git a/libs/utils/IMemory.cpp b/libs/utils/IMemory.cpp deleted file mode 100644 index 429bc2b..0000000 --- a/libs/utils/IMemory.cpp +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "IMemory" - -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <fcntl.h> -#include <unistd.h> - -#include <sys/types.h> -#include <sys/mman.h> - -#include <utils/IMemory.h> -#include <utils/KeyedVector.h> -#include <utils/threads.h> -#include <utils/Atomic.h> -#include <utils/Parcel.h> -#include <utils/CallStack.h> - -#define VERBOSE 0 - -namespace android { -// --------------------------------------------------------------------------- - -class HeapCache : public IBinder::DeathRecipient -{ -public: - HeapCache(); - virtual ~HeapCache(); - - virtual void binderDied(const wp<IBinder>& who); - - sp<IMemoryHeap> find_heap(const sp<IBinder>& binder); - void pin_heap(const sp<IBinder>& binder); - void free_heap(const sp<IBinder>& binder); - sp<IMemoryHeap> get_heap(const sp<IBinder>& binder); - void dump_heaps(); - -private: - // For IMemory.cpp - struct heap_info_t { - sp<IMemoryHeap> heap; - int32_t count; - }; - - void free_heap(const wp<IBinder>& binder); - - Mutex mHeapCacheLock; - KeyedVector< wp<IBinder>, heap_info_t > mHeapCache; -}; - -static sp<HeapCache> gHeapCache = new HeapCache(); - -/******************************************************************************/ - -enum { - HEAP_ID = IBinder::FIRST_CALL_TRANSACTION -}; - -class BpMemoryHeap : public BpInterface<IMemoryHeap> -{ -public: - BpMemoryHeap(const sp<IBinder>& impl); - virtual ~BpMemoryHeap(); - - virtual int getHeapID() const; - virtual void* getBase() const; - virtual size_t getSize() const; - virtual uint32_t getFlags() const; - -private: - friend class IMemory; - friend class HeapCache; - - // for debugging in this module - static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) { - return gHeapCache->find_heap(binder); - } - static inline void free_heap(const sp<IBinder>& binder) { - gHeapCache->free_heap(binder); - } - static inline sp<IMemoryHeap> get_heap(const sp<IBinder>& binder) { - return gHeapCache->get_heap(binder); - } - static inline void dump_heaps() { - gHeapCache->dump_heaps(); - } - void inline pin_heap() const { - gHeapCache->pin_heap(const_cast<BpMemoryHeap*>(this)->asBinder()); - } - - void assertMapped() const; - void assertReallyMapped() const; - void pinHeap() const; - - mutable volatile int32_t mHeapId; - mutable void* mBase; - mutable size_t mSize; - mutable uint32_t mFlags; - mutable bool mRealHeap; - mutable Mutex mLock; -}; - -// ---------------------------------------------------------------------------- - -enum { - GET_MEMORY = IBinder::FIRST_CALL_TRANSACTION -}; - -class BpMemory : public BpInterface<IMemory> -{ -public: - BpMemory(const sp<IBinder>& impl); - virtual ~BpMemory(); - virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const; - -private: - mutable sp<IMemoryHeap> mHeap; - mutable ssize_t mOffset; - mutable size_t mSize; -}; - -/******************************************************************************/ - -void* IMemory::fastPointer(const sp<IBinder>& binder, ssize_t offset) const -{ - sp<IMemoryHeap> realHeap = BpMemoryHeap::get_heap(binder); - void* const base = realHeap->base(); - if (base == MAP_FAILED) - return 0; - return static_cast<char*>(base) + offset; -} - -void* IMemory::pointer() const { - ssize_t offset; - sp<IMemoryHeap> heap = getMemory(&offset); - void* const base = heap!=0 ? heap->base() : MAP_FAILED; - if (base == MAP_FAILED) - return 0; - return static_cast<char*>(base) + offset; -} - -size_t IMemory::size() const { - size_t size; - getMemory(NULL, &size); - return size; -} - -ssize_t IMemory::offset() const { - ssize_t offset; - getMemory(&offset); - return offset; -} - -/******************************************************************************/ - -BpMemory::BpMemory(const sp<IBinder>& impl) - : BpInterface<IMemory>(impl), mOffset(0), mSize(0) -{ -} - -BpMemory::~BpMemory() -{ -} - -sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const -{ - if (mHeap == 0) { - Parcel data, reply; - data.writeInterfaceToken(IMemory::getInterfaceDescriptor()); - if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) { - sp<IBinder> heap = reply.readStrongBinder(); - ssize_t o = reply.readInt32(); - size_t s = reply.readInt32(); - if (heap != 0) { - mHeap = interface_cast<IMemoryHeap>(heap); - if (mHeap != 0) { - mOffset = o; - mSize = s; - } - } - } - } - if (offset) *offset = mOffset; - if (size) *size = mSize; - return mHeap; -} - -// --------------------------------------------------------------------------- - -IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory"); - -#define CHECK_INTERFACE(interface, data, reply) \ - do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ - LOGW("Call incorrectly routed to " #interface); \ - return PERMISSION_DENIED; \ - } } while (0) - -status_t BnMemory::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch(code) { - case GET_MEMORY: { - CHECK_INTERFACE(IMemory, data, reply); - ssize_t offset; - size_t size; - reply->writeStrongBinder( getMemory(&offset, &size)->asBinder() ); - reply->writeInt32(offset); - reply->writeInt32(size); - return NO_ERROR; - } break; - default: - return BBinder::onTransact(code, data, reply, flags); - } -} - - -/******************************************************************************/ - -BpMemoryHeap::BpMemoryHeap(const sp<IBinder>& impl) - : BpInterface<IMemoryHeap>(impl), - mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mRealHeap(false) -{ -} - -BpMemoryHeap::~BpMemoryHeap() { - if (mHeapId != -1) { - close(mHeapId); - if (mRealHeap) { - // by construction we're the last one - if (mBase != MAP_FAILED) { - sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder(); - - if (VERBOSE) { - LOGD("UNMAPPING binder=%p, heap=%p, size=%d, fd=%d", - binder.get(), this, mSize, mHeapId); - CallStack stack; - stack.update(); - stack.dump("callstack"); - } - - munmap(mBase, mSize); - } - } else { - // remove from list only if it was mapped before - sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder(); - free_heap(binder); - } - } -} - -void BpMemoryHeap::assertMapped() const -{ - if (mHeapId == -1) { - sp<IBinder> binder(const_cast<BpMemoryHeap*>(this)->asBinder()); - sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get())); - heap->assertReallyMapped(); - if (heap->mBase != MAP_FAILED) { - Mutex::Autolock _l(mLock); - if (mHeapId == -1) { - mBase = heap->mBase; - mSize = heap->mSize; - android_atomic_write( dup( heap->mHeapId ), &mHeapId ); - } - } else { - // something went wrong - free_heap(binder); - } - } -} - -void BpMemoryHeap::assertReallyMapped() const -{ - if (mHeapId == -1) { - - // remote call without mLock held, worse case scenario, we end up - // calling transact() from multiple threads, but that's not a problem, - // only mmap below must be in the critical section. - - Parcel data, reply; - data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor()); - status_t err = remote()->transact(HEAP_ID, data, &reply); - int parcel_fd = reply.readFileDescriptor(); - ssize_t size = reply.readInt32(); - uint32_t flags = reply.readInt32(); - - LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%d, err=%d (%s)", - asBinder().get(), parcel_fd, size, err, strerror(-err)); - - int fd = dup( parcel_fd ); - LOGE_IF(fd==-1, "cannot dup fd=%d, size=%d, err=%d (%s)", - parcel_fd, size, err, strerror(errno)); - - int access = PROT_READ; - if (!(flags & READ_ONLY)) { - access |= PROT_WRITE; - } - - Mutex::Autolock _l(mLock); - if (mHeapId == -1) { - mRealHeap = true; - mBase = mmap(0, size, access, MAP_SHARED, fd, 0); - if (mBase == MAP_FAILED) { - LOGE("cannot map BpMemoryHeap (binder=%p), size=%d, fd=%d (%s)", - asBinder().get(), size, fd, strerror(errno)); - close(fd); - } else { - if (flags & MAP_ONCE) { - //LOGD("pinning heap (binder=%p, size=%d, fd=%d", - // asBinder().get(), size, fd); - pin_heap(); - } - mSize = size; - mFlags = flags; - android_atomic_write(fd, &mHeapId); - } - } - } -} - -int BpMemoryHeap::getHeapID() const { - assertMapped(); - return mHeapId; -} - -void* BpMemoryHeap::getBase() const { - assertMapped(); - return mBase; -} - -size_t BpMemoryHeap::getSize() const { - assertMapped(); - return mSize; -} - -uint32_t BpMemoryHeap::getFlags() const { - assertMapped(); - return mFlags; -} - -// --------------------------------------------------------------------------- - -IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap"); - -status_t BnMemoryHeap::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch(code) { - case HEAP_ID: { - CHECK_INTERFACE(IMemoryHeap, data, reply); - reply->writeFileDescriptor(getHeapID()); - reply->writeInt32(getSize()); - reply->writeInt32(getFlags()); - return NO_ERROR; - } break; - default: - return BBinder::onTransact(code, data, reply, flags); - } -} - -/*****************************************************************************/ - -HeapCache::HeapCache() - : DeathRecipient() -{ -} - -HeapCache::~HeapCache() -{ -} - -void HeapCache::binderDied(const wp<IBinder>& binder) -{ - //LOGD("binderDied binder=%p", binder.unsafe_get()); - free_heap(binder); -} - -sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder) -{ - Mutex::Autolock _l(mHeapCacheLock); - ssize_t i = mHeapCache.indexOfKey(binder); - if (i>=0) { - heap_info_t& info = mHeapCache.editValueAt(i); - LOGD_IF(VERBOSE, - "found binder=%p, heap=%p, size=%d, fd=%d, count=%d", - binder.get(), info.heap.get(), - static_cast<BpMemoryHeap*>(info.heap.get())->mSize, - static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId, - info.count); - android_atomic_inc(&info.count); - return info.heap; - } else { - heap_info_t info; - info.heap = interface_cast<IMemoryHeap>(binder); - info.count = 1; - //LOGD("adding binder=%p, heap=%p, count=%d", - // binder.get(), info.heap.get(), info.count); - mHeapCache.add(binder, info); - return info.heap; - } -} - -void HeapCache::pin_heap(const sp<IBinder>& binder) -{ - Mutex::Autolock _l(mHeapCacheLock); - ssize_t i = mHeapCache.indexOfKey(binder); - if (i>=0) { - heap_info_t& info(mHeapCache.editValueAt(i)); - android_atomic_inc(&info.count); - binder->linkToDeath(this); - } else { - LOGE("pin_heap binder=%p not found!!!", binder.get()); - } -} - -void HeapCache::free_heap(const sp<IBinder>& binder) { - free_heap( wp<IBinder>(binder) ); -} - -void HeapCache::free_heap(const wp<IBinder>& binder) -{ - sp<IMemoryHeap> rel; - { - Mutex::Autolock _l(mHeapCacheLock); - ssize_t i = mHeapCache.indexOfKey(binder); - if (i>=0) { - heap_info_t& info(mHeapCache.editValueAt(i)); - int32_t c = android_atomic_dec(&info.count); - if (c == 1) { - LOGD_IF(VERBOSE, - "removing binder=%p, heap=%p, size=%d, fd=%d, count=%d", - binder.unsafe_get(), info.heap.get(), - static_cast<BpMemoryHeap*>(info.heap.get())->mSize, - static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId, - info.count); - rel = mHeapCache.valueAt(i).heap; - mHeapCache.removeItemsAt(i); - } - } else { - LOGE("free_heap binder=%p not found!!!", binder.unsafe_get()); - } - } -} - -sp<IMemoryHeap> HeapCache::get_heap(const sp<IBinder>& binder) -{ - sp<IMemoryHeap> realHeap; - Mutex::Autolock _l(mHeapCacheLock); - ssize_t i = mHeapCache.indexOfKey(binder); - if (i>=0) realHeap = mHeapCache.valueAt(i).heap; - else realHeap = interface_cast<IMemoryHeap>(binder); - return realHeap; -} - -void HeapCache::dump_heaps() -{ - Mutex::Autolock _l(mHeapCacheLock); - int c = mHeapCache.size(); - for (int i=0 ; i<c ; i++) { - const heap_info_t& info = mHeapCache.valueAt(i); - BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get())); - LOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%d)", - mHeapCache.keyAt(i).unsafe_get(), - info.heap.get(), info.count, - h->mHeapId, h->mBase, h->mSize); - } -} - - -// --------------------------------------------------------------------------- -}; // namespace android diff --git a/libs/utils/IPCThreadState.cpp b/libs/utils/IPCThreadState.cpp deleted file mode 100644 index 04ae142..0000000 --- a/libs/utils/IPCThreadState.cpp +++ /dev/null @@ -1,1030 +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 <utils/IPCThreadState.h> - -#include <utils/Binder.h> -#include <utils/BpBinder.h> -#include <utils/Debug.h> -#include <utils/Log.h> -#include <utils/TextOutput.h> -#include <utils/threads.h> - -#include <private/utils/binder_module.h> -#include <private/utils/Static.h> - -#include <sys/ioctl.h> -#include <signal.h> -#include <errno.h> -#include <stdio.h> -#include <unistd.h> - -#ifdef HAVE_PTHREADS -#include <pthread.h> -#include <sched.h> -#include <sys/resource.h> -#endif -#ifdef HAVE_WIN32_THREADS -#include <windows.h> -#endif - - -#if LOG_NDEBUG - -#define IF_LOG_TRANSACTIONS() if (false) -#define IF_LOG_COMMANDS() if (false) -#define LOG_REMOTEREFS(...) -#define IF_LOG_REMOTEREFS() if (false) -#define LOG_THREADPOOL(...) -#define LOG_ONEWAY(...) - -#else - -#define IF_LOG_TRANSACTIONS() IF_LOG(LOG_VERBOSE, "transact") -#define IF_LOG_COMMANDS() IF_LOG(LOG_VERBOSE, "ipc") -#define LOG_REMOTEREFS(...) LOG(LOG_DEBUG, "remoterefs", __VA_ARGS__) -#define IF_LOG_REMOTEREFS() IF_LOG(LOG_DEBUG, "remoterefs") -#define LOG_THREADPOOL(...) LOG(LOG_DEBUG, "threadpool", __VA_ARGS__) -#define LOG_ONEWAY(...) LOG(LOG_DEBUG, "ipc", __VA_ARGS__) - -#endif - -// --------------------------------------------------------------------------- - -namespace android { - -static const char* getReturnString(size_t idx); -static const char* getCommandString(size_t idx); -static const void* printReturnCommand(TextOutput& out, const void* _cmd); -static const void* printCommand(TextOutput& out, const void* _cmd); - -// This will result in a missing symbol failure if the IF_LOG_COMMANDS() -// conditionals don't get stripped... but that is probably what we want. -#if !LOG_NDEBUG -static const char *kReturnStrings[] = { -#if 1 /* TODO: error update strings */ - "unknown", -#else - "BR_OK", - "BR_TIMEOUT", - "BR_WAKEUP", - "BR_TRANSACTION", - "BR_REPLY", - "BR_ACQUIRE_RESULT", - "BR_DEAD_REPLY", - "BR_TRANSACTION_COMPLETE", - "BR_INCREFS", - "BR_ACQUIRE", - "BR_RELEASE", - "BR_DECREFS", - "BR_ATTEMPT_ACQUIRE", - "BR_EVENT_OCCURRED", - "BR_NOOP", - "BR_SPAWN_LOOPER", - "BR_FINISHED", - "BR_DEAD_BINDER", - "BR_CLEAR_DEATH_NOTIFICATION_DONE" -#endif -}; - -static const char *kCommandStrings[] = { -#if 1 /* TODO: error update strings */ - "unknown", -#else - "BC_NOOP", - "BC_TRANSACTION", - "BC_REPLY", - "BC_ACQUIRE_RESULT", - "BC_FREE_BUFFER", - "BC_TRANSACTION_COMPLETE", - "BC_INCREFS", - "BC_ACQUIRE", - "BC_RELEASE", - "BC_DECREFS", - "BC_INCREFS_DONE", - "BC_ACQUIRE_DONE", - "BC_ATTEMPT_ACQUIRE", - "BC_RETRIEVE_ROOT_OBJECT", - "BC_SET_THREAD_ENTRY", - "BC_REGISTER_LOOPER", - "BC_ENTER_LOOPER", - "BC_EXIT_LOOPER", - "BC_SYNC", - "BC_STOP_PROCESS", - "BC_STOP_SELF", - "BC_REQUEST_DEATH_NOTIFICATION", - "BC_CLEAR_DEATH_NOTIFICATION", - "BC_DEAD_BINDER_DONE" -#endif -}; - -static const char* getReturnString(size_t idx) -{ - if (idx < sizeof(kReturnStrings) / sizeof(kReturnStrings[0])) - return kReturnStrings[idx]; - else - return "unknown"; -} - -static const char* getCommandString(size_t idx) -{ - if (idx < sizeof(kCommandStrings) / sizeof(kCommandStrings[0])) - return kCommandStrings[idx]; - else - return "unknown"; -} - -static const void* printBinderTransactionData(TextOutput& out, const void* data) -{ - const binder_transaction_data* btd = - (const binder_transaction_data*)data; - out << "target=" << btd->target.ptr << " (cookie " << btd->cookie << ")" << endl - << "code=" << TypeCode(btd->code) << ", flags=" << (void*)btd->flags << endl - << "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size - << " bytes)" << endl - << "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size - << " bytes)" << endl; - return btd+1; -} - -static const void* printReturnCommand(TextOutput& out, const void* _cmd) -{ - static const int32_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[0]); - - const int32_t* cmd = (const int32_t*)_cmd; - int32_t code = *cmd++; - if (code == BR_ERROR) { - out << "BR_ERROR: " << (void*)(*cmd++) << endl; - return cmd; - } else if (code < 0 || code >= N) { - out << "Unknown reply: " << code << endl; - return cmd; - } - - out << kReturnStrings[code]; - switch (code) { - case BR_TRANSACTION: - case BR_REPLY: { - out << ": " << indent; - cmd = (const int32_t *)printBinderTransactionData(out, cmd); - out << dedent; - } break; - - case BR_ACQUIRE_RESULT: { - const int32_t res = *cmd++; - out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)"); - } break; - - case BR_INCREFS: - case BR_ACQUIRE: - case BR_RELEASE: - case BR_DECREFS: { - const int32_t b = *cmd++; - const int32_t c = *cmd++; - out << ": target=" << (void*)b << " (cookie " << (void*)c << ")"; - } break; - - case BR_ATTEMPT_ACQUIRE: { - const int32_t p = *cmd++; - const int32_t b = *cmd++; - const int32_t c = *cmd++; - out << ": target=" << (void*)b << " (cookie " << (void*)c - << "), pri=" << p; - } break; - - case BR_DEAD_BINDER: - case BR_CLEAR_DEATH_NOTIFICATION_DONE: { - const int32_t c = *cmd++; - out << ": death cookie " << (void*)c; - } break; - } - - out << endl; - return cmd; -} - -static const void* printCommand(TextOutput& out, const void* _cmd) -{ - static const int32_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]); - - const int32_t* cmd = (const int32_t*)_cmd; - int32_t code = *cmd++; - if (code < 0 || code >= N) { - out << "Unknown command: " << code << endl; - return cmd; - } - - out << kCommandStrings[code]; - switch (code) { - case BC_TRANSACTION: - case BC_REPLY: { - out << ": " << indent; - cmd = (const int32_t *)printBinderTransactionData(out, cmd); - out << dedent; - } break; - - case BC_ACQUIRE_RESULT: { - const int32_t res = *cmd++; - out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)"); - } break; - - case BC_FREE_BUFFER: { - const int32_t buf = *cmd++; - out << ": buffer=" << (void*)buf; - } break; - - case BC_INCREFS: - case BC_ACQUIRE: - case BC_RELEASE: - case BC_DECREFS: { - const int32_t d = *cmd++; - out << ": descriptor=" << (void*)d; - } break; - - case BC_INCREFS_DONE: - case BC_ACQUIRE_DONE: { - const int32_t b = *cmd++; - const int32_t c = *cmd++; - out << ": target=" << (void*)b << " (cookie " << (void*)c << ")"; - } break; - - case BC_ATTEMPT_ACQUIRE: { - const int32_t p = *cmd++; - const int32_t d = *cmd++; - out << ": decriptor=" << (void*)d << ", pri=" << p; - } break; - - case BC_REQUEST_DEATH_NOTIFICATION: - case BC_CLEAR_DEATH_NOTIFICATION: { - const int32_t h = *cmd++; - const int32_t c = *cmd++; - out << ": handle=" << h << " (death cookie " << (void*)c << ")"; - } break; - - case BC_DEAD_BINDER_DONE: { - const int32_t c = *cmd++; - out << ": death cookie " << (void*)c; - } break; - } - - out << endl; - return cmd; -} -#endif - -static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER; -static bool gHaveTLS = false; -static pthread_key_t gTLS = 0; -static bool gShutdown = false; - -IPCThreadState* IPCThreadState::self() -{ - if (gHaveTLS) { -restart: - const pthread_key_t k = gTLS; - IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k); - if (st) return st; - return new IPCThreadState; - } - - if (gShutdown) return NULL; - - pthread_mutex_lock(&gTLSMutex); - if (!gHaveTLS) { - if (pthread_key_create(&gTLS, threadDestructor) != 0) { - pthread_mutex_unlock(&gTLSMutex); - return NULL; - } - gHaveTLS = true; - } - pthread_mutex_unlock(&gTLSMutex); - goto restart; -} - -void IPCThreadState::shutdown() -{ - gShutdown = true; - - if (gHaveTLS) { - // XXX Need to wait for all thread pool threads to exit! - IPCThreadState* st = (IPCThreadState*)pthread_getspecific(gTLS); - if (st) { - delete st; - pthread_setspecific(gTLS, NULL); - } - gHaveTLS = false; - } -} - -sp<ProcessState> IPCThreadState::process() -{ - return mProcess; -} - -status_t IPCThreadState::clearLastError() -{ - const status_t err = mLastError; - mLastError = NO_ERROR; - return err; -} - -int IPCThreadState::getCallingPid() -{ - return mCallingPid; -} - -int IPCThreadState::getCallingUid() -{ - return mCallingUid; -} - -int64_t IPCThreadState::clearCallingIdentity() -{ - int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid; - clearCaller(); - return token; -} - -void IPCThreadState::restoreCallingIdentity(int64_t token) -{ - mCallingUid = (int)(token>>32); - mCallingPid = (int)token; -} - -void IPCThreadState::clearCaller() -{ - if (mProcess->supportsProcesses()) { - mCallingPid = getpid(); - mCallingUid = getuid(); - } else { - mCallingPid = -1; - mCallingUid = -1; - } -} - -void IPCThreadState::flushCommands() -{ - if (mProcess->mDriverFD <= 0) - return; - talkWithDriver(false); -} - -void IPCThreadState::joinThreadPool(bool isMain) -{ - LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid()); - - mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); - - status_t result; - do { - int32_t cmd; - - // When we've cleared the incoming command queue, process any pending derefs - if (mIn.dataPosition() >= mIn.dataSize()) { - size_t numPending = mPendingWeakDerefs.size(); - if (numPending > 0) { - for (size_t i = 0; i < numPending; i++) { - RefBase::weakref_type* refs = mPendingWeakDerefs[i]; - refs->decWeak(mProcess.get()); - } - mPendingWeakDerefs.clear(); - } - - numPending = mPendingStrongDerefs.size(); - if (numPending > 0) { - for (size_t i = 0; i < numPending; i++) { - BBinder* obj = mPendingStrongDerefs[i]; - obj->decStrong(mProcess.get()); - } - mPendingStrongDerefs.clear(); - } - } - - // now get the next command to be processed, waiting if necessary - result = talkWithDriver(); - if (result >= NO_ERROR) { - size_t IN = mIn.dataAvail(); - if (IN < sizeof(int32_t)) continue; - cmd = mIn.readInt32(); - IF_LOG_COMMANDS() { - alog << "Processing top-level Command: " - << getReturnString(cmd) << endl; - } - result = executeCommand(cmd); - } - - // Let this thread exit the thread pool if it is no longer - // needed and it is not the main process thread. - if(result == TIMED_OUT && !isMain) { - break; - } - } while (result != -ECONNREFUSED && result != -EBADF); - - LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n", - (void*)pthread_self(), getpid(), (void*)result); - - mOut.writeInt32(BC_EXIT_LOOPER); - talkWithDriver(false); -} - -void IPCThreadState::stopProcess(bool immediate) -{ - //LOGI("**** STOPPING PROCESS"); - flushCommands(); - int fd = mProcess->mDriverFD; - mProcess->mDriverFD = -1; - close(fd); - //kill(getpid(), SIGKILL); -} - -status_t IPCThreadState::transact(int32_t handle, - uint32_t code, const Parcel& data, - Parcel* reply, uint32_t flags) -{ - status_t err = data.errorCheck(); - - flags |= TF_ACCEPT_FDS; - - IF_LOG_TRANSACTIONS() { - TextOutput::Bundle _b(alog); - alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand " - << handle << " / code " << TypeCode(code) << ": " - << indent << data << dedent << endl; - } - - if (err == NO_ERROR) { - LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(), - (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY"); - err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL); - } - - if (err != NO_ERROR) { - if (reply) reply->setError(err); - return (mLastError = err); - } - - if ((flags & TF_ONE_WAY) == 0) { - if (reply) { - err = waitForResponse(reply); - } else { - Parcel fakeReply; - err = waitForResponse(&fakeReply); - } - - IF_LOG_TRANSACTIONS() { - TextOutput::Bundle _b(alog); - alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand " - << handle << ": "; - if (reply) alog << indent << *reply << dedent << endl; - else alog << "(none requested)" << endl; - } - } else { - err = waitForResponse(NULL, NULL); - } - - return err; -} - -void IPCThreadState::incStrongHandle(int32_t handle) -{ - LOG_REMOTEREFS("IPCThreadState::incStrongHandle(%d)\n", handle); - mOut.writeInt32(BC_ACQUIRE); - mOut.writeInt32(handle); -} - -void IPCThreadState::decStrongHandle(int32_t handle) -{ - LOG_REMOTEREFS("IPCThreadState::decStrongHandle(%d)\n", handle); - mOut.writeInt32(BC_RELEASE); - mOut.writeInt32(handle); -} - -void IPCThreadState::incWeakHandle(int32_t handle) -{ - LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle); - mOut.writeInt32(BC_INCREFS); - mOut.writeInt32(handle); -} - -void IPCThreadState::decWeakHandle(int32_t handle) -{ - LOG_REMOTEREFS("IPCThreadState::decWeakHandle(%d)\n", handle); - mOut.writeInt32(BC_DECREFS); - mOut.writeInt32(handle); -} - -status_t IPCThreadState::attemptIncStrongHandle(int32_t handle) -{ - mOut.writeInt32(BC_ATTEMPT_ACQUIRE); - mOut.writeInt32(0); // xxx was thread priority - mOut.writeInt32(handle); - status_t result = UNKNOWN_ERROR; - - waitForResponse(NULL, &result); - -#if LOG_REFCOUNTS - printf("IPCThreadState::attemptIncStrongHandle(%ld) = %s\n", - handle, result == NO_ERROR ? "SUCCESS" : "FAILURE"); -#endif - - return result; -} - -void IPCThreadState::expungeHandle(int32_t handle, IBinder* binder) -{ -#if LOG_REFCOUNTS - printf("IPCThreadState::expungeHandle(%ld)\n", handle); -#endif - self()->mProcess->expungeHandle(handle, binder); -} - -status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy) -{ - mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION); - mOut.writeInt32((int32_t)handle); - mOut.writeInt32((int32_t)proxy); - return NO_ERROR; -} - -status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy) -{ - mOut.writeInt32(BC_CLEAR_DEATH_NOTIFICATION); - mOut.writeInt32((int32_t)handle); - mOut.writeInt32((int32_t)proxy); - return NO_ERROR; -} - -IPCThreadState::IPCThreadState() - : mProcess(ProcessState::self()) -{ - pthread_setspecific(gTLS, this); - clearCaller(); - mIn.setDataCapacity(256); - mOut.setDataCapacity(256); -} - -IPCThreadState::~IPCThreadState() -{ -} - -status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags) -{ - status_t err; - status_t statusBuffer; - err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer); - if (err < NO_ERROR) return err; - - return waitForResponse(NULL, NULL); -} - -status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) -{ - int32_t cmd; - int32_t err; - - while (1) { - if ((err=talkWithDriver()) < NO_ERROR) break; - err = mIn.errorCheck(); - if (err < NO_ERROR) break; - if (mIn.dataAvail() == 0) continue; - - cmd = mIn.readInt32(); - - IF_LOG_COMMANDS() { - alog << "Processing waitForResponse Command: " - << getReturnString(cmd) << endl; - } - - switch (cmd) { - case BR_TRANSACTION_COMPLETE: - if (!reply && !acquireResult) goto finish; - break; - - case BR_DEAD_REPLY: - err = DEAD_OBJECT; - goto finish; - - case BR_FAILED_REPLY: - err = FAILED_TRANSACTION; - goto finish; - - case BR_ACQUIRE_RESULT: - { - LOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT"); - const int32_t result = mIn.readInt32(); - if (!acquireResult) continue; - *acquireResult = result ? NO_ERROR : INVALID_OPERATION; - } - goto finish; - - case BR_REPLY: - { - binder_transaction_data tr; - err = mIn.read(&tr, sizeof(tr)); - LOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY"); - if (err != NO_ERROR) goto finish; - - if (reply) { - if ((tr.flags & TF_STATUS_CODE) == 0) { - reply->ipcSetDataReference( - reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer), - tr.data_size, - reinterpret_cast<const size_t*>(tr.data.ptr.offsets), - tr.offsets_size/sizeof(size_t), - freeBuffer, this); - } else { - err = *static_cast<const status_t*>(tr.data.ptr.buffer); - freeBuffer(NULL, - reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer), - tr.data_size, - reinterpret_cast<const size_t*>(tr.data.ptr.offsets), - tr.offsets_size/sizeof(size_t), this); - } - } else { - freeBuffer(NULL, - reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer), - tr.data_size, - reinterpret_cast<const size_t*>(tr.data.ptr.offsets), - tr.offsets_size/sizeof(size_t), this); - continue; - } - } - goto finish; - - default: - err = executeCommand(cmd); - if (err != NO_ERROR) goto finish; - break; - } - } - -finish: - if (err != NO_ERROR) { - if (acquireResult) *acquireResult = err; - if (reply) reply->setError(err); - mLastError = err; - } - - return err; -} - -status_t IPCThreadState::talkWithDriver(bool doReceive) -{ - LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened"); - - binder_write_read bwr; - - // Is the read buffer empty? - const bool needRead = mIn.dataPosition() >= mIn.dataSize(); - - // We don't want to write anything if we are still reading - // from data left in the input buffer and the caller - // has requested to read the next data. - const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0; - - bwr.write_size = outAvail; - bwr.write_buffer = (long unsigned int)mOut.data(); - - // This is what we'll read. - if (doReceive && needRead) { - bwr.read_size = mIn.dataCapacity(); - bwr.read_buffer = (long unsigned int)mIn.data(); - } else { - bwr.read_size = 0; - } - - IF_LOG_COMMANDS() { - TextOutput::Bundle _b(alog); - if (outAvail != 0) { - alog << "Sending commands to driver: " << indent; - const void* cmds = (const void*)bwr.write_buffer; - const void* end = ((const uint8_t*)cmds)+bwr.write_size; - alog << HexDump(cmds, bwr.write_size) << endl; - while (cmds < end) cmds = printCommand(alog, cmds); - alog << dedent; - } - alog << "Size of receive buffer: " << bwr.read_size - << ", needRead: " << needRead << ", doReceive: " << doReceive << endl; - } - - // Return immediately if there is nothing to do. - if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR; - - bwr.write_consumed = 0; - bwr.read_consumed = 0; - status_t err; - do { - IF_LOG_COMMANDS() { - alog << "About to read/write, write size = " << mOut.dataSize() << endl; - } -#if defined(HAVE_ANDROID_OS) - if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0) - err = NO_ERROR; - else - err = -errno; -#else - err = INVALID_OPERATION; -#endif - IF_LOG_COMMANDS() { - alog << "Finished read/write, write size = " << mOut.dataSize() << endl; - } - } while (err == -EINTR); - - IF_LOG_COMMANDS() { - alog << "Our err: " << (void*)err << ", write consumed: " - << bwr.write_consumed << " (of " << mOut.dataSize() - << "), read consumed: " << bwr.read_consumed << endl; - } - - if (err >= NO_ERROR) { - if (bwr.write_consumed > 0) { - if (bwr.write_consumed < (ssize_t)mOut.dataSize()) - mOut.remove(0, bwr.write_consumed); - else - mOut.setDataSize(0); - } - if (bwr.read_consumed > 0) { - mIn.setDataSize(bwr.read_consumed); - mIn.setDataPosition(0); - } - IF_LOG_COMMANDS() { - TextOutput::Bundle _b(alog); - alog << "Remaining data size: " << mOut.dataSize() << endl; - alog << "Received commands from driver: " << indent; - const void* cmds = mIn.data(); - const void* end = mIn.data() + mIn.dataSize(); - alog << HexDump(cmds, mIn.dataSize()) << endl; - while (cmds < end) cmds = printReturnCommand(alog, cmds); - alog << dedent; - } - return NO_ERROR; - } - - return err; -} - -status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, - int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer) -{ - binder_transaction_data tr; - - tr.target.handle = handle; - tr.code = code; - tr.flags = binderFlags; - - const status_t err = data.errorCheck(); - if (err == NO_ERROR) { - tr.data_size = data.ipcDataSize(); - tr.data.ptr.buffer = data.ipcData(); - tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t); - tr.data.ptr.offsets = data.ipcObjects(); - } else if (statusBuffer) { - tr.flags |= TF_STATUS_CODE; - *statusBuffer = err; - tr.data_size = sizeof(status_t); - tr.data.ptr.buffer = statusBuffer; - tr.offsets_size = 0; - tr.data.ptr.offsets = NULL; - } else { - return (mLastError = err); - } - - mOut.writeInt32(cmd); - mOut.write(&tr, sizeof(tr)); - - return NO_ERROR; -} - -sp<BBinder> the_context_object; - -void setTheContextObject(sp<BBinder> obj) -{ - the_context_object = obj; -} - -status_t IPCThreadState::executeCommand(int32_t cmd) -{ - BBinder* obj; - RefBase::weakref_type* refs; - status_t result = NO_ERROR; - - switch (cmd) { - case BR_ERROR: - result = mIn.readInt32(); - break; - - case BR_OK: - break; - - case BR_ACQUIRE: - refs = (RefBase::weakref_type*)mIn.readInt32(); - obj = (BBinder*)mIn.readInt32(); - LOG_ASSERT(refs->refBase() == obj, - "BR_ACQUIRE: object %p does not match cookie %p (expected %p)", - refs, obj, refs->refBase()); - obj->incStrong(mProcess.get()); - IF_LOG_REMOTEREFS() { - LOG_REMOTEREFS("BR_ACQUIRE from driver on %p", obj); - obj->printRefs(); - } - mOut.writeInt32(BC_ACQUIRE_DONE); - mOut.writeInt32((int32_t)refs); - mOut.writeInt32((int32_t)obj); - break; - - case BR_RELEASE: - refs = (RefBase::weakref_type*)mIn.readInt32(); - obj = (BBinder*)mIn.readInt32(); - LOG_ASSERT(refs->refBase() == obj, - "BR_RELEASE: object %p does not match cookie %p (expected %p)", - refs, obj, refs->refBase()); - IF_LOG_REMOTEREFS() { - LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj); - obj->printRefs(); - } - mPendingStrongDerefs.push(obj); - break; - - case BR_INCREFS: - refs = (RefBase::weakref_type*)mIn.readInt32(); - obj = (BBinder*)mIn.readInt32(); - refs->incWeak(mProcess.get()); - mOut.writeInt32(BC_INCREFS_DONE); - mOut.writeInt32((int32_t)refs); - mOut.writeInt32((int32_t)obj); - break; - - case BR_DECREFS: - refs = (RefBase::weakref_type*)mIn.readInt32(); - obj = (BBinder*)mIn.readInt32(); - // NOTE: This assertion is not valid, because the object may no - // longer exist (thus the (BBinder*)cast above resulting in a different - // memory address). - //LOG_ASSERT(refs->refBase() == obj, - // "BR_DECREFS: object %p does not match cookie %p (expected %p)", - // refs, obj, refs->refBase()); - mPendingWeakDerefs.push(refs); - break; - - case BR_ATTEMPT_ACQUIRE: - refs = (RefBase::weakref_type*)mIn.readInt32(); - obj = (BBinder*)mIn.readInt32(); - - { - const bool success = refs->attemptIncStrong(mProcess.get()); - LOG_ASSERT(success && refs->refBase() == obj, - "BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)", - refs, obj, refs->refBase()); - - mOut.writeInt32(BC_ACQUIRE_RESULT); - mOut.writeInt32((int32_t)success); - } - break; - - case BR_TRANSACTION: - { - binder_transaction_data tr; - result = mIn.read(&tr, sizeof(tr)); - LOG_ASSERT(result == NO_ERROR, - "Not enough command data for brTRANSACTION"); - if (result != NO_ERROR) break; - - Parcel buffer; - buffer.ipcSetDataReference( - reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer), - tr.data_size, - reinterpret_cast<const size_t*>(tr.data.ptr.offsets), - tr.offsets_size/sizeof(size_t), freeBuffer, this); - - const pid_t origPid = mCallingPid; - const uid_t origUid = mCallingUid; - - mCallingPid = tr.sender_pid; - mCallingUid = tr.sender_euid; - - //LOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid); - - Parcel reply; - IF_LOG_TRANSACTIONS() { - TextOutput::Bundle _b(alog); - alog << "BR_TRANSACTION thr " << (void*)pthread_self() - << " / obj " << tr.target.ptr << " / code " - << TypeCode(tr.code) << ": " << indent << buffer - << dedent << endl - << "Data addr = " - << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer) - << ", offsets addr=" - << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl; - } - if (tr.target.ptr) { - sp<BBinder> b((BBinder*)tr.cookie); - const status_t error = b->transact(tr.code, buffer, &reply, 0); - if (error < NO_ERROR) reply.setError(error); - - } else { - const status_t error = the_context_object->transact(tr.code, buffer, &reply, 0); - if (error < NO_ERROR) reply.setError(error); - } - - //LOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n", - // mCallingPid, origPid, origUid); - - if ((tr.flags & TF_ONE_WAY) == 0) { - LOG_ONEWAY("Sending reply to %d!", mCallingPid); - sendReply(reply, 0); - } else { - LOG_ONEWAY("NOT sending reply to %d!", mCallingPid); - } - - mCallingPid = origPid; - mCallingUid = origUid; - - IF_LOG_TRANSACTIONS() { - TextOutput::Bundle _b(alog); - alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj " - << tr.target.ptr << ": " << indent << reply << dedent << endl; - } - - } - break; - - case BR_DEAD_BINDER: - { - BpBinder *proxy = (BpBinder*)mIn.readInt32(); - proxy->sendObituary(); - mOut.writeInt32(BC_DEAD_BINDER_DONE); - mOut.writeInt32((int32_t)proxy); - } break; - - case BR_CLEAR_DEATH_NOTIFICATION_DONE: - { - BpBinder *proxy = (BpBinder*)mIn.readInt32(); - proxy->getWeakRefs()->decWeak(proxy); - } break; - - case BR_FINISHED: - result = TIMED_OUT; - break; - - case BR_NOOP: - break; - - case BR_SPAWN_LOOPER: - mProcess->spawnPooledThread(false); - break; - - default: - printf("*** BAD COMMAND %d received from Binder driver\n", cmd); - result = UNKNOWN_ERROR; - break; - } - - if (result != NO_ERROR) { - mLastError = result; - } - - return result; -} - -void IPCThreadState::threadDestructor(void *st) -{ - IPCThreadState* const self = static_cast<IPCThreadState*>(st); - if (self) { - self->flushCommands(); -#if defined(HAVE_ANDROID_OS) - ioctl(self->mProcess->mDriverFD, BINDER_THREAD_EXIT, 0); -#endif - delete self; - } -} - - -void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data, size_t dataSize, - const size_t* objects, size_t objectsSize, - void* cookie) -{ - //LOGI("Freeing parcel %p", &parcel); - IF_LOG_COMMANDS() { - alog << "Writing BC_FREE_BUFFER for " << data << endl; - } - LOG_ASSERT(data != NULL, "Called with NULL data"); - if (parcel != NULL) parcel->closeFileDescriptors(); - IPCThreadState* state = self(); - state->mOut.writeInt32(BC_FREE_BUFFER); - state->mOut.writeInt32((int32_t)data); -} - -}; // namespace android diff --git a/libs/utils/IPermissionController.cpp b/libs/utils/IPermissionController.cpp deleted file mode 100644 index f01d38f..0000000 --- a/libs/utils/IPermissionController.cpp +++ /dev/null @@ -1,86 +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 "PermissionController" - -#include <utils/IPermissionController.h> - -#include <utils/Debug.h> -#include <utils/Log.h> -#include <utils/Parcel.h> -#include <utils/String8.h> - -#include <private/utils/Static.h> - -namespace android { - -// ---------------------------------------------------------------------- - -class BpPermissionController : public BpInterface<IPermissionController> -{ -public: - BpPermissionController(const sp<IBinder>& impl) - : BpInterface<IPermissionController>(impl) - { - } - - virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid) - { - Parcel data, reply; - data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor()); - data.writeString16(permission); - data.writeInt32(pid); - data.writeInt32(uid); - remote()->transact(CHECK_PERMISSION_TRANSACTION, data, &reply); - // fail on exception - if (reply.readInt32() != 0) return 0; - return reply.readInt32() != 0; - } -}; - -IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController"); - -// ---------------------------------------------------------------------- - -#define CHECK_INTERFACE(interface, data, reply) \ - do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ - LOGW("Call incorrectly routed to " #interface); \ - return PERMISSION_DENIED; \ - } } while (0) - -status_t BnPermissionController::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - //printf("PermissionController received: "); data.print(); - switch(code) { - case CHECK_PERMISSION_TRANSACTION: { - CHECK_INTERFACE(IPermissionController, data, reply); - String16 permission = data.readString16(); - int32_t pid = data.readInt32(); - int32_t uid = data.readInt32(); - bool res = checkPermission(permission, pid, uid); - // write exception - reply->writeInt32(0); - reply->writeInt32(res ? 1 : 0); - return NO_ERROR; - } break; - default: - return BBinder::onTransact(code, data, reply, flags); - } -} - -}; // namespace android - diff --git a/libs/utils/IServiceManager.cpp b/libs/utils/IServiceManager.cpp deleted file mode 100644 index 9beeadd..0000000 --- a/libs/utils/IServiceManager.cpp +++ /dev/null @@ -1,230 +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 "ServiceManager" - -#include <utils/IServiceManager.h> - -#include <utils/Debug.h> -#include <utils/IPCThreadState.h> -#include <utils/Log.h> -#include <utils/Parcel.h> -#include <utils/String8.h> -#include <utils/SystemClock.h> - -#include <private/utils/Static.h> - -#include <unistd.h> - -namespace android { - -sp<IServiceManager> defaultServiceManager() -{ - if (gDefaultServiceManager != NULL) return gDefaultServiceManager; - - { - AutoMutex _l(gDefaultServiceManagerLock); - if (gDefaultServiceManager == NULL) { - gDefaultServiceManager = interface_cast<IServiceManager>( - ProcessState::self()->getContextObject(NULL)); - } - } - - return gDefaultServiceManager; -} - -bool checkCallingPermission(const String16& permission) -{ - return checkCallingPermission(permission, NULL, NULL); -} - -static String16 _permission("permission"); - -bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid) -{ - IPCThreadState* ipcState = IPCThreadState::self(); - int32_t pid = ipcState->getCallingPid(); - int32_t uid = ipcState->getCallingUid(); - if (outPid) *outPid = pid; - if (outUid) *outUid= uid; - - sp<IPermissionController> pc; - gDefaultServiceManagerLock.lock(); - pc = gPermissionController; - gDefaultServiceManagerLock.unlock(); - - int64_t startTime = 0; - - while (true) { - if (pc != NULL) { - bool res = pc->checkPermission(permission, pid, uid); - if (res) { - if (startTime != 0) { - LOGI("Check passed after %d seconds for %s from uid=%d pid=%d", - (int)((uptimeMillis()-startTime)/1000), - String8(permission).string(), uid, pid); - } - return res; - } - - // Is this a permission failure, or did the controller go away? - if (pc->asBinder()->isBinderAlive()) { - LOGW("Permission failure: %s from uid=%d pid=%d", - String8(permission).string(), uid, pid); - return false; - } - - // Object is dead! - gDefaultServiceManagerLock.lock(); - if (gPermissionController == pc) { - gPermissionController = NULL; - } - gDefaultServiceManagerLock.unlock(); - } - - // Need to retrieve the permission controller. - sp<IBinder> binder = defaultServiceManager()->checkService(_permission); - if (binder == NULL) { - // Wait for the permission controller to come back... - if (startTime == 0) { - startTime = uptimeMillis(); - LOGI("Waiting to check permission %s from uid=%d pid=%d", - String8(permission).string(), uid, pid); - } - sleep(1); - } else { - pc = interface_cast<IPermissionController>(binder); - // Install the new permission controller, and try again. - gDefaultServiceManagerLock.lock(); - gPermissionController = pc; - gDefaultServiceManagerLock.unlock(); - } - } -} - -// ---------------------------------------------------------------------- - -class BpServiceManager : public BpInterface<IServiceManager> -{ -public: - BpServiceManager(const sp<IBinder>& impl) - : BpInterface<IServiceManager>(impl) - { - } - - virtual sp<IBinder> getService(const String16& name) const - { - unsigned n; - for (n = 0; n < 5; n++){ - sp<IBinder> svc = checkService(name); - if (svc != NULL) return svc; - LOGI("Waiting for sevice %s...\n", String8(name).string()); - sleep(1); - } - return NULL; - } - - virtual sp<IBinder> checkService( const String16& name) const - { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeString16(name); - remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply); - return reply.readStrongBinder(); - } - - virtual status_t addService(const String16& name, const sp<IBinder>& service) - { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeString16(name); - data.writeStrongBinder(service); - status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); - return err == NO_ERROR ? reply.readInt32() : err; - } - - virtual Vector<String16> listServices() - { - Vector<String16> res; - int n = 0; - - for (;;) { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeInt32(n++); - status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply); - if (err != NO_ERROR) - break; - res.add(reply.readString16()); - } - return res; - } -}; - -IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager"); - -// ---------------------------------------------------------------------- - -#define CHECK_INTERFACE(interface, data, reply) \ - do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ - LOGW("Call incorrectly routed to " #interface); \ - return PERMISSION_DENIED; \ - } } while (0) - -status_t BnServiceManager::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - //printf("ServiceManager received: "); data.print(); - switch(code) { - case GET_SERVICE_TRANSACTION: { - CHECK_INTERFACE(IServiceManager, data, reply); - String16 which = data.readString16(); - sp<IBinder> b = const_cast<BnServiceManager*>(this)->getService(which); - reply->writeStrongBinder(b); - return NO_ERROR; - } break; - case CHECK_SERVICE_TRANSACTION: { - CHECK_INTERFACE(IServiceManager, data, reply); - String16 which = data.readString16(); - sp<IBinder> b = const_cast<BnServiceManager*>(this)->checkService(which); - reply->writeStrongBinder(b); - return NO_ERROR; - } break; - case ADD_SERVICE_TRANSACTION: { - CHECK_INTERFACE(IServiceManager, data, reply); - String16 which = data.readString16(); - sp<IBinder> b = data.readStrongBinder(); - status_t err = addService(which, b); - reply->writeInt32(err); - return NO_ERROR; - } break; - case LIST_SERVICES_TRANSACTION: { - CHECK_INTERFACE(IServiceManager, data, reply); - Vector<String16> list = listServices(); - const size_t N = list.size(); - reply->writeInt32(N); - for (size_t i=0; i<N; i++) { - reply->writeString16(list[i]); - } - return NO_ERROR; - } break; - default: - return BBinder::onTransact(code, data, reply, flags); - } -} - -}; // namespace android - diff --git a/libs/utils/InetAddress.cpp b/libs/utils/InetAddress.cpp deleted file mode 100644 index 39a0a68..0000000 --- a/libs/utils/InetAddress.cpp +++ /dev/null @@ -1,236 +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. - */ - -// -// Internet address class. -// -#ifdef HAVE_WINSOCK -# include <winsock2.h> -#else -# include <sys/types.h> -# include <sys/socket.h> -# include <netinet/in.h> -//# include <arpa/inet.h> -# include <netdb.h> -#endif - -#include <utils/inet_address.h> -#include <utils/threads.h> -#include <utils/Log.h> - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> - -using namespace android; - - -/* - * =========================================================================== - * InetAddress - * =========================================================================== - */ - -// lock for the next couple of functions; could tuck into InetAddress -static Mutex* gGHBNLock; - -/* - * Lock/unlock access to the hostent struct returned by gethostbyname(). - */ -static inline void lock_gethostbyname(void) -{ - if (gGHBNLock == NULL) - gGHBNLock = new Mutex; - gGHBNLock->lock(); -} -static inline void unlock_gethostbyname(void) -{ - assert(gGHBNLock != NULL); - gGHBNLock->unlock(); -} - - -/* - * Constructor -- just init members. This is private so that callers - * are required to use getByName(). - */ -InetAddress::InetAddress(void) - : mAddress(NULL), mLength(-1), mName(NULL) -{ -} - -/* - * Destructor -- free address storage. - */ -InetAddress::~InetAddress(void) -{ - delete[] (char*) mAddress; - delete[] mName; -} - -/* - * Copy constructor. - */ -InetAddress::InetAddress(const InetAddress& orig) -{ - *this = orig; // use assignment code -} - -/* - * Assignment operator. - */ -InetAddress& InetAddress::operator=(const InetAddress& addr) -{ - // handle self-assignment - if (this == &addr) - return *this; - // copy mLength and mAddress - mLength = addr.mLength; - if (mLength > 0) { - mAddress = new char[mLength]; - memcpy(mAddress, addr.mAddress, mLength); - LOG(LOG_DEBUG, "socket", - "HEY: copied %d bytes in assignment operator\n", mLength); - } else { - mAddress = NULL; - } - // copy mName - mName = new char[strlen(addr.mName)+1]; - strcpy(mName, addr.mName); - - return *this; -} - -/* - * Create a new object from a name or a dotted-number IP notation. - * - * Returns NULL on failure. - */ -InetAddress* -InetAddress::getByName(const char* host) -{ - InetAddress* newAddr = NULL; - struct sockaddr_in addr; - struct hostent* he; - DurationTimer hostTimer, lockTimer; - - // gethostbyname() isn't reentrant, so we need to lock things until - // we can copy the data out. - lockTimer.start(); - lock_gethostbyname(); - hostTimer.start(); - - he = gethostbyname(host); - if (he == NULL) { - LOG(LOG_WARN, "socket", "WARNING: cannot resolve host %s\n", host); - unlock_gethostbyname(); - return NULL; - } - - memcpy(&addr.sin_addr, he->h_addr, he->h_length); - addr.sin_family = he->h_addrtype; - addr.sin_port = 0; - - // got it, unlock us - hostTimer.stop(); - he = NULL; - unlock_gethostbyname(); - - lockTimer.stop(); - if ((long) lockTimer.durationUsecs() > 100000) { - long lockTime = (long) lockTimer.durationUsecs(); - long hostTime = (long) hostTimer.durationUsecs(); - LOG(LOG_DEBUG, "socket", - "Lookup of %s took %.3fs (gethostbyname=%.3fs lock=%.3fs)\n", - host, lockTime / 1000000.0, hostTime / 1000000.0, - (lockTime - hostTime) / 1000000.0); - } - - // Alloc storage and copy it over. - newAddr = new InetAddress(); - if (newAddr == NULL) - return NULL; - - newAddr->mLength = sizeof(struct sockaddr_in); - newAddr->mAddress = new char[sizeof(struct sockaddr_in)]; - if (newAddr->mAddress == NULL) { - delete newAddr; - return NULL; - } - memcpy(newAddr->mAddress, &addr, newAddr->mLength); - - // Keep this for debug messages. - newAddr->mName = new char[strlen(host)+1]; - if (newAddr->mName == NULL) { - delete newAddr; - return NULL; - } - strcpy(newAddr->mName, host); - - return newAddr; -} - - -/* - * =========================================================================== - * InetSocketAddress - * =========================================================================== - */ - -/* - * Create an address with the host wildcard (INADDR_ANY). - */ -bool InetSocketAddress::create(int port) -{ - assert(mAddress == NULL); - - mAddress = InetAddress::getByName("0.0.0.0"); - if (mAddress == NULL) - return false; - mPort = port; - return true; -} - -/* - * Create address with host and port specified. - */ -bool InetSocketAddress::create(const InetAddress* addr, int port) -{ - assert(mAddress == NULL); - - mAddress = new InetAddress(*addr); // make a copy - if (mAddress == NULL) - return false; - mPort = port; - return true; -} - -/* - * Create address with host and port specified. - */ -bool InetSocketAddress::create(const char* host, int port) -{ - assert(mAddress == NULL); - - mAddress = InetAddress::getByName(host); - if (mAddress == NULL) - return false; - mPort = port; - return true; -} - diff --git a/libs/utils/LogSocket.cpp b/libs/utils/LogSocket.cpp deleted file mode 100644 index 55c1b99..0000000 --- a/libs/utils/LogSocket.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef HAVE_WINSOCK -//#define SOCKETLOG -#endif - -#ifdef SOCKETLOG - -#define LOG_TAG "SOCKETLOG" - -#include <string.h> -#include <cutils/log.h> -#include "utils/LogSocket.h" -#include "utils/logger.h" -#include "cutils/hashmap.h" - -// defined in //device/data/etc/event-log-tags -#define SOCKET_CLOSE_LOG 51000 - -static Hashmap* statsMap = NULL; - -#define LOG_LIST_NUMBER 5 - -typedef struct SocketStats { - int fd; - unsigned int send; - unsigned int recv; - unsigned int ip; - unsigned short port; - short reason; -}SocketStats; - -SocketStats *get_socket_stats(int fd) { - if (statsMap == NULL) { - statsMap = hashmapCreate(8, &hashmapIntHash, &hashmapIntEquals); - } - - SocketStats *s = (SocketStats*) hashmapGet(statsMap, &fd); - if (s == NULL) { - // LOGD("create SocketStats for fd %d", fd); - s = (SocketStats*) malloc(sizeof(SocketStats)); - memset(s, 0, sizeof(SocketStats)); - s->fd = fd; - hashmapPut(statsMap, &s->fd, s); - } - return s; -} - -void log_socket_connect(int fd, unsigned int ip, unsigned short port) { - // LOGD("log_socket_connect for fd %d ip %d port%d", fd, ip, port); - SocketStats *s = get_socket_stats(fd); - s->ip = ip; - s->port = port; -} - -void add_send_stats(int fd, int send) { - if (send <=0) { - LOGE("add_send_stats send %d", send); - return; - } - SocketStats *s = get_socket_stats(fd); - s->send += send; - // LOGD("add_send_stats for fd %d ip %d port%d", fd, s->ip, s->port); -} - -void add_recv_stats(int fd, int recv) { - if (recv <=0) { - LOGE("add_recv_stats recv %d", recv); - return; - } - SocketStats *s = get_socket_stats(fd); - s->recv += recv; - // LOGD("add_recv_stats for fd %d ip %d port%d", fd, s->ip, s->port); -} - -char* put_int(char* buf, int value) { - *buf = EVENT_TYPE_INT; - buf++; - memcpy(buf, &value, sizeof(int)); - return buf + sizeof(int); -} - -void log_socket_close(int fd, short reason) { - if (statsMap) { - SocketStats *s = (SocketStats*) hashmapGet(statsMap, &fd); - if (s != NULL) { - if (s->send != 0 || s->recv != 0) { - s->reason = reason; - // 5 int + list type need 2 bytes - char buf[LOG_LIST_NUMBER * 5 + 2]; - buf[0] = EVENT_TYPE_LIST; - buf[1] = LOG_LIST_NUMBER; - char* writePos = buf + 2; - writePos = put_int(writePos, s->send); - writePos = put_int(writePos, s->recv); - writePos = put_int(writePos, s->ip); - writePos = put_int(writePos, s->port); - writePos = put_int(writePos, s->reason); - - android_bWriteLog(SOCKET_CLOSE_LOG, buf, sizeof(buf)); - // LOGD("send %d recv %d reason %d", s->send, s->recv, s->reason); - } - hashmapRemove(statsMap, &s->fd); - free(s); - } - } -} - -#else -void add_send_stats(int fd, int send) {} -void add_recv_stats(int fd, int recv) {} -void log_socket_close(int fd, short reason) {} -void log_socket_connect(int fd, unsigned int ip, unsigned short port) {} -#endif diff --git a/libs/utils/MODULE_LICENSE_APACHE2 b/libs/utils/MODULE_LICENSE_APACHE2 deleted file mode 100644 index e69de29..0000000 --- a/libs/utils/MODULE_LICENSE_APACHE2 +++ /dev/null diff --git a/libs/utils/MemoryBase.cpp b/libs/utils/MemoryBase.cpp deleted file mode 100644 index f25e11c..0000000 --- a/libs/utils/MemoryBase.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include <stdlib.h> -#include <stdint.h> - -#include <utils/MemoryBase.h> - - -namespace android { - -// --------------------------------------------------------------------------- - -MemoryBase::MemoryBase(const sp<IMemoryHeap>& heap, - ssize_t offset, size_t size) - : mSize(size), mOffset(offset), mHeap(heap) -{ -} - -sp<IMemoryHeap> MemoryBase::getMemory(ssize_t* offset, size_t* size) const -{ - if (offset) *offset = mOffset; - if (size) *size = mSize; - return mHeap; -} - -MemoryBase::~MemoryBase() -{ -} - -// --------------------------------------------------------------------------- -}; // namespace android diff --git a/libs/utils/MemoryDealer.cpp b/libs/utils/MemoryDealer.cpp deleted file mode 100644 index cf8201b..0000000 --- a/libs/utils/MemoryDealer.cpp +++ /dev/null @@ -1,409 +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. - */ - -#define LOG_TAG "MemoryDealer" - -#include <utils/MemoryDealer.h> - -#include <utils/Log.h> -#include <utils/IPCThreadState.h> -#include <utils/SortedVector.h> -#include <utils/String8.h> -#include <utils/MemoryBase.h> - -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> - -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/mman.h> -#include <sys/file.h> - -namespace android { - - -// ---------------------------------------------------------------------------- - -class SimpleMemory : public MemoryBase { -public: - SimpleMemory(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size); - virtual ~SimpleMemory(); -}; - - -// ---------------------------------------------------------------------------- - -MemoryDealer::Allocation::Allocation( - const sp<MemoryDealer>& dealer, ssize_t offset, size_t size, - const sp<IMemory>& memory) - : mDealer(dealer), mOffset(offset), mSize(size), mMemory(memory) -{ -} - -MemoryDealer::Allocation::~Allocation() -{ - if (mSize) { - /* NOTE: it's VERY important to not free allocations of size 0 because - * they're special as they don't have any record in the allocator - * and could alias some real allocation (their offset is zero). */ - mDealer->deallocate(mOffset); - } -} - -sp<IMemoryHeap> MemoryDealer::Allocation::getMemory( - ssize_t* offset, size_t* size) const -{ - return mMemory->getMemory(offset, size); -} - -// ---------------------------------------------------------------------------- - -MemoryDealer::MemoryDealer(size_t size, uint32_t flags, const char* name) - : mHeap(new SharedHeap(size, flags, name)), - mAllocator(new SimpleBestFitAllocator(size)) -{ -} - -MemoryDealer::MemoryDealer(const sp<HeapInterface>& heap) - : mHeap(heap), - mAllocator(new SimpleBestFitAllocator(heap->virtualSize())) -{ -} - -MemoryDealer::MemoryDealer( const sp<HeapInterface>& heap, - const sp<AllocatorInterface>& allocator) - : mHeap(heap), mAllocator(allocator) -{ -} - -MemoryDealer::~MemoryDealer() -{ -} - -sp<IMemory> MemoryDealer::allocate(size_t size, uint32_t flags) -{ - sp<IMemory> memory; - const ssize_t offset = allocator()->allocate(size, flags); - if (offset >= 0) { - sp<IMemory> new_memory = heap()->mapMemory(offset, size); - if (new_memory != 0) { - memory = new Allocation(this, offset, size, new_memory); - } else { - LOGE("couldn't map [%8x, %d]", offset, size); - if (size) { - /* NOTE: it's VERY important to not free allocations of size 0 - * because they're special as they don't have any record in the - * allocator and could alias some real allocation - * (their offset is zero). */ - allocator()->deallocate(offset); - } - } - } - return memory; -} - -void MemoryDealer::deallocate(size_t offset) -{ - allocator()->deallocate(offset); -} - -void MemoryDealer::dump(const char* what, uint32_t flags) const -{ - allocator()->dump(what, flags); -} - -const sp<HeapInterface>& MemoryDealer::heap() const { - return mHeap; -} - -const sp<AllocatorInterface>& MemoryDealer::allocator() const { - return mAllocator; -} - -// ---------------------------------------------------------------------------- - -// align all the memory blocks on a cache-line boundary -const int SimpleBestFitAllocator::kMemoryAlign = 32; - -SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size) -{ - size_t pagesize = getpagesize(); - mHeapSize = ((size + pagesize-1) & ~(pagesize-1)); - - chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign); - mList.insertHead(node); -} - -SimpleBestFitAllocator::~SimpleBestFitAllocator() -{ - while(!mList.isEmpty()) { - delete mList.remove(mList.head()); - } -} - -size_t SimpleBestFitAllocator::size() const -{ - return mHeapSize; -} - -size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags) -{ - Mutex::Autolock _l(mLock); - ssize_t offset = alloc(size, flags); - return offset; -} - -status_t SimpleBestFitAllocator::deallocate(size_t offset) -{ - Mutex::Autolock _l(mLock); - chunk_t const * const freed = dealloc(offset); - if (freed) { - return NO_ERROR; - } - return NAME_NOT_FOUND; -} - -ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags) -{ - if (size == 0) { - return 0; - } - size = (size + kMemoryAlign-1) / kMemoryAlign; - chunk_t* free_chunk = 0; - chunk_t* cur = mList.head(); - - size_t pagesize = getpagesize(); - while (cur) { - int extra = 0; - if (flags & PAGE_ALIGNED) - extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ; - - // best fit - if (cur->free && (cur->size >= (size+extra))) { - if ((!free_chunk) || (cur->size < free_chunk->size)) { - free_chunk = cur; - } - if (cur->size == size) { - break; - } - } - cur = cur->next; - } - - if (free_chunk) { - const size_t free_size = free_chunk->size; - free_chunk->free = 0; - free_chunk->size = size; - if (free_size > size) { - int extra = 0; - if (flags & PAGE_ALIGNED) - extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ; - if (extra) { - chunk_t* split = new chunk_t(free_chunk->start, extra); - free_chunk->start += extra; - mList.insertBefore(free_chunk, split); - } - - LOGE_IF((flags&PAGE_ALIGNED) && - ((free_chunk->start*kMemoryAlign)&(pagesize-1)), - "PAGE_ALIGNED requested, but page is not aligned!!!"); - - const ssize_t tail_free = free_size - (size+extra); - if (tail_free > 0) { - chunk_t* split = new chunk_t( - free_chunk->start + free_chunk->size, tail_free); - mList.insertAfter(free_chunk, split); - } - } - return (free_chunk->start)*kMemoryAlign; - } - return NO_MEMORY; -} - -SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start) -{ - start = start / kMemoryAlign; - chunk_t* cur = mList.head(); - while (cur) { - if (cur->start == start) { - LOG_FATAL_IF(cur->free, - "block at offset 0x%08lX of size 0x%08lX already freed", - cur->start*kMemoryAlign, cur->size*kMemoryAlign); - - // merge freed blocks together - chunk_t* freed = cur; - cur->free = 1; - do { - chunk_t* const p = cur->prev; - chunk_t* const n = cur->next; - if (p && (p->free || !cur->size)) { - freed = p; - p->size += cur->size; - mList.remove(cur); - delete cur; - } - cur = n; - } while (cur && cur->free); - - #ifndef NDEBUG - if (!freed->free) { - dump_l("dealloc (!freed->free)"); - } - #endif - LOG_FATAL_IF(!freed->free, - "freed block at offset 0x%08lX of size 0x%08lX is not free!", - freed->start * kMemoryAlign, freed->size * kMemoryAlign); - - return freed; - } - cur = cur->next; - } - return 0; -} - -void SimpleBestFitAllocator::dump(const char* what, uint32_t flags) const -{ - Mutex::Autolock _l(mLock); - dump_l(what, flags); -} - -void SimpleBestFitAllocator::dump_l(const char* what, uint32_t flags) const -{ - String8 result; - dump_l(result, what, flags); - LOGD("%s", result.string()); -} - -void SimpleBestFitAllocator::dump(String8& result, - const char* what, uint32_t flags) const -{ - Mutex::Autolock _l(mLock); - dump_l(result, what, flags); -} - -void SimpleBestFitAllocator::dump_l(String8& result, - const char* what, uint32_t flags) const -{ - size_t size = 0; - int32_t i = 0; - chunk_t const* cur = mList.head(); - - const size_t SIZE = 256; - char buffer[SIZE]; - snprintf(buffer, SIZE, " %s (%p, size=%u)\n", - what, this, (unsigned int)mHeapSize); - - result.append(buffer); - - while (cur) { - const char* errs[] = {"", "| link bogus NP", - "| link bogus PN", "| link bogus NP+PN" }; - int np = ((cur->next) && cur->next->prev != cur) ? 1 : 0; - int pn = ((cur->prev) && cur->prev->next != cur) ? 2 : 0; - - snprintf(buffer, SIZE, " %3u: %08x | 0x%08X | 0x%08X | %s %s\n", - i, int(cur), int(cur->start*kMemoryAlign), - int(cur->size*kMemoryAlign), - int(cur->free) ? "F" : "A", - errs[np|pn]); - - result.append(buffer); - - if (!cur->free) - size += cur->size*kMemoryAlign; - - i++; - cur = cur->next; - } - snprintf(buffer, SIZE, " size allocated: %u (%u KB)\n", int(size), int(size/1024)); - result.append(buffer); -} - -// ---------------------------------------------------------------------------- - - -SharedHeap::SharedHeap(size_t size, uint32_t flags, char const * name) - : MemoryHeapBase(size, flags, name) -{ -} - -SharedHeap::~SharedHeap() -{ -} - -sp<IMemory> SharedHeap::mapMemory(size_t offset, size_t size) -{ - return new SimpleMemory(this, offset, size); -} - - -SimpleMemory::SimpleMemory(const sp<IMemoryHeap>& heap, - ssize_t offset, size_t size) - : MemoryBase(heap, offset, size) -{ -#ifndef NDEBUG - void* const start_ptr = (void*)(intptr_t(heap->base()) + offset); - memset(start_ptr, 0xda, size); -#endif -} - -SimpleMemory::~SimpleMemory() -{ - size_t freedOffset = getOffset(); - size_t freedSize = getSize(); - - // keep the size to unmap in excess - size_t pagesize = getpagesize(); - size_t start = freedOffset; - size_t end = start + freedSize; - start &= ~(pagesize-1); - end = (end + pagesize-1) & ~(pagesize-1); - - // give back to the kernel the pages we don't need - size_t free_start = freedOffset; - size_t free_end = free_start + freedSize; - if (start < free_start) - start = free_start; - if (end > free_end) - end = free_end; - start = (start + pagesize-1) & ~(pagesize-1); - end &= ~(pagesize-1); - - if (start < end) { - void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start); - size_t size = end-start; - -#ifndef NDEBUG - memset(start_ptr, 0xdf, size); -#endif - - // MADV_REMOVE is not defined on Dapper based Goobuntu -#ifdef MADV_REMOVE - if (size) { - int err = madvise(start_ptr, size, MADV_REMOVE); - LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s", - start_ptr, size, err<0 ? strerror(errno) : "Ok"); - } -#endif - } -} - -}; // namespace android diff --git a/libs/utils/MemoryHeapBase.cpp b/libs/utils/MemoryHeapBase.cpp deleted file mode 100644 index 8251728..0000000 --- a/libs/utils/MemoryHeapBase.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "MemoryHeapBase" - -#include <stdlib.h> -#include <stdint.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/ioctl.h> - -#include <cutils/log.h> -#include <cutils/ashmem.h> -#include <cutils/atomic.h> - -#include <utils/MemoryHeapBase.h> - -#if HAVE_ANDROID_OS -#include <linux/android_pmem.h> -#endif - - -namespace android { - -// --------------------------------------------------------------------------- - -MemoryHeapBase::MemoryHeapBase() - : mFD(-1), mSize(0), mBase(MAP_FAILED), - mDevice(NULL), mNeedUnmap(false) -{ -} - -MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name) - : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), - mDevice(0), mNeedUnmap(false) -{ - const size_t pagesize = getpagesize(); - size = ((size + pagesize-1) & ~(pagesize-1)); - int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size); - LOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno)); - if (fd >= 0) { - if (mapfd(fd, size) == NO_ERROR) { - if (flags & READ_ONLY) { - ashmem_set_prot_region(fd, PROT_READ); - } - } - } -} - -MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags) - : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), - mDevice(0), mNeedUnmap(false) -{ - int fd = open(device, O_RDWR); - LOGE_IF(fd<0, "error opening %s: %s", device, strerror(errno)); - if (fd >= 0) { - const size_t pagesize = getpagesize(); - size = ((size + pagesize-1) & ~(pagesize-1)); - if (mapfd(fd, size) == NO_ERROR) { - mDevice = device; - } - } -} - -MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags) - : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), - mDevice(0), mNeedUnmap(false) -{ - const size_t pagesize = getpagesize(); - size = ((size + pagesize-1) & ~(pagesize-1)); - mapfd(dup(fd), size); -} - -status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device) -{ - if (mFD != -1) { - return INVALID_OPERATION; - } - mFD = fd; - mBase = base; - mSize = size; - mFlags = flags; - mDevice = device; - return NO_ERROR; -} - -status_t MemoryHeapBase::mapfd(int fd, size_t size) -{ - if (size == 0) { - // try to figure out the size automatically -#if HAVE_ANDROID_OS - // first try the PMEM ioctl - pmem_region reg; - int err = ioctl(fd, PMEM_GET_TOTAL_SIZE, ®); - if (err == 0) - size = reg.len; -#endif - if (size == 0) { // try fstat - struct stat sb; - if (fstat(fd, &sb) == 0) - size = sb.st_size; - } - // if it didn't work, let mmap() fail. - } - - if ((mFlags & DONT_MAP_LOCALLY) == 0) { - void* base = (uint8_t*)mmap(0, size, - PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - if (base == MAP_FAILED) { - LOGE("mmap(fd=%d, size=%u) failed (%s)", - fd, uint32_t(size), strerror(errno)); - close(fd); - return -errno; - } - //LOGD("mmap(fd=%d, base=%p, size=%lu)", fd, base, size); - mBase = base; - mNeedUnmap = true; - } else { - mBase = 0; // not MAP_FAILED - mNeedUnmap = false; - } - mFD = fd; - mSize = size; - return NO_ERROR; -} - -MemoryHeapBase::~MemoryHeapBase() -{ - dispose(); -} - -void MemoryHeapBase::dispose() -{ - int fd = android_atomic_or(-1, &mFD); - if (fd >= 0) { - if (mNeedUnmap) { - //LOGD("munmap(fd=%d, base=%p, size=%lu)", fd, mBase, mSize); - munmap(mBase, mSize); - } - mBase = 0; - mSize = 0; - close(fd); - } -} - -int MemoryHeapBase::getHeapID() const { - return mFD; -} - -void* MemoryHeapBase::getBase() const { - return mBase; -} - -size_t MemoryHeapBase::getSize() const { - return mSize; -} - -uint32_t MemoryHeapBase::getFlags() const { - return mFlags; -} - -const char* MemoryHeapBase::getDevice() const { - return mDevice; -} - -// --------------------------------------------------------------------------- -}; // namespace android diff --git a/libs/utils/MemoryHeapPmem.cpp b/libs/utils/MemoryHeapPmem.cpp deleted file mode 100644 index eba2b30..0000000 --- a/libs/utils/MemoryHeapPmem.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "MemoryHeapPmem" - -#include <stdlib.h> -#include <stdint.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/ioctl.h> - -#include <cutils/log.h> - -#include <utils/MemoryHeapPmem.h> -#include <utils/MemoryHeapBase.h> - -#if HAVE_ANDROID_OS -#include <linux/android_pmem.h> -#endif - -namespace android { - -// --------------------------------------------------------------------------- - -MemoryHeapPmem::MemoryPmem::MemoryPmem(const sp<MemoryHeapPmem>& heap) - : BnMemory(), mClientHeap(heap) -{ -} - -MemoryHeapPmem::MemoryPmem::~MemoryPmem() { - if (mClientHeap != NULL) { - mClientHeap->remove(this); - } -} - -// --------------------------------------------------------------------------- - -class SubRegionMemory : public MemoryHeapPmem::MemoryPmem { -public: - SubRegionMemory(const sp<MemoryHeapPmem>& heap, ssize_t offset, size_t size); - virtual ~SubRegionMemory(); - virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const; -private: - friend class MemoryHeapPmem; - void revoke(); - size_t mSize; - ssize_t mOffset; -}; - -SubRegionMemory::SubRegionMemory(const sp<MemoryHeapPmem>& heap, - ssize_t offset, size_t size) - : MemoryHeapPmem::MemoryPmem(heap), mSize(size), mOffset(offset) -{ -#ifndef NDEBUG - void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + offset); - memset(start_ptr, 0xda, size); -#endif - -#if HAVE_ANDROID_OS - if (size > 0) { - const size_t pagesize = getpagesize(); - size = (size + pagesize-1) & ~(pagesize-1); - int our_fd = heap->heapID(); - struct pmem_region sub = { offset, size }; - int err = ioctl(our_fd, PMEM_MAP, &sub); - LOGE_IF(err<0, "PMEM_MAP failed (%s), " - "mFD=%d, sub.offset=%lu, sub.size=%lu", - strerror(errno), our_fd, sub.offset, sub.len); -} -#endif -} - -sp<IMemoryHeap> SubRegionMemory::getMemory(ssize_t* offset, size_t* size) const -{ - if (offset) *offset = mOffset; - if (size) *size = mSize; - return getHeap(); -} - -SubRegionMemory::~SubRegionMemory() -{ - revoke(); -} - - -void SubRegionMemory::revoke() -{ - // NOTE: revoke() doesn't need to be protected by a lock because it - // can only be called from MemoryHeapPmem::revoke(), which means - // that we can't be in ~SubRegionMemory(), or in ~SubRegionMemory(), - // which means MemoryHeapPmem::revoke() wouldn't have been able to - // promote() it. - -#if HAVE_ANDROID_OS - if (mSize != NULL) { - const sp<MemoryHeapPmem>& heap(getHeap()); - int our_fd = heap->heapID(); - struct pmem_region sub; - sub.offset = mOffset; - sub.len = mSize; - int err = ioctl(our_fd, PMEM_UNMAP, &sub); - LOGE_IF(err<0, "PMEM_UNMAP failed (%s), " - "mFD=%d, sub.offset=%lu, sub.size=%lu", - strerror(errno), our_fd, sub.offset, sub.len); - mSize = 0; - } -#endif -} - -// --------------------------------------------------------------------------- - -MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap, - uint32_t flags) - : HeapInterface(), MemoryHeapBase() -{ - char const * const device = pmemHeap->getDevice(); -#if HAVE_ANDROID_OS - if (device) { - int fd = open(device, O_RDWR); - LOGE_IF(fd<0, "couldn't open %s (%s)", device, strerror(errno)); - if (fd >= 0) { - int err = ioctl(fd, PMEM_CONNECT, pmemHeap->heapID()); - if (err < 0) { - LOGE("PMEM_CONNECT failed (%s), mFD=%d, sub-fd=%d", - strerror(errno), fd, pmemHeap->heapID()); - close(fd); - } else { - // everything went well... - mParentHeap = pmemHeap; - MemoryHeapBase::init(fd, - pmemHeap->getBase(), - pmemHeap->getSize(), - pmemHeap->getFlags() | flags, - device); - } - } - } -#else - mParentHeap = pmemHeap; - MemoryHeapBase::init( - dup(pmemHeap->heapID()), - pmemHeap->getBase(), - pmemHeap->getSize(), - pmemHeap->getFlags() | flags, - device); -#endif -} - -MemoryHeapPmem::~MemoryHeapPmem() -{ -} - -sp<IMemory> MemoryHeapPmem::mapMemory(size_t offset, size_t size) -{ - sp<MemoryPmem> memory = createMemory(offset, size); - if (memory != 0) { - Mutex::Autolock _l(mLock); - mAllocations.add(memory); - } - return memory; -} - -sp<MemoryHeapPmem::MemoryPmem> MemoryHeapPmem::createMemory( - size_t offset, size_t size) -{ - sp<SubRegionMemory> memory; - if (heapID() > 0) - memory = new SubRegionMemory(this, offset, size); - return memory; -} - -status_t MemoryHeapPmem::slap() -{ -#if HAVE_ANDROID_OS - size_t size = getSize(); - const size_t pagesize = getpagesize(); - size = (size + pagesize-1) & ~(pagesize-1); - int our_fd = getHeapID(); - struct pmem_region sub = { 0, size }; - int err = ioctl(our_fd, PMEM_MAP, &sub); - LOGE_IF(err<0, "PMEM_MAP failed (%s), " - "mFD=%d, sub.offset=%lu, sub.size=%lu", - strerror(errno), our_fd, sub.offset, sub.len); - return -errno; -#else - return NO_ERROR; -#endif -} - -status_t MemoryHeapPmem::unslap() -{ -#if HAVE_ANDROID_OS - size_t size = getSize(); - const size_t pagesize = getpagesize(); - size = (size + pagesize-1) & ~(pagesize-1); - int our_fd = getHeapID(); - struct pmem_region sub = { 0, size }; - int err = ioctl(our_fd, PMEM_UNMAP, &sub); - LOGE_IF(err<0, "PMEM_UNMAP failed (%s), " - "mFD=%d, sub.offset=%lu, sub.size=%lu", - strerror(errno), our_fd, sub.offset, sub.len); - return -errno; -#else - return NO_ERROR; -#endif -} - -void MemoryHeapPmem::revoke() -{ - SortedVector< wp<MemoryPmem> > allocations; - - { // scope for lock - Mutex::Autolock _l(mLock); - allocations = mAllocations; - } - - ssize_t count = allocations.size(); - for (ssize_t i=0 ; i<count ; i++) { - sp<MemoryPmem> memory(allocations[i].promote()); - if (memory != 0) - memory->revoke(); - } -} - -void MemoryHeapPmem::remove(const wp<MemoryPmem>& memory) -{ - Mutex::Autolock _l(mLock); - mAllocations.remove(memory); -} - -// --------------------------------------------------------------------------- -}; // namespace android diff --git a/libs/utils/NOTICE b/libs/utils/NOTICE deleted file mode 100644 index c5b1efa..0000000 --- a/libs/utils/NOTICE +++ /dev/null @@ -1,190 +0,0 @@ - - Copyright (c) 2005-2008, The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - diff --git a/libs/utils/Parcel.cpp b/libs/utils/Parcel.cpp deleted file mode 100644 index 0f4b647..0000000 --- a/libs/utils/Parcel.cpp +++ /dev/null @@ -1,1377 +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 "Parcel" -//#define LOG_NDEBUG 0 - -#include <utils/Parcel.h> - -#include <utils/Binder.h> -#include <utils/BpBinder.h> -#include <utils/Debug.h> -#include <utils/ProcessState.h> -#include <utils/Log.h> -#include <utils/String8.h> -#include <utils/String16.h> -#include <utils/TextOutput.h> -#include <utils/misc.h> - -#include <private/utils/binder_module.h> - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> - -#ifndef INT32_MAX -#define INT32_MAX ((int32_t)(2147483647)) -#endif - -#define LOG_REFS(...) -//#define LOG_REFS(...) LOG(LOG_DEBUG, "Parcel", __VA_ARGS__) - -// --------------------------------------------------------------------------- - -#define PAD_SIZE(s) (((s)+3)&~3) - -// XXX This can be made public if we want to provide -// support for typed data. -struct small_flat_data -{ - uint32_t type; - uint32_t data; -}; - -namespace android { - -void acquire_object(const sp<ProcessState>& proc, - const flat_binder_object& obj, const void* who) -{ - switch (obj.type) { - case BINDER_TYPE_BINDER: - if (obj.binder) { - LOG_REFS("Parcel %p acquiring reference on local %p", who, obj.cookie); - static_cast<IBinder*>(obj.cookie)->incStrong(who); - } - return; - case BINDER_TYPE_WEAK_BINDER: - if (obj.binder) - static_cast<RefBase::weakref_type*>(obj.binder)->incWeak(who); - return; - case BINDER_TYPE_HANDLE: { - const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle); - if (b != NULL) { - LOG_REFS("Parcel %p acquiring reference on remote %p", who, b.get()); - b->incStrong(who); - } - return; - } - case BINDER_TYPE_WEAK_HANDLE: { - const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle); - if (b != NULL) b.get_refs()->incWeak(who); - return; - } - case BINDER_TYPE_FD: { - // intentionally blank -- nothing to do to acquire this, but we do - // recognize it as a legitimate object type. - return; - } - } - - LOGD("Invalid object type 0x%08lx", obj.type); -} - -void release_object(const sp<ProcessState>& proc, - const flat_binder_object& obj, const void* who) -{ - switch (obj.type) { - case BINDER_TYPE_BINDER: - if (obj.binder) { - LOG_REFS("Parcel %p releasing reference on local %p", who, obj.cookie); - static_cast<IBinder*>(obj.cookie)->decStrong(who); - } - return; - case BINDER_TYPE_WEAK_BINDER: - if (obj.binder) - static_cast<RefBase::weakref_type*>(obj.binder)->decWeak(who); - return; - case BINDER_TYPE_HANDLE: { - const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle); - if (b != NULL) { - LOG_REFS("Parcel %p releasing reference on remote %p", who, b.get()); - b->decStrong(who); - } - return; - } - case BINDER_TYPE_WEAK_HANDLE: { - const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle); - if (b != NULL) b.get_refs()->decWeak(who); - return; - } - case BINDER_TYPE_FD: { - if (obj.cookie != (void*)0) close(obj.handle); - return; - } - } - - LOGE("Invalid object type 0x%08lx", obj.type); -} - -inline static status_t finish_flatten_binder( - const sp<IBinder>& binder, const flat_binder_object& flat, Parcel* out) -{ - return out->writeObject(flat, false); -} - -status_t flatten_binder(const sp<ProcessState>& proc, - const sp<IBinder>& binder, Parcel* out) -{ - flat_binder_object obj; - - obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; - if (binder != NULL) { - IBinder *local = binder->localBinder(); - if (!local) { - BpBinder *proxy = binder->remoteBinder(); - if (proxy == NULL) { - LOGE("null proxy"); - } - const int32_t handle = proxy ? proxy->handle() : 0; - obj.type = BINDER_TYPE_HANDLE; - obj.handle = handle; - obj.cookie = NULL; - } else { - obj.type = BINDER_TYPE_BINDER; - obj.binder = local->getWeakRefs(); - obj.cookie = local; - } - } else { - obj.type = BINDER_TYPE_BINDER; - obj.binder = NULL; - obj.cookie = NULL; - } - - return finish_flatten_binder(binder, obj, out); -} - -status_t flatten_binder(const sp<ProcessState>& proc, - const wp<IBinder>& binder, Parcel* out) -{ - flat_binder_object obj; - - obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; - if (binder != NULL) { - sp<IBinder> real = binder.promote(); - if (real != NULL) { - IBinder *local = real->localBinder(); - if (!local) { - BpBinder *proxy = real->remoteBinder(); - if (proxy == NULL) { - LOGE("null proxy"); - } - const int32_t handle = proxy ? proxy->handle() : 0; - obj.type = BINDER_TYPE_WEAK_HANDLE; - obj.handle = handle; - obj.cookie = NULL; - } else { - obj.type = BINDER_TYPE_WEAK_BINDER; - obj.binder = binder.get_refs(); - obj.cookie = binder.unsafe_get(); - } - return finish_flatten_binder(real, obj, out); - } - - // XXX How to deal? In order to flatten the given binder, - // we need to probe it for information, which requires a primary - // reference... but we don't have one. - // - // The OpenBinder implementation uses a dynamic_cast<> here, - // but we can't do that with the different reference counting - // implementation we are using. - LOGE("Unable to unflatten Binder weak reference!"); - obj.type = BINDER_TYPE_BINDER; - obj.binder = NULL; - obj.cookie = NULL; - return finish_flatten_binder(NULL, obj, out); - - } else { - obj.type = BINDER_TYPE_BINDER; - obj.binder = NULL; - obj.cookie = NULL; - return finish_flatten_binder(NULL, obj, out); - } -} - -inline static status_t finish_unflatten_binder( - BpBinder* proxy, const flat_binder_object& flat, const Parcel& in) -{ - return NO_ERROR; -} - -status_t unflatten_binder(const sp<ProcessState>& proc, - const Parcel& in, sp<IBinder>* out) -{ - const flat_binder_object* flat = in.readObject(false); - - if (flat) { - switch (flat->type) { - case BINDER_TYPE_BINDER: - *out = static_cast<IBinder*>(flat->cookie); - return finish_unflatten_binder(NULL, *flat, in); - case BINDER_TYPE_HANDLE: - *out = proc->getStrongProxyForHandle(flat->handle); - return finish_unflatten_binder( - static_cast<BpBinder*>(out->get()), *flat, in); - } - } - return BAD_TYPE; -} - -status_t unflatten_binder(const sp<ProcessState>& proc, - const Parcel& in, wp<IBinder>* out) -{ - const flat_binder_object* flat = in.readObject(false); - - if (flat) { - switch (flat->type) { - case BINDER_TYPE_BINDER: - *out = static_cast<IBinder*>(flat->cookie); - return finish_unflatten_binder(NULL, *flat, in); - case BINDER_TYPE_WEAK_BINDER: - if (flat->binder != NULL) { - out->set_object_and_refs( - static_cast<IBinder*>(flat->cookie), - static_cast<RefBase::weakref_type*>(flat->binder)); - } else { - *out = NULL; - } - return finish_unflatten_binder(NULL, *flat, in); - case BINDER_TYPE_HANDLE: - case BINDER_TYPE_WEAK_HANDLE: - *out = proc->getWeakProxyForHandle(flat->handle); - return finish_unflatten_binder( - static_cast<BpBinder*>(out->unsafe_get()), *flat, in); - } - } - return BAD_TYPE; -} - -// --------------------------------------------------------------------------- - -Parcel::Parcel() -{ - initState(); -} - -Parcel::~Parcel() -{ - freeDataNoInit(); -} - -const uint8_t* Parcel::data() const -{ - return mData; -} - -size_t Parcel::dataSize() const -{ - return (mDataSize > mDataPos ? mDataSize : mDataPos); -} - -size_t Parcel::dataAvail() const -{ - // TODO: decide what to do about the possibility that this can - // report an available-data size that exceeds a Java int's max - // positive value, causing havoc. Fortunately this will only - // happen if someone constructs a Parcel containing more than two - // gigabytes of data, which on typical phone hardware is simply - // not possible. - return dataSize() - dataPosition(); -} - -size_t Parcel::dataPosition() const -{ - return mDataPos; -} - -size_t Parcel::dataCapacity() const -{ - return mDataCapacity; -} - -status_t Parcel::setDataSize(size_t size) -{ - status_t err; - err = continueWrite(size); - if (err == NO_ERROR) { - mDataSize = size; - LOGV("setDataSize Setting data size of %p to %d\n", this, mDataSize); - } - return err; -} - -void Parcel::setDataPosition(size_t pos) const -{ - mDataPos = pos; - mNextObjectHint = 0; -} - -status_t Parcel::setDataCapacity(size_t size) -{ - if (size > mDataSize) return continueWrite(size); - return NO_ERROR; -} - -status_t Parcel::setData(const uint8_t* buffer, size_t len) -{ - status_t err = restartWrite(len); - if (err == NO_ERROR) { - memcpy(const_cast<uint8_t*>(data()), buffer, len); - mDataSize = len; - mFdsKnown = false; - } - return err; -} - -status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len) -{ - const sp<ProcessState> proc(ProcessState::self()); - status_t err; - uint8_t *data = parcel->mData; - size_t *objects = parcel->mObjects; - size_t size = parcel->mObjectsSize; - int startPos = mDataPos; - int firstIndex = -1, lastIndex = -2; - - if (len == 0) { - return NO_ERROR; - } - - // range checks against the source parcel size - if ((offset > parcel->mDataSize) - || (len > parcel->mDataSize) - || (offset + len > parcel->mDataSize)) { - return BAD_VALUE; - } - - // Count objects in range - for (int i = 0; i < (int) size; i++) { - size_t off = objects[i]; - if ((off >= offset) && (off < offset + len)) { - if (firstIndex == -1) { - firstIndex = i; - } - lastIndex = i; - } - } - int numObjects = lastIndex - firstIndex + 1; - - // grow data - err = growData(len); - if (err != NO_ERROR) { - return err; - } - - // append data - memcpy(mData + mDataPos, data + offset, len); - mDataPos += len; - mDataSize += len; - - if (numObjects > 0) { - // grow objects - if (mObjectsCapacity < mObjectsSize + numObjects) { - int newSize = ((mObjectsSize + numObjects)*3)/2; - size_t *objects = - (size_t*)realloc(mObjects, newSize*sizeof(size_t)); - if (objects == (size_t*)0) { - return NO_MEMORY; - } - mObjects = objects; - mObjectsCapacity = newSize; - } - - // append and acquire objects - int idx = mObjectsSize; - for (int i = firstIndex; i <= lastIndex; i++) { - size_t off = objects[i] - offset + startPos; - mObjects[idx++] = off; - mObjectsSize++; - - const flat_binder_object* flat - = reinterpret_cast<flat_binder_object*>(mData + off); - acquire_object(proc, *flat, this); - - // take note if the object is a file descriptor - if (flat->type == BINDER_TYPE_FD) { - mHasFds = mFdsKnown = true; - } - } - } - - return NO_ERROR; -} - -bool Parcel::hasFileDescriptors() const -{ - if (!mFdsKnown) { - scanForFds(); - } - return mHasFds; -} - -status_t Parcel::writeInterfaceToken(const String16& interface) -{ - // currently the interface identification token is just its name as a string - return writeString16(interface); -} - -bool Parcel::enforceInterface(const String16& interface) const -{ - String16 str = readString16(); - if (str == interface) { - return true; - } else { - LOGW("**** enforceInterface() expected '%s' but read '%s'\n", - String8(interface).string(), String8(str).string()); - return false; - } -} - -const size_t* Parcel::objects() const -{ - return mObjects; -} - -size_t Parcel::objectsCount() const -{ - return mObjectsSize; -} - -status_t Parcel::errorCheck() const -{ - return mError; -} - -void Parcel::setError(status_t err) -{ - mError = err; -} - -status_t Parcel::finishWrite(size_t len) -{ - //printf("Finish write of %d\n", len); - mDataPos += len; - LOGV("finishWrite Setting data pos of %p to %d\n", this, mDataPos); - if (mDataPos > mDataSize) { - mDataSize = mDataPos; - LOGV("finishWrite Setting data size of %p to %d\n", this, mDataSize); - } - //printf("New pos=%d, size=%d\n", mDataPos, mDataSize); - return NO_ERROR; -} - -status_t Parcel::writeUnpadded(const void* data, size_t len) -{ - size_t end = mDataPos + len; - if (end < mDataPos) { - // integer overflow - return BAD_VALUE; - } - - if (end <= mDataCapacity) { -restart_write: - memcpy(mData+mDataPos, data, len); - return finishWrite(len); - } - - status_t err = growData(len); - if (err == NO_ERROR) goto restart_write; - return err; -} - -status_t Parcel::write(const void* data, size_t len) -{ - void* const d = writeInplace(len); - if (d) { - memcpy(d, data, len); - return NO_ERROR; - } - return mError; -} - -void* Parcel::writeInplace(size_t len) -{ - const size_t padded = PAD_SIZE(len); - - // sanity check for integer overflow - if (mDataPos+padded < mDataPos) { - return NULL; - } - - if ((mDataPos+padded) <= mDataCapacity) { -restart_write: - //printf("Writing %ld bytes, padded to %ld\n", len, padded); - uint8_t* const data = mData+mDataPos; - - // Need to pad at end? - if (padded != len) { -#if BYTE_ORDER == BIG_ENDIAN - static const uint32_t mask[4] = { - 0x00000000, 0xffffff00, 0xffff0000, 0xff000000 - }; -#endif -#if BYTE_ORDER == LITTLE_ENDIAN - static const uint32_t mask[4] = { - 0x00000000, 0x00ffffff, 0x0000ffff, 0x000000ff - }; -#endif - //printf("Applying pad mask: %p to %p\n", (void*)mask[padded-len], - // *reinterpret_cast<void**>(data+padded-4)); - *reinterpret_cast<uint32_t*>(data+padded-4) &= mask[padded-len]; - } - - finishWrite(padded); - return data; - } - - status_t err = growData(padded); - if (err == NO_ERROR) goto restart_write; - return NULL; -} - -status_t Parcel::writeInt32(int32_t val) -{ - if ((mDataPos+sizeof(val)) <= mDataCapacity) { -restart_write: - *reinterpret_cast<int32_t*>(mData+mDataPos) = val; - return finishWrite(sizeof(val)); - } - - status_t err = growData(sizeof(val)); - if (err == NO_ERROR) goto restart_write; - return err; -} - -status_t Parcel::writeInt64(int64_t val) -{ - if ((mDataPos+sizeof(val)) <= mDataCapacity) { -restart_write: - *reinterpret_cast<int64_t*>(mData+mDataPos) = val; - return finishWrite(sizeof(val)); - } - - status_t err = growData(sizeof(val)); - if (err == NO_ERROR) goto restart_write; - return err; -} - -status_t Parcel::writeFloat(float val) -{ - if ((mDataPos+sizeof(val)) <= mDataCapacity) { -restart_write: - *reinterpret_cast<float*>(mData+mDataPos) = val; - return finishWrite(sizeof(val)); - } - - status_t err = growData(sizeof(val)); - if (err == NO_ERROR) goto restart_write; - return err; -} - -status_t Parcel::writeDouble(double val) -{ - if ((mDataPos+sizeof(val)) <= mDataCapacity) { -restart_write: - *reinterpret_cast<double*>(mData+mDataPos) = val; - return finishWrite(sizeof(val)); - } - - status_t err = growData(sizeof(val)); - if (err == NO_ERROR) goto restart_write; - return err; -} - -status_t Parcel::writeCString(const char* str) -{ - return write(str, strlen(str)+1); -} - -status_t Parcel::writeString8(const String8& str) -{ - status_t err = writeInt32(str.bytes()); - if (err == NO_ERROR) { - err = write(str.string(), str.bytes()+1); - } - return err; -} - -status_t Parcel::writeString16(const String16& str) -{ - return writeString16(str.string(), str.size()); -} - -status_t Parcel::writeString16(const char16_t* str, size_t len) -{ - if (str == NULL) return writeInt32(-1); - - status_t err = writeInt32(len); - if (err == NO_ERROR) { - len *= sizeof(char16_t); - uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t)); - if (data) { - memcpy(data, str, len); - *reinterpret_cast<char16_t*>(data+len) = 0; - return NO_ERROR; - } - err = mError; - } - return err; -} - -status_t Parcel::writeStrongBinder(const sp<IBinder>& val) -{ - return flatten_binder(ProcessState::self(), val, this); -} - -status_t Parcel::writeWeakBinder(const wp<IBinder>& val) -{ - return flatten_binder(ProcessState::self(), val, this); -} - -status_t Parcel::writeNativeHandle(const native_handle& handle) -{ - if (handle.version != sizeof(native_handle)) - return BAD_TYPE; - - status_t err; - err = writeInt32(handle.numFds); - if (err != NO_ERROR) return err; - - err = writeInt32(handle.numInts); - if (err != NO_ERROR) return err; - - for (int i=0 ; err==NO_ERROR && i<handle.numFds ; i++) - err = writeDupFileDescriptor(handle.data[i]); - - if (err != NO_ERROR) { - LOGD("write native handle, write dup fd failed"); - return err; - } - - err = write(handle.data + handle.numFds, sizeof(int)*handle.numInts); - - return err; -} - -status_t Parcel::writeFileDescriptor(int fd) -{ - flat_binder_object obj; - obj.type = BINDER_TYPE_FD; - obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; - obj.handle = fd; - obj.cookie = (void*)0; - return writeObject(obj, true); -} - -status_t Parcel::writeDupFileDescriptor(int fd) -{ - flat_binder_object obj; - obj.type = BINDER_TYPE_FD; - obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; - obj.handle = dup(fd); - obj.cookie = (void*)1; - return writeObject(obj, true); -} - -status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData) -{ - const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity; - const bool enoughObjects = mObjectsSize < mObjectsCapacity; - if (enoughData && enoughObjects) { -restart_write: - *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val; - - // Need to write meta-data? - if (nullMetaData || val.binder != NULL) { - mObjects[mObjectsSize] = mDataPos; - acquire_object(ProcessState::self(), val, this); - mObjectsSize++; - } - - // remember if it's a file descriptor - if (val.type == BINDER_TYPE_FD) { - mHasFds = mFdsKnown = true; - } - - return finishWrite(sizeof(flat_binder_object)); - } - - if (!enoughData) { - const status_t err = growData(sizeof(val)); - if (err != NO_ERROR) return err; - } - if (!enoughObjects) { - size_t newSize = ((mObjectsSize+2)*3)/2; - size_t* objects = (size_t*)realloc(mObjects, newSize*sizeof(size_t)); - if (objects == NULL) return NO_MEMORY; - mObjects = objects; - mObjectsCapacity = newSize; - } - - goto restart_write; -} - - -void Parcel::remove(size_t start, size_t amt) -{ - LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!"); -} - -status_t Parcel::read(void* outData, size_t len) const -{ - if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) { - memcpy(outData, mData+mDataPos, len); - mDataPos += PAD_SIZE(len); - LOGV("read Setting data pos of %p to %d\n", this, mDataPos); - return NO_ERROR; - } - return NOT_ENOUGH_DATA; -} - -const void* Parcel::readInplace(size_t len) const -{ - if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) { - const void* data = mData+mDataPos; - mDataPos += PAD_SIZE(len); - LOGV("readInplace Setting data pos of %p to %d\n", this, mDataPos); - return data; - } - return NULL; -} - -status_t Parcel::readInt32(int32_t *pArg) const -{ - if ((mDataPos+sizeof(int32_t)) <= mDataSize) { - const void* data = mData+mDataPos; - mDataPos += sizeof(int32_t); - *pArg = *reinterpret_cast<const int32_t*>(data); - return NO_ERROR; - } else { - return NOT_ENOUGH_DATA; - } -} - -int32_t Parcel::readInt32() const -{ - if ((mDataPos+sizeof(int32_t)) <= mDataSize) { - const void* data = mData+mDataPos; - mDataPos += sizeof(int32_t); - LOGV("readInt32 Setting data pos of %p to %d\n", this, mDataPos); - return *reinterpret_cast<const int32_t*>(data); - } - return 0; -} - - -status_t Parcel::readInt64(int64_t *pArg) const -{ - if ((mDataPos+sizeof(int64_t)) <= mDataSize) { - const void* data = mData+mDataPos; - mDataPos += sizeof(int64_t); - *pArg = *reinterpret_cast<const int64_t*>(data); - LOGV("readInt64 Setting data pos of %p to %d\n", this, mDataPos); - return NO_ERROR; - } else { - return NOT_ENOUGH_DATA; - } -} - - -int64_t Parcel::readInt64() const -{ - if ((mDataPos+sizeof(int64_t)) <= mDataSize) { - const void* data = mData+mDataPos; - mDataPos += sizeof(int64_t); - LOGV("readInt64 Setting data pos of %p to %d\n", this, mDataPos); - return *reinterpret_cast<const int64_t*>(data); - } - return 0; -} - -status_t Parcel::readFloat(float *pArg) const -{ - if ((mDataPos+sizeof(float)) <= mDataSize) { - const void* data = mData+mDataPos; - mDataPos += sizeof(float); - LOGV("readFloat Setting data pos of %p to %d\n", this, mDataPos); - *pArg = *reinterpret_cast<const float*>(data); - return NO_ERROR; - } else { - return NOT_ENOUGH_DATA; - } -} - - -float Parcel::readFloat() const -{ - if ((mDataPos+sizeof(float)) <= mDataSize) { - const void* data = mData+mDataPos; - mDataPos += sizeof(float); - LOGV("readFloat Setting data pos of %p to %d\n", this, mDataPos); - return *reinterpret_cast<const float*>(data); - } - return 0; -} - -status_t Parcel::readDouble(double *pArg) const -{ - if ((mDataPos+sizeof(double)) <= mDataSize) { - const void* data = mData+mDataPos; - mDataPos += sizeof(double); - LOGV("readDouble Setting data pos of %p to %d\n", this, mDataPos); - *pArg = *reinterpret_cast<const double*>(data); - return NO_ERROR; - } else { - return NOT_ENOUGH_DATA; - } -} - - -double Parcel::readDouble() const -{ - if ((mDataPos+sizeof(double)) <= mDataSize) { - const void* data = mData+mDataPos; - mDataPos += sizeof(double); - LOGV("readDouble Setting data pos of %p to %d\n", this, mDataPos); - return *reinterpret_cast<const double*>(data); - } - return 0; -} - - -const char* Parcel::readCString() const -{ - const size_t avail = mDataSize-mDataPos; - if (avail > 0) { - const char* str = reinterpret_cast<const char*>(mData+mDataPos); - // is the string's trailing NUL within the parcel's valid bounds? - const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail)); - if (eos) { - const size_t len = eos - str; - mDataPos += PAD_SIZE(len+1); - LOGV("readCString Setting data pos of %p to %d\n", this, mDataPos); - return str; - } - } - return NULL; -} - -String8 Parcel::readString8() const -{ - int32_t size = readInt32(); - // watch for potential int overflow adding 1 for trailing NUL - if (size > 0 && size < INT32_MAX) { - const char* str = (const char*)readInplace(size+1); - if (str) return String8(str, size); - } - return String8(); -} - -String16 Parcel::readString16() const -{ - size_t len; - const char16_t* str = readString16Inplace(&len); - if (str) return String16(str, len); - LOGE("Reading a NULL string not supported here."); - return String16(); -} - -const char16_t* Parcel::readString16Inplace(size_t* outLen) const -{ - int32_t size = readInt32(); - // watch for potential int overflow from size+1 - if (size >= 0 && size < INT32_MAX) { - *outLen = size; - const char16_t* str = (const char16_t*)readInplace((size+1)*sizeof(char16_t)); - if (str != NULL) { - return str; - } - } - *outLen = 0; - return NULL; -} - -sp<IBinder> Parcel::readStrongBinder() const -{ - sp<IBinder> val; - unflatten_binder(ProcessState::self(), *this, &val); - return val; -} - -wp<IBinder> Parcel::readWeakBinder() const -{ - wp<IBinder> val; - unflatten_binder(ProcessState::self(), *this, &val); - return val; -} - - -native_handle* Parcel::readNativeHandle(native_handle* (*alloc)(void*, int, int), void* cookie) const -{ - int numFds, numInts; - status_t err; - err = readInt32(&numFds); - if (err != NO_ERROR) return 0; - err = readInt32(&numInts); - if (err != NO_ERROR) return 0; - - native_handle* h; - if (alloc == 0) { - size_t size = sizeof(native_handle) + sizeof(int)*(numFds + numInts); - h = (native_handle*)malloc(size); - h->version = sizeof(native_handle); - h->numFds = numFds; - h->numInts = numInts; - } else { - h = alloc(cookie, numFds, numInts); - if (h->version != sizeof(native_handle)) { - return 0; - } - } - - for (int i=0 ; err==NO_ERROR && i<numFds ; i++) { - h->data[i] = dup(readFileDescriptor()); - if (h->data[i] < 0) err = BAD_VALUE; - } - - err = read(h->data + numFds, sizeof(int)*numInts); - - if (err != NO_ERROR) { - if (alloc == 0) { - free(h); - } - h = 0; - } - return h; -} - - -int Parcel::readFileDescriptor() const -{ - const flat_binder_object* flat = readObject(true); - if (flat) { - switch (flat->type) { - case BINDER_TYPE_FD: - //LOGI("Returning file descriptor %ld from parcel %p\n", flat->handle, this); - return flat->handle; - } - } - return BAD_TYPE; -} - -const flat_binder_object* Parcel::readObject(bool nullMetaData) const -{ - const size_t DPOS = mDataPos; - if ((DPOS+sizeof(flat_binder_object)) <= mDataSize) { - const flat_binder_object* obj - = reinterpret_cast<const flat_binder_object*>(mData+DPOS); - mDataPos = DPOS + sizeof(flat_binder_object); - if (!nullMetaData && (obj->cookie == NULL && obj->binder == NULL)) { - // When transferring a NULL object, we don't write it into - // the object list, so we don't want to check for it when - // reading. - LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos); - return obj; - } - - // Ensure that this object is valid... - size_t* const OBJS = mObjects; - const size_t N = mObjectsSize; - size_t opos = mNextObjectHint; - - if (N > 0) { - LOGV("Parcel %p looking for obj at %d, hint=%d\n", - this, DPOS, opos); - - // Start at the current hint position, looking for an object at - // the current data position. - if (opos < N) { - while (opos < (N-1) && OBJS[opos] < DPOS) { - opos++; - } - } else { - opos = N-1; - } - if (OBJS[opos] == DPOS) { - // Found it! - LOGV("Parcel found obj %d at index %d with forward search", - this, DPOS, opos); - mNextObjectHint = opos+1; - LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos); - return obj; - } - - // Look backwards for it... - while (opos > 0 && OBJS[opos] > DPOS) { - opos--; - } - if (OBJS[opos] == DPOS) { - // Found it! - LOGV("Parcel found obj %d at index %d with backward search", - this, DPOS, opos); - mNextObjectHint = opos+1; - LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos); - return obj; - } - } - LOGW("Attempt to read object from Parcel %p at offset %d that is not in the object list", - this, DPOS); - } - return NULL; -} - -void Parcel::closeFileDescriptors() -{ - size_t i = mObjectsSize; - if (i > 0) { - //LOGI("Closing file descriptors for %d objects...", mObjectsSize); - } - while (i > 0) { - i--; - const flat_binder_object* flat - = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]); - if (flat->type == BINDER_TYPE_FD) { - //LOGI("Closing fd: %ld\n", flat->handle); - close(flat->handle); - } - } -} - -const uint8_t* Parcel::ipcData() const -{ - return mData; -} - -size_t Parcel::ipcDataSize() const -{ - return (mDataSize > mDataPos ? mDataSize : mDataPos); -} - -const size_t* Parcel::ipcObjects() const -{ - return mObjects; -} - -size_t Parcel::ipcObjectsCount() const -{ - return mObjectsSize; -} - -void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, - const size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie) -{ - freeDataNoInit(); - mError = NO_ERROR; - mData = const_cast<uint8_t*>(data); - mDataSize = mDataCapacity = dataSize; - //LOGI("setDataReference Setting data size of %p to %lu (pid=%d)\n", this, mDataSize, getpid()); - mDataPos = 0; - LOGV("setDataReference Setting data pos of %p to %d\n", this, mDataPos); - mObjects = const_cast<size_t*>(objects); - mObjectsSize = mObjectsCapacity = objectsCount; - mNextObjectHint = 0; - mOwner = relFunc; - mOwnerCookie = relCookie; - scanForFds(); -} - -void Parcel::print(TextOutput& to, uint32_t flags) const -{ - to << "Parcel("; - - if (errorCheck() != NO_ERROR) { - const status_t err = errorCheck(); - to << "Error: " << (void*)err << " \"" << strerror(-err) << "\""; - } else if (dataSize() > 0) { - const uint8_t* DATA = data(); - to << indent << HexDump(DATA, dataSize()) << dedent; - const size_t* OBJS = objects(); - const size_t N = objectsCount(); - for (size_t i=0; i<N; i++) { - const flat_binder_object* flat - = reinterpret_cast<const flat_binder_object*>(DATA+OBJS[i]); - to << endl << "Object #" << i << " @ " << (void*)OBJS[i] << ": " - << TypeCode(flat->type & 0x7f7f7f00) - << " = " << flat->binder; - } - } else { - to << "NULL"; - } - - to << ")"; -} - -void Parcel::releaseObjects() -{ - const sp<ProcessState> proc(ProcessState::self()); - size_t i = mObjectsSize; - uint8_t* const data = mData; - size_t* const objects = mObjects; - while (i > 0) { - i--; - const flat_binder_object* flat - = reinterpret_cast<flat_binder_object*>(data+objects[i]); - release_object(proc, *flat, this); - } -} - -void Parcel::acquireObjects() -{ - const sp<ProcessState> proc(ProcessState::self()); - size_t i = mObjectsSize; - uint8_t* const data = mData; - size_t* const objects = mObjects; - while (i > 0) { - i--; - const flat_binder_object* flat - = reinterpret_cast<flat_binder_object*>(data+objects[i]); - acquire_object(proc, *flat, this); - } -} - -void Parcel::freeData() -{ - freeDataNoInit(); - initState(); -} - -void Parcel::freeDataNoInit() -{ - if (mOwner) { - //LOGI("Freeing data ref of %p (pid=%d)\n", this, getpid()); - mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie); - } else { - releaseObjects(); - if (mData) free(mData); - if (mObjects) free(mObjects); - } -} - -status_t Parcel::growData(size_t len) -{ - size_t newSize = ((mDataSize+len)*3)/2; - return (newSize <= mDataSize) - ? (status_t) NO_MEMORY - : continueWrite(newSize); -} - -status_t Parcel::restartWrite(size_t desired) -{ - if (mOwner) { - freeData(); - return continueWrite(desired); - } - - uint8_t* data = (uint8_t*)realloc(mData, desired); - if (!data && desired > mDataCapacity) { - mError = NO_MEMORY; - return NO_MEMORY; - } - - releaseObjects(); - - if (data) { - mData = data; - mDataCapacity = desired; - } - - mDataSize = mDataPos = 0; - LOGV("restartWrite Setting data size of %p to %d\n", this, mDataSize); - LOGV("restartWrite Setting data pos of %p to %d\n", this, mDataPos); - - free(mObjects); - mObjects = NULL; - mObjectsSize = mObjectsCapacity = 0; - mNextObjectHint = 0; - mHasFds = false; - mFdsKnown = true; - - return NO_ERROR; -} - -status_t Parcel::continueWrite(size_t desired) -{ - // If shrinking, first adjust for any objects that appear - // after the new data size. - size_t objectsSize = mObjectsSize; - if (desired < mDataSize) { - if (desired == 0) { - objectsSize = 0; - } else { - while (objectsSize > 0) { - if (mObjects[objectsSize-1] < desired) - break; - objectsSize--; - } - } - } - - if (mOwner) { - // If the size is going to zero, just release the owner's data. - if (desired == 0) { - freeData(); - return NO_ERROR; - } - - // If there is a different owner, we need to take - // posession. - uint8_t* data = (uint8_t*)malloc(desired); - if (!data) { - mError = NO_MEMORY; - return NO_MEMORY; - } - size_t* objects = NULL; - - if (objectsSize) { - objects = (size_t*)malloc(objectsSize*sizeof(size_t)); - if (!objects) { - mError = NO_MEMORY; - return NO_MEMORY; - } - - // Little hack to only acquire references on objects - // we will be keeping. - size_t oldObjectsSize = mObjectsSize; - mObjectsSize = objectsSize; - acquireObjects(); - mObjectsSize = oldObjectsSize; - } - - if (mData) { - memcpy(data, mData, mDataSize < desired ? mDataSize : desired); - } - if (objects && mObjects) { - memcpy(objects, mObjects, objectsSize*sizeof(size_t)); - } - //LOGI("Freeing data ref of %p (pid=%d)\n", this, getpid()); - mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie); - mOwner = NULL; - - mData = data; - mObjects = objects; - mDataSize = (mDataSize < desired) ? mDataSize : desired; - LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize); - mDataCapacity = desired; - mObjectsSize = mObjectsCapacity = objectsSize; - mNextObjectHint = 0; - - } else if (mData) { - if (objectsSize < mObjectsSize) { - // Need to release refs on any objects we are dropping. - const sp<ProcessState> proc(ProcessState::self()); - for (size_t i=objectsSize; i<mObjectsSize; i++) { - const flat_binder_object* flat - = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]); - if (flat->type == BINDER_TYPE_FD) { - // will need to rescan because we may have lopped off the only FDs - mFdsKnown = false; - } - release_object(proc, *flat, this); - } - size_t* objects = - (size_t*)realloc(mObjects, objectsSize*sizeof(size_t)); - if (objects) { - mObjects = objects; - } - mObjectsSize = objectsSize; - mNextObjectHint = 0; - } - - // We own the data, so we can just do a realloc(). - if (desired > mDataCapacity) { - uint8_t* data = (uint8_t*)realloc(mData, desired); - if (data) { - mData = data; - mDataCapacity = desired; - } else if (desired > mDataCapacity) { - mError = NO_MEMORY; - return NO_MEMORY; - } - } else { - mDataSize = desired; - LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize); - if (mDataPos > desired) { - mDataPos = desired; - LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos); - } - } - - } else { - // This is the first data. Easy! - uint8_t* data = (uint8_t*)malloc(desired); - if (!data) { - mError = NO_MEMORY; - return NO_MEMORY; - } - - if(!(mDataCapacity == 0 && mObjects == NULL - && mObjectsCapacity == 0)) { - LOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired); - } - - mData = data; - mDataSize = mDataPos = 0; - LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize); - LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos); - mDataCapacity = desired; - } - - return NO_ERROR; -} - -void Parcel::initState() -{ - mError = NO_ERROR; - mData = 0; - mDataSize = 0; - mDataCapacity = 0; - mDataPos = 0; - LOGV("initState Setting data size of %p to %d\n", this, mDataSize); - LOGV("initState Setting data pos of %p to %d\n", this, mDataPos); - mObjects = NULL; - mObjectsSize = 0; - mObjectsCapacity = 0; - mNextObjectHint = 0; - mHasFds = false; - mFdsKnown = true; - mOwner = NULL; -} - -void Parcel::scanForFds() const -{ - bool hasFds = false; - for (size_t i=0; i<mObjectsSize; i++) { - const flat_binder_object* flat - = reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]); - if (flat->type == BINDER_TYPE_FD) { - hasFds = true; - break; - } - } - mHasFds = hasFds; - mFdsKnown = true; -} - -}; // namespace android diff --git a/libs/utils/Pipe.cpp b/libs/utils/Pipe.cpp deleted file mode 100644 index 613906b..0000000 --- a/libs/utils/Pipe.cpp +++ /dev/null @@ -1,465 +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. - */ - -// -// Unidirectional pipe. -// - -#include <utils/Pipe.h> -#include <utils/Log.h> - -#if defined(HAVE_WIN32_IPC) -# include <windows.h> -#else -# include <fcntl.h> -# include <unistd.h> -# include <errno.h> -#endif - -#include <stdlib.h> -#include <stdio.h> -#include <assert.h> -#include <string.h> - -using namespace android; - -const unsigned long kInvalidHandle = (unsigned long) -1; - - -/* - * Constructor. Do little. - */ -Pipe::Pipe(void) - : mReadNonBlocking(false), mReadHandle(kInvalidHandle), - mWriteHandle(kInvalidHandle) -{ -} - -/* - * Destructor. Use the system-appropriate close call. - */ -Pipe::~Pipe(void) -{ -#if defined(HAVE_WIN32_IPC) - if (mReadHandle != kInvalidHandle) { - if (!CloseHandle((HANDLE)mReadHandle)) - LOG(LOG_WARN, "pipe", "failed closing read handle (%ld)\n", - mReadHandle); - } - if (mWriteHandle != kInvalidHandle) { - FlushFileBuffers((HANDLE)mWriteHandle); - if (!CloseHandle((HANDLE)mWriteHandle)) - LOG(LOG_WARN, "pipe", "failed closing write handle (%ld)\n", - mWriteHandle); - } -#else - if (mReadHandle != kInvalidHandle) { - if (close((int) mReadHandle) != 0) - LOG(LOG_WARN, "pipe", "failed closing read fd (%d)\n", - (int) mReadHandle); - } - if (mWriteHandle != kInvalidHandle) { - if (close((int) mWriteHandle) != 0) - LOG(LOG_WARN, "pipe", "failed closing write fd (%d)\n", - (int) mWriteHandle); - } -#endif -} - -/* - * Create the pipe. - * - * Use the POSIX stuff for everything but Windows. - */ -bool Pipe::create(void) -{ - assert(mReadHandle == kInvalidHandle); - assert(mWriteHandle == kInvalidHandle); - -#if defined(HAVE_WIN32_IPC) - /* we use this across processes, so they need to be inheritable */ - HANDLE handles[2]; - SECURITY_ATTRIBUTES saAttr; - - saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); - saAttr.bInheritHandle = TRUE; - saAttr.lpSecurityDescriptor = NULL; - - if (!CreatePipe(&handles[0], &handles[1], &saAttr, 0)) { - LOG(LOG_ERROR, "pipe", "unable to create pipe\n"); - return false; - } - mReadHandle = (unsigned long) handles[0]; - mWriteHandle = (unsigned long) handles[1]; - return true; -#else - int fds[2]; - - if (pipe(fds) != 0) { - LOG(LOG_ERROR, "pipe", "unable to create pipe\n"); - return false; - } - mReadHandle = fds[0]; - mWriteHandle = fds[1]; - return true; -#endif -} - -/* - * Create a "half pipe". Please, no Segway riding. - */ -bool Pipe::createReader(unsigned long handle) -{ - mReadHandle = handle; - assert(mWriteHandle == kInvalidHandle); - return true; -} - -/* - * Create a "half pipe" for writing. - */ -bool Pipe::createWriter(unsigned long handle) -{ - mWriteHandle = handle; - assert(mReadHandle == kInvalidHandle); - return true; -} - -/* - * Return "true" if create() has been called successfully. - */ -bool Pipe::isCreated(void) -{ - // one or the other should be open - return (mReadHandle != kInvalidHandle || mWriteHandle != kInvalidHandle); -} - - -/* - * Read data from the pipe. - * - * For Linux and Darwin, just call read(). For Windows, implement - * non-blocking reads by calling PeekNamedPipe first. - */ -int Pipe::read(void* buf, int count) -{ - assert(mReadHandle != kInvalidHandle); - -#if defined(HAVE_WIN32_IPC) - DWORD totalBytesAvail = count; - DWORD bytesRead; - - if (mReadNonBlocking) { - // use PeekNamedPipe to adjust read count expectations - if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL, - &totalBytesAvail, NULL)) - { - LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n"); - return -1; - } - - if (totalBytesAvail == 0) - return 0; - } - - if (!ReadFile((HANDLE) mReadHandle, buf, totalBytesAvail, &bytesRead, - NULL)) - { - DWORD err = GetLastError(); - if (err == ERROR_HANDLE_EOF || err == ERROR_BROKEN_PIPE) - return 0; - LOG(LOG_ERROR, "pipe", "ReadFile failed (err=%ld)\n", err); - return -1; - } - - return (int) bytesRead; -#else - int cc; - cc = ::read(mReadHandle, buf, count); - if (cc < 0 && errno == EAGAIN) - return 0; - return cc; -#endif -} - -/* - * Write data to the pipe. - * - * POSIX systems are trivial, Windows uses a different call and doesn't - * handle non-blocking writes. - * - * If we add non-blocking support here, we probably want to make it an - * all-or-nothing write. - * - * DO NOT use LOG() here, we could be writing a log message. - */ -int Pipe::write(const void* buf, int count) -{ - assert(mWriteHandle != kInvalidHandle); - -#if defined(HAVE_WIN32_IPC) - DWORD bytesWritten; - - if (mWriteNonBlocking) { - // BUG: can't use PeekNamedPipe() to get the amount of space - // left. Looks like we need to use "overlapped I/O" functions. - // I just don't care that much. - } - - if (!WriteFile((HANDLE) mWriteHandle, buf, count, &bytesWritten, NULL)) { - // can't LOG, use stderr - fprintf(stderr, "WriteFile failed (err=%ld)\n", GetLastError()); - return -1; - } - - return (int) bytesWritten; -#else - int cc; - cc = ::write(mWriteHandle, buf, count); - if (cc < 0 && errno == EAGAIN) - return 0; - return cc; -#endif -} - -/* - * Figure out if there is data available on the read fd. - * - * We return "true" on error because we want the caller to try to read - * from the pipe. They'll notice the read failure and do something - * appropriate. - */ -bool Pipe::readReady(void) -{ - assert(mReadHandle != kInvalidHandle); - -#if defined(HAVE_WIN32_IPC) - DWORD totalBytesAvail; - - if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL, - &totalBytesAvail, NULL)) - { - LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n"); - return true; - } - - return (totalBytesAvail != 0); -#else - errno = 0; - fd_set readfds; - struct timeval tv = { 0, 0 }; - int cc; - - FD_ZERO(&readfds); - FD_SET(mReadHandle, &readfds); - - cc = select(mReadHandle+1, &readfds, NULL, NULL, &tv); - if (cc < 0) { - LOG(LOG_ERROR, "pipe", "select() failed\n"); - return true; - } else if (cc == 0) { - /* timed out, nothing available */ - return false; - } else if (cc == 1) { - /* our fd is ready */ - return true; - } else { - LOG(LOG_ERROR, "pipe", "HUH? select() returned > 1\n"); - return true; - } -#endif -} - -/* - * Enable or disable non-blocking mode for the read descriptor. - * - * NOTE: the calls succeed under Mac OS X, but the pipe doesn't appear to - * actually be in non-blocking mode. If this matters -- i.e. you're not - * using a select() call -- put a call to readReady() in front of the - * ::read() call, with a PIPE_NONBLOCK_BROKEN #ifdef in the Makefile for - * Darwin. - */ -bool Pipe::setReadNonBlocking(bool val) -{ - assert(mReadHandle != kInvalidHandle); - -#if defined(HAVE_WIN32_IPC) - // nothing to do -#else - int flags; - - if (fcntl(mReadHandle, F_GETFL, &flags) == -1) { - LOG(LOG_ERROR, "pipe", "couldn't get flags for pipe read fd\n"); - return false; - } - if (val) - flags |= O_NONBLOCK; - else - flags &= ~(O_NONBLOCK); - if (fcntl(mReadHandle, F_SETFL, &flags) == -1) { - LOG(LOG_ERROR, "pipe", "couldn't set flags for pipe read fd\n"); - return false; - } -#endif - - mReadNonBlocking = val; - return true; -} - -/* - * Enable or disable non-blocking mode for the write descriptor. - * - * As with setReadNonBlocking(), this does not work on the Mac. - */ -bool Pipe::setWriteNonBlocking(bool val) -{ - assert(mWriteHandle != kInvalidHandle); - -#if defined(HAVE_WIN32_IPC) - // nothing to do -#else - int flags; - - if (fcntl(mWriteHandle, F_GETFL, &flags) == -1) { - LOG(LOG_WARN, "pipe", - "Warning: couldn't get flags for pipe write fd (errno=%d)\n", - errno); - return false; - } - if (val) - flags |= O_NONBLOCK; - else - flags &= ~(O_NONBLOCK); - if (fcntl(mWriteHandle, F_SETFL, &flags) == -1) { - LOG(LOG_WARN, "pipe", - "Warning: couldn't set flags for pipe write fd (errno=%d)\n", - errno); - return false; - } -#endif - - mWriteNonBlocking = val; - return true; -} - -/* - * Specify whether a file descriptor can be inherited by a child process. - * Under Linux this means setting the close-on-exec flag, under Windows - * this is SetHandleInformation(HANDLE_FLAG_INHERIT). - */ -bool Pipe::disallowReadInherit(void) -{ - if (mReadHandle == kInvalidHandle) - return false; - -#if defined(HAVE_WIN32_IPC) - if (SetHandleInformation((HANDLE) mReadHandle, HANDLE_FLAG_INHERIT, 0) == 0) - return false; -#else - if (fcntl((int) mReadHandle, F_SETFD, FD_CLOEXEC) != 0) - return false; -#endif - return true; -} -bool Pipe::disallowWriteInherit(void) -{ - if (mWriteHandle == kInvalidHandle) - return false; - -#if defined(HAVE_WIN32_IPC) - if (SetHandleInformation((HANDLE) mWriteHandle, HANDLE_FLAG_INHERIT, 0) == 0) - return false; -#else - if (fcntl((int) mWriteHandle, F_SETFD, FD_CLOEXEC) != 0) - return false; -#endif - return true; -} - -/* - * Close read descriptor. - */ -bool Pipe::closeRead(void) -{ - if (mReadHandle == kInvalidHandle) - return false; - -#if defined(HAVE_WIN32_IPC) - if (mReadHandle != kInvalidHandle) { - if (!CloseHandle((HANDLE)mReadHandle)) { - LOG(LOG_WARN, "pipe", "failed closing read handle\n"); - return false; - } - } -#else - if (mReadHandle != kInvalidHandle) { - if (close((int) mReadHandle) != 0) { - LOG(LOG_WARN, "pipe", "failed closing read fd\n"); - return false; - } - } -#endif - mReadHandle = kInvalidHandle; - return true; -} - -/* - * Close write descriptor. - */ -bool Pipe::closeWrite(void) -{ - if (mWriteHandle == kInvalidHandle) - return false; - -#if defined(HAVE_WIN32_IPC) - if (mWriteHandle != kInvalidHandle) { - if (!CloseHandle((HANDLE)mWriteHandle)) { - LOG(LOG_WARN, "pipe", "failed closing write handle\n"); - return false; - } - } -#else - if (mWriteHandle != kInvalidHandle) { - if (close((int) mWriteHandle) != 0) { - LOG(LOG_WARN, "pipe", "failed closing write fd\n"); - return false; - } - } -#endif - mWriteHandle = kInvalidHandle; - return true; -} - -/* - * Get the read handle. - */ -unsigned long Pipe::getReadHandle(void) -{ - assert(mReadHandle != kInvalidHandle); - - return mReadHandle; -} - -/* - * Get the write handle. - */ -unsigned long Pipe::getWriteHandle(void) -{ - assert(mWriteHandle != kInvalidHandle); - - return mWriteHandle; -} - diff --git a/libs/utils/ProcessState.cpp b/libs/utils/ProcessState.cpp deleted file mode 100644 index 4567df6..0000000 --- a/libs/utils/ProcessState.cpp +++ /dev/null @@ -1,398 +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 "ProcessState" - -#include <cutils/process_name.h> - -#include <utils/ProcessState.h> - -#include <utils/Atomic.h> -#include <utils/BpBinder.h> -#include <utils/IPCThreadState.h> -#include <utils/Log.h> -#include <utils/String8.h> -#include <utils/IServiceManager.h> -#include <utils/String8.h> -#include <utils/threads.h> - -#include <private/utils/binder_module.h> -#include <private/utils/Static.h> - -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <sys/stat.h> - -#define BINDER_VM_SIZE (1*1024*1024) - -static bool gSingleProcess = false; - - -// --------------------------------------------------------------------------- - -namespace android { - -// Global variables -int mArgC; -const char* const* mArgV; -int mArgLen; - -class PoolThread : public Thread -{ -public: - PoolThread(bool isMain) - : mIsMain(isMain) - { - } - -protected: - virtual bool threadLoop() - { - IPCThreadState::self()->joinThreadPool(mIsMain); - return false; - } - - const bool mIsMain; -}; - -sp<ProcessState> ProcessState::self() -{ - if (gProcess != NULL) return gProcess; - - AutoMutex _l(gProcessMutex); - if (gProcess == NULL) gProcess = new ProcessState; - return gProcess; -} - -void ProcessState::setSingleProcess(bool singleProcess) -{ - gSingleProcess = singleProcess; -} - - -void ProcessState::setContextObject(const sp<IBinder>& object) -{ - setContextObject(object, String16("default")); -} - -sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller) -{ - if (supportsProcesses()) { - return getStrongProxyForHandle(0); - } else { - return getContextObject(String16("default"), caller); - } -} - -void ProcessState::setContextObject(const sp<IBinder>& object, const String16& name) -{ - AutoMutex _l(mLock); - mContexts.add(name, object); -} - -sp<IBinder> ProcessState::getContextObject(const String16& name, const sp<IBinder>& caller) -{ - mLock.lock(); - sp<IBinder> object( - mContexts.indexOfKey(name) >= 0 ? mContexts.valueFor(name) : NULL); - mLock.unlock(); - - //printf("Getting context object %s for %p\n", String8(name).string(), caller.get()); - - if (object != NULL) return object; - - // Don't attempt to retrieve contexts if we manage them - if (mManagesContexts) { - LOGE("getContextObject(%s) failed, but we manage the contexts!\n", - String8(name).string()); - return NULL; - } - - IPCThreadState* ipc = IPCThreadState::self(); - { - Parcel data, reply; - // no interface token on this magic transaction - data.writeString16(name); - data.writeStrongBinder(caller); - status_t result = ipc->transact(0 /*magic*/, 0, data, &reply, 0); - if (result == NO_ERROR) { - object = reply.readStrongBinder(); - } - } - - ipc->flushCommands(); - - if (object != NULL) setContextObject(object, name); - return object; -} - -bool ProcessState::supportsProcesses() const -{ - return mDriverFD >= 0; -} - -void ProcessState::startThreadPool() -{ - AutoMutex _l(mLock); - if (!mThreadPoolStarted) { - mThreadPoolStarted = true; - spawnPooledThread(true); - } -} - -bool ProcessState::isContextManager(void) const -{ - return mManagesContexts; -} - -bool ProcessState::becomeContextManager(context_check_func checkFunc, void* userData) -{ - if (!mManagesContexts) { - AutoMutex _l(mLock); - mBinderContextCheckFunc = checkFunc; - mBinderContextUserData = userData; - if (mDriverFD >= 0) { - int dummy = 0; -#if defined(HAVE_ANDROID_OS) - status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy); -#else - status_t result = INVALID_OPERATION; -#endif - if (result == 0) { - mManagesContexts = true; - } else if (result == -1) { - mBinderContextCheckFunc = NULL; - mBinderContextUserData = NULL; - LOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno)); - } - } else { - // If there is no driver, our only world is the local - // process so we can always become the context manager there. - mManagesContexts = true; - } - } - return mManagesContexts; -} - -ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle) -{ - const size_t N=mHandleToObject.size(); - if (N <= (size_t)handle) { - handle_entry e; - e.binder = NULL; - e.refs = NULL; - status_t err = mHandleToObject.insertAt(e, N, handle+1-N); - if (err < NO_ERROR) return NULL; - } - return &mHandleToObject.editItemAt(handle); -} - -sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) -{ - sp<IBinder> result; - - AutoMutex _l(mLock); - - handle_entry* e = lookupHandleLocked(handle); - - if (e != NULL) { - // We need to create a new BpBinder if there isn't currently one, OR we - // are unable to acquire a weak reference on this current one. See comment - // in getWeakProxyForHandle() for more info about this. - IBinder* b = e->binder; - if (b == NULL || !e->refs->attemptIncWeak(this)) { - b = new BpBinder(handle); - e->binder = b; - if (b) e->refs = b->getWeakRefs(); - result = b; - } else { - // This little bit of nastyness is to allow us to add a primary - // reference to the remote proxy when this team doesn't have one - // but another team is sending the handle to us. - result.force_set(b); - e->refs->decWeak(this); - } - } - - return result; -} - -wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle) -{ - wp<IBinder> result; - - AutoMutex _l(mLock); - - handle_entry* e = lookupHandleLocked(handle); - - if (e != NULL) { - // We need to create a new BpBinder if there isn't currently one, OR we - // are unable to acquire a weak reference on this current one. The - // attemptIncWeak() is safe because we know the BpBinder destructor will always - // call expungeHandle(), which acquires the same lock we are holding now. - // We need to do this because there is a race condition between someone - // releasing a reference on this BpBinder, and a new reference on its handle - // arriving from the driver. - IBinder* b = e->binder; - if (b == NULL || !e->refs->attemptIncWeak(this)) { - b = new BpBinder(handle); - result = b; - e->binder = b; - if (b) e->refs = b->getWeakRefs(); - } else { - result = b; - e->refs->decWeak(this); - } - } - - return result; -} - -void ProcessState::expungeHandle(int32_t handle, IBinder* binder) -{ - AutoMutex _l(mLock); - - handle_entry* e = lookupHandleLocked(handle); - - // This handle may have already been replaced with a new BpBinder - // (if someone failed the AttemptIncWeak() above); we don't want - // to overwrite it. - if (e && e->binder == binder) e->binder = NULL; -} - -void ProcessState::setArgs(int argc, const char* const argv[]) -{ - mArgC = argc; - mArgV = (const char **)argv; - - mArgLen = 0; - for (int i=0; i<argc; i++) { - mArgLen += strlen(argv[i]) + 1; - } - mArgLen--; -} - -int ProcessState::getArgC() const -{ - return mArgC; -} - -const char* const* ProcessState::getArgV() const -{ - return mArgV; -} - -void ProcessState::setArgV0(const char* txt) -{ - if (mArgV != NULL) { - strncpy((char*)mArgV[0], txt, mArgLen); - set_process_name(txt); - } -} - -void ProcessState::spawnPooledThread(bool isMain) -{ - if (mThreadPoolStarted) { - int32_t s = android_atomic_add(1, &mThreadPoolSeq); - char buf[32]; - sprintf(buf, "Binder Thread #%d", s); - LOGV("Spawning new pooled thread, name=%s\n", buf); - sp<Thread> t = new PoolThread(isMain); - t->run(buf); - } -} - -static int open_driver() -{ - if (gSingleProcess) { - return -1; - } - - int fd = open("/dev/binder", O_RDWR); - if (fd >= 0) { - fcntl(fd, F_SETFD, FD_CLOEXEC); - int vers; -#if defined(HAVE_ANDROID_OS) - status_t result = ioctl(fd, BINDER_VERSION, &vers); -#else - status_t result = -1; - errno = EPERM; -#endif - if (result == -1) { - LOGE("Binder ioctl to obtain version failed: %s", strerror(errno)); - close(fd); - fd = -1; - } - if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) { - LOGE("Binder driver protocol does not match user space protocol!"); - close(fd); - fd = -1; - } -#if defined(HAVE_ANDROID_OS) - size_t maxThreads = 15; - result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads); - if (result == -1) { - LOGE("Binder ioctl to set max threads failed: %s", strerror(errno)); - } -#endif - - } else { - LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno)); - } - return fd; -} - -ProcessState::ProcessState() - : mDriverFD(open_driver()) - , mVMStart(MAP_FAILED) - , mManagesContexts(false) - , mBinderContextCheckFunc(NULL) - , mBinderContextUserData(NULL) - , mThreadPoolStarted(false) - , mThreadPoolSeq(1) -{ - if (mDriverFD >= 0) { - // XXX Ideally, there should be a specific define for whether we - // have mmap (or whether we could possibly have the kernel module - // availabla). -#if !defined(HAVE_WIN32_IPC) - // mmap the binder, providing a chunk of virtual address space to receive transactions. - mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0); - if (mVMStart == MAP_FAILED) { - // *sigh* - LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n"); - close(mDriverFD); - mDriverFD = -1; - } -#else - mDriverFD = -1; -#endif - } - if (mDriverFD < 0) { - // Need to run without the driver, starting our own thread pool. - } -} - -ProcessState::~ProcessState() -{ -} - -}; // namespace android diff --git a/libs/utils/README b/libs/utils/README deleted file mode 100644 index 36a706d..0000000 --- a/libs/utils/README +++ /dev/null @@ -1,14 +0,0 @@ -Android Utility Function Library - -If you need a feature that is native to Linux but not present on other -platforms, construct a platform-dependent implementation that shares -the Linux interface. That way the actual device runs as "light" as -possible. - -If that isn't feasible, create a system-independent interface and hide -the details. - -The ultimate goal is *not* to create a super-duper platform abstraction -layer. The goal is to provide an optimized solution for Linux with -reasonable implementations for other platforms. - diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp deleted file mode 100644 index 0bd1af4..0000000 --- a/libs/utils/RefBase.cpp +++ /dev/null @@ -1,534 +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 "RefBase" - -#include <utils/RefBase.h> - -#include <utils/Atomic.h> -#include <utils/CallStack.h> -#include <utils/KeyedVector.h> -#include <utils/Log.h> -#include <utils/threads.h> - -#include <stdlib.h> -#include <stdio.h> -#include <typeinfo> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> - -// compile with refcounting debugging enabled -#define DEBUG_REFS 0 -#define DEBUG_REFS_ENABLED_BY_DEFAULT 1 -#define DEBUG_REFS_CALLSTACK_ENABLED 1 - -// log all reference counting operations -#define PRINT_REFS 0 - -// --------------------------------------------------------------------------- - -namespace android { - -#define INITIAL_STRONG_VALUE (1<<28) - -// --------------------------------------------------------------------------- - -class RefBase::weakref_impl : public RefBase::weakref_type -{ -public: - volatile int32_t mStrong; - volatile int32_t mWeak; - RefBase* const mBase; - volatile int32_t mFlags; - - -#if !DEBUG_REFS - - weakref_impl(RefBase* base) - : mStrong(INITIAL_STRONG_VALUE) - , mWeak(0) - , mBase(base) - , mFlags(0) - { - } - - void addStrongRef(const void* /*id*/) { } - void removeStrongRef(const void* /*id*/) { } - void addWeakRef(const void* /*id*/) { } - void removeWeakRef(const void* /*id*/) { } - void printRefs() const { } - void trackMe(bool, bool) { } - -#else - - weakref_impl(RefBase* base) - : mStrong(INITIAL_STRONG_VALUE) - , mWeak(0) - , mBase(base) - , mFlags(0) - , mStrongRefs(NULL) - , mWeakRefs(NULL) - , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT) - , mRetain(false) - { - //LOGI("NEW weakref_impl %p for RefBase %p", this, base); - } - - ~weakref_impl() - { - LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!"); - LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!"); - } - - void addStrongRef(const void* id) - { - addRef(&mStrongRefs, id, mStrong); - } - - void removeStrongRef(const void* id) - { - if (!mRetain) - removeRef(&mStrongRefs, id); - else - addRef(&mStrongRefs, id, -mStrong); - } - - void addWeakRef(const void* id) - { - addRef(&mWeakRefs, id, mWeak); - } - - void removeWeakRef(const void* id) - { - if (!mRetain) - removeRef(&mWeakRefs, id); - else - addRef(&mWeakRefs, id, -mWeak); - } - - void trackMe(bool track, bool retain) - { - mTrackEnabled = track; - mRetain = retain; - } - - void printRefs() const - { - String8 text; - - { - AutoMutex _l(const_cast<weakref_impl*>(this)->mMutex); - - char buf[128]; - sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this); - text.append(buf); - printRefsLocked(&text, mStrongRefs); - sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this); - text.append(buf); - printRefsLocked(&text, mWeakRefs); - } - - { - char name[100]; - snprintf(name, 100, "/data/%p.stack", this); - int rc = open(name, O_RDWR | O_CREAT | O_APPEND); - if (rc >= 0) { - write(rc, text.string(), text.length()); - close(rc); - LOGD("STACK TRACE for %p saved in %s", this, name); - } - else LOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this, - name, strerror(errno)); - } - } - -private: - struct ref_entry - { - ref_entry* next; - const void* id; -#if DEBUG_REFS_CALLSTACK_ENABLED - CallStack stack; -#endif - int32_t ref; - }; - - void addRef(ref_entry** refs, const void* id, int32_t mRef) - { - if (mTrackEnabled) { - AutoMutex _l(mMutex); - ref_entry* ref = new ref_entry; - // Reference count at the time of the snapshot, but before the - // update. Positive value means we increment, negative--we - // decrement the reference count. - ref->ref = mRef; - ref->id = id; -#if DEBUG_REFS_CALLSTACK_ENABLED - ref->stack.update(2); -#endif - - ref->next = *refs; - *refs = ref; - } - } - - void removeRef(ref_entry** refs, const void* id) - { - if (mTrackEnabled) { - AutoMutex _l(mMutex); - - ref_entry* ref = *refs; - while (ref != NULL) { - if (ref->id == id) { - *refs = ref->next; - delete ref; - return; - } - - refs = &ref->next; - ref = *refs; - } - - LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!", - id, mBase, this); - } - } - - void printRefsLocked(String8* out, const ref_entry* refs) const - { - char buf[128]; - while (refs) { - char inc = refs->ref >= 0 ? '+' : '-'; - sprintf(buf, "\t%c ID %p (ref %d):\n", - inc, refs->id, refs->ref); - out->append(buf); -#if DEBUG_REFS_CALLSTACK_ENABLED - out->append(refs->stack.toString("\t\t")); -#else - out->append("\t\t(call stacks disabled)"); -#endif - refs = refs->next; - } - } - - Mutex mMutex; - ref_entry* mStrongRefs; - ref_entry* mWeakRefs; - - bool mTrackEnabled; - // Collect stack traces on addref and removeref, instead of deleting the stack references - // on removeref that match the address ones. - bool mRetain; - -#if 0 - void addRef(KeyedVector<const void*, int32_t>* refs, const void* id) - { - AutoMutex _l(mMutex); - ssize_t i = refs->indexOfKey(id); - if (i >= 0) { - ++(refs->editValueAt(i)); - } else { - i = refs->add(id, 1); - } - } - - void removeRef(KeyedVector<const void*, int32_t>* refs, const void* id) - { - AutoMutex _l(mMutex); - ssize_t i = refs->indexOfKey(id); - LOG_ALWAYS_FATAL_IF(i < 0, "RefBase: removing id %p that doesn't exist!", id); - if (i >= 0) { - int32_t val = --(refs->editValueAt(i)); - if (val == 0) { - refs->removeItemsAt(i); - } - } - } - - void printRefs(const KeyedVector<const void*, int32_t>& refs) - { - const size_t N=refs.size(); - for (size_t i=0; i<N; i++) { - printf("\tID %p: %d remain\n", refs.keyAt(i), refs.valueAt(i)); - } - } - - mutable Mutex mMutex; - KeyedVector<const void*, int32_t> mStrongRefs; - KeyedVector<const void*, int32_t> mWeakRefs; -#endif - -#endif -}; - -// --------------------------------------------------------------------------- - -void RefBase::incStrong(const void* id) const -{ - weakref_impl* const refs = mRefs; - refs->addWeakRef(id); - refs->incWeak(id); - - refs->addStrongRef(id); - const int32_t c = android_atomic_inc(&refs->mStrong); - LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs); -#if PRINT_REFS - LOGD("incStrong of %p from %p: cnt=%d\n", this, id, c); -#endif - if (c != INITIAL_STRONG_VALUE) { - return; - } - - android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); - const_cast<RefBase*>(this)->onFirstRef(); -} - -void RefBase::decStrong(const void* id) const -{ - weakref_impl* const refs = mRefs; - refs->removeStrongRef(id); - const int32_t c = android_atomic_dec(&refs->mStrong); -#if PRINT_REFS - LOGD("decStrong of %p from %p: cnt=%d\n", this, id, c); -#endif - LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs); - if (c == 1) { - const_cast<RefBase*>(this)->onLastStrongRef(id); - if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { - delete this; - } - } - refs->removeWeakRef(id); - refs->decWeak(id); -} - -void RefBase::forceIncStrong(const void* id) const -{ - weakref_impl* const refs = mRefs; - refs->addWeakRef(id); - refs->incWeak(id); - - refs->addStrongRef(id); - const int32_t c = android_atomic_inc(&refs->mStrong); - LOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow", - refs); -#if PRINT_REFS - LOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c); -#endif - - switch (c) { - case INITIAL_STRONG_VALUE: - android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); - // fall through... - case 0: - const_cast<RefBase*>(this)->onFirstRef(); - } -} - -int32_t RefBase::getStrongCount() const -{ - return mRefs->mStrong; -} - - - -RefBase* RefBase::weakref_type::refBase() const -{ - return static_cast<const weakref_impl*>(this)->mBase; -} - -void RefBase::weakref_type::incWeak(const void* id) -{ - weakref_impl* const impl = static_cast<weakref_impl*>(this); - impl->addWeakRef(id); - const int32_t c = android_atomic_inc(&impl->mWeak); - LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this); -} - -void RefBase::weakref_type::decWeak(const void* id) -{ - weakref_impl* const impl = static_cast<weakref_impl*>(this); - impl->removeWeakRef(id); - const int32_t c = android_atomic_dec(&impl->mWeak); - LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this); - if (c != 1) return; - - if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { - if (impl->mStrong == INITIAL_STRONG_VALUE) - delete impl->mBase; - else { -// LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase); - delete impl; - } - } else { - impl->mBase->onLastWeakRef(id); - if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) { - delete impl->mBase; - } - } -} - -bool RefBase::weakref_type::attemptIncStrong(const void* id) -{ - incWeak(id); - - weakref_impl* const impl = static_cast<weakref_impl*>(this); - - int32_t curCount = impl->mStrong; - LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow", - this); - while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) { - if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) { - break; - } - curCount = impl->mStrong; - } - - if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) { - bool allow; - if (curCount == INITIAL_STRONG_VALUE) { - // Attempting to acquire first strong reference... this is allowed - // if the object does NOT have a longer lifetime (meaning the - // implementation doesn't need to see this), or if the implementation - // allows it to happen. - allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK - || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id); - } else { - // Attempting to revive the object... this is allowed - // if the object DOES have a longer lifetime (so we can safely - // call the object with only a weak ref) and the implementation - // allows it to happen. - allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK - && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id); - } - if (!allow) { - decWeak(id); - return false; - } - curCount = android_atomic_inc(&impl->mStrong); - - // If the strong reference count has already been incremented by - // someone else, the implementor of onIncStrongAttempted() is holding - // an unneeded reference. So call onLastStrongRef() here to remove it. - // (No, this is not pretty.) Note that we MUST NOT do this if we - // are in fact acquiring the first reference. - if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) { - impl->mBase->onLastStrongRef(id); - } - } - - impl->addWeakRef(id); - impl->addStrongRef(id); - -#if PRINT_REFS - LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount); -#endif - - if (curCount == INITIAL_STRONG_VALUE) { - android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong); - impl->mBase->onFirstRef(); - } - - return true; -} - -bool RefBase::weakref_type::attemptIncWeak(const void* id) -{ - weakref_impl* const impl = static_cast<weakref_impl*>(this); - - int32_t curCount = impl->mWeak; - LOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow", - this); - while (curCount > 0) { - if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) { - break; - } - curCount = impl->mWeak; - } - - if (curCount > 0) { - impl->addWeakRef(id); - } - - return curCount > 0; -} - -int32_t RefBase::weakref_type::getWeakCount() const -{ - return static_cast<const weakref_impl*>(this)->mWeak; -} - -void RefBase::weakref_type::printRefs() const -{ - static_cast<const weakref_impl*>(this)->printRefs(); -} - -void RefBase::weakref_type::trackMe(bool enable, bool retain) -{ - static_cast<const weakref_impl*>(this)->trackMe(enable, retain); -} - -RefBase::weakref_type* RefBase::createWeak(const void* id) const -{ - mRefs->incWeak(id); - return mRefs; -} - -RefBase::weakref_type* RefBase::getWeakRefs() const -{ - return mRefs; -} - -RefBase::RefBase() - : mRefs(new weakref_impl(this)) -{ -// LOGV("Creating refs %p with RefBase %p\n", mRefs, this); -} - -RefBase::~RefBase() -{ -// LOGV("Destroying RefBase %p (refs %p)\n", this, mRefs); - if (mRefs->mWeak == 0) { -// LOGV("Freeing refs %p of old RefBase %p\n", mRefs, this); - delete mRefs; - } -} - -void RefBase::extendObjectLifetime(int32_t mode) -{ - android_atomic_or(mode, &mRefs->mFlags); -} - -void RefBase::onFirstRef() -{ -} - -void RefBase::onLastStrongRef(const void* /*id*/) -{ -} - -bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id) -{ - return (flags&FIRST_INC_STRONG) ? true : false; -} - -void RefBase::onLastWeakRef(const void* /*id*/) -{ -} - -}; // namespace android diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp deleted file mode 100644 index 71e7cd7..0000000 --- a/libs/utils/ResourceTypes.cpp +++ /dev/null @@ -1,3983 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "ResourceType" -//#define LOG_NDEBUG 0 - -#include <utils/Atomic.h> -#include <utils/ByteOrder.h> -#include <utils/Debug.h> -#include <utils/ResourceTypes.h> -#include <utils/String16.h> -#include <utils/String8.h> -#include <utils/TextOutput.h> -#include <utils/Log.h> - -#include <stdlib.h> -#include <string.h> -#include <memory.h> -#include <ctype.h> -#include <stdint.h> - -#ifndef INT32_MAX -#define INT32_MAX ((int32_t)(2147483647)) -#endif - -#define POOL_NOISY(x) //x -#define XML_NOISY(x) //x -#define TABLE_NOISY(x) //x -#define TABLE_GETENTRY(x) //x -#define TABLE_SUPER_NOISY(x) //x -#define LOAD_TABLE_NOISY(x) //x - -namespace android { - -#ifdef HAVE_WINSOCK -#undef nhtol -#undef htonl - -#ifdef HAVE_LITTLE_ENDIAN -#define ntohl(x) ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) ) -#define htonl(x) ntohl(x) -#define ntohs(x) ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) ) -#define htons(x) ntohs(x) -#else -#define ntohl(x) (x) -#define htonl(x) (x) -#define ntohs(x) (x) -#define htons(x) (x) -#endif -#endif - -static void printToLogFunc(void* cookie, const char* txt) -{ - LOGV("%s", txt); -} - -// Standard C isspace() is only required to look at the low byte of its input, so -// produces incorrect results for UTF-16 characters. For safety's sake, assume that -// any high-byte UTF-16 code point is not whitespace. -inline int isspace16(char16_t c) { - return (c < 0x0080 && isspace(c)); -} - -// range checked; guaranteed to NUL-terminate within the stated number of available slots -// NOTE: if this truncates the dst string due to running out of space, no attempt is -// made to avoid splitting surrogate pairs. -static void strcpy16_dtoh(uint16_t* dst, const uint16_t* src, size_t avail) -{ - uint16_t* last = dst + avail - 1; - while (*src && (dst < last)) { - char16_t s = dtohs(*src); - *dst++ = s; - src++; - } - *dst = 0; -} - -static status_t validate_chunk(const ResChunk_header* chunk, - size_t minSize, - const uint8_t* dataEnd, - const char* name) -{ - const uint16_t headerSize = dtohs(chunk->headerSize); - const uint32_t size = dtohl(chunk->size); - - if (headerSize >= minSize) { - if (headerSize <= size) { - if (((headerSize|size)&0x3) == 0) { - if ((ssize_t)size <= (dataEnd-((const uint8_t*)chunk))) { - return NO_ERROR; - } - LOGW("%s data size %p extends beyond resource end %p.", - name, (void*)size, - (void*)(dataEnd-((const uint8_t*)chunk))); - return BAD_TYPE; - } - LOGW("%s size 0x%x or headerSize 0x%x is not on an integer boundary.", - name, (int)size, (int)headerSize); - return BAD_TYPE; - } - LOGW("%s size %p is smaller than header size %p.", - name, (void*)size, (void*)(int)headerSize); - return BAD_TYPE; - } - LOGW("%s header size %p is too small.", - name, (void*)(int)headerSize); - return BAD_TYPE; -} - -inline void Res_value::copyFrom_dtoh(const Res_value& src) -{ - size = dtohs(src.size); - res0 = src.res0; - dataType = src.dataType; - data = dtohl(src.data); -} - -void Res_png_9patch::deviceToFile() -{ - for (int i = 0; i < numXDivs; i++) { - xDivs[i] = htonl(xDivs[i]); - } - for (int i = 0; i < numYDivs; i++) { - yDivs[i] = htonl(yDivs[i]); - } - paddingLeft = htonl(paddingLeft); - paddingRight = htonl(paddingRight); - paddingTop = htonl(paddingTop); - paddingBottom = htonl(paddingBottom); - for (int i=0; i<numColors; i++) { - colors[i] = htonl(colors[i]); - } -} - -void Res_png_9patch::fileToDevice() -{ - for (int i = 0; i < numXDivs; i++) { - xDivs[i] = ntohl(xDivs[i]); - } - for (int i = 0; i < numYDivs; i++) { - yDivs[i] = ntohl(yDivs[i]); - } - paddingLeft = ntohl(paddingLeft); - paddingRight = ntohl(paddingRight); - paddingTop = ntohl(paddingTop); - paddingBottom = ntohl(paddingBottom); - for (int i=0; i<numColors; i++) { - colors[i] = ntohl(colors[i]); - } -} - -size_t Res_png_9patch::serializedSize() -{ - // The size of this struct is 32 bytes on the 32-bit target system - // 4 * int8_t - // 4 * int32_t - // 3 * pointer - return 32 - + numXDivs * sizeof(int32_t) - + numYDivs * sizeof(int32_t) - + numColors * sizeof(uint32_t); -} - -void* Res_png_9patch::serialize() -{ - void* newData = malloc(serializedSize()); - serialize(newData); - return newData; -} - -void Res_png_9patch::serialize(void * outData) -{ - char* data = (char*) outData; - memmove(data, &wasDeserialized, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors - memmove(data + 12, &paddingLeft, 16); // copy paddingXXXX - data += 32; - - memmove(data, this->xDivs, numXDivs * sizeof(int32_t)); - data += numXDivs * sizeof(int32_t); - memmove(data, this->yDivs, numYDivs * sizeof(int32_t)); - data += numYDivs * sizeof(int32_t); - memmove(data, this->colors, numColors * sizeof(uint32_t)); -} - -static void deserializeInternal(const void* inData, Res_png_9patch* outData) { - char* patch = (char*) inData; - if (inData != outData) { - memmove(&outData->wasDeserialized, patch, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors - memmove(&outData->paddingLeft, patch + 12, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors - } - outData->wasDeserialized = true; - char* data = (char*)outData; - data += sizeof(Res_png_9patch); - outData->xDivs = (int32_t*) data; - data += outData->numXDivs * sizeof(int32_t); - outData->yDivs = (int32_t*) data; - data += outData->numYDivs * sizeof(int32_t); - outData->colors = (uint32_t*) data; -} - -Res_png_9patch* Res_png_9patch::deserialize(const void* inData) -{ - if (sizeof(void*) != sizeof(int32_t)) { - LOGE("Cannot deserialize on non 32-bit system\n"); - return NULL; - } - deserializeInternal(inData, (Res_png_9patch*) inData); - return (Res_png_9patch*) inData; -} - -// -------------------------------------------------------------------- -// -------------------------------------------------------------------- -// -------------------------------------------------------------------- - -ResStringPool::ResStringPool() - : mError(NO_INIT), mOwnedData(NULL) -{ -} - -ResStringPool::ResStringPool(const void* data, size_t size, bool copyData) - : mError(NO_INIT), mOwnedData(NULL) -{ - setTo(data, size, copyData); -} - -ResStringPool::~ResStringPool() -{ - uninit(); -} - -status_t ResStringPool::setTo(const void* data, size_t size, bool copyData) -{ - if (!data || !size) { - return (mError=BAD_TYPE); - } - - uninit(); - - const bool notDeviceEndian = htods(0xf0) != 0xf0; - - if (copyData || notDeviceEndian) { - mOwnedData = malloc(size); - if (mOwnedData == NULL) { - return (mError=NO_MEMORY); - } - memcpy(mOwnedData, data, size); - data = mOwnedData; - } - - mHeader = (const ResStringPool_header*)data; - - if (notDeviceEndian) { - ResStringPool_header* h = const_cast<ResStringPool_header*>(mHeader); - h->header.headerSize = dtohs(mHeader->header.headerSize); - h->header.type = dtohs(mHeader->header.type); - h->header.size = dtohl(mHeader->header.size); - h->stringCount = dtohl(mHeader->stringCount); - h->styleCount = dtohl(mHeader->styleCount); - h->flags = dtohl(mHeader->flags); - h->stringsStart = dtohl(mHeader->stringsStart); - h->stylesStart = dtohl(mHeader->stylesStart); - } - - if (mHeader->header.headerSize > mHeader->header.size - || mHeader->header.size > size) { - LOGW("Bad string block: header size %d or total size %d is larger than data size %d\n", - (int)mHeader->header.headerSize, (int)mHeader->header.size, (int)size); - return (mError=BAD_TYPE); - } - mSize = mHeader->header.size; - mEntries = (const uint32_t*) - (((const uint8_t*)data)+mHeader->header.headerSize); - - if (mHeader->stringCount > 0) { - if ((mHeader->stringCount*sizeof(uint32_t) < mHeader->stringCount) // uint32 overflow? - || (mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t))) - > size) { - LOGW("Bad string block: entry of %d items extends past data size %d\n", - (int)(mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t))), - (int)size); - return (mError=BAD_TYPE); - } - mStrings = (const char16_t*) - (((const uint8_t*)data)+mHeader->stringsStart); - if (mHeader->stringsStart >= (mHeader->header.size-sizeof(uint16_t))) { - LOGW("Bad string block: string pool starts at %d, after total size %d\n", - (int)mHeader->stringsStart, (int)mHeader->header.size); - return (mError=BAD_TYPE); - } - if (mHeader->styleCount == 0) { - mStringPoolSize = - (mHeader->header.size-mHeader->stringsStart)/sizeof(uint16_t); - } else { - // check invariant: styles follow the strings - if (mHeader->stylesStart <= mHeader->stringsStart) { - LOGW("Bad style block: style block starts at %d, before strings at %d\n", - (int)mHeader->stylesStart, (int)mHeader->stringsStart); - return (mError=BAD_TYPE); - } - mStringPoolSize = - (mHeader->stylesStart-mHeader->stringsStart)/sizeof(uint16_t); - } - - // check invariant: stringCount > 0 requires a string pool to exist - if (mStringPoolSize == 0) { - LOGW("Bad string block: stringCount is %d but pool size is 0\n", (int)mHeader->stringCount); - return (mError=BAD_TYPE); - } - - if (notDeviceEndian) { - size_t i; - uint32_t* e = const_cast<uint32_t*>(mEntries); - for (i=0; i<mHeader->stringCount; i++) { - e[i] = dtohl(mEntries[i]); - } - char16_t* s = const_cast<char16_t*>(mStrings); - for (i=0; i<mStringPoolSize; i++) { - s[i] = dtohs(mStrings[i]); - } - } - - if (mStrings[mStringPoolSize-1] != 0) { - LOGW("Bad string block: last string is not 0-terminated\n"); - return (mError=BAD_TYPE); - } - } else { - mStrings = NULL; - mStringPoolSize = 0; - } - - if (mHeader->styleCount > 0) { - mEntryStyles = mEntries + mHeader->stringCount; - // invariant: integer overflow in calculating mEntryStyles - if (mEntryStyles < mEntries) { - LOGW("Bad string block: integer overflow finding styles\n"); - return (mError=BAD_TYPE); - } - - if (((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader) > (int)size) { - LOGW("Bad string block: entry of %d styles extends past data size %d\n", - (int)((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader), - (int)size); - return (mError=BAD_TYPE); - } - mStyles = (const uint32_t*) - (((const uint8_t*)data)+mHeader->stylesStart); - if (mHeader->stylesStart >= mHeader->header.size) { - LOGW("Bad string block: style pool starts %d, after total size %d\n", - (int)mHeader->stylesStart, (int)mHeader->header.size); - return (mError=BAD_TYPE); - } - mStylePoolSize = - (mHeader->header.size-mHeader->stylesStart)/sizeof(uint32_t); - - if (notDeviceEndian) { - size_t i; - uint32_t* e = const_cast<uint32_t*>(mEntryStyles); - for (i=0; i<mHeader->styleCount; i++) { - e[i] = dtohl(mEntryStyles[i]); - } - uint32_t* s = const_cast<uint32_t*>(mStyles); - for (i=0; i<mStylePoolSize; i++) { - s[i] = dtohl(mStyles[i]); - } - } - - const ResStringPool_span endSpan = { - { htodl(ResStringPool_span::END) }, - htodl(ResStringPool_span::END), htodl(ResStringPool_span::END) - }; - if (memcmp(&mStyles[mStylePoolSize-(sizeof(endSpan)/sizeof(uint32_t))], - &endSpan, sizeof(endSpan)) != 0) { - LOGW("Bad string block: last style is not 0xFFFFFFFF-terminated\n"); - return (mError=BAD_TYPE); - } - } else { - mEntryStyles = NULL; - mStyles = NULL; - mStylePoolSize = 0; - } - - return (mError=NO_ERROR); -} - -status_t ResStringPool::getError() const -{ - return mError; -} - -void ResStringPool::uninit() -{ - mError = NO_INIT; - if (mOwnedData) { - free(mOwnedData); - mOwnedData = NULL; - } -} - -const uint16_t* ResStringPool::stringAt(size_t idx, size_t* outLen) const -{ - if (mError == NO_ERROR && idx < mHeader->stringCount) { - const uint32_t off = (mEntries[idx]/sizeof(uint16_t)); - if (off < (mStringPoolSize-1)) { - const char16_t* str = mStrings+off; - *outLen = *str; - if ((*str)&0x8000) { - str++; - *outLen = (((*outLen)&0x7fff)<<16) + *str; - } - if ((uint32_t)(str+1+*outLen-mStrings) < mStringPoolSize) { - return str+1; - } else { - LOGW("Bad string block: string #%d extends to %d, past end at %d\n", - (int)idx, (int)(str+1+*outLen-mStrings), (int)mStringPoolSize); - } - } else { - LOGW("Bad string block: string #%d entry is at %d, past end at %d\n", - (int)idx, (int)(off*sizeof(uint16_t)), - (int)(mStringPoolSize*sizeof(uint16_t))); - } - } - return NULL; -} - -const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const -{ - return styleAt(ref.index); -} - -const ResStringPool_span* ResStringPool::styleAt(size_t idx) const -{ - if (mError == NO_ERROR && idx < mHeader->styleCount) { - const uint32_t off = (mEntryStyles[idx]/sizeof(uint32_t)); - if (off < mStylePoolSize) { - return (const ResStringPool_span*)(mStyles+off); - } else { - LOGW("Bad string block: style #%d entry is at %d, past end at %d\n", - (int)idx, (int)(off*sizeof(uint32_t)), - (int)(mStylePoolSize*sizeof(uint32_t))); - } - } - return NULL; -} - -ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const -{ - if (mError != NO_ERROR) { - return mError; - } - - size_t len; - - if (mHeader->flags&ResStringPool_header::SORTED_FLAG) { - // Do a binary search for the string... - ssize_t l = 0; - ssize_t h = mHeader->stringCount-1; - - ssize_t mid; - while (l <= h) { - mid = l + (h - l)/2; - const char16_t* s = stringAt(mid, &len); - int c = s ? strzcmp16(s, len, str, strLen) : -1; - POOL_NOISY(printf("Looking for %s, at %s, cmp=%d, l/mid/h=%d/%d/%d\n", - String8(str).string(), - String8(s).string(), - c, (int)l, (int)mid, (int)h)); - if (c == 0) { - return mid; - } else if (c < 0) { - l = mid + 1; - } else { - h = mid - 1; - } - } - } else { - // It is unusual to get the ID from an unsorted string block... - // most often this happens because we want to get IDs for style - // span tags; since those always appear at the end of the string - // block, start searching at the back. - for (int i=mHeader->stringCount-1; i>=0; i--) { - const char16_t* s = stringAt(i, &len); - POOL_NOISY(printf("Looking for %s, at %s, i=%d\n", - String8(str, strLen).string(), - String8(s).string(), - i)); - if (s && strzcmp16(s, len, str, strLen) == 0) { - return i; - } - } - } - - return NAME_NOT_FOUND; -} - -size_t ResStringPool::size() const -{ - return (mError == NO_ERROR) ? mHeader->stringCount : 0; -} - -// -------------------------------------------------------------------- -// -------------------------------------------------------------------- -// -------------------------------------------------------------------- - -ResXMLParser::ResXMLParser(const ResXMLTree& tree) - : mTree(tree), mEventCode(BAD_DOCUMENT) -{ -} - -void ResXMLParser::restart() -{ - mCurNode = NULL; - mEventCode = mTree.mError == NO_ERROR ? START_DOCUMENT : BAD_DOCUMENT; -} - -ResXMLParser::event_code_t ResXMLParser::getEventType() const -{ - return mEventCode; -} - -ResXMLParser::event_code_t ResXMLParser::next() -{ - if (mEventCode == START_DOCUMENT) { - mCurNode = mTree.mRootNode; - mCurExt = mTree.mRootExt; - return (mEventCode=mTree.mRootCode); - } else if (mEventCode >= FIRST_CHUNK_CODE) { - return nextNode(); - } - return mEventCode; -} - -const int32_t ResXMLParser::getCommentID() const -{ - return mCurNode != NULL ? dtohl(mCurNode->comment.index) : -1; -} - -const uint16_t* ResXMLParser::getComment(size_t* outLen) const -{ - int32_t id = getCommentID(); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -const uint32_t ResXMLParser::getLineNumber() const -{ - return mCurNode != NULL ? dtohl(mCurNode->lineNumber) : -1; -} - -const int32_t ResXMLParser::getTextID() const -{ - if (mEventCode == TEXT) { - return dtohl(((const ResXMLTree_cdataExt*)mCurExt)->data.index); - } - return -1; -} - -const uint16_t* ResXMLParser::getText(size_t* outLen) const -{ - int32_t id = getTextID(); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -ssize_t ResXMLParser::getTextValue(Res_value* outValue) const -{ - if (mEventCode == TEXT) { - outValue->copyFrom_dtoh(((const ResXMLTree_cdataExt*)mCurExt)->typedData); - return sizeof(Res_value); - } - return BAD_TYPE; -} - -const int32_t ResXMLParser::getNamespacePrefixID() const -{ - if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) { - return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->prefix.index); - } - return -1; -} - -const uint16_t* ResXMLParser::getNamespacePrefix(size_t* outLen) const -{ - int32_t id = getNamespacePrefixID(); - //printf("prefix=%d event=%p\n", id, mEventCode); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -const int32_t ResXMLParser::getNamespaceUriID() const -{ - if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) { - return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->uri.index); - } - return -1; -} - -const uint16_t* ResXMLParser::getNamespaceUri(size_t* outLen) const -{ - int32_t id = getNamespaceUriID(); - //printf("uri=%d event=%p\n", id, mEventCode); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -const int32_t ResXMLParser::getElementNamespaceID() const -{ - if (mEventCode == START_TAG) { - return dtohl(((const ResXMLTree_attrExt*)mCurExt)->ns.index); - } - if (mEventCode == END_TAG) { - return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->ns.index); - } - return -1; -} - -const uint16_t* ResXMLParser::getElementNamespace(size_t* outLen) const -{ - int32_t id = getElementNamespaceID(); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -const int32_t ResXMLParser::getElementNameID() const -{ - if (mEventCode == START_TAG) { - return dtohl(((const ResXMLTree_attrExt*)mCurExt)->name.index); - } - if (mEventCode == END_TAG) { - return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->name.index); - } - return -1; -} - -const uint16_t* ResXMLParser::getElementName(size_t* outLen) const -{ - int32_t id = getElementNameID(); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -size_t ResXMLParser::getAttributeCount() const -{ - if (mEventCode == START_TAG) { - return dtohs(((const ResXMLTree_attrExt*)mCurExt)->attributeCount); - } - return 0; -} - -const int32_t ResXMLParser::getAttributeNamespaceID(size_t idx) const -{ - if (mEventCode == START_TAG) { - const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; - if (idx < dtohs(tag->attributeCount)) { - const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) - (((const uint8_t*)tag) - + dtohs(tag->attributeStart) - + (dtohs(tag->attributeSize)*idx)); - return dtohl(attr->ns.index); - } - } - return -2; -} - -const uint16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen) const -{ - int32_t id = getAttributeNamespaceID(idx); - //printf("attribute namespace=%d idx=%d event=%p\n", id, idx, mEventCode); - //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id)); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -const int32_t ResXMLParser::getAttributeNameID(size_t idx) const -{ - if (mEventCode == START_TAG) { - const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; - if (idx < dtohs(tag->attributeCount)) { - const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) - (((const uint8_t*)tag) - + dtohs(tag->attributeStart) - + (dtohs(tag->attributeSize)*idx)); - return dtohl(attr->name.index); - } - } - return -1; -} - -const uint16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const -{ - int32_t id = getAttributeNameID(idx); - //printf("attribute name=%d idx=%d event=%p\n", id, idx, mEventCode); - //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id)); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -const uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const -{ - int32_t id = getAttributeNameID(idx); - if (id >= 0 && (size_t)id < mTree.mNumResIds) { - return dtohl(mTree.mResIds[id]); - } - return 0; -} - -const int32_t ResXMLParser::getAttributeValueStringID(size_t idx) const -{ - if (mEventCode == START_TAG) { - const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; - if (idx < dtohs(tag->attributeCount)) { - const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) - (((const uint8_t*)tag) - + dtohs(tag->attributeStart) - + (dtohs(tag->attributeSize)*idx)); - return dtohl(attr->rawValue.index); - } - } - return -1; -} - -const uint16_t* ResXMLParser::getAttributeStringValue(size_t idx, size_t* outLen) const -{ - int32_t id = getAttributeValueStringID(idx); - //XML_NOISY(printf("getAttributeValue 0x%x=0x%x\n", idx, id)); - return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL; -} - -int32_t ResXMLParser::getAttributeDataType(size_t idx) const -{ - if (mEventCode == START_TAG) { - const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; - if (idx < dtohs(tag->attributeCount)) { - const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) - (((const uint8_t*)tag) - + dtohs(tag->attributeStart) - + (dtohs(tag->attributeSize)*idx)); - return attr->typedValue.dataType; - } - } - return Res_value::TYPE_NULL; -} - -int32_t ResXMLParser::getAttributeData(size_t idx) const -{ - if (mEventCode == START_TAG) { - const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; - if (idx < dtohs(tag->attributeCount)) { - const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) - (((const uint8_t*)tag) - + dtohs(tag->attributeStart) - + (dtohs(tag->attributeSize)*idx)); - return dtohl(attr->typedValue.data); - } - } - return 0; -} - -ssize_t ResXMLParser::getAttributeValue(size_t idx, Res_value* outValue) const -{ - if (mEventCode == START_TAG) { - const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt; - if (idx < dtohs(tag->attributeCount)) { - const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*) - (((const uint8_t*)tag) - + dtohs(tag->attributeStart) - + (dtohs(tag->attributeSize)*idx)); - outValue->copyFrom_dtoh(attr->typedValue); - return sizeof(Res_value); - } - } - return BAD_TYPE; -} - -ssize_t ResXMLParser::indexOfAttribute(const char* ns, const char* attr) const -{ - String16 nsStr(ns != NULL ? ns : ""); - String16 attrStr(attr); - return indexOfAttribute(ns ? nsStr.string() : NULL, ns ? nsStr.size() : 0, - attrStr.string(), attrStr.size()); -} - -ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen, - const char16_t* attr, size_t attrLen) const -{ - if (mEventCode == START_TAG) { - const size_t N = getAttributeCount(); - for (size_t i=0; i<N; i++) { - size_t curNsLen, curAttrLen; - const char16_t* curNs = getAttributeNamespace(i, &curNsLen); - const char16_t* curAttr = getAttributeName(i, &curAttrLen); - //printf("%d: ns=%p attr=%p curNs=%p curAttr=%p\n", - // i, ns, attr, curNs, curAttr); - //printf(" --> attr=%s, curAttr=%s\n", - // String8(attr).string(), String8(curAttr).string()); - if (attr && curAttr && (strzcmp16(attr, attrLen, curAttr, curAttrLen) == 0)) { - if (ns == NULL) { - if (curNs == NULL) return i; - } else if (curNs != NULL) { - //printf(" --> ns=%s, curNs=%s\n", - // String8(ns).string(), String8(curNs).string()); - if (strzcmp16(ns, nsLen, curNs, curNsLen) == 0) return i; - } - } - } - } - - return NAME_NOT_FOUND; -} - -ssize_t ResXMLParser::indexOfID() const -{ - if (mEventCode == START_TAG) { - const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->idIndex); - if (idx > 0) return (idx-1); - } - return NAME_NOT_FOUND; -} - -ssize_t ResXMLParser::indexOfClass() const -{ - if (mEventCode == START_TAG) { - const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->classIndex); - if (idx > 0) return (idx-1); - } - return NAME_NOT_FOUND; -} - -ssize_t ResXMLParser::indexOfStyle() const -{ - if (mEventCode == START_TAG) { - const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->styleIndex); - if (idx > 0) return (idx-1); - } - return NAME_NOT_FOUND; -} - -ResXMLParser::event_code_t ResXMLParser::nextNode() -{ - if (mEventCode < 0) { - return mEventCode; - } - - do { - const ResXMLTree_node* next = (const ResXMLTree_node*) - (((const uint8_t*)mCurNode) + dtohl(mCurNode->header.size)); - //LOGW("Next node: prev=%p, next=%p\n", mCurNode, next); - - if (((const uint8_t*)next) >= mTree.mDataEnd) { - mCurNode = NULL; - return (mEventCode=END_DOCUMENT); - } - - if (mTree.validateNode(next) != NO_ERROR) { - mCurNode = NULL; - return (mEventCode=BAD_DOCUMENT); - } - - mCurNode = next; - const uint16_t headerSize = dtohs(next->header.headerSize); - const uint32_t totalSize = dtohl(next->header.size); - mCurExt = ((const uint8_t*)next) + headerSize; - size_t minExtSize = 0; - event_code_t eventCode = (event_code_t)dtohs(next->header.type); - switch ((mEventCode=eventCode)) { - case RES_XML_START_NAMESPACE_TYPE: - case RES_XML_END_NAMESPACE_TYPE: - minExtSize = sizeof(ResXMLTree_namespaceExt); - break; - case RES_XML_START_ELEMENT_TYPE: - minExtSize = sizeof(ResXMLTree_attrExt); - break; - case RES_XML_END_ELEMENT_TYPE: - minExtSize = sizeof(ResXMLTree_endElementExt); - break; - case RES_XML_CDATA_TYPE: - minExtSize = sizeof(ResXMLTree_cdataExt); - break; - default: - LOGW("Unknown XML block: header type %d in node at %d\n", - (int)dtohs(next->header.type), - (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader))); - continue; - } - - if ((totalSize-headerSize) < minExtSize) { - LOGW("Bad XML block: header type 0x%x in node at 0x%x has size %d, need %d\n", - (int)dtohs(next->header.type), - (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)), - (int)(totalSize-headerSize), (int)minExtSize); - return (mEventCode=BAD_DOCUMENT); - } - - //printf("CurNode=%p, CurExt=%p, headerSize=%d, minExtSize=%d\n", - // mCurNode, mCurExt, headerSize, minExtSize); - - return eventCode; - } while (true); -} - -void ResXMLParser::getPosition(ResXMLParser::ResXMLPosition* pos) const -{ - pos->eventCode = mEventCode; - pos->curNode = mCurNode; - pos->curExt = mCurExt; -} - -void ResXMLParser::setPosition(const ResXMLParser::ResXMLPosition& pos) -{ - mEventCode = pos.eventCode; - mCurNode = pos.curNode; - mCurExt = pos.curExt; -} - - -// -------------------------------------------------------------------- - -static volatile int32_t gCount = 0; - -ResXMLTree::ResXMLTree() - : ResXMLParser(*this) - , mError(NO_INIT), mOwnedData(NULL) -{ - //LOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1); - restart(); -} - -ResXMLTree::ResXMLTree(const void* data, size_t size, bool copyData) - : ResXMLParser(*this) - , mError(NO_INIT), mOwnedData(NULL) -{ - //LOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1); - setTo(data, size, copyData); -} - -ResXMLTree::~ResXMLTree() -{ - //LOGI("Destroying ResXMLTree in %p #%d\n", this, android_atomic_dec(&gCount)-1); - uninit(); -} - -status_t ResXMLTree::setTo(const void* data, size_t size, bool copyData) -{ - uninit(); - mEventCode = START_DOCUMENT; - - if (copyData) { - mOwnedData = malloc(size); - if (mOwnedData == NULL) { - return (mError=NO_MEMORY); - } - memcpy(mOwnedData, data, size); - data = mOwnedData; - } - - mHeader = (const ResXMLTree_header*)data; - mSize = dtohl(mHeader->header.size); - if (dtohs(mHeader->header.headerSize) > mSize || mSize > size) { - LOGW("Bad XML block: header size %d or total size %d is larger than data size %d\n", - (int)dtohs(mHeader->header.headerSize), - (int)dtohl(mHeader->header.size), (int)size); - mError = BAD_TYPE; - restart(); - return mError; - } - mDataEnd = ((const uint8_t*)mHeader) + mSize; - - mStrings.uninit(); - mRootNode = NULL; - mResIds = NULL; - mNumResIds = 0; - - // First look for a couple interesting chunks: the string block - // and first XML node. - const ResChunk_header* chunk = - (const ResChunk_header*)(((const uint8_t*)mHeader) + dtohs(mHeader->header.headerSize)); - const ResChunk_header* lastChunk = chunk; - while (((const uint8_t*)chunk) < (mDataEnd-sizeof(ResChunk_header)) && - ((const uint8_t*)chunk) < (mDataEnd-dtohl(chunk->size))) { - status_t err = validate_chunk(chunk, sizeof(ResChunk_header), mDataEnd, "XML"); - if (err != NO_ERROR) { - mError = err; - goto done; - } - const uint16_t type = dtohs(chunk->type); - const size_t size = dtohl(chunk->size); - XML_NOISY(printf("Scanning @ %p: type=0x%x, size=0x%x\n", - (void*)(((uint32_t)chunk)-((uint32_t)mHeader)), type, size)); - if (type == RES_STRING_POOL_TYPE) { - mStrings.setTo(chunk, size); - } else if (type == RES_XML_RESOURCE_MAP_TYPE) { - mResIds = (const uint32_t*) - (((const uint8_t*)chunk)+dtohs(chunk->headerSize)); - mNumResIds = (dtohl(chunk->size)-dtohs(chunk->headerSize))/sizeof(uint32_t); - } else if (type >= RES_XML_FIRST_CHUNK_TYPE - && type <= RES_XML_LAST_CHUNK_TYPE) { - if (validateNode((const ResXMLTree_node*)chunk) != NO_ERROR) { - mError = BAD_TYPE; - goto done; - } - mCurNode = (const ResXMLTree_node*)lastChunk; - if (nextNode() == BAD_DOCUMENT) { - mError = BAD_TYPE; - goto done; - } - mRootNode = mCurNode; - mRootExt = mCurExt; - mRootCode = mEventCode; - break; - } else { - XML_NOISY(printf("Skipping unknown chunk!\n")); - } - lastChunk = chunk; - chunk = (const ResChunk_header*) - (((const uint8_t*)chunk) + size); - } - - if (mRootNode == NULL) { - LOGW("Bad XML block: no root element node found\n"); - mError = BAD_TYPE; - goto done; - } - - mError = mStrings.getError(); - -done: - restart(); - return mError; -} - -status_t ResXMLTree::getError() const -{ - return mError; -} - -void ResXMLTree::uninit() -{ - mError = NO_INIT; - if (mOwnedData) { - free(mOwnedData); - mOwnedData = NULL; - } - restart(); -} - -const ResStringPool& ResXMLTree::getStrings() const -{ - return mStrings; -} - -status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const -{ - const uint16_t eventCode = dtohs(node->header.type); - - status_t err = validate_chunk( - &node->header, sizeof(ResXMLTree_node), - mDataEnd, "ResXMLTree_node"); - - if (err >= NO_ERROR) { - // Only perform additional validation on START nodes - if (eventCode != RES_XML_START_ELEMENT_TYPE) { - return NO_ERROR; - } - - const uint16_t headerSize = dtohs(node->header.headerSize); - const uint32_t size = dtohl(node->header.size); - const ResXMLTree_attrExt* attrExt = (const ResXMLTree_attrExt*) - (((const uint8_t*)node) + headerSize); - // check for sensical values pulled out of the stream so far... - if ((size >= headerSize + sizeof(ResXMLTree_attrExt)) - && ((void*)attrExt > (void*)node)) { - const size_t attrSize = ((size_t)dtohs(attrExt->attributeSize)) - * dtohs(attrExt->attributeCount); - if ((dtohs(attrExt->attributeStart)+attrSize) <= (size-headerSize)) { - return NO_ERROR; - } - LOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n", - (unsigned int)(dtohs(attrExt->attributeStart)+attrSize), - (unsigned int)(size-headerSize)); - } - else { - LOGW("Bad XML start block: node header size 0x%x, size 0x%x\n", - (unsigned int)headerSize, (unsigned int)size); - } - return BAD_TYPE; - } - - return err; - -#if 0 - const bool isStart = dtohs(node->header.type) == RES_XML_START_ELEMENT_TYPE; - - const uint16_t headerSize = dtohs(node->header.headerSize); - const uint32_t size = dtohl(node->header.size); - - if (headerSize >= (isStart ? sizeof(ResXMLTree_attrNode) : sizeof(ResXMLTree_node))) { - if (size >= headerSize) { - if (((const uint8_t*)node) <= (mDataEnd-size)) { - if (!isStart) { - return NO_ERROR; - } - if ((((size_t)dtohs(node->attributeSize))*dtohs(node->attributeCount)) - <= (size-headerSize)) { - return NO_ERROR; - } - LOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n", - ((int)dtohs(node->attributeSize))*dtohs(node->attributeCount), - (int)(size-headerSize)); - return BAD_TYPE; - } - LOGW("Bad XML block: node at 0x%x extends beyond data end 0x%x\n", - (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)), (int)mSize); - return BAD_TYPE; - } - LOGW("Bad XML block: node at 0x%x header size 0x%x smaller than total size 0x%x\n", - (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)), - (int)headerSize, (int)size); - return BAD_TYPE; - } - LOGW("Bad XML block: node at 0x%x header size 0x%x too small\n", - (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)), - (int)headerSize); - return BAD_TYPE; -#endif -} - -// -------------------------------------------------------------------- -// -------------------------------------------------------------------- -// -------------------------------------------------------------------- - -struct ResTable::Header -{ - Header() : ownedData(NULL), header(NULL) { } - - void* ownedData; - const ResTable_header* header; - size_t size; - const uint8_t* dataEnd; - size_t index; - void* cookie; - - ResStringPool values; -}; - -struct ResTable::Type -{ - Type(const Header* _header, const Package* _package, size_t count) - : header(_header), package(_package), entryCount(count), - typeSpec(NULL), typeSpecFlags(NULL) { } - const Header* const header; - const Package* const package; - const size_t entryCount; - const ResTable_typeSpec* typeSpec; - const uint32_t* typeSpecFlags; - Vector<const ResTable_type*> configs; -}; - -struct ResTable::Package -{ - Package(const Header* _header, const ResTable_package* _package) - : header(_header), package(_package) { } - ~Package() - { - size_t i = types.size(); - while (i > 0) { - i--; - delete types[i]; - } - } - - const Header* const header; - const ResTable_package* const package; - Vector<Type*> types; - - const Type* getType(size_t idx) const { - return idx < types.size() ? types[idx] : NULL; - } -}; - -// A group of objects describing a particular resource package. -// The first in 'package' is always the root object (from the resource -// table that defined the package); the ones after are skins on top of it. -struct ResTable::PackageGroup -{ - PackageGroup(const String16& _name, uint32_t _id) - : name(_name), id(_id), typeCount(0), bags(NULL) { } - ~PackageGroup() { - clearBagCache(); - const size_t N = packages.size(); - for (size_t i=0; i<N; i++) { - delete packages[i]; - } - } - - void clearBagCache() { - if (bags) { - TABLE_NOISY(printf("bags=%p\n", bags)); - Package* pkg = packages[0]; - TABLE_NOISY(printf("typeCount=%x\n", typeCount)); - for (size_t i=0; i<typeCount; i++) { - TABLE_NOISY(printf("type=%d\n", i)); - const Type* type = pkg->getType(i); - if (type != NULL) { - bag_set** typeBags = bags[i]; - TABLE_NOISY(printf("typeBags=%p\n", typeBags)); - if (typeBags) { - TABLE_NOISY(printf("type->entryCount=%x\n", type->entryCount)); - const size_t N = type->entryCount; - for (size_t j=0; j<N; j++) { - if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF) - free(typeBags[j]); - } - free(typeBags); - } - } - } - free(bags); - bags = NULL; - } - } - - String16 const name; - uint32_t const id; - Vector<Package*> packages; - - // Taken from the root package. - ResStringPool typeStrings; - ResStringPool keyStrings; - size_t typeCount; - - // Computed attribute bags, first indexed by the type and second - // by the entry in that type. - bag_set*** bags; -}; - -struct ResTable::bag_set -{ - size_t numAttrs; // number in array - size_t availAttrs; // total space in array - uint32_t typeSpecFlags; - // Followed by 'numAttr' bag_entry structures. -}; - -ResTable::Theme::Theme(const ResTable& table) - : mTable(table) -{ - memset(mPackages, 0, sizeof(mPackages)); -} - -ResTable::Theme::~Theme() -{ - for (size_t i=0; i<Res_MAXPACKAGE; i++) { - package_info* pi = mPackages[i]; - if (pi != NULL) { - free_package(pi); - } - } -} - -void ResTable::Theme::free_package(package_info* pi) -{ - for (size_t j=0; j<pi->numTypes; j++) { - theme_entry* te = pi->types[j].entries; - if (te != NULL) { - free(te); - } - } - free(pi); -} - -ResTable::Theme::package_info* ResTable::Theme::copy_package(package_info* pi) -{ - package_info* newpi = (package_info*)malloc( - sizeof(package_info) + (pi->numTypes*sizeof(type_info))); - newpi->numTypes = pi->numTypes; - for (size_t j=0; j<newpi->numTypes; j++) { - size_t cnt = pi->types[j].numEntries; - newpi->types[j].numEntries = cnt; - theme_entry* te = pi->types[j].entries; - if (te != NULL) { - theme_entry* newte = (theme_entry*)malloc(cnt*sizeof(theme_entry)); - newpi->types[j].entries = newte; - memcpy(newte, te, cnt*sizeof(theme_entry)); - } else { - newpi->types[j].entries = NULL; - } - } - return newpi; -} - -status_t ResTable::Theme::applyStyle(uint32_t resID, bool force) -{ - const bag_entry* bag; - uint32_t bagTypeSpecFlags = 0; - mTable.lock(); - const ssize_t N = mTable.getBagLocked(resID, &bag, &bagTypeSpecFlags); - TABLE_NOISY(LOGV("Applying style 0x%08x to theme %p, count=%d", resID, this, N)); - if (N < 0) { - mTable.unlock(); - return N; - } - - uint32_t curPackage = 0xffffffff; - ssize_t curPackageIndex = 0; - package_info* curPI = NULL; - uint32_t curType = 0xffffffff; - size_t numEntries = 0; - theme_entry* curEntries = NULL; - - const bag_entry* end = bag + N; - while (bag < end) { - const uint32_t attrRes = bag->map.name.ident; - const uint32_t p = Res_GETPACKAGE(attrRes); - const uint32_t t = Res_GETTYPE(attrRes); - const uint32_t e = Res_GETENTRY(attrRes); - - if (curPackage != p) { - const ssize_t pidx = mTable.getResourcePackageIndex(attrRes); - if (pidx < 0) { - LOGE("Style contains key with bad package: 0x%08x\n", attrRes); - bag++; - continue; - } - curPackage = p; - curPackageIndex = pidx; - curPI = mPackages[pidx]; - if (curPI == NULL) { - PackageGroup* const grp = mTable.mPackageGroups[pidx]; - int cnt = grp->typeCount; - curPI = (package_info*)malloc( - sizeof(package_info) + (cnt*sizeof(type_info))); - curPI->numTypes = cnt; - memset(curPI->types, 0, cnt*sizeof(type_info)); - mPackages[pidx] = curPI; - } - curType = 0xffffffff; - } - if (curType != t) { - if (t >= curPI->numTypes) { - LOGE("Style contains key with bad type: 0x%08x\n", attrRes); - bag++; - continue; - } - curType = t; - curEntries = curPI->types[t].entries; - if (curEntries == NULL) { - PackageGroup* const grp = mTable.mPackageGroups[curPackageIndex]; - const Type* type = grp->packages[0]->getType(t); - int cnt = type != NULL ? type->entryCount : 0; - curEntries = (theme_entry*)malloc(cnt*sizeof(theme_entry)); - memset(curEntries, Res_value::TYPE_NULL, cnt*sizeof(theme_entry)); - curPI->types[t].numEntries = cnt; - curPI->types[t].entries = curEntries; - } - numEntries = curPI->types[t].numEntries; - } - if (e >= numEntries) { - LOGE("Style contains key with bad entry: 0x%08x\n", attrRes); - bag++; - continue; - } - theme_entry* curEntry = curEntries + e; - TABLE_NOISY(LOGV("Attr 0x%08x: type=0x%x, data=0x%08x; curType=0x%x", - attrRes, bag->map.value.dataType, bag->map.value.data, - curEntry->value.dataType)); - if (force || curEntry->value.dataType == Res_value::TYPE_NULL) { - curEntry->stringBlock = bag->stringBlock; - curEntry->typeSpecFlags |= bagTypeSpecFlags; - curEntry->value = bag->map.value; - } - - bag++; - } - - mTable.unlock(); - - //LOGI("Applying style 0x%08x (force=%d) theme %p...\n", resID, force, this); - //dumpToLog(); - - return NO_ERROR; -} - -status_t ResTable::Theme::setTo(const Theme& other) -{ - //LOGI("Setting theme %p from theme %p...\n", this, &other); - //dumpToLog(); - //other.dumpToLog(); - - if (&mTable == &other.mTable) { - for (size_t i=0; i<Res_MAXPACKAGE; i++) { - if (mPackages[i] != NULL) { - free_package(mPackages[i]); - } - if (other.mPackages[i] != NULL) { - mPackages[i] = copy_package(other.mPackages[i]); - } else { - mPackages[i] = NULL; - } - } - } else { - // @todo: need to really implement this, not just copy - // the system package (which is still wrong because it isn't - // fixing up resource references). - for (size_t i=0; i<Res_MAXPACKAGE; i++) { - if (mPackages[i] != NULL) { - free_package(mPackages[i]); - } - if (i == 0 && other.mPackages[i] != NULL) { - mPackages[i] = copy_package(other.mPackages[i]); - } else { - mPackages[i] = NULL; - } - } - } - - //LOGI("Final theme:"); - //dumpToLog(); - - return NO_ERROR; -} - -ssize_t ResTable::Theme::getAttribute(uint32_t resID, Res_value* outValue, - uint32_t* outTypeSpecFlags) const -{ - int cnt = 20; - - if (outTypeSpecFlags != NULL) *outTypeSpecFlags = 0; - - do { - const ssize_t p = mTable.getResourcePackageIndex(resID); - const uint32_t t = Res_GETTYPE(resID); - const uint32_t e = Res_GETENTRY(resID); - - TABLE_NOISY(LOGV("Looking up attr 0x%08x in theme %p", resID, this)); - - if (p >= 0) { - const package_info* const pi = mPackages[p]; - if (pi != NULL) { - if (t < pi->numTypes) { - const type_info& ti = pi->types[t]; - if (e < ti.numEntries) { - const theme_entry& te = ti.entries[e]; - if (outTypeSpecFlags != NULL) { - *outTypeSpecFlags |= te.typeSpecFlags; - } - const uint8_t type = te.value.dataType; - if (type == Res_value::TYPE_ATTRIBUTE) { - if (cnt > 0) { - cnt--; - resID = te.value.data; - continue; - } - LOGW("Too many attribute references, stopped at: 0x%08x\n", resID); - return BAD_INDEX; - } else if (type != Res_value::TYPE_NULL) { - *outValue = te.value; - return te.stringBlock; - } - return BAD_INDEX; - } - } - } - } - break; - - } while (true); - - return BAD_INDEX; -} - -ssize_t ResTable::Theme::resolveAttributeReference(Res_value* inOutValue, - ssize_t blockIndex, uint32_t* outLastRef, - uint32_t* inoutTypeSpecFlags) const -{ - //printf("Resolving type=0x%x\n", inOutValue->dataType); - if (inOutValue->dataType == Res_value::TYPE_ATTRIBUTE) { - uint32_t newTypeSpecFlags; - blockIndex = getAttribute(inOutValue->data, inOutValue, &newTypeSpecFlags); - if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newTypeSpecFlags; - //printf("Retrieved attribute new type=0x%x\n", inOutValue->dataType); - if (blockIndex < 0) { - return blockIndex; - } - } - return mTable.resolveReference(inOutValue, blockIndex, outLastRef); -} - -void ResTable::Theme::dumpToLog() const -{ - LOGI("Theme %p:\n", this); - for (size_t i=0; i<Res_MAXPACKAGE; i++) { - package_info* pi = mPackages[i]; - if (pi == NULL) continue; - - LOGI(" Package #0x%02x:\n", (int)(i+1)); - for (size_t j=0; j<pi->numTypes; j++) { - type_info& ti = pi->types[j]; - if (ti.numEntries == 0) continue; - - LOGI(" Type #0x%02x:\n", (int)(j+1)); - for (size_t k=0; k<ti.numEntries; k++) { - theme_entry& te = ti.entries[k]; - if (te.value.dataType == Res_value::TYPE_NULL) continue; - LOGI(" 0x%08x: t=0x%x, d=0x%08x (block=%d)\n", - (int)Res_MAKEID(i, j, k), - te.value.dataType, (int)te.value.data, (int)te.stringBlock); - } - } - } -} - -ResTable::ResTable() - : mError(NO_INIT) -{ - memset(&mParams, 0, sizeof(mParams)); - memset(mPackageMap, 0, sizeof(mPackageMap)); - //LOGI("Creating ResTable %p\n", this); -} - -ResTable::ResTable(const void* data, size_t size, void* cookie, bool copyData) - : mError(NO_INIT) -{ - memset(&mParams, 0, sizeof(mParams)); - memset(mPackageMap, 0, sizeof(mPackageMap)); - add(data, size, cookie, copyData); - LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table"); - //LOGI("Creating ResTable %p\n", this); -} - -ResTable::~ResTable() -{ - //LOGI("Destroying ResTable in %p\n", this); - uninit(); -} - -inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const -{ - return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1; -} - -status_t ResTable::add(const void* data, size_t size, void* cookie, bool copyData) -{ - return add(data, size, cookie, NULL, copyData); -} - -status_t ResTable::add(Asset* asset, void* cookie, bool copyData) -{ - const void* data = asset->getBuffer(true); - if (data == NULL) { - LOGW("Unable to get buffer of resource asset file"); - return UNKNOWN_ERROR; - } - size_t size = (size_t)asset->getLength(); - return add(data, size, cookie, asset, copyData); -} - -status_t ResTable::add(const void* data, size_t size, void* cookie, - Asset* asset, bool copyData) -{ - if (!data) return NO_ERROR; - Header* header = new Header; - header->index = mHeaders.size(); - header->cookie = cookie; - mHeaders.add(header); - - const bool notDeviceEndian = htods(0xf0) != 0xf0; - - LOAD_TABLE_NOISY( - LOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%p, asset=%p, copy=%d\n", - data, size, cookie, asset, copyData)); - - if (copyData || notDeviceEndian) { - header->ownedData = malloc(size); - if (header->ownedData == NULL) { - return (mError=NO_MEMORY); - } - memcpy(header->ownedData, data, size); - data = header->ownedData; - } - - header->header = (const ResTable_header*)data; - header->size = dtohl(header->header->header.size); - //LOGI("Got size 0x%x, again size 0x%x, raw size 0x%x\n", header->size, - // dtohl(header->header->header.size), header->header->header.size); - LOAD_TABLE_NOISY(LOGV("Loading ResTable @%p:\n", header->header)); - LOAD_TABLE_NOISY(printHexData(2, header->header, header->size < 256 ? header->size : 256, - 16, 16, 0, false, printToLogFunc)); - if (dtohs(header->header->header.headerSize) > header->size - || header->size > size) { - LOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n", - (int)dtohs(header->header->header.headerSize), - (int)header->size, (int)size); - return (mError=BAD_TYPE); - } - if (((dtohs(header->header->header.headerSize)|header->size)&0x3) != 0) { - LOGW("Bad resource table: header size 0x%x or total size 0x%x is not on an integer boundary\n", - (int)dtohs(header->header->header.headerSize), - (int)header->size); - return (mError=BAD_TYPE); - } - header->dataEnd = ((const uint8_t*)header->header) + header->size; - - // Iterate through all chunks. - size_t curPackage = 0; - - const ResChunk_header* chunk = - (const ResChunk_header*)(((const uint8_t*)header->header) - + dtohs(header->header->header.headerSize)); - while (((const uint8_t*)chunk) <= (header->dataEnd-sizeof(ResChunk_header)) && - ((const uint8_t*)chunk) <= (header->dataEnd-dtohl(chunk->size))) { - status_t err = validate_chunk(chunk, sizeof(ResChunk_header), header->dataEnd, "ResTable"); - if (err != NO_ERROR) { - return (mError=err); - } - TABLE_NOISY(LOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n", - dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size), - (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)))); - const size_t csize = dtohl(chunk->size); - const uint16_t ctype = dtohs(chunk->type); - if (ctype == RES_STRING_POOL_TYPE) { - if (header->values.getError() != NO_ERROR) { - // Only use the first string chunk; ignore any others that - // may appear. - status_t err = header->values.setTo(chunk, csize); - if (err != NO_ERROR) { - return (mError=err); - } - } else { - LOGW("Multiple string chunks found in resource table."); - } - } else if (ctype == RES_TABLE_PACKAGE_TYPE) { - if (curPackage >= dtohl(header->header->packageCount)) { - LOGW("More package chunks were found than the %d declared in the header.", - dtohl(header->header->packageCount)); - return (mError=BAD_TYPE); - } - if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) { - return mError; - } - curPackage++; - } else { - LOGW("Unknown chunk type %p in table at %p.\n", - (void*)(int)(ctype), - (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))); - } - chunk = (const ResChunk_header*) - (((const uint8_t*)chunk) + csize); - } - - if (curPackage < dtohl(header->header->packageCount)) { - LOGW("Fewer package chunks (%d) were found than the %d declared in the header.", - (int)curPackage, dtohl(header->header->packageCount)); - return (mError=BAD_TYPE); - } - mError = header->values.getError(); - if (mError != NO_ERROR) { - LOGW("No string values found in resource table!"); - } - TABLE_NOISY(LOGV("Returning from add with mError=%d\n", mError)); - return mError; -} - -status_t ResTable::getError() const -{ - return mError; -} - -void ResTable::uninit() -{ - mError = NO_INIT; - size_t N = mPackageGroups.size(); - for (size_t i=0; i<N; i++) { - PackageGroup* g = mPackageGroups[i]; - delete g; - } - N = mHeaders.size(); - for (size_t i=0; i<N; i++) { - Header* header = mHeaders[i]; - if (header->ownedData) { - free(header->ownedData); - } - delete header; - } - - mPackageGroups.clear(); - mHeaders.clear(); -} - -bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const -{ - if (mError != NO_ERROR) { - return false; - } - - const ssize_t p = getResourcePackageIndex(resID); - const int t = Res_GETTYPE(resID); - const int e = Res_GETENTRY(resID); - - if (p < 0) { - LOGW("No package identifier when getting name for resource number 0x%08x", resID); - return false; - } - if (t < 0) { - LOGW("No type identifier when getting name for resource number 0x%08x", resID); - return false; - } - - const PackageGroup* const grp = mPackageGroups[p]; - if (grp == NULL) { - LOGW("Bad identifier when getting name for resource number 0x%08x", resID); - return false; - } - if (grp->packages.size() > 0) { - const Package* const package = grp->packages[0]; - - const ResTable_type* type; - const ResTable_entry* entry; - ssize_t offset = getEntry(package, t, e, NULL, &type, &entry, NULL); - if (offset <= 0) { - return false; - } - - outName->package = grp->name.string(); - outName->packageLen = grp->name.size(); - outName->type = grp->typeStrings.stringAt(t, &outName->typeLen); - outName->name = grp->keyStrings.stringAt( - dtohl(entry->key.index), &outName->nameLen); - return true; - } - - return false; -} - -ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag, - uint32_t* outSpecFlags, ResTable_config* outConfig) const -{ - if (mError != NO_ERROR) { - return mError; - } - - const ssize_t p = getResourcePackageIndex(resID); - const int t = Res_GETTYPE(resID); - const int e = Res_GETENTRY(resID); - - if (p < 0) { - LOGW("No package identifier when getting value for resource number 0x%08x", resID); - return BAD_INDEX; - } - if (t < 0) { - LOGW("No type identifier when getting value for resource number 0x%08x", resID); - return BAD_INDEX; - } - - const Res_value* bestValue = NULL; - const Package* bestPackage = NULL; - ResTable_config bestItem; - memset(&bestItem, 0, sizeof(bestItem)); // make the compiler shut up - - if (outSpecFlags != NULL) *outSpecFlags = 0; - - // Look through all resource packages, starting with the most - // recently added. - const PackageGroup* const grp = mPackageGroups[p]; - if (grp == NULL) { - LOGW("Bad identifier when getting value for resource number 0x%08x", resID); - return false; - } - size_t ip = grp->packages.size(); - while (ip > 0) { - ip--; - - const Package* const package = grp->packages[ip]; - - const ResTable_type* type; - const ResTable_entry* entry; - const Type* typeClass; - ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass); - if (offset <= 0) { - if (offset < 0) { - LOGW("Failure getting entry for 0x%08x (t=%d e=%d) in package %d: 0x%08x\n", - resID, t, e, (int)ip, (int)offset); - return offset; - } - continue; - } - - if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) != 0) { - if (!mayBeBag) { - LOGW("Requesting resource %p failed because it is complex\n", - (void*)resID); - } - continue; - } - - TABLE_NOISY(aout << "Resource type data: " - << HexDump(type, dtohl(type->header.size)) << endl); - - if ((size_t)offset > (dtohl(type->header.size)-sizeof(Res_value))) { - LOGW("ResTable_item at %d is beyond type chunk data %d", - (int)offset, dtohl(type->header.size)); - return BAD_TYPE; - } - - const Res_value* item = - (const Res_value*)(((const uint8_t*)type) + offset); - ResTable_config thisConfig; - thisConfig.copyFromDtoH(type->config); - - if (outSpecFlags != NULL) { - if (typeClass->typeSpecFlags != NULL) { - *outSpecFlags |= dtohl(typeClass->typeSpecFlags[e]); - } else { - *outSpecFlags = -1; - } - } - - if (bestPackage != NULL && bestItem.isBetterThan(thisConfig)) { - continue; - } - - bestItem = thisConfig; - bestValue = item; - bestPackage = package; - } - - TABLE_NOISY(printf("Found result: package %p\n", bestPackage)); - - if (bestValue) { - outValue->size = dtohs(bestValue->size); - outValue->res0 = bestValue->res0; - outValue->dataType = bestValue->dataType; - outValue->data = dtohl(bestValue->data); - if (outConfig != NULL) { - *outConfig = bestItem; - } - TABLE_NOISY(size_t len; - printf("Found value: pkg=%d, type=%d, str=%s, int=%d\n", - bestPackage->header->index, - outValue->dataType, - outValue->dataType == bestValue->TYPE_STRING - ? String8(bestPackage->header->values.stringAt( - outValue->data, &len)).string() - : "", - outValue->data)); - return bestPackage->header->index; - } - - return BAD_INDEX; -} - -ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex, - uint32_t* outLastRef, uint32_t* inoutTypeSpecFlags) const -{ - int count=0; - while (blockIndex >= 0 && value->dataType == value->TYPE_REFERENCE - && value->data != 0 && count < 20) { - if (outLastRef) *outLastRef = value->data; - uint32_t lastRef = value->data; - uint32_t newFlags = 0; - const ssize_t newIndex = getResource(value->data, value, true, &newFlags); - //LOGI("Resolving reference d=%p: newIndex=%d, t=0x%02x, d=%p\n", - // (void*)lastRef, (int)newIndex, (int)value->dataType, (void*)value->data); - //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex); - if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newFlags; - if (newIndex < 0) { - // This can fail if the resource being referenced is a style... - // in this case, just return the reference, and expect the - // caller to deal with. - return blockIndex; - } - blockIndex = newIndex; - count++; - } - return blockIndex; -} - -const char16_t* ResTable::valueToString( - const Res_value* value, size_t stringBlock, - char16_t tmpBuffer[TMP_BUFFER_SIZE], size_t* outLen) -{ - if (!value) { - return NULL; - } - if (value->dataType == value->TYPE_STRING) { - return getTableStringBlock(stringBlock)->stringAt(value->data, outLen); - } - // XXX do int to string conversions. - return NULL; -} - -ssize_t ResTable::lockBag(uint32_t resID, const bag_entry** outBag) const -{ - mLock.lock(); - ssize_t err = getBagLocked(resID, outBag); - if (err < NO_ERROR) { - //printf("*** get failed! unlocking\n"); - mLock.unlock(); - } - return err; -} - -void ResTable::unlockBag(const bag_entry* bag) const -{ - //printf("<<< unlockBag %p\n", this); - mLock.unlock(); -} - -void ResTable::lock() const -{ - mLock.lock(); -} - -void ResTable::unlock() const -{ - mLock.unlock(); -} - -ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag, - uint32_t* outTypeSpecFlags) const -{ - if (mError != NO_ERROR) { - return mError; - } - - const ssize_t p = getResourcePackageIndex(resID); - const int t = Res_GETTYPE(resID); - const int e = Res_GETENTRY(resID); - - if (p < 0) { - LOGW("Invalid package identifier when getting bag for resource number 0x%08x", resID); - return BAD_INDEX; - } - if (t < 0) { - LOGW("No type identifier when getting bag for resource number 0x%08x", resID); - return BAD_INDEX; - } - - //printf("Get bag: id=0x%08x, p=%d, t=%d\n", resID, p, t); - PackageGroup* const grp = mPackageGroups[p]; - if (grp == NULL) { - LOGW("Bad identifier when getting bag for resource number 0x%08x", resID); - return false; - } - - if (t >= (int)grp->typeCount) { - LOGW("Type identifier 0x%x is larger than type count 0x%x", - t+1, (int)grp->typeCount); - return BAD_INDEX; - } - - const Package* const basePackage = grp->packages[0]; - - const Type* const typeConfigs = basePackage->getType(t); - - const size_t NENTRY = typeConfigs->entryCount; - if (e >= (int)NENTRY) { - LOGW("Entry identifier 0x%x is larger than entry count 0x%x", - e, (int)typeConfigs->entryCount); - return BAD_INDEX; - } - - // First see if we've already computed this bag... - if (grp->bags) { - bag_set** typeSet = grp->bags[t]; - if (typeSet) { - bag_set* set = typeSet[e]; - if (set) { - if (set != (bag_set*)0xFFFFFFFF) { - if (outTypeSpecFlags != NULL) { - *outTypeSpecFlags = set->typeSpecFlags; - } - *outBag = (bag_entry*)(set+1); - //LOGI("Found existing bag for: %p\n", (void*)resID); - return set->numAttrs; - } - LOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.", - resID); - return BAD_INDEX; - } - } - } - - // Bag not found, we need to compute it! - if (!grp->bags) { - grp->bags = (bag_set***)malloc(sizeof(bag_set*)*grp->typeCount); - if (!grp->bags) return NO_MEMORY; - memset(grp->bags, 0, sizeof(bag_set*)*grp->typeCount); - } - - bag_set** typeSet = grp->bags[t]; - if (!typeSet) { - typeSet = (bag_set**)malloc(sizeof(bag_set*)*NENTRY); - if (!typeSet) return NO_MEMORY; - memset(typeSet, 0, sizeof(bag_set*)*NENTRY); - grp->bags[t] = typeSet; - } - - // Mark that we are currently working on this one. - typeSet[e] = (bag_set*)0xFFFFFFFF; - - // This is what we are building. - bag_set* set = NULL; - - TABLE_NOISY(LOGI("Building bag: %p\n", (void*)resID)); - - // Now collect all bag attributes from all packages. - size_t ip = grp->packages.size(); - while (ip > 0) { - ip--; - - const Package* const package = grp->packages[ip]; - - const ResTable_type* type; - const ResTable_entry* entry; - const Type* typeClass; - LOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, t, e); - ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass); - LOGV("Resulting offset=%d\n", offset); - if (offset <= 0) { - if (offset < 0) { - if (set) free(set); - return offset; - } - continue; - } - - if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) == 0) { - LOGW("Skipping entry %p in package table %d because it is not complex!\n", - (void*)resID, (int)ip); - continue; - } - - const uint16_t entrySize = dtohs(entry->size); - const uint32_t parent = entrySize >= sizeof(ResTable_map_entry) - ? dtohl(((const ResTable_map_entry*)entry)->parent.ident) : 0; - const uint32_t count = entrySize >= sizeof(ResTable_map_entry) - ? dtohl(((const ResTable_map_entry*)entry)->count) : 0; - - size_t N = count; - - TABLE_NOISY(LOGI("Found map: size=%p parent=%p count=%d\n", - entrySize, parent, count)); - - if (set == NULL) { - // If this map inherits from another, we need to start - // with its parent's values. Otherwise start out empty. - TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n", - entrySize, parent)); - if (parent) { - const bag_entry* parentBag; - uint32_t parentTypeSpecFlags = 0; - const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags); - const size_t NT = ((NP >= 0) ? NP : 0) + N; - set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT); - if (set == NULL) { - return NO_MEMORY; - } - if (NP > 0) { - memcpy(set+1, parentBag, NP*sizeof(bag_entry)); - set->numAttrs = NP; - TABLE_NOISY(LOGI("Initialized new bag with %d inherited attributes.\n", NP)); - } else { - TABLE_NOISY(LOGI("Initialized new bag with no inherited attributes.\n")); - set->numAttrs = 0; - } - set->availAttrs = NT; - set->typeSpecFlags = parentTypeSpecFlags; - } else { - set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N); - if (set == NULL) { - return NO_MEMORY; - } - set->numAttrs = 0; - set->availAttrs = N; - set->typeSpecFlags = 0; - } - } - - if (typeClass->typeSpecFlags != NULL) { - set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[e]); - } else { - set->typeSpecFlags = -1; - } - - // Now merge in the new attributes... - ssize_t curOff = offset; - const ResTable_map* map; - bag_entry* entries = (bag_entry*)(set+1); - size_t curEntry = 0; - uint32_t pos = 0; - TABLE_NOISY(LOGI("Starting with set %p, entries=%p, avail=%d\n", - set, entries, set->availAttrs)); - while (pos < count) { - TABLE_NOISY(printf("Now at %p\n", (void*)curOff)); - - if ((size_t)curOff > (dtohl(type->header.size)-sizeof(ResTable_map))) { - LOGW("ResTable_map at %d is beyond type chunk data %d", - (int)curOff, dtohl(type->header.size)); - return BAD_TYPE; - } - map = (const ResTable_map*)(((const uint8_t*)type) + curOff); - N++; - - const uint32_t newName = htodl(map->name.ident); - bool isInside; - uint32_t oldName = 0; - while ((isInside=(curEntry < set->numAttrs)) - && (oldName=entries[curEntry].map.name.ident) < newName) { - TABLE_NOISY(printf("#%d: Keeping existing attribute: 0x%08x\n", - curEntry, entries[curEntry].map.name.ident)); - curEntry++; - } - - if ((!isInside) || oldName != newName) { - // This is a new attribute... figure out what to do with it. - if (set->numAttrs >= set->availAttrs) { - // Need to alloc more memory... - const size_t newAvail = set->availAttrs+N; - set = (bag_set*)realloc(set, - sizeof(bag_set) - + sizeof(bag_entry)*newAvail); - if (set == NULL) { - return NO_MEMORY; - } - set->availAttrs = newAvail; - entries = (bag_entry*)(set+1); - TABLE_NOISY(printf("Reallocated set %p, entries=%p, avail=%d\n", - set, entries, set->availAttrs)); - } - if (isInside) { - // Going in the middle, need to make space. - memmove(entries+curEntry+1, entries+curEntry, - sizeof(bag_entry)*(set->numAttrs-curEntry)); - set->numAttrs++; - } - TABLE_NOISY(printf("#%d: Inserting new attribute: 0x%08x\n", - curEntry, newName)); - } else { - TABLE_NOISY(printf("#%d: Replacing existing attribute: 0x%08x\n", - curEntry, oldName)); - } - - bag_entry* cur = entries+curEntry; - - cur->stringBlock = package->header->index; - cur->map.name.ident = newName; - cur->map.value.copyFrom_dtoh(map->value); - TABLE_NOISY(printf("Setting entry #%d %p: block=%d, name=0x%08x, type=%d, data=0x%08x\n", - curEntry, cur, cur->stringBlock, cur->map.name.ident, - cur->map.value.dataType, cur->map.value.data)); - - // On to the next! - curEntry++; - pos++; - const size_t size = dtohs(map->value.size); - curOff += size + sizeof(*map)-sizeof(map->value); - }; - if (curEntry > set->numAttrs) { - set->numAttrs = curEntry; - } - } - - // And this is it... - typeSet[e] = set; - if (set) { - if (outTypeSpecFlags != NULL) { - *outTypeSpecFlags = set->typeSpecFlags; - } - *outBag = (bag_entry*)(set+1); - TABLE_NOISY(LOGI("Returning %d attrs\n", set->numAttrs)); - return set->numAttrs; - } - return BAD_INDEX; -} - -void ResTable::setParameters(const ResTable_config* params) -{ - mLock.lock(); - TABLE_GETENTRY(LOGI("Setting parameters: imsi:%d/%d lang:%c%c cnt:%c%c " - "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n", - params->mcc, params->mnc, - params->language[0] ? params->language[0] : '-', - params->language[1] ? params->language[1] : '-', - params->country[0] ? params->country[0] : '-', - params->country[1] ? params->country[1] : '-', - params->orientation, - params->touchscreen, - params->density, - params->keyboard, - params->inputFlags, - params->navigation, - params->screenWidth, - params->screenHeight)); - mParams = *params; - for (size_t i=0; i<mPackageGroups.size(); i++) { - TABLE_NOISY(LOGI("CLEARING BAGS FOR GROUP %d!", i)); - mPackageGroups[i]->clearBagCache(); - } - mLock.unlock(); -} - -void ResTable::getParameters(ResTable_config* params) const -{ - mLock.lock(); - *params = mParams; - mLock.unlock(); -} - -struct id_name_map { - uint32_t id; - size_t len; - char16_t name[6]; -}; - -const static id_name_map ID_NAMES[] = { - { ResTable_map::ATTR_TYPE, 5, { '^', 't', 'y', 'p', 'e' } }, - { ResTable_map::ATTR_L10N, 5, { '^', 'l', '1', '0', 'n' } }, - { ResTable_map::ATTR_MIN, 4, { '^', 'm', 'i', 'n' } }, - { ResTable_map::ATTR_MAX, 4, { '^', 'm', 'a', 'x' } }, - { ResTable_map::ATTR_OTHER, 6, { '^', 'o', 't', 'h', 'e', 'r' } }, - { ResTable_map::ATTR_ZERO, 5, { '^', 'z', 'e', 'r', 'o' } }, - { ResTable_map::ATTR_ONE, 4, { '^', 'o', 'n', 'e' } }, - { ResTable_map::ATTR_TWO, 4, { '^', 't', 'w', 'o' } }, - { ResTable_map::ATTR_FEW, 4, { '^', 'f', 'e', 'w' } }, - { ResTable_map::ATTR_MANY, 5, { '^', 'm', 'a', 'n', 'y' } }, -}; - -uint32_t ResTable::identifierForName(const char16_t* name, size_t nameLen, - const char16_t* type, size_t typeLen, - const char16_t* package, - size_t packageLen, - uint32_t* outTypeSpecFlags) const -{ - TABLE_SUPER_NOISY(printf("Identifier for name: error=%d\n", mError)); - - // Check for internal resource identifier as the very first thing, so - // that we will always find them even when there are no resources. - if (name[0] == '^') { - const int N = (sizeof(ID_NAMES)/sizeof(ID_NAMES[0])); - size_t len; - for (int i=0; i<N; i++) { - const id_name_map* m = ID_NAMES + i; - len = m->len; - if (len != nameLen) { - continue; - } - for (size_t j=1; j<len; j++) { - if (m->name[j] != name[j]) { - goto nope; - } - } - return m->id; -nope: - ; - } - if (nameLen > 7) { - if (name[1] == 'i' && name[2] == 'n' - && name[3] == 'd' && name[4] == 'e' && name[5] == 'x' - && name[6] == '_') { - int index = atoi(String8(name + 7, nameLen - 7).string()); - if (Res_CHECKID(index)) { - LOGW("Array resource index: %d is too large.", - index); - return 0; - } - return Res_MAKEARRAY(index); - } - } - return 0; - } - - if (mError != NO_ERROR) { - return 0; - } - - // Figure out the package and type we are looking in... - - const char16_t* packageEnd = NULL; - const char16_t* typeEnd = NULL; - const char16_t* const nameEnd = name+nameLen; - const char16_t* p = name; - while (p < nameEnd) { - if (*p == ':') packageEnd = p; - else if (*p == '/') typeEnd = p; - p++; - } - if (*name == '@') name++; - if (name >= nameEnd) { - return 0; - } - - if (packageEnd) { - package = name; - packageLen = packageEnd-name; - name = packageEnd+1; - } else if (!package) { - return 0; - } - - if (typeEnd) { - type = name; - typeLen = typeEnd-name; - name = typeEnd+1; - } else if (!type) { - return 0; - } - - if (name >= nameEnd) { - return 0; - } - nameLen = nameEnd-name; - - TABLE_NOISY(printf("Looking for identifier: type=%s, name=%s, package=%s\n", - String8(type, typeLen).string(), - String8(name, nameLen).string(), - String8(package, packageLen).string())); - - const size_t NG = mPackageGroups.size(); - for (size_t ig=0; ig<NG; ig++) { - const PackageGroup* group = mPackageGroups[ig]; - - if (strzcmp16(package, packageLen, - group->name.string(), group->name.size())) { - TABLE_NOISY(printf("Skipping package group: %s\n", String8(group->name).string())); - continue; - } - - const ssize_t ti = group->typeStrings.indexOfString(type, typeLen); - if (ti < 0) { - TABLE_NOISY(printf("Type not found in package %s\n", String8(group->name).string())); - continue; - } - - const ssize_t ei = group->keyStrings.indexOfString(name, nameLen); - if (ei < 0) { - TABLE_NOISY(printf("Name not found in package %s\n", String8(group->name).string())); - continue; - } - - TABLE_NOISY(printf("Search indices: type=%d, name=%d\n", ti, ei)); - - const Type* const typeConfigs = group->packages[0]->getType(ti); - if (typeConfigs == NULL || typeConfigs->configs.size() <= 0) { - TABLE_NOISY(printf("Expected type structure not found in package %s for idnex %d\n", - String8(group->name).string(), ti)); - } - - size_t NTC = typeConfigs->configs.size(); - for (size_t tci=0; tci<NTC; tci++) { - const ResTable_type* const ty = typeConfigs->configs[tci]; - const uint32_t typeOffset = dtohl(ty->entriesStart); - - const uint8_t* const end = ((const uint8_t*)ty) + dtohl(ty->header.size); - const uint32_t* const eindex = (const uint32_t*) - (((const uint8_t*)ty) + dtohs(ty->header.headerSize)); - - const size_t NE = dtohl(ty->entryCount); - for (size_t i=0; i<NE; i++) { - uint32_t offset = dtohl(eindex[i]); - if (offset == ResTable_type::NO_ENTRY) { - continue; - } - - offset += typeOffset; - - if (offset > (dtohl(ty->header.size)-sizeof(ResTable_entry))) { - LOGW("ResTable_entry at %d is beyond type chunk data %d", - offset, dtohl(ty->header.size)); - return 0; - } - if ((offset&0x3) != 0) { - LOGW("ResTable_entry at %d (pkg=%d type=%d ent=%d) is not on an integer boundary when looking for %s:%s/%s", - (int)offset, (int)group->id, (int)ti+1, (int)i, - String8(package, packageLen).string(), - String8(type, typeLen).string(), - String8(name, nameLen).string()); - return 0; - } - - const ResTable_entry* const entry = (const ResTable_entry*) - (((const uint8_t*)ty) + offset); - if (dtohs(entry->size) < sizeof(*entry)) { - LOGW("ResTable_entry size %d is too small", dtohs(entry->size)); - return BAD_TYPE; - } - - TABLE_SUPER_NOISY(printf("Looking at entry #%d: want str %d, have %d\n", - i, ei, dtohl(entry->key.index))); - if (dtohl(entry->key.index) == (size_t)ei) { - if (outTypeSpecFlags) { - *outTypeSpecFlags = typeConfigs->typeSpecFlags[i]; - } - return Res_MAKEID(group->id-1, ti, i); - } - } - } - } - - return 0; -} - -bool ResTable::expandResourceRef(const uint16_t* refStr, size_t refLen, - String16* outPackage, - String16* outType, - String16* outName, - const String16* defType, - const String16* defPackage, - const char** outErrorMsg) -{ - const char16_t* packageEnd = NULL; - const char16_t* typeEnd = NULL; - const char16_t* p = refStr; - const char16_t* const end = p + refLen; - while (p < end) { - if (*p == ':') packageEnd = p; - else if (*p == '/') { - typeEnd = p; - break; - } - p++; - } - p = refStr; - if (*p == '@') p++; - - if (packageEnd) { - *outPackage = String16(p, packageEnd-p); - p = packageEnd+1; - } else { - if (!defPackage) { - if (outErrorMsg) { - *outErrorMsg = "No resource package specified"; - } - return false; - } - *outPackage = *defPackage; - } - if (typeEnd) { - *outType = String16(p, typeEnd-p); - p = typeEnd+1; - } else { - if (!defType) { - if (outErrorMsg) { - *outErrorMsg = "No resource type specified"; - } - return false; - } - *outType = *defType; - } - *outName = String16(p, end-p); - return true; -} - -static uint32_t get_hex(char c, bool* outError) -{ - if (c >= '0' && c <= '9') { - return c - '0'; - } else if (c >= 'a' && c <= 'f') { - return c - 'a' + 0xa; - } else if (c >= 'A' && c <= 'F') { - return c - 'A' + 0xa; - } - *outError = true; - return 0; -} - -struct unit_entry -{ - const char* name; - size_t len; - uint8_t type; - uint32_t unit; - float scale; -}; - -static const unit_entry unitNames[] = { - { "px", strlen("px"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PX, 1.0f }, - { "dip", strlen("dip"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f }, - { "dp", strlen("dp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f }, - { "sp", strlen("sp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_SP, 1.0f }, - { "pt", strlen("pt"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PT, 1.0f }, - { "in", strlen("in"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_IN, 1.0f }, - { "mm", strlen("mm"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_MM, 1.0f }, - { "%", strlen("%"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION, 1.0f/100 }, - { "%p", strlen("%p"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION_PARENT, 1.0f/100 }, - { NULL, 0, 0, 0, 0 } -}; - -static bool parse_unit(const char* str, Res_value* outValue, - float* outScale, const char** outEnd) -{ - const char* end = str; - while (*end != 0 && !isspace((unsigned char)*end)) { - end++; - } - const size_t len = end-str; - - const char* realEnd = end; - while (*realEnd != 0 && isspace((unsigned char)*realEnd)) { - realEnd++; - } - if (*realEnd != 0) { - return false; - } - - const unit_entry* cur = unitNames; - while (cur->name) { - if (len == cur->len && strncmp(cur->name, str, len) == 0) { - outValue->dataType = cur->type; - outValue->data = cur->unit << Res_value::COMPLEX_UNIT_SHIFT; - *outScale = cur->scale; - *outEnd = end; - //printf("Found unit %s for %s\n", cur->name, str); - return true; - } - cur++; - } - - return false; -} - - -bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue) -{ - while (len > 0 && isspace16(*s)) { - s++; - len--; - } - - if (len <= 0) { - return false; - } - - size_t i = 0; - int32_t val = 0; - bool neg = false; - - if (*s == '-') { - neg = true; - i++; - } - - if (s[i] < '0' || s[i] > '9') { - return false; - } - - // Decimal or hex? - if (s[i] == '0' && s[i+1] == 'x') { - if (outValue) - outValue->dataType = outValue->TYPE_INT_HEX; - i += 2; - bool error = false; - while (i < len && !error) { - val = (val*16) + get_hex(s[i], &error); - i++; - } - if (error) { - return false; - } - } else { - if (outValue) - outValue->dataType = outValue->TYPE_INT_DEC; - while (i < len) { - if (s[i] < '0' || s[i] > '9') { - return false; - } - val = (val*10) + s[i]-'0'; - i++; - } - } - - if (neg) val = -val; - - while (i < len && isspace16(s[i])) { - i++; - } - - if (i == len) { - if (outValue) - outValue->data = val; - return true; - } - - return false; -} - -bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue) -{ - while (len > 0 && isspace16(*s)) { - s++; - len--; - } - - if (len <= 0) { - return false; - } - - char buf[128]; - int i=0; - while (len > 0 && *s != 0 && i < 126) { - if (*s > 255) { - return false; - } - buf[i++] = *s++; - len--; - } - - if (len > 0) { - return false; - } - if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') { - return false; - } - - buf[i] = 0; - const char* end; - float f = strtof(buf, (char**)&end); - - if (*end != 0 && !isspace((unsigned char)*end)) { - // Might be a unit... - float scale; - if (parse_unit(end, outValue, &scale, &end)) { - f *= scale; - const bool neg = f < 0; - if (neg) f = -f; - uint64_t bits = (uint64_t)(f*(1<<23)+.5f); - uint32_t radix; - uint32_t shift; - if ((bits&0x7fffff) == 0) { - // Always use 23p0 if there is no fraction, just to make - // things easier to read. - radix = Res_value::COMPLEX_RADIX_23p0; - shift = 23; - } else if ((bits&0xffffffffff800000LL) == 0) { - // Magnitude is zero -- can fit in 0 bits of precision. - radix = Res_value::COMPLEX_RADIX_0p23; - shift = 0; - } else if ((bits&0xffffffff80000000LL) == 0) { - // Magnitude can fit in 8 bits of precision. - radix = Res_value::COMPLEX_RADIX_8p15; - shift = 8; - } else if ((bits&0xffffff8000000000LL) == 0) { - // Magnitude can fit in 16 bits of precision. - radix = Res_value::COMPLEX_RADIX_16p7; - shift = 16; - } else { - // Magnitude needs entire range, so no fractional part. - radix = Res_value::COMPLEX_RADIX_23p0; - shift = 23; - } - int32_t mantissa = (int32_t)( - (bits>>shift) & Res_value::COMPLEX_MANTISSA_MASK); - if (neg) { - mantissa = (-mantissa) & Res_value::COMPLEX_MANTISSA_MASK; - } - outValue->data |= - (radix<<Res_value::COMPLEX_RADIX_SHIFT) - | (mantissa<<Res_value::COMPLEX_MANTISSA_SHIFT); - //printf("Input value: %f 0x%016Lx, mult: %f, radix: %d, shift: %d, final: 0x%08x\n", - // f * (neg ? -1 : 1), bits, f*(1<<23), - // radix, shift, outValue->data); - return true; - } - return false; - } - - while (*end != 0 && isspace((unsigned char)*end)) { - end++; - } - - if (*end == 0) { - if (outValue) { - outValue->dataType = outValue->TYPE_FLOAT; - *(float*)(&outValue->data) = f; - return true; - } - } - - return false; -} - -bool ResTable::stringToValue(Res_value* outValue, String16* outString, - const char16_t* s, size_t len, - bool preserveSpaces, bool coerceType, - uint32_t attrID, - const String16* defType, - const String16* defPackage, - Accessor* accessor, - void* accessorCookie, - uint32_t attrType, - bool enforcePrivate) const -{ - bool localizationSetting = accessor != NULL && accessor->getLocalizationSetting(); - const char* errorMsg = NULL; - - outValue->size = sizeof(Res_value); - outValue->res0 = 0; - - // First strip leading/trailing whitespace. Do this before handling - // escapes, so they can be used to force whitespace into the string. - if (!preserveSpaces) { - while (len > 0 && isspace16(*s)) { - s++; - len--; - } - while (len > 0 && isspace16(s[len-1])) { - len--; - } - // If the string ends with '\', then we keep the space after it. - if (len > 0 && s[len-1] == '\\' && s[len] != 0) { - len++; - } - } - - //printf("Value for: %s\n", String8(s, len).string()); - - uint32_t l10nReq = ResTable_map::L10N_NOT_REQUIRED; - uint32_t attrMin = 0x80000000, attrMax = 0x7fffffff; - bool fromAccessor = false; - if (attrID != 0 && !Res_INTERNALID(attrID)) { - const ssize_t p = getResourcePackageIndex(attrID); - const bag_entry* bag; - ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1; - //printf("For attr 0x%08x got bag of %d\n", attrID, cnt); - if (cnt >= 0) { - while (cnt > 0) { - //printf("Entry 0x%08x = 0x%08x\n", bag->map.name.ident, bag->map.value.data); - switch (bag->map.name.ident) { - case ResTable_map::ATTR_TYPE: - attrType = bag->map.value.data; - break; - case ResTable_map::ATTR_MIN: - attrMin = bag->map.value.data; - break; - case ResTable_map::ATTR_MAX: - attrMax = bag->map.value.data; - break; - case ResTable_map::ATTR_L10N: - l10nReq = bag->map.value.data; - break; - } - bag++; - cnt--; - } - unlockBag(bag); - } else if (accessor && accessor->getAttributeType(attrID, &attrType)) { - fromAccessor = true; - if (attrType == ResTable_map::TYPE_ENUM - || attrType == ResTable_map::TYPE_FLAGS - || attrType == ResTable_map::TYPE_INTEGER) { - accessor->getAttributeMin(attrID, &attrMin); - accessor->getAttributeMax(attrID, &attrMax); - } - if (localizationSetting) { - l10nReq = accessor->getAttributeL10N(attrID); - } - } - } - - const bool canStringCoerce = - coerceType && (attrType&ResTable_map::TYPE_STRING) != 0; - - if (*s == '@') { - outValue->dataType = outValue->TYPE_REFERENCE; - - // Note: we don't check attrType here because the reference can - // be to any other type; we just need to count on the client making - // sure the referenced type is correct. - - //printf("Looking up ref: %s\n", String8(s, len).string()); - - // It's a reference! - if (len == 5 && s[1]=='n' && s[2]=='u' && s[3]=='l' && s[4]=='l') { - outValue->data = 0; - return true; - } else { - bool createIfNotFound = false; - const char16_t* resourceRefName; - int resourceNameLen; - if (len > 2 && s[1] == '+') { - createIfNotFound = true; - resourceRefName = s + 2; - resourceNameLen = len - 2; - } else if (len > 2 && s[1] == '*') { - enforcePrivate = false; - resourceRefName = s + 2; - resourceNameLen = len - 2; - } else { - createIfNotFound = false; - resourceRefName = s + 1; - resourceNameLen = len - 1; - } - String16 package, type, name; - if (!expandResourceRef(resourceRefName,resourceNameLen, &package, &type, &name, - defType, defPackage, &errorMsg)) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, errorMsg); - } - return false; - } - - uint32_t specFlags = 0; - uint32_t rid = identifierForName(name.string(), name.size(), type.string(), - type.size(), package.string(), package.size(), &specFlags); - if (rid != 0) { - if (enforcePrivate) { - if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Resource is not public."); - } - return false; - } - } - if (!accessor) { - outValue->data = rid; - return true; - } - rid = Res_MAKEID( - accessor->getRemappedPackage(Res_GETPACKAGE(rid)), - Res_GETTYPE(rid), Res_GETENTRY(rid)); - TABLE_NOISY(printf("Incl %s:%s/%s: 0x%08x\n", - String8(package).string(), String8(type).string(), - String8(name).string(), rid)); - outValue->data = rid; - return true; - } - - if (accessor) { - uint32_t rid = accessor->getCustomResourceWithCreation(package, type, name, - createIfNotFound); - if (rid != 0) { - TABLE_NOISY(printf("Pckg %s:%s/%s: 0x%08x\n", - String8(package).string(), String8(type).string(), - String8(name).string(), rid)); - outValue->data = rid; - return true; - } - } - } - - if (accessor != NULL) { - accessor->reportError(accessorCookie, "No resource found that matches the given name"); - } - return false; - } - - // if we got to here, and localization is required and it's not a reference, - // complain and bail. - if (l10nReq == ResTable_map::L10N_SUGGESTED) { - if (localizationSetting) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "This attribute must be localized."); - } - } - } - - if (*s == '#') { - // It's a color! Convert to an integer of the form 0xaarrggbb. - uint32_t color = 0; - bool error = false; - if (len == 4) { - outValue->dataType = outValue->TYPE_INT_COLOR_RGB4; - color |= 0xFF000000; - color |= get_hex(s[1], &error) << 20; - color |= get_hex(s[1], &error) << 16; - color |= get_hex(s[2], &error) << 12; - color |= get_hex(s[2], &error) << 8; - color |= get_hex(s[3], &error) << 4; - color |= get_hex(s[3], &error); - } else if (len == 5) { - outValue->dataType = outValue->TYPE_INT_COLOR_ARGB4; - color |= get_hex(s[1], &error) << 28; - color |= get_hex(s[1], &error) << 24; - color |= get_hex(s[2], &error) << 20; - color |= get_hex(s[2], &error) << 16; - color |= get_hex(s[3], &error) << 12; - color |= get_hex(s[3], &error) << 8; - color |= get_hex(s[4], &error) << 4; - color |= get_hex(s[4], &error); - } else if (len == 7) { - outValue->dataType = outValue->TYPE_INT_COLOR_RGB8; - color |= 0xFF000000; - color |= get_hex(s[1], &error) << 20; - color |= get_hex(s[2], &error) << 16; - color |= get_hex(s[3], &error) << 12; - color |= get_hex(s[4], &error) << 8; - color |= get_hex(s[5], &error) << 4; - color |= get_hex(s[6], &error); - } else if (len == 9) { - outValue->dataType = outValue->TYPE_INT_COLOR_ARGB8; - color |= get_hex(s[1], &error) << 28; - color |= get_hex(s[2], &error) << 24; - color |= get_hex(s[3], &error) << 20; - color |= get_hex(s[4], &error) << 16; - color |= get_hex(s[5], &error) << 12; - color |= get_hex(s[6], &error) << 8; - color |= get_hex(s[7], &error) << 4; - color |= get_hex(s[8], &error); - } else { - error = true; - } - if (!error) { - if ((attrType&ResTable_map::TYPE_COLOR) == 0) { - if (!canStringCoerce) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, - "Color types not allowed"); - } - return false; - } - } else { - outValue->data = color; - //printf("Color input=%s, output=0x%x\n", String8(s, len).string(), color); - return true; - } - } else { - if ((attrType&ResTable_map::TYPE_COLOR) != 0) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Color value not valid --" - " must be #rgb, #argb, #rrggbb, or #aarrggbb"); - } - #if 0 - fprintf(stderr, "%s: Color ID %s value %s is not valid\n", - "Resource File", //(const char*)in->getPrintableSource(), - String8(*curTag).string(), - String8(s, len).string()); - #endif - return false; - } - } - } - - if (*s == '?') { - outValue->dataType = outValue->TYPE_ATTRIBUTE; - - // Note: we don't check attrType here because the reference can - // be to any other type; we just need to count on the client making - // sure the referenced type is correct. - - //printf("Looking up attr: %s\n", String8(s, len).string()); - - static const String16 attr16("attr"); - String16 package, type, name; - if (!expandResourceRef(s+1, len-1, &package, &type, &name, - &attr16, defPackage, &errorMsg)) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, errorMsg); - } - return false; - } - - //printf("Pkg: %s, Type: %s, Name: %s\n", - // String8(package).string(), String8(type).string(), - // String8(name).string()); - uint32_t specFlags = 0; - uint32_t rid = - identifierForName(name.string(), name.size(), - type.string(), type.size(), - package.string(), package.size(), &specFlags); - if (rid != 0) { - if (enforcePrivate) { - if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Attribute is not public."); - } - return false; - } - } - if (!accessor) { - outValue->data = rid; - return true; - } - rid = Res_MAKEID( - accessor->getRemappedPackage(Res_GETPACKAGE(rid)), - Res_GETTYPE(rid), Res_GETENTRY(rid)); - //printf("Incl %s:%s/%s: 0x%08x\n", - // String8(package).string(), String8(type).string(), - // String8(name).string(), rid); - outValue->data = rid; - return true; - } - - if (accessor) { - uint32_t rid = accessor->getCustomResource(package, type, name); - if (rid != 0) { - //printf("Mine %s:%s/%s: 0x%08x\n", - // String8(package).string(), String8(type).string(), - // String8(name).string(), rid); - outValue->data = rid; - return true; - } - } - - if (accessor != NULL) { - accessor->reportError(accessorCookie, "No resource found that matches the given name"); - } - return false; - } - - if (stringToInt(s, len, outValue)) { - if ((attrType&ResTable_map::TYPE_INTEGER) == 0) { - // If this type does not allow integers, but does allow floats, - // fall through on this error case because the float type should - // be able to accept any integer value. - if (!canStringCoerce && (attrType&ResTable_map::TYPE_FLOAT) == 0) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Integer types not allowed"); - } - return false; - } - } else { - if (((int32_t)outValue->data) < ((int32_t)attrMin) - || ((int32_t)outValue->data) > ((int32_t)attrMax)) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Integer value out of range"); - } - return false; - } - return true; - } - } - - if (stringToFloat(s, len, outValue)) { - if (outValue->dataType == Res_value::TYPE_DIMENSION) { - if ((attrType&ResTable_map::TYPE_DIMENSION) != 0) { - return true; - } - if (!canStringCoerce) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Dimension types not allowed"); - } - return false; - } - } else if (outValue->dataType == Res_value::TYPE_FRACTION) { - if ((attrType&ResTable_map::TYPE_FRACTION) != 0) { - return true; - } - if (!canStringCoerce) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Fraction types not allowed"); - } - return false; - } - } else if ((attrType&ResTable_map::TYPE_FLOAT) == 0) { - if (!canStringCoerce) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Float types not allowed"); - } - return false; - } - } else { - return true; - } - } - - if (len == 4) { - if ((s[0] == 't' || s[0] == 'T') && - (s[1] == 'r' || s[1] == 'R') && - (s[2] == 'u' || s[2] == 'U') && - (s[3] == 'e' || s[3] == 'E')) { - if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) { - if (!canStringCoerce) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Boolean types not allowed"); - } - return false; - } - } else { - outValue->dataType = outValue->TYPE_INT_BOOLEAN; - outValue->data = (uint32_t)-1; - return true; - } - } - } - - if (len == 5) { - if ((s[0] == 'f' || s[0] == 'F') && - (s[1] == 'a' || s[1] == 'A') && - (s[2] == 'l' || s[2] == 'L') && - (s[3] == 's' || s[3] == 'S') && - (s[4] == 'e' || s[4] == 'E')) { - if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) { - if (!canStringCoerce) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "Boolean types not allowed"); - } - return false; - } - } else { - outValue->dataType = outValue->TYPE_INT_BOOLEAN; - outValue->data = 0; - return true; - } - } - } - - if ((attrType&ResTable_map::TYPE_ENUM) != 0) { - const ssize_t p = getResourcePackageIndex(attrID); - const bag_entry* bag; - ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1; - //printf("Got %d for enum\n", cnt); - if (cnt >= 0) { - resource_name rname; - while (cnt > 0) { - if (!Res_INTERNALID(bag->map.name.ident)) { - //printf("Trying attr #%08x\n", bag->map.name.ident); - if (getResourceName(bag->map.name.ident, &rname)) { - #if 0 - printf("Matching %s against %s (0x%08x)\n", - String8(s, len).string(), - String8(rname.name, rname.nameLen).string(), - bag->map.name.ident); - #endif - if (strzcmp16(s, len, rname.name, rname.nameLen) == 0) { - outValue->dataType = bag->map.value.dataType; - outValue->data = bag->map.value.data; - unlockBag(bag); - return true; - } - } - - } - bag++; - cnt--; - } - unlockBag(bag); - } - - if (fromAccessor) { - if (accessor->getAttributeEnum(attrID, s, len, outValue)) { - return true; - } - } - } - - if ((attrType&ResTable_map::TYPE_FLAGS) != 0) { - const ssize_t p = getResourcePackageIndex(attrID); - const bag_entry* bag; - ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1; - //printf("Got %d for flags\n", cnt); - if (cnt >= 0) { - bool failed = false; - resource_name rname; - outValue->dataType = Res_value::TYPE_INT_HEX; - outValue->data = 0; - const char16_t* end = s + len; - const char16_t* pos = s; - while (pos < end && !failed) { - const char16_t* start = pos; - end++; - while (pos < end && *pos != '|') { - pos++; - } - //printf("Looking for: %s\n", String8(start, pos-start).string()); - const bag_entry* bagi = bag; - ssize_t i; - for (i=0; i<cnt; i++, bagi++) { - if (!Res_INTERNALID(bagi->map.name.ident)) { - //printf("Trying attr #%08x\n", bagi->map.name.ident); - if (getResourceName(bagi->map.name.ident, &rname)) { - #if 0 - printf("Matching %s against %s (0x%08x)\n", - String8(start,pos-start).string(), - String8(rname.name, rname.nameLen).string(), - bagi->map.name.ident); - #endif - if (strzcmp16(start, pos-start, rname.name, rname.nameLen) == 0) { - outValue->data |= bagi->map.value.data; - break; - } - } - } - } - if (i >= cnt) { - // Didn't find this flag identifier. - failed = true; - } - if (pos < end) { - pos++; - } - } - unlockBag(bag); - if (!failed) { - //printf("Final flag value: 0x%lx\n", outValue->data); - return true; - } - } - - - if (fromAccessor) { - if (accessor->getAttributeFlags(attrID, s, len, outValue)) { - //printf("Final flag value: 0x%lx\n", outValue->data); - return true; - } - } - } - - if ((attrType&ResTable_map::TYPE_STRING) == 0) { - if (accessor != NULL) { - accessor->reportError(accessorCookie, "String types not allowed"); - } - return false; - } - - // Generic string handling... - outValue->dataType = outValue->TYPE_STRING; - if (outString) { - bool failed = collectString(outString, s, len, preserveSpaces, &errorMsg); - if (accessor != NULL) { - accessor->reportError(accessorCookie, errorMsg); - } - return failed; - } - - return true; -} - -bool ResTable::collectString(String16* outString, - const char16_t* s, size_t len, - bool preserveSpaces, - const char** outErrorMsg, - bool append) -{ - String16 tmp; - - char quoted = 0; - const char16_t* p = s; - while (p < (s+len)) { - while (p < (s+len)) { - const char16_t c = *p; - if (c == '\\') { - break; - } - if (!preserveSpaces) { - if (quoted == 0 && isspace16(c) - && (c != ' ' || isspace16(*(p+1)))) { - break; - } - if (c == '"' && (quoted == 0 || quoted == '"')) { - break; - } - if (c == '\'' && (quoted == 0 || quoted == '\'')) { - break; - } - } - p++; - } - if (p < (s+len)) { - if (p > s) { - tmp.append(String16(s, p-s)); - } - if (!preserveSpaces && (*p == '"' || *p == '\'')) { - if (quoted == 0) { - quoted = *p; - } else { - quoted = 0; - } - p++; - } else if (!preserveSpaces && isspace16(*p)) { - // Space outside of a quote -- consume all spaces and - // leave a single plain space char. - tmp.append(String16(" ")); - p++; - while (p < (s+len) && isspace16(*p)) { - p++; - } - } else if (*p == '\\') { - p++; - if (p < (s+len)) { - switch (*p) { - case 't': - tmp.append(String16("\t")); - break; - case 'n': - tmp.append(String16("\n")); - break; - case '#': - tmp.append(String16("#")); - break; - case '@': - tmp.append(String16("@")); - break; - case '?': - tmp.append(String16("?")); - break; - case '"': - tmp.append(String16("\"")); - break; - case '\'': - tmp.append(String16("'")); - break; - case '\\': - tmp.append(String16("\\")); - break; - case 'u': - { - char16_t chr = 0; - int i = 0; - while (i < 4 && p[1] != 0) { - p++; - i++; - int c; - if (*p >= '0' && *p <= '9') { - c = *p - '0'; - } else if (*p >= 'a' && *p <= 'f') { - c = *p - 'a' + 10; - } else if (*p >= 'A' && *p <= 'F') { - c = *p - 'A' + 10; - } else { - if (outErrorMsg) { - *outErrorMsg = "Bad character in \\u unicode escape sequence"; - } - return false; - } - chr = (chr<<4) | c; - } - tmp.append(String16(&chr, 1)); - } break; - default: - // ignore unknown escape chars. - break; - } - p++; - } - } - len -= (p-s); - s = p; - } - } - - if (tmp.size() != 0) { - if (len > 0) { - tmp.append(String16(s, len)); - } - if (append) { - outString->append(tmp); - } else { - outString->setTo(tmp); - } - } else { - if (append) { - outString->append(String16(s, len)); - } else { - outString->setTo(s, len); - } - } - - return true; -} - -size_t ResTable::getBasePackageCount() const -{ - if (mError != NO_ERROR) { - return 0; - } - return mPackageGroups.size(); -} - -const char16_t* ResTable::getBasePackageName(size_t idx) const -{ - if (mError != NO_ERROR) { - return 0; - } - LOG_FATAL_IF(idx >= mPackageGroups.size(), - "Requested package index %d past package count %d", - (int)idx, (int)mPackageGroups.size()); - return mPackageGroups[idx]->name.string(); -} - -uint32_t ResTable::getBasePackageId(size_t idx) const -{ - if (mError != NO_ERROR) { - return 0; - } - LOG_FATAL_IF(idx >= mPackageGroups.size(), - "Requested package index %d past package count %d", - (int)idx, (int)mPackageGroups.size()); - return mPackageGroups[idx]->id; -} - -size_t ResTable::getTableCount() const -{ - return mHeaders.size(); -} - -const ResStringPool* ResTable::getTableStringBlock(size_t index) const -{ - return &mHeaders[index]->values; -} - -void* ResTable::getTableCookie(size_t index) const -{ - return mHeaders[index]->cookie; -} - -void ResTable::getConfigurations(Vector<ResTable_config>* configs) const -{ - const size_t I = mPackageGroups.size(); - for (size_t i=0; i<I; i++) { - const PackageGroup* packageGroup = mPackageGroups[i]; - const size_t J = packageGroup->packages.size(); - for (size_t j=0; j<J; j++) { - const Package* package = packageGroup->packages[j]; - const size_t K = package->types.size(); - for (size_t k=0; k<K; k++) { - const Type* type = package->types[k]; - if (type == NULL) continue; - const size_t L = type->configs.size(); - for (size_t l=0; l<L; l++) { - const ResTable_type* config = type->configs[l]; - const ResTable_config* cfg = &config->config; - // only insert unique - const size_t M = configs->size(); - size_t m; - for (m=0; m<M; m++) { - if (0 == (*configs)[m].compare(*cfg)) { - break; - } - } - // if we didn't find it - if (m == M) { - configs->add(*cfg); - } - } - } - } - } -} - -void ResTable::getLocales(Vector<String8>* locales) const -{ - Vector<ResTable_config> configs; - LOGD("calling getConfigurations"); - getConfigurations(&configs); - LOGD("called getConfigurations size=%d", (int)configs.size()); - const size_t I = configs.size(); - for (size_t i=0; i<I; i++) { - char locale[6]; - configs[i].getLocale(locale); - const size_t J = locales->size(); - size_t j; - for (j=0; j<J; j++) { - if (0 == strcmp(locale, (*locales)[j].string())) { - break; - } - } - if (j == J) { - locales->add(String8(locale)); - } - } -} - -ssize_t ResTable::getEntry( - const Package* package, int typeIndex, int entryIndex, - const ResTable_config* config, - const ResTable_type** outType, const ResTable_entry** outEntry, - const Type** outTypeClass) const -{ - LOGV("Getting entry from package %p\n", package); - const ResTable_package* const pkg = package->package; - - const Type* allTypes = package->getType(typeIndex); - LOGV("allTypes=%p\n", allTypes); - if (allTypes == NULL) { - LOGV("Skipping entry type index 0x%02x because type is NULL!\n", typeIndex); - return 0; - } - - if ((size_t)entryIndex >= allTypes->entryCount) { - LOGW("getEntry failing because entryIndex %d is beyond type entryCount %d", - entryIndex, (int)allTypes->entryCount); - return BAD_TYPE; - } - - const ResTable_type* type = NULL; - uint32_t offset = ResTable_type::NO_ENTRY; - ResTable_config bestConfig; - memset(&bestConfig, 0, sizeof(bestConfig)); // make the compiler shut up - - const size_t NT = allTypes->configs.size(); - for (size_t i=0; i<NT; i++) { - const ResTable_type* const thisType = allTypes->configs[i]; - if (thisType == NULL) continue; - - ResTable_config thisConfig; - thisConfig.copyFromDtoH(thisType->config); - - TABLE_GETENTRY(LOGI("Match entry 0x%x in type 0x%x (sz 0x%x): imsi:%d/%d=%d/%d lang:%c%c=%c%c cnt:%c%c=%c%c " - "orien:%d=%d touch:%d=%d density:%d=%d key:%d=%d inp:%d=%d nav:%d=%d w:%d=%d h:%d=%d\n", - entryIndex, typeIndex+1, dtohl(thisType->config.size), - thisConfig.mcc, thisConfig.mnc, - config ? config->mcc : 0, config ? config->mnc : 0, - thisConfig.language[0] ? thisConfig.language[0] : '-', - thisConfig.language[1] ? thisConfig.language[1] : '-', - config && config->language[0] ? config->language[0] : '-', - config && config->language[1] ? config->language[1] : '-', - thisConfig.country[0] ? thisConfig.country[0] : '-', - thisConfig.country[1] ? thisConfig.country[1] : '-', - config && config->country[0] ? config->country[0] : '-', - config && config->country[1] ? config->country[1] : '-', - thisConfig.orientation, - config ? config->orientation : 0, - thisConfig.touchscreen, - config ? config->touchscreen : 0, - thisConfig.density, - config ? config->density : 0, - thisConfig.keyboard, - config ? config->keyboard : 0, - thisConfig.inputFlags, - config ? config->inputFlags : 0, - thisConfig.navigation, - config ? config->navigation : 0, - thisConfig.screenWidth, - config ? config->screenWidth : 0, - thisConfig.screenHeight, - config ? config->screenHeight : 0)); - - // Check to make sure this one is valid for the current parameters. - if (config && !thisConfig.match(*config)) { - TABLE_GETENTRY(LOGI("Does not match config!\n")); - continue; - } - - // Check if there is the desired entry in this type. - - const uint8_t* const end = ((const uint8_t*)thisType) - + dtohl(thisType->header.size); - const uint32_t* const eindex = (const uint32_t*) - (((const uint8_t*)thisType) + dtohs(thisType->header.headerSize)); - - uint32_t thisOffset = dtohl(eindex[entryIndex]); - if (thisOffset == ResTable_type::NO_ENTRY) { - TABLE_GETENTRY(LOGI("Skipping because it is not defined!\n")); - continue; - } - - if (type != NULL) { - // Check if this one is less specific than the last found. If so, - // we will skip it. We check starting with things we most care - // about to those we least care about. - if (!thisConfig.isBetterThan(bestConfig, config)) { - TABLE_GETENTRY(LOGI("This config is worse than last!\n")); - continue; - } - } - - type = thisType; - offset = thisOffset; - bestConfig = thisConfig; - TABLE_GETENTRY(LOGI("Best entry so far -- using it!\n")); - if (!config) break; - } - - if (type == NULL) { - TABLE_GETENTRY(LOGI("No value found for requested entry!\n")); - return BAD_INDEX; - } - - offset += dtohl(type->entriesStart); - TABLE_NOISY(aout << "Looking in resource table " << package->header->header - << ", typeOff=" - << (void*)(((const char*)type)-((const char*)package->header->header)) - << ", offset=" << (void*)offset << endl); - - if (offset > (dtohl(type->header.size)-sizeof(ResTable_entry))) { - LOGW("ResTable_entry at 0x%x is beyond type chunk data 0x%x", - offset, dtohl(type->header.size)); - return BAD_TYPE; - } - if ((offset&0x3) != 0) { - LOGW("ResTable_entry at 0x%x is not on an integer boundary", - offset); - return BAD_TYPE; - } - - const ResTable_entry* const entry = (const ResTable_entry*) - (((const uint8_t*)type) + offset); - if (dtohs(entry->size) < sizeof(*entry)) { - LOGW("ResTable_entry size 0x%x is too small", dtohs(entry->size)); - return BAD_TYPE; - } - - *outType = type; - *outEntry = entry; - if (outTypeClass != NULL) { - *outTypeClass = allTypes; - } - return offset + dtohs(entry->size); -} - -status_t ResTable::parsePackage(const ResTable_package* const pkg, - const Header* const header) -{ - const uint8_t* base = (const uint8_t*)pkg; - status_t err = validate_chunk(&pkg->header, sizeof(*pkg), - header->dataEnd, "ResTable_package"); - if (err != NO_ERROR) { - return (mError=err); - } - - const size_t pkgSize = dtohl(pkg->header.size); - - if (dtohl(pkg->typeStrings) >= pkgSize) { - LOGW("ResTable_package type strings at %p are past chunk size %p.", - (void*)dtohl(pkg->typeStrings), (void*)pkgSize); - return (mError=BAD_TYPE); - } - if ((dtohl(pkg->typeStrings)&0x3) != 0) { - LOGW("ResTable_package type strings at %p is not on an integer boundary.", - (void*)dtohl(pkg->typeStrings)); - return (mError=BAD_TYPE); - } - if (dtohl(pkg->keyStrings) >= pkgSize) { - LOGW("ResTable_package key strings at %p are past chunk size %p.", - (void*)dtohl(pkg->keyStrings), (void*)pkgSize); - return (mError=BAD_TYPE); - } - if ((dtohl(pkg->keyStrings)&0x3) != 0) { - LOGW("ResTable_package key strings at %p is not on an integer boundary.", - (void*)dtohl(pkg->keyStrings)); - return (mError=BAD_TYPE); - } - - Package* package = NULL; - PackageGroup* group = NULL; - uint32_t id = dtohl(pkg->id); - if (id != 0 && id < 256) { - size_t idx = mPackageMap[id]; - if (idx == 0) { - idx = mPackageGroups.size()+1; - - char16_t tmpName[sizeof(pkg->name)/sizeof(char16_t)]; - strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(char16_t)); - group = new PackageGroup(String16(tmpName), id); - if (group == NULL) { - return (mError=NO_MEMORY); - } - - err = group->typeStrings.setTo(base+dtohl(pkg->typeStrings), - header->dataEnd-(base+dtohl(pkg->typeStrings))); - if (err != NO_ERROR) { - return (mError=err); - } - err = group->keyStrings.setTo(base+dtohl(pkg->keyStrings), - header->dataEnd-(base+dtohl(pkg->keyStrings))); - if (err != NO_ERROR) { - return (mError=err); - } - - //printf("Adding new package id %d at index %d\n", id, idx); - err = mPackageGroups.add(group); - if (err < NO_ERROR) { - return (mError=err); - } - mPackageMap[id] = (uint8_t)idx; - } else { - group = mPackageGroups.itemAt(idx-1); - if (group == NULL) { - return (mError=UNKNOWN_ERROR); - } - } - package = new Package(header, pkg); - if (package == NULL) { - return (mError=NO_MEMORY); - } - err = group->packages.add(package); - if (err < NO_ERROR) { - return (mError=err); - } - } else { - LOG_ALWAYS_FATAL("Skins not supported!"); - return NO_ERROR; - } - - - // Iterate through all chunks. - size_t curPackage = 0; - - const ResChunk_header* chunk = - (const ResChunk_header*)(((const uint8_t*)pkg) - + dtohs(pkg->header.headerSize)); - const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size); - while (((const uint8_t*)chunk) <= (endPos-sizeof(ResChunk_header)) && - ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) { - TABLE_NOISY(LOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n", - dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size), - (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)))); - const size_t csize = dtohl(chunk->size); - const uint16_t ctype = dtohs(chunk->type); - if (ctype == RES_TABLE_TYPE_SPEC_TYPE) { - const ResTable_typeSpec* typeSpec = (const ResTable_typeSpec*)(chunk); - err = validate_chunk(&typeSpec->header, sizeof(*typeSpec), - endPos, "ResTable_typeSpec"); - if (err != NO_ERROR) { - return (mError=err); - } - - const size_t typeSpecSize = dtohl(typeSpec->header.size); - - LOAD_TABLE_NOISY(printf("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n", - (void*)(base-(const uint8_t*)chunk), - dtohs(typeSpec->header.type), - dtohs(typeSpec->header.headerSize), - (void*)typeSize)); - // look for block overrun or int overflow when multiplying by 4 - if ((dtohl(typeSpec->entryCount) > (INT32_MAX/sizeof(uint32_t)) - || dtohs(typeSpec->header.headerSize)+(sizeof(uint32_t)*dtohl(typeSpec->entryCount)) - > typeSpecSize)) { - LOGW("ResTable_typeSpec entry index to %p extends beyond chunk end %p.", - (void*)(dtohs(typeSpec->header.headerSize) - +(sizeof(uint32_t)*dtohl(typeSpec->entryCount))), - (void*)typeSpecSize); - return (mError=BAD_TYPE); - } - - if (typeSpec->id == 0) { - LOGW("ResTable_type has an id of 0."); - return (mError=BAD_TYPE); - } - - while (package->types.size() < typeSpec->id) { - package->types.add(NULL); - } - Type* t = package->types[typeSpec->id-1]; - if (t == NULL) { - t = new Type(header, package, dtohl(typeSpec->entryCount)); - package->types.editItemAt(typeSpec->id-1) = t; - } else if (dtohl(typeSpec->entryCount) != t->entryCount) { - LOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d", - (int)dtohl(typeSpec->entryCount), (int)t->entryCount); - return (mError=BAD_TYPE); - } - t->typeSpecFlags = (const uint32_t*)( - ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize)); - t->typeSpec = typeSpec; - - } else if (ctype == RES_TABLE_TYPE_TYPE) { - const ResTable_type* type = (const ResTable_type*)(chunk); - err = validate_chunk(&type->header, sizeof(*type)-sizeof(ResTable_config)+4, - endPos, "ResTable_type"); - if (err != NO_ERROR) { - return (mError=err); - } - - const size_t typeSize = dtohl(type->header.size); - - LOAD_TABLE_NOISY(printf("Type off %p: type=0x%x, headerSize=0x%x, size=%p\n", - (void*)(base-(const uint8_t*)chunk), - dtohs(type->header.type), - dtohs(type->header.headerSize), - (void*)typeSize)); - if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*dtohl(type->entryCount)) - > typeSize) { - LOGW("ResTable_type entry index to %p extends beyond chunk end %p.", - (void*)(dtohs(type->header.headerSize) - +(sizeof(uint32_t)*dtohl(type->entryCount))), - (void*)typeSize); - return (mError=BAD_TYPE); - } - if (dtohl(type->entryCount) != 0 - && dtohl(type->entriesStart) > (typeSize-sizeof(ResTable_entry))) { - LOGW("ResTable_type entriesStart at %p extends beyond chunk end %p.", - (void*)dtohl(type->entriesStart), (void*)typeSize); - return (mError=BAD_TYPE); - } - if (type->id == 0) { - LOGW("ResTable_type has an id of 0."); - return (mError=BAD_TYPE); - } - - while (package->types.size() < type->id) { - package->types.add(NULL); - } - Type* t = package->types[type->id-1]; - if (t == NULL) { - t = new Type(header, package, dtohl(type->entryCount)); - package->types.editItemAt(type->id-1) = t; - } else if (dtohl(type->entryCount) != t->entryCount) { - LOGW("ResTable_type entry count inconsistent: given %d, previously %d", - (int)dtohl(type->entryCount), (int)t->entryCount); - return (mError=BAD_TYPE); - } - - TABLE_GETENTRY( - ResTable_config thisConfig; - thisConfig.copyFromDtoH(type->config); - LOGI("Adding config to type %d: imsi:%d/%d lang:%c%c cnt:%c%c " - "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n", - type->id, - thisConfig.mcc, thisConfig.mnc, - thisConfig.language[0] ? thisConfig.language[0] : '-', - thisConfig.language[1] ? thisConfig.language[1] : '-', - thisConfig.country[0] ? thisConfig.country[0] : '-', - thisConfig.country[1] ? thisConfig.country[1] : '-', - thisConfig.orientation, - thisConfig.touchscreen, - thisConfig.density, - thisConfig.keyboard, - thisConfig.inputFlags, - thisConfig.navigation, - thisConfig.screenWidth, - thisConfig.screenHeight)); - t->configs.add(type); - } else { - status_t err = validate_chunk(chunk, sizeof(ResChunk_header), - endPos, "ResTable_package:unknown"); - if (err != NO_ERROR) { - return (mError=err); - } - } - chunk = (const ResChunk_header*) - (((const uint8_t*)chunk) + csize); - } - - if (group->typeCount == 0) { - group->typeCount = package->types.size(); - } - - return NO_ERROR; -} - -#ifndef HAVE_ANDROID_OS -#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string()) - -#define CHAR16_ARRAY_EQ(constant, var, len) \ - ((len == (sizeof(constant)/sizeof(constant[0]))) && (0 == memcmp((var), (constant), (len)))) - -void ResTable::print() const -{ - printf("mError=0x%x (%s)\n", mError, strerror(mError)); -#if 0 - printf("mParams=%c%c-%c%c,\n", - mParams.language[0], mParams.language[1], - mParams.country[0], mParams.country[1]); -#endif - size_t pgCount = mPackageGroups.size(); - printf("Package Groups (%d)\n", (int)pgCount); - for (size_t pgIndex=0; pgIndex<pgCount; pgIndex++) { - const PackageGroup* pg = mPackageGroups[pgIndex]; - printf("Package Group %d id=%d packageCount=%d name=%s\n", - (int)pgIndex, pg->id, (int)pg->packages.size(), - String8(pg->name).string()); - - size_t pkgCount = pg->packages.size(); - for (size_t pkgIndex=0; pkgIndex<pkgCount; pkgIndex++) { - const Package* pkg = pg->packages[pkgIndex]; - size_t typeCount = pkg->types.size(); - printf(" Package %d id=%d name=%s typeCount=%d\n", (int)pkgIndex, - pkg->package->id, String8(String16(pkg->package->name)).string(), - (int)typeCount); - for (size_t typeIndex=0; typeIndex<typeCount; typeIndex++) { - const Type* typeConfigs = pkg->getType(typeIndex); - if (typeConfigs == NULL) { - printf(" type %d NULL\n", (int)typeIndex); - continue; - } - const size_t NTC = typeConfigs->configs.size(); - printf(" type %d configCount=%d entryCount=%d\n", - (int)typeIndex, (int)NTC, (int)typeConfigs->entryCount); - if (typeConfigs->typeSpecFlags != NULL) { - for (size_t entryIndex=0; entryIndex<typeConfigs->entryCount; entryIndex++) { - uint32_t resID = (0xff000000 & ((pkg->package->id)<<24)) - | (0x00ff0000 & ((typeIndex+1)<<16)) - | (0x0000ffff & (entryIndex)); - resource_name resName; - this->getResourceName(resID, &resName); - printf(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n", - resID, - CHAR16_TO_CSTR(resName.package, resName.packageLen), - CHAR16_TO_CSTR(resName.type, resName.typeLen), - CHAR16_TO_CSTR(resName.name, resName.nameLen), - dtohl(typeConfigs->typeSpecFlags[entryIndex])); - } - } - for (size_t configIndex=0; configIndex<NTC; configIndex++) { - const ResTable_type* type = typeConfigs->configs[configIndex]; - if ((((uint64_t)type)&0x3) != 0) { - printf(" NON-INTEGER ResTable_type ADDRESS: %p\n", type); - continue; - } - printf(" config %d lang=%c%c cnt=%c%c orien=%d touch=%d density=%d key=%d infl=%d nav=%d w=%d h=%d\n", - (int)configIndex, - type->config.language[0] ? type->config.language[0] : '-', - type->config.language[1] ? type->config.language[1] : '-', - type->config.country[0] ? type->config.country[0] : '-', - type->config.country[1] ? type->config.country[1] : '-', - type->config.orientation, - type->config.touchscreen, - dtohs(type->config.density), - type->config.keyboard, - type->config.inputFlags, - type->config.navigation, - dtohs(type->config.screenWidth), - dtohs(type->config.screenHeight)); - size_t entryCount = dtohl(type->entryCount); - uint32_t entriesStart = dtohl(type->entriesStart); - if ((entriesStart&0x3) != 0) { - printf(" NON-INTEGER ResTable_type entriesStart OFFSET: %p\n", (void*)entriesStart); - continue; - } - uint32_t typeSize = dtohl(type->header.size); - if ((typeSize&0x3) != 0) { - printf(" NON-INTEGER ResTable_type header.size: %p\n", (void*)typeSize); - continue; - } - for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) { - - const uint8_t* const end = ((const uint8_t*)type) - + dtohl(type->header.size); - const uint32_t* const eindex = (const uint32_t*) - (((const uint8_t*)type) + dtohs(type->header.headerSize)); - - uint32_t thisOffset = dtohl(eindex[entryIndex]); - if (thisOffset == ResTable_type::NO_ENTRY) { - continue; - } - - uint32_t resID = (0xff000000 & ((pkg->package->id)<<24)) - | (0x00ff0000 & ((typeIndex+1)<<16)) - | (0x0000ffff & (entryIndex)); - resource_name resName; - this->getResourceName(resID, &resName); - printf(" resource 0x%08x %s:%s/%s: ", resID, - CHAR16_TO_CSTR(resName.package, resName.packageLen), - CHAR16_TO_CSTR(resName.type, resName.typeLen), - CHAR16_TO_CSTR(resName.name, resName.nameLen)); - if ((thisOffset&0x3) != 0) { - printf("NON-INTEGER OFFSET: %p\n", (void*)thisOffset); - continue; - } - if ((thisOffset+sizeof(ResTable_entry)) > typeSize) { - printf("OFFSET OUT OF BOUNDS: %p+%p (size is %p)\n", - (void*)entriesStart, (void*)thisOffset, - (void*)typeSize); - continue; - } - - const ResTable_entry* ent = (const ResTable_entry*) - (((const uint8_t*)type) + entriesStart + thisOffset); - if (((entriesStart + thisOffset)&0x3) != 0) { - printf("NON-INTEGER ResTable_entry OFFSET: %p\n", - (void*)(entriesStart + thisOffset)); - continue; - } - if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) { - printf("<bag>"); - } else { - uint16_t esize = dtohs(ent->size); - if ((esize&0x3) != 0) { - printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void*)esize); - continue; - } - if ((thisOffset+esize) > typeSize) { - printf("ResTable_entry OUT OF BOUNDS: %p+%p+%p (size is %p)\n", - (void*)entriesStart, (void*)thisOffset, - (void*)esize, (void*)typeSize); - continue; - } - - const Res_value* value = (const Res_value*) - (((const uint8_t*)ent) + esize); - printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)", - (int)value->dataType, (int)dtohl(value->data), - (int)dtohs(value->size), (int)value->res0); - } - - if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) { - printf(" (PUBLIC)"); - } - printf("\n"); - } - } - } - } - } -} - -#endif // HAVE_ANDROID_OS - -} // namespace android diff --git a/libs/utils/SharedBuffer.cpp b/libs/utils/SharedBuffer.cpp deleted file mode 100644 index 3555fb7..0000000 --- a/libs/utils/SharedBuffer.cpp +++ /dev/null @@ -1,113 +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 <stdlib.h> -#include <string.h> - -#include <utils/SharedBuffer.h> -#include <utils/Atomic.h> - -// --------------------------------------------------------------------------- - -namespace android { - -SharedBuffer* SharedBuffer::alloc(size_t size) -{ - SharedBuffer* sb = static_cast<SharedBuffer *>(malloc(sizeof(SharedBuffer) + size)); - if (sb) { - sb->mRefs = 1; - sb->mSize = size; - } - return sb; -} - - -ssize_t SharedBuffer::dealloc(const SharedBuffer* released) -{ - if (released->mRefs != 0) return -1; // XXX: invalid operation - free(const_cast<SharedBuffer*>(released)); - return 0; -} - -SharedBuffer* SharedBuffer::edit() const -{ - if (onlyOwner()) { - return const_cast<SharedBuffer*>(this); - } - SharedBuffer* sb = alloc(mSize); - if (sb) { - memcpy(sb->data(), data(), size()); - release(); - } - return sb; -} - -SharedBuffer* SharedBuffer::editResize(size_t newSize) const -{ - if (onlyOwner()) { - SharedBuffer* buf = const_cast<SharedBuffer*>(this); - if (buf->mSize == newSize) return buf; - buf = (SharedBuffer*)realloc(buf, sizeof(SharedBuffer) + newSize); - if (buf != NULL) { - buf->mSize = newSize; - return buf; - } - } - SharedBuffer* sb = alloc(newSize); - if (sb) { - const size_t mySize = mSize; - memcpy(sb->data(), data(), newSize < mySize ? newSize : mySize); - release(); - } - return sb; -} - -SharedBuffer* SharedBuffer::attemptEdit() const -{ - if (onlyOwner()) { - return const_cast<SharedBuffer*>(this); - } - return 0; -} - -SharedBuffer* SharedBuffer::reset(size_t new_size) const -{ - // cheap-o-reset. - SharedBuffer* sb = alloc(new_size); - if (sb) { - release(); - } - return sb; -} - -void SharedBuffer::acquire() const { - android_atomic_inc(&mRefs); -} - -int32_t SharedBuffer::release(uint32_t flags) const -{ - int32_t prev = 1; - if (onlyOwner() || ((prev = android_atomic_dec(&mRefs)) == 1)) { - mRefs = 0; - if ((flags & eKeepStorage) == 0) { - free(const_cast<SharedBuffer*>(this)); - } - } - return prev; -} - - -}; // namespace android diff --git a/libs/utils/Socket.cpp b/libs/utils/Socket.cpp deleted file mode 100644 index 51509a3..0000000 --- a/libs/utils/Socket.cpp +++ /dev/null @@ -1,388 +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. - */ - -// -// Internet address class. -// - -#ifdef HAVE_WINSOCK -// This needs to come first, or Cygwin gets concerned about a potential -// clash between WinSock and <sys/types.h>. -# include <winsock2.h> -#endif - -#include <utils/Socket.h> -#include <utils/inet_address.h> -#include <utils/Log.h> -#include <utils/Timers.h> - -#ifndef HAVE_WINSOCK -# include <sys/types.h> -# include <sys/socket.h> -# include <netinet/in.h> -# include <arpa/inet.h> -#endif - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <assert.h> - -using namespace android; - - -/* - * =========================================================================== - * Socket - * =========================================================================== - */ - -#ifndef INVALID_SOCKET -# define INVALID_SOCKET (-1) -#endif -#define UNDEF_SOCKET ((unsigned long) INVALID_SOCKET) - -/*static*/ bool Socket::mBootInitialized = false; - -/* - * Extract system-dependent error code. - */ -static inline int getSocketError(void) { -#ifdef HAVE_WINSOCK - return WSAGetLastError(); -#else - return errno; -#endif -} - -/* - * One-time initialization for socket code. - */ -/*static*/ bool Socket::bootInit(void) -{ -#ifdef HAVE_WINSOCK - WSADATA wsaData; - int err; - - err = WSAStartup(MAKEWORD(2, 0), &wsaData); - if (err != 0) { - LOG(LOG_ERROR, "socket", "Unable to start WinSock\n"); - return false; - } - - LOG(LOG_INFO, "socket", "Using WinSock v%d.%d\n", - LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); -#endif - - mBootInitialized = true; - return true; -} - -/* - * One-time shutdown for socket code. - */ -/*static*/ void Socket::finalShutdown(void) -{ -#ifdef HAVE_WINSOCK - WSACleanup(); -#endif - mBootInitialized = false; -} - - -/* - * Simple constructor. Allow the application to create us and then make - * bind/connect calls. - */ -Socket::Socket(void) - : mSock(UNDEF_SOCKET) -{ - if (!mBootInitialized) - LOG(LOG_WARN, "socket", "WARNING: sockets not initialized\n"); -} - -/* - * Destructor. Closes the socket and resets our storage. - */ -Socket::~Socket(void) -{ - close(); -} - - -/* - * Create a socket and connect to the specified host and port. - */ -int Socket::connect(const char* host, int port) -{ - if (mSock != UNDEF_SOCKET) { - LOG(LOG_WARN, "socket", "Socket already connected\n"); - return -1; - } - - InetSocketAddress sockAddr; - if (!sockAddr.create(host, port)) - return -1; - - //return doConnect(sockAddr); - int foo; - foo = doConnect(sockAddr); - return foo; -} - -/* - * Create a socket and connect to the specified host and port. - */ -int Socket::connect(const InetAddress* addr, int port) -{ - if (mSock != UNDEF_SOCKET) { - LOG(LOG_WARN, "socket", "Socket already connected\n"); - return -1; - } - - InetSocketAddress sockAddr; - if (!sockAddr.create(addr, port)) - return -1; - - return doConnect(sockAddr); -} - -/* - * Finish creating a socket by connecting to the remote host. - * - * Returns 0 on success. - */ -int Socket::doConnect(const InetSocketAddress& sockAddr) -{ -#ifdef HAVE_WINSOCK - SOCKET sock; -#else - int sock; -#endif - const InetAddress* addr = sockAddr.getAddress(); - int port = sockAddr.getPort(); - struct sockaddr_in inaddr; - DurationTimer connectTimer; - - assert(sizeof(struct sockaddr_in) == addr->getAddressLength()); - memcpy(&inaddr, addr->getAddress(), addr->getAddressLength()); - inaddr.sin_port = htons(port); - - //fprintf(stderr, "--- connecting to %s:%d\n", - // sockAddr.getHostName(), port); - - sock = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sock == INVALID_SOCKET) { - int err = getSocketError(); - LOG(LOG_ERROR, "socket", "Unable to create socket (err=%d)\n", err); - return (err != 0) ? err : -1; - } - - connectTimer.start(); - - if (::connect(sock, (struct sockaddr*) &inaddr, sizeof(inaddr)) != 0) { - int err = getSocketError(); - LOG(LOG_WARN, "socket", "Connect to %s:%d failed: %d\n", - sockAddr.getHostName(), port, err); - return (err != 0) ? err : -1; - } - - connectTimer.stop(); - if ((long) connectTimer.durationUsecs() > 100000) { - LOG(LOG_INFO, "socket", - "Connect to %s:%d took %.3fs\n", sockAddr.getHostName(), - port, ((long) connectTimer.durationUsecs()) / 1000000.0); - } - - mSock = (unsigned long) sock; - LOG(LOG_VERBOSE, "socket", - "--- connected to %s:%d\n", sockAddr.getHostName(), port); - return 0; -} - - -/* - * Close the socket if it needs closing. - */ -bool Socket::close(void) -{ - if (mSock != UNDEF_SOCKET) { - //fprintf(stderr, "--- closing socket %lu\n", mSock); -#ifdef HAVE_WINSOCK - if (::closesocket((SOCKET) mSock) != 0) - return false; -#else - if (::close((int) mSock) != 0) - return false; -#endif - } - - mSock = UNDEF_SOCKET; - - return true; -} - -/* - * Read data from socket. - * - * Standard semantics: read up to "len" bytes into "buf". Returns the - * number of bytes read, or less than zero on error. - */ -int Socket::read(void* buf, ssize_t len) const -{ - if (mSock == UNDEF_SOCKET) { - LOG(LOG_ERROR, "socket", "ERROR: read on invalid socket\n"); - return -500; - } - -#ifdef HAVE_WINSOCK - SOCKET sock = (SOCKET) mSock; -#else - int sock = (int) mSock; -#endif - int cc; - - cc = recv(sock, (char*)buf, len, 0); - if (cc < 0) { - int err = getSocketError(); - return (err > 0) ? -err : -1; - } - - return cc; -} - -/* - * Write data to a socket. - * - * Standard semantics: write up to "len" bytes into "buf". Returns the - * number of bytes written, or less than zero on error. - */ -int Socket::write(const void* buf, ssize_t len) const -{ - if (mSock == UNDEF_SOCKET) { - LOG(LOG_ERROR, "socket", "ERROR: write on invalid socket\n"); - return -500; - } - -#ifdef HAVE_WINSOCK - SOCKET sock = (SOCKET) mSock; -#else - int sock = (int) mSock; -#endif - int cc; - - cc = send(sock, (const char*)buf, len, 0); - if (cc < 0) { - int err = getSocketError(); - return (err > 0) ? -err : -1; - } - - return cc; -} - - -/* - * =========================================================================== - * Socket tests - * =========================================================================== - */ - -/* - * Read all data from the socket. The data is read into a buffer that - * expands as needed. - * - * On exit, the buffer is returned, and the length of the data is stored - * in "*sz". A null byte is added to the end, but is not included in - * the length. - */ -static char* socketReadAll(const Socket& s, int *sz) -{ - int max, r; - char *data, *ptr, *tmp; - - data = (char*) malloc(max = 32768); - if (data == NULL) - return NULL; - - ptr = data; - - for (;;) { - if ((ptr - data) == max) { - tmp = (char*) realloc(data, max *= 2); - if(tmp == 0) { - free(data); - return 0; - } - } - r = s.read(ptr, max - (ptr - data)); - if (r == 0) - break; - if (r < 0) { - LOG(LOG_WARN, "socket", "WARNING: socket read failed (res=%d)\n",r); - break; - } - ptr += r; - } - - if ((ptr - data) == max) { - tmp = (char*) realloc(data, max + 1); - if (tmp == NULL) { - free(data); - return NULL; - } - } - *ptr = '\0'; - *sz = (ptr - data); - return data; -} - -/* - * Exercise the Socket class. - */ -void android::TestSockets(void) -{ - printf("----- SOCKET TEST ------\n"); - Socket::bootInit(); - - char* buf = NULL; - int len, cc; - const char* kTestStr = - "GET / HTTP/1.0\n" - "Connection: close\n" - "\n"; - - Socket sock; - if (sock.connect("www.google.com", 80) != 0) { - fprintf(stderr, "socket connected failed\n"); - goto bail; - } - - cc = sock.write(kTestStr, strlen(kTestStr)); - if (cc != (int) strlen(kTestStr)) { - fprintf(stderr, "write failed, res=%d\n", cc); - goto bail; - } - buf = socketReadAll(sock, &len); - - printf("GOT '%s'\n", buf); - -bail: - sock.close(); - free(buf); -} - diff --git a/libs/utils/Static.cpp b/libs/utils/Static.cpp deleted file mode 100644 index 93f7e4f..0000000 --- a/libs/utils/Static.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// All static variables go here, to control initialization and -// destruction order in the library. - -#include <private/utils/Static.h> - -#include <utils/BufferedTextOutput.h> -#include <utils/IPCThreadState.h> -#include <utils/Log.h> - -namespace android { - -class LibUtilsFirstStatics -{ -public: - LibUtilsFirstStatics() - { - initialize_string8(); - initialize_string16(); - } - - ~LibUtilsFirstStatics() - { - terminate_string16(); - terminate_string8(); - } -}; - -static LibUtilsFirstStatics gFirstStatics; -int gDarwinCantLoadAllObjects = 1; - -// ------------ Text output streams - -Vector<int32_t> gTextBuffers; - -class LogTextOutput : public BufferedTextOutput -{ -public: - LogTextOutput() : BufferedTextOutput(MULTITHREADED) { } - virtual ~LogTextOutput() { }; - -protected: - virtual status_t writeLines(const struct iovec& vec, size_t N) - { - android_writevLog(&vec, N); - return NO_ERROR; - } -}; - -class FdTextOutput : public BufferedTextOutput -{ -public: - FdTextOutput(int fd) : BufferedTextOutput(MULTITHREADED), mFD(fd) { } - virtual ~FdTextOutput() { }; - -protected: - virtual status_t writeLines(const struct iovec& vec, size_t N) - { - writev(mFD, &vec, N); - return NO_ERROR; - } - -private: - int mFD; -}; - -static LogTextOutput gLogTextOutput; -static FdTextOutput gStdoutTextOutput(STDOUT_FILENO); -static FdTextOutput gStderrTextOutput(STDERR_FILENO); - -TextOutput& alog(gLogTextOutput); -TextOutput& aout(gStdoutTextOutput); -TextOutput& aerr(gStderrTextOutput); - -#ifndef LIBUTILS_NATIVE - -// ------------ ProcessState.cpp - -Mutex gProcessMutex; -sp<ProcessState> gProcess; - -class LibUtilsIPCtStatics -{ -public: - LibUtilsIPCtStatics() - { - } - - ~LibUtilsIPCtStatics() - { - IPCThreadState::shutdown(); - } -}; - -static LibUtilsIPCtStatics gIPCStatics; - -// ------------ ServiceManager.cpp - -Mutex gDefaultServiceManagerLock; -sp<IServiceManager> gDefaultServiceManager; -sp<IPermissionController> gPermissionController; - -#endif - -} // namespace android diff --git a/libs/utils/StopWatch.cpp b/libs/utils/StopWatch.cpp deleted file mode 100644 index 68a1c52..0000000 --- a/libs/utils/StopWatch.cpp +++ /dev/null @@ -1,79 +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 "StopWatch" - -#include <string.h> -#include <stdlib.h> -#include <stdio.h> - -#include <utils/Log.h> -#include <utils/Errors.h> -#include <utils/StopWatch.h> - -/*****************************************************************************/ - -namespace android { - - -StopWatch::StopWatch(const char *name, int clock, uint32_t flags) - : mName(name), mClock(clock), mFlags(flags), - mStartTime(0), mNumLaps(0) -{ - mStartTime = systemTime(mClock); -} - -StopWatch::~StopWatch() -{ - nsecs_t elapsed = elapsedTime(); - const int n = mNumLaps; - LOGD("StopWatch %s (us): %lld ", mName, ns2us(elapsed)); - for (int i=0 ; i<n ; i++) { - const nsecs_t soFar = mLaps[i].soFar; - const nsecs_t thisLap = mLaps[i].thisLap; - LOGD(" [%d: %lld, %lld]", i, ns2us(soFar), ns2us(thisLap)); - } -} - -const char* StopWatch::name() const -{ - return mName; -} - -nsecs_t StopWatch::lap() -{ - nsecs_t elapsed = elapsedTime(); - if (mNumLaps >= 8) { - elapsed = 0; - } else { - const int n = mNumLaps; - mLaps[n].soFar = elapsed; - mLaps[n].thisLap = n ? (elapsed - mLaps[n-1].soFar) : elapsed; - mNumLaps = n+1; - } - return elapsed; -} - -nsecs_t StopWatch::elapsedTime() const -{ - return systemTime(mClock) - mStartTime; -} - - -/*****************************************************************************/ - -}; // namespace android - diff --git a/libs/utils/String16.cpp b/libs/utils/String16.cpp deleted file mode 100644 index 1f81cad..0000000 --- a/libs/utils/String16.cpp +++ /dev/null @@ -1,609 +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 <utils/String16.h> - -#include <utils/Debug.h> -#include <utils/Log.h> -#include <utils/String8.h> -#include <utils/TextOutput.h> -#include <utils/threads.h> - -#include <private/utils/Static.h> - -#ifdef HAVE_WINSOCK -# undef nhtol -# undef htonl -# undef nhtos -# undef htons - -# ifdef HAVE_LITTLE_ENDIAN -# define ntohl(x) ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) ) -# define htonl(x) ntohl(x) -# define ntohs(x) ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) ) -# define htons(x) ntohs(x) -# else -# define ntohl(x) (x) -# define htonl(x) (x) -# define ntohs(x) (x) -# define htons(x) (x) -# endif -#else -# include <netinet/in.h> -#endif - -#include <memory.h> -#include <stdio.h> -#include <ctype.h> - -// --------------------------------------------------------------------------- - -int strcmp16(const char16_t *s1, const char16_t *s2) -{ - char16_t ch; - int d = 0; - - while ( 1 ) { - d = (int)(ch = *s1++) - (int)*s2++; - if ( d || !ch ) - break; - } - - return d; -} - -int strncmp16(const char16_t *s1, const char16_t *s2, size_t n) -{ - char16_t ch; - int d = 0; - - while ( n-- ) { - d = (int)(ch = *s1++) - (int)*s2++; - if ( d || !ch ) - break; - } - - return d; -} - -char16_t *strcpy16(char16_t *dst, const char16_t *src) -{ - char16_t *q = dst; - const char16_t *p = src; - char16_t ch; - - do { - *q++ = ch = *p++; - } while ( ch ); - - return dst; -} - -size_t strlen16(const char16_t *s) -{ - const char16_t *ss = s; - while ( *ss ) - ss++; - return ss-s; -} - - -char16_t *strncpy16(char16_t *dst, const char16_t *src, size_t n) -{ - char16_t *q = dst; - const char16_t *p = src; - char ch; - - while (n) { - n--; - *q++ = ch = *p++; - if ( !ch ) - break; - } - - *q = 0; - - return dst; -} - -size_t strnlen16(const char16_t *s, size_t maxlen) -{ - const char16_t *ss = s; - - /* Important: the maxlen test must precede the reference through ss; - since the byte beyond the maximum may segfault */ - while ((maxlen > 0) && *ss) { - ss++; - maxlen--; - } - return ss-s; -} - -int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2) -{ - const char16_t* e1 = s1+n1; - const char16_t* e2 = s2+n2; - - while (s1 < e1 && s2 < e2) { - const int d = (int)*s1++ - (int)*s2++; - if (d) { - return d; - } - } - - return n1 < n2 - ? (0 - (int)*s2) - : (n1 > n2 - ? ((int)*s1 - 0) - : 0); -} - -int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2) -{ - const char16_t* e1 = s1H+n1; - const char16_t* e2 = s2N+n2; - - while (s1H < e1 && s2N < e2) { - const char16_t c2 = ntohs(*s2N); - const int d = (int)*s1H++ - (int)c2; - s2N++; - if (d) { - return d; - } - } - - return n1 < n2 - ? (0 - (int)ntohs(*s2N)) - : (n1 > n2 - ? ((int)*s1H - 0) - : 0); -} - -// --------------------------------------------------------------------------- - -namespace android { - -static inline size_t -utf8_char_len(uint8_t ch) -{ - return ((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1; -} - -#define UTF8_SHIFT_AND_MASK(unicode, byte) (unicode)<<=6; (unicode) |= (0x3f & (byte)); - -static inline uint32_t -utf8_to_utf32(const uint8_t *src, size_t length) -{ - uint32_t unicode; - - switch (length) - { - case 1: - return src[0]; - case 2: - unicode = src[0] & 0x1f; - UTF8_SHIFT_AND_MASK(unicode, src[1]) - return unicode; - case 3: - unicode = src[0] & 0x0f; - UTF8_SHIFT_AND_MASK(unicode, src[1]) - UTF8_SHIFT_AND_MASK(unicode, src[2]) - return unicode; - case 4: - unicode = src[0] & 0x07; - UTF8_SHIFT_AND_MASK(unicode, src[1]) - UTF8_SHIFT_AND_MASK(unicode, src[2]) - UTF8_SHIFT_AND_MASK(unicode, src[3]) - return unicode; - default: - return 0xffff; - } - - //printf("Char at %p: len=%d, utf-16=%p\n", src, length, (void*)result); -} - -// --------------------------------------------------------------------------- - -static SharedBuffer* gEmptyStringBuf = NULL; -static char16_t* gEmptyString = NULL; - -static inline char16_t* getEmptyString() -{ - gEmptyStringBuf->acquire(); - return gEmptyString; -} - -void initialize_string16() -{ - SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t)); - char16_t* str = (char16_t*)buf->data(); - *str = 0; - gEmptyStringBuf = buf; - gEmptyString = str; -} - -void terminate_string16() -{ - SharedBuffer::bufferFromData(gEmptyString)->release(); - gEmptyStringBuf = NULL; - gEmptyString = NULL; -} - -// --------------------------------------------------------------------------- - -// Note: not dealing with generating surrogate pairs. -static char16_t* allocFromUTF8(const char* in, size_t len) -{ - if (len == 0) return getEmptyString(); - - size_t chars = 0; - const char* end = in+len; - const char* p = in; - - while (p < end) { - chars++; - p += utf8_char_len(*p); - } - - SharedBuffer* buf = SharedBuffer::alloc((chars+1)*sizeof(char16_t)); - if (buf) { - p = in; - char16_t* str = (char16_t*)buf->data(); - char16_t* d = str; - while (p < end) { - size_t len = utf8_char_len(*p); - *d++ = (char16_t)utf8_to_utf32((const uint8_t*)p, len); - p += len; - } - *d = 0; - - //printf("Created UTF-16 string from UTF-8 \"%s\":", in); - //printHexData(1, str, buf->size(), 16, 1); - //printf("\n"); - - return str; - } - - return getEmptyString(); -} - -// --------------------------------------------------------------------------- - -String16::String16() - : mString(getEmptyString()) -{ -} - -String16::String16(const String16& o) - : mString(o.mString) -{ - SharedBuffer::bufferFromData(mString)->acquire(); -} - -String16::String16(const String16& o, size_t len, size_t begin) - : mString(getEmptyString()) -{ - setTo(o, len, begin); -} - -String16::String16(const char16_t* o) -{ - size_t len = strlen16(o); - SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t)); - LOG_ASSERT(buf, "Unable to allocate shared buffer"); - if (buf) { - char16_t* str = (char16_t*)buf->data(); - strcpy16(str, o); - mString = str; - return; - } - - mString = getEmptyString(); -} - -String16::String16(const char16_t* o, size_t len) -{ - SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t)); - LOG_ASSERT(buf, "Unable to allocate shared buffer"); - if (buf) { - char16_t* str = (char16_t*)buf->data(); - memcpy(str, o, len*sizeof(char16_t)); - str[len] = 0; - mString = str; - return; - } - - mString = getEmptyString(); -} - -String16::String16(const String8& o) - : mString(allocFromUTF8(o.string(), o.size())) -{ -} - -String16::String16(const char* o) - : mString(allocFromUTF8(o, strlen(o))) -{ -} - -String16::String16(const char* o, size_t len) - : mString(allocFromUTF8(o, len)) -{ -} - -String16::~String16() -{ - SharedBuffer::bufferFromData(mString)->release(); -} - -void String16::setTo(const String16& other) -{ - SharedBuffer::bufferFromData(other.mString)->acquire(); - SharedBuffer::bufferFromData(mString)->release(); - mString = other.mString; -} - -status_t String16::setTo(const String16& other, size_t len, size_t begin) -{ - const size_t N = other.size(); - if (begin >= N) { - SharedBuffer::bufferFromData(mString)->release(); - mString = getEmptyString(); - return NO_ERROR; - } - if ((begin+len) > N) len = N-begin; - if (begin == 0 && len == N) { - setTo(other); - return NO_ERROR; - } - - if (&other == this) { - LOG_ALWAYS_FATAL("Not implemented"); - } - - return setTo(other.string()+begin, len); -} - -status_t String16::setTo(const char16_t* other) -{ - return setTo(other, strlen16(other)); -} - -status_t String16::setTo(const char16_t* other, size_t len) -{ - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize((len+1)*sizeof(char16_t)); - if (buf) { - char16_t* str = (char16_t*)buf->data(); - memcpy(str, other, len*sizeof(char16_t)); - str[len] = 0; - mString = str; - return NO_ERROR; - } - return NO_MEMORY; -} - -status_t String16::append(const String16& other) -{ - const size_t myLen = size(); - const size_t otherLen = other.size(); - if (myLen == 0) { - setTo(other); - return NO_ERROR; - } else if (otherLen == 0) { - return NO_ERROR; - } - - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize((myLen+otherLen+1)*sizeof(char16_t)); - if (buf) { - char16_t* str = (char16_t*)buf->data(); - memcpy(str+myLen, other, (otherLen+1)*sizeof(char16_t)); - mString = str; - return NO_ERROR; - } - return NO_MEMORY; -} - -status_t String16::append(const char16_t* chrs, size_t otherLen) -{ - const size_t myLen = size(); - if (myLen == 0) { - setTo(chrs, otherLen); - return NO_ERROR; - } else if (otherLen == 0) { - return NO_ERROR; - } - - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize((myLen+otherLen+1)*sizeof(char16_t)); - if (buf) { - char16_t* str = (char16_t*)buf->data(); - memcpy(str+myLen, chrs, otherLen*sizeof(char16_t)); - str[myLen+otherLen] = 0; - mString = str; - return NO_ERROR; - } - return NO_MEMORY; -} - -status_t String16::insert(size_t pos, const char16_t* chrs) -{ - return insert(pos, chrs, strlen16(chrs)); -} - -status_t String16::insert(size_t pos, const char16_t* chrs, size_t len) -{ - const size_t myLen = size(); - if (myLen == 0) { - return setTo(chrs, len); - return NO_ERROR; - } else if (len == 0) { - return NO_ERROR; - } - - if (pos > myLen) pos = myLen; - - #if 0 - printf("Insert in to %s: pos=%d, len=%d, myLen=%d, chrs=%s\n", - String8(*this).string(), pos, - len, myLen, String8(chrs, len).string()); - #endif - - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize((myLen+len+1)*sizeof(char16_t)); - if (buf) { - char16_t* str = (char16_t*)buf->data(); - if (pos < myLen) { - memmove(str+pos+len, str+pos, (myLen-pos)*sizeof(char16_t)); - } - memcpy(str+pos, chrs, len*sizeof(char16_t)); - str[myLen+len] = 0; - mString = str; - #if 0 - printf("Result (%d chrs): %s\n", size(), String8(*this).string()); - #endif - return NO_ERROR; - } - return NO_MEMORY; -} - -ssize_t String16::findFirst(char16_t c) const -{ - const char16_t* str = string(); - const char16_t* p = str; - const char16_t* e = p + size(); - while (p < e) { - if (*p == c) { - return p-str; - } - p++; - } - return -1; -} - -ssize_t String16::findLast(char16_t c) const -{ - const char16_t* str = string(); - const char16_t* p = str; - const char16_t* e = p + size(); - while (p < e) { - e--; - if (*e == c) { - return e-str; - } - } - return -1; -} - -bool String16::startsWith(const String16& prefix) const -{ - const size_t ps = prefix.size(); - if (ps > size()) return false; - return strzcmp16(mString, ps, prefix.string(), ps) == 0; -} - -bool String16::startsWith(const char16_t* prefix) const -{ - const size_t ps = strlen16(prefix); - if (ps > size()) return false; - return strncmp16(mString, prefix, ps) == 0; -} - -status_t String16::makeLower() -{ - const size_t N = size(); - const char16_t* str = string(); - char16_t* edit = NULL; - for (size_t i=0; i<N; i++) { - const char16_t v = str[i]; - if (v >= 'A' && v <= 'Z') { - if (!edit) { - SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit(); - if (!buf) { - return NO_MEMORY; - } - edit = (char16_t*)buf->data(); - mString = str = edit; - } - edit[i] = tolower((char)v); - } - } - return NO_ERROR; -} - -status_t String16::replaceAll(char16_t replaceThis, char16_t withThis) -{ - const size_t N = size(); - const char16_t* str = string(); - char16_t* edit = NULL; - for (size_t i=0; i<N; i++) { - if (str[i] == replaceThis) { - if (!edit) { - SharedBuffer* buf = SharedBuffer::bufferFromData(mString)->edit(); - if (!buf) { - return NO_MEMORY; - } - edit = (char16_t*)buf->data(); - mString = str = edit; - } - edit[i] = withThis; - } - } - return NO_ERROR; -} - -status_t String16::remove(size_t len, size_t begin) -{ - const size_t N = size(); - if (begin >= N) { - SharedBuffer::bufferFromData(mString)->release(); - mString = getEmptyString(); - return NO_ERROR; - } - if ((begin+len) > N) len = N-begin; - if (begin == 0 && len == N) { - return NO_ERROR; - } - - if (begin > 0) { - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize((N+1)*sizeof(char16_t)); - if (!buf) { - return NO_MEMORY; - } - char16_t* str = (char16_t*)buf->data(); - memmove(str, str+begin, (N-begin+1)*sizeof(char16_t)); - mString = str; - } - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize((len+1)*sizeof(char16_t)); - if (buf) { - char16_t* str = (char16_t*)buf->data(); - str[len] = 0; - mString = str; - return NO_ERROR; - } - return NO_MEMORY; -} - -TextOutput& operator<<(TextOutput& to, const String16& val) -{ - to << String8(val).string(); - return to; -} - -}; // namespace android diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp deleted file mode 100644 index c50d343..0000000 --- a/libs/utils/String8.cpp +++ /dev/null @@ -1,604 +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 <utils/String8.h> - -#include <utils/Log.h> -#include <utils/String16.h> -#include <utils/TextOutput.h> -#include <utils/threads.h> - -#include <private/utils/Static.h> - -#include <ctype.h> - -namespace android { - -// --------------------------------------------------------------------------- - -static const uint32_t kByteMask = 0x000000BF; -static const uint32_t kByteMark = 0x00000080; - -// Surrogates aren't valid for UTF-32 characters, so define some -// constants that will let us screen them out. -static const uint32_t kUnicodeSurrogateHighStart = 0x0000D800; -static const uint32_t kUnicodeSurrogateHighEnd = 0x0000DBFF; -static const uint32_t kUnicodeSurrogateLowStart = 0x0000DC00; -static const uint32_t kUnicodeSurrogateLowEnd = 0x0000DFFF; -static const uint32_t kUnicodeSurrogateStart = kUnicodeSurrogateHighStart; -static const uint32_t kUnicodeSurrogateEnd = kUnicodeSurrogateLowEnd; - -// Mask used to set appropriate bits in first byte of UTF-8 sequence, -// indexed by number of bytes in the sequence. -static const uint32_t kFirstByteMark[] = { - 0x00000000, 0x00000000, 0x000000C0, 0x000000E0, 0x000000F0 -}; - -// Separator used by resource paths. This is not platform dependent contrary -// to OS_PATH_SEPARATOR. -#define RES_PATH_SEPARATOR '/' - -// Return number of utf8 bytes required for the character. -static size_t utf32_to_utf8_bytes(uint32_t srcChar) -{ - size_t bytesToWrite; - - // Figure out how many bytes the result will require. - if (srcChar < 0x00000080) - { - bytesToWrite = 1; - } - else if (srcChar < 0x00000800) - { - bytesToWrite = 2; - } - else if (srcChar < 0x00010000) - { - if ((srcChar < kUnicodeSurrogateStart) - || (srcChar > kUnicodeSurrogateEnd)) - { - bytesToWrite = 3; - } - else - { - // Surrogates are invalid UTF-32 characters. - return 0; - } - } - // Max code point for Unicode is 0x0010FFFF. - else if (srcChar < 0x00110000) - { - bytesToWrite = 4; - } - else - { - // Invalid UTF-32 character. - return 0; - } - - return bytesToWrite; -} - -// Write out the source character to <dstP>. - -static void utf32_to_utf8(uint8_t* dstP, uint32_t srcChar, size_t bytes) -{ - dstP += bytes; - switch (bytes) - { /* note: everything falls through. */ - case 4: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6; - case 3: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6; - case 2: *--dstP = (uint8_t)((srcChar | kByteMark) & kByteMask); srcChar >>= 6; - case 1: *--dstP = (uint8_t)(srcChar | kFirstByteMark[bytes]); - } -} - -// --------------------------------------------------------------------------- - -static SharedBuffer* gEmptyStringBuf = NULL; -static char* gEmptyString = NULL; - -extern int gDarwinCantLoadAllObjects; -int gDarwinIsReallyAnnoying; - -static inline char* getEmptyString() -{ - gEmptyStringBuf->acquire(); - return gEmptyString; -} - -void initialize_string8() -{ -#ifdef LIBUTILS_NATIVE - // Bite me, Darwin! - gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects; -#endif - - SharedBuffer* buf = SharedBuffer::alloc(1); - char* str = (char*)buf->data(); - *str = 0; - gEmptyStringBuf = buf; - gEmptyString = str; -} - -void terminate_string8() -{ - SharedBuffer::bufferFromData(gEmptyString)->release(); - gEmptyStringBuf = NULL; - gEmptyString = NULL; -} - -// --------------------------------------------------------------------------- - -static char* allocFromUTF8(const char* in, size_t len) -{ - if (len > 0) { - SharedBuffer* buf = SharedBuffer::alloc(len+1); - LOG_ASSERT(buf, "Unable to allocate shared buffer"); - if (buf) { - char* str = (char*)buf->data(); - memcpy(str, in, len); - str[len] = 0; - return str; - } - return NULL; - } - - return getEmptyString(); -} - -// Note: not dealing with expanding surrogate pairs. -static char* allocFromUTF16(const char16_t* in, size_t len) -{ - if (len == 0) return getEmptyString(); - - size_t bytes = 0; - const char16_t* end = in+len; - const char16_t* p = in; - - while (p < end) { - bytes += utf32_to_utf8_bytes(*p); - p++; - } - - SharedBuffer* buf = SharedBuffer::alloc(bytes+1); - LOG_ASSERT(buf, "Unable to allocate shared buffer"); - if (buf) { - p = in; - char* str = (char*)buf->data(); - char* d = str; - while (p < end) { - uint32_t c = *p++; - size_t len = utf32_to_utf8_bytes(c); - utf32_to_utf8((uint8_t*)d, c, len); - d += len; - } - *d = 0; - - return str; - } - - return getEmptyString(); -} - -// --------------------------------------------------------------------------- - -String8::String8() - : mString(getEmptyString()) -{ -} - -String8::String8(const String8& o) - : mString(o.mString) -{ - SharedBuffer::bufferFromData(mString)->acquire(); -} - -String8::String8(const char* o) - : mString(allocFromUTF8(o, strlen(o))) -{ - if (mString == NULL) { - mString = getEmptyString(); - } -} - -String8::String8(const char* o, size_t len) - : mString(allocFromUTF8(o, len)) -{ - if (mString == NULL) { - mString = getEmptyString(); - } -} - -String8::String8(const String16& o) - : mString(allocFromUTF16(o.string(), o.size())) -{ -} - -String8::String8(const char16_t* o) - : mString(allocFromUTF16(o, strlen16(o))) -{ -} - -String8::String8(const char16_t* o, size_t len) - : mString(allocFromUTF16(o, len)) -{ -} - -String8::~String8() -{ - SharedBuffer::bufferFromData(mString)->release(); -} - -void String8::setTo(const String8& other) -{ - SharedBuffer::bufferFromData(other.mString)->acquire(); - SharedBuffer::bufferFromData(mString)->release(); - mString = other.mString; -} - -status_t String8::setTo(const char* other) -{ - SharedBuffer::bufferFromData(mString)->release(); - mString = allocFromUTF8(other, strlen(other)); - if (mString) return NO_ERROR; - - mString = getEmptyString(); - return NO_MEMORY; -} - -status_t String8::setTo(const char* other, size_t len) -{ - SharedBuffer::bufferFromData(mString)->release(); - mString = allocFromUTF8(other, len); - if (mString) return NO_ERROR; - - mString = getEmptyString(); - return NO_MEMORY; -} - -status_t String8::setTo(const char16_t* other, size_t len) -{ - SharedBuffer::bufferFromData(mString)->release(); - mString = allocFromUTF16(other, len); - if (mString) return NO_ERROR; - - mString = getEmptyString(); - return NO_MEMORY; -} - -status_t String8::append(const String8& other) -{ - const size_t otherLen = other.bytes(); - if (bytes() == 0) { - setTo(other); - return NO_ERROR; - } else if (otherLen == 0) { - return NO_ERROR; - } - - return real_append(other.string(), otherLen); -} - -status_t String8::append(const char* other) -{ - return append(other, strlen(other)); -} - -status_t String8::append(const char* other, size_t otherLen) -{ - if (bytes() == 0) { - return setTo(other, otherLen); - } else if (otherLen == 0) { - return NO_ERROR; - } - - return real_append(other, otherLen); -} - -status_t String8::real_append(const char* other, size_t otherLen) -{ - const size_t myLen = bytes(); - - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize(myLen+otherLen+1); - if (buf) { - char* str = (char*)buf->data(); - mString = str; - str += myLen; - memcpy(str, other, otherLen); - str[otherLen] = '\0'; - return NO_ERROR; - } - return NO_MEMORY; -} - -char* String8::lockBuffer(size_t size) -{ - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize(size+1); - if (buf) { - char* str = (char*)buf->data(); - mString = str; - return str; - } - return NULL; -} - -void String8::unlockBuffer() -{ - unlockBuffer(strlen(mString)); -} - -status_t String8::unlockBuffer(size_t size) -{ - if (size != this->size()) { - SharedBuffer* buf = SharedBuffer::bufferFromData(mString) - ->editResize(size+1); - if (buf) { - char* str = (char*)buf->data(); - str[size] = 0; - mString = str; - return NO_ERROR; - } - } - - return NO_MEMORY; -} - -ssize_t String8::find(const char* other, size_t start) const -{ - size_t len = size(); - if (start >= len) { - return -1; - } - const char* s = mString+start; - const char* p = strstr(s, other); - return p ? p-mString : -1; -} - -void String8::toLower() -{ - toLower(0, size()); -} - -void String8::toLower(size_t start, size_t length) -{ - const size_t len = size(); - if (start >= len) { - return; - } - if (start+length > len) { - length = len-start; - } - char* buf = lockBuffer(len); - buf += start; - while (length > 0) { - *buf = tolower(*buf); - buf++; - length--; - } - unlockBuffer(len); -} - -void String8::toUpper() -{ - toUpper(0, size()); -} - -void String8::toUpper(size_t start, size_t length) -{ - const size_t len = size(); - if (start >= len) { - return; - } - if (start+length > len) { - length = len-start; - } - char* buf = lockBuffer(len); - buf += start; - while (length > 0) { - *buf = toupper(*buf); - buf++; - length--; - } - unlockBuffer(len); -} - -TextOutput& operator<<(TextOutput& to, const String8& val) -{ - to << val.string(); - return to; -} - -// --------------------------------------------------------------------------- -// Path functions - - -void String8::setPathName(const char* name) -{ - setPathName(name, strlen(name)); -} - -void String8::setPathName(const char* name, size_t len) -{ - char* buf = lockBuffer(len); - - memcpy(buf, name, len); - - // remove trailing path separator, if present - if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR) - len--; - - buf[len] = '\0'; - - unlockBuffer(len); -} - -String8 String8::getPathLeaf(void) const -{ - const char* cp; - const char*const buf = mString; - - cp = strrchr(buf, OS_PATH_SEPARATOR); - if (cp == NULL) - return String8(*this); - else - return String8(cp+1); -} - -String8 String8::getPathDir(void) const -{ - const char* cp; - const char*const str = mString; - - cp = strrchr(str, OS_PATH_SEPARATOR); - if (cp == NULL) - return String8(""); - else - return String8(str, cp - str); -} - -String8 String8::walkPath(String8* outRemains) const -{ - const char* cp; - const char*const str = mString; - const char* buf = str; - - cp = strchr(buf, OS_PATH_SEPARATOR); - if (cp == buf) { - // don't include a leading '/'. - buf = buf+1; - cp = strchr(buf, OS_PATH_SEPARATOR); - } - - if (cp == NULL) { - String8 res = buf != str ? String8(buf) : *this; - if (outRemains) *outRemains = String8(""); - return res; - } - - String8 res(buf, cp-buf); - if (outRemains) *outRemains = String8(cp+1); - return res; -} - -/* - * Helper function for finding the start of an extension in a pathname. - * - * Returns a pointer inside mString, or NULL if no extension was found. - */ -char* String8::find_extension(void) const -{ - const char* lastSlash; - const char* lastDot; - int extLen; - const char* const str = mString; - - // only look at the filename - lastSlash = strrchr(str, OS_PATH_SEPARATOR); - if (lastSlash == NULL) - lastSlash = str; - else - lastSlash++; - - // find the last dot - lastDot = strrchr(lastSlash, '.'); - if (lastDot == NULL) - return NULL; - - // looks good, ship it - return const_cast<char*>(lastDot); -} - -String8 String8::getPathExtension(void) const -{ - char* ext; - - ext = find_extension(); - if (ext != NULL) - return String8(ext); - else - return String8(""); -} - -String8 String8::getBasePath(void) const -{ - char* ext; - const char* const str = mString; - - ext = find_extension(); - if (ext == NULL) - return String8(*this); - else - return String8(str, ext - str); -} - -String8& String8::appendPath(const char* name) -{ - // TODO: The test below will fail for Win32 paths. Fix later or ignore. - if (name[0] != OS_PATH_SEPARATOR) { - if (*name == '\0') { - // nothing to do - return *this; - } - - size_t len = length(); - if (len == 0) { - // no existing filename, just use the new one - setPathName(name); - return *this; - } - - // make room for oldPath + '/' + newPath - int newlen = strlen(name); - - char* buf = lockBuffer(len+1+newlen); - - // insert a '/' if needed - if (buf[len-1] != OS_PATH_SEPARATOR) - buf[len++] = OS_PATH_SEPARATOR; - - memcpy(buf+len, name, newlen+1); - len += newlen; - - unlockBuffer(len); - - return *this; - } else { - setPathName(name); - return *this; - } -} - -String8& String8::convertToResPath() -{ -#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR - size_t len = length(); - if (len > 0) { - char * buf = lockBuffer(len); - for (char * end = buf + len; buf < end; ++buf) { - if (*buf == OS_PATH_SEPARATOR) - *buf = RES_PATH_SEPARATOR; - } - unlockBuffer(len); - } -#endif - return *this; -} - - -}; // namespace android diff --git a/libs/utils/SystemClock.cpp b/libs/utils/SystemClock.cpp deleted file mode 100644 index 2bdc0ce..0000000 --- a/libs/utils/SystemClock.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -/* - * System clock functions. - */ - -#if HAVE_ANDROID_OS -#include <linux/ioctl.h> -#include <linux/rtc.h> -#include <utils/Atomic.h> -#include <linux/android_alarm.h> -#endif - -#include <sys/time.h> -#include <limits.h> -#include <fcntl.h> -#include <errno.h> -#include <string.h> - -#include <utils/SystemClock.h> -#include <utils/Timers.h> - -#define LOG_TAG "SystemClock" -#include "utils/Log.h" - -namespace android { - -/* - * Set the current time. This only works when running as root. - */ -int setCurrentTimeMillis(int64_t millis) -{ -#if WIN32 - // not implemented - return -1; -#else - struct timeval tv; -#if HAVE_ANDROID_OS - struct timespec ts; - int fd; - int res; -#endif - int ret = 0; - - if (millis <= 0 || millis / 1000LL >= INT_MAX) { - return -1; - } - - tv.tv_sec = (time_t) (millis / 1000LL); - tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL); - - LOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec); - -#if HAVE_ANDROID_OS - fd = open("/dev/alarm", O_RDWR); - if(fd < 0) { - LOGW("Unable to open alarm driver: %s\n", strerror(errno)); - return -1; - } - ts.tv_sec = tv.tv_sec; - ts.tv_nsec = tv.tv_usec * 1000; - res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts); - if(res < 0) { - LOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno)); - ret = -1; - } - close(fd); -#else - if (settimeofday(&tv, NULL) != 0) { - LOGW("Unable to set clock to %d.%d: %s\n", - (int) tv.tv_sec, (int) tv.tv_usec, strerror(errno)); - ret = -1; - } -#endif - - return ret; -#endif // WIN32 -} - -/* - * native public static long uptimeMillis(); - */ -int64_t uptimeMillis() -{ - int64_t when = systemTime(SYSTEM_TIME_MONOTONIC); - return (int64_t) nanoseconds_to_milliseconds(when); -} - -/* - * native public static long elapsedRealtime(); - */ -int64_t elapsedRealtime() -{ -#if HAVE_ANDROID_OS - static int s_fd = -1; - - if (s_fd == -1) { - int fd = open("/dev/alarm", O_RDONLY); - if (android_atomic_cmpxchg(-1, fd, &s_fd)) { - close(fd); - } - } - - struct timespec ts; - int result = ioctl(s_fd, - ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts); - - if (result == 0) { - int64_t when = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec; - return (int64_t) nanoseconds_to_milliseconds(when); - } else { - // XXX: there was an error, probably because the driver didn't - // exist ... this should return - // a real error, like an exception! - int64_t when = systemTime(SYSTEM_TIME_MONOTONIC); - return (int64_t) nanoseconds_to_milliseconds(when); - } -#else - int64_t when = systemTime(SYSTEM_TIME_MONOTONIC); - return (int64_t) nanoseconds_to_milliseconds(when); -#endif -} - -}; // namespace android diff --git a/libs/utils/TextOutput.cpp b/libs/utils/TextOutput.cpp deleted file mode 100644 index cebee99..0000000 --- a/libs/utils/TextOutput.cpp +++ /dev/null @@ -1,146 +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 <utils/TextOutput.h> - -#include <utils/Debug.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -// --------------------------------------------------------------------------- - -namespace android { - -TextOutput& operator<<(TextOutput& to, bool val) -{ - if (val) to.print("true", 4); - else to.print("false", 5); - return to; -} - -TextOutput& operator<<(TextOutput& to, int val) -{ - char buf[16]; - sprintf(buf, "%d", val); - to.print(buf, strlen(buf)); - return to; -} - -TextOutput& operator<<(TextOutput& to, long val) -{ - char buf[16]; - sprintf(buf, "%ld", val); - to.print(buf, strlen(buf)); - return to; -} - -TextOutput& operator<<(TextOutput& to, unsigned int val) -{ - char buf[16]; - sprintf(buf, "%u", val); - to.print(buf, strlen(buf)); - return to; -} - -TextOutput& operator<<(TextOutput& to, unsigned long val) -{ - char buf[16]; - sprintf(buf, "%lu", val); - to.print(buf, strlen(buf)); - return to; -} - -TextOutput& operator<<(TextOutput& to, long long val) -{ - char buf[32]; - sprintf(buf, "%Ld", val); - to.print(buf, strlen(buf)); - return to; -} - -TextOutput& operator<<(TextOutput& to, unsigned long long val) -{ - char buf[32]; - sprintf(buf, "%Lu", val); - to.print(buf, strlen(buf)); - return to; -} - -static TextOutput& print_float(TextOutput& to, double value) -{ - char buf[64]; - sprintf(buf, "%g", value); - if( !strchr(buf, '.') && !strchr(buf, 'e') && - !strchr(buf, 'E') ) { - strncat(buf, ".0", sizeof(buf)-1); - } - to.print(buf, strlen(buf)); - return to; -} - -TextOutput& operator<<(TextOutput& to, float val) -{ - return print_float(to,val); -} - -TextOutput& operator<<(TextOutput& to, double val) -{ - return print_float(to,val); -} - -TextOutput& operator<<(TextOutput& to, const void* val) -{ - char buf[16]; - sprintf(buf, "%p", val); - to.print(buf, strlen(buf)); - return to; -} - -static void textOutputPrinter(void* cookie, const char* txt) -{ - ((TextOutput*)cookie)->print(txt, strlen(txt)); -} - -TextOutput& operator<<(TextOutput& to, const TypeCode& val) -{ - printTypeCode(val.typeCode(), textOutputPrinter, (void*)&to); - return to; -} - -HexDump::HexDump(const void *buf, size_t size, size_t bytesPerLine) - : mBuffer(buf) - , mSize(size) - , mBytesPerLine(bytesPerLine) - , mSingleLineCutoff(16) - , mAlignment(4) - , mCArrayStyle(false) -{ - if (bytesPerLine >= 16) mAlignment = 4; - else if (bytesPerLine >= 8) mAlignment = 2; - else mAlignment = 1; -} - -TextOutput& operator<<(TextOutput& to, const HexDump& val) -{ - printHexData(0, val.buffer(), val.size(), val.bytesPerLine(), - val.singleLineCutoff(), val.alignment(), val.carrayStyle(), - textOutputPrinter, (void*)&to); - return to; -} - -}; // namespace android diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp deleted file mode 100644 index 74271ba..0000000 --- a/libs/utils/Threads.cpp +++ /dev/null @@ -1,1126 +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. - */ - -#define LOG_TAG "libutils.threads" - -#include <utils/threads.h> -#include <utils/Log.h> - -#include <stdio.h> -#include <stdlib.h> -#include <memory.h> -#include <errno.h> -#include <assert.h> -#include <unistd.h> - -#if defined(HAVE_PTHREADS) -# include <pthread.h> -# include <sched.h> -# include <sys/resource.h> -#elif defined(HAVE_WIN32_THREADS) -# include <windows.h> -# include <stdint.h> -# include <process.h> -# define HAVE_CREATETHREAD // Cygwin, vs. HAVE__BEGINTHREADEX for MinGW -#endif - -#if defined(HAVE_FUTEX) -#include <private/utils/futex_synchro.h> -#endif - -#if defined(HAVE_PRCTL) -#include <sys/prctl.h> -#endif - -/* - * =========================================================================== - * Thread wrappers - * =========================================================================== - */ - -using namespace android; - -// ---------------------------------------------------------------------------- -#if defined(HAVE_PTHREADS) -#if 0 -#pragma mark - -#pragma mark PTHREAD -#endif -// ---------------------------------------------------------------------------- - -/* - * Create and run a new thead. - * - * We create it "detached", so it cleans up after itself. - */ - -typedef void* (*android_pthread_entry)(void*); - -struct thread_data_t { - thread_func_t entryFunction; - void* userData; - int priority; - char * threadName; - - // we use this trampoline when we need to set the priority with - // nice/setpriority. - static int trampoline(const thread_data_t* t) { - thread_func_t f = t->entryFunction; - void* u = t->userData; - int prio = t->priority; - char * name = t->threadName; - delete t; - setpriority(PRIO_PROCESS, 0, prio); - if (name) { -#if defined(HAVE_PRCTL) - // Mac OS doesn't have this, and we build libutil for the host too - int hasAt = 0; - int hasDot = 0; - char *s = name; - while (*s) { - if (*s == '.') hasDot = 1; - else if (*s == '@') hasAt = 1; - s++; - } - int len = s - name; - if (len < 15 || hasAt || !hasDot) { - s = name; - } else { - s = name + len - 15; - } - prctl(PR_SET_NAME, (unsigned long) s, 0, 0, 0); -#endif - free(name); - } - return f(u); - } -}; - -int androidCreateRawThreadEtc(android_thread_func_t entryFunction, - void *userData, - const char* threadName, - int32_t threadPriority, - size_t threadStackSize, - android_thread_id_t *threadId) -{ - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - -#ifdef HAVE_ANDROID_OS /* valgrind is rejecting RT-priority create reqs */ - if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) { - // We could avoid the trampoline if there was a way to get to the - // android_thread_id_t (pid) from pthread_t - thread_data_t* t = new thread_data_t; - t->priority = threadPriority; - t->threadName = threadName ? strdup(threadName) : NULL; - t->entryFunction = entryFunction; - t->userData = userData; - entryFunction = (android_thread_func_t)&thread_data_t::trampoline; - userData = t; - } -#endif - - if (threadStackSize) { - pthread_attr_setstacksize(&attr, threadStackSize); - } - - errno = 0; - pthread_t thread; - int result = pthread_create(&thread, &attr, - (android_pthread_entry)entryFunction, userData); - if (result != 0) { - LOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, errno=%d)\n" - "(android threadPriority=%d)", - entryFunction, result, errno, threadPriority); - return 0; - } - - if (threadId != NULL) { - *threadId = (android_thread_id_t)thread; // XXX: this is not portable - } - return 1; -} - -android_thread_id_t androidGetThreadId() -{ - return (android_thread_id_t)pthread_self(); -} - -// ---------------------------------------------------------------------------- -#elif defined(HAVE_WIN32_THREADS) -#if 0 -#pragma mark - -#pragma mark WIN32_THREADS -#endif -// ---------------------------------------------------------------------------- - -/* - * Trampoline to make us __stdcall-compliant. - * - * We're expected to delete "vDetails" when we're done. - */ -struct threadDetails { - int (*func)(void*); - void* arg; -}; -static __stdcall unsigned int threadIntermediary(void* vDetails) -{ - struct threadDetails* pDetails = (struct threadDetails*) vDetails; - int result; - - result = (*(pDetails->func))(pDetails->arg); - - delete pDetails; - - LOG(LOG_VERBOSE, "thread", "thread exiting\n"); - return (unsigned int) result; -} - -/* - * Create and run a new thread. - */ -static bool doCreateThread(android_thread_func_t fn, void* arg, android_thread_id_t *id) -{ - HANDLE hThread; - struct threadDetails* pDetails = new threadDetails; // must be on heap - unsigned int thrdaddr; - - pDetails->func = fn; - pDetails->arg = arg; - -#if defined(HAVE__BEGINTHREADEX) - hThread = (HANDLE) _beginthreadex(NULL, 0, threadIntermediary, pDetails, 0, - &thrdaddr); - if (hThread == 0) -#elif defined(HAVE_CREATETHREAD) - hThread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) threadIntermediary, - (void*) pDetails, 0, (DWORD*) &thrdaddr); - if (hThread == NULL) -#endif - { - LOG(LOG_WARN, "thread", "WARNING: thread create failed\n"); - return false; - } - -#if defined(HAVE_CREATETHREAD) - /* close the management handle */ - CloseHandle(hThread); -#endif - - if (id != NULL) { - *id = (android_thread_id_t)thrdaddr; - } - - return true; -} - -int androidCreateRawThreadEtc(android_thread_func_t fn, - void *userData, - const char* threadName, - int32_t threadPriority, - size_t threadStackSize, - android_thread_id_t *threadId) -{ - return doCreateThread( fn, userData, threadId); -} - -android_thread_id_t androidGetThreadId() -{ - return (android_thread_id_t)GetCurrentThreadId(); -} - -// ---------------------------------------------------------------------------- -#else -#error "Threads not supported" -#endif - -// ---------------------------------------------------------------------------- - -#if 0 -#pragma mark - -#pragma mark Common Thread functions -#endif - -int androidCreateThread(android_thread_func_t fn, void* arg) -{ - return createThreadEtc(fn, arg); -} - -int androidCreateThreadGetID(android_thread_func_t fn, void *arg, android_thread_id_t *id) -{ - return createThreadEtc(fn, arg, "android:unnamed_thread", - PRIORITY_DEFAULT, 0, id); -} - -static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc; - -int androidCreateThreadEtc(android_thread_func_t entryFunction, - void *userData, - const char* threadName, - int32_t threadPriority, - size_t threadStackSize, - android_thread_id_t *threadId) -{ - return gCreateThreadFn(entryFunction, userData, threadName, - threadPriority, threadStackSize, threadId); -} - -void androidSetCreateThreadFunc(android_create_thread_fn func) -{ - gCreateThreadFn = func; -} - -namespace android { - -/* - * =========================================================================== - * Mutex class - * =========================================================================== - */ - -#if 0 -#pragma mark - -#pragma mark Mutex -#endif - -#if defined(HAVE_PTHREADS) && !defined(HAVE_FUTEX) -/* - * Simple pthread wrapper. - */ - -Mutex::Mutex() -{ - _init(); -} - -Mutex::Mutex(const char* name) -{ - // XXX: name not used for now - _init(); -} - -void Mutex::_init() -{ - pthread_mutex_t* pMutex = new pthread_mutex_t; - pthread_mutex_init(pMutex, NULL); - mState = pMutex; -} - -Mutex::~Mutex() -{ - delete (pthread_mutex_t*) mState; -} - -status_t Mutex::lock() -{ - int res; - while ((res=pthread_mutex_lock((pthread_mutex_t*) mState)) == EINTR) ; - return -res; -} - -void Mutex::unlock() -{ - pthread_mutex_unlock((pthread_mutex_t*) mState); -} - -status_t Mutex::tryLock() -{ - int res; - while ((res=pthread_mutex_trylock((pthread_mutex_t*) mState)) == EINTR) ; - return -res; -} - -#elif defined(HAVE_FUTEX) -#if 0 -#pragma mark - -#endif - -#define STATE ((futex_mutex_t*) (&mState)) - -Mutex::Mutex() -{ - _init(); -} - -Mutex::Mutex(const char* name) -{ - _init(); -} - -void -Mutex::_init() -{ - futex_mutex_init(STATE); -} - -Mutex::~Mutex() -{ -} - -status_t Mutex::lock() -{ - int res; - while ((res=futex_mutex_lock(STATE, FUTEX_WAIT_INFINITE)) == EINTR) ; - return -res; -} - -void Mutex::unlock() -{ - futex_mutex_unlock(STATE); -} - -status_t Mutex::tryLock() -{ - int res; - while ((res=futex_mutex_trylock(STATE)) == EINTR) ; - return -res; -} -#undef STATE - -#elif defined(HAVE_WIN32_THREADS) -#if 0 -#pragma mark - -#endif - -Mutex::Mutex() -{ - HANDLE hMutex; - - assert(sizeof(hMutex) == sizeof(mState)); - - hMutex = CreateMutex(NULL, FALSE, NULL); - mState = (void*) hMutex; -} - -Mutex::Mutex(const char* name) -{ - // XXX: name not used for now - HANDLE hMutex; - - hMutex = CreateMutex(NULL, FALSE, NULL); - mState = (void*) hMutex; -} - -Mutex::~Mutex() -{ - CloseHandle((HANDLE) mState); -} - -status_t Mutex::lock() -{ - DWORD dwWaitResult; - dwWaitResult = WaitForSingleObject((HANDLE) mState, INFINITE); - return dwWaitResult != WAIT_OBJECT_0 ? -1 : NO_ERROR; -} - -void Mutex::unlock() -{ - if (!ReleaseMutex((HANDLE) mState)) - LOG(LOG_WARN, "thread", "WARNING: bad result from unlocking mutex\n"); -} - -status_t Mutex::tryLock() -{ - DWORD dwWaitResult; - - dwWaitResult = WaitForSingleObject((HANDLE) mState, 0); - if (dwWaitResult != WAIT_OBJECT_0 && dwWaitResult != WAIT_TIMEOUT) - LOG(LOG_WARN, "thread", "WARNING: bad result from try-locking mutex\n"); - return (dwWaitResult == WAIT_OBJECT_0) ? 0 : -1; -} - -#else -#error "Somebody forgot to implement threads for this platform." -#endif - - -/* - * =========================================================================== - * Condition class - * =========================================================================== - */ - -#if 0 -#pragma mark - -#pragma mark Condition -#endif - -#if defined(HAVE_PTHREADS) && !defined(HAVE_FUTEX) - -/* - * Constructor. This is a simple pthread wrapper. - */ -Condition::Condition() -{ - pthread_cond_t* pCond = new pthread_cond_t; - - pthread_cond_init(pCond, NULL); - mState = pCond; -} - -/* - * Destructor. - */ -Condition::~Condition() -{ - pthread_cond_destroy((pthread_cond_t*) mState); - delete (pthread_cond_t*) mState; -} - -/* - * Wait on a condition variable. Lock the mutex before calling. - */ - -status_t Condition::wait(Mutex& mutex) -{ - assert(mutex.mState != NULL); - - int cc; - while ((cc = pthread_cond_wait((pthread_cond_t*)mState, - (pthread_mutex_t*) mutex.mState)) == EINTR) ; - return -cc; -} - -status_t Condition::wait(Mutex& mutex, nsecs_t abstime) -{ - assert(mutex.mState != NULL); - - struct timespec ts; - ts.tv_sec = abstime/1000000000; - ts.tv_nsec = abstime-(ts.tv_sec*1000000000); - - int cc; - while ((cc = pthread_cond_timedwait((pthread_cond_t*)mState, - (pthread_mutex_t*) mutex.mState, &ts)) == EINTR) ; - return -cc; -} - -status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) -{ - return wait(mutex, systemTime()+reltime); -} - -/* - * Signal the condition variable, allowing one thread to continue. - */ -void Condition::signal() -{ - pthread_cond_signal((pthread_cond_t*) mState); -} - -/* - * Signal the condition variable, allowing all threads to continue. - */ -void Condition::broadcast() -{ - pthread_cond_broadcast((pthread_cond_t*) mState); -} - -#elif defined(HAVE_FUTEX) -#if 0 -#pragma mark - -#endif - -#define STATE ((futex_cond_t*) (&mState)) - -/* - * Constructor. This is a simple pthread wrapper. - */ -Condition::Condition() -{ - futex_cond_init(STATE); -} - -/* - * Destructor. - */ -Condition::~Condition() -{ -} - -/* - * Wait on a condition variable. Lock the mutex before calling. - */ - -status_t Condition::wait(Mutex& mutex) -{ - assert(mutex.mState != NULL); - - int res; - while ((res = futex_cond_wait(STATE, - (futex_mutex_t*)(&mutex.mState), FUTEX_WAIT_INFINITE)) == -EINTR) ; - - return -res; -} - -status_t Condition::wait(Mutex& mutex, nsecs_t abstime) -{ - nsecs_t reltime = abstime - systemTime(); - if (reltime <= 0) return true; - return waitRelative(mutex, reltime); -} - -status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) -{ - assert(mutex.mState != NULL); - int res; - unsigned msec = ns2ms(reltime); - if(msec == 0) - return true; - // This code will not time out at the correct time if interrupted by signals - while ((res = futex_cond_wait(STATE, - (futex_mutex_t*)(&mutex.mState), msec)) == -EINTR) ; - return res; -} - -/* - * Signal the condition variable, allowing one thread to continue. - */ -void Condition::signal() -{ - futex_cond_signal(STATE); -} - -/* - * Signal the condition variable, allowing all threads to continue. - */ -void Condition::broadcast() -{ - futex_cond_broadcast(STATE); -} - -#undef STATE - -#elif defined(HAVE_WIN32_THREADS) -#if 0 -#pragma mark - -#endif - -/* - * Windows doesn't have a condition variable solution. It's possible - * to create one, but it's easy to get it wrong. For a discussion, and - * the origin of this implementation, see: - * - * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html - * - * The implementation shown on the page does NOT follow POSIX semantics. - * As an optimization they require acquiring the external mutex before - * calling signal() and broadcast(), whereas POSIX only requires grabbing - * it before calling wait(). The implementation here has been un-optimized - * to have the correct behavior. - */ -typedef struct WinCondition { - // Number of waiting threads. - int waitersCount; - - // Serialize access to waitersCount. - CRITICAL_SECTION waitersCountLock; - - // Semaphore used to queue up threads waiting for the condition to - // become signaled. - HANDLE sema; - - // An auto-reset event used by the broadcast/signal thread to wait - // for all the waiting thread(s) to wake up and be released from - // the semaphore. - HANDLE waitersDone; - - // This mutex wouldn't be necessary if we required that the caller - // lock the external mutex before calling signal() and broadcast(). - // I'm trying to mimic pthread semantics though. - HANDLE internalMutex; - - // Keeps track of whether we were broadcasting or signaling. This - // allows us to optimize the code if we're just signaling. - bool wasBroadcast; - - status_t wait(WinCondition* condState, HANDLE hMutex, nsecs_t* abstime) - { - // Increment the wait count, avoiding race conditions. - EnterCriticalSection(&condState->waitersCountLock); - condState->waitersCount++; - //printf("+++ wait: incr waitersCount to %d (tid=%ld)\n", - // condState->waitersCount, getThreadId()); - LeaveCriticalSection(&condState->waitersCountLock); - - DWORD timeout = INFINITE; - if (abstime) { - nsecs_t reltime = *abstime - systemTime(); - if (reltime < 0) - reltime = 0; - timeout = reltime/1000000; - } - - // Atomically release the external mutex and wait on the semaphore. - DWORD res = - SignalObjectAndWait(hMutex, condState->sema, timeout, FALSE); - - //printf("+++ wait: awake (tid=%ld)\n", getThreadId()); - - // Reacquire lock to avoid race conditions. - EnterCriticalSection(&condState->waitersCountLock); - - // No longer waiting. - condState->waitersCount--; - - // Check to see if we're the last waiter after a broadcast. - bool lastWaiter = (condState->wasBroadcast && condState->waitersCount == 0); - - //printf("+++ wait: lastWaiter=%d (wasBc=%d wc=%d)\n", - // lastWaiter, condState->wasBroadcast, condState->waitersCount); - - LeaveCriticalSection(&condState->waitersCountLock); - - // If we're the last waiter thread during this particular broadcast - // then signal broadcast() that we're all awake. It'll drop the - // internal mutex. - if (lastWaiter) { - // Atomically signal the "waitersDone" event and wait until we - // can acquire the internal mutex. We want to do this in one step - // because it ensures that everybody is in the mutex FIFO before - // any thread has a chance to run. Without it, another thread - // could wake up, do work, and hop back in ahead of us. - SignalObjectAndWait(condState->waitersDone, condState->internalMutex, - INFINITE, FALSE); - } else { - // Grab the internal mutex. - WaitForSingleObject(condState->internalMutex, INFINITE); - } - - // Release the internal and grab the external. - ReleaseMutex(condState->internalMutex); - WaitForSingleObject(hMutex, INFINITE); - - return res == WAIT_OBJECT_0 ? NO_ERROR : -1; - } -} WinCondition; - -/* - * Constructor. Set up the WinCondition stuff. - */ -Condition::Condition() -{ - WinCondition* condState = new WinCondition; - - condState->waitersCount = 0; - condState->wasBroadcast = false; - // semaphore: no security, initial value of 0 - condState->sema = CreateSemaphore(NULL, 0, 0x7fffffff, NULL); - InitializeCriticalSection(&condState->waitersCountLock); - // auto-reset event, not signaled initially - condState->waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL); - // used so we don't have to lock external mutex on signal/broadcast - condState->internalMutex = CreateMutex(NULL, FALSE, NULL); - - mState = condState; -} - -/* - * Destructor. Free Windows resources as well as our allocated storage. - */ -Condition::~Condition() -{ - WinCondition* condState = (WinCondition*) mState; - if (condState != NULL) { - CloseHandle(condState->sema); - CloseHandle(condState->waitersDone); - delete condState; - } -} - - -status_t Condition::wait(Mutex& mutex) -{ - WinCondition* condState = (WinCondition*) mState; - HANDLE hMutex = (HANDLE) mutex.mState; - - return ((WinCondition*)mState)->wait(condState, hMutex, NULL); -} - -status_t Condition::wait(Mutex& mutex, nsecs_t abstime) -{ - WinCondition* condState = (WinCondition*) mState; - HANDLE hMutex = (HANDLE) mutex.mState; - - return ((WinCondition*)mState)->wait(condState, hMutex, &abstime); -} - -status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) -{ - return wait(mutex, systemTime()+reltime); -} - -/* - * Signal the condition variable, allowing one thread to continue. - */ -void Condition::signal() -{ - WinCondition* condState = (WinCondition*) mState; - - // Lock the internal mutex. This ensures that we don't clash with - // broadcast(). - WaitForSingleObject(condState->internalMutex, INFINITE); - - EnterCriticalSection(&condState->waitersCountLock); - bool haveWaiters = (condState->waitersCount > 0); - LeaveCriticalSection(&condState->waitersCountLock); - - // If no waiters, then this is a no-op. Otherwise, knock the semaphore - // down a notch. - if (haveWaiters) - ReleaseSemaphore(condState->sema, 1, 0); - - // Release internal mutex. - ReleaseMutex(condState->internalMutex); -} - -/* - * Signal the condition variable, allowing all threads to continue. - * - * First we have to wake up all threads waiting on the semaphore, then - * we wait until all of the threads have actually been woken before - * releasing the internal mutex. This ensures that all threads are woken. - */ -void Condition::broadcast() -{ - WinCondition* condState = (WinCondition*) mState; - - // Lock the internal mutex. This keeps the guys we're waking up - // from getting too far. - WaitForSingleObject(condState->internalMutex, INFINITE); - - EnterCriticalSection(&condState->waitersCountLock); - bool haveWaiters = false; - - if (condState->waitersCount > 0) { - haveWaiters = true; - condState->wasBroadcast = true; - } - - if (haveWaiters) { - // Wake up all the waiters. - ReleaseSemaphore(condState->sema, condState->waitersCount, 0); - - LeaveCriticalSection(&condState->waitersCountLock); - - // Wait for all awakened threads to acquire the counting semaphore. - // The last guy who was waiting sets this. - WaitForSingleObject(condState->waitersDone, INFINITE); - - // Reset wasBroadcast. (No crit section needed because nobody - // else can wake up to poke at it.) - condState->wasBroadcast = 0; - } else { - // nothing to do - LeaveCriticalSection(&condState->waitersCountLock); - } - - // Release internal mutex. - ReleaseMutex(condState->internalMutex); -} - -#else -#error "condition variables not supported on this platform" -#endif - - -/* - * =========================================================================== - * ReadWriteLock class - * =========================================================================== - */ - -#if 0 -#pragma mark - -#pragma mark ReadWriteLock -#endif - -/* - * Add a reader. Readers are nice. They share. - */ -void ReadWriteLock::lockForRead() -{ - mLock.lock(); - while (mNumWriters > 0) { - LOG(LOG_DEBUG, "thread", "+++ lockForRead: waiting\n"); - mReadWaiter.wait(mLock); - } - assert(mNumWriters == 0); - mNumReaders++; -#if defined(PRINT_RENDER_TIMES) - if (mNumReaders == 1) - mDebugTimer.start(); -#endif - mLock.unlock(); -} - -/* - * Try to add a reader. If it doesn't work right away, return "false". - */ -bool ReadWriteLock::tryLockForRead() -{ - mLock.lock(); - if (mNumWriters > 0) { - mLock.unlock(); - return false; - } - assert(mNumWriters == 0); - mNumReaders++; -#if defined(PRINT_RENDER_TIMES) - if (mNumReaders == 1) - mDebugTimer.start(); -#endif - mLock.unlock(); - return true; -} - -/* - * Remove a reader. - */ -void ReadWriteLock::unlockForRead() -{ - mLock.lock(); - if (mNumReaders == 0) { - LOG(LOG_WARN, "thread", - "WARNING: unlockForRead requested, but not locked\n"); - return; - } - assert(mNumReaders > 0); - assert(mNumWriters == 0); - mNumReaders--; - if (mNumReaders == 0) { // last reader? -#if defined(PRINT_RENDER_TIMES) - mDebugTimer.stop(); - printf(" rdlk held %.3f msec\n", - (double) mDebugTimer.durationUsecs() / 1000.0); -#endif - //printf("+++ signaling writers (if any)\n"); - mWriteWaiter.signal(); // wake one writer (if any) - } - mLock.unlock(); -} - -/* - * Add a writer. This requires exclusive access to the object. - */ -void ReadWriteLock::lockForWrite() -{ - mLock.lock(); - while (mNumReaders > 0 || mNumWriters > 0) { - LOG(LOG_DEBUG, "thread", "+++ lockForWrite: waiting\n"); - mWriteWaiter.wait(mLock); - } - assert(mNumReaders == 0); - assert(mNumWriters == 0); - mNumWriters++; -#if defined(PRINT_RENDER_TIMES) - mDebugTimer.start(); -#endif - mLock.unlock(); -} - -/* - * Try to add a writer. If it doesn't work right away, return "false". - */ -bool ReadWriteLock::tryLockForWrite() -{ - mLock.lock(); - if (mNumReaders > 0 || mNumWriters > 0) { - mLock.unlock(); - return false; - } - assert(mNumReaders == 0); - assert(mNumWriters == 0); - mNumWriters++; -#if defined(PRINT_RENDER_TIMES) - mDebugTimer.start(); -#endif - mLock.unlock(); - return true; -} - -/* - * Remove a writer. - */ -void ReadWriteLock::unlockForWrite() -{ - mLock.lock(); - if (mNumWriters == 0) { - LOG(LOG_WARN, "thread", - "WARNING: unlockForWrite requested, but not locked\n"); - return; - } - assert(mNumWriters == 1); - mNumWriters--; -#if defined(PRINT_RENDER_TIMES) - mDebugTimer.stop(); - //printf(" wrlk held %.3f msec\n", - // (double) mDebugTimer.durationUsecs() / 1000.0); -#endif - // mWriteWaiter.signal(); // should other writers get first dibs? - //printf("+++ signaling readers (if any)\n"); - mReadWaiter.broadcast(); // wake all readers (if any) - mLock.unlock(); -} - -// ---------------------------------------------------------------------------- - -#if 0 -#pragma mark - -#pragma mark Thread::Thread -#endif - -/* - * This is our thread object! - */ - -Thread::Thread(bool canCallJava) - : mCanCallJava(canCallJava), - mThread(thread_id_t(-1)), - mLock("Thread::mLock"), - mStatus(NO_ERROR), - mExitPending(false), mRunning(false) -{ -} - -Thread::~Thread() -{ -} - -status_t Thread::readyToRun() -{ - return NO_ERROR; -} - -status_t Thread::run(const char* name, int32_t priority, size_t stack) -{ - Mutex::Autolock _l(mLock); - - if (mRunning) { - // thread already started - return INVALID_OPERATION; - } - - // reset status and exitPending to their default value, so we can - // try again after an error happened (either below, or in readyToRun()) - mStatus = NO_ERROR; - mExitPending = false; - mThread = thread_id_t(-1); - - // hold a strong reference on ourself - mHoldSelf = this; - - bool res; - if (mCanCallJava) { - res = createThreadEtc(_threadLoop, - this, name, priority, stack, &mThread); - } else { - res = androidCreateRawThreadEtc(_threadLoop, - this, name, priority, stack, &mThread); - } - - if (res == false) { - mStatus = UNKNOWN_ERROR; // something happened! - mRunning = false; - mThread = thread_id_t(-1); - } - - if (mStatus < 0) { - // something happened, don't leak - mHoldSelf.clear(); - } - - return mStatus; -} - -int Thread::_threadLoop(void* user) -{ - Thread* const self = static_cast<Thread*>(user); - sp<Thread> strong(self->mHoldSelf); - wp<Thread> weak(strong); - self->mHoldSelf.clear(); - - // we're about to run... - self->mStatus = self->readyToRun(); - if (self->mStatus!=NO_ERROR || self->mExitPending) { - // pretend the thread never started... - self->mExitPending = false; - self->mRunning = false; - return 0; - } - - // thread is running now - self->mRunning = true; - - do { - bool result = self->threadLoop(); - if (result == false || self->mExitPending) { - self->mExitPending = true; - self->mLock.lock(); - self->mRunning = false; - self->mThreadExitedCondition.signal(); - self->mLock.unlock(); - break; - } - - // Release our strong reference, to let a chance to the thread - // to die a peaceful death. - strong.clear(); - // And immediately, reacquire a strong reference for the next loop - strong = weak.promote(); - } while(strong != 0); - - return 0; -} - -void Thread::requestExit() -{ - mExitPending = true; -} - -status_t Thread::requestExitAndWait() -{ - if (mStatus == OK) { - - if (mThread == getThreadId()) { - LOGW( - "Thread (this=%p): don't call waitForExit() from this " - "Thread object's thread. It's a guaranteed deadlock!", - this); - return WOULD_BLOCK; - } - - requestExit(); - - Mutex::Autolock _l(mLock); - while (mRunning == true) { - mThreadExitedCondition.wait(mLock); - } - mExitPending = false; - } - return mStatus; -} - -bool Thread::exitPending() const -{ - return mExitPending; -} - - - -}; // namespace android diff --git a/libs/utils/TimerProbe.cpp b/libs/utils/TimerProbe.cpp deleted file mode 100644 index 835480d..0000000 --- a/libs/utils/TimerProbe.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <utils/TimerProbe.h> - -#if ENABLE_TIMER_PROBE - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "time" - -namespace android { - -Vector<TimerProbe::Bucket> TimerProbe::gBuckets; -TimerProbe* TimerProbe::gExecuteChain; -int TimerProbe::gIndent; -timespec TimerProbe::gRealBase; - -TimerProbe::TimerProbe(const char tag[], int* slot) : mTag(tag) -{ - mNext = gExecuteChain; - gExecuteChain = this; - mIndent = gIndent; - gIndent += 1; - if (mIndent > 0) { - if (*slot == 0) { - int count = gBuckets.add(); - *slot = count; - Bucket& bucket = gBuckets.editItemAt(count); - memset(&bucket, 0, sizeof(Bucket)); - bucket.mTag = tag; - bucket.mSlotPtr = slot; - bucket.mIndent = mIndent; - } - mBucket = *slot; - } - clock_gettime(CLOCK_REALTIME, &mRealStart); - if (gRealBase.tv_sec == 0) - gRealBase = mRealStart; - clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &mPStart); - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &mTStart); -} - -void TimerProbe::end() -{ - timespec realEnd, pEnd, tEnd; - clock_gettime(CLOCK_REALTIME, &realEnd); - clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &pEnd); - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tEnd); - print(realEnd, pEnd, tEnd); - mTag = NULL; -} - -TimerProbe::~TimerProbe() -{ - if (mTag != NULL) - end(); - gExecuteChain = mNext; - gIndent--; -} - - -uint32_t TimerProbe::ElapsedTime(const timespec& start, const timespec& end) -{ - int sec = end.tv_sec - start.tv_sec; - int nsec = end.tv_nsec - start.tv_nsec; - if (nsec < 0) { - sec--; - nsec += 1000000000; - } - return sec * 1000000 + nsec / 1000; -} - -void TimerProbe::print(const timespec& r, const timespec& p, - const timespec& t) const -{ - uint32_t es = ElapsedTime(gRealBase, mRealStart); - uint32_t er = ElapsedTime(mRealStart, r); - uint32_t ep = ElapsedTime(mPStart, p); - uint32_t et = ElapsedTime(mTStart, t); - if (mIndent > 0) { - Bucket& bucket = gBuckets.editItemAt(mBucket); - if (bucket.mStart == 0) - bucket.mStart = es; - bucket.mReal += er; - bucket.mProcess += ep; - bucket.mThread += et; - bucket.mCount++; - return; - } - int index = 0; - int buckets = gBuckets.size(); - int count = 1; - const char* tag = mTag; - int indent = mIndent; - do { - LOGD("%-30.30s: (%3d) %-5.*s time=%-10.3f real=%7dus process=%7dus (%3d%%) thread=%7dus (%3d%%)\n", - tag, count, indent > 5 ? 5 : indent, "+++++", es / 1000000.0, - er, ep, ep * 100 / er, et, et * 100 / er); - if (index >= buckets) - break; - Bucket& bucket = gBuckets.editItemAt(index); - count = bucket.mCount; - es = bucket.mStart; - er = bucket.mReal; - ep = bucket.mProcess; - et = bucket.mThread; - tag = bucket.mTag; - indent = bucket.mIndent; - *bucket.mSlotPtr = 0; - } while (++index); // always true - gBuckets.clear(); -} - -}; // namespace android - -#endif diff --git a/libs/utils/Timers.cpp b/libs/utils/Timers.cpp deleted file mode 100644 index 2abc811..0000000 --- a/libs/utils/Timers.cpp +++ /dev/null @@ -1,240 +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. - */ - -// -// Timer functions. -// -#include <utils/Timers.h> -#include <utils/ported.h> // may need usleep -#include <utils/Log.h> - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <sys/time.h> -#include <time.h> -#include <errno.h> - -#ifdef HAVE_WIN32_THREADS -#include <windows.h> -#endif - -nsecs_t systemTime(int clock) -{ -#if defined(HAVE_POSIX_CLOCKS) - static const clockid_t clocks[] = { - CLOCK_REALTIME, - CLOCK_MONOTONIC, - CLOCK_PROCESS_CPUTIME_ID, - CLOCK_THREAD_CPUTIME_ID - }; - struct timespec t; - t.tv_sec = t.tv_nsec = 0; - clock_gettime(clocks[clock], &t); - return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec; -#else - // we don't support the clocks here. - struct timeval t; - t.tv_sec = t.tv_usec = 0; - gettimeofday(&t, NULL); - return nsecs_t(t.tv_sec)*1000000000LL + nsecs_t(t.tv_usec)*1000LL; -#endif -} - -//#define MONITOR_USLEEP - -/* - * Sleep long enough that we'll wake up "interval" milliseconds after - * the previous snooze. - * - * The "nextTick" argument is updated on each call, and should be passed - * in every time. Set its fields to zero on the first call. - * - * Returns the #of intervals we have overslept, which will be zero if we're - * on time. [Currently just returns 0 or 1.] - */ -int sleepForInterval(long interval, struct timeval* pNextTick) -{ - struct timeval now; - long long timeBeforeNext; - long sleepTime = 0; - bool overSlept = false; - //int usleepBias = 0; - -#ifdef USLEEP_BIAS - /* - * Linux likes to add 9000ms or so. - * [not using this for now] - */ - //usleepBias = USLEEP_BIAS; -#endif - - gettimeofday(&now, NULL); - - if (pNextTick->tv_sec == 0) { - /* special-case for first time through */ - *pNextTick = now; - sleepTime = interval; - android::DurationTimer::addToTimeval(pNextTick, interval); - } else { - /* - * Compute how much time there is before the next tick. If this - * value is negative, we've run over. If we've run over a little - * bit we can shorten the next frame to keep the pace steady, but - * if we've dramatically overshot we need to re-sync. - */ - timeBeforeNext = android::DurationTimer::subtractTimevals(pNextTick, &now); - //printf("TOP: now=%ld.%ld next=%ld.%ld diff=%ld\n", - // now.tv_sec, now.tv_usec, pNextTick->tv_sec, pNextTick->tv_usec, - // (long) timeBeforeNext); - if (timeBeforeNext < -interval) { - /* way over */ - overSlept = true; - sleepTime = 0; - *pNextTick = now; - } else if (timeBeforeNext <= 0) { - /* slightly over, keep the pace steady */ - overSlept = true; - sleepTime = 0; - } else if (timeBeforeNext <= interval) { - /* right on schedule */ - sleepTime = timeBeforeNext; - } else if (timeBeforeNext > interval && timeBeforeNext <= 2*interval) { - /* sleep call returned early; do a longer sleep this time */ - sleepTime = timeBeforeNext; - } else if (timeBeforeNext > interval) { - /* we went back in time -- somebody updated system clock? */ - /* (could also be a *seriously* broken usleep()) */ - LOG(LOG_DEBUG, "", - " Impossible: timeBeforeNext = %ld\n", (long)timeBeforeNext); - sleepTime = 0; - *pNextTick = now; - } - android::DurationTimer::addToTimeval(pNextTick, interval); - } - //printf(" Before sleep: now=%ld.%ld next=%ld.%ld sleepTime=%ld\n", - // now.tv_sec, now.tv_usec, pNextTick->tv_sec, pNextTick->tv_usec, - // sleepTime); - - /* - * Sleep for the designated period of time. - * - * Linux tends to sleep for longer than requested, often by 17-18ms. - * MinGW tends to sleep for less than requested, by as much as 14ms, - * but occasionally oversleeps for 40+ms (looks like some external - * factors plus round-off on a 64Hz clock). Cygwin is pretty steady. - * - * If you start the MinGW version, and then launch the Cygwin version, - * the MinGW clock becomes more erratic. Not entirely sure why. - * - * (There's a lot of stuff here; it's really just a usleep() call with - * a bunch of instrumentation.) - */ - if (sleepTime > 0) { -#if defined(MONITOR_USLEEP) - struct timeval before, after; - long long actual; - - gettimeofday(&before, NULL); - usleep((long) sleepTime); - gettimeofday(&after, NULL); - - /* check usleep() accuracy; default Linux threads are pretty sloppy */ - actual = android::DurationTimer::subtractTimevals(&after, &before); - if ((long) actual < sleepTime - 14000 /*(sleepTime/10)*/ || - (long) actual > sleepTime + 20000 /*(sleepTime/10)*/) - { - LOG(LOG_DEBUG, "", " Odd usleep: req=%ld, actual=%ld\n", sleepTime, - (long) actual); - } -#else -#ifdef HAVE_WIN32_THREADS - Sleep( sleepTime/1000 ); -#else - usleep((long) sleepTime); -#endif -#endif - } - - //printf("slept %d\n", sleepTime); - - if (overSlept) - return 1; // close enough - else - return 0; -} - - -/* - * =========================================================================== - * DurationTimer - * =========================================================================== - */ - -using namespace android; - -// Start the timer. -void DurationTimer::start(void) -{ - gettimeofday(&mStartWhen, NULL); -} - -// Stop the timer. -void DurationTimer::stop(void) -{ - gettimeofday(&mStopWhen, NULL); -} - -// Get the duration in microseconds. -long long DurationTimer::durationUsecs(void) const -{ - return (long) subtractTimevals(&mStopWhen, &mStartWhen); -} - -// Subtract two timevals. Returns the difference (ptv1-ptv2) in -// microseconds. -/*static*/ long long DurationTimer::subtractTimevals(const struct timeval* ptv1, - const struct timeval* ptv2) -{ - long long stop = ((long long) ptv1->tv_sec) * 1000000LL + - ((long long) ptv1->tv_usec); - long long start = ((long long) ptv2->tv_sec) * 1000000LL + - ((long long) ptv2->tv_usec); - return stop - start; -} - -// Add the specified amount of time to the timeval. -/*static*/ void DurationTimer::addToTimeval(struct timeval* ptv, long usec) -{ - if (usec < 0) { - LOG(LOG_WARN, "", "Negative values not supported in addToTimeval\n"); - return; - } - - // normalize tv_usec if necessary - if (ptv->tv_usec >= 1000000) { - ptv->tv_sec += ptv->tv_usec / 1000000; - ptv->tv_usec %= 1000000; - } - - ptv->tv_usec += usec % 1000000; - if (ptv->tv_usec >= 1000000) { - ptv->tv_usec -= 1000000; - ptv->tv_sec++; - } - ptv->tv_sec += usec / 1000000; -} - diff --git a/libs/utils/Unicode.cpp b/libs/utils/Unicode.cpp deleted file mode 100644 index 33f535f..0000000 --- a/libs/utils/Unicode.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "utils/AndroidUnicode.h" -#include "characterData.h" - -#define LOG_TAG "Unicode" -#include "utils/Log.h" - -// ICU headers for using macros -#include <unicode/utf16.h> - -#define MIN_RADIX 2 -#define MAX_RADIX 36 - -#define TYPE_SHIFT 0 -#define TYPE_MASK ((1<<5)-1) - -#define DIRECTION_SHIFT (TYPE_SHIFT+5) -#define DIRECTION_MASK ((1<<5)-1) - -#define MIRRORED_SHIFT (DIRECTION_SHIFT+5) -#define MIRRORED_MASK ((1<<1)-1) - -#define TOUPPER_SHIFT (MIRRORED_SHIFT+1) -#define TOUPPER_MASK ((1<<6)-1) - -#define TOLOWER_SHIFT (TOUPPER_SHIFT+6) -#define TOLOWER_MASK ((1<<6)-1) - -#define TOTITLE_SHIFT (TOLOWER_SHIFT+6) -#define TOTITLE_MASK ((1<<2)-1) - -#define MIRROR_SHIFT (TOTITLE_SHIFT+2) -#define MIRROR_MASK ((1<<5)-1) - -#define NUMERIC_SHIFT (TOTITLE_SHIFT+2) -#define NUMERIC_MASK ((1<<7)-1) - -#define DECOMPOSITION_SHIFT (11) -#define DECOMPOSITION_MASK ((1<<5)-1) - -/* - * Returns the value stored in the CharacterData tables that contains - * an index into the packed data table and the decomposition type. - */ -static uint16_t findCharacterValue(UChar32 c) -{ - LOG_ASSERT(c >= 0 && c <= 0x10FFFF, "findCharacterValue received an invalid codepoint"); - if (c < 256) - return CharacterData::LATIN1_DATA[c]; - - // Rotate the bits because the tables are separated into even and odd codepoints - c = (c >> 1) | ((c & 1) << 20); - - CharacterData::Range search = CharacterData::FULL_DATA[c >> 16]; - const uint32_t* array = search.array; - - // This trick is so that that compare in the while loop does not - // need to shift the array entry down by 16 - c <<= 16; - c |= 0xFFFF; - - int high = (int)search.length - 1; - int low = 0; - - if (high < 0) - return 0; - - while (low < high - 1) - { - int probe = (high + low) >> 1; - - // The entries contain the codepoint in the high 16 bits and the index - // into PACKED_DATA in the low 16. - if (array[probe] > (unsigned)c) - high = probe; - else - low = probe; - } - - LOG_ASSERT((array[low] <= (unsigned)c), "A suitable range was not found"); - return array[low] & 0xFFFF; -} - -uint32_t android::Unicode::getPackedData(UChar32 c) -{ - // findCharacterValue returns a 16-bit value with the top 5 bits containing a decomposition type - // and the remaining bits containing an index. - return CharacterData::PACKED_DATA[findCharacterValue(c) & 0x7FF]; -} - -android::Unicode::CharType android::Unicode::getType(UChar32 c) -{ - if (c < 0 || c >= 0x10FFFF) - return CHARTYPE_UNASSIGNED; - return (CharType)((getPackedData(c) >> TYPE_SHIFT) & TYPE_MASK); -} - -android::Unicode::DecompositionType android::Unicode::getDecompositionType(UChar32 c) -{ - // findCharacterValue returns a 16-bit value with the top 5 bits containing a decomposition type - // and the remaining bits containing an index. - return (DecompositionType)((findCharacterValue(c) >> DECOMPOSITION_SHIFT) & DECOMPOSITION_MASK); -} - -int android::Unicode::getDigitValue(UChar32 c, int radix) -{ - if (radix < MIN_RADIX || radix > MAX_RADIX) - return -1; - - int tempValue = radix; - - if (c >= '0' && c <= '9') - tempValue = c - '0'; - else if (c >= 'a' && c <= 'z') - tempValue = c - 'a' + 10; - else if (c >= 'A' && c <= 'Z') - tempValue = c - 'A' + 10; - - return tempValue < radix ? tempValue : -1; -} - -int android::Unicode::getNumericValue(UChar32 c) -{ - if (isMirrored(c)) - return -1; - - return (int) CharacterData::NUMERICS[((getPackedData(c) >> NUMERIC_SHIFT) & NUMERIC_MASK)]; -} - -UChar32 android::Unicode::toLower(UChar32 c) -{ - return c + CharacterData::LCDIFF[(getPackedData(c) >> TOLOWER_SHIFT) & TOLOWER_MASK]; -} - -UChar32 android::Unicode::toUpper(UChar32 c) -{ - return c + CharacterData::UCDIFF[(getPackedData(c) >> TOUPPER_SHIFT) & TOUPPER_MASK]; -} - -android::Unicode::Direction android::Unicode::getDirectionality(UChar32 c) -{ - uint32_t data = getPackedData(c); - - if (0 == data) - return DIRECTIONALITY_UNDEFINED; - - Direction d = (Direction) ((data >> DIRECTION_SHIFT) & DIRECTION_MASK); - - if (DIRECTION_MASK == d) - return DIRECTIONALITY_UNDEFINED; - - return d; -} - -bool android::Unicode::isMirrored(UChar32 c) -{ - return ((getPackedData(c) >> MIRRORED_SHIFT) & MIRRORED_MASK) != 0; -} - -UChar32 android::Unicode::toMirror(UChar32 c) -{ - if (!isMirrored(c)) - return c; - - return c + CharacterData::MIRROR_DIFF[(getPackedData(c) >> MIRROR_SHIFT) & MIRROR_MASK]; -} - -UChar32 android::Unicode::toTitle(UChar32 c) -{ - int32_t diff = CharacterData::TCDIFF[(getPackedData(c) >> TOTITLE_SHIFT) & TOTITLE_MASK]; - - if (TOTITLE_MASK == diff) - return toUpper(c); - - return c + diff; -} - - diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp deleted file mode 100644 index 2c2d667..0000000 --- a/libs/utils/VectorImpl.cpp +++ /dev/null @@ -1,611 +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 "Vector" - -#include <string.h> -#include <stdlib.h> -#include <stdio.h> - -#include <utils/Log.h> -#include <utils/Errors.h> -#include <utils/SharedBuffer.h> -#include <utils/VectorImpl.h> - -/*****************************************************************************/ - - -namespace android { - -// ---------------------------------------------------------------------------- - -const size_t kMinVectorCapacity = 4; - -static inline size_t max(size_t a, size_t b) { - return a>b ? a : b; -} - -// ---------------------------------------------------------------------------- - -VectorImpl::VectorImpl(size_t itemSize, uint32_t flags) - : mStorage(0), mCount(0), mFlags(flags), mItemSize(itemSize) -{ -} - -VectorImpl::VectorImpl(const VectorImpl& rhs) - : mStorage(rhs.mStorage), mCount(rhs.mCount), - mFlags(rhs.mFlags), mItemSize(rhs.mItemSize) -{ - if (mStorage) { - SharedBuffer::sharedBuffer(mStorage)->acquire(); - } -} - -VectorImpl::~VectorImpl() -{ - LOG_ASSERT(!mCount, - "[%p] " - "subclasses of VectorImpl must call finish_vector()" - " in their destructor. Leaking %d bytes.", - this, (int)(mCount*mItemSize)); - // We can't call _do_destroy() here because the vtable is already gone. -} - -VectorImpl& VectorImpl::operator = (const VectorImpl& rhs) -{ - LOG_ASSERT(mItemSize == rhs.mItemSize, - "Vector<> have different types (this=%p, rhs=%p)", this, &rhs); - if (this != &rhs) { - release_storage(); - if (rhs.mCount) { - mStorage = rhs.mStorage; - mCount = rhs.mCount; - SharedBuffer::sharedBuffer(mStorage)->acquire(); - } else { - mStorage = 0; - mCount = 0; - } - } - return *this; -} - -void* VectorImpl::editArrayImpl() -{ - if (mStorage) { - SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage)->attemptEdit(); - if (sb == 0) { - sb = SharedBuffer::alloc(capacity() * mItemSize); - if (sb) { - _do_copy(sb->data(), mStorage, mCount); - release_storage(); - mStorage = sb->data(); - } - } - } - return mStorage; -} - -size_t VectorImpl::capacity() const -{ - if (mStorage) { - return SharedBuffer::sharedBuffer(mStorage)->size() / mItemSize; - } - return 0; -} - -ssize_t VectorImpl::insertVectorAt(const VectorImpl& vector, size_t index) -{ - if (index > size()) - return BAD_INDEX; - void* where = _grow(index, vector.size()); - if (where) { - _do_copy(where, vector.arrayImpl(), vector.size()); - } - return where ? index : (ssize_t)NO_MEMORY; -} - -ssize_t VectorImpl::appendVector(const VectorImpl& vector) -{ - return insertVectorAt(vector, size()); -} - -ssize_t VectorImpl::insertAt(size_t index, size_t numItems) -{ - return insertAt(0, index, numItems); -} - -ssize_t VectorImpl::insertAt(const void* item, size_t index, size_t numItems) -{ - if (index > size()) - return BAD_INDEX; - void* where = _grow(index, numItems); - if (where) { - if (item) { - _do_splat(where, item, numItems); - } else { - _do_construct(where, numItems); - } - } - return where ? index : (ssize_t)NO_MEMORY; -} - -static int sortProxy(const void* lhs, const void* rhs, void* func) -{ - return (*(VectorImpl::compar_t)func)(lhs, rhs); -} - -status_t VectorImpl::sort(VectorImpl::compar_t cmp) -{ - return sort(sortProxy, (void*)cmp); -} - -status_t VectorImpl::sort(VectorImpl::compar_r_t cmp, void* state) -{ - // the sort must be stable. we're using insertion sort which - // is well suited for small and already sorted arrays - // for big arrays, it could be better to use mergesort - const ssize_t count = size(); - if (count > 1) { - void* array = const_cast<void*>(arrayImpl()); - void* temp = 0; - ssize_t i = 1; - while (i < count) { - void* item = reinterpret_cast<char*>(array) + mItemSize*(i); - void* curr = reinterpret_cast<char*>(array) + mItemSize*(i-1); - if (cmp(curr, item, state) > 0) { - - if (!temp) { - // we're going to have to modify the array... - array = editArrayImpl(); - if (!array) return NO_MEMORY; - temp = malloc(mItemSize); - if (!temp) return NO_MEMORY; - _do_construct(temp, 1); - item = reinterpret_cast<char*>(array) + mItemSize*(i); - curr = reinterpret_cast<char*>(array) + mItemSize*(i-1); - } - - _do_copy(temp, item, 1); - - ssize_t j = i-1; - void* next = reinterpret_cast<char*>(array) + mItemSize*(i); - do { - _do_copy(next, curr, 1); - next = curr; - --j; - curr = reinterpret_cast<char*>(array) + mItemSize*(j); - } while (j>=0 && (cmp(curr, temp, state) > 0)); - - _do_copy(next, temp, 1); - } - i++; - } - - if (temp) { - _do_destroy(temp, 1); - free(temp); - } - } - return NO_ERROR; -} - -void VectorImpl::pop() -{ - if (size()) - removeItemsAt(size()-1, 1); -} - -void VectorImpl::push() -{ - push(0); -} - -void VectorImpl::push(const void* item) -{ - insertAt(item, size()); -} - -ssize_t VectorImpl::add() -{ - return add(0); -} - -ssize_t VectorImpl::add(const void* item) -{ - return insertAt(item, size()); -} - -ssize_t VectorImpl::replaceAt(size_t index) -{ - return replaceAt(0, index); -} - -ssize_t VectorImpl::replaceAt(const void* prototype, size_t index) -{ - LOG_ASSERT(index<size(), - "[%p] replace: index=%d, size=%d", this, (int)index, (int)size()); - - void* item = editItemLocation(index); - if (item == 0) - return NO_MEMORY; - _do_destroy(item, 1); - if (prototype == 0) { - _do_construct(item, 1); - } else { - _do_copy(item, prototype, 1); - } - return ssize_t(index); -} - -ssize_t VectorImpl::removeItemsAt(size_t index, size_t count) -{ - LOG_ASSERT((index+count)<=size(), - "[%p] remove: index=%d, count=%d, size=%d", - this, (int)index, (int)count, (int)size()); - - if ((index+count) > size()) - return BAD_VALUE; - _shrink(index, count); - return index; -} - -void VectorImpl::finish_vector() -{ - release_storage(); - mStorage = 0; - mCount = 0; -} - -void VectorImpl::clear() -{ - _shrink(0, mCount); -} - -void* VectorImpl::editItemLocation(size_t index) -{ - LOG_ASSERT(index<capacity(), - "[%p] itemLocation: index=%d, capacity=%d, count=%d", - this, (int)index, (int)capacity(), (int)mCount); - - void* buffer = editArrayImpl(); - if (buffer) - return reinterpret_cast<char*>(buffer) + index*mItemSize; - return 0; -} - -const void* VectorImpl::itemLocation(size_t index) const -{ - LOG_ASSERT(index<capacity(), - "[%p] editItemLocation: index=%d, capacity=%d, count=%d", - this, (int)index, (int)capacity(), (int)mCount); - - const void* buffer = arrayImpl(); - if (buffer) - return reinterpret_cast<const char*>(buffer) + index*mItemSize; - return 0; -} - -ssize_t VectorImpl::setCapacity(size_t new_capacity) -{ - size_t current_capacity = capacity(); - ssize_t amount = new_capacity - size(); - if (amount <= 0) { - // we can't reduce the capacity - return current_capacity; - } - SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize); - if (sb) { - void* array = sb->data(); - _do_copy(array, mStorage, size()); - release_storage(); - mStorage = const_cast<void*>(array); - } else { - return NO_MEMORY; - } - return new_capacity; -} - -void VectorImpl::release_storage() -{ - if (mStorage) { - const SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage); - if (sb->release(SharedBuffer::eKeepStorage) == 1) { - _do_destroy(mStorage, mCount); - SharedBuffer::dealloc(sb); - } - } -} - -void* VectorImpl::_grow(size_t where, size_t amount) -{ -// LOGV("_grow(this=%p, where=%d, amount=%d) count=%d, capacity=%d", -// this, (int)where, (int)amount, (int)mCount, (int)capacity()); - - if (where > mCount) - where = mCount; - - const size_t new_size = mCount + amount; - if (capacity() < new_size) { - const size_t new_capacity = max(kMinVectorCapacity, ((new_size*3)+1)/2); -// LOGV("grow vector %p, new_capacity=%d", this, (int)new_capacity); - if ((mStorage) && - (mCount==where) && - (mFlags & HAS_TRIVIAL_COPY) && - (mFlags & HAS_TRIVIAL_DTOR)) - { - const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage); - SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize); - mStorage = sb->data(); - } else { - SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize); - if (sb) { - void* array = sb->data(); - if (where>0) { - _do_copy(array, mStorage, where); - } - if (mCount>where) { - const void* from = reinterpret_cast<const uint8_t *>(mStorage) + where*mItemSize; - void* dest = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize; - _do_copy(dest, from, mCount-where); - } - release_storage(); - mStorage = const_cast<void*>(array); - } - } - } else { - ssize_t s = mCount-where; - if (s>0) { - void* array = editArrayImpl(); - void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize; - const void* from = reinterpret_cast<const uint8_t *>(array) + where*mItemSize; - _do_move_forward(to, from, s); - } - } - mCount += amount; - void* free_space = const_cast<void*>(itemLocation(where)); - return free_space; -} - -void VectorImpl::_shrink(size_t where, size_t amount) -{ - if (!mStorage) - return; - -// LOGV("_shrink(this=%p, where=%d, amount=%d) count=%d, capacity=%d", -// this, (int)where, (int)amount, (int)mCount, (int)capacity()); - - if (where >= mCount) - where = mCount - amount; - - const size_t new_size = mCount - amount; - if (new_size*3 < capacity()) { - const size_t new_capacity = max(kMinVectorCapacity, new_size*2); -// LOGV("shrink vector %p, new_capacity=%d", this, (int)new_capacity); - if ((where == mCount-amount) && - (mFlags & HAS_TRIVIAL_COPY) && - (mFlags & HAS_TRIVIAL_DTOR)) - { - const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage); - SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize); - mStorage = sb->data(); - } else { - SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize); - if (sb) { - void* array = sb->data(); - if (where>0) { - _do_copy(array, mStorage, where); - } - if (mCount > where+amount) { - const void* from = reinterpret_cast<const uint8_t *>(mStorage) + (where+amount)*mItemSize; - void* dest = reinterpret_cast<uint8_t *>(array) + where*mItemSize; - _do_copy(dest, from, mCount-(where+amount)); - } - release_storage(); - mStorage = const_cast<void*>(array); - } - } - } else { - void* array = editArrayImpl(); - void* to = reinterpret_cast<uint8_t *>(array) + where*mItemSize; - _do_destroy(to, amount); - ssize_t s = mCount-(where+amount); - if (s>0) { - const void* from = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize; - _do_move_backward(to, from, s); - } - } - - // adjust the number of items... - mCount -= amount; -} - -size_t VectorImpl::itemSize() const { - return mItemSize; -} - -void VectorImpl::_do_construct(void* storage, size_t num) const -{ - if (!(mFlags & HAS_TRIVIAL_CTOR)) { - do_construct(storage, num); - } -} - -void VectorImpl::_do_destroy(void* storage, size_t num) const -{ - if (!(mFlags & HAS_TRIVIAL_DTOR)) { - do_destroy(storage, num); - } -} - -void VectorImpl::_do_copy(void* dest, const void* from, size_t num) const -{ - if (!(mFlags & HAS_TRIVIAL_COPY)) { - do_copy(dest, from, num); - } else { - memcpy(dest, from, num*itemSize()); - } -} - -void VectorImpl::_do_splat(void* dest, const void* item, size_t num) const { - do_splat(dest, item, num); -} - -void VectorImpl::_do_move_forward(void* dest, const void* from, size_t num) const { - do_move_forward(dest, from, num); -} - -void VectorImpl::_do_move_backward(void* dest, const void* from, size_t num) const { - do_move_backward(dest, from, num); -} - -void VectorImpl::reservedVectorImpl1() { } -void VectorImpl::reservedVectorImpl2() { } -void VectorImpl::reservedVectorImpl3() { } -void VectorImpl::reservedVectorImpl4() { } -void VectorImpl::reservedVectorImpl5() { } -void VectorImpl::reservedVectorImpl6() { } -void VectorImpl::reservedVectorImpl7() { } -void VectorImpl::reservedVectorImpl8() { } - -/*****************************************************************************/ - -SortedVectorImpl::SortedVectorImpl(size_t itemSize, uint32_t flags) - : VectorImpl(itemSize, flags) -{ -} - -SortedVectorImpl::SortedVectorImpl(const VectorImpl& rhs) -: VectorImpl(rhs) -{ -} - -SortedVectorImpl::~SortedVectorImpl() -{ -} - -SortedVectorImpl& SortedVectorImpl::operator = (const SortedVectorImpl& rhs) -{ - return static_cast<SortedVectorImpl&>( VectorImpl::operator = (static_cast<const VectorImpl&>(rhs)) ); -} - -ssize_t SortedVectorImpl::indexOf(const void* item) const -{ - return _indexOrderOf(item); -} - -size_t SortedVectorImpl::orderOf(const void* item) const -{ - size_t o; - _indexOrderOf(item, &o); - return o; -} - -ssize_t SortedVectorImpl::_indexOrderOf(const void* item, size_t* order) const -{ - // binary search - ssize_t err = NAME_NOT_FOUND; - ssize_t l = 0; - ssize_t h = size()-1; - ssize_t mid; - const void* a = arrayImpl(); - const size_t s = itemSize(); - while (l <= h) { - mid = l + (h - l)/2; - const void* const curr = reinterpret_cast<const char *>(a) + (mid*s); - const int c = do_compare(curr, item); - if (c == 0) { - err = l = mid; - break; - } else if (c < 0) { - l = mid + 1; - } else { - h = mid - 1; - } - } - if (order) *order = l; - return err; -} - -ssize_t SortedVectorImpl::add(const void* item) -{ - size_t order; - ssize_t index = _indexOrderOf(item, &order); - if (index < 0) { - index = VectorImpl::insertAt(item, order, 1); - } else { - index = VectorImpl::replaceAt(item, index); - } - return index; -} - -ssize_t SortedVectorImpl::merge(const VectorImpl& vector) -{ - // naive merge... - if (!vector.isEmpty()) { - const void* buffer = vector.arrayImpl(); - const size_t is = itemSize(); - size_t s = vector.size(); - for (size_t i=0 ; i<s ; i++) { - ssize_t err = add( reinterpret_cast<const char*>(buffer) + i*is ); - if (err<0) { - return err; - } - } - } - return NO_ERROR; -} - -ssize_t SortedVectorImpl::merge(const SortedVectorImpl& vector) -{ - // we've merging a sorted vector... nice! - ssize_t err = NO_ERROR; - if (!vector.isEmpty()) { - // first take care of the case where the vectors are sorted together - if (do_compare(vector.itemLocation(vector.size()-1), arrayImpl()) <= 0) { - err = VectorImpl::insertVectorAt(static_cast<const VectorImpl&>(vector), 0); - } else if (do_compare(vector.arrayImpl(), itemLocation(size()-1)) >= 0) { - err = VectorImpl::appendVector(static_cast<const VectorImpl&>(vector)); - } else { - // this could be made a little better - err = merge(static_cast<const VectorImpl&>(vector)); - } - } - return err; -} - -ssize_t SortedVectorImpl::remove(const void* item) -{ - ssize_t i = indexOf(item); - if (i>=0) { - VectorImpl::removeItemsAt(i, 1); - } - return i; -} - -void SortedVectorImpl::reservedSortedVectorImpl1() { }; -void SortedVectorImpl::reservedSortedVectorImpl2() { }; -void SortedVectorImpl::reservedSortedVectorImpl3() { }; -void SortedVectorImpl::reservedSortedVectorImpl4() { }; -void SortedVectorImpl::reservedSortedVectorImpl5() { }; -void SortedVectorImpl::reservedSortedVectorImpl6() { }; -void SortedVectorImpl::reservedSortedVectorImpl7() { }; -void SortedVectorImpl::reservedSortedVectorImpl8() { }; - - -/*****************************************************************************/ - -}; // namespace android - diff --git a/libs/utils/ZipEntry.cpp b/libs/utils/ZipEntry.cpp deleted file mode 100644 index fbc9e67..0000000 --- a/libs/utils/ZipEntry.cpp +++ /dev/null @@ -1,696 +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 to entries in a Zip archive. -// - -#define LOG_TAG "zip" - -#include "utils/ZipEntry.h" -#include "utils/Log.h" - -#include <stdio.h> -#include <string.h> -#include <assert.h> - -using namespace android; - -/* - * Initialize a new ZipEntry structure from a FILE* positioned at a - * CentralDirectoryEntry. - * - * On exit, the file pointer will be at the start of the next CDE or - * at the EOCD. - */ -status_t ZipEntry::initFromCDE(FILE* fp) -{ - status_t result; - long posn; - bool hasDD; - - //LOGV("initFromCDE ---\n"); - - /* read the CDE */ - result = mCDE.read(fp); - if (result != NO_ERROR) { - LOGD("mCDE.read failed\n"); - return result; - } - - //mCDE.dump(); - - /* using the info in the CDE, go load up the LFH */ - posn = ftell(fp); - if (fseek(fp, mCDE.mLocalHeaderRelOffset, SEEK_SET) != 0) { - LOGD("local header seek failed (%ld)\n", - mCDE.mLocalHeaderRelOffset); - return UNKNOWN_ERROR; - } - - result = mLFH.read(fp); - if (result != NO_ERROR) { - LOGD("mLFH.read failed\n"); - return result; - } - - if (fseek(fp, posn, SEEK_SET) != 0) - return UNKNOWN_ERROR; - - //mLFH.dump(); - - /* - * We *might* need to read the Data Descriptor at this point and - * integrate it into the LFH. If this bit is set, the CRC-32, - * compressed size, and uncompressed size will be zero. In practice - * these seem to be rare. - */ - hasDD = (mLFH.mGPBitFlag & kUsesDataDescr) != 0; - if (hasDD) { - // do something clever - //LOGD("+++ has data descriptor\n"); - } - - /* - * Sanity-check the LFH. Note that this will fail if the "kUsesDataDescr" - * flag is set, because the LFH is incomplete. (Not a problem, since we - * prefer the CDE values.) - */ - if (!hasDD && !compareHeaders()) { - LOGW("WARNING: header mismatch\n"); - // keep going? - } - - /* - * If the mVersionToExtract is greater than 20, we may have an - * issue unpacking the record -- could be encrypted, compressed - * with something we don't support, or use Zip64 extensions. We - * can defer worrying about that to when we're extracting data. - */ - - return NO_ERROR; -} - -/* - * Initialize a new entry. Pass in the file name and an optional comment. - * - * Initializes the CDE and the LFH. - */ -void ZipEntry::initNew(const char* fileName, const char* comment) -{ - assert(fileName != NULL && *fileName != '\0'); // name required - - /* most fields are properly initialized by constructor */ - mCDE.mVersionMadeBy = kDefaultMadeBy; - mCDE.mVersionToExtract = kDefaultVersion; - mCDE.mCompressionMethod = kCompressStored; - mCDE.mFileNameLength = strlen(fileName); - if (comment != NULL) - mCDE.mFileCommentLength = strlen(comment); - mCDE.mExternalAttrs = 0x81b60020; // matches what WinZip does - - if (mCDE.mFileNameLength > 0) { - mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1]; - strcpy((char*) mCDE.mFileName, fileName); - } - if (mCDE.mFileCommentLength > 0) { - /* TODO: stop assuming null-terminated ASCII here? */ - mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1]; - strcpy((char*) mCDE.mFileComment, comment); - } - - copyCDEtoLFH(); -} - -/* - * Initialize a new entry, starting with the ZipEntry from a different - * archive. - * - * Initializes the CDE and the LFH. - */ -status_t ZipEntry::initFromExternal(const ZipFile* pZipFile, - const ZipEntry* pEntry) -{ - /* - * Copy everything in the CDE over, then fix up the hairy bits. - */ - memcpy(&mCDE, &pEntry->mCDE, sizeof(mCDE)); - - if (mCDE.mFileNameLength > 0) { - mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1]; - if (mCDE.mFileName == NULL) - return NO_MEMORY; - strcpy((char*) mCDE.mFileName, (char*)pEntry->mCDE.mFileName); - } - if (mCDE.mFileCommentLength > 0) { - mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1]; - if (mCDE.mFileComment == NULL) - return NO_MEMORY; - strcpy((char*) mCDE.mFileComment, (char*)pEntry->mCDE.mFileComment); - } - if (mCDE.mExtraFieldLength > 0) { - /* we null-terminate this, though it may not be a string */ - mCDE.mExtraField = new unsigned char[mCDE.mExtraFieldLength+1]; - if (mCDE.mExtraField == NULL) - return NO_MEMORY; - memcpy(mCDE.mExtraField, pEntry->mCDE.mExtraField, - mCDE.mExtraFieldLength+1); - } - - /* construct the LFH from the CDE */ - copyCDEtoLFH(); - - /* - * The LFH "extra" field is independent of the CDE "extra", so we - * handle it here. - */ - assert(mLFH.mExtraField == NULL); - mLFH.mExtraFieldLength = pEntry->mLFH.mExtraFieldLength; - if (mLFH.mExtraFieldLength > 0) { - mLFH.mExtraField = new unsigned char[mLFH.mExtraFieldLength+1]; - if (mLFH.mExtraField == NULL) - return NO_MEMORY; - memcpy(mLFH.mExtraField, pEntry->mLFH.mExtraField, - mLFH.mExtraFieldLength+1); - } - - return NO_ERROR; -} - -/* - * Insert pad bytes in the LFH by tweaking the "extra" field. This will - * potentially confuse something that put "extra" data in here earlier, - * but I can't find an actual problem. - */ -status_t ZipEntry::addPadding(int padding) -{ - if (padding <= 0) - return INVALID_OPERATION; - - //LOGI("HEY: adding %d pad bytes to existing %d in %s\n", - // padding, mLFH.mExtraFieldLength, mCDE.mFileName); - - if (mLFH.mExtraFieldLength > 0) { - /* extend existing field */ - unsigned char* newExtra; - - newExtra = new unsigned char[mLFH.mExtraFieldLength + padding]; - if (newExtra == NULL) - return NO_MEMORY; - memset(newExtra + mLFH.mExtraFieldLength, 0, padding); - memcpy(newExtra, mLFH.mExtraField, mLFH.mExtraFieldLength); - - delete[] mLFH.mExtraField; - mLFH.mExtraField = newExtra; - mLFH.mExtraFieldLength += padding; - } else { - /* create new field */ - mLFH.mExtraField = new unsigned char[padding]; - memset(mLFH.mExtraField, 0, padding); - mLFH.mExtraFieldLength = padding; - } - - return NO_ERROR; -} - -/* - * Set the fields in the LFH equal to the corresponding fields in the CDE. - * - * This does not touch the LFH "extra" field. - */ -void ZipEntry::copyCDEtoLFH(void) -{ - mLFH.mVersionToExtract = mCDE.mVersionToExtract; - mLFH.mGPBitFlag = mCDE.mGPBitFlag; - mLFH.mCompressionMethod = mCDE.mCompressionMethod; - mLFH.mLastModFileTime = mCDE.mLastModFileTime; - mLFH.mLastModFileDate = mCDE.mLastModFileDate; - mLFH.mCRC32 = mCDE.mCRC32; - mLFH.mCompressedSize = mCDE.mCompressedSize; - mLFH.mUncompressedSize = mCDE.mUncompressedSize; - mLFH.mFileNameLength = mCDE.mFileNameLength; - // the "extra field" is independent - - delete[] mLFH.mFileName; - if (mLFH.mFileNameLength > 0) { - mLFH.mFileName = new unsigned char[mLFH.mFileNameLength+1]; - strcpy((char*) mLFH.mFileName, (const char*) mCDE.mFileName); - } else { - mLFH.mFileName = NULL; - } -} - -/* - * Set some information about a file after we add it. - */ -void ZipEntry::setDataInfo(long uncompLen, long compLen, unsigned long crc32, - int compressionMethod) -{ - mCDE.mCompressionMethod = compressionMethod; - mCDE.mCRC32 = crc32; - mCDE.mCompressedSize = compLen; - mCDE.mUncompressedSize = uncompLen; - mCDE.mCompressionMethod = compressionMethod; - if (compressionMethod == kCompressDeflated) { - mCDE.mGPBitFlag |= 0x0002; // indicates maximum compression used - } - copyCDEtoLFH(); -} - -/* - * See if the data in mCDE and mLFH match up. This is mostly useful for - * debugging these classes, but it can be used to identify damaged - * archives. - * - * Returns "false" if they differ. - */ -bool ZipEntry::compareHeaders(void) const -{ - if (mCDE.mVersionToExtract != mLFH.mVersionToExtract) { - LOGV("cmp: VersionToExtract\n"); - return false; - } - if (mCDE.mGPBitFlag != mLFH.mGPBitFlag) { - LOGV("cmp: GPBitFlag\n"); - return false; - } - if (mCDE.mCompressionMethod != mLFH.mCompressionMethod) { - LOGV("cmp: CompressionMethod\n"); - return false; - } - if (mCDE.mLastModFileTime != mLFH.mLastModFileTime) { - LOGV("cmp: LastModFileTime\n"); - return false; - } - if (mCDE.mLastModFileDate != mLFH.mLastModFileDate) { - LOGV("cmp: LastModFileDate\n"); - return false; - } - if (mCDE.mCRC32 != mLFH.mCRC32) { - LOGV("cmp: CRC32\n"); - return false; - } - if (mCDE.mCompressedSize != mLFH.mCompressedSize) { - LOGV("cmp: CompressedSize\n"); - return false; - } - if (mCDE.mUncompressedSize != mLFH.mUncompressedSize) { - LOGV("cmp: UncompressedSize\n"); - return false; - } - if (mCDE.mFileNameLength != mLFH.mFileNameLength) { - LOGV("cmp: FileNameLength\n"); - return false; - } -#if 0 // this seems to be used for padding, not real data - if (mCDE.mExtraFieldLength != mLFH.mExtraFieldLength) { - LOGV("cmp: ExtraFieldLength\n"); - return false; - } -#endif - if (mCDE.mFileName != NULL) { - if (strcmp((char*) mCDE.mFileName, (char*) mLFH.mFileName) != 0) { - LOGV("cmp: FileName\n"); - return false; - } - } - - return true; -} - - -/* - * Convert the DOS date/time stamp into a UNIX time stamp. - */ -time_t ZipEntry::getModWhen(void) const -{ - struct tm parts; - - parts.tm_sec = (mCDE.mLastModFileTime & 0x001f) << 1; - parts.tm_min = (mCDE.mLastModFileTime & 0x07e0) >> 5; - parts.tm_hour = (mCDE.mLastModFileTime & 0xf800) >> 11; - parts.tm_mday = (mCDE.mLastModFileDate & 0x001f); - parts.tm_mon = ((mCDE.mLastModFileDate & 0x01e0) >> 5) -1; - parts.tm_year = ((mCDE.mLastModFileDate & 0xfe00) >> 9) + 80; - parts.tm_wday = parts.tm_yday = 0; - parts.tm_isdst = -1; // DST info "not available" - - return mktime(&parts); -} - -/* - * Set the CDE/LFH timestamp from UNIX time. - */ -void ZipEntry::setModWhen(time_t when) -{ -#ifdef HAVE_LOCALTIME_R - struct tm tmResult; -#endif - time_t even; - unsigned short zdate, ztime; - - struct tm* ptm; - - /* round up to an even number of seconds */ - even = (time_t)(((unsigned long)(when) + 1) & (~1)); - - /* expand */ -#ifdef HAVE_LOCALTIME_R - ptm = localtime_r(&even, &tmResult); -#else - ptm = localtime(&even); -#endif - - int year; - year = ptm->tm_year; - if (year < 80) - year = 80; - - zdate = (year - 80) << 9 | (ptm->tm_mon+1) << 5 | ptm->tm_mday; - ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1; - - mCDE.mLastModFileTime = mLFH.mLastModFileTime = ztime; - mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate; -} - - -/* - * =========================================================================== - * ZipEntry::LocalFileHeader - * =========================================================================== - */ - -/* - * Read a local file header. - * - * On entry, "fp" points to the signature at the start of the header. - * On exit, "fp" points to the start of data. - */ -status_t ZipEntry::LocalFileHeader::read(FILE* fp) -{ - status_t result = NO_ERROR; - unsigned char buf[kLFHLen]; - - assert(mFileName == NULL); - assert(mExtraField == NULL); - - if (fread(buf, 1, kLFHLen, fp) != kLFHLen) { - result = UNKNOWN_ERROR; - goto bail; - } - - if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) { - LOGD("whoops: didn't find expected signature\n"); - result = UNKNOWN_ERROR; - goto bail; - } - - mVersionToExtract = ZipEntry::getShortLE(&buf[0x04]); - mGPBitFlag = ZipEntry::getShortLE(&buf[0x06]); - mCompressionMethod = ZipEntry::getShortLE(&buf[0x08]); - mLastModFileTime = ZipEntry::getShortLE(&buf[0x0a]); - mLastModFileDate = ZipEntry::getShortLE(&buf[0x0c]); - mCRC32 = ZipEntry::getLongLE(&buf[0x0e]); - mCompressedSize = ZipEntry::getLongLE(&buf[0x12]); - mUncompressedSize = ZipEntry::getLongLE(&buf[0x16]); - mFileNameLength = ZipEntry::getShortLE(&buf[0x1a]); - mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1c]); - - // TODO: validate sizes - - /* grab filename */ - if (mFileNameLength != 0) { - mFileName = new unsigned char[mFileNameLength+1]; - if (mFileName == NULL) { - result = NO_MEMORY; - goto bail; - } - if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) { - result = UNKNOWN_ERROR; - goto bail; - } - mFileName[mFileNameLength] = '\0'; - } - - /* grab extra field */ - if (mExtraFieldLength != 0) { - mExtraField = new unsigned char[mExtraFieldLength+1]; - if (mExtraField == NULL) { - result = NO_MEMORY; - goto bail; - } - if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) { - result = UNKNOWN_ERROR; - goto bail; - } - mExtraField[mExtraFieldLength] = '\0'; - } - -bail: - return result; -} - -/* - * Write a local file header. - */ -status_t ZipEntry::LocalFileHeader::write(FILE* fp) -{ - unsigned char buf[kLFHLen]; - - ZipEntry::putLongLE(&buf[0x00], kSignature); - ZipEntry::putShortLE(&buf[0x04], mVersionToExtract); - ZipEntry::putShortLE(&buf[0x06], mGPBitFlag); - ZipEntry::putShortLE(&buf[0x08], mCompressionMethod); - ZipEntry::putShortLE(&buf[0x0a], mLastModFileTime); - ZipEntry::putShortLE(&buf[0x0c], mLastModFileDate); - ZipEntry::putLongLE(&buf[0x0e], mCRC32); - ZipEntry::putLongLE(&buf[0x12], mCompressedSize); - ZipEntry::putLongLE(&buf[0x16], mUncompressedSize); - ZipEntry::putShortLE(&buf[0x1a], mFileNameLength); - ZipEntry::putShortLE(&buf[0x1c], mExtraFieldLength); - - if (fwrite(buf, 1, kLFHLen, fp) != kLFHLen) - return UNKNOWN_ERROR; - - /* write filename */ - if (mFileNameLength != 0) { - if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength) - return UNKNOWN_ERROR; - } - - /* write "extra field" */ - if (mExtraFieldLength != 0) { - if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) - return UNKNOWN_ERROR; - } - - return NO_ERROR; -} - - -/* - * Dump the contents of a LocalFileHeader object. - */ -void ZipEntry::LocalFileHeader::dump(void) const -{ - LOGD(" LocalFileHeader contents:\n"); - LOGD(" versToExt=%u gpBits=0x%04x compression=%u\n", - mVersionToExtract, mGPBitFlag, mCompressionMethod); - LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n", - mLastModFileTime, mLastModFileDate, mCRC32); - LOGD(" compressedSize=%lu uncompressedSize=%lu\n", - mCompressedSize, mUncompressedSize); - LOGD(" filenameLen=%u extraLen=%u\n", - mFileNameLength, mExtraFieldLength); - if (mFileName != NULL) - LOGD(" filename: '%s'\n", mFileName); -} - - -/* - * =========================================================================== - * ZipEntry::CentralDirEntry - * =========================================================================== - */ - -/* - * Read the central dir entry that appears next in the file. - * - * On entry, "fp" should be positioned on the signature bytes for the - * entry. On exit, "fp" will point at the signature word for the next - * entry or for the EOCD. - */ -status_t ZipEntry::CentralDirEntry::read(FILE* fp) -{ - status_t result = NO_ERROR; - unsigned char buf[kCDELen]; - - /* no re-use */ - assert(mFileName == NULL); - assert(mExtraField == NULL); - assert(mFileComment == NULL); - - if (fread(buf, 1, kCDELen, fp) != kCDELen) { - result = UNKNOWN_ERROR; - goto bail; - } - - if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) { - LOGD("Whoops: didn't find expected signature\n"); - result = UNKNOWN_ERROR; - goto bail; - } - - mVersionMadeBy = ZipEntry::getShortLE(&buf[0x04]); - mVersionToExtract = ZipEntry::getShortLE(&buf[0x06]); - mGPBitFlag = ZipEntry::getShortLE(&buf[0x08]); - mCompressionMethod = ZipEntry::getShortLE(&buf[0x0a]); - mLastModFileTime = ZipEntry::getShortLE(&buf[0x0c]); - mLastModFileDate = ZipEntry::getShortLE(&buf[0x0e]); - mCRC32 = ZipEntry::getLongLE(&buf[0x10]); - mCompressedSize = ZipEntry::getLongLE(&buf[0x14]); - mUncompressedSize = ZipEntry::getLongLE(&buf[0x18]); - mFileNameLength = ZipEntry::getShortLE(&buf[0x1c]); - mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1e]); - mFileCommentLength = ZipEntry::getShortLE(&buf[0x20]); - mDiskNumberStart = ZipEntry::getShortLE(&buf[0x22]); - mInternalAttrs = ZipEntry::getShortLE(&buf[0x24]); - mExternalAttrs = ZipEntry::getLongLE(&buf[0x26]); - mLocalHeaderRelOffset = ZipEntry::getLongLE(&buf[0x2a]); - - // TODO: validate sizes and offsets - - /* grab filename */ - if (mFileNameLength != 0) { - mFileName = new unsigned char[mFileNameLength+1]; - if (mFileName == NULL) { - result = NO_MEMORY; - goto bail; - } - if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) { - result = UNKNOWN_ERROR; - goto bail; - } - mFileName[mFileNameLength] = '\0'; - } - - /* read "extra field" */ - if (mExtraFieldLength != 0) { - mExtraField = new unsigned char[mExtraFieldLength+1]; - if (mExtraField == NULL) { - result = NO_MEMORY; - goto bail; - } - if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) { - result = UNKNOWN_ERROR; - goto bail; - } - mExtraField[mExtraFieldLength] = '\0'; - } - - - /* grab comment, if any */ - if (mFileCommentLength != 0) { - mFileComment = new unsigned char[mFileCommentLength+1]; - if (mFileComment == NULL) { - result = NO_MEMORY; - goto bail; - } - if (fread(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength) - { - result = UNKNOWN_ERROR; - goto bail; - } - mFileComment[mFileCommentLength] = '\0'; - } - -bail: - return result; -} - -/* - * Write a central dir entry. - */ -status_t ZipEntry::CentralDirEntry::write(FILE* fp) -{ - unsigned char buf[kCDELen]; - - ZipEntry::putLongLE(&buf[0x00], kSignature); - ZipEntry::putShortLE(&buf[0x04], mVersionMadeBy); - ZipEntry::putShortLE(&buf[0x06], mVersionToExtract); - ZipEntry::putShortLE(&buf[0x08], mGPBitFlag); - ZipEntry::putShortLE(&buf[0x0a], mCompressionMethod); - ZipEntry::putShortLE(&buf[0x0c], mLastModFileTime); - ZipEntry::putShortLE(&buf[0x0e], mLastModFileDate); - ZipEntry::putLongLE(&buf[0x10], mCRC32); - ZipEntry::putLongLE(&buf[0x14], mCompressedSize); - ZipEntry::putLongLE(&buf[0x18], mUncompressedSize); - ZipEntry::putShortLE(&buf[0x1c], mFileNameLength); - ZipEntry::putShortLE(&buf[0x1e], mExtraFieldLength); - ZipEntry::putShortLE(&buf[0x20], mFileCommentLength); - ZipEntry::putShortLE(&buf[0x22], mDiskNumberStart); - ZipEntry::putShortLE(&buf[0x24], mInternalAttrs); - ZipEntry::putLongLE(&buf[0x26], mExternalAttrs); - ZipEntry::putLongLE(&buf[0x2a], mLocalHeaderRelOffset); - - if (fwrite(buf, 1, kCDELen, fp) != kCDELen) - return UNKNOWN_ERROR; - - /* write filename */ - if (mFileNameLength != 0) { - if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength) - return UNKNOWN_ERROR; - } - - /* write "extra field" */ - if (mExtraFieldLength != 0) { - if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) - return UNKNOWN_ERROR; - } - - /* write comment */ - if (mFileCommentLength != 0) { - if (fwrite(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength) - return UNKNOWN_ERROR; - } - - return NO_ERROR; -} - -/* - * Dump the contents of a CentralDirEntry object. - */ -void ZipEntry::CentralDirEntry::dump(void) const -{ - LOGD(" CentralDirEntry contents:\n"); - LOGD(" versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n", - mVersionMadeBy, mVersionToExtract, mGPBitFlag, mCompressionMethod); - LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n", - mLastModFileTime, mLastModFileDate, mCRC32); - LOGD(" compressedSize=%lu uncompressedSize=%lu\n", - mCompressedSize, mUncompressedSize); - LOGD(" filenameLen=%u extraLen=%u commentLen=%u\n", - mFileNameLength, mExtraFieldLength, mFileCommentLength); - LOGD(" diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n", - mDiskNumberStart, mInternalAttrs, mExternalAttrs, - mLocalHeaderRelOffset); - - if (mFileName != NULL) - LOGD(" filename: '%s'\n", mFileName); - if (mFileComment != NULL) - LOGD(" comment: '%s'\n", mFileComment); -} - diff --git a/libs/utils/ZipFile.cpp b/libs/utils/ZipFile.cpp deleted file mode 100644 index 89aa874..0000000 --- a/libs/utils/ZipFile.cpp +++ /dev/null @@ -1,1296 +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 to Zip archives. -// - -#define LOG_TAG "zip" - -#include "utils/ZipFile.h" -#include "utils/ZipUtils.h" -#include "utils/Log.h" - -#include <zlib.h> -#define DEF_MEM_LEVEL 8 // normally in zutil.h? - -#include <memory.h> -#include <sys/stat.h> -#include <errno.h> -#include <assert.h> - -using namespace android; - -/* - * Some environments require the "b", some choke on it. - */ -#define FILE_OPEN_RO "rb" -#define FILE_OPEN_RW "r+b" -#define FILE_OPEN_RW_CREATE "w+b" - -/* should live somewhere else? */ -static status_t errnoToStatus(int err) -{ - if (err == ENOENT) - return NAME_NOT_FOUND; - else if (err == EACCES) - return PERMISSION_DENIED; - else - return UNKNOWN_ERROR; -} - -/* - * Open a file and parse its guts. - */ -status_t ZipFile::open(const char* zipFileName, int flags) -{ - bool newArchive = false; - - assert(mZipFp == NULL); // no reopen - - if ((flags & kOpenTruncate)) - flags |= kOpenCreate; // trunc implies create - - if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite)) - return INVALID_OPERATION; // not both - if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite))) - return INVALID_OPERATION; // not neither - if ((flags & kOpenCreate) && !(flags & kOpenReadWrite)) - return INVALID_OPERATION; // create requires write - - if (flags & kOpenTruncate) { - newArchive = true; - } else { - newArchive = (access(zipFileName, F_OK) != 0); - if (!(flags & kOpenCreate) && newArchive) { - /* not creating, must already exist */ - LOGD("File %s does not exist", zipFileName); - return NAME_NOT_FOUND; - } - } - - /* open the file */ - const char* openflags; - if (flags & kOpenReadWrite) { - if (newArchive) - openflags = FILE_OPEN_RW_CREATE; - else - openflags = FILE_OPEN_RW; - } else { - openflags = FILE_OPEN_RO; - } - mZipFp = fopen(zipFileName, openflags); - if (mZipFp == NULL) { - int err = errno; - LOGD("fopen failed: %d\n", err); - return errnoToStatus(err); - } - - status_t result; - if (!newArchive) { - /* - * Load the central directory. If that fails, then this probably - * isn't a Zip archive. - */ - result = readCentralDir(); - } else { - /* - * Newly-created. The EndOfCentralDir constructor actually - * sets everything to be the way we want it (all zeroes). We - * set mNeedCDRewrite so that we create *something* if the - * caller doesn't add any files. (We could also just unlink - * the file if it's brand new and nothing was added, but that's - * probably doing more than we really should -- the user might - * have a need for empty zip files.) - */ - mNeedCDRewrite = true; - result = NO_ERROR; - } - - if (flags & kOpenReadOnly) - mReadOnly = true; - else - assert(!mReadOnly); - - return result; -} - -/* - * Return the Nth entry in the archive. - */ -ZipEntry* ZipFile::getEntryByIndex(int idx) const -{ - if (idx < 0 || idx >= (int) mEntries.size()) - return NULL; - - return mEntries[idx]; -} - -/* - * Find an entry by name. - */ -ZipEntry* ZipFile::getEntryByName(const char* fileName) const -{ - /* - * Do a stupid linear string-compare search. - * - * There are various ways to speed this up, especially since it's rare - * to intermingle changes to the archive with "get by name" calls. We - * don't want to sort the mEntries vector itself, however, because - * it's used to recreate the Central Directory. - * - * (Hash table works, parallel list of pointers in sorted order is good.) - */ - int idx; - - for (idx = mEntries.size()-1; idx >= 0; idx--) { - ZipEntry* pEntry = mEntries[idx]; - if (!pEntry->getDeleted() && - strcmp(fileName, pEntry->getFileName()) == 0) - { - return pEntry; - } - } - - return NULL; -} - -/* - * Empty the mEntries vector. - */ -void ZipFile::discardEntries(void) -{ - int count = mEntries.size(); - - while (--count >= 0) - delete mEntries[count]; - - mEntries.clear(); -} - - -/* - * Find the central directory and read the contents. - * - * The fun thing about ZIP archives is that they may or may not be - * readable from start to end. In some cases, notably for archives - * that were written to stdout, the only length information is in the - * central directory at the end of the file. - * - * Of course, the central directory can be followed by a variable-length - * comment field, so we have to scan through it backwards. The comment - * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff - * itself, plus apparently sometimes people throw random junk on the end - * just for the fun of it. - * - * This is all a little wobbly. If the wrong value ends up in the EOCD - * area, we're hosed. This appears to be the way that everbody handles - * it though, so we're in pretty good company if this fails. - */ -status_t ZipFile::readCentralDir(void) -{ - status_t result = NO_ERROR; - unsigned char* buf = NULL; - off_t fileLength, seekStart; - long readAmount; - int i; - - fseek(mZipFp, 0, SEEK_END); - fileLength = ftell(mZipFp); - rewind(mZipFp); - - /* too small to be a ZIP archive? */ - if (fileLength < EndOfCentralDir::kEOCDLen) { - LOGD("Length is %ld -- too small\n", (long)fileLength); - result = INVALID_OPERATION; - goto bail; - } - - buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch]; - if (buf == NULL) { - LOGD("Failure allocating %d bytes for EOCD search", - EndOfCentralDir::kMaxEOCDSearch); - result = NO_MEMORY; - goto bail; - } - - if (fileLength > EndOfCentralDir::kMaxEOCDSearch) { - seekStart = fileLength - EndOfCentralDir::kMaxEOCDSearch; - readAmount = EndOfCentralDir::kMaxEOCDSearch; - } else { - seekStart = 0; - readAmount = (long) fileLength; - } - if (fseek(mZipFp, seekStart, SEEK_SET) != 0) { - LOGD("Failure seeking to end of zip at %ld", (long) seekStart); - result = UNKNOWN_ERROR; - goto bail; - } - - /* read the last part of the file into the buffer */ - if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) { - LOGD("short file? wanted %ld\n", readAmount); - result = UNKNOWN_ERROR; - goto bail; - } - - /* find the end-of-central-dir magic */ - for (i = readAmount - 4; i >= 0; i--) { - if (buf[i] == 0x50 && - ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature) - { - LOGV("+++ Found EOCD at buf+%d\n", i); - break; - } - } - if (i < 0) { - LOGD("EOCD not found, not Zip\n"); - result = INVALID_OPERATION; - goto bail; - } - - /* extract eocd values */ - result = mEOCD.readBuf(buf + i, readAmount - i); - if (result != NO_ERROR) { - LOGD("Failure reading %ld bytes of EOCD values", readAmount - i); - goto bail; - } - //mEOCD.dump(); - - if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 || - mEOCD.mNumEntries != mEOCD.mTotalNumEntries) - { - LOGD("Archive spanning not supported\n"); - result = INVALID_OPERATION; - goto bail; - } - - /* - * So far so good. "mCentralDirSize" is the size in bytes of the - * central directory, so we can just seek back that far to find it. - * We can also seek forward mCentralDirOffset bytes from the - * start of the file. - * - * We're not guaranteed to have the rest of the central dir in the - * buffer, nor are we guaranteed that the central dir will have any - * sort of convenient size. We need to skip to the start of it and - * read the header, then the other goodies. - * - * The only thing we really need right now is the file comment, which - * we're hoping to preserve. - */ - if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) { - LOGD("Failure seeking to central dir offset %ld\n", - mEOCD.mCentralDirOffset); - result = UNKNOWN_ERROR; - goto bail; - } - - /* - * Loop through and read the central dir entries. - */ - LOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries); - int entry; - for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) { - ZipEntry* pEntry = new ZipEntry; - - result = pEntry->initFromCDE(mZipFp); - if (result != NO_ERROR) { - LOGD("initFromCDE failed\n"); - delete pEntry; - goto bail; - } - - mEntries.add(pEntry); - } - - - /* - * If all went well, we should now be back at the EOCD. - */ - { - unsigned char checkBuf[4]; - if (fread(checkBuf, 1, 4, mZipFp) != 4) { - LOGD("EOCD check read failed\n"); - result = INVALID_OPERATION; - goto bail; - } - if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) { - LOGD("EOCD read check failed\n"); - result = UNKNOWN_ERROR; - goto bail; - } - LOGV("+++ EOCD read check passed\n"); - } - -bail: - delete[] buf; - return result; -} - - -/* - * Add a new file to the archive. - * - * This requires creating and populating a ZipEntry structure, and copying - * the data into the file at the appropriate position. The "appropriate - * position" is the current location of the central directory, which we - * casually overwrite (we can put it back later). - * - * If we were concerned about safety, we would want to make all changes - * in a temp file and then overwrite the original after everything was - * safely written. Not really a concern for us. - */ -status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size, - const char* storageName, int sourceType, int compressionMethod, - ZipEntry** ppEntry) -{ - ZipEntry* pEntry = NULL; - status_t result = NO_ERROR; - long lfhPosn, startPosn, endPosn, uncompressedLen; - FILE* inputFp = NULL; - unsigned long crc; - time_t modWhen; - - if (mReadOnly) - return INVALID_OPERATION; - - assert(compressionMethod == ZipEntry::kCompressDeflated || - compressionMethod == ZipEntry::kCompressStored); - - /* make sure we're in a reasonable state */ - assert(mZipFp != NULL); - assert(mEntries.size() == mEOCD.mTotalNumEntries); - - /* make sure it doesn't already exist */ - if (getEntryByName(storageName) != NULL) - return ALREADY_EXISTS; - - if (!data) { - inputFp = fopen(fileName, FILE_OPEN_RO); - if (inputFp == NULL) - return errnoToStatus(errno); - } - - if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) { - result = UNKNOWN_ERROR; - goto bail; - } - - pEntry = new ZipEntry; - pEntry->initNew(storageName, NULL); - - /* - * From here on out, failures are more interesting. - */ - mNeedCDRewrite = true; - - /* - * Write the LFH, even though it's still mostly blank. We need it - * as a place-holder. In theory the LFH isn't necessary, but in - * practice some utilities demand it. - */ - lfhPosn = ftell(mZipFp); - pEntry->mLFH.write(mZipFp); - startPosn = ftell(mZipFp); - - /* - * Copy the data in, possibly compressing it as we go. - */ - if (sourceType == ZipEntry::kCompressStored) { - if (compressionMethod == ZipEntry::kCompressDeflated) { - bool failed = false; - result = compressFpToFp(mZipFp, inputFp, data, size, &crc); - if (result != NO_ERROR) { - LOGD("compression failed, storing\n"); - failed = true; - } else { - /* - * Make sure it has compressed "enough". This probably ought - * to be set through an API call, but I don't expect our - * criteria to change over time. - */ - long src = inputFp ? ftell(inputFp) : size; - long dst = ftell(mZipFp) - startPosn; - if (dst + (dst / 10) > src) { - LOGD("insufficient compression (src=%ld dst=%ld), storing\n", - src, dst); - failed = true; - } - } - - if (failed) { - compressionMethod = ZipEntry::kCompressStored; - if (inputFp) rewind(inputFp); - fseek(mZipFp, startPosn, SEEK_SET); - /* fall through to kCompressStored case */ - } - } - /* handle "no compression" request, or failed compression from above */ - if (compressionMethod == ZipEntry::kCompressStored) { - if (inputFp) { - result = copyFpToFp(mZipFp, inputFp, &crc); - } else { - result = copyDataToFp(mZipFp, data, size, &crc); - } - if (result != NO_ERROR) { - // don't need to truncate; happens in CDE rewrite - LOGD("failed copying data in\n"); - goto bail; - } - } - - // currently seeked to end of file - uncompressedLen = inputFp ? ftell(inputFp) : size; - } else if (sourceType == ZipEntry::kCompressDeflated) { - /* we should support uncompressed-from-compressed, but it's not - * important right now */ - assert(compressionMethod == ZipEntry::kCompressDeflated); - - bool scanResult; - int method; - long compressedLen; - - scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen, - &compressedLen, &crc); - if (!scanResult || method != ZipEntry::kCompressDeflated) { - LOGD("this isn't a deflated gzip file?"); - result = UNKNOWN_ERROR; - goto bail; - } - - result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL); - if (result != NO_ERROR) { - LOGD("failed copying gzip data in\n"); - goto bail; - } - } else { - assert(false); - result = UNKNOWN_ERROR; - goto bail; - } - - /* - * We could write the "Data Descriptor", but there doesn't seem to - * be any point since we're going to go back and write the LFH. - * - * Update file offsets. - */ - endPosn = ftell(mZipFp); // seeked to end of compressed data - - /* - * Success! Fill out new values. - */ - pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc, - compressionMethod); - modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp)); - pEntry->setModWhen(modWhen); - pEntry->setLFHOffset(lfhPosn); - mEOCD.mNumEntries++; - mEOCD.mTotalNumEntries++; - mEOCD.mCentralDirSize = 0; // mark invalid; set by flush() - mEOCD.mCentralDirOffset = endPosn; - - /* - * Go back and write the LFH. - */ - if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) { - result = UNKNOWN_ERROR; - goto bail; - } - pEntry->mLFH.write(mZipFp); - - /* - * Add pEntry to the list. - */ - mEntries.add(pEntry); - if (ppEntry != NULL) - *ppEntry = pEntry; - pEntry = NULL; - -bail: - if (inputFp != NULL) - fclose(inputFp); - delete pEntry; - return result; -} - -/* - * Add an entry by copying it from another zip file. If "padding" is - * nonzero, the specified number of bytes will be added to the "extra" - * field in the header. - * - * If "ppEntry" is non-NULL, a pointer to the new entry will be returned. - */ -status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry, - int padding, ZipEntry** ppEntry) -{ - ZipEntry* pEntry = NULL; - status_t result; - long lfhPosn, endPosn; - - if (mReadOnly) - return INVALID_OPERATION; - - /* make sure we're in a reasonable state */ - assert(mZipFp != NULL); - assert(mEntries.size() == mEOCD.mTotalNumEntries); - - if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) { - result = UNKNOWN_ERROR; - goto bail; - } - - pEntry = new ZipEntry; - if (pEntry == NULL) { - result = NO_MEMORY; - goto bail; - } - - result = pEntry->initFromExternal(pSourceZip, pSourceEntry); - if (result != NO_ERROR) - goto bail; - if (padding != 0) { - result = pEntry->addPadding(padding); - if (result != NO_ERROR) - goto bail; - } - - /* - * From here on out, failures are more interesting. - */ - mNeedCDRewrite = true; - - /* - * Write the LFH. Since we're not recompressing the data, we already - * have all of the fields filled out. - */ - lfhPosn = ftell(mZipFp); - pEntry->mLFH.write(mZipFp); - - /* - * Copy the data over. - * - * If the "has data descriptor" flag is set, we want to copy the DD - * fields as well. This is a fixed-size area immediately following - * the data. - */ - if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0) - { - result = UNKNOWN_ERROR; - goto bail; - } - - off_t copyLen; - copyLen = pSourceEntry->getCompressedLen(); - if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0) - copyLen += ZipEntry::kDataDescriptorLen; - - if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL) - != NO_ERROR) - { - LOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName); - result = UNKNOWN_ERROR; - goto bail; - } - - /* - * Update file offsets. - */ - endPosn = ftell(mZipFp); - - /* - * Success! Fill out new values. - */ - pEntry->setLFHOffset(lfhPosn); // sets mCDE.mLocalHeaderRelOffset - mEOCD.mNumEntries++; - mEOCD.mTotalNumEntries++; - mEOCD.mCentralDirSize = 0; // mark invalid; set by flush() - mEOCD.mCentralDirOffset = endPosn; - - /* - * Add pEntry to the list. - */ - mEntries.add(pEntry); - if (ppEntry != NULL) - *ppEntry = pEntry; - pEntry = NULL; - - result = NO_ERROR; - -bail: - delete pEntry; - return result; -} - -/* - * Copy all of the bytes in "src" to "dst". - * - * On exit, "srcFp" will be seeked to the end of the file, and "dstFp" - * will be seeked immediately past the data. - */ -status_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32) -{ - unsigned char tmpBuf[32768]; - size_t count; - - *pCRC32 = crc32(0L, Z_NULL, 0); - - while (1) { - count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp); - if (ferror(srcFp) || ferror(dstFp)) - return errnoToStatus(errno); - if (count == 0) - break; - - *pCRC32 = crc32(*pCRC32, tmpBuf, count); - - if (fwrite(tmpBuf, 1, count, dstFp) != count) { - LOGD("fwrite %d bytes failed\n", (int) count); - return UNKNOWN_ERROR; - } - } - - return NO_ERROR; -} - -/* - * Copy all of the bytes in "src" to "dst". - * - * On exit, "dstFp" will be seeked immediately past the data. - */ -status_t ZipFile::copyDataToFp(FILE* dstFp, - const void* data, size_t size, unsigned long* pCRC32) -{ - size_t count; - - *pCRC32 = crc32(0L, Z_NULL, 0); - if (size > 0) { - *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size); - if (fwrite(data, 1, size, dstFp) != size) { - LOGD("fwrite %d bytes failed\n", (int) size); - return UNKNOWN_ERROR; - } - } - - return NO_ERROR; -} - -/* - * Copy some of the bytes in "src" to "dst". - * - * If "pCRC32" is NULL, the CRC will not be computed. - * - * On exit, "srcFp" will be seeked to the end of the file, and "dstFp" - * will be seeked immediately past the data just written. - */ -status_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length, - unsigned long* pCRC32) -{ - unsigned char tmpBuf[32768]; - size_t count; - - if (pCRC32 != NULL) - *pCRC32 = crc32(0L, Z_NULL, 0); - - while (length) { - long readSize; - - readSize = sizeof(tmpBuf); - if (readSize > length) - readSize = length; - - count = fread(tmpBuf, 1, readSize, srcFp); - if ((long) count != readSize) { // error or unexpected EOF - LOGD("fread %d bytes failed\n", (int) readSize); - return UNKNOWN_ERROR; - } - - if (pCRC32 != NULL) - *pCRC32 = crc32(*pCRC32, tmpBuf, count); - - if (fwrite(tmpBuf, 1, count, dstFp) != count) { - LOGD("fwrite %d bytes failed\n", (int) count); - return UNKNOWN_ERROR; - } - - length -= readSize; - } - - return NO_ERROR; -} - -/* - * Compress all of the data in "srcFp" and write it to "dstFp". - * - * On exit, "srcFp" will be seeked to the end of the file, and "dstFp" - * will be seeked immediately past the compressed data. - */ -status_t ZipFile::compressFpToFp(FILE* dstFp, FILE* srcFp, - const void* data, size_t size, unsigned long* pCRC32) -{ - status_t result = NO_ERROR; - const size_t kBufSize = 32768; - unsigned char* inBuf = NULL; - unsigned char* outBuf = NULL; - z_stream zstream; - bool atEof = false; // no feof() aviailable yet - unsigned long crc; - int zerr; - - /* - * Create an input buffer and an output buffer. - */ - inBuf = new unsigned char[kBufSize]; - outBuf = new unsigned char[kBufSize]; - if (inBuf == NULL || outBuf == NULL) { - result = NO_MEMORY; - goto bail; - } - - /* - * 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 = outBuf; - zstream.avail_out = kBufSize; - zstream.data_type = Z_UNKNOWN; - - zerr = deflateInit2(&zstream, Z_BEST_COMPRESSION, - Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); - if (zerr != Z_OK) { - result = UNKNOWN_ERROR; - if (zerr == Z_VERSION_ERROR) { - LOGE("Installed zlib is not compatible with linked version (%s)\n", - ZLIB_VERSION); - } else { - LOGD("Call to deflateInit2 failed (zerr=%d)\n", zerr); - } - goto bail; - } - - crc = crc32(0L, Z_NULL, 0); - - /* - * Loop while we have data. - */ - do { - size_t getSize; - int flush; - - /* only read if the input buffer is empty */ - if (zstream.avail_in == 0 && !atEof) { - LOGV("+++ reading %d bytes\n", (int)kBufSize); - if (data) { - getSize = size > kBufSize ? kBufSize : size; - memcpy(inBuf, data, getSize); - data = ((const char*)data) + getSize; - size -= getSize; - } else { - getSize = fread(inBuf, 1, kBufSize, srcFp); - if (ferror(srcFp)) { - LOGD("deflate read failed (errno=%d)\n", errno); - goto z_bail; - } - } - if (getSize < kBufSize) { - LOGV("+++ got %d bytes, EOF reached\n", - (int)getSize); - atEof = true; - } - - crc = crc32(crc, inBuf, getSize); - - zstream.next_in = inBuf; - zstream.avail_in = getSize; - } - - if (atEof) - flush = Z_FINISH; /* tell zlib that we're done */ - else - flush = Z_NO_FLUSH; /* more to come! */ - - zerr = deflate(&zstream, flush); - if (zerr != Z_OK && zerr != Z_STREAM_END) { - LOGD("zlib deflate call failed (zerr=%d)\n", zerr); - result = UNKNOWN_ERROR; - goto z_bail; - } - - /* write when we're full or when we're done */ - if (zstream.avail_out == 0 || - (zerr == Z_STREAM_END && zstream.avail_out != (uInt) kBufSize)) - { - LOGV("+++ writing %d bytes\n", (int) (zstream.next_out - outBuf)); - if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) != - (size_t)(zstream.next_out - outBuf)) - { - LOGD("write %d failed in deflate\n", - (int) (zstream.next_out - outBuf)); - goto z_bail; - } - - zstream.next_out = outBuf; - zstream.avail_out = kBufSize; - } - } while (zerr == Z_OK); - - assert(zerr == Z_STREAM_END); /* other errors should've been caught */ - - *pCRC32 = crc; - -z_bail: - deflateEnd(&zstream); /* free up any allocated structures */ - -bail: - delete[] inBuf; - delete[] outBuf; - - return result; -} - -/* - * Mark an entry as deleted. - * - * We will eventually need to crunch the file down, but if several files - * are being removed (perhaps as part of an "update" process) we can make - * things considerably faster by deferring the removal to "flush" time. - */ -status_t ZipFile::remove(ZipEntry* pEntry) -{ - /* - * Should verify that pEntry is actually part of this archive, and - * not some stray ZipEntry from a different file. - */ - - /* mark entry as deleted, and mark archive as dirty */ - pEntry->setDeleted(); - mNeedCDRewrite = true; - return NO_ERROR; -} - -/* - * Flush any pending writes. - * - * In particular, this will crunch out deleted entries, and write the - * Central Directory and EOCD if we have stomped on them. - */ -status_t ZipFile::flush(void) -{ - status_t result = NO_ERROR; - long eocdPosn; - int i, count; - - if (mReadOnly) - return INVALID_OPERATION; - if (!mNeedCDRewrite) - return NO_ERROR; - - assert(mZipFp != NULL); - - result = crunchArchive(); - if (result != NO_ERROR) - return result; - - if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) - return UNKNOWN_ERROR; - - count = mEntries.size(); - for (i = 0; i < count; i++) { - ZipEntry* pEntry = mEntries[i]; - pEntry->mCDE.write(mZipFp); - } - - eocdPosn = ftell(mZipFp); - mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset; - - mEOCD.write(mZipFp); - - /* - * If we had some stuff bloat up during compression and get replaced - * with plain files, or if we deleted some entries, there's a lot - * of wasted space at the end of the file. Remove it now. - */ - if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) { - LOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno)); - // not fatal - } - - /* should we clear the "newly added" flag in all entries now? */ - - mNeedCDRewrite = false; - return NO_ERROR; -} - -/* - * Crunch deleted files out of an archive by shifting the later files down. - * - * Because we're not using a temp file, we do the operation inside the - * current file. - */ -status_t ZipFile::crunchArchive(void) -{ - status_t result = NO_ERROR; - int i, count; - long delCount, adjust; - -#if 0 - printf("CONTENTS:\n"); - for (i = 0; i < (int) mEntries.size(); i++) { - printf(" %d: lfhOff=%ld del=%d\n", - i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted()); - } - printf(" END is %ld\n", (long) mEOCD.mCentralDirOffset); -#endif - - /* - * Roll through the set of files, shifting them as appropriate. We - * could probably get a slight performance improvement by sliding - * multiple files down at once (because we could use larger reads - * when operating on batches of small files), but it's not that useful. - */ - count = mEntries.size(); - delCount = adjust = 0; - for (i = 0; i < count; i++) { - ZipEntry* pEntry = mEntries[i]; - long span; - - if (pEntry->getLFHOffset() != 0) { - long nextOffset; - - /* Get the length of this entry by finding the offset - * of the next entry. Directory entries don't have - * file offsets, so we need to find the next non-directory - * entry. - */ - nextOffset = 0; - for (int ii = i+1; nextOffset == 0 && ii < count; ii++) - nextOffset = mEntries[ii]->getLFHOffset(); - if (nextOffset == 0) - nextOffset = mEOCD.mCentralDirOffset; - span = nextOffset - pEntry->getLFHOffset(); - - assert(span >= ZipEntry::LocalFileHeader::kLFHLen); - } else { - /* This is a directory entry. It doesn't have - * any actual file contents, so there's no need to - * move anything. - */ - span = 0; - } - - //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n", - // i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count); - - if (pEntry->getDeleted()) { - adjust += span; - delCount++; - - delete pEntry; - mEntries.removeAt(i); - - /* adjust loop control */ - count--; - i--; - } else if (span != 0 && adjust > 0) { - /* shuffle this entry back */ - //printf("+++ Shuffling '%s' back %ld\n", - // pEntry->getFileName(), adjust); - result = filemove(mZipFp, pEntry->getLFHOffset() - adjust, - pEntry->getLFHOffset(), span); - if (result != NO_ERROR) { - /* this is why you use a temp file */ - LOGE("error during crunch - archive is toast\n"); - return result; - } - - pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust); - } - } - - /* - * Fix EOCD info. We have to wait until the end to do some of this - * because we use mCentralDirOffset to determine "span" for the - * last entry. - */ - mEOCD.mCentralDirOffset -= adjust; - mEOCD.mNumEntries -= delCount; - mEOCD.mTotalNumEntries -= delCount; - mEOCD.mCentralDirSize = 0; // mark invalid; set by flush() - - assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries); - assert(mEOCD.mNumEntries == count); - - return result; -} - -/* - * Works like memmove(), but on pieces of a file. - */ -status_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n) -{ - if (dst == src || n <= 0) - return NO_ERROR; - - unsigned char readBuf[32768]; - - if (dst < src) { - /* shift stuff toward start of file; must read from start */ - while (n != 0) { - size_t getSize = sizeof(readBuf); - if (getSize > n) - getSize = n; - - if (fseek(fp, (long) src, SEEK_SET) != 0) { - LOGD("filemove src seek %ld failed\n", (long) src); - return UNKNOWN_ERROR; - } - - if (fread(readBuf, 1, getSize, fp) != getSize) { - LOGD("filemove read %ld off=%ld failed\n", - (long) getSize, (long) src); - return UNKNOWN_ERROR; - } - - if (fseek(fp, (long) dst, SEEK_SET) != 0) { - LOGD("filemove dst seek %ld failed\n", (long) dst); - return UNKNOWN_ERROR; - } - - if (fwrite(readBuf, 1, getSize, fp) != getSize) { - LOGD("filemove write %ld off=%ld failed\n", - (long) getSize, (long) dst); - return UNKNOWN_ERROR; - } - - src += getSize; - dst += getSize; - n -= getSize; - } - } else { - /* shift stuff toward end of file; must read from end */ - assert(false); // write this someday, maybe - return UNKNOWN_ERROR; - } - - return NO_ERROR; -} - - -/* - * Get the modification time from a file descriptor. - */ -time_t ZipFile::getModTime(int fd) -{ - struct stat sb; - - if (fstat(fd, &sb) < 0) { - LOGD("HEY: fstat on fd %d failed\n", fd); - return (time_t) -1; - } - - return sb.st_mtime; -} - - -#if 0 /* this is a bad idea */ -/* - * Get a copy of the Zip file descriptor. - * - * We don't allow this if the file was opened read-write because we tend - * to leave the file contents in an uncertain state between calls to - * flush(). The duplicated file descriptor should only be valid for reads. - */ -int ZipFile::getZipFd(void) const -{ - if (!mReadOnly) - return INVALID_OPERATION; - assert(mZipFp != NULL); - - int fd; - fd = dup(fileno(mZipFp)); - if (fd < 0) { - LOGD("didn't work, errno=%d\n", errno); - } - - return fd; -} -#endif - - -#if 0 -/* - * Expand data. - */ -bool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const -{ - return false; -} -#endif - -// free the memory when you're done -void* ZipFile::uncompress(const ZipEntry* entry) -{ - size_t unlen = entry->getUncompressedLen(); - size_t clen = entry->getCompressedLen(); - - void* buf = malloc(unlen); - if (buf == NULL) { - return NULL; - } - - fseek(mZipFp, 0, SEEK_SET); - - off_t offset = entry->getFileOffset(); - if (fseek(mZipFp, offset, SEEK_SET) != 0) { - goto bail; - } - - switch (entry->getCompressionMethod()) - { - case ZipEntry::kCompressStored: { - ssize_t amt = fread(buf, 1, unlen, mZipFp); - if (amt != (ssize_t)unlen) { - goto bail; - } -#if 0 - printf("data...\n"); - const unsigned char* p = (unsigned char*)buf; - const unsigned char* end = p+unlen; - for (int i=0; i<32 && p < end; i++) { - printf("0x%08x ", (int)(offset+(i*0x10))); - for (int j=0; j<0x10 && p < end; j++) { - printf(" %02x", *p); - p++; - } - printf("\n"); - } -#endif - - } - break; - case ZipEntry::kCompressDeflated: { - if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) { - goto bail; - } - } - break; - default: - goto bail; - } - return buf; - -bail: - free(buf); - return NULL; -} - - -/* - * =========================================================================== - * ZipFile::EndOfCentralDir - * =========================================================================== - */ - -/* - * Read the end-of-central-dir fields. - * - * "buf" should be positioned at the EOCD signature, and should contain - * the entire EOCD area including the comment. - */ -status_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len) -{ - /* don't allow re-use */ - assert(mComment == NULL); - - if (len < kEOCDLen) { - /* looks like ZIP file got truncated */ - LOGD(" Zip EOCD: expected >= %d bytes, found %d\n", - kEOCDLen, len); - return INVALID_OPERATION; - } - - /* this should probably be an assert() */ - if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) - return UNKNOWN_ERROR; - - mDiskNumber = ZipEntry::getShortLE(&buf[0x04]); - mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]); - mNumEntries = ZipEntry::getShortLE(&buf[0x08]); - mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]); - mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]); - mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]); - mCommentLen = ZipEntry::getShortLE(&buf[0x14]); - - // TODO: validate mCentralDirOffset - - if (mCommentLen > 0) { - if (kEOCDLen + mCommentLen > len) { - LOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n", - kEOCDLen, mCommentLen, len); - return UNKNOWN_ERROR; - } - mComment = new unsigned char[mCommentLen]; - memcpy(mComment, buf + kEOCDLen, mCommentLen); - } - - return NO_ERROR; -} - -/* - * Write an end-of-central-directory section. - */ -status_t ZipFile::EndOfCentralDir::write(FILE* fp) -{ - unsigned char buf[kEOCDLen]; - - ZipEntry::putLongLE(&buf[0x00], kSignature); - ZipEntry::putShortLE(&buf[0x04], mDiskNumber); - ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir); - ZipEntry::putShortLE(&buf[0x08], mNumEntries); - ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries); - ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize); - ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset); - ZipEntry::putShortLE(&buf[0x14], mCommentLen); - - if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen) - return UNKNOWN_ERROR; - if (mCommentLen > 0) { - assert(mComment != NULL); - if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen) - return UNKNOWN_ERROR; - } - - return NO_ERROR; -} - -/* - * Dump the contents of an EndOfCentralDir object. - */ -void ZipFile::EndOfCentralDir::dump(void) const -{ - LOGD(" EndOfCentralDir contents:\n"); - LOGD(" diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n", - mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries); - LOGD(" centDirSize=%lu centDirOff=%lu commentLen=%u\n", - mCentralDirSize, mCentralDirOffset, mCommentLen); -} - diff --git a/libs/utils/ZipFileCRO.cpp b/libs/utils/ZipFileCRO.cpp deleted file mode 100644 index d312daf..0000000 --- a/libs/utils/ZipFileCRO.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "utils/ZipFileCRO.h" -#include "utils/ZipFileRO.h" - -using namespace android; - -ZipFileCRO ZipFileXRO_open(const char* path) { - ZipFileRO* zip = new ZipFileRO(); - if (zip->open(path) == NO_ERROR) { - return (ZipFileCRO)zip; - } - return NULL; -} - -void ZipFileCRO_destroy(ZipFileCRO zipToken) { - ZipFileRO* zip = (ZipFileRO*)zipToken; - delete zip; -} - -ZipEntryCRO ZipFileCRO_findEntryByName(ZipFileCRO zipToken, - const char* fileName) { - ZipFileRO* zip = (ZipFileRO*)zipToken; - return (ZipEntryCRO)zip->findEntryByName(fileName); -} - -bool ZipFileCRO_getEntryInfo(ZipFileCRO zipToken, ZipEntryRO entryToken, - int* pMethod, long* pUncompLen, - long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) { - ZipFileRO* zip = (ZipFileRO*)zipToken; - ZipEntryRO entry = (ZipEntryRO)entryToken; - return zip->getEntryInfo(entry, pMethod, pUncompLen, pCompLen, pOffset, - pModWhen, pCrc32); -} - -bool ZipFileCRO_uncompressEntry(ZipFileCRO zipToken, ZipEntryRO entryToken, int fd) { - ZipFileRO* zip = (ZipFileRO*)zipToken; - ZipEntryRO entry = (ZipEntryRO)entryToken; - return zip->uncompressEntry(entry, fd); -} diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp deleted file mode 100644 index ae8c719..0000000 --- a/libs/utils/ZipFileRO.cpp +++ /dev/null @@ -1,724 +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 "utils/ZipFileRO.h" -#include "utils/Log.h" -#include "utils/misc.h" - -#include <zlib.h> - -#include <string.h> -#include <fcntl.h> -#include <errno.h> -#include <assert.h> - -using namespace android; - -/* - * Zip file constants. - */ -#define kEOCDSignature 0x06054b50 -#define kEOCDLen 22 -#define kEOCDNumEntries 8 // offset to #of entries in file -#define kEOCDFileOffset 16 // offset to central directory - -#define kMaxCommentLen 65535 // longest possible in ushort -#define kMaxEOCDSearch (kMaxCommentLen + kEOCDLen) - -#define kLFHSignature 0x04034b50 -#define kLFHLen 30 // excluding variable-len fields -#define kLFHNameLen 26 // offset to filename length -#define kLFHExtraLen 28 // offset to extra length - -#define kCDESignature 0x02014b50 -#define kCDELen 46 // excluding variable-len fields -#define kCDEMethod 10 // offset to compression method -#define kCDEModWhen 12 // offset to modification timestamp -#define kCDECRC 16 // offset to entry CRC -#define kCDECompLen 20 // offset to compressed length -#define kCDEUncompLen 24 // offset to uncompressed length -#define kCDENameLen 28 // offset to filename length -#define kCDEExtraLen 30 // offset to extra length -#define kCDECommentLen 32 // offset to comment length -#define kCDELocalOffset 42 // offset to local hdr - -/* - * The values we return for ZipEntryRO use 0 as an invalid value, so we - * want to adjust the hash table index by a fixed amount. Using a large - * value helps insure that people don't mix & match arguments, e.g. to - * findEntryByIndex(). - */ -#define kZipEntryAdj 10000 - -/* - * Convert a ZipEntryRO to a hash table index, verifying that it's in a - * valid range. - */ -int ZipFileRO::entryToIndex(const ZipEntryRO entry) const -{ - long ent = ((long) entry) - kZipEntryAdj; - if (ent < 0 || ent >= mHashTableSize || mHashTable[ent].name == NULL) { - LOGW("Invalid ZipEntryRO %p (%ld)\n", entry, ent); - return -1; - } - return ent; -} - - -/* - * Open the specified file read-only. We memory-map the entire thing and - * close the file before returning. - */ -status_t ZipFileRO::open(const char* zipFileName) -{ - int fd = -1; - off_t length; - - assert(mFileMap == NULL); - - /* - * Open and map the specified file. - */ - fd = ::open(zipFileName, O_RDONLY); - if (fd < 0) { - LOGW("Unable to open zip '%s': %s\n", zipFileName, strerror(errno)); - return NAME_NOT_FOUND; - } - - length = lseek(fd, 0, SEEK_END); - if (length < 0) { - close(fd); - return UNKNOWN_ERROR; - } - - mFileMap = new FileMap(); - if (mFileMap == NULL) { - close(fd); - return NO_MEMORY; - } - if (!mFileMap->create(zipFileName, fd, 0, length, true)) { - LOGW("Unable to map '%s': %s\n", zipFileName, strerror(errno)); - close(fd); - return UNKNOWN_ERROR; - } - - mFd = fd; - - /* - * Got it mapped, verify it and create data structures for fast access. - */ - if (!parseZipArchive()) { - mFileMap->release(); - mFileMap = NULL; - return UNKNOWN_ERROR; - } - - return OK; -} - -/* - * Parse the Zip archive, verifying its contents and initializing internal - * data structures. - */ -bool ZipFileRO::parseZipArchive(void) -{ -#define CHECK_OFFSET(_off) { \ - if ((unsigned int) (_off) >= maxOffset) { \ - LOGE("ERROR: bad offset %u (max %d): %s\n", \ - (unsigned int) (_off), maxOffset, #_off); \ - goto bail; \ - } \ - } - const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr(); - const unsigned char* ptr; - size_t length = mFileMap->getDataLength(); - bool result = false; - unsigned int i, numEntries, cdOffset; - unsigned int val; - - /* - * The first 4 bytes of the file will either be the local header - * signature for the first file (kLFHSignature) or, if the archive doesn't - * have any files in it, the end-of-central-directory signature - * (kEOCDSignature). - */ - val = get4LE(basePtr); - if (val == kEOCDSignature) { - LOGI("Found Zip archive, but it looks empty\n"); - goto bail; - } else if (val != kLFHSignature) { - LOGV("Not a Zip archive (found 0x%08x)\n", val); - goto bail; - } - - /* - * Find the EOCD. We'll find it immediately unless they have a file - * comment. - */ - ptr = basePtr + length - kEOCDLen; - - while (ptr >= basePtr) { - if (*ptr == (kEOCDSignature & 0xff) && get4LE(ptr) == kEOCDSignature) - break; - ptr--; - } - if (ptr < basePtr) { - LOGI("Could not find end-of-central-directory in Zip\n"); - goto bail; - } - - /* - * There are two interesting items in the EOCD block: the number of - * entries in the file, and the file offset of the start of the - * central directory. - * - * (There's actually a count of the #of entries in this file, and for - * all files which comprise a spanned archive, but for our purposes - * we're only interested in the current file. Besides, we expect the - * two to be equivalent for our stuff.) - */ - numEntries = get2LE(ptr + kEOCDNumEntries); - cdOffset = get4LE(ptr + kEOCDFileOffset); - - /* valid offsets are [0,EOCD] */ - unsigned int maxOffset; - maxOffset = (ptr - basePtr) +1; - - LOGV("+++ numEntries=%d cdOffset=%d\n", numEntries, cdOffset); - if (numEntries == 0 || cdOffset >= length) { - LOGW("Invalid entries=%d offset=%d (len=%zd)\n", - numEntries, cdOffset, length); - goto bail; - } - - /* - * Create hash table. We have a minimum 75% load factor, possibly as - * low as 50% after we round off to a power of 2. - */ - mNumEntries = numEntries; - mHashTableSize = roundUpPower2(1 + ((numEntries * 4) / 3)); - mHashTable = (HashEntry*) calloc(1, sizeof(HashEntry) * mHashTableSize); - - /* - * Walk through the central directory, adding entries to the hash - * table. - */ - ptr = basePtr + cdOffset; - for (i = 0; i < numEntries; i++) { - unsigned int fileNameLen, extraLen, commentLen, localHdrOffset; - const unsigned char* localHdr; - unsigned int hash; - - if (get4LE(ptr) != kCDESignature) { - LOGW("Missed a central dir sig (at %d)\n", i); - goto bail; - } - if (ptr + kCDELen > basePtr + length) { - LOGW("Ran off the end (at %d)\n", i); - goto bail; - } - - localHdrOffset = get4LE(ptr + kCDELocalOffset); - CHECK_OFFSET(localHdrOffset); - fileNameLen = get2LE(ptr + kCDENameLen); - extraLen = get2LE(ptr + kCDEExtraLen); - commentLen = get2LE(ptr + kCDECommentLen); - - //LOGV("+++ %d: localHdr=%d fnl=%d el=%d cl=%d\n", - // i, localHdrOffset, fileNameLen, extraLen, commentLen); - //LOGV(" '%.*s'\n", fileNameLen, ptr + kCDELen); - - /* add the CDE filename to the hash table */ - hash = computeHash((const char*)ptr + kCDELen, fileNameLen); - addToHash((const char*)ptr + kCDELen, fileNameLen, hash); - - localHdr = basePtr + localHdrOffset; - if (get4LE(localHdr) != kLFHSignature) { - LOGW("Bad offset to local header: %d (at %d)\n", - localHdrOffset, i); - goto bail; - } - - ptr += kCDELen + fileNameLen + extraLen + commentLen; - CHECK_OFFSET(ptr - basePtr); - } - - result = true; - -bail: - return result; -#undef CHECK_OFFSET -} - - -/* - * Simple string hash function for non-null-terminated strings. - */ -/*static*/ unsigned int ZipFileRO::computeHash(const char* str, int len) -{ - unsigned int hash = 0; - - while (len--) - hash = hash * 31 + *str++; - - return hash; -} - -/* - * Add a new entry to the hash table. - */ -void ZipFileRO::addToHash(const char* str, int strLen, unsigned int hash) -{ - int ent = hash & (mHashTableSize-1); - - /* - * We over-allocate the table, so we're guaranteed to find an empty slot. - */ - while (mHashTable[ent].name != NULL) - ent = (ent + 1) & (mHashTableSize-1); - - mHashTable[ent].name = str; - mHashTable[ent].nameLen = strLen; -} - -/* - * Find a matching entry. - * - * Returns 0 if not found. - */ -ZipEntryRO ZipFileRO::findEntryByName(const char* fileName) const -{ - int nameLen = strlen(fileName); - unsigned int hash = computeHash(fileName, nameLen); - int ent = hash & (mHashTableSize-1); - - while (mHashTable[ent].name != NULL) { - if (mHashTable[ent].nameLen == nameLen && - memcmp(mHashTable[ent].name, fileName, nameLen) == 0) - { - /* match */ - return (ZipEntryRO) (ent + kZipEntryAdj); - } - - ent = (ent + 1) & (mHashTableSize-1); - } - - return NULL; -} - -/* - * Find the Nth entry. - * - * This currently involves walking through the sparse hash table, counting - * non-empty entries. If we need to speed this up we can either allocate - * a parallel lookup table or (perhaps better) provide an iterator interface. - */ -ZipEntryRO ZipFileRO::findEntryByIndex(int idx) const -{ - if (idx < 0 || idx >= mNumEntries) { - LOGW("Invalid index %d\n", idx); - return NULL; - } - - for (int ent = 0; ent < mHashTableSize; ent++) { - if (mHashTable[ent].name != NULL) { - if (idx-- == 0) - return (ZipEntryRO) (ent + kZipEntryAdj); - } - } - - return NULL; -} - -/* - * 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, long* pUncompLen, - long* pCompLen, off_t* pOffset, long* pModWhen, long* pCrc32) const -{ - int ent = entryToIndex(entry); - if (ent < 0) - return false; - - /* - * Recover the start of the central directory entry from the filename - * pointer. - */ - const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr(); - const unsigned char* ptr = (const unsigned char*) mHashTable[ent].name; - size_t zipLength = mFileMap->getDataLength(); - - ptr -= kCDELen; - - int method = get2LE(ptr + kCDEMethod); - if (pMethod != NULL) - *pMethod = method; - - if (pModWhen != NULL) - *pModWhen = get4LE(ptr + kCDEModWhen); - if (pCrc32 != NULL) - *pCrc32 = get4LE(ptr + kCDECRC); - - /* - * We need to make sure that the lengths are not so large that somebody - * trying to map the compressed or uncompressed data runs off the end - * of the mapped region. - */ - unsigned long localHdrOffset = get4LE(ptr + kCDELocalOffset); - if (localHdrOffset + kLFHLen >= zipLength) { - LOGE("ERROR: bad local hdr offset in zip\n"); - return false; - } - const unsigned char* localHdr = basePtr + localHdrOffset; - off_t dataOffset = localHdrOffset + kLFHLen - + get2LE(localHdr + kLFHNameLen) + get2LE(localHdr + kLFHExtraLen); - if ((unsigned long) dataOffset >= zipLength) { - LOGE("ERROR: bad data offset in zip\n"); - return false; - } - - if (pCompLen != NULL) { - *pCompLen = get4LE(ptr + kCDECompLen); - if (*pCompLen < 0 || (size_t)(dataOffset + *pCompLen) >= zipLength) { - LOGE("ERROR: bad compressed length in zip\n"); - return false; - } - } - if (pUncompLen != NULL) { - *pUncompLen = get4LE(ptr + kCDEUncompLen); - if (*pUncompLen < 0) { - LOGE("ERROR: negative uncompressed length in zip\n"); - return false; - } - if (method == kCompressStored && - (size_t)(dataOffset + *pUncompLen) >= zipLength) - { - LOGE("ERROR: bad uncompressed length in zip\n"); - return false; - } - } - - if (pOffset != NULL) { - *pOffset = dataOffset; - } - return true; -} - -/* - * Copy the entry's filename to the buffer. - */ -int ZipFileRO::getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen) - const -{ - int ent = entryToIndex(entry); - if (ent < 0) - return -1; - - int nameLen = mHashTable[ent].nameLen; - if (bufLen < nameLen+1) - return nameLen+1; - - memcpy(buffer, mHashTable[ent].name, nameLen); - buffer[nameLen] = '\0'; - return 0; -} - -/* - * Create a new FileMap object that spans the data in "entry". - */ -FileMap* ZipFileRO::createEntryFileMap(ZipEntryRO entry) const -{ - /* - * TODO: the efficient way to do this is to modify FileMap to allow - * sub-regions of a file to be mapped. A reference-counting scheme - * can manage the base memory mapping. For now, we just create a brand - * new mapping off of the Zip archive file descriptor. - */ - - FileMap* newMap; - long compLen; - off_t offset; - - if (!getEntryInfo(entry, NULL, NULL, &compLen, &offset, NULL, NULL)) - return NULL; - - newMap = new FileMap(); - if (!newMap->create(mFileMap->getFileName(), mFd, offset, compLen, 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) const -{ - const int kSequentialMin = 32768; - bool result = false; - int ent = entryToIndex(entry); - if (ent < 0) - return -1; - - const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr(); - int method; - long uncompLen, compLen; - off_t offset; - - getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL); - - /* - * Experiment with madvise hint. When we want to uncompress a file, - * we pull some stuff out of the central dir entry and then hit a - * bunch of compressed or uncompressed data sequentially. The CDE - * visit will cause a limited amount of read-ahead because it's at - * the end of the file. We could end up doing lots of extra disk - * access if the file we're prying open is small. Bottom line is we - * probably don't want to turn MADV_SEQUENTIAL on and leave it on. - * - * So, if the compressed size of the file is above a certain minimum - * size, temporarily boost the read-ahead in the hope that the extra - * pair of system calls are negated by a reduction in page faults. - */ - if (compLen > kSequentialMin) - mFileMap->advise(FileMap::SEQUENTIAL); - - if (method == kCompressStored) { - memcpy(buffer, basePtr + offset, uncompLen); - } else { - if (!inflateBuffer(buffer, basePtr + offset, uncompLen, compLen)) - goto bail; - } - - if (compLen > kSequentialMin) - mFileMap->advise(FileMap::NORMAL); - - result = true; - -bail: - return result; -} - -/* - * 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 -{ - bool result = false; - int ent = entryToIndex(entry); - if (ent < 0) - return -1; - - const unsigned char* basePtr = (const unsigned char*)mFileMap->getDataPtr(); - int method; - long uncompLen, compLen; - off_t offset; - - getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL); - - if (method == kCompressStored) { - ssize_t actual; - - actual = write(fd, basePtr + offset, uncompLen); - if (actual < 0) { - LOGE("Write failed: %s\n", strerror(errno)); - goto bail; - } else if (actual != uncompLen) { - LOGE("Partial write during uncompress (%d of %ld)\n", - (int)actual, uncompLen); - goto bail; - } else { - LOGI("+++ successful write\n"); - } - } else { - if (!inflateBuffer(fd, basePtr+offset, uncompLen, compLen)) - goto bail; - } - - result = true; - -bail: - return result; -} - -/* - * Uncompress "deflate" data from one buffer to another. - */ -/*static*/ bool ZipFileRO::inflateBuffer(void* outBuf, const void* inBuf, - long uncompLen, long compLen) -{ - bool result = false; - z_stream zstream; - int zerr; - - /* - * Initialize the zlib stream struct. - */ - memset(&zstream, 0, sizeof(zstream)); - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.opaque = Z_NULL; - zstream.next_in = (Bytef*)inBuf; - zstream.avail_in = compLen; - zstream.next_out = (Bytef*) outBuf; - zstream.avail_out = uncompLen; - 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) { - LOGE("Installed zlib is not compatible with linked version (%s)\n", - ZLIB_VERSION); - } else { - LOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr); - } - goto bail; - } - - /* - * Expand data. - */ - zerr = inflate(&zstream, Z_FINISH); - if (zerr != Z_STREAM_END) { - LOGW("Zip inflate failed, zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)\n", - zerr, zstream.next_in, zstream.avail_in, - zstream.next_out, zstream.avail_out); - goto z_bail; - } - - /* paranoia */ - if ((long) zstream.total_out != uncompLen) { - LOGW("Size mismatch on inflated file (%ld vs %ld)\n", - zstream.total_out, uncompLen); - goto z_bail; - } - - result = true; - -z_bail: - inflateEnd(&zstream); /* free up any allocated structures */ - -bail: - return result; -} - -/* - * Uncompress "deflate" data from one buffer to an open file descriptor. - */ -/*static*/ bool ZipFileRO::inflateBuffer(int fd, const void* inBuf, - long uncompLen, long compLen) -{ - bool result = false; - const int kWriteBufSize = 32768; - unsigned char writeBuf[kWriteBufSize]; - z_stream zstream; - int zerr; - - /* - * Initialize the zlib stream struct. - */ - memset(&zstream, 0, sizeof(zstream)); - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.opaque = Z_NULL; - zstream.next_in = (Bytef*)inBuf; - zstream.avail_in = compLen; - zstream.next_out = (Bytef*) writeBuf; - zstream.avail_out = sizeof(writeBuf); - 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) { - LOGE("Installed zlib is not compatible with linked version (%s)\n", - ZLIB_VERSION); - } else { - LOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr); - } - goto bail; - } - - /* - * Loop while we have more to do. - */ - do { - /* - * Expand data. - */ - zerr = inflate(&zstream, Z_NO_FLUSH); - if (zerr != Z_OK && zerr != Z_STREAM_END) { - LOGW("zlib inflate: zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)\n", - zerr, zstream.next_in, zstream.avail_in, - zstream.next_out, zstream.avail_out); - goto z_bail; - } - - /* write when we're full or when we're done */ - if (zstream.avail_out == 0 || - (zerr == Z_STREAM_END && zstream.avail_out != sizeof(writeBuf))) - { - long writeSize = zstream.next_out - writeBuf; - int cc = write(fd, writeBuf, writeSize); - if (cc != (int) writeSize) { - LOGW("write failed in inflate (%d vs %ld)\n", cc, writeSize); - goto z_bail; - } - - zstream.next_out = writeBuf; - zstream.avail_out = sizeof(writeBuf); - } - } while (zerr == Z_OK); - - assert(zerr == Z_STREAM_END); /* other errors should've been caught */ - - /* paranoia */ - if ((long) zstream.total_out != uncompLen) { - LOGW("Size mismatch on inflated file (%ld vs %ld)\n", - zstream.total_out, uncompLen); - goto z_bail; - } - - result = true; - -z_bail: - inflateEnd(&zstream); /* free up any allocated structures */ - -bail: - return result; -} diff --git a/libs/utils/ZipUtils.cpp b/libs/utils/ZipUtils.cpp deleted file mode 100644 index bfbacfe..0000000 --- a/libs/utils/ZipUtils.cpp +++ /dev/null @@ -1,344 +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 "utils/ZipUtils.h" -#include "utils/ZipFileRO.h" -#include "utils/Log.h" - -#include <stdlib.h> -#include <string.h> -#include <assert.h> - -#include <zlib.h> - -using namespace android; - -/* - * Utility function that expands zip/gzip "deflate" compressed data - * into a buffer. - * - * "fd" is an open file positioned at the start of the "deflate" data - * "buf" must hold at least "uncompressedLen" bytes. - */ -/*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf, - long uncompressedLen, long compressedLen) -{ - bool result = false; - const unsigned long kReadBufSize = 32768; - unsigned char* readBuf = NULL; - z_stream zstream; - int zerr; - unsigned long compRemaining; - - assert(uncompressedLen >= 0); - assert(compressedLen >= 0); - - readBuf = new unsigned char[kReadBufSize]; - if (readBuf == NULL) - goto bail; - compRemaining = compressedLen; - - /* - * Initialize the zlib stream. - */ - memset(&zstream, 0, sizeof(zstream)); - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.opaque = Z_NULL; - zstream.next_in = NULL; - zstream.avail_in = 0; - zstream.next_out = (Bytef*) buf; - zstream.avail_out = uncompressedLen; - zstream.data_type = Z_UNKNOWN; - - /* - * Use the undocumented "negative window bits" feature to tell zlib - * that there's no zlib header waiting for it. - */ - zerr = inflateInit2(&zstream, -MAX_WBITS); - if (zerr != Z_OK) { - if (zerr == Z_VERSION_ERROR) { - LOGE("Installed zlib is not compatible with linked version (%s)\n", - ZLIB_VERSION); - } else { - LOGE("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; - LOGV("+++ reading %ld bytes (%ld left)\n", - getSize, compRemaining); - - int cc = read(fd, readBuf, getSize); - if (cc != (int) getSize) { - LOGD("inflate read failed (%d vs %ld)\n", - cc, getSize); - goto z_bail; - } - - compRemaining -= getSize; - - zstream.next_in = readBuf; - zstream.avail_in = getSize; - } - - /* uncompress the data */ - zerr = inflate(&zstream, Z_NO_FLUSH); - if (zerr != Z_OK && zerr != Z_STREAM_END) { - LOGD("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) { - LOGW("Size mismatch on inflated file (%ld vs %ld)\n", - zstream.total_out, uncompressedLen); - goto z_bail; - } - - // success! - result = true; - -z_bail: - inflateEnd(&zstream); /* free up any allocated structures */ - -bail: - delete[] readBuf; - return result; -} - -/* - * 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*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf, - long uncompressedLen, long compressedLen) -{ - bool result = false; - const unsigned long kReadBufSize = 32768; - unsigned char* readBuf = NULL; - z_stream zstream; - int zerr; - unsigned long compRemaining; - - assert(uncompressedLen >= 0); - assert(compressedLen >= 0); - - readBuf = new unsigned char[kReadBufSize]; - if (readBuf == NULL) - goto bail; - compRemaining = compressedLen; - - /* - * Initialize the zlib stream. - */ - memset(&zstream, 0, sizeof(zstream)); - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.opaque = Z_NULL; - zstream.next_in = NULL; - zstream.avail_in = 0; - zstream.next_out = (Bytef*) buf; - zstream.avail_out = uncompressedLen; - zstream.data_type = Z_UNKNOWN; - - /* - * Use the undocumented "negative window bits" feature to tell zlib - * that there's no zlib header waiting for it. - */ - zerr = inflateInit2(&zstream, -MAX_WBITS); - if (zerr != Z_OK) { - if (zerr == Z_VERSION_ERROR) { - LOGE("Installed zlib is not compatible with linked version (%s)\n", - ZLIB_VERSION); - } else { - LOGE("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; - LOGV("+++ reading %ld bytes (%ld left)\n", - getSize, compRemaining); - - int cc = fread(readBuf, getSize, 1, fp); - if (cc != (int) getSize) { - LOGD("inflate read failed (%d vs %ld)\n", - cc, getSize); - goto z_bail; - } - - compRemaining -= getSize; - - zstream.next_in = readBuf; - zstream.avail_in = getSize; - } - - /* uncompress the data */ - zerr = inflate(&zstream, Z_NO_FLUSH); - if (zerr != Z_OK && zerr != Z_STREAM_END) { - LOGD("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) { - LOGW("Size mismatch on inflated file (%ld vs %ld)\n", - zstream.total_out, uncompressedLen); - goto z_bail; - } - - // success! - result = true; - -z_bail: - inflateEnd(&zstream); /* free up any allocated structures */ - -bail: - delete[] readBuf; - return result; -} - -/* - * 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 = ZipFileRO::get4LE(&buf[0]); - *pUncompressedLen = ZipFileRO::get4LE(&buf[4]); - - return true; -} - diff --git a/libs/utils/characterData.h b/libs/utils/characterData.h deleted file mode 100644 index e931d99..0000000 --- a/libs/utils/characterData.h +++ /dev/null @@ -1,730 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Automatically generated on 07-11-2006 by make-CharacterDataC -// DO NOT EDIT DIRECTLY -namespace CharacterData { - - // Structure containing an array of ranges - struct Range { - int length; - const uint32_t* array; - }; - - // For Latin1 characters just index into this array to get the index and decomposition - static const uint16_t LATIN1_DATA[] = { - 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, - 0x0001, 0x0002, 0x0003, 0x0002, 0x0004, 0x0003, 0x0001, 0x0001, - 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, - 0x0001, 0x0001, 0x0001, 0x0001, 0x0003, 0x0003, 0x0003, 0x0002, - 0x0005, 0x0006, 0x0006, 0x0007, 0x0008, 0x0007, 0x0006, 0x0006, - 0x0009, 0x000A, 0x0006, 0x000B, 0x000C, 0x000D, 0x000C, 0x000C, - 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, - 0x0016, 0x0017, 0x000C, 0x0006, 0x0018, 0x0019, 0x001A, 0x0006, - 0x0006, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020, 0x0021, - 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, - 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, - 0x0032, 0x0033, 0x0034, 0x0035, 0x0006, 0x0036, 0x0037, 0x0038, - 0x0037, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, - 0x0050, 0x0051, 0x0052, 0x0035, 0x0019, 0x0036, 0x0019, 0x0001, - 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0003, 0x0001, 0x0001, - 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, - 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, - 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, - 0x5853, 0x0006, 0x0008, 0x0008, 0x0008, 0x0008, 0x0054, 0x0054, - 0x1037, 0x0054, 0x7855, 0x0056, 0x0019, 0x0057, 0x0054, 0x1037, - 0x0058, 0x0059, 0x785A, 0x785B, 0x1037, 0x105C, 0x0054, 0x0006, - 0x1037, 0x785D, 0x7855, 0x005E, 0x305F, 0x305F, 0x305F, 0x0006, - 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0060, 0x0860, - 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, - 0x0060, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0019, - 0x0060, 0x0860, 0x0860, 0x0860, 0x0860, 0x0860, 0x0060, 0x0055, - 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0061, 0x0861, - 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, - 0x0061, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0019, - 0x0061, 0x0861, 0x0861, 0x0861, 0x0861, 0x0861, 0x0061, 0x0862 - }; - - // Each of these arrays is stripped into ranges. In order to build the arrays, each - // codepoint was bit-shifted so that even and odd characters were separated into different - // arrays. The identifier of each array is the top byte after bit-shifting. - // The numbers stored in the array are the bit-shifted codepoint, the decomposition, and an - // index into another array of all possible packed data values. The top 16 bits are the - // codepoint and the bottom 16 are the decomposition and index. The top 5 bits for the decomposition - // and the rest for the index. - static const uint32_t a0[] = { - 0x00800863, 0x00880063, 0x00890863, 0x00930063, 0x00940863, 0x00980864, 0x00991063, 0x009A0863, - 0x009C0055, 0x009D0865, 0x00A01065, 0x00A10065, 0x00A20865, 0x00A50063, 0x00A60863, 0x00A90063, - 0x00AA0863, 0x00B30063, 0x00B40863, 0x00BC0866, 0x00BD0865, 0x00C00055, 0x00C10063, 0x00C30067, - 0x00C40065, 0x00C50068, 0x00C60065, 0x00C70069, 0x00C8006A, 0x00C90065, 0x00CA006B, 0x00CB006C, - 0x00CC0063, 0x00CD006D, 0x00CE006C, 0x00CF006E, 0x00D00863, 0x00D10063, 0x00D3006F, 0x00D40065, - 0x00D50055, 0x00D60063, 0x00D7006F, 0x00D80865, 0x00D90070, 0x00DA0065, 0x00DC0063, 0x00DD0055, - 0x00DE0063, 0x00DF0055, 0x00E00071, 0x00E21072, 0x00E31073, 0x00E41074, 0x00E51072, 0x00E61073, - 0x00E70865, 0x00EF0863, 0x00F20063, 0x00F30863, 0x00F80855, 0x00F91074, 0x00FA0863, 0x00FB0075, - 0x00FC0863, 0x010E0063, 0x010F0863, 0x01100076, 0x01110063, 0x01130863, 0x011A0055, 0x011D0077, - 0x011E0065, 0x011F0077, 0x01200055, 0x01210078, 0x01280055, 0x012A0079, 0x012B007A, 0x012C0055, - 0x0130007A, 0x01310055, 0x0134007B, 0x01350055, 0x0139007C, 0x013A0055, 0x0140007D, 0x01410055, - 0x0144007D, 0x0145007E, 0x01460055, 0x0149007F, 0x014A0080, 0x014B0055, 0x01587881, 0x015D0082, - 0x015E0081, 0x01610037, 0x01630082, 0x01680081, 0x01690037, 0x016C1037, 0x016F0037, 0x01707881, - 0x01730037, 0x01770081, 0x01780037, 0x01800083, 0x01A00883, 0x01A10083, 0x01A20883, 0x01A30083, - 0x01B80078, 0x01BA0837, 0x01BB0078, 0x01BD1081, 0x01BE0078, 0x01BF0806, 0x01C00078, 0x01C21037, - 0x01C30884, 0x01C40885, 0x01C60886, 0x01C70887, 0x01C80855, 0x01C90060, 0x01D10078, 0x01D20060, - 0x01D50860, 0x01D60888, 0x01D70889, 0x01D80855, 0x01D90061, 0x01E1008A, 0x01E20061, 0x01E50861, - 0x01E6088B, 0x01E7088C, 0x01E8108D, 0x01E91077, 0x01EA0877, 0x01EB108E, 0x01EC0063, 0x01F8108F, - 0x01F91090, 0x01FA1091, 0x01FB0019, 0x01FC0065, 0x01FD0063, 0x01FE0055, 0x01FF0077, 0x02000892, - 0x02010092, 0x02060892, 0x02080060, 0x02180061, 0x02280893, 0x02290093, 0x022E0893, 0x02300063, - 0x023B0863, 0x023C0063, 0x02410094, 0x02420083, 0x02440095, 0x02450063, 0x02600077, 0x02610865, - 0x02620065, 0x02680863, 0x026A0063, 0x026B0863, 0x026C0063, 0x026D0863, 0x02700063, 0x02710863, - 0x02740063, 0x02750863, 0x027B0063, 0x027C0863, 0x027D0078, 0x02800063, 0x02880078, 0x02990096, - 0x02AC0078, 0x02AD0097, 0x02B00078, 0x02B10098, 0x02C40078, 0x02C50099, 0x02C60078, 0x02C90083, - 0x02DD0078, 0x02DE0083, 0x02DF009A, 0x02E10083, 0x02E3009A, 0x02E40078, 0x02E8009B, 0x02F60078, - 0x02F8009B, 0x02FA009A, 0x02FB0078, 0x0300009C, 0x03020078, 0x0306000C, 0x03070054, 0x03080083, - 0x030B0078, 0x030F009D, 0x03100078, 0x0311089E, 0x0314009E, 0x031E0078, 0x0320009F, 0x0321009E, - 0x03260083, 0x033000A0, 0x033100A1, 0x033200A2, 0x033300A3, 0x033400A4, 0x03350007, 0x033600A5, - 0x0337009E, 0x03380083, 0x0339009E, 0x033B109E, 0x033D009E, 0x0360089E, 0x0362009E, 0x036A009D, - 0x036B0083, 0x036F0095, 0x03700083, 0x0373009F, 0x03740083, 0x0377009E, 0x0378000E, 0x03790010, - 0x037A0012, 0x037B0014, 0x037C0016, 0x037D009E, 0x037F00A6, 0x0380009D, 0x03870078, 0x0388009E, - 0x03980083, 0x03A60078, 0x03A7009E, 0x03B70078, 0x03C0009E, 0x03D30083, 0x03D90078, 0x04810083, - 0x04820071, 0x049A0871, 0x049B0071, 0x049D0078, 0x049E0083, 0x049F00A7, 0x04A10083, 0x04A500A7, - 0x04A70078, 0x04A80071, 0x04A90083, 0x04AB0078, 0x04AC0871, 0x04B00071, 0x04B10083, 0x04B20097, - 0x04B300A8, 0x04B400A9, 0x04B500AA, 0x04B600AB, 0x04B700AC, 0x04B80097, 0x04B90078, 0x04C100A7, - 0x04C20078, 0x04C30071, 0x04C70078, 0x04C80071, 0x04C90078, 0x04CA0071, 0x04DA0078, 0x04DB0071, - 0x04DD0078, 0x04DE0083, 0x04DF00A7, 0x04E10083, 0x04E30078, 0x04E400A7, 0x04E50078, 0x04E608A7, - 0x04E70071, 0x04E80078, 0x04EE0871, 0x04EF0078, 0x04F00071, 0x04F10083, 0x04F20078, 0x04F300A8, - 0x04F400A9, 0x04F500AA, 0x04F600AB, 0x04F700AC, 0x04F80071, 0x04F90008, 0x04FA00AD, 0x04FB00AE, - 0x04FC00AF, 0x04FD0094, 0x04FE0078, 0x05010083, 0x05020078, 0x05030071, 0x05060078, 0x05080071, - 0x05090078, 0x050A0071, 0x051A0078, 0x051B0871, 0x051C0071, 0x051D0078, 0x051E0083, 0x051F00A7, - 0x05210083, 0x05220078, 0x05240083, 0x05250078, 0x05260083, 0x05270078, 0x052D0871, 0x052E0071, - 0x052F0871, 0x05300078, 0x053300A8, 0x053400A9, 0x053500AA, 0x053600AB, 0x053700AC, 0x05380083, - 0x05390071, 0x053B0078, 0x05410083, 0x05420078, 0x05430071, 0x05470078, 0x05480071, 0x05490078, - 0x054A0071, 0x055A0078, 0x055B0071, 0x055D0078, 0x055E0083, 0x055F00A7, 0x05610083, 0x05630078, - 0x05640083, 0x05650078, 0x056600A7, 0x05670078, 0x05680071, 0x05690078, 0x05700071, 0x05710083, - 0x05720078, 0x057300A8, 0x057400A9, 0x057500AA, 0x057600AB, 0x057700AC, 0x05780078, 0x058100A7, - 0x05820078, 0x05830071, 0x05870078, 0x05880071, 0x05890078, 0x058A0071, 0x059A0078, 0x059B0071, - 0x059D0078, 0x059E0083, 0x059F00A7, 0x05A10083, 0x05A20078, 0x05A408A7, 0x05A50078, 0x05A608A7, - 0x05A70078, 0x05AB0083, 0x05AC0078, 0x05AE0871, 0x05AF0078, 0x05B00071, 0x05B10078, 0x05B300A8, - 0x05B400A9, 0x05B500AA, 0x05B600AB, 0x05B700AC, 0x05B80094, 0x05B90078, 0x05C10083, 0x05C20078, - 0x05C30071, 0x05C60078, 0x05C70071, 0x05CA0871, 0x05CB0078, 0x05CD0071, 0x05D00078, 0x05D20071, - 0x05D30078, 0x05D40071, 0x05D60078, 0x05D70071, 0x05DD0078, 0x05DF00A7, 0x05E00083, 0x05E100A7, - 0x05E20078, 0x05E300A7, 0x05E508A7, 0x05E70078, 0x05F300A8, 0x05F400A9, 0x05F500AA, 0x05F600AB, - 0x05F700AC, 0x05F800B0, 0x05F900B1, 0x05FA0054, 0x05FE0078, 0x060100A7, 0x06020078, 0x06030071, - 0x061A0078, 0x061B0071, 0x061D0078, 0x061F0083, 0x062100A7, 0x06230083, 0x06240883, 0x06250083, - 0x06270078, 0x062B0083, 0x062C0078, 0x06300071, 0x06310078, 0x063300A8, 0x063400A9, 0x063500AA, - 0x063600AB, 0x063700AC, 0x06380078, 0x064100A7, 0x06420078, 0x06430071, 0x065A0078, 0x065B0071, - 0x065D0078, 0x065E0083, 0x065F00A7, 0x066008A7, 0x066100A7, 0x066300B2, 0x066408A7, 0x06660083, - 0x06670078, 0x066B00A7, 0x066C0078, 0x066F0071, 0x06710078, 0x067300A8, 0x067400A9, 0x067500AA, - 0x067600AB, 0x067700AC, 0x06780078, 0x068100A7, 0x06820078, 0x06830071, 0x069D0078, 0x069F00A7, - 0x06A10083, 0x06A20078, 0x06A300A7, 0x06A508A7, 0x06A70078, 0x06B00071, 0x06B10078, 0x06B300A8, - 0x06B400A9, 0x06B500AA, 0x06B600AB, 0x06B700AC, 0x06B80078, 0x06C100A7, 0x06C20078, 0x06C30071, - 0x06CC0078, 0x06CD0071, 0x06D90078, 0x06DA0071, 0x06DE0078, 0x06E00071, 0x06E40078, 0x06E50083, - 0x06E60078, 0x06E800A7, 0x06E90083, 0x06EC00A7, 0x06ED08A7, 0x06F00078, 0x06F900A7, 0x06FA0097, - 0x06FB0078, 0x07010071, 0x071A0083, 0x071E0078, 0x07200071, 0x07230081, 0x07240083, 0x072800A8, - 0x072900A9, 0x072A00AA, 0x072B00AB, 0x072C00AC, 0x072D0097, 0x072E0078, 0x07410071, 0x07430078, - 0x07440071, 0x07460078, 0x074A0071, 0x074C0078, 0x074D0071, 0x07500078, 0x07510071, 0x07520078, - 0x07550071, 0x07560078, 0x07570071, 0x075A0083, 0x075D0078, 0x075E0083, 0x075F0078, 0x07600071, - 0x07630081, 0x07640083, 0x07670078, 0x076800A8, 0x076900A9, 0x076A00AA, 0x076B00AB, 0x076C00AC, - 0x076D0078, 0x076E1071, 0x076F0078, 0x07800071, 0x07810094, 0x07820097, 0x07865897, 0x07870097, - 0x078A0094, 0x078C0083, 0x078D0094, 0x079000A8, 0x079100A9, 0x079200AA, 0x079300AB, 0x079400AC, - 0x079500B3, 0x079A0094, 0x079D00B4, 0x079F00A7, 0x07A00071, 0x07A40078, 0x07A50071, 0x07A90871, - 0x07AA0071, 0x07AE0871, 0x07AF0071, 0x07B60078, 0x07B90083, 0x07BB0883, 0x07BD0083, 0x07C40071, - 0x07C60078, 0x07C80083, 0x07CC0078, 0x07CD0083, 0x07D10883, 0x07D20083, 0x07D60883, 0x07D70083, - 0x07DF0094, 0x07E30083, 0x07E40094, 0x07E70078, 0x07E80097, 0x07E90078, 0x08000071, 0x08110078, - 0x08120071, 0x08130871, 0x08140078, 0x08150071, 0x081600A7, 0x08170083, 0x081A0078, 0x081B0083, - 0x081C00A7, 0x081D0078, 0x082000A8, 0x082100A9, 0x082200AA, 0x082300AB, 0x082400AC, 0x08250097, - 0x08280071, 0x082B00A7, 0x082C0083, 0x082D0078, 0x085000B5, 0x08630078, 0x08680071, 0x087E7881, - 0x087F0078, 0x08800071, 0x08AD0078, 0x08B00071, 0x08D20078, 0x08D40071, 0x08FD0078, 0x09000071, - 0x09270078, 0x09280071, 0x092F0078, 0x09300071, 0x09470078, 0x09480071, 0x095B0078, 0x095C0071, - 0x09630078, 0x09640071, 0x098B0078, 0x098C0071, 0x09AE0078, 0x09B00094, 0x09B10097, 0x09B500B6, - 0x09B600B7, 0x09B700B8, 0x09B800B9, 0x09B900B0, 0x09BA00BA, 0x09BB00BB, 0x09BC00BC, 0x09BD00BD, - 0x09BE00BE, 0x09BF0078, 0x09C00071, 0x09C80054, 0x09CD0078, 0x09D00071, 0x09FB0078, 0x0A010071, - 0x0B370097, 0x0B380071, 0x0B3C0078, 0x0B400005, 0x0B410071, 0x0B4E00BF, 0x0B4F0078, 0x0B500071, - 0x0B760097, 0x0B7700C0, 0x0B7800C1, 0x0B790078, 0x0B800071, 0x0B890083, 0x0B8B0078, 0x0B900071, - 0x0B990083, 0x0B9B0097, 0x0B9C0078, 0x0BA00071, 0x0BA90083, 0x0BAA0078, 0x0BB00071, 0x0BB90083, - 0x0BBA0078, 0x0BC00071, 0x0BDA00C2, 0x0BDB00A7, 0x0BDC0083, 0x0BDF00A7, 0x0BE30083, 0x0BE400A7, - 0x0BE50083, 0x0BEA0097, 0x0BEE0071, 0x0BEF0078, 0x0BF000A8, 0x0BF100A9, 0x0BF200AA, 0x0BF300AB, - 0x0BF400AC, 0x0BF50078, 0x0BF800C3, 0x0BF900C4, 0x0BFA00C5, 0x0BFB00C6, 0x0BFC00C7, 0x0BFD0078, - 0x0C000006, 0x0C030099, 0x0C040006, 0x0C060083, 0x0C070005, 0x0C0800A8, 0x0C0900A9, 0x0C0A00AA, - 0x0C0B00AB, 0x0C0C00AC, 0x0C0D0078, 0x0C100071, 0x0C3C0078, 0x0C400071, 0x0C550078, 0x0C800071, - 0x0C8F0078, 0x0C900083, 0x0C9200A7, 0x0C940083, 0x0C9500C8, 0x0C960078, 0x0C9800A7, 0x0C990083, - 0x0C9A00A7, 0x0C9D0083, 0x0C9E0078, 0x0CA00054, 0x0CA10078, 0x0CA20006, 0x0CA300A8, 0x0CA400A9, - 0x0CA500AA, 0x0CA600AB, 0x0CA700AC, 0x0CA80071, 0x0CB70078, 0x0CB80071, 0x0CBB0078, 0x0CC00071, - 0x0CD50078, 0x0CD800A7, 0x0CE10071, 0x0CE400A7, 0x0CE50078, 0x0CE800A8, 0x0CE900A9, 0x0CEA00AA, - 0x0CEB00AB, 0x0CEC00AC, 0x0CED0078, 0x0CEF0006, 0x0CF00054, 0x0D000071, 0x0D0C0083, 0x0D0D00A7, - 0x0D0E0078, 0x0D0F0097, 0x0D100078, 0x0E800055, 0x0E967881, 0x0EA70081, 0x0EA87881, 0x0EB17055, - 0x0EB60055, 0x0EBC7881, 0x0EBD0055, 0x0ECE7881, 0x0EE00083, 0x0EE20078, 0x0F000863, 0x0F4B0855, - 0x0F4D1055, 0x0F4E0078, 0x0F500863, 0x0F7D0078, 0x0F8008C9, 0x0F8408CA, 0x0F8808C9, 0x0F8B0078, - 0x0F8C08CA, 0x0F8F0078, 0x0F9008C9, 0x0F9408CA, 0x0F9808C9, 0x0F9C08CA, 0x0FA008C9, 0x0FA30078, - 0x0FA408CA, 0x0FA70078, 0x0FA80855, 0x0FAC0078, 0x0FB008C9, 0x0FB408CA, 0x0FB808CB, 0x0FB908CC, - 0x0FBB08CD, 0x0FBC08CE, 0x0FBD08CF, 0x0FBE08D0, 0x0FBF0078, 0x0FC008C9, 0x0FC408D1, 0x0FC808C9, - 0x0FCC08D1, 0x0FD008C9, 0x0FD408D1, 0x0FD808C9, 0x0FD90855, 0x0FDC08CA, 0x0FDD08D2, 0x0FDE08D3, - 0x0FDF08D4, 0x0FE01037, 0x0FE10855, 0x0FE408D5, 0x0FE608D3, 0x0FE70837, 0x0FE808C9, 0x0FE90855, - 0x0FEA0078, 0x0FEB0855, 0x0FEC08CA, 0x0FED08D6, 0x0FEE0078, 0x0FEF0837, 0x0FF008C9, 0x0FF10855, - 0x0FF408CA, 0x0FF508D7, 0x0FF608D8, 0x0FF70837, 0x0FF80078, 0x0FF90855, 0x0FFC08D9, 0x0FFD08DA, - 0x0FFE08D3, 0x0FFF1037, 0x10000805, 0x10011005, 0x10060057, 0x100700C2, 0x10080099, 0x100B0006, - 0x100C00DB, 0x100D00B4, 0x100E00DB, 0x100F00B4, 0x10100006, 0x10121006, 0x101400DC, 0x101500DD, - 0x101600DE, 0x101700DF, 0x10180007, 0x101A1007, 0x101B1006, 0x101C0006, 0x101D00E0, 0x101E1006, - 0x10200038, 0x10210006, 0x102200E1, 0x1023000A, 0x10241006, 0x10250006, 0x10290019, 0x102A0038, - 0x102B0006, 0x10300057, 0x10320078, 0x10350057, 0x103878E2, 0x10390078, 0x103A78E3, 0x103B78E4, - 0x103C78E5, 0x103D780B, 0x103E7819, 0x103F780A, 0x104070E2, 0x1041705A, 0x104270E3, 0x104370E4, - 0x104470E5, 0x1045700B, 0x10467019, 0x1047700A, 0x10487081, 0x104B0078, 0x10500008, 0x10541008, - 0x10550008, 0x105B0078, 0x10680083, 0x106F0095, 0x10730083, 0x10760078, 0x10801054, 0x10812877, - 0x10820054, 0x10831054, 0x10840054, 0x10852855, 0x10862877, 0x10872855, 0x10882877, 0x108A0054, - 0x108B1054, 0x108C0054, 0x108D2877, 0x108F0054, 0x10907854, 0x10922877, 0x109308E6, 0x10942877, - 0x109508E7, 0x10962877, 0x10970058, 0x10982877, 0x10990054, 0x109A2855, 0x109B1071, 0x109D0054, - 0x109E2855, 0x109F2877, 0x10A028E8, 0x10A10019, 0x10A32855, 0x10A50054, 0x10A70078, 0x10AA305F, - 0x10B010E9, 0x10B110EA, 0x10B210EB, 0x10B310EC, 0x10B410ED, 0x10B510EE, 0x10B610EF, 0x10B710F0, - 0x10B810F1, 0x10B910F2, 0x10BA10F3, 0x10BB10F4, 0x10BC10F5, 0x10BD10F6, 0x10BE10F7, 0x10BF10F8, - 0x10C000F9, 0x10C100FA, 0x10C20078, 0x10C80019, 0x10CB0054, 0x10CD0819, 0x10CE0054, 0x10D00019, - 0x10D10054, 0x10D30019, 0x10D40054, 0x10D70819, 0x10D80054, 0x10E70819, 0x10E80054, 0x10E90019, - 0x10EB0054, 0x10FA0019, 0x110100E8, 0x110208E8, 0x11030019, 0x110400FB, 0x110608FC, 0x11070019, - 0x1109000B, 0x110A0019, 0x110B00E8, 0x110C0019, 0x110D00E8, 0x110F0019, 0x111000E8, 0x111208E8, - 0x11140019, 0x111610E8, 0x111700E8, 0x111810E8, 0x111900E8, 0x111A0019, 0x111E00FD, 0x111F00E8, - 0x112208E8, 0x112300E8, 0x11270019, 0x112900FD, 0x112B0019, 0x113008E8, 0x113200FD, 0x11360019, - 0x113708FD, 0x113900FD, 0x113A08FD, 0x113B00FD, 0x113C08FD, 0x113D00FD, 0x114008FD, 0x114100FD, - 0x114208FD, 0x114300FD, 0x114408FD, 0x114500FD, 0x114600E8, 0x11470019, 0x114800FE, 0x114A0019, - 0x114C00FF, 0x114D0019, 0x115100FD, 0x11520019, 0x11530100, 0x11540101, 0x115500E8, 0x115608E8, - 0x115800FD, 0x115C00E8, 0x115D0019, 0x115F00E8, 0x11600019, 0x116500FE, 0x11670019, 0x116800FD, - 0x11690019, 0x116B00FD, 0x117008FD, 0x117200FD, 0x117508FD, 0x11770019, 0x117800FD, 0x11790102, - 0x117B0103, 0x117C00E8, 0x117D0104, 0x117F0105, 0x11800054, 0x118400FD, 0x11860054, 0x119000E8, - 0x11910054, 0x1195080A, 0x11960054, 0x119B0094, 0x11BE0019, 0x11BF0054, 0x11CE0019, 0x11DA00B4, - 0x11DB0006, 0x11DC0054, 0x11EE0078, 0x12000054, 0x12140078, 0x12200054, 0x12260078, 0x12301906, - 0x12311907, 0x12321908, 0x12331909, 0x1234190A, 0x1235190B, 0x1236190C, 0x1237190D, 0x1238190E, - 0x1239190F, 0x123A1106, 0x123B1107, 0x123C1108, 0x123D1109, 0x123E110A, 0x123F110B, 0x1240110C, - 0x1241110D, 0x1242110E, 0x1243110F, 0x1244105D, 0x1245105B, 0x12461110, 0x12471111, 0x12481112, - 0x12491113, 0x124A1114, 0x124B1115, 0x124C1116, 0x124D1117, 0x124E1094, 0x125B1918, 0x12681919, - 0x127518C3, 0x1276011A, 0x1277011B, 0x1278011C, 0x1279011D, 0x127A011E, 0x127B00C4, 0x127C00C5, - 0x127D00C6, 0x127E00C7, 0x127F011F, 0x12800054, 0x12FC0019, 0x13000054, 0x134F0078, 0x13500054, - 0x13560094, 0x13570054, 0x13590078, 0x13810054, 0x13850078, 0x13860054, 0x13940078, 0x13950054, - 0x13A60078, 0x13A80054, 0x13AA0078, 0x13AB0054, 0x13B00078, 0x13B10054, 0x13B40009, 0x13BB0106, - 0x13BC0107, 0x13BD0108, 0x13BE0109, 0x13BF010A, 0x13C00106, 0x13C10107, 0x13C20108, 0x13C30109, - 0x13C4010A, 0x13C50106, 0x13C60107, 0x13C70108, 0x13C80109, 0x13C9010A, 0x13CA0054, 0x13CB0078, - 0x13CC0054, 0x13D80078, 0x13D90054, 0x13E000E8, 0x13E10019, 0x13E200FE, 0x13E3000A, 0x13E40078, - 0x13E80019, 0x13EA00E8, 0x13EB00FE, 0x13EC0019, 0x13EE00E8, 0x13EF00FE, 0x13F00019, 0x13F100FD, - 0x13F30009, 0x13F60078, 0x13F80019, 0x14000094, 0x14800019, 0x14C2000A, 0x14C70120, 0x14C80121, - 0x14C9000A, 0x14CD0019, 0x14CE00E8, 0x14D80019, 0x14DC0122, 0x14DD0019, 0x14E000FD, 0x14E100E8, - 0x14E200FD, 0x14E30019, 0x14E700E8, 0x14E800FE, 0x14EA00FD, 0x14EB0019, 0x14EC0009, 0x14EE00E8, - 0x14EF0019, 0x14F200E8, 0x14F30019, 0x14F400E8, 0x14F50019, 0x14FA00E8, 0x14FC00FD, 0x14FD0019, - 0x14FE0009, 0x14FF0019, 0x150500E8, 0x150610E8, 0x150700E8, 0x15110019, 0x151200E8, 0x15140019, - 0x151600FE, 0x15180019, 0x151A00FD, 0x151B0019, 0x151E00FD, 0x151F00E8, 0x15200019, 0x152C00E8, - 0x152D0019, 0x153200FD, 0x15330019, 0x153500E8, 0x15370019, 0x153800E8, 0x15390019, 0x153A10E8, - 0x153B1019, 0x153C0019, 0x153D00FE, 0x153E00E8, 0x153F00FE, 0x154300E8, 0x154600FE, 0x154700E8, - 0x154900FE, 0x154F00E8, 0x155100FE, 0x15520019, 0x155300FD, 0x15570019, 0x155800FE, 0x155900E8, - 0x155A00FE, 0x155B00E8, 0x155E00FE, 0x156400E8, 0x156700FE, 0x156C0019, 0x156E08E8, 0x156F0123, - 0x15700019, 0x157100E8, 0x15720124, 0x157300E8, 0x15740019, 0x157600FD, 0x157700E8, 0x15780019, - 0x157C00FE, 0x157E0019, 0x15800054, 0x158A0078, 0x16000096, 0x16180098, 0x16300078, 0x16400063, - 0x16720055, 0x16730054, 0x16760078, 0x167D0006, 0x16800125, 0x16930078, 0x16980071, 0x16B30078, - 0x16C00071, 0x16CC0078, 0x16D00071, 0x16F00078, 0x17000006, 0x17010126, 0x17030006, 0x170500E0, - 0x17060126, 0x17070006, 0x170C0078, 0x170E0126, 0x170F0078, 0x17400054, 0x174D0078, 0x174E0054, - 0x177A0078, 0x17801054, 0x17EB0078, 0x17F80054, 0x17FE0078, 0x18008805, 0x18010006, 0x18020054, - 0x18030071, 0x18040009, 0x18090054, 0x180A0009, 0x180E0099, 0x180F00BF, 0x18100054, 0x18110127, - 0x18120128, 0x18130129, 0x1814012A, 0x18150083, 0x18180099, 0x18190081, 0x181B1054, 0x181C112B, - 0x181D112C, 0x181E0071, 0x181F0054, 0x18200078, 0x18210071, 0x18260871, 0x18320071, 0x18380871, - 0x18390071, 0x183A0871, 0x183C0071, 0x183D0871, 0x183F0071, 0x184A0871, 0x184B0071, 0x184C0078, - 0x184D0083, 0x184E1037, 0x184F0881, 0x18500099, 0x18510071, 0x18560871, 0x18620071, 0x18680871, - 0x18690071, 0x186A0871, 0x186C0071, 0x186D0871, 0x186F0071, 0x187A0871, 0x187B0071, 0x187C0871, - 0x187E0081, 0x187F0881, 0x18800078, 0x18830071, 0x18970078, 0x18991071, 0x18C80094, 0x18C978AD, - 0x18CA78AE, 0x18CB7894, 0x18D00071, 0x18DC0078, 0x18E00054, 0x18E80078, 0x18F80071, 0x19001094, - 0x190F1054, 0x191010AD, 0x191110AE, 0x1912112D, 0x1913112E, 0x1914112F, 0x19151094, 0x19220078, - 0x19286854, 0x19291930, 0x192A1931, 0x192B1932, 0x192C1933, 0x192D1934, 0x192E1935, 0x192F1936, - 0x19301894, 0x193E1854, 0x194018AD, 0x194118AE, 0x1942192D, 0x1943192E, 0x1944192F, 0x19451894, - 0x19591937, 0x195A1938, 0x195B1939, 0x195C193A, 0x195D193B, 0x195E193C, 0x195F193D, 0x19601094, - 0x19666854, 0x19681894, 0x19806894, 0x19AC1094, 0x19B96894, 0x19BC6854, 0x19BE6894, 0x19EF6854, - 0x19F01094, 0x1A000071, 0x26DB0078, 0x26E00054, 0x27000071, 0x4FDE0078, 0x50000071, 0x52470078, - 0x52480054, 0x52640078, 0x53800037, 0x538C0078, 0x54000071, 0x540100C8, 0x54020071, 0x54030083, - 0x54040071, 0x541200A7, 0x54130083, 0x54140054, 0x54160078, 0x56000071, 0x6BD20078, 0x6C00013E, - 0x7000013F, 0x7C800871, 0x7D070071, 0x7D080871, 0x7D0A0071, 0x7D0B0871, 0x7D120071, 0x7D130871, - 0x7D140071, 0x7D150871, 0x7D170078, 0x7D180871, 0x7D360078, 0x7D380871, 0x7D6D0078, 0x7D801055, - 0x7D840078, 0x7D8A1055, 0x7D8C0078, 0x7D8F0083, 0x7D90289B, 0x7D95089B, 0x7DA10078, 0x7DA2089B, - 0x7DA8409E, 0x7DAA389E, 0x7DAB409E, 0x7DAC389E, 0x7DAD409E, 0x7DAE389E, 0x7DAF409E, 0x7DB0389E, - 0x7DB1409E, 0x7DB2389E, 0x7DB3409E, 0x7DB4389E, 0x7DB5409E, 0x7DB6389E, 0x7DB7409E, 0x7DB8389E, - 0x7DB9409E, 0x7DBA389E, 0x7DBB409E, 0x7DBC389E, 0x7DBD409E, 0x7DBE389E, 0x7DBF409E, 0x7DC0389E, - 0x7DC1409E, 0x7DC8389E, 0x7DC9409E, 0x7DCA389E, 0x7DCB409E, 0x7DCC389E, 0x7DCD409E, 0x7DCE389E, - 0x7DCF409E, 0x7DD1389E, 0x7DD2409E, 0x7DD4389E, 0x7DD5409E, 0x7DD6389E, 0x7DD7409E, 0x7DD90078, - 0x7DEA209E, 0x7DEB489E, 0x7DEC209E, 0x7DEF409E, 0x7DF3389E, 0x7DF5409E, 0x7DFC389E, 0x7DFD209E, - 0x7DFE409E, 0x7DFF389E, 0x7E00409E, 0x7E32209E, 0x7E4C389E, 0x7E70489E, 0x7E7B409E, 0x7E89209E, - 0x7E97389E, 0x7E9A489E, 0x7E9E209E, 0x7E9F00B4, 0x7EA00078, 0x7EA8389E, 0x7EAC209E, 0x7EAE389E, - 0x7EAF209E, 0x7EB0389E, 0x7EB1209E, 0x7EB4389E, 0x7EB5209E, 0x7EB8389E, 0x7EBA209E, 0x7EC3389E, - 0x7EC80078, 0x7EC9389E, 0x7ECB209E, 0x7ECC389E, 0x7ECD209E, 0x7EDA389E, 0x7EDB209E, 0x7EDC389E, - 0x7EDE209E, 0x7EE2389E, 0x7EE3209E, 0x7EE40078, 0x7EF8409E, 0x7EFE4140, 0x7EFF0078, 0x7F000083, - 0x7F088006, 0x7F0C80BF, 0x7F0D0078, 0x7F100083, 0x7F120078, 0x7F188006, 0x7F198099, 0x7F1A8038, - 0x7F1B80BF, 0x7F230006, 0x7F2480BF, 0x7F251006, 0x7F271038, 0x7F28600C, 0x7F2A6006, 0x7F2C6099, - 0x7F2D60BF, 0x7F306006, 0x7F31600B, 0x7F326019, 0x7F346006, 0x7F356007, 0x7F360078, 0x7F38409E, - 0x7F41209E, 0x7F46489E, 0x7F47209E, 0x7F49489E, 0x7F4A209E, 0x7F4C489E, 0x7F4D209E, 0x7F4E489E, - 0x7F4F209E, 0x7F50489E, 0x7F51209E, 0x7F52489E, 0x7F53209E, 0x7F54489E, 0x7F55209E, 0x7F5A489E, - 0x7F5B209E, 0x7F5C489E, 0x7F5D209E, 0x7F5E489E, 0x7F5F209E, 0x7F60489E, 0x7F61209E, 0x7F62489E, - 0x7F63209E, 0x7F64489E, 0x7F65209E, 0x7F66489E, 0x7F67209E, 0x7F68489E, 0x7F69209E, 0x7F6A489E, - 0x7F6B209E, 0x7F6C489E, 0x7F6D209E, 0x7F6E489E, 0x7F6F209E, 0x7F70489E, 0x7F71209E, 0x7F72489E, - 0x7F73209E, 0x7F74489E, 0x7F75209E, 0x7F76489E, 0x7F77209E, 0x7F7A489E, 0x7F7B209E, 0x7F7F0078, - 0x7F818806, 0x7F828808, 0x7F838806, 0x7F848809, 0x7F858806, 0x7F86880C, 0x7F88880E, 0x7F898810, - 0x7F8A8812, 0x7F8B8814, 0x7F8C8816, 0x7F8D880C, 0x7F8E8818, 0x7F8F881A, 0x7F908806, 0x7F918860, - 0x7F9E8806, 0x7F9F8837, 0x7FA18861, 0x7FAE8819, 0x7FB0880A, 0x7FB15009, 0x7FB25006, 0x7FB35071, - 0x7FB85081, 0x7FB95071, 0x7FCF5081, 0x7FD05071, 0x7FE00078, 0x7FE15071, 0x7FE40078, 0x7FE55071, - 0x7FE80078, 0x7FE95071, 0x7FEC0078, 0x7FED5071, 0x7FEF0078, 0x7FF08808, 0x7FF18819, 0x7FF28854, - 0x7FF38808, 0x7FF45054, 0x7FF55019, 0x7FF75054, 0x7FF80078, 0x7FFD0141, 0x7FFE0054, 0x7FFF0078, - 0x80000071, 0x80060078, 0x80070071, 0x801F0078, 0x80200071, 0x80270078, 0x80280071, 0x802F0078, - 0x80400071, 0x807E0078, 0x80800097, 0x80810094, 0x80820078, 0x808400B6, 0x808500B7, 0x808600B8, - 0x808700B9, 0x808800B0, 0x808900BA, 0x808A00BB, 0x808B00BC, 0x808C00BD, 0x808D0142, 0x808E0143, - 0x808F0144, 0x80900145, 0x809100B1, 0x80920146, 0x80930147, 0x80940148, 0x80950149, 0x8096014A, - 0x8097014B, 0x8098014C, 0x8099014D, 0x809A0078, 0x809C0094, 0x80A0014E, 0x80A1014F, 0x80A20150, - 0x80A30151, 0x80A40152, 0x80A50150, 0x80A60153, 0x80A70151, 0x80A80154, 0x80A90155, 0x80AA0156, - 0x80AB0157, 0x80AC014F, 0x80AE0158, 0x80B00154, 0x80B30150, 0x80B50155, 0x80B60153, 0x80B90151, - 0x80BA0150, 0x80BB005F, 0x80BD0054, 0x80C500C3, 0x80C60078, 0x81800071, 0x819000AD, 0x819100B0, - 0x81920078, 0x81980071, 0x81A50159, 0x81A60078, 0x81C00071, 0x81CF0078, 0x81D00071, 0x81E20078, - 0x81E40071, 0x81E80094, 0x81E90158, 0x81EA015A, 0x81EB0078, 0x8200015B, 0x8214015C, 0x82280071, - 0x824F0078, 0x825000A8, 0x825100A9, 0x825200AA, 0x825300AB, 0x825400AC, 0x82550078, 0x8400009B, - 0x84030078, 0x8404009B, 0x841B0078, 0x841C009B, 0x841D0078, 0x841E009B, 0x841F0078, 0x8500009B, - 0x85010083, 0x85020078, 0x85030083, 0x85040078, 0x85060083, 0x8508009B, 0x850A0078, 0x850B009B, - 0x850C0078, 0x850D009B, 0x851A0078, 0x851C0083, 0x851E0078, 0x8520015D, 0x8521015E, 0x8522015F, - 0x85230160, 0x85240078, 0x8528009A, 0x852D0078, 0xE8000094, 0xE87B0078, 0xE8800094, 0xE8940078, - 0xE8950094, 0xE8AF0894, 0xE8B300A7, 0xE8B40083, 0xE8B50094, 0xE8B700A7, 0xE8BA0057, 0xE8BE0083, - 0xE8C20094, 0xE8C30083, 0xE8C60094, 0xE8D50083, 0xE8D70094, 0xE8DE0894, 0xE8E10094, 0xE8EF0078, - 0xE9000054, 0xE9210083, 0xE9230078, 0xE9800054, 0xE9AC0078, 0xEA002877, 0xEA0D2855, 0xEA1A2877, - 0xEA272855, 0xEA342877, 0xEA412855, 0xEA4E2877, 0xEA500078, 0xEA512877, 0xEA520078, 0xEA532877, - 0xEA540078, 0xEA552877, 0xEA5B2855, 0xEA5D0078, 0xEA5F2855, 0xEA620078, 0xEA632855, 0xEA682877, - 0xEA752855, 0xEA822877, 0xEA830078, 0xEA842877, 0xEA860078, 0xEA872877, 0xEA8F2855, 0xEA9C2877, - 0xEA9D0078, 0xEA9E2877, 0xEAA40078, 0xEAA52877, 0xEAA92855, 0xEAB62877, 0xEAC32855, 0xEAD02877, - 0xEADD2855, 0xEAEA2877, 0xEAF72855, 0xEB042877, 0xEB112855, 0xEB1E2877, 0xEB2B2855, 0xEB382877, - 0xEB452855, 0xEB530078, 0xEB542877, 0xEB612855, 0xEB712877, 0xEB7E2855, 0xEB8E2877, 0xEB9B2855, - 0xEBAB2877, 0xEBB82855, 0xEBC82877, 0xEBD52855, 0xEBE50078, 0xEBE7280E, 0xEBE82810, 0xEBE92812, - 0xEBEA2814, 0xEBEB2816, 0xEBEC280E, 0xEBED2810, 0xEBEE2812, 0xEBEF2814, 0xEBF02816, 0xEBF1280E, - 0xEBF22810, 0xEBF32812, 0xEBF42814, 0xEBF52816, 0xEBF6280E, 0xEBF72810, 0xEBF82812, 0xEBF92814, - 0xEBFA2816, 0xEBFB280E, 0xEBFC2810, 0xEBFD2812, 0xEBFE2814, 0xEBFF2816, 0xEC000078 - }; - - static const uint32_t a1[] = { - 0x00000071, 0x536C0078, 0x7C000871, 0x7D0F0078 - }; - - static const uint32_t a7[] = { - 0x00100057, 0x00400078, 0x00800083, 0x00F80078, 0x8000013F, 0xFFFF0078 - }; - - static const uint32_t a8[] = { - 0x0000013F, 0x7FFF0078 - }; - - static const uint32_t a16[] = { - 0x00800865, 0x00880065, 0x00890865, 0x00930065, 0x00940865, 0x00980161, 0x00991065, 0x009A0865, - 0x009C0863, 0x009F1063, 0x00A00063, 0x00A10863, 0x00A41055, 0x00A50065, 0x00A60865, 0x00A90065, - 0x00AA0865, 0x00B30065, 0x00B40865, 0x00BC0863, 0x00BF1162, 0x00C00163, 0x00C10065, 0x00C30063, - 0x00C40068, 0x00C50063, 0x00C60055, 0x00C70164, 0x00C80063, 0x00C90068, 0x00CA0165, 0x00CB0166, - 0x00CC0065, 0x00CD0055, 0x00CE0167, 0x00CF0168, 0x00D00865, 0x00D10065, 0x00D30063, 0x00D4006F, - 0x00D50055, 0x00D60065, 0x00D70863, 0x00D80070, 0x00D90063, 0x00DB0169, 0x00DC0065, 0x00DD0071, - 0x00DE0065, 0x00DF016A, 0x00E00071, 0x00E21074, 0x00E31072, 0x00E41073, 0x00E51074, 0x00E60863, - 0x00EE016B, 0x00EF0865, 0x00F20065, 0x00F30865, 0x00F81072, 0x00F91073, 0x00FA0865, 0x00FB016C, - 0x00FC0865, 0x010E0065, 0x010F0865, 0x01100055, 0x01110065, 0x01130865, 0x011A0055, 0x011D0063, - 0x011E016D, 0x011F0055, 0x0120016E, 0x01210078, 0x01280055, 0x0129016F, 0x012A0055, 0x012B007A, - 0x012C0170, 0x012D0171, 0x012E0055, 0x01310172, 0x01320055, 0x01340173, 0x01350055, 0x01370173, - 0x01380055, 0x013A0174, 0x013B0055, 0x0141007D, 0x01420055, 0x0145007E, 0x01460055, 0x01587881, - 0x015C0082, 0x015D0081, 0x01610037, 0x01630082, 0x01680081, 0x01690037, 0x016C1037, 0x016F0037, - 0x01707881, 0x01720037, 0x01800083, 0x01A00883, 0x01A20175, 0x01A30083, 0x01B80078, 0x01BA0037, - 0x01BB0078, 0x01C20837, 0x01C30806, 0x01C40885, 0x01C50078, 0x01C70887, 0x01C80060, 0x01D50860, - 0x01D60889, 0x01D80061, 0x01E50861, 0x01E6088C, 0x01E70078, 0x01E81176, 0x01E90877, 0x01EA1177, - 0x01EB0055, 0x01EC0065, 0x01F81093, 0x01F90055, 0x01FA1178, 0x01FB0063, 0x01FC10D8, 0x01FD0065, - 0x01FE0077, 0x02000892, 0x02020092, 0x02030892, 0x02040092, 0x02060892, 0x02070092, 0x02080060, - 0x020C0860, 0x020D0060, 0x02180061, 0x021C0861, 0x021D0061, 0x02280893, 0x022A0093, 0x022B0893, - 0x022C0093, 0x022E0893, 0x022F0093, 0x02300065, 0x023B0865, 0x023C0065, 0x02410083, 0x02430078, - 0x02440095, 0x02450065, 0x02600863, 0x02610063, 0x02670078, 0x02680865, 0x026A0065, 0x026B0865, - 0x026C0065, 0x026D0865, 0x02700065, 0x02710865, 0x02740065, 0x02750865, 0x027B0065, 0x027C0865, - 0x027D0078, 0x02800065, 0x02880078, 0x02980096, 0x02AB0078, 0x02AC0081, 0x02AD0097, 0x02B00098, - 0x02C31055, 0x02C40097, 0x02C50078, 0x02C80083, 0x02E1009A, 0x02E20083, 0x02E40078, 0x02E8009B, - 0x02F50078, 0x02F8009B, 0x02F9009A, 0x02FA0078, 0x0300009C, 0x03020078, 0x03050140, 0x0306009D, - 0x03070054, 0x03080083, 0x030B0078, 0x030D009D, 0x030E0078, 0x030F009D, 0x0310009E, 0x0311089E, - 0x0313009E, 0x031D0078, 0x0320009E, 0x03250083, 0x032F0078, 0x03300179, 0x0331017A, 0x0332017B, - 0x0333017C, 0x0334017D, 0x033500A5, 0x0336009D, 0x0337009E, 0x033A109E, 0x033C009E, 0x0369089E, - 0x036A009E, 0x036B0083, 0x036E009C, 0x036F0083, 0x0372009F, 0x03730083, 0x03740054, 0x03750083, - 0x0377009E, 0x0378000F, 0x03790011, 0x037A0013, 0x037B0015, 0x037C0017, 0x037D009E, 0x037E00A6, - 0x037F009E, 0x0380009D, 0x03870057, 0x03880083, 0x0389009E, 0x03980083, 0x03A50078, 0x03A6009E, - 0x03B70078, 0x03C0009E, 0x03D30083, 0x03D8009E, 0x03D90078, 0x04800083, 0x048100A7, 0x04820071, - 0x04940871, 0x04950071, 0x04980871, 0x04990071, 0x049D0078, 0x049E0071, 0x049F00A7, 0x04A00083, - 0x04A400A7, 0x04A60083, 0x04A70078, 0x04A80083, 0x04AA0078, 0x04AC0871, 0x04B00071, 0x04B10083, - 0x04B20097, 0x04B3017E, 0x04B4017F, 0x04B50180, 0x04B60181, 0x04B70182, 0x04B80078, 0x04BE0071, - 0x04BF0078, 0x04C00083, 0x04C100A7, 0x04C20071, 0x04C60078, 0x04C70071, 0x04C80078, 0x04C90071, - 0x04D40078, 0x04D50071, 0x04D80078, 0x04DB0071, 0x04DD0078, 0x04DE0071, 0x04DF00A7, 0x04E00083, - 0x04E20078, 0x04E300A7, 0x04E40078, 0x04E508A7, 0x04E60083, 0x04E70078, 0x04EB00A7, 0x04EC0078, - 0x04EE0871, 0x04F00071, 0x04F10083, 0x04F20078, 0x04F3017E, 0x04F4017F, 0x04F50180, 0x04F60181, - 0x04F70182, 0x04F80071, 0x04F90008, 0x04FA00B6, 0x04FB00B7, 0x04FC0183, 0x04FD0078, 0x05000083, - 0x050100A7, 0x05020071, 0x05050078, 0x05070071, 0x05080078, 0x05090071, 0x05140078, 0x05150071, - 0x05180078, 0x05190871, 0x051A0071, 0x051B0078, 0x051C0071, 0x051D0078, 0x051F00A7, 0x05200083, - 0x05210078, 0x05230083, 0x05240078, 0x05250083, 0x05270078, 0x052C0871, 0x052E0078, 0x0533017E, - 0x0534017F, 0x05350180, 0x05360181, 0x05370182, 0x05380083, 0x05390071, 0x053A0078, 0x05400083, - 0x054100A7, 0x05420071, 0x05540078, 0x05550071, 0x05580078, 0x05590071, 0x055D0078, 0x055E0071, - 0x055F00A7, 0x05600083, 0x056400A7, 0x05660083, 0x05670078, 0x05700071, 0x05710083, 0x05720078, - 0x0573017E, 0x0574017F, 0x05750180, 0x05760181, 0x05770182, 0x05780008, 0x05790078, 0x05800083, - 0x058100A7, 0x05820071, 0x05860078, 0x05870071, 0x05880078, 0x05890071, 0x05940078, 0x05950071, - 0x05980078, 0x05990071, 0x059D0078, 0x059E0071, 0x059F0083, 0x05A20078, 0x05A300A7, 0x05A40078, - 0x05A508A7, 0x05A60083, 0x05A70078, 0x05AB00A7, 0x05AC0078, 0x05AE0871, 0x05AF0071, 0x05B10078, - 0x05B3017E, 0x05B4017F, 0x05B50180, 0x05B60181, 0x05B70182, 0x05B80071, 0x05B90078, 0x05C10071, - 0x05C50078, 0x05C70071, 0x05C80078, 0x05C90071, 0x05CB0078, 0x05CC0071, 0x05CD0078, 0x05CF0071, - 0x05D00078, 0x05D10071, 0x05D20078, 0x05D40071, 0x05D50078, 0x05D70071, 0x05DD0078, 0x05DF00A7, - 0x05E10078, 0x05E300A7, 0x05E40078, 0x05E508A7, 0x05E60083, 0x05E70078, 0x05EB00A7, 0x05EC0078, - 0x05F3017E, 0x05F4017F, 0x05F50180, 0x05F60181, 0x05F70182, 0x05F80184, 0x05F90054, 0x05FC0008, - 0x05FD0078, 0x060000A7, 0x06020071, 0x06060078, 0x06070071, 0x06080078, 0x06090071, 0x06140078, - 0x06150071, 0x061D0078, 0x061F0083, 0x062000A7, 0x06220078, 0x06230083, 0x06240078, 0x06250083, - 0x06270078, 0x062A0083, 0x062B0078, 0x06300071, 0x06310078, 0x0633017E, 0x0634017F, 0x06350180, - 0x06360181, 0x06370182, 0x06380078, 0x064100A7, 0x06420071, 0x06460078, 0x06470071, 0x06480078, - 0x06490071, 0x06540078, 0x06550071, 0x065D0078, 0x065E0071, 0x065F00B2, 0x066000A7, 0x06620078, - 0x066308A7, 0x06640078, 0x066508A7, 0x06660083, 0x06670078, 0x066A00A7, 0x066B0078, 0x06700071, - 0x06710078, 0x0673017E, 0x0674017F, 0x06750180, 0x06760181, 0x06770182, 0x06780078, 0x068100A7, - 0x06820071, 0x06860078, 0x06870071, 0x06880078, 0x06890071, 0x06940078, 0x06950071, 0x069D0078, - 0x069F00A7, 0x06A00083, 0x06A20078, 0x06A300A7, 0x06A40078, 0x06A508A7, 0x06A60083, 0x06A70078, - 0x06AB00A7, 0x06AC0078, 0x06B00071, 0x06B10078, 0x06B3017E, 0x06B4017F, 0x06B50180, 0x06B60181, - 0x06B70182, 0x06B80078, 0x06C100A7, 0x06C20071, 0x06CB0078, 0x06CD0071, 0x06DF0078, 0x06E00071, - 0x06E30078, 0x06E700A7, 0x06E90083, 0x06EA0078, 0x06EC00A7, 0x06EE08A7, 0x06EF00A7, 0x06F00078, - 0x06F900A7, 0x06FA0078, 0x07000071, 0x07180083, 0x07191071, 0x071A0083, 0x071D0078, 0x071F0008, - 0x07200071, 0x07230083, 0x07270097, 0x0728017E, 0x0729017F, 0x072A0180, 0x072B0181, 0x072C0182, - 0x072D0097, 0x072E0078, 0x07400071, 0x07410078, 0x07430071, 0x07440078, 0x07460071, 0x07470078, - 0x074A0071, 0x07540078, 0x07550071, 0x07580083, 0x07591071, 0x075A0083, 0x075E0071, 0x075F0078, - 0x07600071, 0x07620078, 0x07640083, 0x07670078, 0x0768017E, 0x0769017F, 0x076A0180, 0x076B0181, - 0x076C0182, 0x076D0078, 0x076E1071, 0x076F0078, 0x07800094, 0x07820097, 0x07890094, 0x078C0083, - 0x078D0094, 0x0790017E, 0x0791017F, 0x07920180, 0x07930181, 0x07940182, 0x079500B3, 0x079A0083, - 0x079D00BF, 0x079F00A7, 0x07A00071, 0x07A10871, 0x07A20071, 0x07A60871, 0x07A70071, 0x07AB0871, - 0x07AC0071, 0x07B40871, 0x07B50078, 0x07B80083, 0x07B90883, 0x07BB1083, 0x07BD0083, 0x07BF00A7, - 0x07C00883, 0x07C10083, 0x07C20097, 0x07C30083, 0x07C40071, 0x07C60078, 0x07C80083, 0x07C90883, - 0x07CA0083, 0x07CE0883, 0x07CF0083, 0x07D30883, 0x07D40083, 0x07DC0883, 0x07DD0083, 0x07DE0078, - 0x07DF0094, 0x07E60078, 0x07E70094, 0x07E80097, 0x07E90078, 0x08000071, 0x08150078, 0x08160083, - 0x081800A7, 0x08190078, 0x081B0083, 0x081D0078, 0x0820017E, 0x0821017F, 0x08220180, 0x08230181, - 0x08240182, 0x08250097, 0x08280071, 0x082B00A7, 0x082C0083, 0x082D0078, 0x085000B5, 0x08630078, - 0x08680071, 0x087D0097, 0x087E0078, 0x08800071, 0x08AD0078, 0x08AF0071, 0x08D10078, 0x08D40071, - 0x08FD0078, 0x09000071, 0x09240078, 0x09250071, 0x09270078, 0x09280071, 0x092B0078, 0x092D0071, - 0x092F0078, 0x09300071, 0x09440078, 0x09450071, 0x09470078, 0x09480071, 0x09580078, 0x09590071, - 0x095B0078, 0x095C0071, 0x095F0078, 0x09610071, 0x09630078, 0x09640071, 0x096B0078, 0x096C0071, - 0x09880078, 0x09890071, 0x098B0078, 0x098C0071, 0x09AD0078, 0x09AF0083, 0x09B00097, 0x09B400AD, - 0x09B500AE, 0x09B6012D, 0x09B7012E, 0x09B8012F, 0x09B90185, 0x09BA0186, 0x09BB0187, 0x09BC0188, - 0x09BD0184, 0x09BE0078, 0x09C00071, 0x09C80054, 0x09CD0078, 0x09D00071, 0x09FA0078, 0x0A000071, - 0x0B360097, 0x0B370071, 0x0B3B0078, 0x0B400071, 0x0B4D00B4, 0x0B4E0078, 0x0B500071, 0x0B750097, - 0x0B770189, 0x0B780078, 0x0B800071, 0x0B860078, 0x0B870071, 0x0B890083, 0x0B8A0078, 0x0B900071, - 0x0B990083, 0x0B9A0097, 0x0B9B0078, 0x0BA00071, 0x0BA90083, 0x0BAA0078, 0x0BB00071, 0x0BB60078, - 0x0BB70071, 0x0BB80078, 0x0BB90083, 0x0BBA0078, 0x0BC00071, 0x0BDA00C2, 0x0BDB0083, 0x0BDF00A7, - 0x0BE40083, 0x0BEA0097, 0x0BEB0081, 0x0BEC0097, 0x0BED0008, 0x0BEE0083, 0x0BEF0078, 0x0BF0017E, - 0x0BF1017F, 0x0BF20180, 0x0BF30181, 0x0BF40182, 0x0BF50078, 0x0BF80106, 0x0BF90107, 0x0BFA0108, - 0x0BFB0109, 0x0BFC010A, 0x0BFD0078, 0x0C000006, 0x0C050083, 0x0C070078, 0x0C08017E, 0x0C09017F, - 0x0C0A0180, 0x0C0B0181, 0x0C0C0182, 0x0C0D0078, 0x0C100071, 0x0C210081, 0x0C220071, 0x0C3C0078, - 0x0C400071, 0x0C540083, 0x0C550078, 0x0C800071, 0x0C8E0078, 0x0C900083, 0x0C9100A7, 0x0C930083, - 0x0C9400C8, 0x0C960078, 0x0C9800A7, 0x0C9C0083, 0x0C9E0078, 0x0CA20006, 0x0CA3017E, 0x0CA4017F, - 0x0CA50180, 0x0CA60181, 0x0CA70182, 0x0CA80071, 0x0CB70078, 0x0CB80071, 0x0CBA0078, 0x0CC00071, - 0x0CD50078, 0x0CD800A7, 0x0CE00071, 0x0CE400A7, 0x0CE50078, 0x0CE8017E, 0x0CE9017F, 0x0CEA0180, - 0x0CEB0181, 0x0CEC0182, 0x0CED0078, 0x0CEF0006, 0x0CF00054, 0x0D000071, 0x0D0B0083, 0x0D0C00A7, - 0x0D0E0078, 0x0D0F0097, 0x0D100078, 0x0E800055, 0x0E967881, 0x0E970081, 0x0E987881, 0x0E9D0081, - 0x0E9E7881, 0x0EB17055, 0x0EB50055, 0x0ECD7881, 0x0EE00083, 0x0EE20078, 0x0F000865, 0x0F4B0855, - 0x0F4D098A, 0x0F4E0078, 0x0F500865, 0x0F7D0078, 0x0F8008C9, 0x0F8408CA, 0x0F8808C9, 0x0F8B0078, - 0x0F8C08CA, 0x0F8F0078, 0x0F9008C9, 0x0F9408CA, 0x0F9808C9, 0x0F9C08CA, 0x0FA008C9, 0x0FA30078, - 0x0FA408CA, 0x0FA70078, 0x0FA808C9, 0x0FAC08CA, 0x0FB008C9, 0x0FB408CA, 0x0FB808CB, 0x0FB908CC, - 0x0FBB08CD, 0x0FBC08CE, 0x0FBD08CF, 0x0FBE08D0, 0x0FBF0078, 0x0FC008C9, 0x0FC408D1, 0x0FC808C9, - 0x0FCC08D1, 0x0FD008C9, 0x0FD408D1, 0x0FD808C9, 0x0FD9098B, 0x0FDA0078, 0x0FDB0855, 0x0FDC08CA, - 0x0FDD08D2, 0x0FDE1037, 0x0FE00837, 0x0FE1098B, 0x0FE20078, 0x0FE30855, 0x0FE408D5, 0x0FE60837, - 0x0FE808C9, 0x0FE90855, 0x0FEA0078, 0x0FEB0855, 0x0FEC08CA, 0x0FED08D6, 0x0FEE0837, 0x0FF008C9, - 0x0FF10855, 0x0FF20890, 0x0FF30855, 0x0FF408CA, 0x0FF508D7, 0x0FF60837, 0x0FF80078, 0x0FF9098B, - 0x0FFA0078, 0x0FFB0855, 0x0FFC08D9, 0x0FFD08DA, 0x0FFE0837, 0x0FFF0078, 0x10000805, 0x10011005, - 0x10035805, 0x10041005, 0x10050057, 0x1007018C, 0x10085899, 0x10090099, 0x100B1006, 0x100C018D, - 0x100D00DB, 0x100E018D, 0x100F00DB, 0x10100006, 0x10121006, 0x10130006, 0x1014018E, 0x1015018F, - 0x10160190, 0x10175853, 0x10180007, 0x10191007, 0x101A0006, 0x101B1006, 0x101C0126, 0x101D0006, - 0x101F0038, 0x10200006, 0x10220009, 0x10231006, 0x10250006, 0x102B1006, 0x102C0006, 0x102F1005, - 0x10300057, 0x10320078, 0x10350057, 0x10387855, 0x10390078, 0x103A7910, 0x103B7911, 0x103C7912, - 0x103D780B, 0x103E7809, 0x103F7855, 0x1040705D, 0x1041705B, 0x10427110, 0x10437111, 0x10447112, - 0x1045700B, 0x10467009, 0x10470078, 0x10487081, 0x104A0078, 0x10500008, 0x105B0078, 0x10680083, - 0x106E0095, 0x10700083, 0x10710095, 0x10720083, 0x10760078, 0x10801054, 0x10831077, 0x10841054, - 0x10852877, 0x10872855, 0x10882877, 0x10892855, 0x108A2877, 0x108B0054, 0x108C2877, 0x108F0054, - 0x10901054, 0x10910054, 0x10950991, 0x10962877, 0x10972855, 0x10982877, 0x109A1071, 0x109C2855, - 0x109D1054, 0x109E2855, 0x109F2877, 0x10A00019, 0x10A22877, 0x10A32855, 0x10A50019, 0x10A60078, - 0x10A9305F, 0x10AF3106, 0x10B01192, 0x10B11193, 0x10B21194, 0x10B31195, 0x10B41196, 0x10B51197, - 0x10B61198, 0x10B71199, 0x10B8119A, 0x10B9119B, 0x10BA119C, 0x10BB119D, 0x10BC119E, 0x10BD119F, - 0x10BE11A0, 0x10BF11A1, 0x10C001A2, 0x10C101A3, 0x10C20078, 0x10C80019, 0x10CA0054, 0x10CD0819, - 0x10CE0054, 0x10D10019, 0x10D20054, 0x10E60854, 0x10E70819, 0x10E80054, 0x10FA0019, 0x110000E8, - 0x11020019, 0x110408FB, 0x110500FC, 0x11070019, 0x110800E8, 0x11090059, 0x110A01A4, 0x110B0019, - 0x110D00E8, 0x11110019, 0x111500E8, 0x111610E8, 0x111800E8, 0x111A0019, 0x111C00E8, 0x111E00FE, - 0x111F00E8, 0x112008E8, 0x112101A5, 0x112200E8, 0x112308E8, 0x112500E8, 0x11260019, 0x112900FE, - 0x112B0019, 0x112F00E8, 0x11300019, 0x113200FE, 0x11360819, 0x113708FE, 0x113900FE, 0x113A08FE, - 0x113B00FE, 0x113C08FE, 0x113D00FE, 0x114008FE, 0x114100FE, 0x114208FE, 0x114300FE, 0x114408FE, - 0x114500FE, 0x11460019, 0x114700FD, 0x11490019, 0x115100FE, 0x11520019, 0x115300E8, 0x115401A6, - 0x115608E8, 0x115800FE, 0x115C0019, 0x115F00E8, 0x11600019, 0x116400FD, 0x116601A7, 0x11670019, - 0x116800FE, 0x11690019, 0x116B00FE, 0x117008FE, 0x117200FE, 0x117508FE, 0x11770019, 0x117800FE, - 0x11790102, 0x117A00E8, 0x117B0103, 0x117C00E8, 0x117D0104, 0x117E0105, 0x117F00E8, 0x11800054, - 0x118400FE, 0x11860054, 0x119000E8, 0x11910054, 0x11940809, 0x11950054, 0x119B0094, 0x11BD0054, - 0x11CA0094, 0x11CB0054, 0x11CD0019, 0x11DA00BF, 0x11DB0054, 0x11EE0078, 0x12000054, 0x12130078, - 0x12200054, 0x12250078, 0x123018C4, 0x123118C5, 0x123218C6, 0x123318C7, 0x1234191F, 0x1235191A, - 0x1236191B, 0x1237191C, 0x1238191D, 0x1239191E, 0x123A10C4, 0x123B10C5, 0x123C10C6, 0x123D10C7, - 0x123E111F, 0x123F111A, 0x1240111B, 0x1241111C, 0x1242111D, 0x1243111E, 0x1244105A, 0x124510E3, - 0x124610E4, 0x124710E5, 0x124811A8, 0x124911A9, 0x124A11AA, 0x124B11AB, 0x124C11AC, 0x124D11AD, - 0x124E1094, 0x125B1918, 0x12681919, 0x1275010B, 0x1276010C, 0x1277010D, 0x1278010E, 0x1279010F, - 0x127A0106, 0x127B0107, 0x127C0108, 0x127D0109, 0x127E010A, 0x127F00C3, 0x12800054, 0x12DB0019, - 0x12DC0054, 0x12E00019, 0x12E10054, 0x12FC0019, 0x13000054, 0x13370019, 0x13380054, 0x134E0078, - 0x13500054, 0x13590078, 0x13800054, 0x13820078, 0x13830054, 0x13850078, 0x13860054, 0x13A90078, - 0x13AC0054, 0x13AF0078, 0x13B00054, 0x13B4000A, 0x13BB00C4, 0x13BC00C5, 0x13BD00C6, 0x13BE00C7, - 0x13BF011F, 0x13C000C4, 0x13C100C5, 0x13C200C6, 0x13C300C7, 0x13C4011F, 0x13C500C4, 0x13C600C5, - 0x13C700C6, 0x13C800C7, 0x13C9011F, 0x13CA0078, 0x13CC0054, 0x13DF0078, 0x13E00019, 0x13E100FD, - 0x13E20009, 0x13E30078, 0x13E80019, 0x13E900E8, 0x13EA00FD, 0x13EB0019, 0x13EE00FD, 0x13EF0019, - 0x13F100FE, 0x13F3000A, 0x13F60078, 0x13F80019, 0x14000094, 0x14800019, 0x14C10009, 0x14C601AE, - 0x14C701AF, 0x14C80009, 0x14CC0019, 0x14CD00E8, 0x14D80019, 0x14E000FE, 0x14E100E8, 0x14E200FE, - 0x14E30019, 0x14E400E8, 0x14E50019, 0x14E700FD, 0x14E90019, 0x14EA00FE, 0x14EB0019, 0x14EC000A, - 0x14EE0019, 0x14F000E8, 0x14F30019, 0x14F400E8, 0x14F50019, 0x14FA01B0, 0x14FB00E8, 0x14FC00FE, - 0x14FD0019, 0x14FE000A, 0x14FF0019, 0x150500E8, 0x150E0019, 0x150F00E8, 0x15110019, 0x151400E8, - 0x151500FD, 0x15170019, 0x151A00FE, 0x151B0019, 0x151E00FE, 0x151F0019, 0x152B00E8, 0x152C0019, - 0x153200FE, 0x15330019, 0x153500E8, 0x15380019, 0x153900E8, 0x153A1019, 0x153B0019, 0x153C00FD, - 0x153D00E8, 0x153E00FD, 0x154200E8, 0x154500FD, 0x154600E8, 0x154800FD, 0x154E00E8, 0x155000FD, - 0x155100E8, 0x15520019, 0x155300FE, 0x155700FD, 0x155800E8, 0x155900FD, 0x155A00E8, 0x155D00FD, - 0x156300E8, 0x156600FD, 0x156B0019, 0x157101B1, 0x15730019, 0x157600FE, 0x15770019, 0x157900E8, - 0x157A0019, 0x157B00FD, 0x157D00E8, 0x157F0019, 0x15800054, 0x158A0078, 0x16000096, 0x16170078, - 0x16180098, 0x162F0078, 0x16400065, 0x16720054, 0x16750078, 0x167C0006, 0x167E005F, 0x167F0006, - 0x16800125, 0x16930078, 0x16980071, 0x16B30078, 0x16B77881, 0x16B80078, 0x16C00071, 0x16CB0078, - 0x16D00071, 0x16D30078, 0x16D40071, 0x16D70078, 0x16D80071, 0x16DB0078, 0x16DC0071, 0x16DF0078, - 0x16E00071, 0x16E30078, 0x16E40071, 0x16E70078, 0x16E80071, 0x16EB0078, 0x16EC0071, 0x16EF0078, - 0x17000006, 0x170100E0, 0x17030006, 0x17040126, 0x17050006, 0x170600E0, 0x17070006, 0x170B0099, - 0x170C0078, 0x170E00E0, 0x170F0078, 0x17400054, 0x174F1054, 0x17500054, 0x17791054, 0x177A0078, - 0x17801054, 0x17EB0078, 0x17F80054, 0x17FE0078, 0x18000006, 0x18020081, 0x180301B2, 0x1804000A, - 0x18090054, 0x180A000A, 0x180E00B4, 0x180F00BF, 0x181001B3, 0x181101B4, 0x181201B5, 0x181301B6, - 0x181401B7, 0x18150083, 0x18180081, 0x181B0054, 0x181C11B8, 0x181D0081, 0x181E0006, 0x181F0054, - 0x18200071, 0x18320871, 0x18350071, 0x18380871, 0x183A0071, 0x183B0871, 0x183D0071, 0x183E0871, - 0x183F0071, 0x184B0078, 0x184C0083, 0x184D1037, 0x184E0081, 0x184F8071, 0x18500071, 0x18620871, - 0x18650071, 0x18680871, 0x186A0071, 0x186B0871, 0x186D0071, 0x186E0871, 0x186F0071, 0x187B0871, - 0x187D0006, 0x187E0081, 0x187F8071, 0x18800078, 0x18820071, 0x18960078, 0x18981071, 0x18C70078, - 0x18C80094, 0x18C978B6, 0x18CA78B7, 0x18CB7894, 0x18D00071, 0x18DC0078, 0x18E00054, 0x18E80078, - 0x18F80071, 0x19001094, 0x190E1054, 0x190F0078, 0x191010B6, 0x191110B7, 0x191210B8, 0x191310B9, - 0x191410B0, 0x19151094, 0x19220078, 0x192819B9, 0x192919BA, 0x192A19BB, 0x192B19BC, 0x192C19BD, - 0x192D19BE, 0x192E19BF, 0x192F19C0, 0x19301894, 0x193E1854, 0x193F0094, 0x194018B6, 0x194118B7, - 0x194218B8, 0x194318B9, 0x194418B0, 0x19451894, 0x195819C1, 0x195919C2, 0x195A19C3, 0x195B19C4, - 0x195C19C5, 0x195D19C6, 0x195E19C7, 0x195F19C8, 0x19601094, 0x19666854, 0x19681894, 0x197F0078, - 0x19806894, 0x19AC1094, 0x19B86894, 0x19BB6854, 0x19BD6894, 0x19EF6854, 0x19F01094, 0x19FF6854, - 0x1A000071, 0x26DB0078, 0x26E00054, 0x27000071, 0x4FDE0078, 0x50000071, 0x500A0081, 0x500B0071, - 0x52460078, 0x52480054, 0x52630078, 0x53800037, 0x538B0078, 0x54000071, 0x54050083, 0x54060071, - 0x541100A7, 0x54120083, 0x541300A7, 0x54140054, 0x54160078, 0x56000071, 0x6BD20078, 0x6C00013E, - 0x7000013F, 0x7C800871, 0x7D070071, 0x7D0A0871, 0x7D0F0071, 0x7D120871, 0x7D130071, 0x7D150871, - 0x7D170078, 0x7D180871, 0x7D350078, 0x7D380871, 0x7D6D0078, 0x7D801055, 0x7D830078, 0x7D891055, - 0x7D8C0078, 0x7D8E089B, 0x7D90289B, 0x7D94280B, 0x7D95089B, 0x7D9B0078, 0x7D9C089B, 0x7D9E0078, - 0x7DA0089B, 0x7DA20078, 0x7DA3089B, 0x7DA7109B, 0x7DA8209E, 0x7DAA489E, 0x7DAB209E, 0x7DAC489E, - 0x7DAD209E, 0x7DAE489E, 0x7DAF209E, 0x7DB0489E, 0x7DB1209E, 0x7DB2489E, 0x7DB3209E, 0x7DB4489E, - 0x7DB5209E, 0x7DB6489E, 0x7DB7209E, 0x7DB8489E, 0x7DB9209E, 0x7DBA489E, 0x7DBB209E, 0x7DBC489E, - 0x7DBD209E, 0x7DBE489E, 0x7DBF209E, 0x7DC0489E, 0x7DC1209E, 0x7DC8489E, 0x7DC9209E, 0x7DCA489E, - 0x7DCB209E, 0x7DCC489E, 0x7DCD209E, 0x7DCE489E, 0x7DCF209E, 0x7DD1489E, 0x7DD2209E, 0x7DD4489E, - 0x7DD5209E, 0x7DD6489E, 0x7DD7209E, 0x7DD90078, 0x7DE9409E, 0x7DEA389E, 0x7DEB409E, 0x7DEF209E, - 0x7DF3489E, 0x7DF5209E, 0x7DFC409E, 0x7DFD389E, 0x7DFE209E, 0x7DFF489E, 0x7E00409E, 0x7E32209E, - 0x7E4B389E, 0x7E6F489E, 0x7E7A409E, 0x7E88209E, 0x7E96389E, 0x7E9A489E, 0x7E9E409E, 0x7E9F00BF, - 0x7EA00078, 0x7EA8209E, 0x7EA9389E, 0x7EAD209E, 0x7EAE389E, 0x7EAF209E, 0x7EB0389E, 0x7EB3209E, - 0x7EB5389E, 0x7EB7209E, 0x7EB9389E, 0x7EBA209E, 0x7EBB389E, 0x7EBC209E, 0x7EBE389E, 0x7EBF209E, - 0x7EC1389E, 0x7EC2209E, 0x7EC4389E, 0x7EC5209E, 0x7EC6389E, 0x7EC80078, 0x7EC9389E, 0x7ECB209E, - 0x7ECE389E, 0x7ECF209E, 0x7EDA389E, 0x7EDB209E, 0x7EE1389E, 0x7EE3209E, 0x7EE40078, 0x7EF8409E, - 0x7EFE0054, 0x7EFF0078, 0x7F000083, 0x7F088006, 0x7F0B80B4, 0x7F0C8006, 0x7F0D0078, 0x7F100083, - 0x7F120078, 0x7F188099, 0x7F198038, 0x7F1A80B4, 0x7F220006, 0x7F2380B4, 0x7F241006, 0x7F261038, - 0x7F286006, 0x7F290078, 0x7F2A600C, 0x7F2B6006, 0x7F2C60B4, 0x7F2F6007, 0x7F306006, 0x7F31600D, - 0x7F326019, 0x7F330078, 0x7F346008, 0x7F356006, 0x7F360078, 0x7F38489E, 0x7F39009E, 0x7F3A0078, - 0x7F3B489E, 0x7F40409E, 0x7F45389E, 0x7F46409E, 0x7F48389E, 0x7F49409E, 0x7F4B389E, 0x7F4C409E, - 0x7F4D389E, 0x7F4E409E, 0x7F4F389E, 0x7F50409E, 0x7F51389E, 0x7F52409E, 0x7F53389E, 0x7F54409E, - 0x7F59389E, 0x7F5A409E, 0x7F5B389E, 0x7F5C409E, 0x7F5D389E, 0x7F5E409E, 0x7F5F389E, 0x7F60409E, - 0x7F61389E, 0x7F62409E, 0x7F63389E, 0x7F64409E, 0x7F65389E, 0x7F66409E, 0x7F67389E, 0x7F68409E, - 0x7F69389E, 0x7F6A409E, 0x7F6B389E, 0x7F6C409E, 0x7F6D389E, 0x7F6E409E, 0x7F6F389E, 0x7F70409E, - 0x7F71389E, 0x7F72409E, 0x7F73389E, 0x7F74409E, 0x7F75389E, 0x7F76409E, 0x7F79389E, 0x7F7A409E, - 0x7F7E0078, 0x7F7F0057, 0x7F808806, 0x7F818807, 0x7F838806, 0x7F84880A, 0x7F85880B, 0x7F86880D, - 0x7F87880C, 0x7F88880F, 0x7F898811, 0x7F8A8813, 0x7F8B8815, 0x7F8C8817, 0x7F8D8806, 0x7F8E8819, - 0x7F8F8806, 0x7F908860, 0x7F9D8835, 0x7F9E8836, 0x7F9F8838, 0x7FA08861, 0x7FAD8835, 0x7FAE8836, - 0x7FAF8809, 0x7FB05006, 0x7FB1500A, 0x7FB25006, 0x7FB35071, 0x7FCF5081, 0x7FD05071, 0x7FDF0078, - 0x7FE15071, 0x7FE40078, 0x7FE55071, 0x7FE80078, 0x7FE95071, 0x7FEC0078, 0x7FED5071, 0x7FEE0078, - 0x7FF08808, 0x7FF18837, 0x7FF28808, 0x7FF30078, 0x7FF45019, 0x7FF65054, 0x7FF70078, 0x7FFC0141, - 0x7FFE0054, 0x7FFF0078, 0x80000071, 0x80130078, 0x80140071, 0x801D0078, 0x801E0071, 0x80270078, - 0x80280071, 0x802F0078, 0x80400071, 0x807D0078, 0x80800006, 0x80810078, 0x808300AD, 0x808400AE, - 0x8085012D, 0x8086012E, 0x8087012F, 0x80880185, 0x80890186, 0x808A0187, 0x808B0188, 0x808C0184, - 0x808D01C9, 0x808E01CA, 0x808F01CB, 0x809001CC, 0x809101CD, 0x809201CE, 0x809301CF, 0x809401D0, - 0x809500BE, 0x809601D1, 0x809701D2, 0x809801D3, 0x809901D4, 0x809A0078, 0x809B0094, 0x80A0014E, - 0x80A10152, 0x80A20153, 0x80A30157, 0x80A40154, 0x80A50155, 0x80A60156, 0x80A70152, 0x80A80150, - 0x80A90153, 0x80AA01D5, 0x80AB0154, 0x80AC014F, 0x80AD0158, 0x80AF0152, 0x80B00154, 0x80B201D6, - 0x80B30150, 0x80B501D7, 0x80B60153, 0x80B80156, 0x80B90152, 0x80BA005F, 0x80BC0054, 0x80C50078, - 0x81800071, 0x818F0078, 0x8190012D, 0x819100BB, 0x81920078, 0x81980071, 0x81A50078, 0x81C00071, - 0x81CF0097, 0x81D00071, 0x81E20078, 0x81E40071, 0x81E8014F, 0x81E90154, 0x81EA0155, 0x81EB0078, - 0x8200015B, 0x8214015C, 0x82280071, 0x824F0078, 0x8250017E, 0x8251017F, 0x82520180, 0x82530181, - 0x82540182, 0x82550078, 0x8400009B, 0x84030078, 0x8405009B, 0x841C0078, 0x841F009B, 0x84200078, - 0x85000083, 0x85030078, 0x85060083, 0x8508009B, 0x851A0078, 0x851C0083, 0x851D0078, 0x851F0083, - 0x852001D8, 0x852101D9, 0x852201DA, 0x852301DB, 0x85240078, 0x8528009A, 0x852C0078, 0xE8000094, - 0xE87B0078, 0xE8800094, 0xE8930078, 0xE8950094, 0xE8AF0894, 0xE8B200A7, 0xE8B30083, 0xE8B50094, - 0xE8B600A7, 0xE8B90057, 0xE8BD0083, 0xE8C10094, 0xE8C20083, 0xE8C60094, 0xE8D50083, 0xE8D70094, - 0xE8DD0894, 0xE8E00094, 0xE8EF0078, 0xE9000054, 0xE9210083, 0xE9220054, 0xE9230078, 0xE9800054, - 0xE9AB0078, 0xEA002877, 0xEA0D2855, 0xEA1A2877, 0xEA272855, 0xEA2A0078, 0xEA2B2855, 0xEA342877, - 0xEA412855, 0xEA4E0078, 0xEA4F2877, 0xEA500078, 0xEA522877, 0xEA530078, 0xEA542877, 0xEA560078, - 0xEA572877, 0xEA5B2855, 0xEA682877, 0xEA752855, 0xEA822877, 0xEA850078, 0xEA862877, 0xEA8A0078, - 0xEA8B2877, 0xEA8E0078, 0xEA8F2855, 0xEA9C2877, 0xEA9F0078, 0xEAA02877, 0xEAA20078, 0xEAA52877, - 0xEAA80078, 0xEAA92855, 0xEAB62877, 0xEAC32855, 0xEAD02877, 0xEADD2855, 0xEAEA2877, 0xEAF72855, - 0xEB042877, 0xEB112855, 0xEB1E2877, 0xEB2B2855, 0xEB382877, 0xEB452855, 0xEB530078, 0xEB542877, - 0xEB6029DC, 0xEB612855, 0xEB6D29DC, 0xEB6E2855, 0xEB712877, 0xEB7D29DC, 0xEB7E2855, 0xEB8A29DC, - 0xEB8B2855, 0xEB8E2877, 0xEB9A29DC, 0xEB9B2855, 0xEBA729DC, 0xEBA82855, 0xEBAB2877, 0xEBB729DC, - 0xEBB82855, 0xEBC429DC, 0xEBC52855, 0xEBC82877, 0xEBD429DC, 0xEBD52855, 0xEBE129DC, 0xEBE22855, - 0xEBE50078, 0xEBE7280F, 0xEBE82811, 0xEBE92813, 0xEBEA2815, 0xEBEB2817, 0xEBEC280F, 0xEBED2811, - 0xEBEE2813, 0xEBEF2815, 0xEBF02817, 0xEBF1280F, 0xEBF22811, 0xEBF32813, 0xEBF42815, 0xEBF52817, - 0xEBF6280F, 0xEBF72811, 0xEBF82813, 0xEBF92815, 0xEBFA2817, 0xEBFB280F, 0xEBFC2811, 0xEBFD2813, - 0xEBFE2815, 0xEBFF2817, 0xEC000078 - }; - - static const uint32_t a17[] = { - 0x00000071, 0x536B0078, 0x7C000871, 0x7D0F0078 - }; - - static const uint32_t a23[] = { - 0x00000057, 0x00010078, 0x00100057, 0x00400078, 0x00800083, 0x00F80078, 0x8000013F, 0xFFFF0078 - }; - - static const uint32_t a24[] = { - 0x0000013F, 0x7FFF0078 - }; - - - // The full set of all arrays to be searched. - static const Range FULL_DATA[] = { - {sizeof(a0)/sizeof(uint32_t), a0}, - {sizeof(a1)/sizeof(uint32_t), a1}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {sizeof(a7)/sizeof(uint32_t), a7}, - {sizeof(a8)/sizeof(uint32_t), a8}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {sizeof(a16)/sizeof(uint32_t), a16}, - {sizeof(a17)/sizeof(uint32_t), a17}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {sizeof(a23)/sizeof(uint32_t), a23}, - {sizeof(a24)/sizeof(uint32_t), a24}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0}, - {0, 0} - }; - - // Array of uppercase differences - static const short UCDIFF[] = { - 0, -32, 743, 121, -1, -232, -300, 97, - 163, 130, 56, -2, -79, -210, -206, -205, - -202, -203, -207, -209, -211, -213, -214, -218, - -217, -219, -83, 84, -38, -37, -31, -64, - -63, -62, -57, -47, -54, -86, -80, 7, - -96, -48, -59, 8, 74, 86, 100, 128, - 112, 126, 9, -7205, -16, -26, -7264, -40 - }; - - // Array of lowercase differences - static const short LCDIFF[] = { - 0, 32, 1, -199, -121, 210, 206, 205, - 79, 202, 203, 207, 211, 209, 213, 214, - 218, 217, 219, 2, -97, -56, -130, -163, - 83, 38, 37, 64, 63, -60, -7, 80, - 48, 7264, -8, -74, -9, -86, -100, -112, - -128, -126, -7517, -8383, -8262, 16, 26, 40 - }; - - // Array of titlecase differences - static const short TCDIFF[] = { - 3, 1, 0, -1 - }; - - // Array of mirrored character differences - static const short MIRROR_DIFF[] = { - 0, 1, -1, 2, -2, 16, -16, 3, - -3, 2016, 138, 1824, 2104, 2108, 2106, -138, - 8, 7, -8, -7, -1824, -2016, -2104, -2106, - -2108 - }; - - // Array of all possible numeric values - static const int NUMERICS[] = { - -1, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 35, -2, 100, 1000, - 40, 50, 60, 70, 80, 90, 10000, 500, - 5000, 36, 37, 38, 39, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 200, 300, - 400, 600, 700, 800, 900, 2000, 3000, 4000, - 6000, 7000, 8000, 9000, 20000, 30000, 40000, 50000, - 60000, 70000, 80000, 90000 - }; - - // All possible packed data values, no duplicates - static const uint32_t PACKED_DATA[] = { - 0x00000000, 0x0000012F, 0x0000016F, 0x0000014F, 0x0000018F, 0x0000018C, 0x000001B8, 0x000000B8, - 0x000000BA, 0x020005B5, 0x040005B6, 0x00000099, 0x000000F8, 0x00000094, 0x02000069, 0x04000069, - 0x06000069, 0x08000069, 0x0A000069, 0x0C000069, 0x0E000069, 0x10000069, 0x12000069, 0x14000069, - 0x060005B9, 0x000001B9, 0x080005B9, 0x16020001, 0x18020001, 0x1A020001, 0x1C020001, 0x1E020001, - 0x20020001, 0x22020001, 0x24020001, 0x26020001, 0x28020001, 0x2A020001, 0x2C020001, 0x2E020001, - 0x30020001, 0x32020001, 0x34020001, 0x36020001, 0x38020001, 0x3A020001, 0x3C020001, 0x3E020001, - 0x40020001, 0x42020001, 0x44020001, 0x46020001, 0x48020001, 0x060005B5, 0x080005B6, 0x000001BB, - 0x000001B7, 0x16000802, 0x18000802, 0x1A000802, 0x1C000802, 0x1E000802, 0x20000802, 0x22000802, - 0x24000802, 0x26000802, 0x28000802, 0x2A000802, 0x2C000802, 0x2E000802, 0x30000802, 0x32000802, - 0x34000802, 0x36000802, 0x38000802, 0x3A000802, 0x3C000802, 0x3E000802, 0x40000802, 0x42000802, - 0x44000802, 0x46000802, 0x48000802, 0x000000EC, 0x000001BC, 0x00000002, 0x0A0005BD, 0x00000130, - 0x000000BC, 0x000000B9, 0x0600006B, 0x0800006B, 0x00001002, 0x0400006B, 0x0C0005BE, 0x4A0001AB, - 0x00020001, 0x00000802, 0x00001802, 0x00040001, 0x00060001, 0x00002002, 0x00080001, 0x000C0001, - 0x000E0001, 0x00100001, 0x00140001, 0x00160001, 0x00180001, 0x00004002, 0x00004802, 0x00200001, - 0x00220001, 0x00000005, 0x00A60001, 0x01805802, 0x01042003, 0x00280001, 0x002C0001, 0x00000001, - 0x00000000, 0x00007002, 0x00007802, 0x00009802, 0x0000A802, 0x0000B802, 0x0000C002, 0x0000C802, - 0x0000D002, 0x00000004, 0x000001A4, 0x00000106, 0x00320001, 0x00340001, 0x00360001, 0x00380001, - 0x0000E002, 0x0000E802, 0x0000F002, 0x0000F802, 0x00010002, 0x00010802, 0x00012002, 0x00012802, - 0x00013802, 0x003A0001, 0x003E0001, 0x00013002, 0x0000001C, 0x00000107, 0x00400001, 0x00000018, - 0x00014802, 0x000001B4, 0x00000038, 0x00000025, 0x00000050, 0x00000058, 0x00000045, 0x00000044, - 0x020000C9, 0x060000C9, 0x0A0000C9, 0x0E0000C9, 0x120000C9, 0x000000D8, 0x0000005C, 0x00000008, - 0x02000009, 0x06000009, 0x0A000009, 0x0E000009, 0x12000009, 0x0400000B, 0x0800000B, 0x0000000B, - 0x1600000B, 0x4E00000B, 0x00000006, 0x4A00000B, 0x000001B5, 0x00420001, 0x0600000B, 0x0A00000B, - 0x0E00000B, 0x1200000B, 0x3E00000B, 0x5200000B, 0x5600000B, 0x5A00000B, 0x5C00000B, 0x000001B6, - 0x2400000A, 0x2800000A, 0x00000010, 0x020001AB, 0x060001AB, 0x0A0001AB, 0x0E0001AB, 0x120001AB, - 0x00000108, 0x00015802, 0x00440001, 0x00016002, 0x00016802, 0x00017002, 0x00017802, 0x00018002, - 0x00018802, 0x00440003, 0x00460001, 0x00480003, 0x00019802, 0x004A0001, 0x004C0001, 0x004E0001, - 0x003C0001, 0x00500001, 0x00520001, 0x000001BD, 0x0000018D, 0x000001D0, 0x00000250, 0x00000230, - 0x040005BE, 0x000000F9, 0x0200006B, 0x0A00006B, 0x0E00006B, 0x1200006B, 0x00540001, 0x00560001, - 0x000005B9, 0x045A000A, 0x085A000A, 0x0C5A000A, 0x105A000A, 0x145A000A, 0x185A000A, 0x525A000A, - 0x5E5A000A, 0x0401A00A, 0x0801A00A, 0x0C01A00A, 0x1001A00A, 0x1401A00A, 0x1801A00A, 0x5201A00A, - 0x5E01A00A, 0x4E00000A, 0x5C00000A, 0x0E0005B9, 0x100005B9, 0x020005B9, 0x040005B9, 0x160005B9, - 0x180005B9, 0x1A0005B9, 0x200005B9, 0x220005B9, 0x240005B9, 0x260005B9, 0x040001AB, 0x080001AB, - 0x0C0001AB, 0x100001AB, 0x140001AB, 0x180001AB, 0x1C0001AB, 0x200001AB, 0x240001AB, 0x280001AB, - 0x0C00006B, 0x1000006B, 0x1400006B, 0x1800006B, 0x1C00006B, 0x2000006B, 0x2400006B, 0x2800006B, - 0x005C001C, 0x0001A81C, 0x1A0001AB, 0x1E0001AB, 0x220001AB, 0x260001AB, 0x2A0001AB, 0x160001AB, - 0x020005B6, 0x100005B6, 0x280005B9, 0x2C0005B9, 0x300005B9, 0x0001B002, 0x020005BD, 0x0600000A, - 0x0A00000A, 0x0E00000A, 0x1200000A, 0x1600000A, 0x3E00000A, 0x0C00000B, 0x1000000B, 0x1400000B, - 0x2E0001AB, 0x320001AB, 0x360001AB, 0x3A0001AB, 0x3E0001AB, 0x420001AB, 0x460001AB, 0x640001AB, - 0x680001AB, 0x6A0001AB, 0x6E0001AB, 0x720001AB, 0x760001AB, 0x7A0001AB, 0x00000013, 0x00000012, - 0x0000005A, 0x000001B0, 0x7C00000B, 0x8000000B, 0x8200000B, 0x8600000B, 0x8C00000B, 0x6000000B, - 0x9200000B, 0x9600000B, 0x9800000B, 0x9C00000B, 0xA000000B, 0xA400000B, 0x4A0001AA, 0x040001AA, - 0x520001AA, 0x600001AA, 0x0C0001AA, 0x5E0001AA, 0x160001AA, 0x4C0001AA, 0x4E0001AA, 0x9E0001AA, - 0x060001AA, 0x8800000A, 0x2A0001AA, 0x005E0001, 0x0001B802, 0x0400002B, 0x0800002B, 0x1600002B, - 0x4C00002B, 0x00002802, 0x00003002, 0x000A0001, 0x00120001, 0x00003802, 0x001A0001, 0x001C0001, - 0x001E0001, 0x00240001, 0x00005002, 0x00006002, 0x002A0001, 0x002E0001, 0x00300001, 0x00006802, - 0x00008002, 0x00008802, 0x00009002, 0x0000A002, 0x0000B002, 0x0000D906, 0x00011002, 0x00011802, - 0x00014002, 0x040000C9, 0x080000C9, 0x0C0000C9, 0x100000C9, 0x140000C9, 0x04000009, 0x08000009, - 0x0C000009, 0x10000009, 0x14000009, 0x2200000B, 0x4C00000B, 0x2A00000B, 0x5000000B, 0x5400000B, - 0x5800000B, 0x2600000A, 0x00015002, 0x00019002, 0x00000030, 0x000001BE, 0x0000014E, 0x00000210, - 0x000001F0, 0x00580001, 0x065A000A, 0x0A5A000A, 0x0E5A000A, 0x125A000A, 0x165A000A, 0x1A5A000A, - 0x4C5A000A, 0x4E5A000A, 0x0601A00A, 0x0A01A00A, 0x0E01A00A, 0x1201A00A, 0x1601A00A, 0x1A01A00A, - 0x4C01A00A, 0x4E01A00A, 0x6000000A, 0x0000000A, 0x120005B9, 0x140005B9, 0x1C0005B9, 0x1E0005B9, - 0x1600006B, 0x1A00006B, 0x1E00006B, 0x2200006B, 0x2600006B, 0x2A00006B, 0x0E0005B5, 0x040005B5, - 0x2A0005B9, 0x2E0005B9, 0x0200000A, 0x0400000A, 0x0800000A, 0x0C00000A, 0x1000000A, 0x1400000A, - 0x2A00000A, 0x2C0001AB, 0x300001AB, 0x340001AB, 0x380001AB, 0x3C0001AB, 0x400001AB, 0x440001AB, - 0x480001AB, 0x620001AB, 0x660001AB, 0x500001AB, 0x6C0001AB, 0x700001AB, 0x740001AB, 0x780001AB, - 0x520001AB, 0x7E00000B, 0x5E00000B, 0x8400000B, 0x8800000B, 0x8A00000B, 0x8E00000B, 0x9000000B, - 0x9400000B, 0x9A00000B, 0x9E00000B, 0xA200000B, 0xA600000B, 0x5C0001AA, 0x3E0001AA, 0x7E0001AA, - 0x0600002B, 0x0A00002B, 0x2A00002B, 0x4E00002B, 0x00000019 - }; -} diff --git a/libs/utils/executablepath_darwin.cpp b/libs/utils/executablepath_darwin.cpp deleted file mode 100644 index 2e3c3a0..0000000 --- a/libs/utils/executablepath_darwin.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <utils/executablepath.h> -#import <Carbon/Carbon.h> -#include <unistd.h> - -void executablepath(char s[PATH_MAX]) -{ - ProcessSerialNumber psn; - GetCurrentProcess(&psn); - CFDictionaryRef dict; - dict = ProcessInformationCopyDictionary(&psn, 0xffffffff); - CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict, - CFSTR("CFBundleExecutable")); - CFStringGetCString(value, s, PATH_MAX+1, kCFStringEncodingUTF8); -} - diff --git a/libs/utils/executablepath_linux.cpp b/libs/utils/executablepath_linux.cpp deleted file mode 100644 index b8d2a3d..0000000 --- a/libs/utils/executablepath_linux.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <utils/executablepath.h> -#include <sys/types.h> -#include <unistd.h> -#include <limits.h> -#include <stdio.h> - -void executablepath(char exe[PATH_MAX]) -{ - char proc[100]; - sprintf(proc, "/proc/%d/exe", getpid()); - - int err = readlink(proc, exe, PATH_MAX); -} - diff --git a/libs/utils/futex_synchro.c b/libs/utils/futex_synchro.c deleted file mode 100644 index ba19520..0000000 --- a/libs/utils/futex_synchro.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdio.h> -#include <limits.h> - -#include <sys/time.h> -#include <sched.h> - -#include <errno.h> - -#include <private/utils/futex_synchro.h> - - -// This futex glue code is need on desktop linux, but is already part of bionic. -#if !defined(HAVE_FUTEX_WRAPPERS) - -#include <sys/syscall.h> -typedef unsigned int u32; -#define asmlinkage -#define __user -#include <linux/futex.h> -#include <utils/Atomic.h> - - -int futex (int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3) -{ - int err = syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3); - return err == 0 ? 0 : -errno; -} - -int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout) -{ - return futex((int*)ftx, FUTEX_WAIT, val, timeout, NULL, 0); -} - -int __futex_wake(volatile void *ftx, int count) -{ - return futex((int*)ftx, FUTEX_WAKE, count, NULL, NULL, 0); -} - -int __atomic_cmpxchg(int old, int _new, volatile int *ptr) -{ - return android_atomic_cmpxchg(old, _new, ptr); -} - -int __atomic_swap(int _new, volatile int *ptr) -{ - return android_atomic_swap(_new, ptr); -} - -int __atomic_dec(volatile int *ptr) -{ - return android_atomic_dec(ptr); -} - -#else // !defined(__arm__) - -int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout); -int __futex_wake(volatile void *ftx, int count); - -int __atomic_cmpxchg(int old, int _new, volatile int *ptr); -int __atomic_swap(int _new, volatile int *ptr); -int __atomic_dec(volatile int *ptr); - -#endif // !defined(HAVE_FUTEX_WRAPPERS) - - -// lock states -// -// 0: unlocked -// 1: locked, no waiters -// 2: locked, maybe waiters - -void futex_mutex_init(futex_mutex_t *m) -{ - m->value = 0; -} - -int futex_mutex_lock(futex_mutex_t *m, unsigned msec) -{ - if(__atomic_cmpxchg(0, 1, &m->value) == 0) { - return 0; - } - if(msec == FUTEX_WAIT_INFINITE) { - while(__atomic_swap(2, &m->value) != 0) { - __futex_wait(&m->value, 2, 0); - } - } else { - struct timespec ts; - ts.tv_sec = msec / 1000; - ts.tv_nsec = (msec % 1000) * 1000000; - while(__atomic_swap(2, &m->value) != 0) { - if(__futex_wait(&m->value, 2, &ts) == -ETIMEDOUT) { - return -1; - } - } - } - return 0; -} - -int futex_mutex_trylock(futex_mutex_t *m) -{ - if(__atomic_cmpxchg(0, 1, &m->value) == 0) { - return 0; - } - return -1; -} - -void futex_mutex_unlock(futex_mutex_t *m) -{ - if(__atomic_dec(&m->value) != 1) { - m->value = 0; - __futex_wake(&m->value, 1); - } -} - -/* XXX *technically* there is a race condition that could allow - * XXX a signal to be missed. If thread A is preempted in _wait() - * XXX after unlocking the mutex and before waiting, and if other - * XXX threads call signal or broadcast UINT_MAX times (exactly), - * XXX before thread A is scheduled again and calls futex_wait(), - * XXX then the signal will be lost. - */ - -void futex_cond_init(futex_cond_t *c) -{ - c->value = 0; -} - -int futex_cond_wait(futex_cond_t *c, futex_mutex_t *m, unsigned msec) -{ - if(msec == FUTEX_WAIT_INFINITE){ - int oldvalue = c->value; - futex_mutex_unlock(m); - __futex_wait(&c->value, oldvalue, 0); - futex_mutex_lock(m, FUTEX_WAIT_INFINITE); - return 0; - } else { - int oldvalue = c->value; - struct timespec ts; - ts.tv_sec = msec / 1000; - ts.tv_nsec = (msec % 1000) * 1000000; - futex_mutex_unlock(m); - const int err = __futex_wait(&c->value, oldvalue, &ts); - futex_mutex_lock(m, FUTEX_WAIT_INFINITE); - return err; - } -} - -void futex_cond_signal(futex_cond_t *c) -{ - __atomic_dec(&c->value); - __futex_wake(&c->value, 1); -} - -void futex_cond_broadcast(futex_cond_t *c) -{ - __atomic_dec(&c->value); - __futex_wake(&c->value, INT_MAX); -} - diff --git a/libs/utils/misc.cpp b/libs/utils/misc.cpp deleted file mode 100644 index dc89d15..0000000 --- a/libs/utils/misc.cpp +++ /dev/null @@ -1,185 +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. - */ - -// -// Miscellaneous utility functions. -// -#include <utils/misc.h> - -#include <sys/stat.h> -#include <string.h> -#include <errno.h> -#include <assert.h> -#include <stdio.h> - -using namespace android; - -namespace android { - -/* - * Like strdup(), but uses C++ "new" operator instead of malloc. - */ -char* strdupNew(const char* str) -{ - char* newStr; - int len; - - if (str == NULL) - return NULL; - - len = strlen(str); - newStr = new char[len+1]; - memcpy(newStr, str, len+1); - - return newStr; -} - -/* - * Concatenate an argument vector. - */ -char* concatArgv(int argc, const char* const argv[]) -{ - char* newStr = NULL; - int len, totalLen, posn, idx; - - /* - * First, figure out the total length. - */ - totalLen = idx = 0; - while (1) { - if (idx == argc || argv[idx] == NULL) - break; - if (idx) - totalLen++; // leave a space between args - totalLen += strlen(argv[idx]); - idx++; - } - - /* - * Alloc the string. - */ - newStr = new char[totalLen +1]; - if (newStr == NULL) - return NULL; - - /* - * Finally, allocate the string and copy data over. - */ - idx = posn = 0; - while (1) { - if (idx == argc || argv[idx] == NULL) - break; - if (idx) - newStr[posn++] = ' '; - - len = strlen(argv[idx]); - memcpy(&newStr[posn], argv[idx], len); - posn += len; - - idx++; - } - - assert(posn == totalLen); - newStr[posn] = '\0'; - - return newStr; -} - -/* - * Count the #of args in an argument vector. Don't count the final NULL. - */ -int countArgv(const char* const argv[]) -{ - int count = 0; - - while (argv[count] != NULL) - count++; - - return count; -} - - -#include <stdio.h> -/* - * 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; -} - -/* - * Round up to the next highest power of 2. - * - * Found on http://graphics.stanford.edu/~seander/bithacks.html. - */ -unsigned int roundUpPower2(unsigned int val) -{ - val--; - val |= val >> 1; - val |= val >> 2; - val |= val >> 4; - val |= val >> 8; - val |= val >> 16; - val++; - - return val; -} - -}; // namespace android - diff --git a/libs/utils/ported.cpp b/libs/utils/ported.cpp deleted file mode 100644 index 656e46f..0000000 --- a/libs/utils/ported.cpp +++ /dev/null @@ -1,106 +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. - */ - -// -// Ports of standard functions that don't exist on a specific platform. -// -// Note these are NOT in the "android" namespace. -// -#include <utils/ported.h> - -#if defined(NEED_GETTIMEOFDAY) || defined(NEED_USLEEP) -# include <sys/time.h> -# include <windows.h> -#endif - - -#if defined(NEED_GETTIMEOFDAY) -/* - * Replacement gettimeofday() for Windows environments (primarily MinGW). - * - * Ignores "tz". - */ -int gettimeofday(struct timeval* ptv, struct timezone* tz) -{ - long long nsTime; // time in 100ns units since Jan 1 1601 - FILETIME ft; - - if (tz != NULL) { - // oh well - } - - ::GetSystemTimeAsFileTime(&ft); - nsTime = (long long) ft.dwHighDateTime << 32 | - (long long) ft.dwLowDateTime; - // convert to time in usec since Jan 1 1970 - ptv->tv_usec = (long) ((nsTime / 10LL) % 1000000LL); - ptv->tv_sec = (long) ((nsTime - 116444736000000000LL) / 10000000LL); - - return 0; -} -#endif - -#if defined(NEED_USLEEP) -// -// Replacement usleep for Windows environments (primarily MinGW). -// -void usleep(unsigned long usec) -{ - // Win32 API function Sleep() takes milliseconds - ::Sleep((usec + 500) / 1000); -} -#endif - -#if 0 //defined(NEED_PIPE) -// -// Replacement pipe() command for MinGW -// -// The _O_NOINHERIT flag sets bInheritHandle to FALSE in the -// SecurityAttributes argument to CreatePipe(). This means the handles -// aren't inherited when a new process is created. The examples I've seen -// use it, possibly because there's a lot of junk going on behind the -// scenes. (I'm assuming "process" and "thread" are different here, so -// we should be okay spinning up a thread.) The recommended practice is -// to dup() the descriptor you want the child to have. -// -// It appears that unnamed pipes can't do non-blocking ("overlapped") I/O. -// You can't use select() either, since that only works on sockets. The -// Windows API calls that are useful here all operate on a HANDLE, not -// an integer file descriptor, and I don't think you can get there from -// here. The "named pipe" stuff is insane. -// -int pipe(int filedes[2]) -{ - return _pipe(filedes, 0, _O_BINARY | _O_NOINHERIT); -} -#endif - -#if defined(NEED_SETENV) -/* - * MinGW lacks these. For now, just stub them out so the code compiles. - */ -int setenv(const char* name, const char* value, int overwrite) -{ - return 0; -} -void unsetenv(const char* name) -{ -} -char* getenv(const char* name) -{ - return NULL; -} -#endif |