More fixes and additions
Archives now use a link list for archive infos and treenodes. Handling replaced treenodes is easier and fixes renaming issues if a file was opened and renamed. More LM2 archive improvements, with more chunk loading.
This commit is contained in:
parent
1059113cee
commit
1429a00178
Binary file not shown.
@ -5,8 +5,24 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Toolbox.Library.IO;
|
using Toolbox.Library.IO;
|
||||||
|
|
||||||
namespace FirstPlugin
|
namespace FirstPlugin.LuigisMansion.DarkMoon
|
||||||
{
|
{
|
||||||
|
public class ChunkEntry
|
||||||
|
{
|
||||||
|
public uint Unknown1;
|
||||||
|
public uint ChunkOffset;
|
||||||
|
public DataType ChunkType;
|
||||||
|
public uint ChunkSubCount;
|
||||||
|
public uint Unknown3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ChunkSubEntry
|
||||||
|
{
|
||||||
|
public SubDataType ChunkType;
|
||||||
|
public uint ChunkSize;
|
||||||
|
public uint ChunkOffset;
|
||||||
|
}
|
||||||
|
|
||||||
//Table consists of 2 chunk entry lists that define how the .data reads sections
|
//Table consists of 2 chunk entry lists that define how the .data reads sections
|
||||||
public class LM2_ChunkTable
|
public class LM2_ChunkTable
|
||||||
{
|
{
|
||||||
@ -18,28 +34,6 @@ namespace FirstPlugin
|
|||||||
public List<ChunkEntry> ChunkEntries = new List<ChunkEntry>();
|
public List<ChunkEntry> ChunkEntries = new List<ChunkEntry>();
|
||||||
public List<ChunkSubEntry> ChunkSubEntries = new List<ChunkSubEntry>();
|
public List<ChunkSubEntry> ChunkSubEntries = new List<ChunkSubEntry>();
|
||||||
|
|
||||||
public class ChunkEntry
|
|
||||||
{
|
|
||||||
public uint Unknown1;
|
|
||||||
public uint ChunkOffset;
|
|
||||||
public uint ChunkType;
|
|
||||||
public uint ChunkSubCount;
|
|
||||||
public uint Unknown3;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ChunkSubEntry
|
|
||||||
{
|
|
||||||
public uint ChunkSize;
|
|
||||||
public DataType ChunkType;
|
|
||||||
public uint Unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum DataType : uint
|
|
||||||
{
|
|
||||||
TextureHeader = 0x0201B501,
|
|
||||||
TextureData = 0x1701B502,
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Read(FileReader tableReader)
|
public void Read(FileReader tableReader)
|
||||||
{
|
{
|
||||||
tableReader.SetByteOrder(false);
|
tableReader.SetByteOrder(false);
|
||||||
@ -52,8 +46,8 @@ namespace FirstPlugin
|
|||||||
|
|
||||||
entry.Unknown1 = tableReader.ReadUInt32(); //8
|
entry.Unknown1 = tableReader.ReadUInt32(); //8
|
||||||
entry.ChunkOffset = tableReader.ReadUInt32(); //The chunk offset in the file. Relative to the first chunk position in the file
|
entry.ChunkOffset = tableReader.ReadUInt32(); //The chunk offset in the file. Relative to the first chunk position in the file
|
||||||
entry.ChunkType = tableReader.ReadUInt32(); //The type of chunk. 0x8701B5 for example for texture info
|
entry.ChunkType = tableReader.ReadEnum<DataType>(false); //The type of chunk. 0x8701B5 for example for texture info
|
||||||
entry.ChunkSubCount = tableReader.ReadUInt32();
|
entry.ChunkSubCount = tableReader.ReadUInt32(); //Uncertain about this. 2 for textures (info + block). Some sections however use large numbers.
|
||||||
|
|
||||||
//This increases by 2 each chunk info, however the starting value is not 0
|
//This increases by 2 each chunk info, however the starting value is not 0
|
||||||
//Note the last entry does not have this
|
//Note the last entry does not have this
|
||||||
@ -71,9 +65,9 @@ namespace FirstPlugin
|
|||||||
while (!tableReader.EndOfStream && tableReader.Position <= tableReader.BaseStream.Length - 12)
|
while (!tableReader.EndOfStream && tableReader.Position <= tableReader.BaseStream.Length - 12)
|
||||||
{
|
{
|
||||||
ChunkSubEntry subEntry = new ChunkSubEntry();
|
ChunkSubEntry subEntry = new ChunkSubEntry();
|
||||||
subEntry.ChunkType = tableReader.ReadEnum<DataType>(false); //The type of chunk. 0x8701B5 for example for texture info
|
subEntry.ChunkType = tableReader.ReadEnum<SubDataType>(false); //The type of chunk. 0x8701B5 for example for texture info
|
||||||
subEntry.ChunkSize = tableReader.ReadUInt32();
|
subEntry.ChunkSize = tableReader.ReadUInt32();
|
||||||
subEntry.Unknown = tableReader.ReadUInt32();
|
subEntry.ChunkOffset = tableReader.ReadUInt32();
|
||||||
ChunkSubEntries.Add(subEntry);
|
ChunkSubEntries.Add(subEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ using Toolbox.Library.IO;
|
|||||||
using Toolbox.Library.Forms;
|
using Toolbox.Library.Forms;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
namespace FirstPlugin
|
namespace FirstPlugin.LuigisMansion.DarkMoon
|
||||||
{
|
{
|
||||||
//Parse info based on https://github.com/TheFearsomeDzeraora/LM2L
|
//Parse info based on https://github.com/TheFearsomeDzeraora/LM2L
|
||||||
public class LM2_DICT : TreeNodeFile, IFileFormat, IArchiveFile
|
public class LM2_DICT : TreeNodeFile, IFileFormat, IArchiveFile
|
||||||
@ -47,7 +47,7 @@ namespace FirstPlugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FileEntry> files = new List<FileEntry>();
|
public List<ChunkDataEntry> files = new List<ChunkDataEntry>();
|
||||||
public IEnumerable<ArchiveFileInfo> Files => files;
|
public IEnumerable<ArchiveFileInfo> Files => files;
|
||||||
|
|
||||||
public void ClearFiles() { files.Clear(); }
|
public void ClearFiles() { files.Clear(); }
|
||||||
@ -55,6 +55,23 @@ namespace FirstPlugin
|
|||||||
public bool IsCompressed = false;
|
public bool IsCompressed = false;
|
||||||
|
|
||||||
public LM2_ChunkTable ChunkTable;
|
public LM2_ChunkTable ChunkTable;
|
||||||
|
public List<FileEntry> fileEntries = new List<FileEntry>();
|
||||||
|
|
||||||
|
//The click event will load the viewport and any models found in the file if there are any
|
||||||
|
public override void OnClick(TreeView treeview)
|
||||||
|
{
|
||||||
|
if (modelFolder.Nodes.Count != 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode textureFolder = new TreeNode("Textures");
|
||||||
|
TreeNode modelFolder = new TreeNode("Models");
|
||||||
|
|
||||||
public void Load(System.IO.Stream stream)
|
public void Load(System.IO.Stream stream)
|
||||||
{
|
{
|
||||||
@ -71,23 +88,22 @@ namespace FirstPlugin
|
|||||||
reader.SeekBegin(0x2C);
|
reader.SeekBegin(0x2C);
|
||||||
byte[] Unknowns = reader.ReadBytes((int)FileCount);
|
byte[] Unknowns = reader.ReadBytes((int)FileCount);
|
||||||
|
|
||||||
|
TreeNode tableNodes = new TreeNode("File Section Entries");
|
||||||
|
|
||||||
long FileTablePos = reader.Position;
|
long FileTablePos = reader.Position;
|
||||||
for (int i = 0; i < FileCount; i++)
|
for (int i = 0; i < FileCount; i++)
|
||||||
{
|
{
|
||||||
var file = new FileEntry(this);
|
var file = new FileEntry(this);
|
||||||
|
file.Text = $"entry {i}";
|
||||||
file.Read(reader);
|
file.Read(reader);
|
||||||
|
fileEntries.Add(file);
|
||||||
|
tableNodes.Nodes.Add(file);
|
||||||
|
|
||||||
//Skip the file table entries as those are not needed to be loaded
|
|
||||||
if (file.FileType != 0 && i > 1)
|
|
||||||
{
|
|
||||||
file.FileName = $"File {i} (FileType: ({file.FileType}) Unknowns: {file.Unknown2} {file.Unknown3})";
|
|
||||||
files.Add(file);
|
|
||||||
}
|
|
||||||
//The first file stores a chunk layout
|
//The first file stores a chunk layout
|
||||||
//The second one seems to be a duplicate?
|
//The second one seems to be a duplicate?
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
using (var tableReader = new FileReader(file.FileData))
|
using (var tableReader = new FileReader(file.GetData()))
|
||||||
{
|
{
|
||||||
ChunkTable = new LM2_ChunkTable();
|
ChunkTable = new LM2_ChunkTable();
|
||||||
ChunkTable.Read(tableReader);
|
ChunkTable.Read(tableReader);
|
||||||
@ -97,68 +113,120 @@ namespace FirstPlugin
|
|||||||
|
|
||||||
TreeNode list1 = new TreeNode("Entry List 1");
|
TreeNode list1 = new TreeNode("Entry List 1");
|
||||||
TreeNode list2 = new TreeNode("Entry List 2 ");
|
TreeNode list2 = new TreeNode("Entry List 2 ");
|
||||||
|
debugFolder.Nodes.Add(tableNodes);
|
||||||
debugFolder.Nodes.Add(list1);
|
debugFolder.Nodes.Add(list1);
|
||||||
debugFolder.Nodes.Add(list2);
|
debugFolder.Nodes.Add(list2);
|
||||||
|
|
||||||
foreach (var chunk in ChunkTable.ChunkEntries)
|
foreach (var chunk in ChunkTable.ChunkEntries)
|
||||||
{
|
{
|
||||||
list1.Nodes.Add($"ChunkType {chunk.ChunkType.ToString("X")} ChunkOffset {chunk.ChunkOffset} Unknown1 {chunk.Unknown1} ChunkSubCount {chunk.ChunkSubCount} Unknown3 {chunk.Unknown3}");
|
list1.Nodes.Add($"ChunkType {chunk.ChunkType} ChunkOffset {chunk.ChunkOffset} Unknown1 {chunk.Unknown1} ChunkSubCount {chunk.ChunkSubCount} Unknown3 {chunk.Unknown3}");
|
||||||
}
|
}
|
||||||
foreach (var chunk in ChunkTable.ChunkSubEntries)
|
foreach (var chunk in ChunkTable.ChunkSubEntries)
|
||||||
{
|
{
|
||||||
list2.Nodes.Add($"ChunkType {chunk.ChunkType} ChunkSize {chunk.ChunkSize} Unknown {chunk.Unknown}");
|
list2.Nodes.Add($"ChunkType {chunk.ChunkType} ChunkSize {chunk.ChunkSize} Unknown {chunk.ChunkOffset}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Now go through each file and format and connect the headers and blocks
|
//Set an instance of our current data
|
||||||
uint ImageIndex = 0;
|
//Chunks are in order, so you build off of when an instance gets loaded
|
||||||
|
TexturePOWE currentTexture = new TexturePOWE();
|
||||||
|
LM2_Model currentModel = new LM2_Model();
|
||||||
|
|
||||||
List<TexturePOWE> Textures = new List<TexturePOWE>();
|
//Each part of the file is divided into multiple file/section entries
|
||||||
|
//The first entry being the chunk table parsed before this
|
||||||
|
//The second file being a duplicate (sometimes slightly larger than the first)
|
||||||
|
//The third file stores texture headers, while the fourth one usually has the rest of the main data
|
||||||
|
//Any additional ones currently are unknown how they work. Some of which have unknown compression aswell
|
||||||
|
|
||||||
TreeNode textureFolder = new TreeNode("Textures");
|
byte[] File002Data = fileEntries[2].GetData(); //Get the third file
|
||||||
|
byte[] File003Data = fileEntries[3].GetData(); //Get the fourth file
|
||||||
|
|
||||||
for (int i = 0; i < files.Count; i++)
|
int chunkId = 0;
|
||||||
|
uint ImageHeaderIndex = 0;
|
||||||
|
uint modelIndex = 0;
|
||||||
|
foreach (var chunk in ChunkTable.ChunkSubEntries)
|
||||||
{
|
{
|
||||||
if (files[i].FileType == FileEntry.DataType.Texture)
|
var chunkEntry = new ChunkDataEntry(this, chunk);
|
||||||
{
|
chunkEntry.DataFile = File003Data;
|
||||||
if (files[i].Unknown3 == 1) //Info
|
chunkEntry.FileName = $"Chunk {chunk.ChunkType} {chunkId++}";
|
||||||
|
files.Add(chunkEntry);
|
||||||
|
|
||||||
|
switch (chunk.ChunkType)
|
||||||
{
|
{
|
||||||
|
case SubDataType.TextureHeader:
|
||||||
|
chunkEntry.DataFile = File002Data;
|
||||||
|
|
||||||
//Read the info
|
//Read the info
|
||||||
using (var textureReader = new FileReader(files[i].FileData))
|
using (var textureReader = new FileReader(chunkEntry.FileData))
|
||||||
{
|
{
|
||||||
int headerIndex = 0;
|
currentTexture = new TexturePOWE();
|
||||||
while (!textureReader.EndOfStream && textureReader.ReadUInt32() == TexturePOWE.Identifier)
|
currentTexture.ImageKey = "texture";
|
||||||
|
currentTexture.SelectedImageKey = currentTexture.ImageKey;
|
||||||
|
currentTexture.Index = ImageHeaderIndex;
|
||||||
|
currentTexture.Read(textureReader);
|
||||||
|
currentTexture.Text = $"Texture {ImageHeaderIndex}";
|
||||||
|
textureFolder.Nodes.Add(currentTexture);
|
||||||
|
|
||||||
|
ImageHeaderIndex++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SubDataType.TextureData:
|
||||||
|
currentTexture.ImageData = chunkEntry.FileData;
|
||||||
|
break;
|
||||||
|
case SubDataType.ModelStart:
|
||||||
|
currentModel.ModelInfo = new LM2_ModelInfo();
|
||||||
|
currentModel.Text = $"Model {modelIndex}";
|
||||||
|
currentModel.ModelInfo.Data = chunkEntry.FileData;
|
||||||
|
modelFolder.Nodes.Add(currentModel);
|
||||||
|
|
||||||
|
modelIndex++;
|
||||||
|
break;
|
||||||
|
case SubDataType.VertexStartPointers:
|
||||||
|
using (var vtxPtrReader = new FileReader(chunkEntry.FileData))
|
||||||
{
|
{
|
||||||
var texture = new TexturePOWE();
|
while (!vtxPtrReader.EndOfStream)
|
||||||
texture.ImageKey = "texture";
|
currentModel.VertexBufferPointers.Add(vtxPtrReader.ReadUInt32());
|
||||||
texture.SelectedImageKey = texture.ImageKey;
|
}
|
||||||
texture.Index = ImageIndex;
|
break;
|
||||||
texture.Read(textureReader);
|
case SubDataType.SubmeshInfo:
|
||||||
texture.Text = $"Texture {headerIndex++}";
|
int MeshCount = chunkEntry.FileData.Length / 0x28;
|
||||||
textureFolder.Nodes.Add(texture);
|
using (var meshReader = new FileReader(chunkEntry.FileData))
|
||||||
Textures.Add(texture);
|
{
|
||||||
|
for (uint i = 0; i < MeshCount; i++)
|
||||||
|
{
|
||||||
|
LM2_Mesh mesh = new LM2_Mesh();
|
||||||
|
mesh.Read(meshReader);
|
||||||
|
currentModel.Meshes.Add(mesh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case SubDataType.ModelTransform:
|
||||||
|
using (var transformReader = new FileReader(chunkEntry.FileData))
|
||||||
|
currentModel.Transform = transformReader.ReadMatrix4();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else //Block
|
|
||||||
{
|
|
||||||
uint Offset = 0;
|
|
||||||
foreach (var tex in Textures)
|
|
||||||
{
|
|
||||||
if (tex.Index == ImageIndex)
|
|
||||||
{
|
|
||||||
tex.ImageData = Utils.SubArray(files[i].FileData, Offset, tex.ImageSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Offset += tex.ImageSize;
|
foreach (LM2_Model model in modelFolder.Nodes)
|
||||||
}
|
{
|
||||||
ImageIndex++;
|
for (int i = 0; i < model.VertexBufferPointers.Count; i++)
|
||||||
}
|
{
|
||||||
|
LM2_Mesh mesh = model.Meshes[i];
|
||||||
|
|
||||||
|
RenderableMeshWrapper genericObj = new RenderableMeshWrapper();
|
||||||
|
genericObj.Mesh = mesh;
|
||||||
|
genericObj.Text = $"Mesh {i}";
|
||||||
|
model.Nodes.Add(genericObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (modelFolder.Nodes.Count > 0)
|
||||||
|
Nodes.Add(modelFolder);
|
||||||
|
|
||||||
if (textureFolder.Nodes.Count > 0)
|
if (textureFolder.Nodes.Count > 0)
|
||||||
Nodes.Add(textureFolder);
|
Nodes.Add(textureFolder);
|
||||||
}
|
}
|
||||||
@ -184,102 +252,16 @@ namespace FirstPlugin
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TexturePOWE : STGenericTexture
|
public class ChunkDataEntry : ArchiveFileInfo
|
||||||
{
|
|
||||||
public static readonly uint Identifier = 0xE977D350;
|
|
||||||
|
|
||||||
public uint Index { get; set; }
|
|
||||||
|
|
||||||
public uint ID { get; set; }
|
|
||||||
public uint ImageSize { get; set; }
|
|
||||||
public uint ID2 { get; set; }
|
|
||||||
|
|
||||||
public byte[] ImageData { get; set; }
|
|
||||||
|
|
||||||
public void Read(FileReader reader)
|
|
||||||
{
|
|
||||||
PlatformSwizzle = PlatformSwizzle.Platform_3DS;
|
|
||||||
|
|
||||||
ID = reader.ReadUInt32();
|
|
||||||
ImageSize = reader.ReadUInt32();
|
|
||||||
ID2 = reader.ReadUInt32();
|
|
||||||
reader.Seek(0x8);
|
|
||||||
Width = reader.ReadUInt16();
|
|
||||||
Height = reader.ReadUInt16();
|
|
||||||
reader.Seek(3);
|
|
||||||
var numMips = reader.ReadByte();
|
|
||||||
reader.Seek(0x14);
|
|
||||||
byte FormatCtr = reader.ReadByte();
|
|
||||||
reader.Seek(3);
|
|
||||||
|
|
||||||
MipCount = 1;
|
|
||||||
Format = CTR_3DS.ConvertPICAToGenericFormat((CTR_3DS.PICASurfaceFormat)FormatCtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnClick(TreeView treeview)
|
|
||||||
{
|
|
||||||
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(this.GenericProperties);
|
|
||||||
editor.LoadImage(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool CanEdit { get; set; } = false;
|
|
||||||
|
|
||||||
public override void SetImageData(Bitmap bitmap, int ArrayLevel)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0)
|
|
||||||
{
|
|
||||||
return ImageData;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 class FileEntry : ArchiveFileInfo
|
|
||||||
{
|
{
|
||||||
|
public byte[] DataFile;
|
||||||
public LM2_DICT ParentDictionary { get; set; }
|
public LM2_DICT ParentDictionary { get; set; }
|
||||||
|
public ChunkSubEntry Entry;
|
||||||
|
|
||||||
public uint Offset;
|
public ChunkDataEntry(LM2_DICT dict, ChunkSubEntry entry)
|
||||||
public uint DecompressedSize;
|
|
||||||
public uint CompressedSize;
|
|
||||||
public DataType FileType;
|
|
||||||
public byte Unknown2;
|
|
||||||
public byte Unknown3; //Possibly the effect? 0 for image block, 1 for info
|
|
||||||
|
|
||||||
public enum DataType : ushort
|
|
||||||
{
|
{
|
||||||
Texture = 0x80,
|
ParentDictionary = dict;
|
||||||
|
Entry = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override byte[] FileData
|
public override byte[] FileData
|
||||||
@ -291,6 +273,27 @@ namespace FirstPlugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private byte[] GetData( )
|
||||||
|
{
|
||||||
|
using (var reader = new FileReader(DataFile))
|
||||||
|
{
|
||||||
|
reader.SeekBegin(Entry.ChunkOffset);
|
||||||
|
return reader.ReadBytes((int)Entry.ChunkSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FileEntry : TreeNodeFile, IContextMenuNode
|
||||||
|
{
|
||||||
|
public LM2_DICT ParentDictionary { get; set; }
|
||||||
|
|
||||||
|
public uint Offset;
|
||||||
|
public uint DecompressedSize;
|
||||||
|
public uint CompressedSize;
|
||||||
|
public ushort Unknown1;
|
||||||
|
public byte Unknown2;
|
||||||
|
public byte Unknown3; //Possibly the effect? 0 for image block, 1 for info
|
||||||
|
|
||||||
public FileEntry(LM2_DICT dict)
|
public FileEntry(LM2_DICT dict)
|
||||||
{
|
{
|
||||||
ParentDictionary = dict;
|
ParentDictionary = dict;
|
||||||
@ -301,7 +304,7 @@ namespace FirstPlugin
|
|||||||
Offset = reader.ReadUInt32();
|
Offset = reader.ReadUInt32();
|
||||||
DecompressedSize = reader.ReadUInt32();
|
DecompressedSize = reader.ReadUInt32();
|
||||||
CompressedSize = reader.ReadUInt32();
|
CompressedSize = reader.ReadUInt32();
|
||||||
FileType = reader.ReadEnum<DataType>(false);
|
Unknown1 = reader.ReadUInt16();
|
||||||
Unknown2 = reader.ReadByte();
|
Unknown2 = reader.ReadByte();
|
||||||
Unknown3 = reader.ReadByte();
|
Unknown3 = reader.ReadByte();
|
||||||
}
|
}
|
||||||
@ -319,7 +322,39 @@ namespace FirstPlugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] GetData()
|
public ToolStripItem[] GetContextMenuItems()
|
||||||
|
{
|
||||||
|
List<ToolStripItem> Items = new List<ToolStripItem>();
|
||||||
|
Items.Add(new STToolStipMenuItem("Export Raw Data", null, Export, Keys.Control | Keys.E));
|
||||||
|
return Items.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Export(object sender, EventArgs args)
|
||||||
|
{
|
||||||
|
SaveFileDialog sfd = new SaveFileDialog();
|
||||||
|
sfd.FileName = Text;
|
||||||
|
sfd.Filter = "Raw Data (*.*)|*.*";
|
||||||
|
|
||||||
|
if (sfd.ShowDialog() == DialogResult.OK)
|
||||||
|
{
|
||||||
|
System.IO.File.WriteAllBytes(sfd.FileName, GetData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnClick(TreeView treeView)
|
||||||
|
{
|
||||||
|
HexEditor editor = (HexEditor)LibraryGUI.GetActiveContent(typeof(HexEditor));
|
||||||
|
if (editor == null)
|
||||||
|
{
|
||||||
|
editor = new HexEditor();
|
||||||
|
LibraryGUI.LoadEditor(editor);
|
||||||
|
}
|
||||||
|
editor.Text = Text;
|
||||||
|
editor.Dock = DockStyle.Fill;
|
||||||
|
editor.LoadData(GetData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetData()
|
||||||
{
|
{
|
||||||
byte[] Data = new byte[DecompressedSize];
|
byte[] Data = new byte[DecompressedSize];
|
||||||
|
|
||||||
|
28
File_Format_Library/FileFormats/Archives/LM2/LM2_Enums.cs
Normal file
28
File_Format_Library/FileFormats/Archives/LM2/LM2_Enums.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FirstPlugin.LuigisMansion.DarkMoon
|
||||||
|
{
|
||||||
|
public enum DataType : uint
|
||||||
|
{
|
||||||
|
Texture = 0x8701B500,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SubDataType : uint
|
||||||
|
{
|
||||||
|
ModelStart = 0x1201B006,
|
||||||
|
SubmeshInfo = 0x1201B003, //Or polygon groups?
|
||||||
|
VertexStartPointers = 0x1201B004,
|
||||||
|
ModelTransform = 0x1301B001, //Matrix4x4. 0x40 in size
|
||||||
|
MeshBuffers = 0x1301B005, //vertex and index buffer
|
||||||
|
MaterialName = 0x1201B333,
|
||||||
|
MeshIndexTable = 0x12017105,
|
||||||
|
MessageData = 0x12027020,
|
||||||
|
ShaderData = 0x1401B400,
|
||||||
|
TextureHeader = 0x0201B501,
|
||||||
|
TextureData = 0x1701B502,
|
||||||
|
}
|
||||||
|
}
|
120
File_Format_Library/FileFormats/Archives/LM2/LM2_Model.cs
Normal file
120
File_Format_Library/FileFormats/Archives/LM2/LM2_Model.cs
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using Toolbox.Library;
|
||||||
|
using Toolbox.Library.IO;
|
||||||
|
using Toolbox.Library.Forms;
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
|
namespace FirstPlugin.LuigisMansion.DarkMoon
|
||||||
|
{
|
||||||
|
public class LM2_Model : TreeNodeCustom
|
||||||
|
{
|
||||||
|
public LM2_ModelInfo ModelInfo;
|
||||||
|
public List<LM2_Mesh> Meshes = new List<LM2_Mesh>();
|
||||||
|
public List<uint> VertexBufferPointers = new List<uint>();
|
||||||
|
public Matrix4 Transform { get; set; }
|
||||||
|
|
||||||
|
public override void OnClick(TreeView treeView)
|
||||||
|
{
|
||||||
|
STPropertyGrid editor = (STPropertyGrid)LibraryGUI.GetActiveContent(typeof(STPropertyGrid));
|
||||||
|
if (editor == null)
|
||||||
|
{
|
||||||
|
editor = new STPropertyGrid();
|
||||||
|
LibraryGUI.LoadEditor(editor);
|
||||||
|
}
|
||||||
|
editor.Text = Text;
|
||||||
|
editor.Dock = DockStyle.Fill;
|
||||||
|
editor.LoadProperty(this, OnPropertyChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnPropertyChanged() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LM2_ModelInfo
|
||||||
|
{
|
||||||
|
public byte[] Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RenderableMeshWrapper : STGenericObject
|
||||||
|
{
|
||||||
|
public LM2_Mesh Mesh { get; set; }
|
||||||
|
|
||||||
|
public override void OnClick(TreeView treeView)
|
||||||
|
{
|
||||||
|
STPropertyGrid editor = (STPropertyGrid)LibraryGUI.GetActiveContent(typeof(STPropertyGrid));
|
||||||
|
if (editor == null)
|
||||||
|
{
|
||||||
|
editor = new STPropertyGrid();
|
||||||
|
LibraryGUI.LoadEditor(editor);
|
||||||
|
}
|
||||||
|
editor.Text = Text;
|
||||||
|
editor.Dock = DockStyle.Fill;
|
||||||
|
editor.LoadProperty(Mesh, OnPropertyChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnPropertyChanged() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LM2_IndexList
|
||||||
|
{
|
||||||
|
public short[] UnknownIndices { get; set; }
|
||||||
|
|
||||||
|
public uint Unknown { get; set; }
|
||||||
|
|
||||||
|
public short[] UnknownIndices2 { get; set; }
|
||||||
|
|
||||||
|
public uint[] Unknown2 { get; set; }
|
||||||
|
|
||||||
|
public void Read(FileReader reader)
|
||||||
|
{
|
||||||
|
UnknownIndices = reader.ReadInt16s(4);
|
||||||
|
Unknown = reader.ReadUInt32();
|
||||||
|
UnknownIndices2 = reader.ReadInt16s(8);
|
||||||
|
Unknown2 = reader.ReadUInt32s(6); //Increases by 32 each entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LM2_Mesh
|
||||||
|
{
|
||||||
|
public uint IndexStartOffset { get; private set; } //relative to buffer start
|
||||||
|
public ushort IndexCount { get; private set; } //divide by 3 to get face count
|
||||||
|
public ushort IndexFormat { get; private set; } //0x0 - ushort, 0x8000 - byte
|
||||||
|
|
||||||
|
public ushort BufferStride { get; private set; }
|
||||||
|
public ushort Unknown { get; private set; }
|
||||||
|
public ushort Unknown2 { get; private set; }
|
||||||
|
public ulong DataFormat { get; private set; }
|
||||||
|
public uint Unknown4 { get; private set; }
|
||||||
|
public uint Unknown5 { get; private set; }
|
||||||
|
public uint Unknown6 { get; private set; }
|
||||||
|
public ushort VertexCount { get; private set; }
|
||||||
|
public ushort Unknown7 { get; private set; }
|
||||||
|
public uint HashID { get; private set; }
|
||||||
|
|
||||||
|
public void Read(FileReader reader)
|
||||||
|
{
|
||||||
|
IndexStartOffset = reader.ReadUInt32();
|
||||||
|
IndexCount = reader.ReadUInt16();
|
||||||
|
IndexFormat = reader.ReadUInt16();
|
||||||
|
BufferStride = reader.ReadUInt16();
|
||||||
|
Unknown = reader.ReadUInt16();
|
||||||
|
Unknown2 = reader.ReadUInt16();
|
||||||
|
DataFormat = reader.ReadUInt64();
|
||||||
|
Unknown4 = reader.ReadUInt32();
|
||||||
|
Unknown5 = reader.ReadUInt32();
|
||||||
|
Unknown6 = reader.ReadUInt32();
|
||||||
|
VertexCount = reader.ReadUInt16();
|
||||||
|
Unknown7 = reader.ReadUInt16(); //0x100
|
||||||
|
HashID = reader.ReadUInt32(); //0x100
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FormatInfo
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
99
File_Format_Library/FileFormats/Archives/LM2/TexturePOWE.cs
Normal file
99
File_Format_Library/FileFormats/Archives/LM2/TexturePOWE.cs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Toolbox.Library;
|
||||||
|
using Toolbox.Library.IO;
|
||||||
|
using Toolbox.Library.Forms;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace FirstPlugin.LuigisMansion.DarkMoon
|
||||||
|
{
|
||||||
|
public class TexturePOWE : STGenericTexture
|
||||||
|
{
|
||||||
|
public static readonly uint Identifier = 0xE977D350;
|
||||||
|
|
||||||
|
public uint Index { get; set; }
|
||||||
|
|
||||||
|
public uint ID { get; set; }
|
||||||
|
public uint ImageSize { get; set; }
|
||||||
|
public uint ID2 { get; set; }
|
||||||
|
|
||||||
|
public byte[] ImageData { get; set; }
|
||||||
|
|
||||||
|
public void Read(FileReader reader)
|
||||||
|
{
|
||||||
|
//Magic and ID not pointed to for sub entries so just skip them for now
|
||||||
|
// uint magic = reader.ReadUInt32();
|
||||||
|
// if (magic != Identifier)
|
||||||
|
// throw new Exception($"Invalid texture header magic! Expected {Identifier.ToString("x")}. Got {Identifier.ToString("x")}");
|
||||||
|
// ID = reader.ReadUInt32();
|
||||||
|
|
||||||
|
PlatformSwizzle = PlatformSwizzle.Platform_3DS;
|
||||||
|
|
||||||
|
ImageSize = reader.ReadUInt32();
|
||||||
|
ID2 = reader.ReadUInt32();
|
||||||
|
reader.Seek(0x8);
|
||||||
|
Width = reader.ReadUInt16();
|
||||||
|
Height = reader.ReadUInt16();
|
||||||
|
reader.Seek(3);
|
||||||
|
var numMips = reader.ReadByte();
|
||||||
|
reader.Seek(0x14);
|
||||||
|
byte FormatCtr = reader.ReadByte();
|
||||||
|
reader.Seek(3);
|
||||||
|
|
||||||
|
MipCount = 1;
|
||||||
|
Format = CTR_3DS.ConvertPICAToGenericFormat((CTR_3DS.PICASurfaceFormat)FormatCtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnClick(TreeView treeview)
|
||||||
|
{
|
||||||
|
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(this.GenericProperties);
|
||||||
|
editor.LoadImage(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanEdit { get; set; } = false;
|
||||||
|
|
||||||
|
public override void SetImageData(Bitmap bitmap, int ArrayLevel)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0)
|
||||||
|
{
|
||||||
|
return ImageData;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -206,6 +206,9 @@
|
|||||||
<Compile Include="FileFormats\Archives\IGA_PAK.cs" />
|
<Compile Include="FileFormats\Archives\IGA_PAK.cs" />
|
||||||
<Compile Include="FileFormats\Archives\LM2\LM2_ChunkTable.cs" />
|
<Compile Include="FileFormats\Archives\LM2\LM2_ChunkTable.cs" />
|
||||||
<Compile Include="FileFormats\Archives\LM2\LM2_DICT.cs" />
|
<Compile Include="FileFormats\Archives\LM2\LM2_DICT.cs" />
|
||||||
|
<Compile Include="FileFormats\Archives\LM2\LM2_Enums.cs" />
|
||||||
|
<Compile Include="FileFormats\Archives\LM2\LM2_Model.cs" />
|
||||||
|
<Compile Include="FileFormats\Archives\LM2\TexturePOWE.cs" />
|
||||||
<Compile Include="FileFormats\Archives\LZARC.cs" />
|
<Compile Include="FileFormats\Archives\LZARC.cs" />
|
||||||
<Compile Include="FileFormats\Archives\ME01.cs" />
|
<Compile Include="FileFormats\Archives\ME01.cs" />
|
||||||
<Compile Include="FileFormats\Archives\MKGPDX_PAC.cs" />
|
<Compile Include="FileFormats\Archives\MKGPDX_PAC.cs" />
|
||||||
|
@ -7,6 +7,7 @@ using Toolbox.Library;
|
|||||||
using Toolbox.Library.Forms;
|
using Toolbox.Library.Forms;
|
||||||
using Toolbox.Library.IO;
|
using Toolbox.Library.IO;
|
||||||
using FirstPlugin.Forms;
|
using FirstPlugin.Forms;
|
||||||
|
using FirstPlugin.LuigisMansion.DarkMoon;
|
||||||
|
|
||||||
namespace FirstPlugin
|
namespace FirstPlugin
|
||||||
{
|
{
|
||||||
|
@ -540,8 +540,8 @@ namespace Toolbox.Library.Forms
|
|||||||
|
|
||||||
private void treeViewCustom1_DragOver(object sender, DragEventArgs e)
|
private void treeViewCustom1_DragOver(object sender, DragEventArgs e)
|
||||||
{
|
{
|
||||||
var file = GetActiveArchive();
|
var root = GetActiveArchive();
|
||||||
if (file == null || !file.CanReplaceFiles)
|
if (root == null || !root.ArchiveFile.CanReplaceFiles)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Point pt = treeViewCustom1.PointToClient(new Point(e.X, e.Y));
|
Point pt = treeViewCustom1.PointToClient(new Point(e.X, e.Y));
|
||||||
@ -557,10 +557,15 @@ namespace Toolbox.Library.Forms
|
|||||||
// e.Effect = DragDropEffects.None;
|
// e.Effect = DragDropEffects.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IArchiveFile GetActiveArchive()
|
private ArchiveRootNodeWrapper GetActiveArchive()
|
||||||
{
|
{
|
||||||
if (treeViewCustom1.SelectedNode != null && treeViewCustom1.SelectedNode is ArchiveBase)
|
var node = treeViewCustom1.SelectedNode;
|
||||||
return ((ArchiveBase)treeViewCustom1.SelectedNode).ArchiveFile;
|
if (node != null && node is ArchiveRootNodeWrapper)
|
||||||
|
return (ArchiveRootNodeWrapper)node;
|
||||||
|
if (node != null && node is ArchiveFileWrapper)
|
||||||
|
return ((ArchiveFileWrapper)node).RootNode;
|
||||||
|
if (node != null && node is ArchiveFolderNodeWrapper)
|
||||||
|
return ((ArchiveFolderNodeWrapper)node).RootNode;
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -183,13 +183,15 @@ namespace Toolbox.Library
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void AddFiles(TreeNode parentNode, IArchiveFile archiveFile, string[] Files)
|
public static void AddFiles(TreeNode parentNode, ArchiveRootNodeWrapper rootNode, string[] Files)
|
||||||
{
|
{
|
||||||
|
var archiveFile = rootNode.ArchiveFile;
|
||||||
|
|
||||||
if (Files == null || Files.Length <= 0 || !archiveFile.CanAddFiles) return;
|
if (Files == null || Files.Length <= 0 || !archiveFile.CanAddFiles) return;
|
||||||
|
|
||||||
for (int i = 0; i < Files.Length; i++)
|
for (int i = 0; i < Files.Length; i++)
|
||||||
{
|
{
|
||||||
var File = ArchiveFileWrapper.FromPath(Files[i], archiveFile);
|
var File = ArchiveFileWrapper.FromPath(Files[i], rootNode);
|
||||||
string FileName = Path.GetFileName(Files[i]);
|
string FileName = Path.GetFileName(Files[i]);
|
||||||
|
|
||||||
//Don't add the root file name
|
//Don't add the root file name
|
||||||
@ -209,9 +211,9 @@ namespace Toolbox.Library
|
|||||||
if (HasAddedFile)
|
if (HasAddedFile)
|
||||||
{
|
{
|
||||||
if (parentNode is ArchiveRootNodeWrapper)
|
if (parentNode is ArchiveRootNodeWrapper)
|
||||||
((ArchiveRootNodeWrapper)parentNode).FileNodes.Add(File);
|
((ArchiveRootNodeWrapper)parentNode).AddFileNode(File);
|
||||||
if (parentNode is ArchiveFolderNodeWrapper)
|
if (parentNode is ArchiveFolderNodeWrapper)
|
||||||
((ArchiveRootNodeWrapper)parentNode).FileNodes.Add(File);
|
((ArchiveRootNodeWrapper)parentNode).AddFileNode(File);
|
||||||
|
|
||||||
parentNode.Nodes.Add(File);
|
parentNode.Nodes.Add(File);
|
||||||
}
|
}
|
||||||
|
@ -147,6 +147,50 @@ namespace Toolbox.Library.IO
|
|||||||
return new Syroot.IOExtension.Half(ReadUInt16());
|
return new Syroot.IOExtension.Half(ReadUInt16());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Matrix4 ReadMatrix4(bool SwapRows = false)
|
||||||
|
{
|
||||||
|
Matrix4 mat4 = new Matrix4();
|
||||||
|
if (SwapRows)
|
||||||
|
{
|
||||||
|
mat4.M11 = ReadSingle();
|
||||||
|
mat4.M21 = ReadSingle();
|
||||||
|
mat4.M31 = ReadSingle();
|
||||||
|
mat4.M41 = ReadSingle();
|
||||||
|
mat4.M12 = ReadSingle();
|
||||||
|
mat4.M22 = ReadSingle();
|
||||||
|
mat4.M32 = ReadSingle();
|
||||||
|
mat4.M42 = ReadSingle();
|
||||||
|
mat4.M13 = ReadSingle();
|
||||||
|
mat4.M23 = ReadSingle();
|
||||||
|
mat4.M33 = ReadSingle();
|
||||||
|
mat4.M43 = ReadSingle();
|
||||||
|
mat4.M14 = ReadSingle();
|
||||||
|
mat4.M24 = ReadSingle();
|
||||||
|
mat4.M34 = ReadSingle();
|
||||||
|
mat4.M44 = ReadSingle();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mat4.M11 = ReadSingle();
|
||||||
|
mat4.M12 = ReadSingle();
|
||||||
|
mat4.M13 = ReadSingle();
|
||||||
|
mat4.M14 = ReadSingle();
|
||||||
|
mat4.M21 = ReadSingle();
|
||||||
|
mat4.M22 = ReadSingle();
|
||||||
|
mat4.M23 = ReadSingle();
|
||||||
|
mat4.M24 = ReadSingle();
|
||||||
|
mat4.M31 = ReadSingle();
|
||||||
|
mat4.M32 = ReadSingle();
|
||||||
|
mat4.M33 = ReadSingle();
|
||||||
|
mat4.M34 = ReadSingle();
|
||||||
|
mat4.M41 = ReadSingle();
|
||||||
|
mat4.M42 = ReadSingle();
|
||||||
|
mat4.M43 = ReadSingle();
|
||||||
|
mat4.M44 = ReadSingle();
|
||||||
|
}
|
||||||
|
return mat4;
|
||||||
|
}
|
||||||
|
|
||||||
public void SeekBegin(uint Offset) { Seek(Offset, SeekOrigin.Begin); }
|
public void SeekBegin(uint Offset) { Seek(Offset, SeekOrigin.Begin); }
|
||||||
public void SeekBegin(int Offset) { Seek(Offset, SeekOrigin.Begin); }
|
public void SeekBegin(int Offset) { Seek(Offset, SeekOrigin.Begin); }
|
||||||
public void SeekBegin(long Offset) { Seek(Offset, SeekOrigin.Begin); }
|
public void SeekBegin(long Offset) { Seek(Offset, SeekOrigin.Begin); }
|
||||||
|
@ -183,7 +183,8 @@ namespace Toolbox.Library
|
|||||||
//Wrapper for the archive file itself
|
//Wrapper for the archive file itself
|
||||||
public class ArchiveRootNodeWrapper : ArchiveBase, IContextMenuNode
|
public class ArchiveRootNodeWrapper : ArchiveBase, IContextMenuNode
|
||||||
{
|
{
|
||||||
public List<ArchiveFileWrapper> FileNodes = new List<ArchiveFileWrapper>();
|
//A list that links archive file infos to treenodes of varying types
|
||||||
|
public List<Tuple<ArchiveFileInfo, TreeNode>> FileNodes = new List<Tuple<ArchiveFileInfo, TreeNode>>();
|
||||||
|
|
||||||
public virtual object PropertyDisplay { get; set; }
|
public virtual object PropertyDisplay { get; set; }
|
||||||
|
|
||||||
@ -195,6 +196,11 @@ namespace Toolbox.Library
|
|||||||
PropertyDisplay = new GenericArchiveProperties(archiveFile, text);
|
PropertyDisplay = new GenericArchiveProperties(archiveFile, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddFileNode(ArchiveFileWrapper fileWrapper)
|
||||||
|
{
|
||||||
|
FileNodes.Add(Tuple.Create(fileWrapper.ArchiveFileInfo, (TreeNode)fileWrapper));
|
||||||
|
}
|
||||||
|
|
||||||
public ToolStripItem[] GetContextMenuItems()
|
public ToolStripItem[] GetContextMenuItems()
|
||||||
{
|
{
|
||||||
var ToolStrips = new ToolStripItem[]
|
var ToolStrips = new ToolStripItem[]
|
||||||
@ -232,7 +238,7 @@ namespace Toolbox.Library
|
|||||||
|
|
||||||
if (ofd.ShowDialog() == DialogResult.OK)
|
if (ofd.ShowDialog() == DialogResult.OK)
|
||||||
{
|
{
|
||||||
TreeHelper.AddFiles(this, ArchiveFile, ofd.FileNames);
|
TreeHelper.AddFiles(this, this, ofd.FileNames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +248,9 @@ namespace Toolbox.Library
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < FileNodes.Count; i++)
|
for (int i = 0; i < FileNodes.Count; i++)
|
||||||
FileNodes[i].ArchiveFileInfo.FileName = SetFullPath(FileNodes[i], this);
|
{
|
||||||
|
FileNodes[i].Item1.FileName = SetFullPath(FileNodes[i].Item2, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string SetFullPath(TreeNode node, TreeNode root)
|
private static string SetFullPath(TreeNode node, TreeNode root)
|
||||||
@ -411,7 +419,7 @@ namespace Toolbox.Library
|
|||||||
}
|
}
|
||||||
else if (node is ArchiveFileInfo)
|
else if (node is ArchiveFileInfo)
|
||||||
{
|
{
|
||||||
ArchiveFileWrapper wrapperFile = new ArchiveFileWrapper(node.Name, (ArchiveFileInfo)node, archiveFile);
|
ArchiveFileWrapper wrapperFile = new ArchiveFileWrapper(node.Name, (ArchiveFileInfo)node, this);
|
||||||
wrapperFile.Name = node.Name;
|
wrapperFile.Name = node.Name;
|
||||||
parent.Nodes.Add(wrapperFile);
|
parent.Nodes.Add(wrapperFile);
|
||||||
}
|
}
|
||||||
@ -468,11 +476,11 @@ namespace Toolbox.Library
|
|||||||
|
|
||||||
if (rootIndex == roots.Length - 1)
|
if (rootIndex == roots.Length - 1)
|
||||||
{
|
{
|
||||||
ArchiveFileWrapper wrapperFile = new ArchiveFileWrapper(parentName, node, archiveFile);
|
ArchiveFileWrapper wrapperFile = new ArchiveFileWrapper(parentName, node, this);
|
||||||
wrapperFile.Name = nodeName;
|
wrapperFile.Name = nodeName;
|
||||||
parentNode.Nodes.Add(wrapperFile);
|
parentNode.Nodes.Add(wrapperFile);
|
||||||
parentNode = wrapperFile;
|
parentNode = wrapperFile;
|
||||||
FileNodes.Add(wrapperFile);
|
AddFileNode(wrapperFile);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -557,7 +565,7 @@ namespace Toolbox.Library
|
|||||||
ofd.Multiselect = true;
|
ofd.Multiselect = true;
|
||||||
|
|
||||||
if (ofd.ShowDialog() == DialogResult.OK) {
|
if (ofd.ShowDialog() == DialogResult.OK) {
|
||||||
TreeHelper.AddFiles(this, ArchiveFile, ofd.FileNames);
|
TreeHelper.AddFiles(this, RootNode, ofd.FileNames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -618,11 +626,14 @@ namespace Toolbox.Library
|
|||||||
//Wrapper for files
|
//Wrapper for files
|
||||||
public class ArchiveFileWrapper : ArchiveBase, IContextMenuNode
|
public class ArchiveFileWrapper : ArchiveBase, IContextMenuNode
|
||||||
{
|
{
|
||||||
|
public ArchiveRootNodeWrapper RootNode;
|
||||||
|
|
||||||
public virtual ArchiveFileInfo ArchiveFileInfo { get; set; }
|
public virtual ArchiveFileInfo ArchiveFileInfo { get; set; }
|
||||||
|
|
||||||
public ArchiveFileWrapper(string text, ArchiveFileInfo archiveFileInfo, IArchiveFile archiveFile) : base(archiveFile)
|
public ArchiveFileWrapper(string text, ArchiveFileInfo archiveFileInfo, ArchiveRootNodeWrapper rootNode) : base(rootNode.ArchiveFile)
|
||||||
{
|
{
|
||||||
Text = text;
|
Text = text;
|
||||||
|
RootNode = rootNode;
|
||||||
// ReloadMenus(archiveFile);
|
// ReloadMenus(archiveFile);
|
||||||
|
|
||||||
ArchiveFileInfo = archiveFileInfo;
|
ArchiveFileInfo = archiveFileInfo;
|
||||||
@ -705,12 +716,12 @@ namespace Toolbox.Library
|
|||||||
else return "";
|
else return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ArchiveFileWrapper FromPath(string FilePath, IArchiveFile archiveFile)
|
public static ArchiveFileWrapper FromPath(string FilePath, ArchiveRootNodeWrapper rootNode)
|
||||||
{
|
{
|
||||||
var ArchiveFileInfo = new ArchiveFileInfo();
|
var ArchiveFileInfo = new ArchiveFileInfo();
|
||||||
ArchiveFileInfo.FileName = FilePath;
|
ArchiveFileInfo.FileName = FilePath;
|
||||||
ArchiveFileInfo.FileData = File.ReadAllBytes(FilePath);
|
ArchiveFileInfo.FileData = File.ReadAllBytes(FilePath);
|
||||||
return new ArchiveFileWrapper(Path.GetFileName(FilePath), ArchiveFileInfo, archiveFile);
|
return new ArchiveFileWrapper(Path.GetFileName(FilePath), ArchiveFileInfo, rootNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ToolStripItem[] GetContextMenuItems()
|
public ToolStripItem[] GetContextMenuItems()
|
||||||
@ -781,12 +792,12 @@ namespace Toolbox.Library
|
|||||||
OpenFormDialog(file);
|
OpenFormDialog(file);
|
||||||
}
|
}
|
||||||
else if (file is TreeNode)
|
else if (file is TreeNode)
|
||||||
ReplaceNode(this.Parent, this, (TreeNode)file);
|
ReplaceNode(this.Parent, this, (TreeNode)file, RootNode);
|
||||||
else if (file is IArchiveFile)
|
else if (file is IArchiveFile)
|
||||||
{
|
{
|
||||||
var FileRoot = new ArchiveRootNodeWrapper(file.FileName, (IArchiveFile)file);
|
var FileRoot = new ArchiveRootNodeWrapper(file.FileName, (IArchiveFile)file);
|
||||||
FileRoot.FillTreeNodes();
|
FileRoot.FillTreeNodes();
|
||||||
ReplaceNode(this.Parent, this, FileRoot);
|
ReplaceNode(this.Parent, this, FileRoot, RootNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -847,15 +858,20 @@ namespace Toolbox.Library
|
|||||||
editor.UpdateEditor();
|
editor.UpdateEditor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ReplaceNode(TreeNode node, TreeNode replaceNode, TreeNode NewNode)
|
public static void ReplaceNode(TreeNode node, ArchiveFileWrapper replaceNode, TreeNode NewNode, ArchiveRootNodeWrapper rootNode)
|
||||||
{
|
{
|
||||||
if (NewNode == null)
|
if (NewNode == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var fileInfo = replaceNode.ArchiveFileInfo;
|
||||||
|
|
||||||
int index = node.Nodes.IndexOf(replaceNode);
|
int index = node.Nodes.IndexOf(replaceNode);
|
||||||
node.Nodes.RemoveAt(index);
|
node.Nodes.RemoveAt(index);
|
||||||
node.Nodes.Insert(index, NewNode);
|
node.Nodes.Insert(index, NewNode);
|
||||||
|
|
||||||
|
rootNode.FileNodes.RemoveAt(index);
|
||||||
|
rootNode.FileNodes.Insert(index, Tuple.Create(fileInfo, NewNode));
|
||||||
|
|
||||||
NewNode.ImageKey = replaceNode.ImageKey;
|
NewNode.ImageKey = replaceNode.ImageKey;
|
||||||
NewNode.SelectedImageKey = replaceNode.SelectedImageKey;
|
NewNode.SelectedImageKey = replaceNode.SelectedImageKey;
|
||||||
NewNode.Text = replaceNode.Text;
|
NewNode.Text = replaceNode.Text;
|
||||||
|
Loading…
Reference in New Issue
Block a user