More assetmanager work. Bakc to compile success state
diff --git a/annotations/build.gradle b/annotations/build.gradle
index 79c61f4..20ba4f5 100644
--- a/annotations/build.gradle
+++ b/annotations/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
new RoboJavaModulePlugin(
diff --git a/integration-tests/dependency-on-stubs/build.gradle b/integration-tests/dependency-on-stubs/build.gradle
index acfd6a7..0ac99bc 100644
--- a/integration-tests/dependency-on-stubs/build.gradle
+++ b/integration-tests/dependency-on-stubs/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
apply plugin: RoboJavaModulePlugin
diff --git a/integration-tests/libphonenumber/build.gradle b/integration-tests/libphonenumber/build.gradle
index 3a0dcb7..2511086 100644
--- a/integration-tests/libphonenumber/build.gradle
+++ b/integration-tests/libphonenumber/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
apply plugin: RoboJavaModulePlugin
diff --git a/integration-tests/mockito-experimental/build.gradle b/integration-tests/mockito-experimental/build.gradle
index 3c32436..6b59f77 100644
--- a/integration-tests/mockito-experimental/build.gradle
+++ b/integration-tests/mockito-experimental/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
apply plugin: RoboJavaModulePlugin
diff --git a/integration-tests/mockito/build.gradle b/integration-tests/mockito/build.gradle
index 08253a5..61cc9ae 100644
--- a/integration-tests/mockito/build.gradle
+++ b/integration-tests/mockito/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
apply plugin: RoboJavaModulePlugin
diff --git a/integration-tests/powermock/build.gradle b/integration-tests/powermock/build.gradle
index 526dc26..cab7c55 100644
--- a/integration-tests/powermock/build.gradle
+++ b/integration-tests/powermock/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
apply plugin: RoboJavaModulePlugin
diff --git a/junit/build.gradle b/junit/build.gradle
index 884edf6..e930f90 100644
--- a/junit/build.gradle
+++ b/junit/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
new RoboJavaModulePlugin(
diff --git a/processor/build.gradle b/processor/build.gradle
index c7a33f2..d473c9c 100644
--- a/processor/build.gradle
+++ b/processor/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
new RoboJavaModulePlugin(
diff --git a/resources/build.gradle b/resources/build.gradle
index 77d7c02..df94923 100644
--- a/resources/build.gradle
+++ b/resources/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
new RoboJavaModulePlugin(
diff --git a/resources/src/main/java/org/robolectric/res/android/Asset.java b/resources/src/main/java/org/robolectric/res/android/Asset.java
index a6ed59e..e9b2d7d 100644
--- a/resources/src/main/java/org/robolectric/res/android/Asset.java
+++ b/resources/src/main/java/org/robolectric/res/android/Asset.java
@@ -1,102 +1,127 @@
package org.robolectric.res.android;
+import static org.robolectric.res.android.Util.ALOGI;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Class providing access to a read-only asset. Asset objects are NOT thread-safe, and should not
+ * be shared across threads.
+ *
+ * transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-7.1.1_r13/include/androidfw/Asset.h
+ * and https://android.googlesource.com/platform/frameworks/base/+/android-7.1.1_r13/libs/androidfw/Asset.cpp
+ *
+ * Instances of this class provide read-only operations on a byte stream.
+ * Access may
+ * be optimized for streaming, random, or whole buffer modes. All operations are supported
+ * regardless of how the file was opened, but some things will be less efficient. [pass that
+ * in??]. "Asset" is the base class for all types of assets. The classes below
+ * provide most of the implementation. The AssetManager uses one of the static "create"
+ * functions defined here to create a new instance.
+ */
public class Asset {
-// static const bool kIsDebug = false;
+ //
+
+ // public:
+// virtual ~Asset(void) = default;
+// static int32_t getGlobalCount();
+// static String8 getAssetAllocations();
//
-// static Mutex gAssetLock;
-// static int32_t gCount = 0;
-// static Asset* gHead = NULL;
-// static Asset* gTail = NULL;
-//
-// void Asset::registerAsset(Asset* asset)
-// {
-// AutoMutex _l(gAssetLock);
-// gCount++;
-// asset->mNext = asset->mPrev = NULL;
-// if (gTail == NULL) {
-// gHead = gTail = asset;
-// } else {
-// asset->mPrev = gTail;
-// gTail->mNext = asset;
-// gTail = asset;
-// }
-//
-// if (kIsDebug) {
-// ALOGI("Creating Asset %p #%d\n", asset, gCount);
-// }
-// }
-//
-// void Asset::unregisterAsset(Asset* asset)
-// {
-// AutoMutex _l(gAssetLock);
-// gCount--;
-// if (gHead == asset) {
-// gHead = asset->mNext;
-// }
-// if (gTail == asset) {
-// gTail = asset->mPrev;
-// }
-// if (asset->mNext != NULL) {
-// asset->mNext->mPrev = asset->mPrev;
-// }
-// if (asset->mPrev != NULL) {
-// asset->mPrev->mNext = asset->mNext;
-// }
-// asset->mNext = asset->mPrev = NULL;
-//
-// if (kIsDebug) {
-// ALOGI("Destroying Asset in %p #%d\n", asset, gCount);
-// }
-// }
-//
-// int32_t Asset::getGlobalCount()
-// {
-// AutoMutex _l(gAssetLock);
-// return gCount;
-// }
-//
-// String8 Asset::getAssetAllocations()
-// {
+// /* used when opening an asset */
+ enum AccessMode {
+ ACCESS_UNKNOWN,
+ /* read chunks, and seek forward and backward */
+ ACCESS_RANDOM,
+ /* read sequentially, with an occasional forward seek */
+ ACCESS_STREAMING,
+ /* caller plans to ask for a read-only buffer with all data */
+ ACCESS_BUFFER,
+ }
+
+//using namespace android;
+//#ifndef O_BINARY
+//# define O_BINARY 0
+//#endif
+private static final boolean kIsDebug = false;
+private static final Object gAssetLock = new Object();
+private static List<Asset> gAssets = new LinkedList<>();
+
+ private String8 mAssetSource; // debug string
+
+ /* set the asset source string */
+ void setAssetSource(String8 path) {
+ mAssetSource = path;
+ }
+
+protected void registerAsset(Asset asset)
+{
+ int gCount = 0;
+ synchronized (gAssetLock) {
+ gAssets.add(asset);
+ gCount = gAssets.size();
+ }
+ if (kIsDebug) {
+ ALOGI("Creating Asset %p #%d\n", asset, gCount);
+ }
+
+}
+
+protected void unregisterAsset(Asset asset) {
+ int gCount = 0;
+ synchronized (gAssetLock) {
+ gAssets.remove(asset);
+ gCount = gAssets.size();
+ }
+ if (kIsDebug) {
+ ALOGI("Destroying Asset in %p #%d\n", asset, gCount);
+ }
+}
+
+protected int getGlobalCount()
+{
+ synchronized (gAssetLock) {
+ return gAssets.size();
+ }
+}
+
+//String8 Asset::getAssetAllocations()
+//{
// AutoMutex _l(gAssetLock);
// String8 res;
// Asset* cur = gHead;
// while (cur != NULL) {
-// if (cur->isAllocated()) {
-// res.append(" ");
-// res.append(cur->getAssetSource());
-// off64_t size = (cur->getLength()+512)/1024;
-// char buf[64];
-// sprintf(buf, ": %dK\n", (int)size);
-// res.append(buf);
-// }
-// cur = cur->mNext;
+// if (cur->isAllocated()) {
+// res.append(" ");
+// res.append(cur->getAssetSource());
+// off64_t size = (cur->getLength()+512)/1024;
+// char buf[64];
+// sprintf(buf, ": %dK\n", (int)size);
+// res.append(buf);
+// }
+// cur = cur->mNext;
// }
-//
// return res;
-// }
-//
-// Asset::Asset(void)
+//}
+//Asset::Asset(void)
// : mAccessMode(ACCESS_UNKNOWN), mNext(NULL), mPrev(NULL)
-// {
-// }
-//
-///*
-// * 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)
-// {
+//{
+//}
+/*
+ * 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 createFromFile(String fileName, AccessMode mode)
+{
// _FileAsset* pAsset;
// status_t result;
// off64_t length;
// int fd;
-//
// fd = open(fileName, O_RDONLY | O_BINARY);
// if (fd < 0)
-// return NULL;
-//
+// 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
@@ -108,44 +133,43 @@
// length = lseek64(fd, 0, SEEK_END);
// if (length < 0) {
// ::close(fd);
-// return NULL;
+// return NULL;
// }
// (void) lseek64(fd, 0, SEEK_SET);
//#else
// struct stat st;
// if (fstat(fd, &st) < 0) {
// ::close(fd);
-// return NULL;
-// }
-//
+// return NULL;
+// }
// if (!S_ISREG(st.st_mode)) {
// ::close(fd);
-// return NULL;
+// return NULL;
// }
//#endif
-//
-// pAsset = new _FileAsset;
+// pAsset = new _FileAsset;
// result = pAsset->openChunk(fileName, fd, 0, length);
// if (result != NO_ERROR) {
-// delete pAsset;
-// return NULL;
+// 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;
+ return null;
+}
+
+/*
+ * 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 createFromCompressedFile(String fileName,
+ AccessMode mode)
+{
+ return null;
+// _CompressedAsset pAsset;
// status_t result;
// off64_t fileLen;
// bool scanResult;
@@ -153,268 +177,225 @@
// int method;
// long uncompressedLen, compressedLen;
// int fd;
-//
// fd = open(fileName, O_RDONLY | O_BINARY);
// if (fd < 0)
-// return NULL;
-//
+// return NULL;
// fileLen = lseek(fd, 0, SEEK_END);
// if (fileLen < 0) {
// ::close(fd);
-// return NULL;
+// 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;
+// return NULL;
// }
-//
// unsigned long crc32;
// scanResult = ZipUtils::examineGzip(fp, &method, &uncompressedLen,
// &compressedLen, &crc32);
// offset = ftell(fp);
// fclose(fp);
// if (!scanResult) {
-// ALOGD("File '%s' is not in gzip format\n", fileName);
+// ALOGD("File '%s' is not in gzip format\n", fileName);
// ::close(fd);
-// return NULL;
+// return NULL;
// }
-//
// pAsset = new _CompressedAsset;
// result = pAsset->openChunk(fd, offset, method, uncompressedLen,
-// compressedLen);
+// compressedLen);
// if (result != NO_ERROR) {
-// delete pAsset;
-// return NULL;
+// delete pAsset;
+// return NULL;
// }
-//
// pAsset->mAccessMode = mode;
// return pAsset;
-// }
-//
-//
+}
//#if 0
///*
// * Create a new Asset from part of an open file.
// */
///*static*/ Asset* Asset::createFromFileSegment(int fd, off64_t offset,
-// size_t length, AccessMode mode)
-// {
+// 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;
-//
+// return NULL;
// pAsset->mAccessMode = mode;
// return pAsset;
-// }
-//
+//}
///*
// * Create a new Asset from compressed data in an open file.
// */
///*static*/ Asset* Asset::createFromCompressedData(int fd, off64_t offset,
-// int compressionMethod, size_t uncompressedLen, size_t compressedLen,
-// AccessMode mode)
-// {
+// 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);
+// uncompressedLen, compressedLen);
// if (result != NO_ERROR)
-// return NULL;
-//
+// return NULL;
// pAsset->mAccessMode = mode;
// return pAsset;
-// }
+//}
//#endif
-//
///*
// * Create a new Asset from a memory mapping.
// */
///*static*/ Asset* Asset::createFromUncompressedMap(FileMap* dataMap,
-// AccessMode mode)
-// {
+// AccessMode mode)
+//{
// _FileAsset* pAsset;
// status_t result;
-//
// pAsset = new _FileAsset;
// result = pAsset->openChunk(dataMap);
// if (result != NO_ERROR)
-// return NULL;
-//
+// return NULL;
// pAsset->mAccessMode = mode;
// return pAsset;
-// }
-//
+//}
///*
// * Create a new Asset from compressed data in a memory mapping.
// */
///*static*/ Asset* Asset::createFromCompressedMap(FileMap* dataMap,
-// size_t uncompressedLen, AccessMode mode)
-// {
+// size_t uncompressedLen, AccessMode mode)
+//{
// _CompressedAsset* pAsset;
// status_t result;
-//
// pAsset = new _CompressedAsset;
// result = pAsset->openChunk(dataMap, uncompressedLen);
// if (result != NO_ERROR)
-// return NULL;
-//
+// return NULL;
// pAsset->mAccessMode = mode;
// return pAsset;
-// }
-//
-//
-// /*
-// * Do generic seek() housekeeping. Pass in the offset/whence values from
-// * the seek request, along with the current chunk offset and the chunk
-// * length.
-// *
-// * Returns the new chunk offset, or -1 if the seek is illegal.
-// */
-// off64_t Asset::handleSeek(off64_t offset, int whence, off64_t curPosn, off64_t maxPosn)
-// {
+//}
+///*
+// * Do generic seek() housekeeping. Pass in the offset/whence values from
+// * the seek request, along with the current chunk offset and the chunk
+// * length.
+// *
+// * Returns the new chunk offset, or -1 if the seek is illegal.
+// */
+//off64_t Asset::handleSeek(off64_t offset, int whence, off64_t curPosn, off64_t maxPosn)
+//{
// off64_t newOffset;
-//
// switch (whence) {
-// case SEEK_SET:
+// case SEEK_SET:
// newOffset = offset;
// break;
-// case SEEK_CUR:
+// case SEEK_CUR:
// newOffset = curPosn + offset;
// break;
-// case SEEK_END:
+// case SEEK_END:
// newOffset = maxPosn + offset;
// break;
-// default:
+// default:
// ALOGW("unexpected whence %d\n", whence);
// // this was happening due to an off64_t size mismatch
// assert(false);
// return (off64_t) -1;
// }
-//
// if (newOffset < 0 || newOffset > maxPosn) {
-// ALOGW("seek out of range: want %ld, end=%ld\n",
-// (long) newOffset, (long) maxPosn);
-// return (off64_t) -1;
+// ALOGW("seek out of range: want %ld, end=%ld\n",
+// (long) newOffset, (long) maxPosn);
+// return (off64_t) -1;
// }
-//
// return newOffset;
-// }
-//
-//
+//}
///*
// * ===========================================================================
// * _FileAsset
// * ===========================================================================
// */
-//
///*
// * Constructor.
// */
-// _FileAsset::_FileAsset(void)
+//_FileAsset::_FileAsset(void)
// : mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mMap(NULL), mBuf(NULL)
-// {
+//{
// // Register the Asset with the global list here after it is fully constructed and its
// // vtable pointer points to this concrete type. b/31113965
// registerAsset(this);
-// }
-//
+//}
///*
// * Destructor. Release resources.
// */
-// _FileAsset::~_FileAsset(void)
-// {
+//_FileAsset::~_FileAsset(void)
+//{
// close();
-//
// // Unregister the Asset from the global list here before it is destructed and while its vtable
// // pointer still points to this concrete type. b/31113965
// unregisterAsset(this);
-// }
-//
-// /*
-// * Operate on a chunk of an uncompressed file.
-// *
-// * Zero-length chunks are allowed.
-// */
-// status_t _FileAsset::openChunk(const char* fileName, int fd, off64_t offset, size_t length)
-// {
+//}
+///*
+// * Operate on a chunk of an uncompressed file.
+// *
+// * Zero-length chunks are allowed.
+// */
+//status_t _FileAsset::openChunk(const char* fileName, int fd, off64_t offset, size_t length)
+//{
// assert(mFp == NULL); // no reopen
// assert(mMap == NULL);
// assert(fd >= 0);
// assert(offset >= 0);
-//
// /*
// * Seek to end to get file length.
// */
// off64_t fileLength;
// fileLength = lseek64(fd, 0, SEEK_END);
// if (fileLength == (off64_t) -1) {
-// // probably a bad file descriptor
-// ALOGD("failed lseek (errno=%d)\n", errno);
-// return UNKNOWN_ERROR;
+// // probably a bad file descriptor
+// ALOGD("failed lseek (errno=%d)\n", errno);
+// return UNKNOWN_ERROR;
// }
-//
// if ((off64_t) (offset + length) > fileLength) {
-// ALOGD("start (%ld) + len (%ld) > end (%ld)\n",
-// (long) offset, (long) length, (long) fileLength);
-// return BAD_INDEX;
+// ALOGD("start (%ld) + len (%ld) > end (%ld)\n",
+// (long) offset, (long) length, (long) fileLength);
+// return BAD_INDEX;
// }
-//
// /* after fdopen, the fd will be closed on fclose() */
// mFp = fdopen(fd, "rb");
// if (mFp == NULL)
-// return UNKNOWN_ERROR;
-//
+// 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);
+// assert(false);
// }
-//
// mFileName = fileName != NULL ? strdup(fileName) : NULL;
-//
// return NO_ERROR;
-// }
-//
-// /*
-// * Create the chunk from the map.
-// */
-// status_t _FileAsset::openChunk(FileMap* dataMap)
-// {
+//}
+///*
+// * 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)
-// {
+//}
+///*
+// * 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
@@ -422,37 +403,33 @@
// * using the buffer or because what they're doing has appropriate
// * performance needs and access patterns.
// */
-// if (mBuf == NULL)
-// getBuffer(false);
+// if (mBuf == NULL)
+// getBuffer(false);
// }
-//
// /* adjust count if we're near EOF */
// maxLen = mLength - mOffset;
// if (count > maxLen)
-// count = maxLen;
-//
+// count = maxLen;
// if (!count)
-// return 0;
-//
+// return 0;
// if (mMap != NULL) {
// /* copy from mapped area */
-// //printf("map read\n");
-// memcpy(buf, (char*)mMap->getDataPtr() + mOffset, count);
-// actual = count;
+// //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;
+// //printf("buf read\n");
+// memcpy(buf, (char*)mBuf + mOffset, count);
+// actual = count;
// } else {
// /* read from the file */
-// //printf("file read\n");
-// if (ftell(mFp) != mStart + mOffset) {
-// ALOGE("Hosed: %ld != %ld+%ld\n",
-// ftell(mFp), (long) mStart, (long) mOffset);
-// assert(false);
-// }
-//
+// //printf("file read\n");
+// if (ftell(mFp) != mStart + mOffset) {
+// ALOGE("Hosed: %ld != %ld+%ld\n",
+// ftell(mFp), (long) mStart, (long) mOffset);
+// assert(false);
+// }
// /*
// * This returns 0 on error or eof. We need to use ferror() or feof()
// * to tell the difference, but we don't currently have those on the
@@ -460,68 +437,57 @@
// * 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);
+// actual = fread(buf, 1, count, mFp);
+// if (actual == 0) // something failed -- I/O error?
+// return -1;
+// assert(actual == count);
// }
-//
// mOffset += actual;
// return actual;
-// }
-//
-// /*
-// * Seek to a new position.
-// */
-// off64_t _FileAsset::seek(off64_t offset, int whence)
-// {
+//}
+///*
+// * Seek to a new position.
+// */
+//off64_t _FileAsset::seek(off64_t offset, int whence)
+//{
// off64_t newPosn;
// off64_t actualOffset;
-//
// // compute new position within chunk
// newPosn = handleSeek(offset, whence, mOffset, mLength);
// if (newPosn == (off64_t) -1)
-// return newPosn;
-//
+// return newPosn;
// actualOffset = mStart + newPosn;
-//
// if (mFp != NULL) {
-// if (fseek(mFp, (long) actualOffset, SEEK_SET) != 0)
-// return (off64_t) -1;
+// if (fseek(mFp, (long) actualOffset, SEEK_SET) != 0)
+// return (off64_t) -1;
// }
-//
// mOffset = actualOffset - mStart;
// return mOffset;
-// }
-//
-// /*
-// * Close the asset.
-// */
-// void _FileAsset::close(void)
-// {
+//}
+///*
+// * Close the asset.
+// */
+//void _FileAsset::close(void)
+//{
// if (mMap != NULL) {
-// delete mMap;
-// mMap = NULL;
+// delete mMap;
+// mMap = NULL;
// }
// if (mBuf != NULL) {
-// delete[] mBuf;
-// mBuf = NULL;
+// delete[] mBuf;
+// mBuf = NULL;
// }
-//
// if (mFileName != NULL) {
-// free(mFileName);
-// 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;
+// // 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.
// *
@@ -531,289 +497,268 @@
// * deal with it here.
// */
//const void* _FileAsset::getBuffer(bool wordAligned)
-// Object getBuffer(boolean wordAligned)
-// {
+//{
// /* subsequent requests just use what we did previously */
// if (mBuf != NULL)
-// return mBuf;
+// return mBuf;
// if (mMap != NULL) {
-// if (!wordAligned) {
-// return mMap->getDataPtr();
-// }
-// return ensureAlignment(mMap);
+// if (!wordAligned) {
+// return mMap->getDataPtr();
+// }
+// return ensureAlignment(mMap);
// }
-//
// assert(mFp != NULL);
-//
// if (mLength < kReadVsMapThreshold) {
-// unsigned char* buf;
-// long allocLen;
-//
+// unsigned char* buf;
+// long allocLen;
// /* zero-length files are allowed; not sure about zero-len allocs */
// /* (works fine with gcc + x86linux) */
-// allocLen = mLength;
-// if (mLength == 0)
-// allocLen = 1;
-//
-// buf = new unsigned char[allocLen];
-// if (buf == NULL) {
-// ALOGE("alloc of %ld bytes failed\n", (long) allocLen);
-// return NULL;
-// }
-//
-// ALOGV("Asset %p allocating buffer size %d (smaller than threshold)", this, (int)allocLen);
-// if (mLength > 0) {
-// long oldPosn = ftell(mFp);
-// fseek(mFp, mStart, SEEK_SET);
-// if (fread(buf, 1, mLength, mFp) != (size_t) mLength) {
-// ALOGE("failed reading %ld bytes\n", (long) mLength);
-// delete[] buf;
-// return NULL;
+// allocLen = mLength;
+// if (mLength == 0)
+// allocLen = 1;
+// buf = new unsigned char[allocLen];
+// if (buf == NULL) {
+// ALOGE("alloc of %ld bytes failed\n", (long) allocLen);
+// return NULL;
// }
-// fseek(mFp, oldPosn, SEEK_SET);
-// }
-//
-// ALOGV(" getBuffer: loaded into buffer\n");
-//
-// mBuf = buf;
-// return mBuf;
+// ALOGV("Asset %p allocating buffer size %d (smaller than threshold)", this, (int)allocLen);
+// if (mLength > 0) {
+// long oldPosn = ftell(mFp);
+// fseek(mFp, mStart, SEEK_SET);
+// if (fread(buf, 1, mLength, mFp) != (size_t) mLength) {
+// ALOGE("failed reading %ld bytes\n", (long) mLength);
+// delete[] buf;
+// return NULL;
+// }
+// fseek(mFp, oldPosn, SEEK_SET);
+// }
+// ALOGV(" getBuffer: loaded into buffer\n");
+// mBuf = buf;
+// return mBuf;
// } else {
-// FileMap* map;
-//
-// map = new FileMap;
-// if (!map->create(NULL, fileno(mFp), mStart, mLength, true)) {
-// delete map;
-// return NULL;
-// }
-//
-// ALOGV(" getBuffer: mapped\n");
-//
-// mMap = map;
-// if (!wordAligned) {
-// return mMap->getDataPtr();
-// }
-// return ensureAlignment(mMap);
+// FileMap* map;
+// map = new FileMap;
+// if (!map->create(NULL, fileno(mFp), mStart, mLength, true)) {
+// delete map;
+// return NULL;
+// }
+// ALOGV(" getBuffer: mapped\n");
+// mMap = map;
+// if (!wordAligned) {
+// return mMap->getDataPtr();
+// }
+// return ensureAlignment(mMap);
// }
-// }
-
-// int _FileAsset::openFileDescriptor(off64_t* outStart, off64_t* outLength) const
-// {
+//}
+//int _FileAsset::openFileDescriptor(off64_t* outStart, off64_t* outLength) const
+//{
// if (mMap != NULL) {
// const char* fname = mMap->getFileName();
-// if (fname == NULL) {
-// fname = mFileName;
-// }
-// if (fname == NULL) {
-// return -1;
-// }
+// if (fname == NULL) {
+// fname = mFileName;
+// }
+// if (fname == NULL) {
+// return -1;
+// }
// *outStart = mMap->getDataOffset();
// *outLength = mMap->getDataLength();
-// return open(fname, O_RDONLY | O_BINARY);
+// return open(fname, O_RDONLY | O_BINARY);
// }
// if (mFileName == NULL) {
-// return -1;
+// return -1;
// }
// *outStart = mStart;
// *outLength = mLength;
// return open(mFileName, O_RDONLY | O_BINARY);
-// }
-//
+//}
//const void* _FileAsset::ensureAlignment(FileMap* map)
-// {
+//{
// void* data = map->getDataPtr();
// if ((((size_t)data)&0x3) == 0) {
-// // We can return this directly if it is aligned on a word
-// // boundary.
-// ALOGV("Returning aligned FileAsset %p (%s).", this,
-// getAssetSource());
-// return data;
+// // We can return this directly if it is aligned on a word
+// // boundary.
+// ALOGV("Returning aligned FileAsset %p (%s).", this,
+// getAssetSource());
+// return data;
// }
// // If not aligned on a word boundary, then we need to copy it into
// // our own buffer.
// ALOGV("Copying FileAsset %p (%s) to buffer size %d to make it aligned.", this,
-// getAssetSource(), (int)mLength);
+// getAssetSource(), (int)mLength);
// unsigned char* buf = new unsigned char[mLength];
// if (buf == NULL) {
-// ALOGE("alloc of %ld bytes failed\n", (long) mLength);
-// return NULL;
+// ALOGE("alloc of %ld bytes failed\n", (long) mLength);
+// return NULL;
// }
// memcpy(buf, data, mLength);
// mBuf = buf;
// return buf;
-// }
-//
+//}
+/*
+ * ===========================================================================
+ * _CompressedAsset
+ * ===========================================================================
+ */
+private static class _CompressedAsset extends Asset {
+ private long mStart; // offset to start of compressed data
+ private long mCompressedLen; // length of the compressed data
+ private long mUncompressedLen; // length of the uncompressed data
+ private long mOffset; // current offset, 0 == start of uncomp data
+ //FileMap* mMap; // for memory-mapped input
+ private int mFd; // for file input
+ //StreamingZipInflater mZipInflater; // for streaming large compressed assets
+ private byte[] mBuf; // for getBuffer()
+
+/*
+ * Constructor.
+ */
+_CompressedAsset() {
+ mStart = 0;
+ mCompressedLen = 0;
+ mUncompressedLen = 0;
+ mOffset = 0;
+ // mMap = null;
+ mFd = -1;
+ //mZipInflater = null;
+ mBuf = null;
+
+ // Register the Asset with the global list here after it is fully constructed and its
+ // vtable pointer points to this concrete type. b/31113965
+ registerAsset(this);
+
+
+}
+/*
+ * Destructor. Release resources.
+ */
+@Override
+public void finalize()
+ {
+ // close();
+ // Unregister the Asset from the global list here before it is destructed and while its vtable
+ // pointer still points to this concrete type. b/31113965
+ unregisterAsset(this);
+}
///*
-// * ===========================================================================
-// * _CompressedAsset
-// * ===========================================================================
+// * 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.
// */
-//
-///*
-// * Constructor.
-// */
-// _CompressedAsset::_CompressedAsset(void)
-// : mStart(0), mCompressedLen(0), mUncompressedLen(0), mOffset(0),
-// mMap(NULL), mFd(-1), mZipInflater(NULL), mBuf(NULL)
-// {
-// // Register the Asset with the global list here after it is fully constructed and its
-// // vtable pointer points to this concrete type. b/31113965
-// registerAsset(this);
-// }
-//
-///*
-// * Destructor. Release resources.
-// */
-// _CompressedAsset::~_CompressedAsset(void)
-// {
-// close();
-//
-// // Unregister the Asset from the global list here before it is destructed and while its vtable
-// // pointer still points to this concrete type. b/31113965
-// unregisterAsset(this);
-// }
-//
-// /*
-// * Open a chunk of compressed data inside a file.
-// *
-// * This currently just sets up some values and returns. On the first
-// * read, we expand the entire file into a buffer and return data from it.
-// */
-// status_t _CompressedAsset::openChunk(int fd, off64_t offset,
-// int compressionMethod, size_t uncompressedLen, size_t compressedLen)
-// {
+//status_t _CompressedAsset::openChunk(int fd, off64_t offset,
+// int compressionMethod, size_t uncompressedLen, size_t compressedLen)
+//{
// assert(mFd < 0); // no re-open
// assert(mMap == NULL);
// assert(fd >= 0);
// assert(offset >= 0);
// assert(compressedLen > 0);
-//
// if (compressionMethod != ZipFileRO::kCompressDeflated) {
-// assert(false);
-// return UNKNOWN_ERROR;
+// assert(false);
+// return UNKNOWN_ERROR;
// }
-//
// mStart = offset;
// mCompressedLen = compressedLen;
// mUncompressedLen = uncompressedLen;
// assert(mOffset == 0);
// mFd = fd;
// assert(mBuf == NULL);
-//
// if (uncompressedLen > StreamingZipInflater::OUTPUT_CHUNK_SIZE) {
-// mZipInflater = new StreamingZipInflater(mFd, offset, uncompressedLen, compressedLen);
+// mZipInflater = new StreamingZipInflater(mFd, offset, uncompressedLen, compressedLen);
// }
-//
// return NO_ERROR;
-// }
-//
-// /*
-// * Open a chunk of compressed data in a mapped region.
-// *
-// * Nothing is expanded until the first read call.
-// */
-// status_t _CompressedAsset::openChunk(FileMap* dataMap, size_t uncompressedLen)
-// {
+//}
+///*
+// * Open a chunk of compressed data in a mapped region.
+// *
+// * Nothing is expanded until the first read call.
+// */
+//status_t _CompressedAsset::openChunk(FileMap* dataMap, size_t uncompressedLen)
+//{
// assert(mFd < 0); // no re-open
// assert(mMap == NULL);
// assert(dataMap != NULL);
-//
// mMap = dataMap;
// mStart = -1; // not used
// mCompressedLen = dataMap->getDataLength();
// mUncompressedLen = uncompressedLen;
// assert(mOffset == 0);
-//
// if (uncompressedLen > StreamingZipInflater::OUTPUT_CHUNK_SIZE) {
-// mZipInflater = new StreamingZipInflater(dataMap, uncompressedLen);
+// mZipInflater = new StreamingZipInflater(dataMap, uncompressedLen);
// }
// return NO_ERROR;
-// }
-//
-// /*
-// * Read data from a chunk of compressed data.
-// *
-// * [For now, that's just copying data out of a buffer.]
-// */
-// ssize_t _CompressedAsset::read(void* buf, size_t count)
-// {
+//}
+///*
+// * Read data from a chunk of compressed data.
+// *
+// * [For now, that's just copying data out of a buffer.]
+// */
+//ssize_t _CompressedAsset::read(void* buf, size_t count)
+//{
// size_t maxLen;
// size_t actual;
-//
// assert(mOffset >= 0 && mOffset <= mUncompressedLen);
-//
// /* If we're relying on a streaming inflater, go through that */
// if (mZipInflater) {
-// actual = mZipInflater->read(buf, count);
+// actual = mZipInflater->read(buf, count);
// } else {
-// if (mBuf == NULL) {
-// if (getBuffer(false) == NULL)
-// return -1;
-// }
-// assert(mBuf != NULL);
-//
+// 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;
-//
+// 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;
+// //printf("comp buf read\n");
+// memcpy(buf, (char*)mBuf + mOffset, count);
+// actual = count;
// }
-//
// mOffset += actual;
// return actual;
-// }
-//
-// /*
-// * Handle a seek request.
-// *
-// * If we're working in a streaming mode, this is going to be fairly
-// * expensive, because it requires plowing through a bunch of compressed
-// * data.
-// */
-// off64_t _CompressedAsset::seek(off64_t offset, int whence)
-// {
+//}
+///*
+// * Handle a seek request.
+// *
+// * If we're working in a streaming mode, this is going to be fairly
+// * expensive, because it requires plowing through a bunch of compressed
+// * data.
+// */
+//off64_t _CompressedAsset::seek(off64_t offset, int whence)
+//{
// off64_t newPosn;
-//
// // compute new position within chunk
// newPosn = handleSeek(offset, whence, mOffset, mUncompressedLen);
// if (newPosn == (off64_t) -1)
-// return newPosn;
-//
+// return newPosn;
// if (mZipInflater) {
-// mZipInflater->seekAbsolute(newPosn);
+// mZipInflater->seekAbsolute(newPosn);
// }
// mOffset = newPosn;
// return mOffset;
-// }
-//
-// /*
-// * Close the asset.
-// */
-// void _CompressedAsset::close(void)
-// {
+//}
+///*
+// * Close the asset.
+// */
+//void _CompressedAsset::close(void)
+//{
// if (mMap != NULL) {
-// delete mMap;
-// mMap = NULL;
+// delete mMap;
+// mMap = NULL;
// }
-//
// delete[] mBuf;
// mBuf = NULL;
-//
// delete mZipInflater;
// mZipInflater = NULL;
-//
// if (mFd > 0) {
// ::close(mFd);
-// mFd = -1;
+// mFd = -1;
// }
-// }
-//
+//}
///*
// * Get a pointer to a read-only buffer of data.
// *
@@ -821,56 +766,47 @@
// * buffer.
// */
//const void* _CompressedAsset::getBuffer(bool)
-// {
+//{
// unsigned char* buf = NULL;
-//
// if (mBuf != NULL)
-// return mBuf;
-//
+// return mBuf;
// /*
// * Allocate a buffer and read the file into it.
// */
// buf = new unsigned char[mUncompressedLen];
// if (buf == NULL) {
-// ALOGW("alloc %ld bytes failed\n", (long) mUncompressedLen);
+// ALOGW("alloc %ld bytes failed\n", (long) mUncompressedLen);
// goto bail;
// }
-//
// if (mMap != NULL) {
-// if (!ZipUtils::inflateToBuffer(mMap->getDataPtr(), buf,
-// mUncompressedLen, mCompressedLen))
+// if (!ZipUtils::inflateToBuffer(mMap->getDataPtr(), buf,
+// mUncompressedLen, mCompressedLen))
// goto bail;
// } else {
-// assert(mFd >= 0);
-//
+// assert(mFd >= 0);
// /*
// * Seek to the start of the compressed data.
// */
-// if (lseek(mFd, mStart, SEEK_SET) != mStart)
+// if (lseek(mFd, mStart, SEEK_SET) != mStart)
// goto bail;
-//
// /*
// * Expand the data into it.
// */
-// if (!ZipUtils::inflateToBuffer(mFd, buf, mUncompressedLen,
-// mCompressedLen))
+// if (!ZipUtils::inflateToBuffer(mFd, buf, mUncompressedLen,
+// mCompressedLen))
// goto bail;
// }
-//
// /*
// * Success - now that we have the full asset in RAM we
// * no longer need the streaming inflater
// */
// delete mZipInflater;
// mZipInflater = NULL;
-//
// mBuf = buf;
// buf = NULL;
-//
-// bail:
+//bail:
// delete[] buf;
// return mBuf;
-// }
//
-
+}
}
diff --git a/resources/src/main/java/org/robolectric/res/android/CppAssetManager.java b/resources/src/main/java/org/robolectric/res/android/CppAssetManager.java
index 2194e70..0cea798 100644
--- a/resources/src/main/java/org/robolectric/res/android/CppAssetManager.java
+++ b/resources/src/main/java/org/robolectric/res/android/CppAssetManager.java
@@ -1,5 +1,6 @@
package org.robolectric.res.android;
+import static org.robolectric.res.android.Util.ALOGV;
import static org.robolectric.res.android.Util.ALOGW;
import static org.robolectric.res.android.Util.ATRACE_CALL;
import static org.robolectric.res.android.Util.LOG_FATAL_IF;
@@ -9,17 +10,30 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
+import javax.annotation.Nullable;
+import org.robolectric.res.android.Asset.AccessMode;
import org.robolectric.res.android.CppAssetManager.FileType;
// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-7.1.1_r13/libs/androidfw/AssetManager.cpp
public class CppAssetManager {
enum FileType {
- kFileTypeRegular
+ kFileTypeUnknown,
+ kFileTypeNonexistent, // i.e. ENOENT
+ kFileTypeRegular,
+ kFileTypeDirectory,
+ kFileTypeCharDev,
+ kFileTypeBlockDev,
+ kFileTypeFifo,
+ kFileTypeSymlink,
+ kFileTypeSocket,
}
@@ -31,10 +45,10 @@
public asset_path() {
- this("", FileType.kFileTypeRegular, "", false, false);
+ this(new String8(), FileType.kFileTypeRegular, "", false, false);
}
- public asset_path(String path, FileType fileType, String idmap,
+ public asset_path(String8 path, FileType fileType, String idmap,
boolean isSystemOverlay,
boolean isSystemAsset) {
this.path = path;
@@ -44,7 +58,7 @@
this.isSystemAsset = isSystemAsset;
}
- String path;
+ String8 path;
FileType type;
String idmap;
boolean isSystemOverlay;
@@ -53,7 +67,8 @@
private final Object mLock = new Object();
-// ZipSet mZipSet;
+ //ZipSet mZipSet;
+ Object mZipSet;
private final List<asset_path> mAssetPaths = new ArrayList<>();
private String mLocale;
@@ -64,14 +79,17 @@
// static final boolean kIsDebug = false;
//
-// static final char* kAssetsRoot = "assets";
-// static final char* kAppZipName = NULL; //"classes.jar";
+ static final String kAssetsRoot = "assets";
+ static final String kAppZipName = null; //"classes.jar";
// static final char* kSystemAssets = "framework/framework-res.apk";
// static final char* kResourceCache = "resource-cache";
//
// static final char* kExcludeExtension = ".EXCLUDE";
//
-// static Asset* final kExcludedAsset = (Asset*) 0xd000000d;
+
+ // TODO: figure out how to translate this to Java
+ // static Asset final kExcludedAsset = (Asset*) 0xd000000d;
+ static final Asset kExcludedAsset = null;
//
// static volatile int gCount = 0;
//
@@ -162,65 +180,68 @@
// delete[] mLocale;
// }
//
-// boolean addAssetPath(
-// final String8& path, int* cookie, boolean appAsLib, boolean isSystemAsset) {
-// AutoMutex _l(mLock);
-//
-// asset_path ap;
-//
-// String8 realPath(path);
-// if (kAppZipName) {
-// realPath.appendPath(kAppZipName);
-// }
-// ap.type = .getFileType(realPath.string());
-// if (ap.type == kFileTypeRegular) {
-// ap.path = realPath;
-// } else {
-// ap.path = path;
-// ap.type = .getFileType(path.string());
-// if (ap.type != kFileTypeDirectory && ap.type != kFileTypeRegular) {
-// ALOGW("Asset path %s is neither a directory nor file (type=%d).",
-// path.string(), (int)ap.type);
-// return false;
-// }
-// }
-//
-// // Skip if we have it already.
-// for (int i=0; i<mAssetPaths.size(); i++) {
-// if (mAssetPaths[i].path == ap.path) {
-// if (cookie) {
-// *cookie = static_cast<int>(i+1);
-// }
-// return true;
-// }
-// }
-//
-// ALOGV("In %p Asset %s path: %s", this,
-// ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string());
-//
-// ap.isSystemAsset = isSystemAsset;
-// mAssetPaths.add(ap);
-//
-// // new paths are always added at the end
-// if (cookie) {
-// *cookie = static_cast<int>(mAssetPaths.size());
-// }
-//
-// #ifdef __ANDROID__
-// // Load overlays, if any
-// asset_path oap;
-// for (int idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) {
-// oap.isSystemAsset = isSystemAsset;
-// mAssetPaths.add(oap);
-// }
-// #endif
-//
-// if (mResources != NULL) {
-// appendPathToResTable(ap, appAsLib);
-// }
-//
-// return true;
-// }
+ boolean addAssetPath(
+ final String8 path, @Nullable Ref<Integer> cookie, boolean appAsLib, boolean isSystemAsset) {
+ synchronized (mLock) {
+
+ asset_path ap = new asset_path();
+
+ String8 realPath = path;
+ if (kAppZipName != null) {
+ realPath.appendPath(kAppZipName);
+ }
+ ap.type = getFileType(realPath.string());
+ if (ap.type == FileType.kFileTypeRegular) {
+ ap.path = realPath;
+ } else {
+ ap.path = path;
+ ap.type = getFileType(path.string());
+ if (ap.type != FileType.kFileTypeDirectory && ap.type != FileType.kFileTypeRegular) {
+ ALOGW("Asset path %s is neither a directory nor file (type=%s).",
+ path.toString(), ap.type.name());
+ return false;
+ }
+ }
+
+ // Skip if we have it already.
+ for (int i = 0; i < mAssetPaths.size(); i++) {
+ if (mAssetPaths.get(i).path.equals(ap.path)) {
+ if (cookie != null) {
+ cookie.set(i + 1);
+ }
+ return true;
+ }
+ }
+
+ ALOGV("In %p Asset %s path: %s", this,
+ ap.type == FileType.kFileTypeDirectory ? "dir" : "zip", ap.path.toString());
+
+ ap.isSystemAsset = isSystemAsset;
+ mAssetPaths.add(ap);
+
+ // new paths are always added at the end
+ if (cookie != null) {
+ cookie.set(mAssetPaths.size());
+ }
+
+ // TODO: implement this?
+ //#ifdef __ANDROID__
+ // Load overlays, if any
+ //asset_path oap;
+ //for (int idx = 0; mZipSet.getOverlay(ap.path, idx, & oap)
+ // ; idx++){
+ // oap.isSystemAsset = isSystemAsset;
+ // mAssetPaths.add(oap);
+ // }
+ //#endif
+
+ if (mResources != null) {
+ appendPathToResTable(ap, appAsLib);
+ }
+
+ return true;
+ }
+ }
//
// boolean addOverlayPath(final String8& packagePath, int* cookie)
// {
@@ -381,44 +402,44 @@
// *outConfig = *mConfig;
// }
//
-// /*
-// * Open an asset.
-// *
-// * The data could be in any asset path. Each asset path could be:
-// * - A directory on disk.
-// * - A Zip archive, uncompressed or compressed.
-// *
-// * If the file is in a directory, it could have a .gz suffix, meaning it is compressed.
-// *
-// * We should probably reject requests for "illegal" filenames, e.g. those
-// * with illegal characters or "../" backward relative paths.
-// */
-// Asset* open(final char* fileName, AccessMode mode)
-// {
-// AutoMutex _l(mLock);
-//
-// LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
-//
-// String8 assetName(kAssetsRoot);
-// assetName.appendPath(fileName);
-//
-// /*
-// * For each top-level asset path, search for the asset.
-// */
-//
-// int i = mAssetPaths.size();
-// while (i > 0) {
-// i--;
-// ALOGV("Looking for asset '%s' in '%s'\n",
-// assetName.string(), mAssetPaths.itemAt(i).path.string());
-// Asset* pAsset = openNonAssetInPathLocked(assetName.string(), mode, mAssetPaths.itemAt(i));
-// if (pAsset != NULL) {
-// return pAsset != kExcludedAsset ? pAsset : NULL;
-// }
-// }
-//
-// return NULL;
-// }
+ /*
+ * Open an asset.
+ *
+ * The data could be in any asset path. Each asset path could be:
+ * - A directory on disk.
+ * - A Zip archive, uncompressed or compressed.
+ *
+ * If the file is in a directory, it could have a .gz suffix, meaning it is compressed.
+ *
+ * We should probably reject requests for "illegal" filenames, e.g. those
+ * with illegal characters or "../" backward relative paths.
+ */
+ Asset open(final String fileName, AccessMode mode)
+ {
+ synchronized (mLock) {
+
+ LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
+
+ String8 assetName = new String8(kAssetsRoot);
+ assetName.appendPath(fileName);
+ /*
+ * For each top-level asset path, search for the asset.
+ */
+ int i = mAssetPaths.size();
+ while (i > 0) {
+ i--;
+ ALOGV("Looking for asset '%s' in '%s'\n",
+ assetName.string(), mAssetPaths.get(i).path.string());
+ Asset pAsset = openNonAssetInPathLocked(assetName.string(), mode,
+ mAssetPaths.get(i));
+ if (pAsset != null) {
+ return Objects.equals(pAsset, kExcludedAsset) ? null : pAsset;
+ }
+ }
+
+ return null;
+ }
+ }
//
// /*
// * Open a non-asset file as if it were an asset.
@@ -471,30 +492,30 @@
// 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 getFileType(final 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;
-// }
-// }
+ /*
+ * 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 getFileType(final String 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.AccessMode.ACCESS_STREAMING);
+ // delete pAsset;
+
+ if (pAsset == null) {
+ return FileType.kFileTypeNonexistent;
+ } else {
+ return FileType.kFileTypeRegular;
+ }
+ }
boolean appendPathToResTable(final asset_path ap, boolean appAsLib) {
URL resource = getClass().getResource("/resources.ap_");
@@ -746,40 +767,40 @@
// }
// }
//
-// /*
-// * 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* openNonAssetInPathLocked(final char* fileName, AccessMode mode,
-// final 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);
-//
+ /*
+ * 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 openNonAssetInPathLocked(final String fileName, AccessMode mode,
+ final asset_path ap)
+ {
+ Asset pAsset = null;
+
+ /* look at the filesystem on disk */
+ if (ap.type == FileType.kFileTypeDirectory) {
+ String8 path = new String8(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 = new String8(fileName);
+//
// /* check the appropriate Zip file */
// ZipFileRO* pZip = getZipFileLocked(ap);
// if (pZip != NULL) {
@@ -791,17 +812,17 @@
// pZip.releaseEntry(entry);
// }
// }
-//
+//
// if (pAsset != NULL) {
// /* create a "source" name, for debug/display */
// pAsset.setAssetSource(
// createZipSourceNameLocked(ZipSet.getPathName(ap.path.string()), String8(""),
// String8(fileName)));
// }
-// }
-//
-// return pAsset;
-// }
+ }
+
+ return pAsset;
+ }
//
// /*
// * Create a "source name" for a file from a Zip archive.
@@ -840,33 +861,33 @@
// 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* openAssetFromFileLocked(final String8& pathName,
-// AccessMode mode)
-// {
-// Asset* pAsset = NULL;
-//
-// if (strcasecmp(pathName.getPathExtension().string(), ".gz") == 0) {
-// //printf("TRYING '%s'\n", (final char*) pathName);
-// pAsset = Asset.createFromCompressedFile(pathName.string(), mode);
-// } else {
-// //printf("TRYING '%s'\n", (final char*) pathName);
-// pAsset = Asset.createFromFile(pathName.string(), mode);
-// }
-//
-// return pAsset;
-// }
+ /*
+ * 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 openAssetFromFileLocked(final String8 pathName,
+ AccessMode mode)
+ {
+ Asset pAsset = null;
+
+ if (pathName.getPathExtension().toLowerCase().equals(".gz")) {
+ //printf("TRYING '%s'\n", (final char*) pathName);
+ pAsset = Asset.createFromCompressedFile(pathName.string(), mode);
+ } else {
+ //printf("TRYING '%s'\n", (final char*) pathName);
+ pAsset = Asset.createFromFile(pathName.string(), mode);
+ }
+
+ return pAsset;
+ }
//
// /*
// * Given an entry in a Zip archive, create a new Asset object.
diff --git a/resources/src/main/java/org/robolectric/res/android/Type.java b/resources/src/main/java/org/robolectric/res/android/DataType.java
similarity index 88%
rename from resources/src/main/java/org/robolectric/res/android/Type.java
rename to resources/src/main/java/org/robolectric/res/android/DataType.java
index 1554877..75d6794 100644
--- a/resources/src/main/java/org/robolectric/res/android/Type.java
+++ b/resources/src/main/java/org/robolectric/res/android/DataType.java
@@ -7,7 +7,7 @@
import java.util.Map;
/** Resource type codes. */
-public enum Type {
+public enum DataType {
/** {@code data} is either 0 (undefined) or 1 (empty). */
NULL(0x00),
/** {@code data} holds a {@link ResourceTableChunk} entry reference. */
@@ -41,17 +41,17 @@
private final byte code;
- private static final Map<Byte, Type> FROM_BYTE;
+ private static final Map<Byte, DataType> FROM_BYTE;
static {
- Builder<Byte, Type> builder = ImmutableMap.builder();
- for (Type type : values()) {
+ Builder<Byte, DataType> builder = ImmutableMap.builder();
+ for (DataType type : values()) {
builder.put(type.code(), type);
}
FROM_BYTE = builder.build();
}
- Type(int code) {
+ DataType(int code) {
this.code = UnsignedBytes.checkedCast(code);
}
@@ -59,7 +59,7 @@
return code;
}
- public static Type fromCode(byte code) {
+ public static DataType fromCode(byte code) {
return Preconditions.checkNotNull(FROM_BYTE.get(code), "Unknown resource type: %s", code);
}
}
diff --git a/resources/src/main/java/org/robolectric/res/android/ResTable.java b/resources/src/main/java/org/robolectric/res/android/ResTable.java
index 790f399..7b5586b 100644
--- a/resources/src/main/java/org/robolectric/res/android/ResTable.java
+++ b/resources/src/main/java/org/robolectric/res/android/ResTable.java
@@ -398,6 +398,42 @@
return entry.get()._package_.header.index;
}
+ public final int resolveReference(ResValue value, int blockIndex,
+ Ref<Integer> outLastRef, Ref<Integer> inoutTypeSpecFlags,
+ Ref<ResTableConfig> outConfig)
+ {
+ int count=0;
+ while (blockIndex >= 0 && value.dataType == DataType.REFERENCE.code()
+ && value.data != 0 && count < 20) {
+ if (outLastRef.get() == null) {
+ outLastRef.set(value.data);
+ }
+ Ref<Integer> newFlags = new Ref<>(0);
+ final int newIndex = getResource(value.data, new Ref<>(value), true, 0,
+ newFlags, outConfig);
+ if (newIndex == BAD_INDEX) {
+ return BAD_INDEX;
+ }
+ if (kDebugTableTheme) {
+ Util.ALOGI("Resolving reference 0x%x: newIndex=%d, type=0x%x, data=0x%x\n",
+ value.data, (int)newIndex, (int)value.dataType, value.data);
+ }
+ //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex);
+ if (inoutTypeSpecFlags != null) {
+ inoutTypeSpecFlags.set(inoutTypeSpecFlags.get() | newFlags.get());
+ }
+ 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;
+ }
+
Entry getEntry(int resId, String qualifiers) {
return getEntry(ResourceIds.getPackageIdentifier(resId),
ResourceIds.getTypeIdentifier(resId),
@@ -599,6 +635,10 @@
this.parameters = parameters;
}
+ public int getTableCookie(int index) {
+ return mHeaders.get(index).cookie;
+ }
+
// 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.
@@ -625,7 +665,7 @@
// clearBagCache();
// final int numTypes = types.size();
// for (int i = 0; i < numTypes; i++) {
-// final List<Type> typeList = types.get(i);
+// final List<DataType> typeList = types.get(i);
// final int numInnerTypes = typeList.size();
// for (int j = 0; j < numInnerTypes; j++) {
// if (typeList.get(j)._package_.owner == owner) {
@@ -652,7 +692,7 @@
// if (kDebugTableNoisy) {
// printf("type=%zu\n", i);
// }
-// final List<Type> typeList = types.get(i);
+// final List<DataType> typeList = types.get(i);
// if (!typeList.isEmpty()) {
// TypeCacheEntry cacheEntry = typeCacheEntries.editItemAt(i);
//
@@ -773,7 +813,7 @@
StringPoolRef keyStr;
}
- // struct ResTable::Type
+ // struct ResTable::DataType
public static class Type {
final Header header;
diff --git a/resources/src/main/java/org/robolectric/res/android/ResTableConfig.java b/resources/src/main/java/org/robolectric/res/android/ResTableConfig.java
index a5decfa..66c0d64 100644
--- a/resources/src/main/java/org/robolectric/res/android/ResTableConfig.java
+++ b/resources/src/main/java/org/robolectric/res/android/ResTableConfig.java
@@ -341,7 +341,7 @@
public int orientation;
int touchscreen;
- int density;
+ public int density;
int keyboard;
int navigation;
int inputFlags;
diff --git a/resources/src/main/java/org/robolectric/res/android/ResTableType.java b/resources/src/main/java/org/robolectric/res/android/ResTableType.java
index 2a5bfab..05e3a30 100644
--- a/resources/src/main/java/org/robolectric/res/android/ResTableType.java
+++ b/resources/src/main/java/org/robolectric/res/android/ResTableType.java
@@ -26,7 +26,7 @@
* It would be nice to have an additional ordered index of entries, so
* we can do a binary search if trying to find a resource by string name.
*
- * Type from androidfw/include/androidfw/ResourceTypes.h
+ * DataType from androidfw/include/androidfw/ResourceTypes.h
*/
public class ResTableType {
public static final int NO_ENTRY = 0xFFFFFFFF;
@@ -39,7 +39,7 @@
public ResChunkHeader header;
- // The type identifier this chunk is holding. Type IDs start
+ // The type identifier this chunk is holding. DataType IDs start
// at 1 (corresponding to the value of the type bits in a
// resource identifier). 0 is invalid.
public byte id;
diff --git a/resources/src/main/java/org/robolectric/res/android/ResValue.java b/resources/src/main/java/org/robolectric/res/android/ResValue.java
index 7297a98..b5abeaf 100644
--- a/resources/src/main/java/org/robolectric/res/android/ResValue.java
+++ b/resources/src/main/java/org/robolectric/res/android/ResValue.java
@@ -9,6 +9,7 @@
* <p>frameworks/base/include/androidfw/ResourceTypes.h (struct Res_value)
*/
public final class ResValue {
+ // must be one of DataType
public int dataType;
public int data;
diff --git a/resources/src/main/java/org/robolectric/res/android/String8.java b/resources/src/main/java/org/robolectric/res/android/String8.java
new file mode 100644
index 0000000..a0311c0
--- /dev/null
+++ b/resources/src/main/java/org/robolectric/res/android/String8.java
@@ -0,0 +1,406 @@
+package org.robolectric.res.android;
+
+import java.io.File;
+
+// transliterated from https://android.googlesource.com/platform/system/core/+/android-7.1.1_r13/libutils/String8.cpp
+// and https://android.googlesource.com/platform/system/core/+/android-7.1.1_r13/include/utils/String8.h
+public class String8 {
+
+ private StringBuilder mString;
+
+ public String8() {
+ this("");
+ }
+
+ public String8(String value) {
+ mString = new StringBuilder(value);
+ }
+
+ public String8(String8 path) {
+ this(path.string());
+ }
+
+//size_t String8::length() const
+//{
+// return SharedBuffer::sizeFromData(mString)-1;
+//}
+//String8 String8::format(const char* fmt, ...)
+//{
+// va_list args;
+// va_start(args, fmt);
+// String8 result(formatV(fmt, args));
+// va_end(args);
+// return result;
+//}
+//String8 String8::formatV(const char* fmt, va_list args)
+//{
+// String8 result;
+// result.appendFormatV(fmt, args);
+// return result;
+//}
+//void String8::clear() {
+// SharedBuffer::bufferFromData(mString)->release();
+// mString = getEmptyString();
+//}
+//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)
+//{
+// const char *newString = allocFromUTF8(other, strlen(other));
+// SharedBuffer::bufferFromData(mString)->release();
+// mString = newString;
+// if (mString) return NO_ERROR;
+// mString = getEmptyString();
+// return NO_MEMORY;
+//}
+//status_t String8::setTo(const char* other, size_t len)
+//{
+// const char *newString = allocFromUTF8(other, len);
+// SharedBuffer::bufferFromData(mString)->release();
+// mString = newString;
+// if (mString) return NO_ERROR;
+// mString = getEmptyString();
+// return NO_MEMORY;
+//}
+//status_t String8::setTo(const char16_t* other, size_t len)
+//{
+// const char *newString = allocFromUTF16(other, len);
+// SharedBuffer::bufferFromData(mString)->release();
+// mString = newString;
+// if (mString) return NO_ERROR;
+// mString = getEmptyString();
+// return NO_MEMORY;
+//}
+//status_t String8::setTo(const char32_t* other, size_t len)
+//{
+// const char *newString = allocFromUTF32(other, len);
+// SharedBuffer::bufferFromData(mString)->release();
+// mString = newString;
+// 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);
+//}
+public String8 append(final String other) {
+ mString.append(other);
+ return this;
+}
+//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::appendFormat(const char* fmt, ...)
+//{
+// va_list args;
+// va_start(args, fmt);
+// status_t result = appendFormatV(fmt, args);
+// va_end(args);
+// return result;
+//}
+//status_t String8::appendFormatV(const char* fmt, va_list args)
+//{
+// int n, result = NO_ERROR;
+// va_list tmp_args;
+// /* args is undefined after vsnprintf.
+// * So we need a copy here to avoid the
+// * second vsnprintf access undefined args.
+// */
+// va_copy(tmp_args, args);
+// n = vsnprintf(NULL, 0, fmt, tmp_args);
+// va_end(tmp_args);
+// if (n != 0) {
+// size_t oldLength = length();
+// char* buf = lockBuffer(oldLength + n);
+// if (buf) {
+// vsnprintf(buf + oldLength, n + 1, fmt, args);
+// } else {
+// result = NO_MEMORY;
+// }
+// }
+// return result;
+//}
+//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) {
+// return NO_MEMORY;
+// }
+// char* str = (char*)buf->data();
+// str[size] = 0;
+// mString = str;
+// }
+// return NO_ERROR;
+//}
+//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;
+//}
+//bool String8::removeAll(const char* other) {
+// ssize_t index = find(other);
+// if (index < 0) return false;
+// char* buf = lockBuffer(size());
+// if (!buf) return false; // out of memory
+// size_t skip = strlen(other);
+// size_t len = size();
+// size_t tail = index;
+// while (size_t(index) < len) {
+// ssize_t next = find(other, index + skip);
+// if (next < 0) {
+// next = len;
+// }
+// memmove(buf + tail, buf + index + skip, next - index - skip);
+// tail += next - index - skip;
+// index = next;
+// }
+// unlockBuffer(tail);
+// return true;
+//}
+//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);
+//}
+//size_t String8::getUtf32Length() const
+//{
+// return utf8_to_utf32_length(mString, length());
+//}
+//int32_t String8::getUtf32At(size_t index, size_t *next_index) const
+//{
+// return utf32_from_utf8_at(mString, length(), index, next_index);
+//}
+//void String8::getUtf32(char32_t* dst) const
+//{
+// utf8_to_utf32(mString, length(), dst);
+//}
+//// ---------------------------------------------------------------------------
+//// 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 index inside mString, or -1 if no extension was found.
+ */
+private int find_extension()
+{
+ int lastSlashIndex;
+
+ final StringBuilder str = mString;
+ // only look at the filename
+ lastSlashIndex = str.lastIndexOf(File.pathSeparator);
+ if (lastSlashIndex == -1) {
+ lastSlashIndex = 0;
+ } else {
+ lastSlashIndex++;
+ }
+ // find the last dot
+ return str.lastIndexOf(".", lastSlashIndex);
+}
+
+public String getPathExtension()
+{
+ int extIndex;
+ extIndex = find_extension();
+ if (extIndex != -1) {
+ return mString.substring(extIndex);
+ }
+ else {
+ return "";
+ }
+}
+//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);
+//}
+
+ public String8 appendPath(String name) {
+ if (name.length() == 0) {
+ // nothing to do
+ return this;
+ }
+ if (name.charAt(0) != File.pathSeparatorChar) {
+ mString.append(File.pathSeparatorChar);
+ }
+ mString.append(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
+
+ public final String string() {
+ return mString.toString();
+ }
+}
+
+
diff --git a/resources/src/main/java/org/robolectric/res/android/Util.java b/resources/src/main/java/org/robolectric/res/android/Util.java
index f54ab83..8e186e7 100644
--- a/resources/src/main/java/org/robolectric/res/android/Util.java
+++ b/resources/src/main/java/org/robolectric/res/android/Util.java
@@ -44,8 +44,8 @@
System.out.println(String.format(message, args));
}
- static void ALOGV(String message, int level) {
- System.out.println(message);
+ static void ALOGV(String message, Object... args) {
+ System.out.println(String.format(message, args));
}
static void ALOGI(String message, Object... args) {
@@ -53,10 +53,7 @@
}
static void LOG_FATAL_IF(boolean assertion, String message) {
- if (!assertion) {
- System.out.println(message);
- }
- assert assertion;
+ assert !assertion : message;
}
static void ATRACE_CALL() {
diff --git a/resources/src/main/java/org/robolectric/res/arsc/ResourceString.java b/resources/src/main/java/org/robolectric/res/arsc/ResourceString.java
index d6b4a74..658c063 100644
--- a/resources/src/main/java/org/robolectric/res/arsc/ResourceString.java
+++ b/resources/src/main/java/org/robolectric/res/arsc/ResourceString.java
@@ -29,7 +29,7 @@
/** Provides utilities to decode/encode a String packed in an arsc resource file. */
public final class ResourceString {
- /** Type of {@link ResourceString} to encode / decode. */
+ /** DataType of {@link ResourceString} to encode / decode. */
public enum Type {
UTF8(UTF_8),
UTF16(UTF_16LE);
diff --git a/resources/src/test/java/org/robolectric/res/android/ResTableTest.java b/resources/src/test/java/org/robolectric/res/android/ResTableTest.java
index ba8ba73..de4d8e2 100644
--- a/resources/src/test/java/org/robolectric/res/android/ResTableTest.java
+++ b/resources/src/test/java/org/robolectric/res/android/ResTableTest.java
@@ -35,25 +35,26 @@
@Test
public void testGetEntry_intType() {
Entry entry = resTable.getEntry(R.integer.flock_size, null);
- assertThat(entry.entry.value.dataType).isEqualTo(Type.INT_DEC.code());
+ assertThat(entry.entry.value.dataType).isEqualTo(DataType.INT_DEC.code());
assertThat(entry.entry.value.data).isEqualTo(1234);
}
@Test
public void testGetEntry_intType_large() {
Entry entry = resTable.getEntry(R.integer.flock_size, "large");
- assertThat(entry.entry.value.dataType).isEqualTo(Type.INT_DEC.code());
+ assertThat(entry.entry.value.dataType).isEqualTo(DataType.INT_DEC.code());
assertThat(entry.entry.value.data).isEqualTo(1000000);
}
@Test
public void testGetEntry_stringType() throws Exception {
- assertThat(resTable.getEntry(R.string.first_string, null).entry.value.dataType).isEqualTo(Type.STRING.code());
+ assertThat(resTable.getEntry(R.string.first_string, null).entry.value.dataType).isEqualTo(
+ DataType.STRING.code());
}
@Test
public void testGetEntry_boolType() throws Exception {
- assertThat(resTable.getEntry(R.bool.is_verizon, null).entry.value.dataType).isEqualTo(Type.INT_BOOLEAN.code());
+ assertThat(resTable.getEntry(R.bool.is_verizon, null).entry.value.dataType).isEqualTo(DataType.INT_BOOLEAN.code());
// Uncomment when we start selecting correct configuration
// assertThat(resTable.getEntry(R.bool.is_verizon, 0).value.dataType).isEqualTo(0);
}
diff --git a/robolectric/build.gradle b/robolectric/build.gradle
index c4e0ac4..5370af5 100644
--- a/robolectric/build.gradle
+++ b/robolectric/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
new RoboJavaModulePlugin(
diff --git a/sandbox/build.gradle b/sandbox/build.gradle
index da008de..371b11d 100644
--- a/sandbox/build.gradle
+++ b/sandbox/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
new RoboJavaModulePlugin(
diff --git a/shadowapi/build.gradle b/shadowapi/build.gradle
index f10e1d3..ebd519b 100644
--- a/shadowapi/build.gradle
+++ b/shadowapi/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
new RoboJavaModulePlugin(
diff --git a/shadows/framework/build.gradle b/shadows/framework/build.gradle
index c0da4f4..004b8fb 100644
--- a/shadows/framework/build.gradle
+++ b/shadows/framework/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
new RoboJavaModulePlugin(
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/Converter.java b/shadows/framework/src/main/java/org/robolectric/shadows/Converter.java
index 967f158..b11067d 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/Converter.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/Converter.java
@@ -37,7 +37,7 @@
case "fraction":
return new FromFraction();
default:
- throw new UnsupportedOperationException("Type not supported: " + type);
+ throw new UnsupportedOperationException("DataType not supported: " + type);
}
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager.java
index 9021611..be232b7 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager.java
@@ -47,7 +47,7 @@
} else {
invokeConstructor(AssetManager.class, realObject);
resTable = loadAppResTable();
- cppAssetManager = new CppAssetManager(this);
+ cppAssetManager = new CppAssetManager();
}
}
@@ -61,7 +61,7 @@
invokeConstructor(AssetManager.class, realObject,
ClassParameter.from(boolean.class, isSystem));
resTable = isSystem ? loadSystemResTable() : loadAppResTable();
- cppAssetManager = new CppAssetManager(this);
+ cppAssetManager = new CppAssetManager();
}
}
@@ -429,7 +429,7 @@
public int loadResourceValue(int ident, short density, TypedValue outValue, boolean resolve) {
if (outValue == null) {
throw new NullPointerException("outValue");
- return 0;
+ //return 0;
}
CppAssetManager am = assetManagerForJavaObject();
if (am == null) {
@@ -444,25 +444,43 @@
if (kThrowOnBadId) {
if (block == BAD_INDEX) {
throw new IllegalStateException("Bad resource!");
- return 0;
+ //return 0;
}
}
Ref<Integer> ref = new Ref<>(ident);
if (resolve) {
- block = res.resolveReference(value, block, ref, typeSpecFlags, config);
+ block = res.resolveReference(value.get(), block, ref, typeSpecFlags, config);
if (kThrowOnBadId) {
if (block == BAD_INDEX) {
throw new IllegalStateException("Bad resource!");
- return 0;
+ //return 0;
}
}
}
if (block >= 0) {
- return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
+ //return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
+ return copyValue(outValue, res, value.get(), ref.get(), block, typeSpecFlags.get(),
+ config.get());
+
}
- return static_cast<jint>(block);
+ return block;
}
+ int copyValue(TypedValue outValue, ResTable table, ResValue value, int ref, int block,
+ int typeSpecFlags, ResTableConfig config) {
+ outValue.type = value.dataType;
+ outValue.assetCookie = table.getTableCookie(block);
+ outValue.data = value.data;
+ outValue.string = null;
+ outValue.resourceId = ref;
+ outValue.changingConfigurations = typeSpecFlags;
+
+ if (config != null) {
+ outValue.density = config.density;
+ }
+ return block;
+ }
+
// /** Returns true if the resource was found, filling in mRetStringBlock and
// * mRetData. */
// private native final int loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue,
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypedArray.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypedArray.java
index 6311386..244d3c8 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypedArray.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypedArray.java
@@ -63,7 +63,7 @@
for (int index = 0; index < data.length; index+= ShadowAssetManager.STYLE_NUM_ENTRIES) {
final int type = data[index+ShadowAssetManager.STYLE_TYPE];
result.append("Index: ").append(index / ShadowAssetManager.STYLE_NUM_ENTRIES).append(System.lineSeparator());
- result.append(Strings.padEnd("Type: ", 25, ' ')).append(TYPE_MAP.get(type)).append(System.lineSeparator());
+ result.append(Strings.padEnd("DataType: ", 25, ' ')).append(TYPE_MAP.get(type)).append(System.lineSeparator());
if (type != TypedValue.TYPE_NULL) {
result.append(Strings.padEnd("Style data: ", 25, ' ')).append(data[index+ ShadowAssetManager.STYLE_DATA]).append(System.lineSeparator());
result.append(Strings.padEnd("Asset cookie ", 25, ' ')).append(data[index+ShadowAssetManager.STYLE_ASSET_COOKIE]).append(System.lineSeparator());
diff --git a/shadows/httpclient/build.gradle b/shadows/httpclient/build.gradle
index cf1492a..97396d4 100644
--- a/shadows/httpclient/build.gradle
+++ b/shadows/httpclient/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
new RoboJavaModulePlugin(
diff --git a/shadows/httpclient/src/main/java/org/robolectric/shadows/httpclient/TestHttpResponse.java b/shadows/httpclient/src/main/java/org/robolectric/shadows/httpclient/TestHttpResponse.java
index 8cc8fa9..6e5320c 100644
--- a/shadows/httpclient/src/main/java/org/robolectric/shadows/httpclient/TestHttpResponse.java
+++ b/shadows/httpclient/src/main/java/org/robolectric/shadows/httpclient/TestHttpResponse.java
@@ -193,7 +193,7 @@
}
@Override public Header getContentType() {
- return getFirstHeader("Content-Type");
+ return getFirstHeader("Content-DataType");
}
@Override public Header getContentEncoding() {
diff --git a/shadows/httpclient/src/test/java/org/robolectric/shadows/httpclient/ShadowDefaultRequestDirectorTest.java b/shadows/httpclient/src/test/java/org/robolectric/shadows/httpclient/ShadowDefaultRequestDirectorTest.java
index 59fd721..ccca270 100644
--- a/shadows/httpclient/src/test/java/org/robolectric/shadows/httpclient/ShadowDefaultRequestDirectorTest.java
+++ b/shadows/httpclient/src/test/java/org/robolectric/shadows/httpclient/ShadowDefaultRequestDirectorTest.java
@@ -288,7 +288,7 @@
@Test
public void shouldSupportBasicResponseHandlerHandleResponse() throws Exception {
- FakeHttp.addPendingHttpResponse(200, "OK", new BasicHeader("Content-Type", "text/plain"));
+ FakeHttp.addPendingHttpResponse(200, "OK", new BasicHeader("Content-DataType", "text/plain"));
DefaultHttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(new HttpGet("http://www.nowhere.org"));
diff --git a/shadows/maps/build.gradle b/shadows/maps/build.gradle
index 864a947..0b168f2 100644
--- a/shadows/maps/build.gradle
+++ b/shadows/maps/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
new RoboJavaModulePlugin(
diff --git a/shadows/multidex/build.gradle b/shadows/multidex/build.gradle
index 57e2757..b29dace 100644
--- a/shadows/multidex/build.gradle
+++ b/shadows/multidex/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
new RoboJavaModulePlugin(
diff --git a/shadows/playservices/build.gradle b/shadows/playservices/build.gradle
index 26863f0..14e9905 100644
--- a/shadows/playservices/build.gradle
+++ b/shadows/playservices/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
new RoboJavaModulePlugin(
diff --git a/shadows/supportv4/build.gradle b/shadows/supportv4/build.gradle
index e131eb2..7d0f13f 100644
--- a/shadows/supportv4/build.gradle
+++ b/shadows/supportv4/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
new RoboJavaModulePlugin(
diff --git a/utils/build.gradle b/utils/build.gradle
index 80c5894..2257849 100644
--- a/utils/build.gradle
+++ b/utils/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id "net.ltgt.errorprone" version "0.0.10"
+ //id "net.ltgt.errorprone" version "0.0.11"
}
new RoboJavaModulePlugin(