ResourceFinder ( rn-find )

Righteo. Here’s to 2015 and my ability to write things on an infrequent basis.

*rummages through old code*

Here’s some possibly buggy code that someone else might find useful. It’s called ResourceFinder (a.k.a. rn-find ) and it finds resources [1].

Preamble

It’s a bit like the unix ‘find‘ command, except that it will also descend within archive files (currently, just .zip and .zip-like archives; e.g. .jar, .war, .ear, .har (not those hars, these hars) and .rar (not those rars, these rars).

This is handy since Java uses the zip format for packaging most things, and third-party indexers, if they support searching zip files, are usually out-of-date as soon as you recompile or redeploy things, which is fairly often.

It’s in the randomnoun common-public JAR as of version 0.2.2, which you can download from this page or the over here and copy into c:\util\java or /usr/local/java depending on your OS, together with log4j-good-bits.

common-public
com.randomnoun.common:common-public

I usually run it from a command-line using a .cmd or .sh wrapper, which sets up the classpath and invokes the CLI class.

If you’re on Windows, pop this in, say, c:\util\bin, and then add that to your PATH:

rn-find.cmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@echo off
rem rn-find.cmd
rem $Id$
rem
rem Shortcut to ResourceFinder java class
rem This batch file will use either the latest Eclipse workspace ResourceFinder class; 
rem or the released class. (See CLASSPATH below).
 
set JAVA_HOME=C:\Java\jdk1.7.0_60
 
set CLASSPATH=

rem ResourceFinder in current Eclipse workspace:
rem set CLASSPATH=%CLASSPATH%;C:\Users\knoxg\workspace-4.4.1-sts-3.6.2-rn\common\target\classes
rem set CLASSPATH=%CLASSPATH%;C:\Users\knoxg\.m2\repository\log4j\log4j\1.2.15\log4j-1.2.15.jar

rem ResourceFinder in latest release:
set CLASSPATH=%CLASSPATH%;c:\util\java\common-public-0.2.1.jar
set CLASSPATH=%CLASSPATH%;c:\util\java\log4j-1.2.15.jar
 
%JAVA_HOME%\bin\java -cp "%CLASSPATH%" com.randomnoun.common.ResourceFinder %1 %2 %3 %4 %5 %6 %7 %8 %9

Or if you use linux, put this in /usr/local/bin instead (and chmod +x it):

rn-find
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/bin/bash
#
# rn-find
# $Id$
#
# Shortcut to ResourceFinder java class
# This shell script will use either the latest Eclipse workspace ResourceFinder class; 
# or the released class. (See CLASSPATH below).
#
# To retrieve this JAR, run
#   wget http://central.maven.org/maven2/com/randomnoun/common/common-public/0.2.1/common-public-0.2.1.jar
 
JAVA_HOME=/cygdrive/c/Java/jdk1.7.0_60
 
CLASSPATH=
 
# ResourceFinder in current Eclipse workspace:
# CLASSPATH="${CLASSPATH};C:/Users/knoxg/workspace-4.4.1-sts-3.6.2-rn/common-public/target/classes"
# CLASSPATH="${CLASSPATH};C:/Users/knoxg/.m2/repository/log4j/log4j/1.2.15/log4j-1.2.15.jar"
 
# ResourceFinder in latest release:
CLASSPATH="${CLASSPATH};c:\util\java\common-public-0.2.1.jar"
CLASSPATH="${CLASSPATH};c:\util\java\log4j-1.2.15.jar"
 
${JAVA_HOME}/bin/java -cp "${CLASSPATH}" com.randomnoun.common.ResourceFinder "$@"

If you run it without any command-line parameters, you get a short usage description:

C:\Users\knoxg> c:\util\bin\rn-find
Usage: 
  java com.randomnoun.common.ResourceFinder [options] searchTerm
or
  java com.randomnoun.common.ResourceFinder [options] -a
where [options] are:
 -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

* A maximum of one -d switch should be present
* The -d and -c switches are mutually exclusive

Exception in thread "main" java.lang.IllegalArgumentException: Expected resource search term or options
	at com.randomnoun.common.ResourceFinder.main(ResourceFinder.java:1102)

A few use-cases are probably in order then:

Default search

With just a searchTerm argument, this will search all files in the current working directory and any subdirectories for files that contain the searchTerm (in the example below, the word ‘mushroom’ in lower case).

Each file will displayed one per line, with a 0-based index shown at the start of the line; e.g.

c:\some\path> rn-find mushroom
[0] mushroom.bat
[1] java/mushroom.jar
[2] java/mushroom.jar#recipes.jar#mushroom.txt
[3] java/mushroom.jar#recipes.jar#mushroom.png

You’ll notice that files contained within archives have a ‘#‘ character between the archive name and the contained filename; also that archives can be contained in archives (to any depth).

Case-insensitive search

if you want case-insensitivity, add the -i flag:

knoxg@bnedev03:/ooh/now/im/on/linux$ rn-find -i mushroom
[0] mushroom.bat
[1] java/mushroom.jar
[2] java/mushroom.jar#com/example/contrived/recipes/OmeletteWithMushroom.class
[3] java/mushroom.jar#recipes.jar#mushroom.txt
[4] java/mushroom.jar#recipes.jar#mushroom.png

Display resource contents

If you want to see what’s in the mushroom.txt file above (contained two archives deep), use the -d flag:

$ # display the contents of the file next to the [3] marker
$ rn-find -d 3 -i mushroom
This is what's in the mushroom.txt file.

Mushrooms are small, round, and can be used in many popular dishes. 
In ASCII form, they look like this:

    _______
   /_     _\
     (___)

You’ll notice the index and filename are suppressed when the -d flag is used, which will prevent corruption of binary files if piped to a file:

$ # extract the PNG file into the /tmp directory
$ rn-find -d 4 -i mushroom > /tmp/mushroom.png

Display decompiled java source

Back in the day, if you wanted to decompile a .class file into something .java-ish, you could use the -dj flag instead of -d:

$ # decompile the OmeletteWithMushroom.class file
$ rn-find -dj 2 -i mushroom
# jad output would appear here

This used to work providing jad was located on your PATH, but since jad hasn’t tracked any recent changes to the java bytecode specification (it’s broken from about 1.5 on, from memory); and the more recent JD decompiler (and CLI wrapper ) doesn’t seem to work at all, you can probably forget about decompiling until that’s fixed.

Search resource contents

If you want to search within the content of the files, use the -c flag (or for a case-insensitive content search use the -ci flag); e.g. to search for the word ‘round‘ inside files having filenames that contain the word ‘mushroom‘, then:

$ rn-find -ci round -i mushroom
[3] [line 3, col 21] java/mushroom.jar#recipes.jar#mushroom.txt

Display resource metadata

If you want to list the files with their filesizes and last modified timestamps, use the use the -v flag, and to add SHA1/MD5 hashes, use the -vv flag:

$ rn-find -vv -i mushroom
[0] mushroom.bat 28391 1/12/2014 03:15:22 4c02e2a5578ae4fb67b4aa77ec7532f9 dcfd5d26ca449e547b1fe96716627f8069fa6b16
[1] java/mushroom.jar 1/12/2014 03:18:15 9ab5bcbcf8a02054d75ad5213417d82a 1504e60a50523b9ecfc820a258e1a9294fa32129
[2] java/mushroom.jar#com/example/contrived/recipes/OmeletteWithMushroom.class 1/12/2014 03:15:22 bff90b08ced5a9640cd6be8b6a6255ba 23ac63d8a57946a17be06b5e79c96269c8ae96bc
[3] java/mushroom.jar#recipes.jar#mushroom.txt 1/12/2014 03:24:26 bbbf9b5f668cc6b2f33126633be3e8f9 237c2245439b8b5b27bb13aa6a9e9b8471dc4347
[4] java/mushroom.jar#recipes.jar#mushroom.png 1/12/2014 03:28:11 fb338b621aa80636f3f78b9a2538853d 35d6fe8c4ff25053ce6b03526d49690f2eb3a649

Regular expression search

You can modify the searchTerm (‘mushroom’) to be a regular expression by adding the ‘sr’ flag:

$ rn-find -sr -i mushro+m    # one or more oh's in mushrooooom
[0] mushroom.bat
[1] embedded/mushrom.rom
[2] java/mushroom.jar
[3] java/mushroom.jar#com/example/contrived/recipes/OmeletteWithMushroom.class
[4] java/mushroom.jar#recipes.jar#mushroom.txt

Show all files

And you can display the name of all files by using the -a flag and omitting the searchTerm

$ rn-find -a
[0] COPYRIGHT
[1] LICENCE
[2] mario.exe
[3] mushroom.bat
[4] embedded/mushrom.rom
[5] java/mushroom.jar
[6] java/mushroom.jar#com/example/contrived/recipes/OmeletteWithMushroom.class
[7] java/mushroom.jar#recipes.jar#mushroom.txt

Postamble

So anyway, that’s the guts of it. There’s a few other switches for other search types, dealing with errors, manifest unmangling, but 90% of the time you’ll probably be searching for file names or content within the file.

If you like, why not run it over your entire filesystem every morning at 3am or so, pipe that to a file, and then use grep to find things slightly faster. Like locate does.

If you include the MD5/SHA1 hashes as well you could write a script to detect people changing files on your filesystem, which you could then build a $710 million company around.


Update 12/1/2015 bumped common-public version to 0.2.2 (removed logging, fixed content search)

[1] ‘resources’ in the Java sense; i.e. anything you might find on a CLASSPATH.

Add a Comment

Your email address will not be published. Required fields are marked *