Class ResourceFinder

java.lang.Object
com.randomnoun.common.ResourceFinder

public class ResourceFinder extends Object
Find a resource recursively through all JARs, EARs, WARs, etc from the current directory down.

Command-line usage

The following command-line arguments are recognised

Usage
-h -? displays this helptext
-f follow symlinks
-a show all resources found (i.e. do not use searchTerm)
Search criteria:
-i case-insensitive match
-sc if present, searchTerm matches within filename (default)
-ss if present, searchTerm matches start of filename
-se if present, searchTerm matches exact filename
-sr if present, searchTerm matches filename as a regular expression
-mf n max filesystem folder depth (0 = do not descend into subfolders)
-ma n max archive depth (0 = do not descend into archives)
-x if present, will attempt to recover if errors occur reading archives (errors sent to stderr)
Action when resource found:
-v verbose; display filenames with file sizes and timestamps
-vv display MD5/SHA1 hashes of resources (NB: modifies display order)
-d n dump/display the contents of the n'th resource found
-d all dump the name and contents of all resources found
-d names dump just the names of all resources found (default)
-d n1,n2...dump the name and contents of the n1'th, n2'nd etc... resources found
-dm n|all as per -d, but performs manifest unmangling on resource (fixes linewraps)
-dj n|all as per -d, but performs class decompiling (requires jad to be in PATH)
-c text search for text in contents of resource (uses UTF-8 encoding)
-ci text case-insensitive search for text in contents of resources

TODO split CLI functionality into separate class

TODO pass enough information to the callback classes to display somewhat sane progress bar

TODO fix -dj switch + handle inner classes

TODO rewrite jad to deal with annotations and other 1.5+ crap

TODO -cs switches to change search behaviour within content

