resources/src/main/java/org/robolectric/res/android/CppAssetManager.java
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;

  }
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;

  }
/*
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.