@Trivial
    public static Map<String, IteratorData> collectIteratorData(ZipEntryData[] zipEntryData) {
        Map<String, IteratorData> allNestingData = new HashMap<String, IteratorData>();

        // Re-use offset lists.  There can be a lot of these
        // created for a busy tree.  Offset lists are only needed
        // for entries from the current entry back to the root.

        List<List<Integer>> offsetsStorage = new ArrayList<List<Integer>>(32);

        String r_lastPath = ""; // Root
        int r_lastPathLen = 0;

        List<Integer> offsets = EMPTY_OFFSETS;

        int nestingDepth = 0;

        List<String> r_pathStack = new ArrayList<String>(32);
        List<List<Integer>> offsetsStack = new ArrayList<List<Integer>>(32);

        for ( int nextOffset = 0; nextOffset < zipEntryData.length; nextOffset++ ) {
            String r_nextPath = zipEntryData[nextOffset].r_getPath();
            int r_nextPathLen = r_nextPath.length();

            // The next path may be on a different branch.
            //
            // Backup until a common branch is located, emitting nesting data
            // for each branch we cross.

            while ( !isChildOf(r_nextPath, r_nextPathLen, r_lastPath, r_lastPathLen) ) {
                if ( offsets != EMPTY_OFFSETS ) {
                    allNestingData.put(
                        r_lastPath,
                        new IteratorData( r_lastPath, releaseOffsets(offsetsStorage, offsets) ) );
                }

                nestingDepth--;
                r_lastPath = r_pathStack.remove(nestingDepth);
                r_lastPathLen = r_lastPath.length();
                offsets = offsetsStack.remove(nestingDepth);
            }

            // The entry is now guaranteed to be on the
            // same branch as the last entry.
            //
            // But, the entry be more than one nesting level
            // deeper than the last entry.
            //
            // Create and add new offset collections for each
            // new nesting level.  There may be additional
            // entries for the new nesting levels besides the
            // entry.

            Integer nextOffsetObj = Integer.valueOf(nextOffset);

            int lastSlashLoc = r_lastPathLen + 1;
            while ( lastSlashLoc != -1 ) {
                int nextSlashLoc = r_nextPath.indexOf('/', lastSlashLoc);
                String r_nextPartialPath;
                int r_nextPartialPathLen;
                if ( nextSlashLoc == -1 ) {
                    r_nextPartialPath = r_nextPath;
                    r_nextPartialPathLen = r_nextPathLen;
                    lastSlashLoc = nextSlashLoc;
                } else {
                    r_nextPartialPath = r_nextPath.substring(0, nextSlashLoc);
                    r_nextPartialPathLen = nextSlashLoc;
                    lastSlashLoc = nextSlashLoc + 1;
                }

                if ( offsets == EMPTY_OFFSETS ) {
                    offsets = allocateOffsets(offsetsStorage);
                }
                offsets.add(nextOffsetObj);

                nestingDepth++;
                r_pathStack.add(r_lastPath);
                offsetsStack.add(offsets);

                r_lastPath = r_nextPartialPath;
                r_lastPathLen = r_nextPartialPathLen;

                offsets = EMPTY_OFFSETS;
            }
        }

        // Usually, we are left some nestings beneath the root.
        //
        // Finish off each of those nestings.

        while ( nestingDepth > 0 ) {
            if ( offsets != EMPTY_OFFSETS ) {
                allNestingData.put(
                    r_lastPath,
                    new IteratorData( r_lastPath, releaseOffsets(offsetsStorage, offsets) ) );
            }
            nestingDepth--;
            r_lastPath = r_pathStack.remove(nestingDepth);
            offsets = offsetsStack.remove(nestingDepth);
        }

        // If root data remains, finish that off too.

        if ( offsets != EMPTY_OFFSETS ) {
            allNestingData.put(
                r_lastPath,
                new IteratorData( r_lastPath, releaseOffsets(offsetsStorage, offsets) ) );
        }

        return allNestingData;
    }
@ Trivial public static Map < String , IteratorData > collectIteratorData ( ZipEntryData [ ] zipEntryData ) { Map < String , IteratorData > allNestingData = new HashMap < String , IteratorData > ( ) ; List < List < Integer > > offsetsStorage = new ArrayList < List < Integer > > ( 32 ) ; String r_lastPath = "" ; int r_lastPathLen = 0 ; List < Integer > offsets = EMPTY_OFFSETS ; int nestingDepth = 0 ; List < String > r_pathStack = new ArrayList < String > ( 32 ) ; List < List < Integer > > offsetsStack = new ArrayList < List < Integer > > ( 32 ) ; for ( int nextOffset = 0 ; nextOffset < zipEntryData . length ; nextOffset ++ ) { String r_nextPath = zipEntryData [ nextOffset ] . r_getPath ( ) ; int r_nextPathLen = r_nextPath . length ( ) ; while ( ! isChildOf ( r_nextPath , r_nextPathLen , r_lastPath , r_lastPathLen ) ) { if ( offsets != EMPTY_OFFSETS ) { allNestingData . put ( r_lastPath , new IteratorData ( r_lastPath , releaseOffsets ( offsetsStorage , offsets ) ) ) ; } nestingDepth -- ; r_lastPath = r_pathStack . remove ( nestingDepth ) ; r_lastPathLen = r_lastPath . length ( ) ; offsets = offsetsStack . remove ( nestingDepth ) ; } Integer nextOffsetObj = Integer . valueOf ( nextOffset ) ; int lastSlashLoc = r_lastPathLen + 1 ; while ( lastSlashLoc != - 1 ) { int nextSlashLoc = r_nextPath . indexOf ( '/' , lastSlashLoc ) ; String r_nextPartialPath ; int r_nextPartialPathLen ; if ( nextSlashLoc == - 1 ) { r_nextPartialPath = r_nextPath ; r_nextPartialPathLen = r_nextPathLen ; lastSlashLoc = nextSlashLoc ; } else { r_nextPartialPath = r_nextPath . substring ( 0 , nextSlashLoc ) ; r_nextPartialPathLen = nextSlashLoc ; lastSlashLoc = nextSlashLoc + 1 ; } if ( offsets == EMPTY_OFFSETS ) { offsets = allocateOffsets ( offsetsStorage ) ; } offsets . add ( nextOffsetObj ) ; nestingDepth ++ ; r_pathStack . add ( r_lastPath ) ; offsetsStack . add ( offsets ) ; r_lastPath = r_nextPartialPath ; r_lastPathLen = r_nextPartialPathLen ; offsets = EMPTY_OFFSETS ; } } while ( nestingDepth > 0 ) { if ( offsets != EMPTY_OFFSETS ) { allNestingData . put ( r_lastPath , new IteratorData ( r_lastPath , releaseOffsets ( offsetsStorage , offsets ) ) ) ; } nestingDepth -- ; r_lastPath = r_pathStack . remove ( nestingDepth ) ; offsets = offsetsStack . remove ( nestingDepth ) ; } if ( offsets != EMPTY_OFFSETS ) { allNestingData . put ( r_lastPath , new IteratorData ( r_lastPath , releaseOffsets ( offsetsStorage , offsets ) ) ) ; } return allNestingData ; }
Collect the iterator data for a collection of zip entries.

Keys of the entries must be paths stripped of leading and trailing slashes.

The entries must be in ascending order per {@link PathUtils#PATH_COMPARATOR}.

Only place data for paths which have no children.  In particular, leaf entries,
which should be most of the entries of the enclosing zip file, have no children.

See {@link IteratorData} for additional details.

@param zipEntryData The data for which to collect iterator data.

@return A table of iterator data for the zip entries.