Author:
knoxg
  • Field Details

    • MATCHTYPE_CONTAINS

      public static final int MATCHTYPE_CONTAINS
      Match type used in matches(String)} comparisons that tests whether the last component of a resource name contains a specified string; e.g. "abc/def.txt" will match against the searchTerm "ef" using this matchType.
      See Also:
    • MATCHTYPE_STARTSWITH

      public static final int MATCHTYPE_STARTSWITH
      Match type used in matches(String)} comparisons that tests whether the last component of a resource name starts with a specified string; e.g. "abc/def.txt" will match against the searchTerm "de" using this matchType.
      See Also:
    • MATCHTYPE_EXACT

      public static final int MATCHTYPE_EXACT
      Match type used in matches(String)} comparisons that tests whether the last component of a resource name is equal to a specified regular expression; e.g. "abc/def.txt" will match against the searchTerm "def.txt" using this matchType.
      See Also:
    • MATCHTYPE_REGEX

      public static final int MATCHTYPE_REGEX
      Match type used in matches(String)} comparisons that tests whether the last component of a resource name matches a specified regular expression; e.g. "abc/def.txt" will match against the searchTerm ".*e.*" using this matchType.
      See Also:
  • Constructor Details

    • ResourceFinder

      public ResourceFinder(String searchTerm, int matchType, boolean ignoreCase, File startDirectory, ResourceFinder.ResourceFinderCallback callback) throws IOException
      Creates a new resource finder object
      Parameters:
      searchTerm - resource being searched for
      matchType - a MATCHTYPE_* constant denoting how the searchTerm is to be used to match against resource names
      ignoreCase - if true, will perform a case insensitive search
      startDirectory - directory from which search begins
      callback - callback to be invoked on every resource that matches the search criteria
      Throws:
      IOException - if the start directory is invalid
    • ResourceFinder

      public ResourceFinder(String searchTerm, int matchType, boolean ignoreCase, ZipInputStream startInputStream, ResourceFinder.ResourceFinderCallback callback) throws IOException
      Creates a new resource finder object
      Parameters:
      searchTerm - resource being searched for
      matchType - a MATCHTYPE_* constant denoting how the searchTerm is to be used to match against resource names
      ignoreCase - if true, will perform a case insensitive search
      startInputStream - stream from which search begins
      callback - callback to be invoked on every resource that matches the search criteria
      Throws:
      IOException - if the start directory is invalid
  • Method Details

    • abort

      public void abort()
      Call this method within a ResourceFinder.ResourceFinderCallback to stop looking for resources
    • getStartDirectory

      Return the file or directory from which search begins. If this returns null, try getStartInputStream()
    • getStartInputStream

      Return the ZipInputStream from which search begins. If this returns null, try getStartDirectory()
    • matches

      public boolean matches(String resourceName)
      Tests a resource name against the search criteria specified in this object
      Parameters:
      resourceName - the last component of a resource name
      Returns:
      true if the resource passes the search criteria, false otherwise
    • setFollowSymLinks

      public void setFollowSymLinks(boolean followSymlinks)
      Sets whether to follow symbolic links during filesystem scans. By default symlinks will not be followed.
      Parameters:
      followSymlinks - true if symbolic links should be followed during filesystem scans, false otherwise
      See Also:
    • getFollowSymlinks

      public boolean getFollowSymlinks()
      Returns whether symbolic links will be followed during filesystem scans
      Returns:
      whether symbolic links will be followed during filesystem scans
      See Also:
    • setShowAll

      public void setShowAll(boolean showAll)
      Sets whether the ResourceFinderCallback should be invoked for every file in every archive iterated over (i.e. to ignore the searchTerm ). By default this flag is set to false.
      Parameters:
      showAll - if true, will invoke the ResourceFinderCallback for every file in every archive iterated over
      See Also:
    • getShowAll

      public boolean getShowAll()
      Returns whether the ResourceFinderCallback will be invoked for every file in every archive iterated over
      Returns:
      true if the ResourceFinderCallback will be invoked for every file in every archive iterated over, false otherwise
      See Also:
    • setIgnoreErrors

      public void setIgnoreErrors(boolean ignoreErrors)
      Sets whether to ignore (some) exceptions encountered whilst processing ZipInputStreams.

      Only EOFExceptions, ZipExceptions, IllegalArgumentExceptions and the push-back buffer IOException will be ignored if this flag is set. Ignored exceptions will still be logged.

      By default, this flag is set to false.

      Parameters:
      ignoreErrors - true to ignore exceptions as described above, false otherwise
      See Also:
    • getIgnoreErrors

      public boolean getIgnoreErrors()
      Returns true if exceptions will be ignored whilst processing ZipInputStreams
      Returns:
      true if exceptions will be ignored whilst processing ZipInputStreams
      See Also:
    • find

      public void find() throws IOException
      Searches and returns a list of resources matching the criteria defined in the constructor

      TODO the list returned by this object probably isn't accurate.

      Throws:
      IOException
    • isArchive

      public boolean isArchive(String name)
      Returns true if the filename will be treated as an archive
      Parameters:
      name - a filename
      Returns:
      true if the file is an archive, false otherwise
    • isLink

      public static boolean isLink(File file) throws IOException
      Determines whether a file is a symbolic link. (Copied from http://www.idiom.com/~zilla/Xfiles/javasymlinks.html)
      Parameters:
      file - file to test
      Returns:
      true if the file is a symbolic link, false otherwise
      Throws:
      IOException
    • findResourceInFolder

      public void findResourceInFolder(File folder, String prefix) throws IOException
      Returns a list of resources within the supplied folder, subfolders, and archives contained within these folders
      Parameters:
      folder - the folder to search from
      prefix - a prefix which is included in any results returned by this method
      Throws:
      IOException
    • ignorableException

      public void ignorableException(String message, Exception e) throws ZipException
      If ignoreErrors is true, send a message to stderr with the exception message, otherwise throw an encapsulated ZipException
      Parameters:
      message - message describing exception
      e - cause of the exception
      Throws:
      ZipException
    • findResourceInZip

      public void findResourceInZip(ZipInputStream zipInputStream, String prefix) throws IOException
      Returns a list of resources within the supplied archive, and archives contained within this archive
      Parameters:
      zipInputStream - the archive to search
      prefix - a prefix which is included in any results returned by this method. By convention, this prefix should end with a '#' to separate it from resources found within the resource.
      Throws:
      IOException
    • getResourceStream

      public static InputStream getResourceStream(String resourceName) throws IOException
      Returns a resource as an inputstream
      Parameters:
      resourceName - a resource name, as defined by the class javadoc
      Returns:
      the resource as an InputStream
      Throws:
      FileNotFoundException - the resource could not be found
      IOException - the resource could not be read
    • getResourceComponent

      public static InputStream getResourceComponent(ZipInputStream zipInputStream, String component, String fullResource) throws IOException
      Private method to recursively search within an archive for a file
      Parameters:
      zipInputStream - input stream to search
      component - resource name fragment, separated by '#' characters
      fullResource - full resource name (only used in exception messages)
      Returns:
      the input stream
      Throws:
      IOException - the input stream cannot be read
    • setMaxArchiveDepth

      public void setMaxArchiveDepth(long maxArchiveDepth)
      Sets the maximum number of times I'm going to recursively enter a JAR/EAR/WAR/whatever.
      • 0 = none; i.e. will just perform a directory scan.
      • 1..n = will search up to n directories/archives deep
      • -1 = infinite; i.e. will not perform depth checking
      Parameters:
      maxArchiveDepth - maximum depth (-1=no limit, 0=will not recursive into JARs/WARs etc..)
    • setMaxFolderDepth

      public void setMaxFolderDepth(long maxFolderDepth)
      Sets the maximum folder depth to descend into the filesystem structure.

      This will not limit folder depth within archives, only folder depth within the filesystem

      This setting has no effect if using the InputStream constructor.

      • 0 = none; i.e. will just scan within the top-level folder.
      • 1..n = will search up to n folders deep
      • -1 = infinite; i.e. will not perform folder depth checking
      Parameters:
      maxFolderDepth - maximum depth (-1=no limit, 0=will not recurse into folders)
    • usage

      public static String usage()
    • main

      public static void main(String[] args) throws IOException
      Command-line interface to this class
      Parameters:
      args - arguments
      Throws:
      IOException