Wip zar, gar,, and more rarc saving progress
This commit is contained in:
parent
40c0fcae11
commit
e0df03cc26
Binary file not shown.
237
File_Format_Library/FileFormats/Archives/Grezzo/ZAR.cs
Normal file
237
File_Format_Library/FileFormats/Archives/Grezzo/ZAR.cs
Normal file
@ -0,0 +1,237 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Toolbox;
|
||||
using System.Windows.Forms;
|
||||
using Toolbox.Library;
|
||||
using Toolbox.Library.IO;
|
||||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
public class ZAR : IArchiveFile, IFileFormat
|
||||
{
|
||||
public FileType FileType { get; set; } = FileType.Archive;
|
||||
|
||||
public bool CanSave { get; set; }
|
||||
public string[] Description { get; set; } = new string[] { "Zelda/Grezzo Archive" };
|
||||
public string[] Extension { get; set; } = new string[] { "*.zar", "*.gar" };
|
||||
public string FileName { get; set; }
|
||||
public string FilePath { get; set; }
|
||||
public IFileInfo IFileInfo { get; set; }
|
||||
|
||||
public bool CanAddFiles { get; set; }
|
||||
public bool CanRenameFiles { get; set; }
|
||||
public bool CanReplaceFiles { get; set; }
|
||||
public bool CanDeleteFiles { get; set; }
|
||||
|
||||
public bool Identify(System.IO.Stream stream)
|
||||
{
|
||||
using (var reader = new Toolbox.Library.IO.FileReader(stream, true))
|
||||
{
|
||||
return reader.CheckSignature(4, "ZAR/x01") || reader.CheckSignature(4, "GAR\x02") || reader.CheckSignature(4, "GAR\x05");
|
||||
}
|
||||
}
|
||||
|
||||
public Type[] Types
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Type> types = new List<Type>();
|
||||
return types.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public List<FileEntry> files = new List<FileEntry>();
|
||||
|
||||
public IEnumerable<ArchiveFileInfo> Files => files;
|
||||
|
||||
public void ClearFiles() { files.Clear(); }
|
||||
|
||||
public enum VersionMagic
|
||||
{
|
||||
ZAR1, //OOT3D
|
||||
GAR2, //MM3D
|
||||
GAR5, //LM3DS
|
||||
}
|
||||
|
||||
public Header header;
|
||||
|
||||
public void Load(System.IO.Stream stream)
|
||||
{
|
||||
header = new Header();
|
||||
header.Read(new FileReader(stream), files);
|
||||
}
|
||||
|
||||
public class Header
|
||||
{
|
||||
public VersionMagic Version;
|
||||
|
||||
public uint FileSize;
|
||||
public ushort FileGroupCount;
|
||||
public ushort FileCount;
|
||||
public uint FileGroupOffset;
|
||||
public uint FileInfoOffset;
|
||||
public uint DataOffset;
|
||||
public string Codename;
|
||||
|
||||
public List<FileGroup> FileGroups = new List<FileGroup>();
|
||||
public List<GarFileInfo> GarFileInfos = new List<GarFileInfo>();
|
||||
|
||||
public void Read(FileReader reader, List<FileEntry> files)
|
||||
{
|
||||
reader.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian;
|
||||
string Signature = reader.ReadString(4, Encoding.ASCII);
|
||||
switch (Signature)
|
||||
{
|
||||
case "ZAR\x01":
|
||||
Version = VersionMagic.ZAR1;
|
||||
break;
|
||||
case "GAR\x02":
|
||||
Version = VersionMagic.GAR2;
|
||||
break;
|
||||
case "GAR\x05":
|
||||
Version = VersionMagic.GAR5;
|
||||
break;
|
||||
}
|
||||
|
||||
FileSize = reader.ReadUInt32();
|
||||
FileGroupCount = reader.ReadUInt16();
|
||||
FileCount = reader.ReadUInt16();
|
||||
FileGroupOffset = reader.ReadUInt32();
|
||||
FileInfoOffset = reader.ReadUInt32();
|
||||
DataOffset = reader.ReadUInt32();
|
||||
Codename = reader.ReadString(0x08);
|
||||
|
||||
switch (Codename)
|
||||
{
|
||||
case "queen\0\0\0":
|
||||
case "jenkins\0":
|
||||
ReadZeldaArchive(reader, files);
|
||||
break;
|
||||
case "agora\0\0\0":
|
||||
case "SYSTEM\0\0":
|
||||
ReadGrezzoArchive(reader, files);
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"Unexpected codename! {Codename}");
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadGrezzoArchive(FileReader reader, List<FileEntry> files)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void ReadZeldaArchive(FileReader reader, List<FileEntry> files)
|
||||
{
|
||||
reader.SeekBegin(FileGroupOffset);
|
||||
for (int i = 0; i < FileGroupCount; i++)
|
||||
FileGroups.Add(new FileGroup(reader));
|
||||
|
||||
for (int i = 0; i < FileGroupCount; i++)
|
||||
FileGroups[i].Ids = reader.ReadInt32s((int)FileGroups[i].FileCount);
|
||||
|
||||
|
||||
reader.SeekBegin(FileInfoOffset);
|
||||
for (int i = 0; i < FileGroupCount; i++)
|
||||
{
|
||||
for (int f = 0; f < FileGroups[i].FileCount; f++)
|
||||
GarFileInfos.Add(new GarFileInfo(reader));
|
||||
}
|
||||
|
||||
reader.SeekBegin(DataOffset);
|
||||
uint[] Offsets = reader.ReadUInt32s(FileCount);
|
||||
for (int i = 0; i < GarFileInfos.Count; i++)
|
||||
{
|
||||
files.Add(new FileEntry()
|
||||
{
|
||||
FileName = GarFileInfos[i].FileName,
|
||||
FileData = reader.getSection(Offsets[i], GarFileInfos[i].FileSize)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class FileGroup
|
||||
{
|
||||
public uint FileCount;
|
||||
public uint DataOffset;
|
||||
public uint InfoOffset;
|
||||
|
||||
public int[] Ids;
|
||||
|
||||
public FileGroup(FileReader reader)
|
||||
{
|
||||
FileCount = reader.ReadUInt32();
|
||||
DataOffset = reader.ReadUInt32();
|
||||
InfoOffset = reader.ReadUInt32();
|
||||
reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
|
||||
public class ZarFileInfo
|
||||
{
|
||||
public uint FileSize;
|
||||
public string FileName;
|
||||
|
||||
public ZarFileInfo(FileReader reader)
|
||||
{
|
||||
FileSize = reader.ReadUInt32();
|
||||
FileName = reader.LoadString(false, typeof(uint));
|
||||
}
|
||||
}
|
||||
|
||||
public class GarFileInfo
|
||||
{
|
||||
public uint FileSize;
|
||||
public string FileName;
|
||||
public string Name;
|
||||
|
||||
public GarFileInfo(FileReader reader)
|
||||
{
|
||||
FileSize = reader.ReadUInt32();
|
||||
Name = reader.LoadString(false, typeof(uint));
|
||||
FileName = reader.LoadString(false, typeof(uint));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public byte[] Save()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool AddFile(ArchiveFileInfo archiveFileInfo)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool DeleteFile(ArchiveFileInfo archiveFileInfo)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public class FileEntry : ArchiveFileInfo
|
||||
{
|
||||
public uint Unknown { get; set; }
|
||||
|
||||
internal uint Size;
|
||||
internal uint Offset;
|
||||
internal uint NameOffset;
|
||||
|
||||
public void Read(FileReader reader)
|
||||
{
|
||||
uint Unknown = reader.ReadUInt32();
|
||||
NameOffset = reader.ReadUInt32();
|
||||
Offset = reader.ReadUInt32();
|
||||
Size = reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
145
File_Format_Library/FileFormats/Archives/Grezzo/ZSI.cs
Normal file
145
File_Format_Library/FileFormats/Archives/Grezzo/ZSI.cs
Normal file
@ -0,0 +1,145 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Toolbox;
|
||||
using System.Windows.Forms;
|
||||
using Toolbox.Library;
|
||||
using Toolbox.Library.IO;
|
||||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
//Information on this file from noclip
|
||||
//https://github.com/magcius/noclip.website/blob/master/src/oot3d/zsi.ts
|
||||
public class ZSI : TreeNodeFile, IFileFormat
|
||||
{
|
||||
public FileType FileType { get; set; } = FileType.Archive;
|
||||
|
||||
public bool CanSave { get; set; }
|
||||
public string[] Description { get; set; } = new string[] { "Zelda Scene Information (OOT3D/MM3D)" };
|
||||
public string[] Extension { get; set; } = new string[] { "*.zsi" };
|
||||
public string FileName { get; set; }
|
||||
public string FilePath { get; set; }
|
||||
public IFileInfo IFileInfo { get; set; }
|
||||
|
||||
public bool CanAddFiles { get; set; }
|
||||
public bool CanRenameFiles { get; set; }
|
||||
public bool CanReplaceFiles { get; set; }
|
||||
public bool CanDeleteFiles { get; set; }
|
||||
|
||||
public bool Identify(System.IO.Stream stream)
|
||||
{
|
||||
using (var reader = new Toolbox.Library.IO.FileReader(stream, true))
|
||||
{
|
||||
return reader.CheckSignature(4, "ZSI\x01") || reader.CheckSignature(4, "ZSI\x09");
|
||||
}
|
||||
}
|
||||
|
||||
public Type[] Types
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Type> types = new List<Type>();
|
||||
return types.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public GameVersion Version;
|
||||
|
||||
public enum GameVersion
|
||||
{
|
||||
OOT3D,
|
||||
MM3D,
|
||||
}
|
||||
|
||||
public enum HeaderCommands : uint
|
||||
{
|
||||
Actor = 0x01,
|
||||
Collision = 0x03,
|
||||
Rooms = 0x04,
|
||||
Mesh = 0x0A,
|
||||
DoorActor = 0x0E,
|
||||
SkyboxSettings = 0x11,
|
||||
End = 0x14,
|
||||
MultiSetup = 0x18,
|
||||
EnvironmentSettings = 0x0F,
|
||||
}
|
||||
|
||||
public void Load(System.IO.Stream stream)
|
||||
{
|
||||
Text = FileName;
|
||||
|
||||
using (var reader = new FileReader(stream))
|
||||
{
|
||||
reader.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian;
|
||||
string Signature = reader.ReadString(4, Encoding.ASCII);
|
||||
switch (Signature)
|
||||
{
|
||||
case "ZSI\x01":
|
||||
Version = GameVersion.OOT3D;
|
||||
break;
|
||||
default:
|
||||
Version = GameVersion.MM3D;
|
||||
break;
|
||||
}
|
||||
|
||||
string CodeName = reader.ReadString(0x0C);
|
||||
|
||||
ReadScene(reader);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadScene(FileReader reader)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
reader.SetByteOrder(true);
|
||||
uint cmd1 = reader.ReadUInt32();
|
||||
reader.SetByteOrder(false);
|
||||
uint cmd2 = reader.ReadUInt32();
|
||||
|
||||
reader.Seek(0x08);
|
||||
|
||||
var cmdType = cmd1 >> 24;
|
||||
|
||||
if (cmdType == (uint)HeaderCommands.End)
|
||||
break;
|
||||
|
||||
switch (cmdType)
|
||||
{
|
||||
case (uint)HeaderCommands.EnvironmentSettings:
|
||||
{
|
||||
Nodes.Add("EnvironmentSettings");
|
||||
}
|
||||
break;
|
||||
case (uint)HeaderCommands.DoorActor:
|
||||
{
|
||||
Nodes.Add("DoorActor");
|
||||
}
|
||||
break;
|
||||
case (uint)HeaderCommands.Rooms:
|
||||
{
|
||||
Nodes.Add("Rooms");
|
||||
}
|
||||
break;
|
||||
case (uint)HeaderCommands.SkyboxSettings:
|
||||
{
|
||||
Nodes.Add("SkyboxSettings");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public byte[] Save()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -57,8 +57,8 @@ namespace FirstPlugin.LuigisMansion.DarkMoon
|
||||
public LM2_Renderer Renderer;
|
||||
public DrawableContainer DrawableContainer = new DrawableContainer();
|
||||
|
||||
TreeNode textureFolder = new TreeNode("Textures");
|
||||
TreeNode modelFolder = new TreeNode("Models");
|
||||
TextureFolder textureFolder = new TextureFolder("Textures");
|
||||
LM2_ModelFolder modelFolder;
|
||||
TreeNode materialNamesFolder = new TreeNode("Material Names");
|
||||
TreeNode chunkFolder = new TreeNode("Chunks");
|
||||
|
||||
@ -70,6 +70,7 @@ namespace FirstPlugin.LuigisMansion.DarkMoon
|
||||
public bool DrawablesLoaded = false;
|
||||
public void Load(System.IO.Stream stream)
|
||||
{
|
||||
modelFolder = new LM2_ModelFolder(this);
|
||||
DrawableContainer.Name = FileName;
|
||||
Renderer = new LM2_Renderer();
|
||||
DrawableContainer.Drawables.Add(Renderer);
|
||||
|
@ -163,73 +163,44 @@ namespace FirstPlugin
|
||||
}
|
||||
}
|
||||
|
||||
public int GetTotalCount()
|
||||
{
|
||||
int count = 0;
|
||||
foreach (var dir in Nodes)
|
||||
GetTotalCount(dir, count);
|
||||
return count;
|
||||
}
|
||||
private List<FileEntry> _savedFiles = new List<FileEntry>();
|
||||
private List<DirectoryEntry> _savedDirectories = new List<DirectoryEntry>();
|
||||
|
||||
public int GetFileCount()
|
||||
private void LoadAllDirectoriesAndFiles(DirectoryEntry parentDir)
|
||||
{
|
||||
int count = 0;
|
||||
foreach (var dir in Nodes)
|
||||
GetFileCount(dir, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
public int GetDirectoryCount()
|
||||
{
|
||||
int count = 0;
|
||||
foreach (var dir in Nodes)
|
||||
GetDirectoryCount(dir, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
private int GetTotalCount(INode node, int count)
|
||||
{
|
||||
count++;
|
||||
|
||||
if (node is DirectoryEntry)
|
||||
for (int i = 0; i < parentDir.nodes.Count; i++)
|
||||
{
|
||||
foreach (var c in ((DirectoryEntry)node).nodes)
|
||||
return GetTotalCount(c, count);
|
||||
if (parentDir.nodes[i] is DirectoryEntry)
|
||||
{
|
||||
_savedDirectories.Add((DirectoryEntry)parentDir.nodes[i]);
|
||||
}
|
||||
else
|
||||
_savedFiles.Add((FileEntry)parentDir.nodes[i]);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
private int GetFileCount(INode node, int count)
|
||||
{
|
||||
if (node is FileEntry)
|
||||
count++;
|
||||
|
||||
if (node is DirectoryEntry)
|
||||
for (int i = 0; i < parentDir.nodes.Count; i++)
|
||||
{
|
||||
foreach (var c in ((DirectoryEntry)node).nodes)
|
||||
return GetFileCount(c, count);
|
||||
if (parentDir.nodes[i] is DirectoryEntry)
|
||||
LoadAllDirectoriesAndFiles((DirectoryEntry)parentDir.nodes[i]);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private int GetDirectoryCount(INode node, int count)
|
||||
{
|
||||
if (node is DirectoryEntry)
|
||||
{
|
||||
count++;
|
||||
|
||||
foreach (var c in ((DirectoryEntry)node).nodes)
|
||||
return GetDirectoryCount(c, count);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
//Save a string table to a char array like WArchive
|
||||
//It's a good idea, and i don't want to deal with offset linking
|
||||
private List<char> _exportStringTable;
|
||||
private List<byte[]> _savedFileData;
|
||||
public void SaveFile(FileWriter writer)
|
||||
{
|
||||
_exportStringTable = new List<char>();
|
||||
_savedFileData = new List<byte[]>();
|
||||
|
||||
_savedDirectories.Add(Directories[0]);
|
||||
LoadAllDirectoriesAndFiles(Directories[0]);
|
||||
|
||||
_exportStringTable = new List<char>();
|
||||
_exportStringTable.AddRange(".\0".ToCharArray());
|
||||
_exportStringTable.AddRange("..\0".ToCharArray());
|
||||
|
||||
long pos = writer.Position;
|
||||
|
||||
writer.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian;
|
||||
@ -244,40 +215,126 @@ namespace FirstPlugin
|
||||
writer.SeekBegin(HeaderSize);
|
||||
long InfoPos = writer.Position;
|
||||
|
||||
writer.Write(GetDirectoryCount());
|
||||
writer.Write(_savedDirectories.Count);
|
||||
writer.Write(uint.MaxValue); //DirectoryOffset
|
||||
writer.Write(GetFileCount());
|
||||
writer.Write(_savedDirectories.Count + _savedFiles.Count);
|
||||
writer.Write(uint.MaxValue); //File Node Offset
|
||||
writer.Write(uint.MaxValue); //String pool size
|
||||
writer.Write(uint.MaxValue); //String pool offset
|
||||
writer.Write((ushort)GetFileCount());
|
||||
writer.Write((ushort)0);
|
||||
writer.Write((ushort)Unknown);
|
||||
writer.Write(0); //padding
|
||||
|
||||
//Write directory Offset
|
||||
WriteOffset(writer, 4, InfoPos);
|
||||
for (int dir = 0; dir < Directories.Length; dir++)
|
||||
for (int dir = 0; dir < _savedDirectories.Count; dir++)
|
||||
{
|
||||
Directories[dir].Write(writer);
|
||||
writer.Write(_savedDirectories[dir].Identifier);
|
||||
writer.Write((int)_exportStringTable.Count);
|
||||
writer.Write(_savedDirectories[dir].Hash);
|
||||
writer.Write((ushort)(_savedDirectories[dir].nodes.Count));
|
||||
// writer.Write(_savedDirectories[dir].FirstNodeIndex);
|
||||
writer.Write(_savedFiles.FindIndex(i => i.Name == _savedDirectories[dir].nodes[0].Name));
|
||||
|
||||
_exportStringTable.AddRange(_savedDirectories[dir].Name.ToCharArray());
|
||||
_exportStringTable.Add('\0'); //Null terminated
|
||||
}
|
||||
|
||||
writer.Seek(16); //Add padding after directories
|
||||
writer.Align(32);
|
||||
|
||||
//Write the node offset
|
||||
//Write the files
|
||||
WriteOffset(writer, 12, InfoPos);
|
||||
for (int dir = 0; dir < Directories.Length; dir++)
|
||||
foreach (FileEntry entry in _savedFiles)
|
||||
{
|
||||
for (int n = 0; n < Directories[dir].NodeCount; n++)
|
||||
{
|
||||
entry.SaveFileFormat();
|
||||
|
||||
writer.Write(entry.FileId);
|
||||
writer.Write(entry.Hash);
|
||||
writer.Write(entry.Flags);
|
||||
writer.Seek(1); //Padding
|
||||
|
||||
//I'm not sure what each dot does, but handle these based on
|
||||
//https://github.com/LordNed/WArchive-Tools/blob/master/ArchiveToolsLib/Archive/ArchivePacker.cs#L122
|
||||
if ((entry.Name == "."))
|
||||
{
|
||||
writer.Write((ushort)0);
|
||||
}
|
||||
else if ((entry.Name == ".."))
|
||||
{
|
||||
writer.Write((ushort)2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_savedFiles.Find(i => i.Name == entry.Name) != null)
|
||||
{
|
||||
string test = new string(_exportStringTable.ToArray());
|
||||
|
||||
int testt = test.IndexOf(entry.Name);
|
||||
|
||||
writer.Write((ushort)test.IndexOf(entry.Name));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Offset of name in the string table
|
||||
writer.Write((ushort)_exportStringTable.Count);
|
||||
|
||||
// Add name to string table
|
||||
_exportStringTable.AddRange(entry.Name.ToCharArray());
|
||||
|
||||
// Strings must be null terminated
|
||||
_exportStringTable.Add('\0');
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.Flags == 0x02)
|
||||
{
|
||||
if (entry.FileData[0] != byte.MaxValue)
|
||||
{
|
||||
writer.Write((int)entry.FileData[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write((int)-1);
|
||||
}
|
||||
|
||||
writer.Write((int)0x10); //Fixed data size
|
||||
}
|
||||
if (entry.Flags == 0x11)
|
||||
{
|
||||
writer.Write((int)_savedFileData.Count);
|
||||
writer.Write(_savedFileData.Count);
|
||||
writer.Write(entry.FileData.Length);
|
||||
_savedFileData.Add(entry.FileData);
|
||||
}
|
||||
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
//Write file size
|
||||
writer.Align(32);
|
||||
|
||||
WriteOffset(writer, 20, InfoPos);
|
||||
writer.Write(_exportStringTable.ToArray());
|
||||
|
||||
writer.Align(32);
|
||||
|
||||
WriteOffset(writer, 12, pos);
|
||||
foreach (var data in _savedFileData)
|
||||
writer.Write(data);
|
||||
|
||||
writer.Align(32);
|
||||
|
||||
//Write string table size
|
||||
using (writer.TemporarySeek(pos + 0x4, System.IO.SeekOrigin.Begin))
|
||||
{
|
||||
writer.Write((uint)writer.BaseStream.Length);
|
||||
}
|
||||
|
||||
//Write file size
|
||||
using (writer.TemporarySeek(InfoPos + 16, System.IO.SeekOrigin.Begin))
|
||||
{
|
||||
writer.Write((uint)_exportStringTable.Count);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteDirectories()
|
||||
@ -323,15 +380,10 @@ namespace FirstPlugin
|
||||
public RARC ParentArchive { get; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
private uint Identifier;
|
||||
|
||||
public uint Identifier;
|
||||
internal uint NameOffset; //Relative to string table
|
||||
|
||||
public ushort Hash { get; set; }
|
||||
|
||||
public ushort NodeCount;
|
||||
|
||||
public uint FirstNodeIndex { get; set; }
|
||||
|
||||
public DirectoryEntry(RARC rarc) { ParentArchive = rarc; }
|
||||
@ -344,8 +396,6 @@ namespace FirstPlugin
|
||||
nodes.Add(node);
|
||||
}
|
||||
|
||||
|
||||
internal long _positionPtr;
|
||||
public void Read(FileReader reader)
|
||||
{
|
||||
Identifier = reader.ReadUInt32();
|
||||
@ -355,17 +405,8 @@ namespace FirstPlugin
|
||||
FirstNodeIndex = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public void Write(FileWriter writer)
|
||||
{
|
||||
_positionPtr = writer.Position;
|
||||
|
||||
public void UpdateHash() {
|
||||
Hash = CalculateHash(Name);
|
||||
|
||||
writer.Write(Identifier);
|
||||
writer.Write(NameOffset);
|
||||
writer.Write(Hash);
|
||||
writer.Write(NodeCount);
|
||||
writer.Write(FirstNodeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -416,21 +457,6 @@ namespace FirstPlugin
|
||||
Offset = reader.ReadUInt32();
|
||||
Size = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public void Write(FileWriter writer)
|
||||
{
|
||||
_positionPtr = writer.Position;
|
||||
|
||||
SaveFileFormat();
|
||||
|
||||
writer.Write(FileId);
|
||||
writer.Write(Hash);
|
||||
writer.Write(Flags);
|
||||
writer.Seek(1); //Padding
|
||||
writer.Write(NameOffset);
|
||||
writer.Write(uint.MaxValue);
|
||||
writer.Write(FileData.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,6 +137,9 @@ namespace FirstPlugin
|
||||
}
|
||||
|
||||
sarcData.Files.Clear();
|
||||
|
||||
// stream.Close();
|
||||
// stream.Dispose();
|
||||
}
|
||||
|
||||
public bool AddFile(ArchiveFileInfo archiveFileInfo)
|
||||
|
@ -19,7 +19,7 @@ namespace FirstPlugin
|
||||
|
||||
public bool CanSave { get; set; }
|
||||
public string[] Description { get; set; } = new string[] { "BCRES" };
|
||||
public string[] Extension { get; set; } = new string[] { "*.bcres" };
|
||||
public string[] Extension { get; set; } = new string[] { "*.bcres", "*.cgfx" };
|
||||
public string FileName { get; set; }
|
||||
public string FilePath { get; set; }
|
||||
public IFileInfo IFileInfo { get; set; }
|
||||
|
@ -241,9 +241,12 @@ namespace FirstPlugin
|
||||
|
||||
if (FaceGroup.SkinnningMode == SkinnningMode.Rigid)
|
||||
{
|
||||
Matrix4 sb = skeleton.bones[(int)FaceGroup.BoneIndexList[v.boneIds[0]]].Transform;
|
||||
v.pos = Vector3.TransformPosition(v.pos, sb);
|
||||
v.nrm = Vector3.TransformNormal(v.nrm, sb);
|
||||
if (v.boneIds.Count > 0)
|
||||
{
|
||||
Matrix4 sb = skeleton.bones[(int)FaceGroup.BoneIndexList[v.boneIds[0]]].Transform;
|
||||
v.pos = Vector3.TransformPosition(v.pos, sb);
|
||||
v.nrm = Vector3.TransformNormal(v.nrm, sb);
|
||||
}
|
||||
}
|
||||
if (FaceGroup.SkinnningMode == SkinnningMode.None)
|
||||
{
|
||||
|
243
File_Format_Library/FileFormats/Texture/CTXB.cs
Normal file
243
File_Format_Library/FileFormats/Texture/CTXB.cs
Normal file
@ -0,0 +1,243 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Toolbox;
|
||||
using System.Windows.Forms;
|
||||
using Toolbox.Library;
|
||||
using Toolbox.Library.IO;
|
||||
using Toolbox.Library.Forms;
|
||||
|
||||
namespace FirstPlugin
|
||||
{
|
||||
public class CTXB : TreeNodeFile, IFileFormat
|
||||
{
|
||||
public FileType FileType { get; set; } = FileType.Archive;
|
||||
|
||||
public bool CanSave { get; set; }
|
||||
public string[] Description { get; set; } = new string[] { "CTXB" };
|
||||
public string[] Extension { get; set; } = new string[] { "*.ctxb" };
|
||||
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 Toolbox.Library.IO.FileReader(stream, true))
|
||||
{
|
||||
return reader.CheckSignature(4, "ctxb");
|
||||
}
|
||||
}
|
||||
|
||||
public Type[] Types
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Type> types = new List<Type>();
|
||||
return types.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public Header header;
|
||||
|
||||
public void Load(System.IO.Stream stream)
|
||||
{
|
||||
Text = FileName;
|
||||
|
||||
header = new Header();
|
||||
header.Read(new FileReader(stream), this);
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public byte[] Save()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public class Header
|
||||
{
|
||||
public List<Chunk> Chunks = new List<Chunk>();
|
||||
|
||||
public void Read(FileReader reader, CTXB ctxb)
|
||||
{
|
||||
string Magic = reader.ReadSignature(4, "ctxb");
|
||||
uint FileSize = reader.ReadUInt32();
|
||||
uint ChunkCount = reader.ReadUInt32();
|
||||
reader.ReadUInt32(); //padding
|
||||
uint ChunkOffset = reader.ReadUInt32();
|
||||
uint TextureDataOffset = reader.ReadUInt32();
|
||||
|
||||
for (int i = 0; i < ChunkCount; i++)
|
||||
Chunks.Add(new Chunk(reader));
|
||||
|
||||
for (int i = 0; i < ChunkCount; i++)
|
||||
{
|
||||
for (int t = 0; t < Chunks[i].Textures.Count; t++)
|
||||
{
|
||||
var texWrapper = new TextureWrapper();
|
||||
texWrapper.Text = $"Texture {t}";
|
||||
texWrapper.ImageKey = "texture";
|
||||
texWrapper.SelectedImageKey = texWrapper.ImageKey;
|
||||
|
||||
if (Chunks[i].Textures[t].Name != string.Empty)
|
||||
texWrapper.Text = Chunks[i].Textures[t].Name;
|
||||
|
||||
texWrapper.Width = Chunks[i].Textures[t].Width;
|
||||
texWrapper.Height = Chunks[i].Textures[t].Height;
|
||||
texWrapper.Format = CTR_3DS.ConvertPICAToGenericFormat(Chunks[i].Textures[t].PicaFormat);
|
||||
|
||||
reader.SeekBegin(TextureDataOffset + Chunks[i].Textures[t].DataOffset);
|
||||
texWrapper.ImageData = reader.ReadBytes((int)Chunks[i].Textures[t].ImageSize);
|
||||
ctxb.Nodes.Add(texWrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Chunk
|
||||
{
|
||||
public readonly string Magic = "tex ";
|
||||
|
||||
public List<Texture> Textures = new List<Texture>();
|
||||
|
||||
public Chunk(FileReader reader)
|
||||
{
|
||||
reader.ReadSignature(4, Magic);
|
||||
uint SectionSize = reader.ReadUInt32();
|
||||
uint TextureCount = reader.ReadUInt32();
|
||||
for (int i = 0; i < TextureCount; i++)
|
||||
Textures.Add(new Texture(reader));
|
||||
}
|
||||
}
|
||||
|
||||
public class Texture
|
||||
{
|
||||
public ushort MaxLevel { get; set; }
|
||||
public ushort Unknown { get; set; }
|
||||
public ushort Width { get; set; }
|
||||
public ushort Height { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
public uint ImageSize { get; set; }
|
||||
public uint DataOffset { get; set; }
|
||||
|
||||
public CTR_3DS.PICASurfaceFormat PicaFormat;
|
||||
|
||||
public enum TextureFormat : uint
|
||||
{
|
||||
ETC1 = 0x0000675A,
|
||||
ETC1A4 = 0x0000675B,
|
||||
RGBA8 = 0x14016752,
|
||||
RGBA4444 = 0x80336752,
|
||||
RGBA5551 = 0x80346752,
|
||||
RGB565 = 0x83636754,
|
||||
RGB8 = 0x14016754,
|
||||
A8 = 0x14016756,
|
||||
L8 = 0x14016757,
|
||||
L4 = 0x67616757,
|
||||
LA8 = 0x14016758,
|
||||
}
|
||||
|
||||
public Texture(FileReader reader)
|
||||
{
|
||||
ImageSize = reader.ReadUInt32();
|
||||
MaxLevel = reader.ReadUInt16();
|
||||
Unknown = reader.ReadUInt16();
|
||||
Width = reader.ReadUInt16();
|
||||
Height = reader.ReadUInt16();
|
||||
TextureFormat Format = reader.ReadEnum<TextureFormat>(true);
|
||||
DataOffset = reader.ReadUInt32();
|
||||
Name = reader.LoadString(false, typeof(uint));
|
||||
|
||||
PicaFormat = ToPica(Format);
|
||||
}
|
||||
|
||||
private static CTR_3DS.PICASurfaceFormat ToPica(TextureFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case TextureFormat.A8: return CTR_3DS.PICASurfaceFormat.A8;
|
||||
case TextureFormat.ETC1: return CTR_3DS.PICASurfaceFormat.ETC1;
|
||||
case TextureFormat.ETC1A4: return CTR_3DS.PICASurfaceFormat.ETC1A4;
|
||||
case TextureFormat.L4: return CTR_3DS.PICASurfaceFormat.L4;
|
||||
case TextureFormat.L8: return CTR_3DS.PICASurfaceFormat.L8;
|
||||
case TextureFormat.LA8: return CTR_3DS.PICASurfaceFormat.LA8;
|
||||
case TextureFormat.RGB565: return CTR_3DS.PICASurfaceFormat.RGB565;
|
||||
case TextureFormat.RGBA4444: return CTR_3DS.PICASurfaceFormat.RGBA4;
|
||||
case TextureFormat.RGBA5551: return CTR_3DS.PICASurfaceFormat.RGBA5551;
|
||||
case TextureFormat.RGBA8: return CTR_3DS.PICASurfaceFormat.RGBA8;
|
||||
case TextureFormat.RGB8: return CTR_3DS.PICASurfaceFormat.RGB8;
|
||||
default:
|
||||
throw new Exception($"Unsupported format! {format}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TextureWrapper : STGenericTexture
|
||||
{
|
||||
public byte[] ImageData;
|
||||
|
||||
public override bool CanEdit { get; set; } = false;
|
||||
public override TEX_FORMAT[] SupportedFormats
|
||||
{
|
||||
get
|
||||
{
|
||||
return new TEX_FORMAT[]
|
||||
{
|
||||
TEX_FORMAT.B5G6R5_UNORM,
|
||||
TEX_FORMAT.R8G8_UNORM,
|
||||
TEX_FORMAT.B5G5R5A1_UNORM,
|
||||
TEX_FORMAT.B4G4R4A4_UNORM,
|
||||
TEX_FORMAT.LA8,
|
||||
TEX_FORMAT.HIL08,
|
||||
TEX_FORMAT.L8,
|
||||
TEX_FORMAT.A8_UNORM,
|
||||
TEX_FORMAT.LA4,
|
||||
TEX_FORMAT.A4,
|
||||
TEX_FORMAT.ETC1_UNORM,
|
||||
TEX_FORMAT.ETC1_A4,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public TextureWrapper() {
|
||||
PlatformSwizzle = PlatformSwizzle.Platform_3DS;
|
||||
}
|
||||
|
||||
public override void OnClick(TreeView treeview)
|
||||
{
|
||||
UpdateEditor();
|
||||
}
|
||||
|
||||
private void UpdateEditor()
|
||||
{
|
||||
ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase));
|
||||
if (editor == null)
|
||||
{
|
||||
editor = new ImageEditorBase();
|
||||
editor.Dock = DockStyle.Fill;
|
||||
LibraryGUI.LoadEditor(editor);
|
||||
}
|
||||
|
||||
editor.Text = Text;
|
||||
editor.LoadProperties(GenericProperties);
|
||||
editor.LoadImage(this);
|
||||
}
|
||||
|
||||
public override void SetImageData(System.Drawing.Bitmap bitmap, int ArrayLevel)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0)
|
||||
{
|
||||
return ImageData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -225,6 +225,8 @@
|
||||
<Compile Include="FileFormats\Archives\Sonic Racing\SP2.cs" />
|
||||
<Compile Include="FileFormats\Archives\TMPK.cs" />
|
||||
<Compile Include="FileFormats\Archives\U8.cs" />
|
||||
<Compile Include="FileFormats\Archives\Grezzo\ZAR.cs" />
|
||||
<Compile Include="FileFormats\Archives\Grezzo\ZSI.cs" />
|
||||
<Compile Include="FileFormats\Audio\Archives\BARS.cs" />
|
||||
<Compile Include="FileFormats\Audio\BARSLIST.cs" />
|
||||
<Compile Include="FileFormats\Audio\BCSTM.cs" />
|
||||
@ -267,6 +269,7 @@
|
||||
<Compile Include="FileFormats\Font\BffntCharSet2Xlor.cs" />
|
||||
<Compile Include="FileFormats\Font\BFTTF.cs" />
|
||||
<Compile Include="FileFormats\Message\MSBP.cs" />
|
||||
<Compile Include="FileFormats\Texture\CTXB.cs" />
|
||||
<Compile Include="FileFormats\Texture\TPL.cs" />
|
||||
<Compile Include="FileFormats\Rom\GCDisk.cs" />
|
||||
<Compile Include="GL\BMD_Renderer.cs" />
|
||||
|
@ -358,8 +358,12 @@ namespace FirstPlugin
|
||||
Formats.Add(typeof(BFTTF));
|
||||
Formats.Add(typeof(PACx30XL));
|
||||
Formats.Add(typeof(BinGzArchive));
|
||||
// Formats.Add(typeof(MSBP));
|
||||
// Formats.Add(typeof(MSBP));
|
||||
Formats.Add(typeof(ZAR));
|
||||
// Formats.Add(typeof(ZSI));
|
||||
Formats.Add(typeof(CTXB));
|
||||
|
||||
|
||||
// Formats.Add(typeof(GFA));
|
||||
|
||||
//Unfinished wip formats not ready for use
|
||||
|
93
Switch_Toolbox_Library/Compression/LZSS.cs
Normal file
93
Switch_Toolbox_Library/Compression/LZSS.cs
Normal file
@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Threading.Tasks;
|
||||
using Toolbox.Library.IO;
|
||||
using K4os.Compression.LZ4.Streams;
|
||||
|
||||
namespace Toolbox.Library
|
||||
{
|
||||
//From https://github.com/xdanieldzd/N3DSCmbViewer/blob/3c3f66cf40d9122f8d0ebeab07c4db659b426b8b/N3DSCmbViewer/LZSS.cs
|
||||
//and https://github.com/lue/MM3D/blob/master/src/lzs.cpp
|
||||
public class LZSS : ICompressionFormat
|
||||
{
|
||||
public string[] Description { get; set; } = new string[] { "LZSS Compression" };
|
||||
public string[] Extension { get; set; } = new string[] { "*.lzs", "*.lzss" };
|
||||
|
||||
public bool Identify(Stream stream)
|
||||
{
|
||||
using (var reader = new FileReader(stream, true))
|
||||
{
|
||||
return reader.CheckSignature(4, "LzS\x01");
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanCompress { get; } = true;
|
||||
|
||||
public Stream Decompress(Stream stream)
|
||||
{
|
||||
byte[] arcdata = stream.ToArray();
|
||||
|
||||
string tag = Encoding.ASCII.GetString(arcdata, 0, 4);
|
||||
uint unknown = BitConverter.ToUInt32(arcdata, 4);
|
||||
uint decompressedSize = BitConverter.ToUInt32(arcdata, 8);
|
||||
uint compressedSize = BitConverter.ToUInt32(arcdata, 12);
|
||||
|
||||
if (arcdata.Length != compressedSize + 0x10) throw new Exception("compressed size mismatch");
|
||||
|
||||
List<byte> outdata = new List<byte>();
|
||||
byte[] BUFFER = new byte[4096];
|
||||
for (int i = 0; i < BUFFER.Length; i++) BUFFER[i] = 0;
|
||||
byte flags8 = 0;
|
||||
ushort writeidx = 0xFEE;
|
||||
ushort readidx = 0;
|
||||
uint fidx = 0x10;
|
||||
|
||||
while (fidx < arcdata.Length)
|
||||
{
|
||||
flags8 = arcdata[fidx];
|
||||
fidx++;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if ((flags8 & 1) != 0)
|
||||
{
|
||||
outdata.Add(arcdata[fidx]);
|
||||
BUFFER[writeidx] = arcdata[fidx];
|
||||
writeidx++; writeidx %= 4096;
|
||||
fidx++;
|
||||
}
|
||||
else
|
||||
{
|
||||
readidx = arcdata[fidx];
|
||||
fidx++;
|
||||
readidx |= (ushort)((arcdata[fidx] & 0xF0) << 4);
|
||||
for (int j = 0; j < (arcdata[fidx] & 0x0F) + 3; j++)
|
||||
{
|
||||
outdata.Add(BUFFER[readidx]);
|
||||
BUFFER[writeidx] = BUFFER[readidx];
|
||||
readidx++; readidx %= 4096;
|
||||
writeidx++; writeidx %= 4096;
|
||||
}
|
||||
fidx++;
|
||||
}
|
||||
flags8 >>= 1;
|
||||
if (fidx >= arcdata.Length) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (decompressedSize != outdata.Count)
|
||||
throw new Exception(string.Format("Size mismatch: got {0} bytes after decompression, expected {1}.\n", outdata.Count, decompressedSize));
|
||||
|
||||
return new MemoryStream(outdata.ToArray());
|
||||
}
|
||||
|
||||
public Stream Compress(Stream stream)
|
||||
{
|
||||
var mem = new MemoryStream();
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ namespace Toolbox.Library
|
||||
public static Type[] GetCompressionFormats()
|
||||
{
|
||||
List<Type> Formats = new List<Type>();
|
||||
|
||||
Formats.Add(typeof(LZSS));
|
||||
return Formats.ToArray();
|
||||
}
|
||||
}
|
||||
|
@ -231,7 +231,7 @@ namespace Toolbox.Library.IO
|
||||
if (OffsetType == typeof(int))
|
||||
offset = ReadInt32();
|
||||
|
||||
if (offset == 0) return null;
|
||||
if (offset == 0) return string.Empty;
|
||||
|
||||
if (IsRelative)
|
||||
offset = offset + pos;
|
||||
@ -261,11 +261,19 @@ namespace Toolbox.Library.IO
|
||||
}
|
||||
return output.ToArray();
|
||||
}
|
||||
|
||||
public byte[] getSection(uint offset, uint size)
|
||||
{
|
||||
Position = offset;
|
||||
return ReadBytes((int)size);
|
||||
}
|
||||
|
||||
public byte[] getSection(int offset, int size)
|
||||
{
|
||||
Position = offset;
|
||||
return ReadBytes(size);
|
||||
}
|
||||
|
||||
public Vector4 ReadVec4()
|
||||
{
|
||||
return new Vector4(ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle());
|
||||
|
Binary file not shown.
Binary file not shown.
@ -209,6 +209,7 @@
|
||||
<Compile Include="Collections\SortExtensions.cs" />
|
||||
<Compile Include="Compression\LZ4F.cs" />
|
||||
<Compile Include="Compression\LZ77_WII.cs" />
|
||||
<Compile Include="Compression\LZSS.cs" />
|
||||
<Compile Include="Compression\STLibraryCompression.cs" />
|
||||
<Compile Include="Compression\YAZ0.cs" />
|
||||
<Compile Include="Compression\ZCMP.cs" />
|
||||
|
@ -210,6 +210,16 @@ namespace Toolbox.Library
|
||||
}
|
||||
}
|
||||
|
||||
//Get compression formats
|
||||
foreach (ICompressionFormat f in FileManager.GetCompressionFormats())
|
||||
{
|
||||
for (int i = 0; i < f.Extension.Length; i++)
|
||||
{
|
||||
Filter += $"{f.Extension[i]};";
|
||||
FilterEach.Add($"{f.Description[0]} ({f.Extension[i]}) |{f.Extension[i]}|");
|
||||
}
|
||||
}
|
||||
|
||||
Filter += $"{"*.z"};";
|
||||
Filter += $"{"*.cmp"};";
|
||||
Filter += $"{"*.yaz0"};";
|
||||
@ -264,6 +274,17 @@ namespace Toolbox.Library
|
||||
FilterEach.Add($"{f.Description[0]} ({f.Extension[i]}) |{f.Extension[i]}|");
|
||||
}
|
||||
}
|
||||
|
||||
//Get compression formats
|
||||
foreach (ICompressionFormat f in FileManager.GetCompressionFormats())
|
||||
{
|
||||
for (int i = 0; i < f.Extension.Length; i++)
|
||||
{
|
||||
Filter += $"{f.Extension[i]};";
|
||||
FilterEach.Add($"{f.Description[0]} ({f.Extension[i]}) |{f.Extension[i]}|");
|
||||
}
|
||||
}
|
||||
|
||||
Filter += $"{"*.z"};";
|
||||
Filter += $"{"*.cmp"};";
|
||||
Filter += $"{"*.yaz0"};";
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user