mirror of
https://github.com/KillzXGaming/Switch-Toolbox
synced 2025-02-16 22:08:26 +00:00
Add working SDF (Mario and Rabbids) archive support.
This commit is contained in:
parent
3ab44e1f63
commit
8f849bf260
25 changed files with 737 additions and 176 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -7,10 +7,11 @@ using Switch_Toolbox;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using Switch_Toolbox.Library;
|
using Switch_Toolbox.Library;
|
||||||
using Switch_Toolbox.Library.IO;
|
using Switch_Toolbox.Library.IO;
|
||||||
|
using Switch_Toolbox.Library.Forms;
|
||||||
|
|
||||||
namespace FirstPlugin
|
namespace FirstPlugin
|
||||||
{
|
{
|
||||||
public class SDF : TreeNodeFile, IFileFormat
|
public class SDF : IArchiveFile, IFileFormat
|
||||||
{
|
{
|
||||||
public FileType FileType { get; set; } = FileType.Archive;
|
public FileType FileType { get; set; } = FileType.Archive;
|
||||||
|
|
||||||
|
@ -21,6 +22,11 @@ namespace FirstPlugin
|
||||||
public string FilePath { get; set; }
|
public string FilePath { get; set; }
|
||||||
public IFileInfo IFileInfo { get; set; }
|
public IFileInfo IFileInfo { get; set; }
|
||||||
|
|
||||||
|
public bool CanAddFiles { get; set; } = false;
|
||||||
|
public bool CanRenameFiles { get; set; } = false;
|
||||||
|
public bool CanReplaceFiles { get; set; } = false;
|
||||||
|
public bool CanDeleteFiles { get; set; } = false;
|
||||||
|
|
||||||
public bool Identify(System.IO.Stream stream)
|
public bool Identify(System.IO.Stream stream)
|
||||||
{
|
{
|
||||||
using (var reader = new Switch_Toolbox.Library.IO.FileReader(stream, true))
|
using (var reader = new Switch_Toolbox.Library.IO.FileReader(stream, true))
|
||||||
|
@ -38,15 +44,19 @@ namespace FirstPlugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<FileEntry> files = new List<FileEntry>();
|
||||||
|
public IEnumerable<ArchiveFileInfo> Files => files;
|
||||||
|
|
||||||
SDFTOC_Header Header;
|
SDFTOC_Header Header;
|
||||||
SDFTOC_ID startId;
|
SDFTOC_ID startId;
|
||||||
int[] block1;
|
int[] block1;
|
||||||
SDFTOC_ID[] blockIds;
|
SDFTOC_ID[] blockIds;
|
||||||
SDFTOC_Block2[] block2Array;
|
public SDFTOC_Block2[] block2Array;
|
||||||
byte[] DecompressedBlock;
|
byte[] DecompressedBlock;
|
||||||
SDFTOC_ID endId;
|
SDFTOC_ID endId;
|
||||||
|
|
||||||
List<string> FilePaths = new List<string>();
|
//Temp but just for now as this is expeirmental. Need to optmize tree loading
|
||||||
|
private readonly int MAX_FILE_DISPLAY = 4000;
|
||||||
|
|
||||||
//Thanks to https://github.com/GoldFarmer/rouge_sdf/blob/master/main.cpp for docs/structs
|
//Thanks to https://github.com/GoldFarmer/rouge_sdf/blob/master/main.cpp for docs/structs
|
||||||
public void Load(System.IO.Stream stream)
|
public void Load(System.IO.Stream stream)
|
||||||
|
@ -97,30 +107,14 @@ namespace FirstPlugin
|
||||||
//Read last id
|
//Read last id
|
||||||
endId = new SDFTOC_ID(reader);
|
endId = new SDFTOC_ID(reader);
|
||||||
|
|
||||||
Text = FileName;
|
MessageBox.Show("Note! Support for this format is experimental. The tool will only load < 4000 files atm due to slow loading");
|
||||||
|
|
||||||
LoadTree();
|
for (int i = 0; i < FileEntries.Count; i++)
|
||||||
|
if (i < MAX_FILE_DISPLAY)
|
||||||
|
files.Add(FileEntries[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadTree()
|
|
||||||
{
|
|
||||||
// Get a list of everything under the users' temp folder as an example
|
|
||||||
string[] fileList;
|
|
||||||
fileList = FilePaths.ToArray();
|
|
||||||
|
|
||||||
// Parse the file list into a TreeNode collection
|
|
||||||
TreeNode node = GetNodes(new TreeNode(), fileList);
|
|
||||||
Nodes.Add(node); // Add the new nodes
|
|
||||||
|
|
||||||
// Copy the new nodes to an array
|
|
||||||
int nodeCount = node.Nodes.Count;
|
|
||||||
TreeNode[] nodes = new TreeNode[nodeCount];
|
|
||||||
node.Nodes.CopyTo(nodes, 0);
|
|
||||||
|
|
||||||
Nodes.AddRange(nodes); // Add the new nodes
|
|
||||||
}
|
|
||||||
|
|
||||||
private TreeNode GetNodes(TreeNode parent, string[] fileList)
|
private TreeNode GetNodes(TreeNode parent, string[] fileList)
|
||||||
{
|
{
|
||||||
// build a TreeNode collection from the file list
|
// build a TreeNode collection from the file list
|
||||||
|
@ -151,53 +145,6 @@ namespace FirstPlugin
|
||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FillTreeNodes(TreeNode root, List<string> files)
|
|
||||||
{
|
|
||||||
var rootText = root.Text;
|
|
||||||
var rootTextLength = rootText.Length;
|
|
||||||
var nodeStrings = files;
|
|
||||||
foreach (var node in nodeStrings)
|
|
||||||
{
|
|
||||||
string nodeString = node;
|
|
||||||
nodeString = nodeString.Replace(@"\", "/");
|
|
||||||
|
|
||||||
var roots = nodeString.Split(new char[] { '/' },
|
|
||||||
StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
|
|
||||||
// The initial parent is the root node
|
|
||||||
var parentNode = root;
|
|
||||||
var sb = new StringBuilder(rootText, nodeString.Length + rootTextLength);
|
|
||||||
for (int rootIndex = 0; rootIndex < roots.Length; rootIndex++)
|
|
||||||
{
|
|
||||||
// Build the node name
|
|
||||||
var parentName = roots[rootIndex];
|
|
||||||
sb.Append("/");
|
|
||||||
sb.Append(parentName);
|
|
||||||
var nodeName = sb.ToString();
|
|
||||||
|
|
||||||
// Search for the node
|
|
||||||
var index = parentNode.Nodes.IndexOfKey(nodeName);
|
|
||||||
if (index == -1)
|
|
||||||
{
|
|
||||||
// Node was not found, add it
|
|
||||||
|
|
||||||
var temp = new TreeNode(parentName, 0, 0);
|
|
||||||
if (rootIndex == roots.Length - 1)
|
|
||||||
temp = new TreeNode(parentName); //File entry
|
|
||||||
|
|
||||||
temp.Name = nodeName;
|
|
||||||
parentNode.Nodes.Add(temp);
|
|
||||||
parentNode = temp;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Node was found, set that as parent and continue
|
|
||||||
parentNode = parentNode.Nodes[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DecompressNameBlock(uint magic, byte[] CompressedBlock, SDFTOC_Header header)
|
public void DecompressNameBlock(uint magic, byte[] CompressedBlock, SDFTOC_Header header)
|
||||||
{
|
{
|
||||||
byte[] decomp = null;
|
byte[] decomp = null;
|
||||||
|
@ -226,11 +173,108 @@ namespace FirstPlugin
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool AddFile(ArchiveFileInfo archiveFileInfo)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DeleteFile(ArchiveFileInfo archiveFileInfo)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FileEntry : ArchiveFileInfo
|
||||||
|
{
|
||||||
|
public SDF SDFParent;
|
||||||
|
public string FilePath;
|
||||||
|
public string FolderPath;
|
||||||
|
public string FileBlockPath;
|
||||||
|
public ulong PackageID;
|
||||||
|
public ulong Offset;
|
||||||
|
public ulong DecompressedSize;
|
||||||
|
public List<ulong> CompressedSizes;
|
||||||
|
public ulong DdsType;
|
||||||
|
public bool UseDDS;
|
||||||
|
public bool IsCompressed = false;
|
||||||
|
|
||||||
|
public override byte[] FileData
|
||||||
|
{
|
||||||
|
get => GetFileBytes();
|
||||||
|
set => base.FileData = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IFileFormat OpenFile()
|
||||||
|
{
|
||||||
|
var FileFormat = STFileLoader.OpenFileFormat(
|
||||||
|
IOExtensions.RemoveIllegaleFolderNameCharacters(FileName), FileData, true);
|
||||||
|
|
||||||
|
if (FileFormat is DDS)
|
||||||
|
((DDS)FileFormat).SwitchSwizzle = true;
|
||||||
|
|
||||||
|
return FileFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetFileBytes()
|
||||||
|
{
|
||||||
|
List<byte[]> Data = new List<byte[]>();
|
||||||
|
if (File.Exists(FileBlockPath))
|
||||||
|
{
|
||||||
|
var block = File.Open(FileBlockPath, FileMode.Open);
|
||||||
|
using (var stream = new FileReader(block))
|
||||||
|
{
|
||||||
|
if (CompressedSizes.Count == 0)
|
||||||
|
{
|
||||||
|
//Decompressed File
|
||||||
|
string FileNameBlock = Path.Combine(FolderPath, FilePath);
|
||||||
|
string FolerPath = Path.GetDirectoryName(FileNameBlock);
|
||||||
|
if (!Directory.Exists(FolerPath))
|
||||||
|
Directory.CreateDirectory(FolerPath);
|
||||||
|
|
||||||
|
return stream.getSection((int)Offset, (int)DecompressedSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var PageSize = (double)0x10000;
|
||||||
|
var DecompOffset = 0;
|
||||||
|
var CompOffset = 0;
|
||||||
|
IsCompressed = true;
|
||||||
|
|
||||||
|
if (UseDDS)
|
||||||
|
{
|
||||||
|
Data.Add(SDFParent.block2Array[DdsType].Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < CompressedSizes.Count; i++)
|
||||||
|
{
|
||||||
|
var decompSize = (int)Math.Min((int)DecompressedSize - DecompOffset, PageSize);
|
||||||
|
if (CompressedSizes[i] == 0 || decompSize == (int)CompressedSizes[i])
|
||||||
|
{
|
||||||
|
stream.Seek((int)Offset + CompOffset, SeekOrigin.Begin);
|
||||||
|
CompressedSizes[i] = (ulong)decompSize;
|
||||||
|
Data.Add( stream.ReadBytes(decompSize));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stream.Seek((int)Offset + CompOffset, SeekOrigin.Begin);
|
||||||
|
Data.Add(STLibraryCompression.ZSTD.Decompress(stream.ReadBytes((int)CompressedSizes[i])));
|
||||||
|
}
|
||||||
|
DecompOffset += (int)decompSize;
|
||||||
|
CompOffset += (int)CompressedSizes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
block.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Utils.CombineByteArray(Data.ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<FileEntry> FileEntries = new List<FileEntry>();
|
||||||
|
|
||||||
public void ParseNames(FileReader reader, string Name = "")
|
public void ParseNames(FileReader reader, string Name = "")
|
||||||
{
|
{
|
||||||
if (!Name.Contains("dummy") && FilePaths.Count < 200)
|
|
||||||
FilePaths.Add(Name);
|
|
||||||
|
|
||||||
char ch = reader.ReadChar();
|
char ch = reader.ReadChar();
|
||||||
|
|
||||||
if (ch == 0)
|
if (ch == 0)
|
||||||
|
@ -253,7 +297,7 @@ namespace FirstPlugin
|
||||||
int flag1 = (ch >> 3) & 1;
|
int flag1 = (ch >> 3) & 1;
|
||||||
// int flag1 = ch & 8;
|
// int flag1 = ch & 8;
|
||||||
|
|
||||||
if (count1 != 0)
|
if (count1 > 0)
|
||||||
{
|
{
|
||||||
uint strangeId = reader.ReadUInt32();
|
uint strangeId = reader.ReadUInt32();
|
||||||
byte chr2 = reader.ReadByte();
|
byte chr2 = reader.ReadByte();
|
||||||
|
@ -264,10 +308,10 @@ namespace FirstPlugin
|
||||||
for (int chunkIndex = 0; chunkIndex < count1; chunkIndex++)
|
for (int chunkIndex = 0; chunkIndex < count1; chunkIndex++)
|
||||||
{
|
{
|
||||||
byte ch3 = reader.ReadByte();
|
byte ch3 = reader.ReadByte();
|
||||||
if (ch3 == 0)
|
// if (ch3 == 0)
|
||||||
{
|
// {
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
|
|
||||||
int compressedSizeByteCount = (ch3 & 3) + 1;
|
int compressedSizeByteCount = (ch3 & 3) + 1;
|
||||||
int packageOffsetByteCount = (ch3 >> 2) & 7;
|
int packageOffsetByteCount = (ch3 >> 2) & 7;
|
||||||
|
@ -295,7 +339,7 @@ namespace FirstPlugin
|
||||||
|
|
||||||
if (packageId >= Header.Block1Count)
|
if (packageId >= Header.Block1Count)
|
||||||
{
|
{
|
||||||
throw new InvalidDataException("SDF Package ID outside of TOC range");
|
// throw new InvalidDataException($"SDF Package ID ({packageId}) outside of TOC range ({ Header.Block1Count})");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -317,8 +361,8 @@ namespace FirstPlugin
|
||||||
|
|
||||||
if (Header.Version <= 0x16)
|
if (Header.Version <= 0x16)
|
||||||
{
|
{
|
||||||
fileId = (long)readVariadicInteger(4, reader);
|
// fileId = (long)readVariadicInteger(4, reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compSizeArray.Count == 0 && hasCompression)
|
if (compSizeArray.Count == 0 && hasCompression)
|
||||||
compSizeArray.Add(compressedSize);
|
compSizeArray.Add(compressedSize);
|
||||||
|
@ -333,7 +377,7 @@ namespace FirstPlugin
|
||||||
{
|
{
|
||||||
reader.ReadByte();
|
reader.ReadByte();
|
||||||
reader.ReadByte();
|
reader.ReadByte();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -345,32 +389,43 @@ namespace FirstPlugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ulong NextMultiple(ulong value, ulong multiple) => NextMultiple((long)value, multiple);
|
|
||||||
public static ulong NextMultiple(long value, ulong multiple)
|
|
||||||
{
|
|
||||||
return (ulong)Math.Ceiling(value / (double)multiple) * multiple;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DumpFile(string Name, ulong packageId, ulong packageOffset, ulong decompresedSize,
|
public void DumpFile(string Name, ulong packageId, ulong packageOffset, ulong decompresedSize,
|
||||||
List<ulong> compressedSize, ulong ddsType, bool Append, bool UseDDS)
|
List<ulong> compressedSize, ulong ddsType, bool Append, bool UseDDS)
|
||||||
{
|
{
|
||||||
string PathFolder = Path.GetDirectoryName(FileName);
|
string PathFolder = Path.GetDirectoryName(FilePath);
|
||||||
|
|
||||||
string layer;
|
string layer;
|
||||||
Console.WriteLine(Name + " " + packageId + " " + packageOffset + " " + decompresedSize + " " + ddsType + " " + UseDDS);
|
if (packageId < 1000) layer = "A";
|
||||||
if (packageId < 1000)
|
else if (packageId < 2000) layer = "B";
|
||||||
|
else if (packageId < 3000) layer = "C";
|
||||||
|
else layer = "D";
|
||||||
|
|
||||||
|
string ID = packageId.ToString("D" + 4);
|
||||||
|
|
||||||
|
string BlockFilePath = Path.Combine(PathFolder, $"sdf-{layer}-{ID}.sdfdata");
|
||||||
|
if (Append)
|
||||||
{
|
{
|
||||||
layer = "A";
|
|
||||||
}
|
|
||||||
else if (packageId < 2000)
|
|
||||||
{
|
|
||||||
layer = "B";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
layer = "C";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsFile = !Name.Contains("dummy") && decompresedSize > 5;
|
||||||
|
if (IsFile)
|
||||||
|
{
|
||||||
|
FileEntries.Add(new FileEntry()
|
||||||
|
{
|
||||||
|
SDFParent = this,
|
||||||
|
FileName = Name,
|
||||||
|
FileBlockPath = BlockFilePath,
|
||||||
|
FilePath = Name,
|
||||||
|
FolderPath = PathFolder,
|
||||||
|
CompressedSizes = compressedSize,
|
||||||
|
DdsType = ddsType,
|
||||||
|
UseDDS = UseDDS,
|
||||||
|
DecompressedSize = decompresedSize,
|
||||||
|
PackageID = packageId,
|
||||||
|
Offset = packageOffset,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Unload()
|
public void Unload()
|
||||||
|
|
|
@ -413,15 +413,16 @@ namespace FirstPlugin
|
||||||
|
|
||||||
if (SelectedSection is ExternalFileData)
|
if (SelectedSection is ExternalFileData)
|
||||||
{
|
{
|
||||||
HexEditor editor = (HexEditor)bfresEditor.GetActiveEditor(typeof(HexEditor));
|
ArchiveFilePanel editor = (ArchiveFilePanel)LibraryGUI.Instance.GetActiveContent(typeof(ArchiveFilePanel));
|
||||||
if (editor == null)
|
if (editor == null)
|
||||||
{
|
{
|
||||||
editor = new HexEditor();
|
editor = new ArchiveFilePanel();
|
||||||
editor.Dock = DockStyle.Fill;
|
editor.Dock = DockStyle.Fill;
|
||||||
bfresEditor.LoadEditor(editor);
|
LibraryGUI.Instance.LoadEditor(editor);
|
||||||
}
|
}
|
||||||
editor.Text = Text;
|
|
||||||
editor.LoadData(((ExternalFileData)SelectedSection).Data);
|
editor.LoadFile(((ExternalFileData)SelectedSection).ArchiveFileInfo);
|
||||||
|
editor.UpdateEditor();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,6 +782,8 @@ namespace FirstPlugin
|
||||||
((BNTX)node).Unload();
|
((BNTX)node).Unload();
|
||||||
}
|
}
|
||||||
Nodes.Clear();
|
Nodes.Clear();
|
||||||
|
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Save()
|
public byte[] Save()
|
||||||
|
|
|
@ -9,23 +9,106 @@ namespace Bfres.Structs
|
||||||
{
|
{
|
||||||
public class ExternalFileData : STGenericWrapper
|
public class ExternalFileData : STGenericWrapper
|
||||||
{
|
{
|
||||||
|
public ArchiveFileInfo ArchiveFileInfo;
|
||||||
|
|
||||||
public override string ExportFilter => "All files (*.*)|*.*";
|
public override string ExportFilter => "All files (*.*)|*.*";
|
||||||
|
|
||||||
//Format to attach
|
public byte[] Data
|
||||||
public IFileFormat FileFormat;
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ArchiveFileInfo.FileData;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ArchiveFileInfo.FileData = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] Data;
|
|
||||||
public ExternalFileData(string name, byte[] data)
|
public ExternalFileData(string name, byte[] data)
|
||||||
{
|
{
|
||||||
ImageKey = "folder";
|
ImageKey = "folder";
|
||||||
|
|
||||||
Text = name;
|
Text = name;
|
||||||
Data = data;
|
|
||||||
|
|
||||||
CanDelete = true;
|
CanDelete = true;
|
||||||
CanRename = true;
|
CanRename = true;
|
||||||
CanReplace = true;
|
CanReplace = true;
|
||||||
CanExport = true;
|
CanExport = true;
|
||||||
|
|
||||||
|
ArchiveFileInfo = new ArchiveFileInfo();
|
||||||
|
ArchiveFileInfo.FileData = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Todo move all of this data into one single class
|
||||||
|
//Using ArchiveFileWrapper would be used wrong due to requring an IArchiveFile
|
||||||
|
public override void OnDoubleMouseClick(TreeView treeview)
|
||||||
|
{
|
||||||
|
IFileFormat file = ArchiveFileInfo.OpenFile();
|
||||||
|
if (file == null) //Format not supported so return
|
||||||
|
return;
|
||||||
|
|
||||||
|
ArchiveFileInfo.FileFormat = file;
|
||||||
|
|
||||||
|
if (Utils.HasInterface(file.GetType(), typeof(IEditor<>)))
|
||||||
|
{
|
||||||
|
OpenFormDialog(file);
|
||||||
|
}
|
||||||
|
else if (file != null && file is TreeNodeFile)
|
||||||
|
ReplaceNode(this, (TreeNodeFile)file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ReplaceNode(TreeNode replaceNode, TreeNodeFile NewNode)
|
||||||
|
{
|
||||||
|
if (NewNode == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// node.Nodes.RemoveAt(index);
|
||||||
|
// node.Nodes.Insert(index, NewNode);
|
||||||
|
|
||||||
|
|
||||||
|
NewNode.ImageKey = replaceNode.ImageKey;
|
||||||
|
NewNode.SelectedImageKey = replaceNode.SelectedImageKey;
|
||||||
|
NewNode.Text = replaceNode.Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OpenFormDialog(IFileFormat fileFormat)
|
||||||
|
{
|
||||||
|
UserControl form = GetEditorForm(fileFormat);
|
||||||
|
form.Text = (((IFileFormat)fileFormat).FileName);
|
||||||
|
|
||||||
|
var parentForm = LibraryGUI.Instance.GetActiveForm();
|
||||||
|
|
||||||
|
GenericEditorForm editorForm = new GenericEditorForm(true, form);
|
||||||
|
editorForm.FormClosing += (sender, e) => FormClosing(sender, e, fileFormat);
|
||||||
|
if (editorForm.ShowDialog() == DialogResult.OK)
|
||||||
|
{
|
||||||
|
if (fileFormat.CanSave)
|
||||||
|
{
|
||||||
|
ArchiveFileInfo.FileData = fileFormat.Save();
|
||||||
|
UpdateEditor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FormClosing(object sender, EventArgs args, IFileFormat fileFormat)
|
||||||
|
{
|
||||||
|
if (((Form)sender).DialogResult != DialogResult.OK)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserControl GetEditorForm(IFileFormat fileFormat)
|
||||||
|
{
|
||||||
|
Type objectType = fileFormat.GetType();
|
||||||
|
foreach (var inter in objectType.GetInterfaces())
|
||||||
|
{
|
||||||
|
if (inter.IsGenericType && inter.GetGenericTypeDefinition() == typeof(IEditor<>))
|
||||||
|
{
|
||||||
|
System.Reflection.MethodInfo method = objectType.GetMethod("OpenForm");
|
||||||
|
return (UserControl)method.Invoke(fileFormat, new object[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnClick(TreeView treeview) {
|
public override void OnClick(TreeView treeview) {
|
||||||
|
|
|
@ -193,6 +193,8 @@ namespace FirstPlugin
|
||||||
|
|
||||||
if (PluginRuntime.bntxContainers.Contains(this))
|
if (PluginRuntime.bntxContainers.Contains(this))
|
||||||
PluginRuntime.bntxContainers.Remove(this);
|
PluginRuntime.bntxContainers.Remove(this);
|
||||||
|
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] CreateNewBNTX(string Name)
|
public static byte[] CreateNewBNTX(string Name)
|
||||||
|
@ -225,6 +227,20 @@ namespace FirstPlugin
|
||||||
Textures.Remove(textureData.Text);
|
Textures.Remove(textureData.Text);
|
||||||
LibraryGUI.Instance.UpdateViewport();
|
LibraryGUI.Instance.UpdateViewport();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override UserControl GetEditor()
|
||||||
|
{
|
||||||
|
STPropertyGrid editor = new STPropertyGrid();
|
||||||
|
editor.Text = Text;
|
||||||
|
editor.Dock = DockStyle.Fill;
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void FillEditor(UserControl control)
|
||||||
|
{
|
||||||
|
((STPropertyGrid)control).LoadProperty(BinaryTexFile, OnPropertyChanged);
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnClick(TreeView treeView)
|
public override void OnClick(TreeView treeView)
|
||||||
{
|
{
|
||||||
if (Parent != null && Parent is BFRES)
|
if (Parent != null && Parent is BFRES)
|
||||||
|
|
|
@ -69,17 +69,17 @@ namespace FirstPlugin
|
||||||
|
|
||||||
public List<GTXDataBlock> blocks = new List<GTXDataBlock>();
|
public List<GTXDataBlock> blocks = new List<GTXDataBlock>();
|
||||||
|
|
||||||
public override void OnClick(TreeView treeview)
|
public override UserControl GetEditor()
|
||||||
{
|
{
|
||||||
STPropertyGrid editor = (STPropertyGrid)LibraryGUI.Instance.GetActiveContent(typeof(STPropertyGrid));
|
STPropertyGrid editor = new STPropertyGrid();
|
||||||
if (editor == null)
|
|
||||||
{
|
|
||||||
editor = new STPropertyGrid();
|
|
||||||
LibraryGUI.Instance.LoadEditor(editor);
|
|
||||||
}
|
|
||||||
editor.Text = Text;
|
editor.Text = Text;
|
||||||
editor.Dock = DockStyle.Fill;
|
editor.Dock = DockStyle.Fill;
|
||||||
editor.LoadProperty(header, null);
|
return editor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void FillEditor(UserControl control)
|
||||||
|
{
|
||||||
|
((STPropertyGrid)control).LoadProperty(header);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Load(System.IO.Stream stream)
|
public void Load(System.IO.Stream stream)
|
||||||
|
|
|
@ -318,12 +318,12 @@ namespace FirstPlugin
|
||||||
|
|
||||||
Formats.Add(typeof(Turbo.Course_MapCamera_bin));
|
Formats.Add(typeof(Turbo.Course_MapCamera_bin));
|
||||||
Formats.Add(typeof(Turbo.PartsBIN));
|
Formats.Add(typeof(Turbo.PartsBIN));
|
||||||
|
Formats.Add(typeof(SDF));
|
||||||
|
|
||||||
//Unfinished wip formats not ready for use
|
//Unfinished wip formats not ready for use
|
||||||
if (Runtime.DEVELOPER_DEBUG_MODE)
|
if (Runtime.DEVELOPER_DEBUG_MODE)
|
||||||
{
|
{
|
||||||
Formats.Add(typeof(GFBMDL));
|
Formats.Add(typeof(GFBMDL));
|
||||||
Formats.Add(typeof(SDF));
|
|
||||||
Formats.Add(typeof(NCA));
|
Formats.Add(typeof(NCA));
|
||||||
Formats.Add(typeof(XCI));
|
Formats.Add(typeof(XCI));
|
||||||
Formats.Add(typeof(BFLAN));
|
Formats.Add(typeof(BFLAN));
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -766,10 +766,10 @@ namespace Switch_Toolbox.Library
|
||||||
ArrayCount = DX10header.arrayFlag;
|
ArrayCount = DX10header.arrayFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Swizzle = false;
|
public bool SwitchSwizzle = false;
|
||||||
public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0)
|
public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0)
|
||||||
{
|
{
|
||||||
if (Swizzle)
|
if (SwitchSwizzle)
|
||||||
return TegraX1Swizzle.GetImageData(this, bdata, ArrayLevel, MipLevel);
|
return TegraX1Swizzle.GetImageData(this, bdata, ArrayLevel, MipLevel);
|
||||||
|
|
||||||
return GetArrayFaces(this, ArrayCount)[ArrayLevel].mipmaps[MipLevel];
|
return GetArrayFaces(this, ArrayCount)[ArrayLevel].mipmaps[MipLevel];
|
||||||
|
|
56
Switch_Toolbox_Library/FileFormats/ZIP.cs
Normal file
56
Switch_Toolbox_Library/FileFormats/ZIP.cs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.IO.Compression;
|
||||||
|
|
||||||
|
namespace Switch_Toolbox.Library
|
||||||
|
{
|
||||||
|
public class ZIP : TreeNodeFile, IFileFormat
|
||||||
|
{
|
||||||
|
const int MagicFileConstant = 0x504B0304;
|
||||||
|
|
||||||
|
public FileType FileType { get; set; } = FileType.Archive;
|
||||||
|
|
||||||
|
public bool CanSave { get; set; }
|
||||||
|
public string[] Description { get; set; } = new string[] { "ZIP" };
|
||||||
|
public string[] Extension { get; set; } = new string[] { "*.zip" };
|
||||||
|
public string FileName { get; set; }
|
||||||
|
public string FilePath { get; set; }
|
||||||
|
public IFileInfo IFileInfo { get; set; }
|
||||||
|
|
||||||
|
public bool Identify(System.IO.Stream stream)
|
||||||
|
{
|
||||||
|
using (var reader = new Switch_Toolbox.Library.IO.FileReader(stream, true))
|
||||||
|
{
|
||||||
|
reader.SetByteOrder(true);
|
||||||
|
return reader.ReadInt32() == MagicFileConstant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type[] Types
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
List<Type> types = new List<Type>();
|
||||||
|
return types.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Load(System.IO.Stream stream)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Save()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unload()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,7 +52,6 @@ namespace Switch_Toolbox.Library.Forms
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void UpdateEditor()
|
public void UpdateEditor()
|
||||||
{
|
{
|
||||||
if (GetEditor() == 0)
|
if (GetEditor() == 0)
|
||||||
|
@ -65,18 +64,25 @@ namespace Switch_Toolbox.Library.Forms
|
||||||
|
|
||||||
private void UpdateFileEditor()
|
private void UpdateFileEditor()
|
||||||
{
|
{
|
||||||
|
if (!ArchiveFileInfo.IsSupportedFileFormat())
|
||||||
|
{
|
||||||
|
AddControl(new STUserControl());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var File = ArchiveFileInfo.FileFormat;
|
var File = ArchiveFileInfo.FileFormat;
|
||||||
if (File == null)
|
if (File == null) //If the file is not open yet, try temporarily for a preview
|
||||||
File = ArchiveFileInfo.OpenFile();
|
File = ArchiveFileInfo.OpenFile();
|
||||||
|
|
||||||
UserControl control = GetEditorForm(File);
|
UserControl control = GetEditorForm(File);
|
||||||
if (control != null)
|
if (control != null)
|
||||||
{
|
{
|
||||||
AddControl(control);
|
AddControl(control);
|
||||||
|
|
||||||
// if (CheckActiveType(control.GetType()))
|
|
||||||
// AddControl(control);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//If the format isn't active we can just dispose it
|
||||||
|
if (ArchiveFileInfo.FileFormat == null)
|
||||||
|
File.Unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CheckActiveType(Type type)
|
private bool CheckActiveType(Type type)
|
||||||
|
@ -89,13 +95,30 @@ namespace Switch_Toolbox.Library.Forms
|
||||||
if (fileFormat == null)
|
if (fileFormat == null)
|
||||||
return new STUserControl() { Dock = DockStyle.Fill };
|
return new STUserControl() { Dock = DockStyle.Fill };
|
||||||
|
|
||||||
|
if (fileFormat is TreeNodeFile)
|
||||||
|
{
|
||||||
|
var Editor = ((TreeNodeFile)fileFormat).GetEditor();
|
||||||
|
var ActiveEditor = GetActiveEditor(Editor.GetType());
|
||||||
|
if (ActiveEditor != null)
|
||||||
|
Editor = ActiveEditor;
|
||||||
|
|
||||||
|
((TreeNodeFile)fileFormat).FillEditor(Editor);
|
||||||
|
|
||||||
|
return Editor;
|
||||||
|
}
|
||||||
|
|
||||||
Type objectType = fileFormat.GetType();
|
Type objectType = fileFormat.GetType();
|
||||||
foreach (var inter in objectType.GetInterfaces())
|
foreach (var inter in objectType.GetInterfaces())
|
||||||
{
|
{
|
||||||
if (inter.IsGenericType && inter.GetGenericTypeDefinition() == typeof(IEditor<>))
|
if (inter.IsGenericType && inter.GetGenericTypeDefinition() == typeof(IEditor<>))
|
||||||
{
|
{
|
||||||
System.Reflection.MethodInfo method = objectType.GetMethod("OpenForm");
|
System.Reflection.MethodInfo method = objectType.GetMethod("OpenForm");
|
||||||
return (UserControl)method.Invoke(fileFormat, new object[0]);
|
var Editor = (UserControl)method.Invoke(fileFormat, new object[0]);
|
||||||
|
var ActiveEditor = GetActiveEditor(Editor.GetType());
|
||||||
|
if (ActiveEditor != null)
|
||||||
|
Editor = ActiveEditor;
|
||||||
|
|
||||||
|
return Editor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -22,6 +22,7 @@ namespace Switch_Toolbox.Library
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TreeNodeFile : TreeNodeCustom
|
public class TreeNodeFile : TreeNodeCustom
|
||||||
{
|
{
|
||||||
public bool CanDelete
|
public bool CanDelete
|
||||||
|
@ -38,6 +39,23 @@ namespace Switch_Toolbox.Library
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual UserControl GetEditor() { return new STUserControl(); }
|
||||||
|
public virtual void FillEditor(UserControl control) { }
|
||||||
|
|
||||||
|
public override void OnClick(TreeView treeview)
|
||||||
|
{
|
||||||
|
var Editor = GetEditor();
|
||||||
|
Editor.Dock = DockStyle.Fill;
|
||||||
|
|
||||||
|
var ActiveEditor = LibraryGUI.Instance.GetActiveContent(Editor.GetType());
|
||||||
|
if (ActiveEditor != null)
|
||||||
|
Editor = ActiveEditor;
|
||||||
|
else
|
||||||
|
LibraryGUI.Instance.LoadEditor(Editor);
|
||||||
|
|
||||||
|
FillEditor(Editor);
|
||||||
|
}
|
||||||
|
|
||||||
public TreeNodeFile()
|
public TreeNodeFile()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -77,13 +77,13 @@
|
||||||
this.findToolStripMenuItem.Text = "Find";
|
this.findToolStripMenuItem.Text = "Find";
|
||||||
this.findToolStripMenuItem.Click += new System.EventHandler(this.findToolStripMenuItem_Click);
|
this.findToolStripMenuItem.Click += new System.EventHandler(this.findToolStripMenuItem_Click);
|
||||||
//
|
//
|
||||||
// HexEditor
|
// HexEditor2
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
this.Controls.Add(this.hexBox1);
|
this.Controls.Add(this.hexBox1);
|
||||||
this.Controls.Add(this.stContextMenuStrip1);
|
this.Controls.Add(this.stContextMenuStrip1);
|
||||||
this.Name = "HexEditor";
|
this.Name = "HexEditor2";
|
||||||
this.Size = new System.Drawing.Size(529, 454);
|
this.Size = new System.Drawing.Size(529, 454);
|
||||||
this.stContextMenuStrip1.ResumeLayout(false);
|
this.stContextMenuStrip1.ResumeLayout(false);
|
||||||
this.stContextMenuStrip1.PerformLayout();
|
this.stContextMenuStrip1.PerformLayout();
|
||||||
|
|
|
@ -11,10 +11,38 @@ using Be.Windows.Forms;
|
||||||
|
|
||||||
namespace Switch_Toolbox.Library.Forms
|
namespace Switch_Toolbox.Library.Forms
|
||||||
{
|
{
|
||||||
public partial class HexEditor : UserControl
|
public partial class HexEditor : STUserControl
|
||||||
{
|
{
|
||||||
FindOptions _findOptions = new FindOptions();
|
FindOptions _findOptions = new FindOptions();
|
||||||
|
|
||||||
|
public HexEditor()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
hexBox1.BackColor = FormThemes.BaseTheme.FormBackColor;
|
||||||
|
hexBox1.ForeColor = FormThemes.BaseTheme.FormForeColor;
|
||||||
|
hexBox1.SelectionBackColor = FormThemes.BaseTheme.FormContextMenuSelectColor;
|
||||||
|
hexBox1.SelectionForeColor = FormThemes.BaseTheme.FormForeColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnControlClosing()
|
||||||
|
{
|
||||||
|
Cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cleanup()
|
||||||
|
{
|
||||||
|
if (hexBox1.ByteProvider != null)
|
||||||
|
{
|
||||||
|
hexBox1.ByteProvider.DeleteBytes(0, hexBox1.ByteProvider.Length);
|
||||||
|
|
||||||
|
IDisposable byteProvider = hexBox1.ByteProvider as IDisposable;
|
||||||
|
if (byteProvider != null)
|
||||||
|
byteProvider.Dispose();
|
||||||
|
hexBox1.ByteProvider = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool EnableMenuBar
|
public bool EnableMenuBar
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
|
@ -30,18 +58,12 @@ namespace Switch_Toolbox.Library.Forms
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public HexEditor()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
hexBox1.BackColor = FormThemes.BaseTheme.FormBackColor;
|
|
||||||
hexBox1.ForeColor = FormThemes.BaseTheme.FormForeColor;
|
|
||||||
hexBox1.SelectionBackColor = FormThemes.BaseTheme.FormContextMenuSelectColor;
|
|
||||||
hexBox1.SelectionForeColor = FormThemes.BaseTheme.FormForeColor;
|
|
||||||
}
|
|
||||||
public void LoadData(byte[] data)
|
public void LoadData(byte[] data)
|
||||||
{
|
{
|
||||||
hexBox1.ByteProvider = new DynamicByteProvider(data);
|
Cleanup();
|
||||||
|
|
||||||
|
IByteProvider provider = new DynamicByteProvider(data);
|
||||||
|
hexBox1.ByteProvider = provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findToolStripMenuItem_Click(object sender, EventArgs e)
|
private void findToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
|
|
56
Switch_Toolbox_Library/Forms/Editors/HexEditor/HexEditorNew.Designer.cs
generated
Normal file
56
Switch_Toolbox_Library/Forms/Editors/HexEditor/HexEditorNew.Designer.cs
generated
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
namespace Switch_Toolbox.Library.Forms.Old
|
||||||
|
{
|
||||||
|
partial class HexEditor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Component Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.stPanel1 = new Switch_Toolbox.Library.Forms.STPanel();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// stPanel1
|
||||||
|
//
|
||||||
|
this.stPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
this.stPanel1.Location = new System.Drawing.Point(0, 0);
|
||||||
|
this.stPanel1.Name = "stPanel1";
|
||||||
|
this.stPanel1.Size = new System.Drawing.Size(529, 454);
|
||||||
|
this.stPanel1.TabIndex = 2;
|
||||||
|
//
|
||||||
|
// HexEditor
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.Controls.Add(this.stPanel1);
|
||||||
|
this.Name = "HexEditor";
|
||||||
|
this.Size = new System.Drawing.Size(529, 454);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
private STPanel stPanel1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Data;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.ComponentModel.Design;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using Be.Windows.Forms;
|
||||||
|
|
||||||
|
namespace Switch_Toolbox.Library.Forms.Old
|
||||||
|
{
|
||||||
|
public partial class HexEditor : STUserControl
|
||||||
|
{
|
||||||
|
FindOptions _findOptions = new FindOptions();
|
||||||
|
ByteViewer ByteViewer;
|
||||||
|
|
||||||
|
public HexEditor()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
ByteViewer = new ByteViewer();
|
||||||
|
ByteViewer.BackColor = FormThemes.BaseTheme.FormBackColor;
|
||||||
|
ByteViewer.ForeColor = FormThemes.BaseTheme.FormForeColor;
|
||||||
|
|
||||||
|
ByteViewer.Dock = DockStyle.Fill;
|
||||||
|
stPanel1.Controls.Add(ByteViewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnControlClosing()
|
||||||
|
{
|
||||||
|
Cleanup();
|
||||||
|
ByteViewer.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cleanup()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void LoadData(byte[] data)
|
||||||
|
{
|
||||||
|
Cleanup();
|
||||||
|
ByteViewer.SetBytes(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
120
Switch_Toolbox_Library/Forms/Editors/HexEditor/HexEditorNew.resx
Normal file
120
Switch_Toolbox_Library/Forms/Editors/HexEditor/HexEditorNew.resx
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
|
@ -114,52 +114,63 @@ namespace Switch_Toolbox.Library.Forms
|
||||||
{
|
{
|
||||||
var rootText = root.Text;
|
var rootText = root.Text;
|
||||||
var rootTextLength = rootText.Length;
|
var rootTextLength = rootText.Length;
|
||||||
var nodeStrings = archiveFile.Files;
|
var nodeFiles = archiveFile.Files;
|
||||||
foreach (var node in nodeStrings)
|
if (nodeFiles.Count() > 400)
|
||||||
{
|
{
|
||||||
string nodeString = node.FileName;
|
foreach (var node in nodeFiles)
|
||||||
|
|
||||||
var roots = nodeString.Split(new char[] { '/' },
|
|
||||||
StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
|
|
||||||
// The initial parent is the root node
|
|
||||||
var parentNode = root;
|
|
||||||
var sb = new StringBuilder(rootText, nodeString.Length + rootTextLength);
|
|
||||||
for (int rootIndex = 0; rootIndex < roots.Length; rootIndex++)
|
|
||||||
{
|
{
|
||||||
// Build the node name
|
ArchiveFileWrapper wrapperFile = new ArchiveFileWrapper(node.FileName, node, archiveFile);
|
||||||
var parentName = roots[rootIndex];
|
root.Nodes.Add(wrapperFile);
|
||||||
sb.Append("/");
|
}
|
||||||
sb.Append(parentName);
|
}
|
||||||
var nodeName = sb.ToString();
|
else
|
||||||
|
{
|
||||||
|
foreach (var node in nodeFiles)
|
||||||
|
{
|
||||||
|
string nodeString = node.FileName;
|
||||||
|
|
||||||
// Search for the node
|
var roots = nodeString.Split(new char[] { '/' },
|
||||||
var index = parentNode.Nodes.IndexOfKey(nodeName);
|
StringSplitOptions.RemoveEmptyEntries);
|
||||||
if (index == -1)
|
|
||||||
|
// The initial parent is the root node
|
||||||
|
var parentNode = root;
|
||||||
|
var sb = new StringBuilder(rootText, nodeString.Length + rootTextLength);
|
||||||
|
for (int rootIndex = 0; rootIndex < roots.Length; rootIndex++)
|
||||||
{
|
{
|
||||||
// Node was not found, add it
|
// Build the node name
|
||||||
|
var parentName = roots[rootIndex];
|
||||||
|
sb.Append("/");
|
||||||
|
sb.Append(parentName);
|
||||||
|
var nodeName = sb.ToString();
|
||||||
|
|
||||||
var folder = new ArchiveFolderNodeWrapper(parentName, archiveFile);
|
// Search for the node
|
||||||
|
var index = parentNode.Nodes.IndexOfKey(nodeName);
|
||||||
if (rootIndex == roots.Length - 1)
|
if (index == -1)
|
||||||
{
|
{
|
||||||
ArchiveFileWrapper wrapperFile = new ArchiveFileWrapper(parentName, node, archiveFile);
|
// Node was not found, add it
|
||||||
wrapperFile.Name = nodeName;
|
|
||||||
parentNode.Nodes.Add(wrapperFile);
|
var folder = new ArchiveFolderNodeWrapper(parentName, archiveFile);
|
||||||
parentNode = wrapperFile;
|
|
||||||
|
if (rootIndex == roots.Length - 1)
|
||||||
|
{
|
||||||
|
ArchiveFileWrapper wrapperFile = new ArchiveFileWrapper(parentName, node, archiveFile);
|
||||||
|
wrapperFile.Name = nodeName;
|
||||||
|
parentNode.Nodes.Add(wrapperFile);
|
||||||
|
parentNode = wrapperFile;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
folder.Name = nodeName;
|
||||||
|
parentNode.Nodes.Add(folder);
|
||||||
|
parentNode = folder;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
folder.Name = nodeName;
|
// Node was found, set that as parent and continue
|
||||||
parentNode.Nodes.Add(folder);
|
parentNode = parentNode.Nodes[index];
|
||||||
parentNode = folder;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Node was found, set that as parent and continue
|
|
||||||
parentNode = parentNode.Nodes[index];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,12 +40,32 @@ namespace Switch_Toolbox.Library
|
||||||
|
|
||||||
public FileType FileDataType = FileType.Default;
|
public FileType FileDataType = FileType.Default;
|
||||||
|
|
||||||
public IFileFormat OpenFile()
|
public virtual IFileFormat OpenFile()
|
||||||
{
|
{
|
||||||
return STFileLoader.OpenFileFormat(
|
return STFileLoader.OpenFileFormat(
|
||||||
IOExtensions.RemoveIllegaleFolderNameCharacters(FileName), FileData, true);
|
IOExtensions.RemoveIllegaleFolderNameCharacters(FileName), FileData, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsSupportedFileFormat()
|
||||||
|
{
|
||||||
|
if (FileData == null || FileData.Length <= 4)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
using (var stream = new MemoryStream(FileData))
|
||||||
|
{
|
||||||
|
foreach (IFileFormat fileFormat in FileManager.GetFileFormats())
|
||||||
|
{
|
||||||
|
fileFormat.FileName = FileName;
|
||||||
|
if (fileFormat.Identify(stream))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public virtual void Replace()
|
public virtual void Replace()
|
||||||
{
|
{
|
||||||
string fileName = Path.GetFileName(FileName.RemoveIllegaleFileNameCharacters());
|
string fileName = Path.GetFileName(FileName.RemoveIllegaleFileNameCharacters());
|
||||||
|
|
|
@ -35,6 +35,9 @@
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<SignAssembly>false</SignAssembly>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="AssimpNet">
|
<Reference Include="AssimpNet">
|
||||||
<HintPath>..\Toolbox\Lib\AssimpNet.dll</HintPath>
|
<HintPath>..\Toolbox\Lib\AssimpNet.dll</HintPath>
|
||||||
|
@ -224,6 +227,7 @@
|
||||||
<Compile Include="FileFormats\R4G4.cs" />
|
<Compile Include="FileFormats\R4G4.cs" />
|
||||||
<Compile Include="FileFormats\SizeTables\RSTB.cs" />
|
<Compile Include="FileFormats\SizeTables\RSTB.cs" />
|
||||||
<Compile Include="FileFormats\SizeTables\TPFileSizeTable.cs" />
|
<Compile Include="FileFormats\SizeTables\TPFileSizeTable.cs" />
|
||||||
|
<Compile Include="FileFormats\ZIP.cs" />
|
||||||
<Compile Include="Forms\Archive\ArchiveFilePanel.cs">
|
<Compile Include="Forms\Archive\ArchiveFilePanel.cs">
|
||||||
<SubType>UserControl</SubType>
|
<SubType>UserControl</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -370,6 +374,12 @@
|
||||||
<DependentUpon>AudioPlayer.cs</DependentUpon>
|
<DependentUpon>AudioPlayer.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Forms\Editors\Audio\AudioFile.cs" />
|
<Compile Include="Forms\Editors\Audio\AudioFile.cs" />
|
||||||
|
<Compile Include="Forms\Editors\HexEditor\HexEditorNew.cs">
|
||||||
|
<SubType>UserControl</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Forms\Editors\HexEditor\HexEditorNew.Designer.cs">
|
||||||
|
<DependentUpon>HexEditorNew.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Forms\Editors\HexEditor\HexEditor.cs">
|
<Compile Include="Forms\Editors\HexEditor\HexEditor.cs">
|
||||||
<SubType>UserControl</SubType>
|
<SubType>UserControl</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -780,6 +790,9 @@
|
||||||
<EmbeddedResource Include="Forms\Editors\CubeMapFaceCreator.resx">
|
<EmbeddedResource Include="Forms\Editors\CubeMapFaceCreator.resx">
|
||||||
<DependentUpon>CubeMapFaceCreator.cs</DependentUpon>
|
<DependentUpon>CubeMapFaceCreator.cs</DependentUpon>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Forms\Editors\HexEditor\HexEditorNew.resx">
|
||||||
|
<DependentUpon>HexEditorNew.cs</DependentUpon>
|
||||||
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Include="Forms\Editors\HexEditor\HexEditor.resx">
|
<EmbeddedResource Include="Forms\Editors\HexEditor\HexEditor.resx">
|
||||||
<DependentUpon>HexEditor.cs</DependentUpon>
|
<DependentUpon>HexEditor.cs</DependentUpon>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
|
|
@ -6,6 +6,7 @@ using System.Runtime.Serialization.Formatters.Binary;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Switch_Toolbox.Library.IO;
|
||||||
|
|
||||||
namespace Switch_Toolbox.Library
|
namespace Switch_Toolbox.Library
|
||||||
{
|
{
|
||||||
|
@ -135,6 +136,16 @@ namespace Switch_Toolbox.Library
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] SubArray(Stream data, uint offset, uint length)
|
||||||
|
{
|
||||||
|
using (var reader = new FileReader(data))
|
||||||
|
{
|
||||||
|
reader.Position = offset;
|
||||||
|
return reader.ReadBytes((int)length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static byte[] SubArray(byte[] data, uint offset, uint length)
|
public static byte[] SubArray(byte[] data, uint offset, uint length)
|
||||||
{
|
{
|
||||||
return data.Skip((int)offset).Take((int)length).ToArray();
|
return data.Skip((int)offset).Take((int)length).ToArray();
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
</requestedPrivileges>
|
</requestedPrivileges>
|
||||||
<applicationRequestMinimum>
|
<applicationRequestMinimum>
|
||||||
<defaultAssemblyRequest permissionSetReference="Custom" />
|
<defaultAssemblyRequest permissionSetReference="Custom" />
|
||||||
<PermissionSet class="System.Security.PermissionSet" version="1" ID="Custom" SameSite="site" Unrestricted="true" />
|
<PermissionSet class="System.Security.PermissionSet" version="1" ID="Custom" SameSite="site" />
|
||||||
</applicationRequestMinimum>
|
</applicationRequestMinimum>
|
||||||
</security>
|
</security>
|
||||||
</trustInfo>
|
</trustInfo>
|
||||||
|
|
Loading…
Add table
Reference in a new issue