192 lines
6.0 KiB
C#
192 lines
6.0 KiB
C#
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";
|
|
}
|
|
}
|
|
} |