boolean scanAndMergeZipLocked()

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;

  }