Archived
Private
Public Access
1
0
This repository has been archived on 2026-02-04. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
ProjectBackup/C#/FiveM/CarConverter/MainWindow.xaml.cs
2022-09-04 12:45:01 +02:00

416 lines
15 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.Win32;
using Microsoft.WindowsAPICodePack.Dialogs;
using RageLib.Archives;
using RageLib.GTA5.Archives;
using RageLib.GTA5.ArchiveWrappers;
using RageLib.GTA5.Cryptography;
using RageLib.GTA5.Utilities;
namespace CarConverter {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow {
private DirectoryInfo root;
public MainWindow() {
InitializeComponent();
var path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\CarConverter\";
if (Directory.Exists(path))
OutputDir.Content = File.ReadAllText(path + "DefaultOutput.penis");
//ConsoleManager.Show();
}
private void OnRPFDrop(object sender, DragEventArgs e) {
Clear(null, null);
var files = e.Data.GetData(DataFormats.FileDrop) as string[];
if (files.Length != 1) {
MessageBox.Show("Du kannst nur eine Datei gleichzeitig Decompilen");
}
else {
root = new DirectoryInfo(DecompileRpfFile(new FileInfo(files[0])));
TreeViewItem item = new TreeViewItem();
item.Header = new FileInfo(files[0]).Name;
item.Tag = root;
item.FontWeight = FontWeights.Normal;
FoldersItem.Items.Add(item);
PlaceFilesInTree(item, root);
LoadFiles(root);
}
}
private void PlaceFilesInTree(TreeViewItem parent, DirectoryInfo info) {
foreach (DirectoryInfo directoryInfo in info.GetDirectories()) {
TreeViewItem p = new TreeViewItem();
p.Header = directoryInfo.Name;
p.Tag = directoryInfo;
p.FontWeight = FontWeights.Normal;
parent.Items.Add(p);
PlaceFilesInTree(p, directoryInfo);
}
foreach (FileInfo file in info.GetFiles()) {
TreeViewItem item = new TreeViewItem();
item.Header = file.Name;
item.Tag = file;
item.FontWeight = FontWeights.Normal;
parent.Items.Add(item);
}
}
private string DecompileRpfFile(FileInfo fileInfo) {
try {
var outFolder = Path.GetTempPath() + @"CarConverter\Decompiled\";
if (Directory.Exists(outFolder))
Directory.Delete(outFolder, true);
var fileStream = new FileStream(fileInfo.FullName, FileMode.Open);
var inputArchive = RageArchiveWrapper7.Open(fileStream, fileInfo.Name);
var queue = new List<Tuple<string, RageArchiveWrapper7, bool>>()
{ new Tuple<string, RageArchiveWrapper7, bool>(fileInfo.FullName, inputArchive, false) };
while (queue.Count > 0) {
var fullPath = queue[0].Item1;
var rpf = queue[0].Item2;
var isTmpStream = queue[0].Item3;
queue.RemoveAt(0);
ArchiveUtilities.ForEachFile(fullPath.Replace(fileInfo.FullName, ""), rpf.Root, rpf.archive_.Encryption, (fullFileName, file, encryption) => {
string path = outFolder + fullFileName;
string dir = Path.GetDirectoryName(path);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
Console.WriteLine(fullFileName);
if (file.Name.EndsWith(".rpf")) {
try {
var tmpStream = new FileStream(Path.GetTempFileName(), FileMode.Open);
file.Export(tmpStream);
RageArchiveWrapper7 archive = RageArchiveWrapper7.Open(tmpStream, file.Name);
queue.Add(new Tuple<string, RageArchiveWrapper7, bool>(fullFileName, archive, true));
}
catch (Exception e) {
Console.WriteLine(e);
}
}
else {
if (file.Name.EndsWith(".xml") || file.Name.EndsWith(".meta")) {
byte[] data = GetBinaryFileData((IArchiveBinaryFile)file, encryption);
string xml;
if (data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF) // Detect BOM
{
xml = Encoding.UTF8.GetString(data, 3, data.Length - 3);
}
else {
xml = Encoding.UTF8.GetString(data);
}
File.WriteAllText(path, xml, Encoding.UTF8);
}
else {
file.Export(path);
}
}
});
var stream = (FileStream)rpf.archive_.BaseStream;
string fileName = stream.Name;
rpf.Dispose();
if (isTmpStream) {
File.Delete(fileName);
}
}
return outFolder;
}
catch (Exception e) {
Console.WriteLine(e);
}
return "";
}
private static byte[] GetBinaryFileData(IArchiveBinaryFile file, RageArchiveEncryption7 encryption)
{
using (var ms = new MemoryStream())
{
file.Export(ms);
byte[] data = ms.ToArray();
if(file.IsEncrypted)
{
if (encryption == RageArchiveEncryption7.AES)
{
data = GTA5Crypto.DecryptAES(data);
}
else // if(encryption == RageArchiveEncryption7.NG)
{
data = GTA5Crypto.DecryptNG(data, file.Name, (uint)file.UncompressedSize);
}
}
if (file.IsCompressed)
{
using (var dfls = new DeflateStream(new MemoryStream(data), CompressionMode.Decompress))
{
using (var outstr = new MemoryStream())
{
dfls.CopyTo(outstr);
data = outstr.ToArray();
}
}
}
return data;
}
}
private void LoadFiles(DirectoryInfo directory) {
DirectoryInfo metaFolder = new DirectoryInfo(directory.FullName + @"data\");
foreach (FileInfo file in metaFolder.GetFiles()) {
AddMetaFile(file);
}
DirectoryInfo streamFolder = new DirectoryInfo(directory.FullName + @"x64\vehicles.rpf");
foreach (FileInfo file in streamFolder.GetFiles()) {
AddStreamFile(file);
}
DirectoryInfo modsFolder = new DirectoryInfo(directory.FullName + @"x64\vehiclemods");
if (modsFolder.Exists) {
foreach (DirectoryInfo folder in modsFolder.GetDirectories()) {
foreach (FileInfo file in folder.GetFiles()) {
AddStreamFile(file);
}
}
}
if (StreamFiles.Items.Count > 0)
CarName.Text = ((StreamFiles.Items[0] as TreeViewItem).Tag as FileInfo).Name.Split('.')[0];
}
private void AddMetaFile(FileInfo file) {
TreeViewItem item = new TreeViewItem();
item.Header = file.Name;
item.Tag = file;
item.FontWeight = FontWeights.Normal;
MetaFiles.Items.Add(item);
}
private void AddStreamFile(FileInfo file) {
TreeViewItem item = new TreeViewItem();
item.Header = file.Name;
item.Tag = file;
item.FontWeight = FontWeights.Normal;
StreamFiles.Items.Add(item);
}
private void OnImplement(object sender, MouseButtonEventArgs e) {
TreeViewItem item = FoldersItem.SelectedItem as TreeViewItem;
if (item == null) return;
if (item.Tag is FileInfo) {
FileInfo file = item.Tag as FileInfo;
if (file is null) return;
if (file.Name.EndsWith(".meta")) {
AddMetaFile(file);
}
else {
AddStreamFile(file);
}
}
}
private void OnRemove(object sender, MouseButtonEventArgs e) {
TreeView view = sender as TreeView;
if (view is null) return;
view.Items.Remove(view.SelectedItem);
}
private void Clear(object sender, RoutedEventArgs e) {
FoldersItem.Items.Clear();
MetaFiles.Items.Clear();
StreamFiles.Items.Clear();
root = null;
}
private void Build(object sender, RoutedEventArgs e) {
try {
var outputPath = OutputDir.Content + @"\" + CarName.Text;
if (Directory.Exists(outputPath))
Directory.Delete(outputPath, true);
DirectoryInfo info = Directory.CreateDirectory(outputPath);
File.WriteAllBytes(info.FullName + @"\__resource.lua", GetResourceBytes());
DirectoryInfo streamFolder = info.CreateSubdirectory("stream");
foreach (var item in MetaFiles.Items) {
FileInfo file = (item as TreeViewItem).Tag as FileInfo;
file.CopyTo(info.FullName + @"\" + file.Name);
}
foreach (var item in StreamFiles.Items) {
FileInfo file = (item as TreeViewItem).Tag as FileInfo;
file.CopyTo(streamFolder.FullName + @"\" + file.Name);
}
MessageBox.Show("Fertig du Pimmelberger");
}
catch (Exception exception) {
Console.WriteLine(exception);
}
}
private byte[] GetResourceBytes() {
return Encoding.ASCII.GetBytes("resource_manifest_version '77731fab-63ca-442c-a67b-abc70f28dfa5'\n\n" +
"files {\n" +
" 'carcols.meta',\n" +
" 'vehicles.meta',\n" +
" 'carvariations.meta',\n" +
" 'handling.meta',\n" +
"}\n\n" +
"data_file 'CARCOLS_FILE' 'carcols.meta'\n" +
"data_file 'HANDLING_FILE' 'handling.meta'\n" +
"data_file 'VEHICLE_METADATA_FILE' 'vehicles.meta'\n" +
"data_file 'VEHICLE_VARIATION_FILE' 'carvariations.meta'\n");
}
private void ChooseOutput(object sender, RoutedEventArgs e) {
var dialog = new CommonOpenFileDialog();
dialog.Multiselect = false;
dialog.IsFolderPicker = true;
if (dialog.ShowDialog(this) == CommonFileDialogResult.Ok) {
OutputDir.Content = dialog.FileName;
//Save Output dir
var path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\CarConverter\";
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
File.WriteAllText(path + "DefaultOutput.penis", OutputDir.Content as string);
}
}
}
[SuppressUnmanagedCodeSecurity]
public static class ConsoleManager
{
private const string Kernel32DllName = "kernel32.dll";
[DllImport(Kernel32DllName)]
private static extern bool AllocConsole();
[DllImport(Kernel32DllName)]
private static extern bool FreeConsole();
[DllImport(Kernel32DllName)]
private static extern IntPtr GetConsoleWindow();
[DllImport(Kernel32DllName)]
private static extern int GetConsoleOutputCP();
public static bool HasConsole
{
get { return GetConsoleWindow() != IntPtr.Zero; }
}
/// <summary>
/// Creates a new console instance if the process is not attached to a console already.
/// </summary>
public static void Show()
{
//#if DEBUG
if (!HasConsole)
{
AllocConsole();
InvalidateOutAndError();
}
//#endif
}
/// <summary>
/// If the process has a console attached to it, it will be detached and no longer visible. Writing to the System.Console is still possible, but no output will be shown.
/// </summary>
public static void Hide()
{
//#if DEBUG
if (HasConsole)
{
SetOutAndErrorNull();
FreeConsole();
}
//#endif
}
public static void Toggle()
{
if (HasConsole)
{
Hide();
}
else
{
Show();
}
}
static void InvalidateOutAndError()
{
Type type = typeof(System.Console);
System.Reflection.FieldInfo _out = type.GetField("_out",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
System.Reflection.FieldInfo _error = type.GetField("_error",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
System.Reflection.MethodInfo _InitializeStdOutError = type.GetMethod("InitializeStdOutError",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
Debug.Assert(_out != null);
Debug.Assert(_error != null);
Debug.Assert(_InitializeStdOutError != null);
_out.SetValue(null, null);
_error.SetValue(null, null);
_InitializeStdOutError.Invoke(null, new object[] { true });
}
static void SetOutAndErrorNull()
{
Console.SetOut(TextWriter.Null);
Console.SetError(TextWriter.Null);
}
}
}