diff --git a/.vs/Toolbox/v15/.suo b/.vs/Toolbox/v15/.suo index 7626cbc8..bd7cb1f0 100644 Binary files a/.vs/Toolbox/v15/.suo and b/.vs/Toolbox/v15/.suo differ diff --git a/File_Format_Library/FileFormats/DKCTF/MSBT.cs b/File_Format_Library/FileFormats/DKCTF/MSBT.cs index e7f6e838..8dee9625 100644 --- a/File_Format_Library/FileFormats/DKCTF/MSBT.cs +++ b/File_Format_Library/FileFormats/DKCTF/MSBT.cs @@ -6,12 +6,14 @@ using System.Threading.Tasks; using System.Runtime.InteropServices; using Toolbox.Library; using Toolbox.Library.IO; +using Toolbox.Library.Forms; +using System.IO; using System.Windows.Forms; using FirstPlugin.Forms; namespace DKCTF { - public class MSBT : TreeNodeFile, IFileFormat + public class MSBT : TreeNodeFile, IFileFormat, ILeaveOpenOnLoad { public FileType FileType { get; set; } = FileType.Layout; @@ -42,13 +44,17 @@ namespace DKCTF } } + private Stream _stream; public void Load(System.IO.Stream stream) { - using (var reader = new Toolbox.Library.IO.FileReader(stream)) + _stream = stream; + using (var reader = new Toolbox.Library.IO.FileReader(stream, true)) { reader.SetByteOrder(true); var header = reader.ReadStruct(); + Text = FileName; + //parse the data int index = 0; while (!reader.EndOfStream) @@ -57,8 +63,10 @@ namespace DKCTF long startPos = reader.Position; reader.SeekBegin(startPos + (int)chunk.DataOffset); - byte[] chunkData = reader.ReadBytes((int)chunk.DataSize); - Nodes.Add(new MessageEntry(chunkData, index++, chunk.ChunkType)); + var subStream = new SubStream(_stream, reader.Position, (long)chunk.DataSize); + Nodes.Add(new MessageEntry(subStream, index++, chunk.ChunkType)); + + reader.SeekBegin(startPos + (int)chunk.DataOffset + (int)chunk.DataSize); } } } @@ -67,19 +75,40 @@ namespace DKCTF } - public class MessageEntry : TreeNodeCustom + public class MessageEntry : TreeNodeCustom, IContextMenuNode { FirstPlugin.MSBT msbt; - public MessageEntry(byte[] data, int index, string type) + private Stream stream; + public MessageEntry(Stream data, int index, string type) { - Text = $"Message Entry ({type}) {index}"; + stream = data; - var chunkFile = STFileLoader.OpenFileFormat(Text, data); + Text = $"{type}.msbt"; + + var chunkFile = STFileLoader.OpenFileFormat(data, Text); if (chunkFile != null && chunkFile is FirstPlugin.MSBT) msbt = (FirstPlugin.MSBT)chunkFile; } + public ToolStripItem[] GetContextMenuItems() + { + List Items = new List(); + Items.Add(new STToolStipMenuItem("Export", null, ExportAction, Keys.Control | Keys.E)); + return Items.ToArray(); + } + + private void ExportAction(object sender, EventArgs args) + { + SaveFileDialog sfd = new SaveFileDialog(); + sfd.Filter = Utils.GetAllFilters(typeof(MSBT)); + sfd.FileName = Text; + if (sfd.ShowDialog() == DialogResult.OK) + { + stream.ExportToFile(sfd.FileName); + } + } + public override void OnClick(TreeView treeview) { if (msbt != null) diff --git a/File_Format_Library/FileFormats/Effects/EFF.cs b/File_Format_Library/FileFormats/Effects/EFF.cs index 3d2050f7..39065ae6 100644 --- a/File_Format_Library/FileFormats/Effects/EFF.cs +++ b/File_Format_Library/FileFormats/Effects/EFF.cs @@ -5,10 +5,11 @@ using System.Text; using System.Threading.Tasks; using Toolbox.Library.IO; using Toolbox.Library; +using System.Windows.Forms; namespace FirstPlugin { - public class EFF : TreeNodeFile,IFileFormat + public class EFF : TreeNodeFile,IFileFormat, IContextMenuNode { public FileType FileType { get; set; } = FileType.Effect; @@ -36,19 +37,54 @@ namespace FirstPlugin } } + private PTCL ptcl; + private byte[] DataStart; public void Load(System.IO.Stream stream) { Text = FileName; + CanSave = true; FileReader reader = new FileReader(stream); - reader.Seek(4096, System.IO.SeekOrigin.Begin); + int SectionSize = 0; + while (true) + { + string magicCheck = reader.ReadString(4, Encoding.ASCII); + if (magicCheck == "VFXB") + { + reader.Seek(-4); + break; + } - PTCL pctl = new PTCL(); - pctl.Text = "Output.pctl"; - Nodes.Add(pctl); + SectionSize += 4; + } - PTCL.Header Header = new PTCL.Header(); - Header.Read(reader, pctl); + DataStart = reader.getSection(0, SectionSize); + + Text = FileName; + ptcl = new PTCL(); + ptcl.IFileInfo = new IFileInfo(); + ptcl.FileName = "Output.pctl"; + Nodes.Add(ptcl); + + ptcl.Load(new SubStream(stream, reader.Position)); + } + + public ToolStripItem[] GetContextMenuItems() + { + return new ToolStripItem[] + { + new ToolStripMenuItem("Save", null, SaveAction, Keys.Control | Keys.S), + }; + } + + private void SaveAction(object sender, EventArgs args) + { + SaveFileDialog sfd = new SaveFileDialog(); + sfd.Filter = Utils.GetAllFilters(typeof(EFF)); + sfd.FileName = FileName; + + if (sfd.ShowDialog() == DialogResult.OK) + STFileSaver.SaveFileFormat(this, sfd.FileName); } public void Unload() @@ -58,6 +94,13 @@ namespace FirstPlugin public void Save(System.IO.Stream stream) { + using (var writer = new FileWriter(stream)) + { + writer.Write(DataStart); + var mem = new System.IO.MemoryStream(); + ptcl.Save(mem); + writer.Write(mem.ToArray()); + } } } } diff --git a/File_Format_Library/FileFormats/Effects/PCTL.cs b/File_Format_Library/FileFormats/Effects/PCTL.cs index 5c4eb61a..6c0e74af 100644 --- a/File_Format_Library/FileFormats/Effects/PCTL.cs +++ b/File_Format_Library/FileFormats/Effects/PCTL.cs @@ -64,38 +64,39 @@ namespace FirstPlugin Text = FileName; CanSave = true; - FileReader reader = new FileReader(new MemoryStream(data)); - - reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; - string Signature = reader.ReadString(4, Encoding.ASCII); - - byte VersionNum = reader.ReadByte(); - if (VersionNum != 0 && Signature == "SPBD") - Is3DS = true; - - reader.Position = 0; - if (Is3DS) + using (var reader = new FileReader(stream)) { - reader.ByteOrder = ByteOrder.LittleEndian; - header3DS = new PTCL_3DS.Header(); - header3DS.Read(reader, this); - } - else if (Signature == "EFTF" || Signature == "SPBD") - { - IsWiiU = true; - headerU = new PTCL_WiiU.Header(); - headerU.Read(reader, this); - } - else - { - header = new Header(); - header.Read(reader, this); - } + reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; + string Signature = reader.ReadString(4, Encoding.ASCII); - reader.Close(); - reader.Dispose(); - stream.Close(); - stream.Dispose(); + byte VersionNum = reader.ReadByte(); + if (VersionNum != 0 && Signature == "SPBD") + Is3DS = true; + + reader.Position = 0; + if (Is3DS) + { + reader.ByteOrder = ByteOrder.LittleEndian; + header3DS = new PTCL_3DS.Header(); + header3DS.Read(reader, this); + } + else if (Signature == "EFTF" || Signature == "SPBD") + { + IsWiiU = true; + headerU = new PTCL_WiiU.Header(); + headerU.Read(reader, this); + } + else + { + header = new Header(); + header.Read(reader, this); + } + + reader.Close(); + reader.Dispose(); + stream.Close(); + stream.Dispose(); + } ContextMenuStrip = new STContextMenuStrip(); ContextMenuStrip.Items.Add(new ToolStripMenuItem("Save", null, Save, Keys.Control | Keys.S)); @@ -116,11 +117,8 @@ namespace FirstPlugin } private void Save(object sender, EventArgs args) { - List formats = new List(); - formats.Add(this); - SaveFileDialog sfd = new SaveFileDialog(); - sfd.Filter = Utils.GetAllFilters(formats); + sfd.Filter = Utils.GetAllFilters(typeof(PTCL)); sfd.FileName = FileName; if (sfd.ShowDialog() == DialogResult.OK) diff --git a/Switch_Toolbox_Library/IO/Extensions/StreamExport.cs b/Switch_Toolbox_Library/IO/Extensions/StreamExport.cs new file mode 100644 index 00000000..178b0f3a --- /dev/null +++ b/Switch_Toolbox_Library/IO/Extensions/StreamExport.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; + +namespace Toolbox.Library.IO +{ + public static class StreamExport + { + public static void ExportToFile(this Stream stream, string fileName) + { + using (var fileStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Write)) + { + stream.CopyTo(fileStream); + } + } + } +} diff --git a/Switch_Toolbox_Library/IO/STFileLoader.cs b/Switch_Toolbox_Library/IO/STFileLoader.cs index 291c6e2e..832f320d 100644 --- a/Switch_Toolbox_Library/IO/STFileLoader.cs +++ b/Switch_Toolbox_Library/IO/STFileLoader.cs @@ -133,190 +133,201 @@ namespace Toolbox.Library.IO public static IFileFormat OpenFileFormat(string FileName, byte[] data = null, bool LeaveStreamOpen = false, bool InArchive = false, TreeNode archiveNode = null, bool Compressed = false, CompressionType CompType = 0, uint DecompressedSize = 0, uint CompressedSize = 0) { - uint DecompressedFileSize = 0; - uint CompressedFileSize = 0; - - FileReader fileReader; - if (data != null) - fileReader = new FileReader(data); - else - fileReader = new FileReader(FileName); - - if (CompType == CompressionType.None) - DecompressedFileSize = (uint)fileReader.BaseStream.Length; - if (CompType != CompressionType.None) - CompressedFileSize = (uint)fileReader.BaseStream.Length; - - if (fileReader.BaseStream.Length <= 4) - { - fileReader.Close(); - fileReader.Dispose(); - return null; - } - - Cursor.Current = Cursors.WaitCursor; - fileReader.ByteOrder = ByteOrder.BigEndian; - uint MagicHex = fileReader.ReadUInt32(); - - string Magic = fileReader.ReadMagic(0, 4); - - fileReader.Position = 0; - ushort MagicHex2 = fileReader.ReadUInt16(); - - //Another hacky magic check if decomp size is first - fileReader.Position = 4; - ushort MagicHex3 = fileReader.ReadUInt16(); - Stream stream; if (data != null) stream = new MemoryStream(data); else stream = File.OpenRead(FileName); - //Note this method will soon be how all compression formats are handled rather than being checked here - foreach (ICompressionFormat compressionFormat in FileManager.GetCompressionFormats()) + return OpenFileFormat(stream, FileName, data, LeaveStreamOpen, InArchive, + archiveNode, Compressed, CompType, DecompressedSize, CompressedSize); + } + + /// + /// Gets the from a file or byte array. + /// + /// The name of the file + /// The byte array of the data + /// If the file is in an archive so it can be saved back + /// The node being replaced from an archive + /// If the file is being compressed or not + /// The type of being used + /// + public static IFileFormat OpenFileFormat(Stream stream, string FileName, byte[] data = null, bool LeaveStreamOpen = false, bool InArchive = false, + TreeNode archiveNode = null, bool Compressed = false, CompressionType CompType = 0, uint DecompressedSize = 0, uint CompressedSize = 0) + { + uint DecompressedFileSize = 0; + uint CompressedFileSize = 0; + + using (var fileReader = new FileReader(stream, true)) { - if (compressionFormat.Identify(stream)) + if (CompType == CompressionType.None) + DecompressedFileSize = (uint)fileReader.BaseStream.Length; + if (CompType != CompressionType.None) + CompressedFileSize = (uint)fileReader.BaseStream.Length; + + if (fileReader.BaseStream.Length <= 4) { - stream = compressionFormat.Decompress(stream); + fileReader.Close(); + fileReader.Dispose(); + return null; } - } - if (Magic == "Yaz0") - { - if (data != null) - data = EveryFileExplorer.YAZ0.Decompress(data); - else - data = EveryFileExplorer.YAZ0.Decompress(FileName); + Cursor.Current = Cursors.WaitCursor; + fileReader.ByteOrder = ByteOrder.BigEndian; + uint MagicHex = fileReader.ReadUInt32(); + + string Magic = fileReader.ReadMagic(0, 4); - return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, - CompressionType.Yaz0, DecompressedFileSize, CompressedFileSize); - } - if (Path.GetExtension(FileName) == ".cbtex") - { fileReader.Position = 0; - byte compType = fileReader.ReadByte(); - if (compType == 0x50) + ushort MagicHex2 = fileReader.ReadUInt16(); + + //Another hacky magic check if decomp size is first + fileReader.Position = 4; + ushort MagicHex3 = fileReader.ReadUInt16(); + + //Note this method will soon be how all compression formats are handled rather than being checked here + foreach (ICompressionFormat compressionFormat in FileManager.GetCompressionFormats()) + { + if (compressionFormat.Identify(stream)) + { + stream = compressionFormat.Decompress(stream); + } + } + + if (Magic == "Yaz0") + { + if (data != null) + data = EveryFileExplorer.YAZ0.Decompress(data); + else + data = EveryFileExplorer.YAZ0.Decompress(FileName); + + return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, + CompressionType.Yaz0, DecompressedFileSize, CompressedFileSize); + } + if (Path.GetExtension(FileName) == ".cbtex") + { + fileReader.Position = 0; + byte compType = fileReader.ReadByte(); + if (compType == 0x50) + { + if (data == null) + data = File.ReadAllBytes(FileName); + + fileReader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; + + fileReader.Seek(4, System.IO.SeekOrigin.Begin); + uint decompSize = fileReader.ReadUInt32(); + uint compSize = (uint)fileReader.BaseStream.Length - 8; + + var comp = new STLibraryCompression.MTA_CUSTOM(); + data = comp.Decompress(data, decompSize); + + return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, + CompressionType.MarioTennisCustom, DecompressedFileSize, CompressedFileSize); + } + fileReader.Position = 0; + } + if (Path.GetExtension(FileName) == ".lz") { if (data == null) data = File.ReadAllBytes(FileName); - fileReader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; - - fileReader.Seek(4, System.IO.SeekOrigin.Begin); - uint decompSize = fileReader.ReadUInt32(); - uint compSize = (uint)fileReader.BaseStream.Length - 8; - - var comp = new STLibraryCompression.MTA_CUSTOM(); - data = comp.Decompress(data, decompSize); + data = LZ77_WII.Decompress(fileReader.getSection(16, data.Length - 16)); return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, - CompressionType.MarioTennisCustom, DecompressedFileSize, CompressedFileSize); + CompressionType.Yaz0, DecompressedFileSize, CompressedFileSize); + } + if (MagicHex == 0x28B52FFD || MagicHex == 0xFD2FB528) + { + if (data != null) + data = STLibraryCompression.ZSTD.Decompress(fileReader.getSection(0, data.Length)); + else + data = STLibraryCompression.ZSTD.Decompress(File.ReadAllBytes(FileName)); + + return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, + CompressionType.Zstb, DecompressedFileSize, CompressedFileSize); + } + if (Magic == "ZCMP" || MagicHex2 == 0x789C || MagicHex2 == 0x78DA || Path.GetExtension(FileName) == ".z" && CompType == CompressionType.None) + { + if (data == null) + data = File.ReadAllBytes(FileName); + + data = STLibraryCompression.ZLIB.Decompress(data); + return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, + CompressionType.Zlib, DecompressedFileSize, CompressedFileSize); + } + if (MagicHex3 == 0x789C || MagicHex3 == 0x78DA && CompType == CompressionType.None) + { + if (data == null) + data = File.ReadAllBytes(FileName); + + fileReader.Position = 0; + int OuSize = fileReader.ReadInt32(); + int InSize = data.Length - 4; + data = STLibraryCompression.ZLIB.Decompress(fileReader.getSection(4, InSize)); + return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, + CompressionType.Zlib, DecompressedFileSize, CompressedFileSize); + } + if (Path.GetExtension(FileName) == ".carc" && CompType == CompressionType.None) + { + if (data == null) + data = File.ReadAllBytes(FileName); + + data = STLibraryCompression.ZLIB.Decompress(fileReader.getSection(0x10, data.Length - 0x10)); + return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, + CompressionType.Zlib, DecompressedFileSize, CompressedFileSize); + } + if (Magic == "ZLIB") + { + if (data == null) + data = File.ReadAllBytes(FileName); + + data = STLibraryCompression.GZIP.Decompress(fileReader.getSection(64, data.Length - 64)); + return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, + CompressionType.Zlib, DecompressedFileSize, CompressedFileSize); + } + if (MagicHex == 0x1f8b0808 || MagicHex2 == 0x1f8b && CompType == CompressionType.None) + { + if (data == null) + data = File.ReadAllBytes(FileName); + + data = STLibraryCompression.GZIP.Decompress(data); + return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, + CompressionType.Gzip, DecompressedFileSize, CompressedFileSize); + } + if (MagicHex == 0x184D2204) + { + if (data == null) + data = File.ReadAllBytes(FileName); + + data = STLibraryCompression.Type_LZ4.Decompress(data); + return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, + CompressionType.Lz4, DecompressedFileSize, CompressedFileSize); + } + if (Path.GetExtension(FileName) == ".lz" && CompType == CompressionType.None) + { + if (data == null) + data = File.ReadAllBytes(FileName); + + data = STLibraryCompression.LZ77.Decompress(fileReader.getSection(16, data.Length - 16)); + return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, + CompressionType.Zlib, DecompressedFileSize, CompressedFileSize); + } + if (Path.GetExtension(FileName) == ".cmp" && CompType == CompressionType.None) + { + if (data == null) + data = File.ReadAllBytes(FileName); + + fileReader.Position = 0; + int OuSize = fileReader.ReadInt32(); + int InSize = data.Length - 4; + data = STLibraryCompression.Type_LZ4F.Decompress(fileReader.getSection(4, InSize)); + + return OpenFileFormat(FileName, data, InArchive, LeaveStreamOpen, archiveNode, true, + CompressionType.Lz4f, DecompressedFileSize, CompressedFileSize); } - fileReader.Position = 0; } - if (Path.GetExtension(FileName) == ".lz") - { - if (data == null) - data = File.ReadAllBytes(FileName); - - data = LZ77_WII.Decompress(fileReader.getSection(16, data.Length - 16)); - - return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, - CompressionType.Yaz0, DecompressedFileSize, CompressedFileSize); - } - if (MagicHex == 0x28B52FFD || MagicHex == 0xFD2FB528) - { - if (data != null) - data = STLibraryCompression.ZSTD.Decompress(fileReader.getSection(0, data.Length)); - else - data = STLibraryCompression.ZSTD.Decompress(File.ReadAllBytes(FileName)); - - return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, - CompressionType.Zstb, DecompressedFileSize, CompressedFileSize); - } - if (Magic == "ZCMP" || MagicHex2 == 0x789C || MagicHex2 == 0x78DA || Path.GetExtension(FileName) == ".z" && CompType == CompressionType.None) - { - if (data == null) - data = File.ReadAllBytes(FileName); - - data = STLibraryCompression.ZLIB.Decompress(data); - return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, - CompressionType.Zlib, DecompressedFileSize, CompressedFileSize); - } - if (MagicHex3 == 0x789C || MagicHex3 == 0x78DA && CompType == CompressionType.None) - { - if (data == null) - data = File.ReadAllBytes(FileName); - - fileReader.Position = 0; - int OuSize = fileReader.ReadInt32(); - int InSize = data.Length - 4; - data = STLibraryCompression.ZLIB.Decompress(fileReader.getSection(4, InSize)); - return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, - CompressionType.Zlib, DecompressedFileSize, CompressedFileSize); - } - if (Path.GetExtension(FileName) == ".carc" && CompType == CompressionType.None) - { - if (data == null) - data = File.ReadAllBytes(FileName); - - data = STLibraryCompression.ZLIB.Decompress(fileReader.getSection(0x10, data.Length - 0x10)); - return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, - CompressionType.Zlib, DecompressedFileSize, CompressedFileSize); - } - if (Magic == "ZLIB") - { - if (data == null) - data = File.ReadAllBytes(FileName); - - data = STLibraryCompression.GZIP.Decompress(fileReader.getSection(64, data.Length - 64)); - return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, - CompressionType.Zlib, DecompressedFileSize, CompressedFileSize); - } - if (MagicHex == 0x1f8b0808 || MagicHex2 == 0x1f8b && CompType == CompressionType.None) - { - if (data == null) - data = File.ReadAllBytes(FileName); - - data = STLibraryCompression.GZIP.Decompress(data); - return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, - CompressionType.Gzip, DecompressedFileSize, CompressedFileSize); - } - if (MagicHex == 0x184D2204) - { - if (data == null) - data = File.ReadAllBytes(FileName); - - data = STLibraryCompression.Type_LZ4.Decompress(data); - return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, - CompressionType.Lz4, DecompressedFileSize, CompressedFileSize); - } - if (Path.GetExtension(FileName) == ".lz" && CompType == CompressionType.None) - { - if (data == null) - data = File.ReadAllBytes(FileName); - - data = STLibraryCompression.LZ77.Decompress(fileReader.getSection(16, data.Length - 16)); - return OpenFileFormat(FileName, data, LeaveStreamOpen, InArchive, archiveNode, true, - CompressionType.Zlib, DecompressedFileSize, CompressedFileSize); - } - if (Path.GetExtension(FileName) == ".cmp" && CompType == CompressionType.None) - { - if (data == null) - data = File.ReadAllBytes(FileName); - - fileReader.Position = 0; - int OuSize = fileReader.ReadInt32(); - int InSize = data.Length - 4; - data = STLibraryCompression.Type_LZ4F.Decompress(fileReader.getSection(4, InSize)); - - return OpenFileFormat(FileName, data, InArchive, LeaveStreamOpen, archiveNode, true, - CompressionType.Lz4f, DecompressedFileSize, CompressedFileSize); - } - - fileReader.Close(); - fileReader.Dispose(); foreach (IFileFormat fileFormat in FileManager.GetFileFormats()) { diff --git a/Switch_Toolbox_Library/IO/SubStream.cs b/Switch_Toolbox_Library/IO/SubStream.cs index 56c57d3d..73dcdc87 100644 --- a/Switch_Toolbox_Library/IO/SubStream.cs +++ b/Switch_Toolbox_Library/IO/SubStream.cs @@ -27,6 +27,22 @@ namespace Toolbox.Library.IO this.length = length; baseOffset = offset; } + + public SubStream(Stream baseStream, long offset) + { + long length = baseStream.Length - offset; + + if (baseStream == null) throw new ArgumentNullException("baseStream"); + if (!baseStream.CanRead) throw new ArgumentException("baseStream.CanRead is false"); + if (!baseStream.CanSeek) throw new ArgumentException("baseStream.CanSeek is false"); + if (offset < 0) throw new ArgumentOutOfRangeException("offset"); + if (offset + length > baseStream.Length) throw new ArgumentOutOfRangeException("length"); + + this.baseStream = baseStream; + this.length = length; + baseOffset = offset; + } + public override int Read(byte[] buffer, int offset, int count) { baseStream.Position = baseOffset + offset + Position; diff --git a/Switch_Toolbox_Library/Toolbox.Library.dll b/Switch_Toolbox_Library/Toolbox.Library.dll index 85d7af79..0962c008 100644 Binary files a/Switch_Toolbox_Library/Toolbox.Library.dll and b/Switch_Toolbox_Library/Toolbox.Library.dll differ diff --git a/Switch_Toolbox_Library/Toolbox.Library.pdb b/Switch_Toolbox_Library/Toolbox.Library.pdb index e32bf3e4..5c2841cc 100644 Binary files a/Switch_Toolbox_Library/Toolbox.Library.pdb and b/Switch_Toolbox_Library/Toolbox.Library.pdb differ diff --git a/Switch_Toolbox_Library/Toolbox_Library.csproj b/Switch_Toolbox_Library/Toolbox_Library.csproj index f22f611c..75ac6a70 100644 --- a/Switch_Toolbox_Library/Toolbox_Library.csproj +++ b/Switch_Toolbox_Library/Toolbox_Library.csproj @@ -291,6 +291,7 @@ +