Resource File Types
File Header Magic Numbers still need to be implemented but it's a start
This commit is contained in:
parent
e16397ebd6
commit
c259ac70a2
10 changed files with 120 additions and 75 deletions
|
@ -1,5 +1,7 @@
|
||||||
package the.bytecode.club.bytecodeviewer;
|
package the.bytecode.club.bytecodeviewer;
|
||||||
|
|
||||||
|
import the.bytecode.club.bytecodeviewer.resources.ResourceType;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
|
|
||||||
|
@ -35,7 +37,7 @@ public class Constants
|
||||||
public static final String libsDirectory = getBCVDirectory() + fs + "libs" + fs;
|
public static final String libsDirectory = getBCVDirectory() + fs + "libs" + fs;
|
||||||
public static String krakatauWorkingDirectory = getBCVDirectory() + fs + "krakatau_" + krakatauVersion;
|
public static String krakatauWorkingDirectory = getBCVDirectory() + fs + "krakatau_" + krakatauVersion;
|
||||||
public static String enjarifyWorkingDirectory = getBCVDirectory() + fs + "enjarify_" + enjarifyVersion;
|
public static String enjarifyWorkingDirectory = getBCVDirectory() + fs + "enjarify_" + enjarifyVersion;
|
||||||
public static final String[] SUPPORTED_FILE_EXTENSIONS = new String[]{"jar", "zip", "class", "apk", "xapk", "dex", "war", "jsp"};
|
public static final String[] SUPPORTED_FILE_EXTENSIONS = ResourceType.supportedBCVExtensionMap.keySet().toArray(new String[0]);
|
||||||
|
|
||||||
public static final PrintStream ERR = System.err;
|
public static final PrintStream ERR = System.err;
|
||||||
public static final PrintStream OUT = System.out;
|
public static final PrintStream OUT = System.out;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
|
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
||||||
|
import the.bytecode.club.bytecodeviewer.resources.ResourceType;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||||
|
@ -14,81 +16,42 @@ import java.util.ArrayList;
|
||||||
*/
|
*/
|
||||||
public class ImageRenderer extends DefaultTreeCellRenderer
|
public class ImageRenderer extends DefaultTreeCellRenderer
|
||||||
{
|
{
|
||||||
//called every time there is a pane update, I.E. whenever you expand a folder
|
//called every time there is a pane update
|
||||||
@Override
|
@Override
|
||||||
public Component getTreeCellRendererComponent(
|
public Component getTreeCellRendererComponent(
|
||||||
JTree tree, Object value,
|
JTree tree, Object value,
|
||||||
boolean sel, boolean expanded, boolean leaf,
|
boolean sel, boolean expanded, boolean leaf,
|
||||||
int row, boolean hasFocus)
|
int row, boolean hasFocus)
|
||||||
{
|
{
|
||||||
|
|
||||||
Component ret = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
|
Component ret = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
|
||||||
|
|
||||||
if (value instanceof ResourceTreeNode)
|
if (value instanceof ResourceTreeNode)
|
||||||
{
|
{
|
||||||
ResourceTreeNode node = (ResourceTreeNode) value;
|
ResourceTreeNode node = (ResourceTreeNode) value;
|
||||||
String name = node.toString().toLowerCase();
|
String name = node.toString().toLowerCase();
|
||||||
|
String onlyName = FilenameUtils.getName(name);
|
||||||
|
boolean iconSet = false;
|
||||||
|
|
||||||
if (name.endsWith(".jar") || name.endsWith(".war") || name.endsWith(".ear"))
|
//guess file type based on extension
|
||||||
|
ResourceType knownResourceType = onlyName.contains(":") ? null
|
||||||
|
: ResourceType.extensionMap.get(FilenameUtils.getExtension(onlyName).toLowerCase());
|
||||||
|
|
||||||
|
//set the icon to a known file type
|
||||||
|
if (knownResourceType != null)
|
||||||
{
|
{
|
||||||
setIcon(IconResources.jarIcon);
|
setIcon(knownResourceType.getIcon());
|
||||||
}
|
iconSet = true;
|
||||||
else if (name.endsWith(".zip"))
|
|
||||||
{
|
|
||||||
setIcon(IconResources.zipIcon);
|
|
||||||
}
|
|
||||||
else if (name.endsWith(".bat"))
|
|
||||||
{
|
|
||||||
setIcon(IconResources.batIcon);
|
|
||||||
}
|
|
||||||
else if (name.endsWith(".sh"))
|
|
||||||
{
|
|
||||||
setIcon(IconResources.shIcon);
|
|
||||||
}
|
|
||||||
else if (name.endsWith(".cs"))
|
|
||||||
{
|
|
||||||
setIcon(IconResources.csharpIcon);
|
|
||||||
}
|
|
||||||
else if (name.endsWith(".c") || name.endsWith(".cpp") || name.endsWith(".h"))
|
|
||||||
{
|
|
||||||
setIcon(IconResources.cplusplusIcon);
|
|
||||||
}
|
|
||||||
else if (name.endsWith(".xapk") || name.endsWith(".apk") || name.endsWith(".dex"))
|
|
||||||
{
|
|
||||||
setIcon(IconResources.androidIcon);
|
|
||||||
}
|
|
||||||
else if (name.endsWith(".png") || name.endsWith(".jpg") || name.endsWith(".jpeg")
|
|
||||||
|| name.endsWith(".bmp") || name.endsWith(".gif"))
|
|
||||||
{
|
|
||||||
setIcon(IconResources.imageIcon);
|
|
||||||
}
|
|
||||||
else if (name.endsWith(".class"))
|
|
||||||
{
|
|
||||||
setIcon(IconResources.classIcon);
|
|
||||||
}
|
|
||||||
else if (name.endsWith(".java"))
|
|
||||||
{
|
|
||||||
setIcon(IconResources.javaIcon);
|
|
||||||
}
|
|
||||||
else if (name.endsWith(".txt") || name.endsWith(".md"))
|
|
||||||
{
|
|
||||||
setIcon(IconResources.textIcon);
|
|
||||||
}
|
}
|
||||||
|
//hardcoded resource icons go here
|
||||||
else if (name.equals("decoded resources"))
|
else if (name.equals("decoded resources"))
|
||||||
{
|
{
|
||||||
setIcon(IconResources.decodedIcon);
|
setIcon(IconResources.decodedIcon);
|
||||||
|
iconSet = true;
|
||||||
}
|
}
|
||||||
else if (name.endsWith(".properties") || name.endsWith(".xml") || name.endsWith(".jsp")
|
|
||||||
|| name.endsWith(".mf") || name.endsWith(".config") || name.endsWith(".cfg"))
|
//folders
|
||||||
|
if (node.getChildCount() > 0)
|
||||||
{
|
{
|
||||||
setIcon(IconResources.configIcon);
|
|
||||||
}
|
|
||||||
else if (node.getChildCount() <= 0)
|
|
||||||
{ //random file
|
|
||||||
setIcon(IconResources.fileIcon);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ //folder
|
|
||||||
ArrayList<TreeNode> nodes = new ArrayList<>();
|
ArrayList<TreeNode> nodes = new ArrayList<>();
|
||||||
ArrayList<TreeNode> totalNodes = new ArrayList<>();
|
ArrayList<TreeNode> totalNodes = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -127,13 +90,19 @@ public class ImageRenderer extends DefaultTreeCellRenderer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!iconSet)
|
||||||
|
{
|
||||||
|
//java packages
|
||||||
if (isJava)
|
if (isJava)
|
||||||
setIcon(IconResources.packagesIcon);
|
setIcon(IconResources.packagesIcon);
|
||||||
else
|
else //regular folders
|
||||||
{
|
|
||||||
setIcon(IconResources.folderIcon);
|
setIcon(IconResources.folderIcon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//unknown files
|
||||||
|
else if (knownResourceType == null)
|
||||||
|
setIcon(IconResources.fileIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -7,6 +7,7 @@ import javax.swing.JButton;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.imgscalr.Scalr;
|
import org.imgscalr.Scalr;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||||
|
@ -14,6 +15,7 @@ import the.bytecode.club.bytecodeviewer.gui.components.ImageJLabel;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea;
|
import the.bytecode.club.bytecodeviewer.gui.components.SearchableRSyntaxTextArea;
|
||||||
import the.bytecode.club.bytecodeviewer.gui.hexviewer.JHexEditor;
|
import the.bytecode.club.bytecodeviewer.gui.hexviewer.JHexEditor;
|
||||||
import the.bytecode.club.bytecodeviewer.resources.ResourceContainer;
|
import the.bytecode.club.bytecodeviewer.resources.ResourceContainer;
|
||||||
|
import the.bytecode.club.bytecodeviewer.resources.ResourceType;
|
||||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||||
import the.bytecode.club.bytecodeviewer.util.SyntaxLanguage;
|
import the.bytecode.club.bytecodeviewer.util.SyntaxLanguage;
|
||||||
|
|
||||||
|
@ -70,14 +72,23 @@ public class FileViewer extends ResourceViewer
|
||||||
public void setContents()
|
public void setContents()
|
||||||
{
|
{
|
||||||
final String nameLowerCase = this.name.toLowerCase();
|
final String nameLowerCase = this.name.toLowerCase();
|
||||||
|
final String onlyName = FilenameUtils.getName(nameLowerCase);
|
||||||
final String contentsAsString = new String(contents);
|
final String contentsAsString = new String(contents);
|
||||||
|
|
||||||
//image viewer
|
//image viewer
|
||||||
if (!MiscUtils.isPureAscii(contentsAsString))
|
if (!MiscUtils.isPureAscii(contentsAsString))
|
||||||
{
|
{
|
||||||
//TODO webp?
|
//TODO:
|
||||||
if (nameLowerCase.endsWith(".png") || nameLowerCase.endsWith(".jpg") || nameLowerCase.endsWith(".jpeg") ||
|
// + Webp?
|
||||||
nameLowerCase.endsWith(".gif") || nameLowerCase.endsWith(".tif") || nameLowerCase.endsWith(".bmp"))
|
// + Add file header checks
|
||||||
|
// + Check for CAFEBABE
|
||||||
|
// + ClassRead then quick-decompile using Pane1 Decompiler
|
||||||
|
// (If none selected, try Pane2, Pane3, default to Proycon)
|
||||||
|
|
||||||
|
|
||||||
|
//check by file extension to display image
|
||||||
|
if (!onlyName.contains(":") &&
|
||||||
|
ResourceType.imageExtensionMap.containsKey(FilenameUtils.getExtension(onlyName)))
|
||||||
{
|
{
|
||||||
canRefresh = true;
|
canRefresh = true;
|
||||||
|
|
||||||
|
@ -101,9 +112,6 @@ public class FileViewer extends ResourceViewer
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//check for CAFEBABE
|
|
||||||
//ClassRead then quick-decompile using Pane1 Decompiler
|
|
||||||
// (If none selected, try Pane2, Pane3, default to Proycon)
|
|
||||||
|
|
||||||
//hex viewer
|
//hex viewer
|
||||||
else if (BytecodeViewer.viewer.forcePureAsciiAsText.isSelected())
|
else if (BytecodeViewer.viewer.forcePureAsciiAsText.isSelected())
|
||||||
|
|
|
@ -13,7 +13,6 @@ import org.objectweb.asm.tree.ClassNode;
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
import the.bytecode.club.bytecodeviewer.api.Plugin;
|
import the.bytecode.club.bytecodeviewer.api.Plugin;
|
||||||
import the.bytecode.club.bytecodeviewer.plugin.PluginLaunchStrategy;
|
import the.bytecode.club.bytecodeviewer.plugin.PluginLaunchStrategy;
|
||||||
import the.bytecode.club.bytecodeviewer.util.JarUtils;
|
|
||||||
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
import the.bytecode.club.bytecodeviewer.util.MiscUtils;
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
|
@ -88,7 +87,7 @@ public class CompiledJavaPluginLaunchStrategy implements PluginLaunchStrategy {
|
||||||
if (name.endsWith(".class"))
|
if (name.endsWith(".class"))
|
||||||
{
|
{
|
||||||
byte[] bytes = MiscUtils.getBytes(jis);
|
byte[] bytes = MiscUtils.getBytes(jis);
|
||||||
if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe"))
|
if (MiscUtils.getFileHeaderMagicNumber(bytes).equalsIgnoreCase("cafebabe"))
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
ClassReader cr = new ClassReader(bytes);
|
ClassReader cr = new ClassReader(bytes);
|
||||||
|
|
|
@ -104,7 +104,7 @@ public class ResourceContainerImporter
|
||||||
public ResourceContainerImporter addClassResource(String name, InputStream stream) throws IOException
|
public ResourceContainerImporter addClassResource(String name, InputStream stream) throws IOException
|
||||||
{
|
{
|
||||||
byte[] bytes = MiscUtils.getBytes(stream);
|
byte[] bytes = MiscUtils.getBytes(stream);
|
||||||
if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe"))
|
if (MiscUtils.getFileHeaderMagicNumber(bytes).equalsIgnoreCase("cafebabe"))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
package the.bytecode.club.bytecodeviewer.resources;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Konloch
|
||||||
|
* @since 7/13/2021
|
||||||
|
*/
|
||||||
|
|
||||||
|
public enum ResourceType
|
||||||
|
{
|
||||||
|
CLASS_FILE(IconResources.classIcon, "class"),
|
||||||
|
JAVA_ARCHIVE(IconResources.jarIcon, "jar", "war", "ear"),
|
||||||
|
ZIP_ARCHIVE(IconResources.zipIcon, "zip"),
|
||||||
|
ANDROID_ARCHIVE(IconResources.androidIcon, "apk", "wapk", "dex"),
|
||||||
|
IMAGE_FILE(IconResources.imageIcon, "png", "jpg", "jpeg", "bmp", "wbmp", "gif", "tif"),
|
||||||
|
CONFIG_TEXT_FILE(IconResources.configIcon, "properties", "xml", "jsp", "mf", "config", "config", "yaml", "ini", "json"),
|
||||||
|
JAVA_FILE(IconResources.javaIcon, "java"),
|
||||||
|
TEXT_FILE(IconResources.textIcon, "txt", "md", "log"),
|
||||||
|
CPP_FILE(IconResources.cplusplusIcon, "c", "cpp", "h"),
|
||||||
|
CSHAR_FILE(IconResources.csharpIcon, "cs"),
|
||||||
|
BAT_FILE(IconResources.batIcon, "bat", "batch"),
|
||||||
|
SH_FILE(IconResources.shIcon, "sh", "bash"),
|
||||||
|
;
|
||||||
|
|
||||||
|
public static final HashMap<String, ResourceType> extensionMap = new HashMap<>();
|
||||||
|
public static final HashMap<String, ResourceType> imageExtensionMap = new HashMap<>();
|
||||||
|
public static final HashMap<String, ResourceType> supportedBCVExtensionMap = new HashMap<>();
|
||||||
|
|
||||||
|
private final ImageIcon icon;
|
||||||
|
private final String[] extensions;
|
||||||
|
//private final byte[][] headerMagicNumber;
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
//add all extensions
|
||||||
|
for(ResourceType t : values())
|
||||||
|
for(String extension : t.extensions)
|
||||||
|
extensionMap.put(extension, t);
|
||||||
|
|
||||||
|
//add image extensions
|
||||||
|
for(String extension : IMAGE_FILE.extensions)
|
||||||
|
imageExtensionMap.put(extension, IMAGE_FILE);
|
||||||
|
|
||||||
|
//add extensions BCV can be opened with
|
||||||
|
for(String extension : CLASS_FILE.extensions)
|
||||||
|
supportedBCVExtensionMap.put(extension, CLASS_FILE);
|
||||||
|
for(String extension : JAVA_ARCHIVE.extensions)
|
||||||
|
supportedBCVExtensionMap.put(extension, JAVA_ARCHIVE);
|
||||||
|
for(String extension : ZIP_ARCHIVE.extensions)
|
||||||
|
supportedBCVExtensionMap.put(extension, ZIP_ARCHIVE);
|
||||||
|
for(String extension : ANDROID_ARCHIVE.extensions)
|
||||||
|
supportedBCVExtensionMap.put(extension, ANDROID_ARCHIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceType(ImageIcon icon, String... extensions)
|
||||||
|
{
|
||||||
|
this.icon = icon;
|
||||||
|
this.extensions = extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageIcon getIcon()
|
||||||
|
{
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ public class ClassResourceImporter implements Importer
|
||||||
byte[] bytes = MiscUtils.getBytes(new FileInputStream(file));
|
byte[] bytes = MiscUtils.getBytes(new FileInputStream(file));
|
||||||
ResourceContainer container = new ResourceContainer(file);
|
ResourceContainer container = new ResourceContainer(file);
|
||||||
|
|
||||||
if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe"))
|
if (MiscUtils.getFileHeaderMagicNumber(bytes).equalsIgnoreCase("cafebabe"))
|
||||||
{
|
{
|
||||||
final ClassNode cn = JarUtils.getNode(bytes);
|
final ClassNode cn = JarUtils.getNode(bytes);
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ public class DirectoryResourceImporter implements Importer
|
||||||
else if (fileName.endsWith(".class"))
|
else if (fileName.endsWith(".class"))
|
||||||
{
|
{
|
||||||
byte[] bytes = Files.readAllBytes(Paths.get(child.getAbsolutePath()));
|
byte[] bytes = Files.readAllBytes(Paths.get(child.getAbsolutePath()));
|
||||||
if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe"))
|
if (MiscUtils.getFileHeaderMagicNumber(bytes).equalsIgnoreCase("cafebabe"))
|
||||||
{
|
{
|
||||||
final ClassNode cn = JarUtils.getNode(bytes);
|
final ClassNode cn = JarUtils.getNode(bytes);
|
||||||
allDirectoryClasses.put(FilenameUtils.removeExtension(trimmedPath), cn);
|
allDirectoryClasses.put(FilenameUtils.removeExtension(trimmedPath), cn);
|
||||||
|
|
|
@ -77,7 +77,7 @@ public class JarUtils
|
||||||
if (!entry.isDirectory())
|
if (!entry.isDirectory())
|
||||||
files.put(name, bytes);
|
files.put(name, bytes);
|
||||||
} else {
|
} else {
|
||||||
if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe"))
|
if (MiscUtils.getFileHeaderMagicNumber(bytes).equalsIgnoreCase("cafebabe"))
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
final ClassNode cn = getNode(bytes);
|
final ClassNode cn = getNode(bytes);
|
||||||
|
@ -133,7 +133,7 @@ public class JarUtils
|
||||||
if (!name.endsWith(".class")) {
|
if (!name.endsWith(".class")) {
|
||||||
files.put(name, bytes);
|
files.put(name, bytes);
|
||||||
} else {
|
} else {
|
||||||
if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe"))
|
if (MiscUtils.getFileHeaderMagicNumber(bytes).equalsIgnoreCase("cafebabe"))
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
final ClassNode cn = getNode(bytes);
|
final ClassNode cn = getNode(bytes);
|
||||||
|
@ -165,7 +165,7 @@ public class JarUtils
|
||||||
final String name = entry.getName();
|
final String name = entry.getName();
|
||||||
if (name.endsWith(".class")) {
|
if (name.endsWith(".class")) {
|
||||||
byte[] bytes = MiscUtils.getBytes(jis);
|
byte[] bytes = MiscUtils.getBytes(jis);
|
||||||
if (MiscUtils.getFileHeader(bytes).equalsIgnoreCase("cafebabe"))
|
if (MiscUtils.getFileHeaderMagicNumber(bytes).equalsIgnoreCase("cafebabe"))
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
final ClassNode cn = getNode(bytes);
|
final ClassNode cn = getNode(bytes);
|
||||||
|
|
|
@ -160,7 +160,7 @@ public class MiscUtils
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getFileHeader(byte[] fileContents)
|
public static String getFileHeaderMagicNumber(byte[] fileContents)
|
||||||
{
|
{
|
||||||
return String.format("%02X%02X%02X%02X", fileContents[0],
|
return String.format("%02X%02X%02X%02X", fileContents[0],
|
||||||
fileContents[1], fileContents[2],fileContents[3]);
|
fileContents[1], fileContents[2],fileContents[3]);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue