Initial version
This commit is contained in:
+192
@@ -0,0 +1,192 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace EonaCat.JavaDecompile;
|
||||
|
||||
public static class JarProcessor
|
||||
{
|
||||
public static List<TreeViewItem> ExtractStructure(string jarPath)
|
||||
{
|
||||
using var archive = ZipFile.OpenRead(jarPath);
|
||||
var root = new TreeViewItem { Header = Path.GetFileName(jarPath), Tag = null, IsExpanded = true };
|
||||
|
||||
foreach (var entry in archive.Entries.OrderBy(e => e.FullName))
|
||||
{
|
||||
var parts = entry.FullName.Split(new[] { '/' }, System.StringSplitOptions.RemoveEmptyEntries);
|
||||
TreeViewItem parent = root;
|
||||
for (int i = 0; i < parts.Length; i++)
|
||||
{
|
||||
string part = parts[i];
|
||||
bool isLast = i == parts.Length - 1;
|
||||
TreeViewItem? existing = parent.Items.OfType<TreeViewItem>().FirstOrDefault(x => (string)x.Header == part);
|
||||
if (existing == null)
|
||||
{
|
||||
var node = new TreeViewItem { Header = part };
|
||||
if (isLast && !entry.FullName.EndsWith("/"))
|
||||
{
|
||||
node.Tag = entry.FullName;
|
||||
}
|
||||
|
||||
parent.Items.Add(node);
|
||||
parent = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
parent = existing;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new List<TreeViewItem> { root };
|
||||
}
|
||||
|
||||
public static bool IsImage(string path)
|
||||
{
|
||||
string[] exts = { ".png", ".jpg", ".jpeg", ".bmp", ".gif", ".ico" };
|
||||
return exts.Any(e => path.EndsWith(e, System.StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
public static BitmapImage? ExtractImage(string jarPath, string entryPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var archive = ZipFile.OpenRead(jarPath);
|
||||
var entry = archive.GetEntry(entryPath);
|
||||
if (entry == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using var s = entry.Open();
|
||||
using var ms = new MemoryStream();
|
||||
s.CopyTo(ms);
|
||||
ms.Position = 0;
|
||||
var img = new BitmapImage();
|
||||
img.BeginInit();
|
||||
img.StreamSource = ms;
|
||||
img.CacheOption = BitmapCacheOption.OnLoad;
|
||||
img.EndInit();
|
||||
img.Freeze();
|
||||
return img;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<TreeViewItem>? ExtractStructureFromInnerJar(string mainJar, string innerJarEntry)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var outer = ZipFile.OpenRead(mainJar);
|
||||
var entry = outer.GetEntry(innerJarEntry);
|
||||
if (entry == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string temp = Path.Combine(Path.GetTempPath(), "EonaCat.JavaDecompile", Path.GetRandomFileName());
|
||||
Directory.CreateDirectory(temp);
|
||||
string innerPath = Path.Combine(temp, Path.GetFileName(innerJarEntry));
|
||||
using var s = entry.Open();
|
||||
using var fs = File.Create(innerPath);
|
||||
s.CopyTo(fs);
|
||||
fs.Close();
|
||||
return ExtractStructure(innerPath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ReadTextFromJar(string jarPath, string entryPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var archive = ZipFile.OpenRead(jarPath);
|
||||
var entry = archive.GetEntry(entryPath);
|
||||
if (entry == null)
|
||||
{
|
||||
return "// File not found";
|
||||
}
|
||||
|
||||
using var stream = entry.Open();
|
||||
if (IsBinary(entry.FullName))
|
||||
{
|
||||
return $"[{entry.FullName}] Binary file ({entry.Length} bytes)";
|
||||
}
|
||||
|
||||
using var reader = new StreamReader(stream, Encoding.UTF8, true);
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "// Error reading file";
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsBinary(string path)
|
||||
{
|
||||
string[] exts = { ".class", ".jar" };
|
||||
return exts.Any(e => path.EndsWith(e, System.StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
public static string DecompileClass(string jarPath, string classPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
string tmp = Path.Combine(Path.GetTempPath(), "EonaCat.JavaDecompile", Path.GetRandomFileName());
|
||||
Directory.CreateDirectory(tmp);
|
||||
string cls = Path.Combine(tmp, Path.GetFileName(classPath));
|
||||
string outDir = Path.Combine(tmp, "out");
|
||||
Directory.CreateDirectory(outDir);
|
||||
|
||||
using (var arc = ZipFile.OpenRead(jarPath))
|
||||
{
|
||||
var entry = arc.GetEntry(classPath);
|
||||
if (entry == null)
|
||||
{
|
||||
return "// Class not found";
|
||||
}
|
||||
|
||||
using var s = entry.Open();
|
||||
using var fs = File.Create(cls);
|
||||
s.CopyTo(fs);
|
||||
}
|
||||
|
||||
string cfr = Path.Combine(AppContext.BaseDirectory, "assets", "external", "cfr.jar");
|
||||
if (!File.Exists(cfr))
|
||||
{
|
||||
return "// CFR not found";
|
||||
}
|
||||
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = "java",
|
||||
Arguments = $"-jar \"{cfr}\" \"{cls}\" --outputdir \"{outDir}\"",
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
using var p = Process.Start(psi);
|
||||
p?.WaitForExit();
|
||||
|
||||
string baseName = Path.GetFileNameWithoutExtension(classPath);
|
||||
string f = Directory.GetFiles(outDir, $"{baseName}.java", SearchOption.AllDirectories).FirstOrDefault();
|
||||
return f != null ? File.ReadAllText(f, Encoding.UTF8) : "// Decompiled file not found";
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "// Error decompiling class";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user