public void enumerate() throws IOException { final IPathHandler handler = m_handler; for (m_pathIndex = 0; m_pathIndex < m_path.size(); ++m_pathIndex) // important not to cache m_path.size() { final File f = (File) m_path.get(m_pathIndex); if (!f.exists()) { if (IGNORE_INVALID_ENTRIES) continue; else throw new IllegalArgumentException("path entry does not exist: [" + f + "]"); } if (f.isDirectory()) { if (m_verbose) m_log.verbose("processing dir path entry [" + f.getAbsolutePath() + "] ..."); m_currentPathDir = f; enumeratePathDir(null); } else { final String name = f.getName(); final String lcName = name.toLowerCase(); if (lcName.endsWith(".zip") || lcName.endsWith(".jar")) { if (m_verbose) m_log.verbose("processing archive path entry [" + f.getAbsolutePath() + "] ..."); final File parent = f.getParentFile(); // could be null final File archive = new File(name); m_currentPathDir = parent; // move to enumeratePathArchive(): handler.handleArchiveStart (parent, archive); enumeratePathArchive(name); handler.handleArchiveEnd( parent, archive); // note: it is important that this is called after the zip stream has // been closed } else if (!IGNORE_INVALID_ENTRIES) { throw new IllegalArgumentException( "path entry is not a directory or an archive: [" + f + "]"); } } } }
private void enumeratePathDir(final String dir) throws IOException { final boolean trace1 = m_trace1; final File currentPathDir = m_currentPathDir; final File fullDir = dir != null ? new File(currentPathDir, dir) : currentPathDir; final String[] children = fullDir.list(); final IPathHandler handler = m_handler; for (int c = 0, cLimit = children.length; c < cLimit; ++c) { final String childName = children[c]; final File child = dir != null ? new File(dir, childName) : new File(childName); final File fullChild = new File(fullDir, childName); if (fullChild.isDirectory()) { handler.handleDirStart(currentPathDir, child); if (trace1) m_log.trace1("enumeratePathDir", "recursing into [" + child.getName() + "] ..."); enumeratePathDir(child.getPath()); handler.handleDirEnd(currentPathDir, child); } else { // final String lcName = childName.toLowerCase (); // // if (lcName.endsWith (".zip") || lcName.endsWith (".jar")) // { // handler.handleArchiveStart (currentPathDir, child); // enumeratePathArchive (child.getPath ()); // handler.handleArchiveEnd (currentPathDir, child); // } // else { if (trace1) m_log.trace1("enumeratePathDir", "processing file [" + child.getName() + "] ..."); handler.handleFile(currentPathDir, child); } } } }
private void enumeratePathArchive(final String archive) throws IOException { final boolean trace1 = m_trace1; final File fullArchive = new File(m_currentPathDir, archive); JarInputStream in = null; try { // note: Sun's JarFile uses native code and has been known to // crash the JVM in some builds; however, it uses random file // access and can find "bad" manifests that are not the first // entries in their archives (which JarInputStream can't do); // [bugs: 4263225, 4696354, 4338238] // // there is really no good solution here but as a compromise // I try to read the manifest again via a JarFile if the stream // returns null for it: in = new JarInputStream( new BufferedInputStream(new FileInputStream(fullArchive), 32 * 1024)); final IPathHandler handler = m_handler; Manifest manifest = in.getManifest(); // can be null if (manifest == null) manifest = readManifestViaJarFile(fullArchive); // can be null handler.handleArchiveStart(m_currentPathDir, new File(archive), manifest); // note: this loop does not skip over the manifest-related // entries [the handler needs to be smart about that] for (ZipEntry entry; (entry = in.getNextEntry()) != null; ) { // TODO: handle nested archives if (trace1) m_log.trace1( "enumeratePathArchive", "processing archive entry [" + entry.getName() + "] ..."); handler.handleArchiveEntry(in, entry); in.closeEntry(); } // TODO: this needs major testing if (m_processManifest) { // note: JarInputStream only reads the manifest if it the // first jar entry if (manifest == null) manifest = in.getManifest(); if (manifest != null) { final Attributes attributes = manifest.getMainAttributes(); if (attributes != null) { // note: Sun's documentation says that multiple Class-Path: // entries are merged sequentially // (http://java.sun.com/products/jdk/1.2/docs/guide/extensions/spec.html) // however, their own code does not implement this final String jarClassPath = attributes.getValue(Attributes.Name.CLASS_PATH); if (jarClassPath != null) { final StringTokenizer tokenizer = new StringTokenizer(jarClassPath); for (int p = 1; tokenizer.hasMoreTokens(); ) { final String relPath = tokenizer.nextToken(); final File archiveParent = fullArchive.getParentFile(); final File path = archiveParent != null ? new File(archiveParent, relPath) : new File(relPath); final String fullPath = m_canonical ? Files.canonicalizePathname(path.getPath()) : path.getPath(); if (m_pathSet.add(fullPath)) { if (m_verbose) m_log.verbose(" added manifest Class-Path entry [" + path + "]"); m_path.add( m_pathIndex + (p++), path); // insert after the current m_path entry } } } } } } } catch (FileNotFoundException fnfe) // ignore: this should not happen { if ($assert.ENABLED) throw fnfe; } finally { if (in != null) try { in.close(); } catch (Exception ignore) { } } }