in resources/src/main/java/org/robolectric/res/android/CppAssetManager.java [1246:1374]
boolean scanAndMergeZipLocked(Ref<SortedVector<AssetDir.FileInfo>> pMergedInfo,
final asset_path ap, final String rootDir, final String baseDirName) {
ZipFileRO pZip;
List<String8> dirs = new ArrayList<>();
//AssetDir.FileInfo info = new FileInfo();
SortedVector<AssetDir.FileInfo> contents = new SortedVector<>();
String8 sourceName;
String8 zipName;
String8 dirName = new String8();
pZip = mZipSet.getZip(ap.path.string());
if (pZip == null) {
ALOGW("Failure opening zip %s\n", ap.path.string());
return false;
}
zipName = ZipSet.getPathName(ap.path.string());
/* convert "sounds" to "rootDir/sounds" */
if (rootDir != null) {
dirName = new String8(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();
final Ref<Enumeration<? extends ZipEntry>> iterationCookie = new Ref<>(null);
if (!pZip.startIteration(iterationCookie, dirName.string(), null)) {
ALOGW("ZipFileRO.startIteration returned false");
return false;
}
ZipEntryRO entry;
while ((entry = pZip.nextEntry(iterationCookie.get())) != null) {
final Ref<String> nameBuf = new Ref<>(null);
if (pZip.getEntryFileName(entry, nameBuf) != 0) {
// TODO: fix this if we expect to have long names
ALOGE("ARGH: name too long?\n");
continue;
}
// System.out.printf("Comparing %s in %s?\n", nameBuf.get(), dirName.string());
if (!nameBuf.get().startsWith(dirName.string() + '/')) {
// not matching
continue;
}
if (dirNameLen == 0 || nameBuf.get().charAt(dirNameLen) == '/') {
int cp = 0;
int nextSlashIndex;
//cp = nameBuf + dirNameLen;
cp += dirNameLen;
if (dirNameLen != 0) {
cp++; // advance past the '/'
}
nextSlashIndex = nameBuf.get().indexOf('/', cp);
//xxx this may break if there are bare directory entries
if (nextSlashIndex == -1) {
/* this is a file in the requested directory */
String8 fileName = new String8(nameBuf.get()).getPathLeaf();
if (fileName.string().isEmpty()) {
// ignore
continue;
}
AssetDir.FileInfo info = new FileInfo();
info.set(fileName, FileType.kFileTypeRegular);
info.setSourceName(
createZipSourceNameLocked(zipName, dirName, info.getFileName()));
contents.add(info);
//printf("FOUND: file '%s'\n", info.getFileName().string());
} else {
/* this is a subdir; add it if we don't already have it*/
String8 subdirName = new String8(nameBuf.get().substring(cp, nextSlashIndex));
int j;
int N = dirs.size();
for (j = 0; j < N; j++) {
if (subdirName.equals(dirs.get(j))) {
break;
}
}
if (j == N) {
dirs.add(subdirName);
}
//printf("FOUND: dir '%s'\n", subdirName.string());
}
}
}
pZip.endIteration(iterationCookie);
/*
* Add the set of unique directories.
*/
for (int i = 0; i < dirs.size(); i++) {
AssetDir.FileInfo info = new FileInfo();
info.set(dirs.get(i), kFileTypeDirectory);
info.setSourceName(
createZipSourceNameLocked(zipName, dirName, info.getFileName()));
contents.add(info);
}
mergeInfoLocked(pMergedInfo, contents);
return true;
}