diff --git a/BrawlboxHelper/BrawlboxHelper.dll b/BrawlboxHelper/BrawlboxHelper.dll index 8564fa74..b781a8af 100644 Binary files a/BrawlboxHelper/BrawlboxHelper.dll and b/BrawlboxHelper/BrawlboxHelper.dll differ diff --git a/File_Format_Library/FileFormats/Archives/U8.cs b/File_Format_Library/FileFormats/Archives/U8.cs index 6973b5a3..88241575 100644 --- a/File_Format_Library/FileFormats/Archives/U8.cs +++ b/File_Format_Library/FileFormats/Archives/U8.cs @@ -7,6 +7,7 @@ using Toolbox; using System.Windows.Forms; using Toolbox.Library; using Toolbox.Library.IO; +using System.IO; namespace FirstPlugin { @@ -16,7 +17,7 @@ namespace FirstPlugin public bool CanSave { get; set; } public string[] Description { get; set; } = new string[] { "U8" }; - public string[] Extension { get; set; } = new string[] { "*.u8"}; + public string[] Extension { get; set; } = new string[] { "*.u8", "*.arc", "*.cmparc"}; public string FileName { get; set; } public string FilePath { get; set; } public IFileInfo IFileInfo { get; set; } @@ -28,14 +29,30 @@ namespace FirstPlugin private readonly uint BEMagic = 0x55AA382D; private readonly uint LEMagic = 0x2D38AA55; + private int LZType = 0x0, LZSize = 0; - public bool Identify(System.IO.Stream stream) + public bool Identify(Stream stream) { - using (var reader = new Toolbox.Library.IO.FileReader(stream, true)) + using (var reader = new FileReader(stream, true)) { reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; + byte LZCheck = reader.ReadByte(); + if (LZCheck == 0x11 || LZCheck == 0x10) + { + LZType = LZCheck; + + // For the Wii's U8 ARC files compressed with LZ77 Type 10 or Type 11, the decompiled file size is written in little endian. + reader.ByteOrder = Syroot.BinaryData.ByteOrder.LittleEndian; + LZSize = reader.ReadInt32(); + reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; + } + else + { + reader.Position = 0; + } uint signature = reader.ReadUInt32(); + reader.Position = 0; return signature == BEMagic || signature == LEMagic; } @@ -65,9 +82,25 @@ namespace FirstPlugin private bool IsBigEndian = false; - public void Load(System.IO.Stream stream) + public void Load(Stream stream) { - using (var reader = new FileReader(stream)) + SubStream sub; + if (LZType == 0x11 || LZType == 0x10) + { + sub = new SubStream(stream, 4); + } + else + { + sub = null; + } + + Stream dataStream = + LZType == 0x11 ? new MemoryStream(LZ77_WII.Decompress11(sub.ToArray(), LZSize)) : + LZType == 0x10 ? new MemoryStream(LZ77_WII.Decompress10LZ(sub.ToArray(), LZSize)) : stream; + + dataStream.Position = 0; + + using (var reader = new FileReader(dataStream)) { reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; diff --git a/File_Format_Library/FileFormats/Font/BXFNT/BXFNT.cs b/File_Format_Library/FileFormats/Font/BXFNT/BXFNT.cs index 4ef11d2e..79fa405e 100644 --- a/File_Format_Library/FileFormats/Font/BXFNT/BXFNT.cs +++ b/File_Format_Library/FileFormats/Font/BXFNT/BXFNT.cs @@ -20,8 +20,8 @@ namespace FirstPlugin public FileType FileType { get; set; } = FileType.Font; public bool CanSave { get; set; } - public string[] Description { get; set; } = new string[] { "Cafe Font", "CTR Font", "Revolution Font" }; - public string[] Extension { get; set; } = new string[] { "*.bffnt", "*.bcfnt", "*.brfnt", }; + public string[] Description { get; set; } = new string[] { "Cafe Font", "CTR Font", "Revolution Font", "Revolution Archived Font" }; + public string[] Extension { get; set; } = new string[] { "*.bffnt", "*.bcfnt", "*.brfnt", "*.brfna" }; public string FileName { get; set; } public string FilePath { get; set; } public IFileInfo IFileInfo { get; set; } @@ -33,7 +33,8 @@ namespace FirstPlugin return reader.CheckSignature(4, "FFNT") || reader.CheckSignature(4, "CFNT") || reader.CheckSignature(4, "RFNT") || - reader.CheckSignature(4, "TNFR"); + reader.CheckSignature(4, "TNFR") || + reader.CheckSignature(4, "RFNA"); } } @@ -101,7 +102,8 @@ namespace FirstPlugin } else if (bffnt.Platform == FFNT.PlatformType.Cafe) { - for (int s = 0; s < tglp.SheetDataList.Count; s++) { + for (int s = 0; s < tglp.SheetDataList.Count; s++) + { var surface = new Gx2ImageBlock(); surface.Text = $"Sheet_{s}"; surface.Load(tglp, s); @@ -206,6 +208,7 @@ namespace FirstPlugin public ushort HeaderSize; public uint Version { get; set; } + public GLGR GlyphGroup { get; set; } public FINF FontSection { get; set; } public FontKerningTable KerningTable { get; set; } @@ -226,7 +229,7 @@ namespace FirstPlugin reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian; Signature = reader.ReadString(4, Encoding.ASCII); - if (Signature != "FFNT" && Signature != "CFNT" && Signature != "RFNT" && Signature != "TNFR") + if (Signature != "FFNT" && Signature != "CFNT" && Signature != "RFNT" && Signature != "TNFR" && Signature != "RFNA") throw new Exception($"Invalid signature {Signature}! Expected FFNT or CFNT or RFNT."); BOM = reader.ReadUInt16(); @@ -237,7 +240,8 @@ namespace FirstPlugin //Parse header first and check the version //Brfnt uses a slightly different header structure - if (Signature == "RFNT" || Signature == "TNFR") { + if (Signature == "RFNT" || Signature == "TNFR" || Signature == "RFNA") + { Version = reader.ReadUInt16(); uint FileSize = reader.ReadUInt32(); HeaderSize = reader.ReadUInt16(); @@ -265,13 +269,24 @@ namespace FirstPlugin if (Signature == "CFNT") Platform = PlatformType.Ctr; - if (Signature == "RFNT" || Signature == "TNFR") + if (Signature == "RFNT" || Signature == "TNFR" || Signature == "RFNA") Platform = PlatformType.Wii; Console.WriteLine($"Platform {Platform}"); reader.Seek(HeaderSize, SeekOrigin.Begin); + if (Signature == "RFNA") + { + GlyphGroup = new GLGR(); + GlyphGroup.Read(reader); + // It's needed to take off 22 because of the included header length in SectionSize. + reader.Seek(GlyphGroup.SectionSize - 0x16, SeekOrigin.Current); + } FontSection = new FINF(); + if (GlyphGroup != null) + { + FontSection.GlyphGroup = GlyphGroup; + } FontSection.Read(reader, this); //Check for any unread blocks @@ -347,7 +362,8 @@ namespace FirstPlugin writer.SeekBegin(HeaderSize); FontSection.Write(writer, this); - if (KerningTable != null) { + if (KerningTable != null) + { BlockCounter++; KerningTable.Write(writer, this); } @@ -392,33 +408,33 @@ namespace FirstPlugin float YScale = (fontHeight / TextureGlyph.CellWidth); float height = (TextureGlyph.SheetHeight - 2) / TextureGlyph.ColumnCount; - /* int pos = 0; - for (int i = 0; i < text.Length; i++) - { - char character = text[i]; + /* int pos = 0; + for (int i = 0; i < text.Length; i++) + { + char character = text[i]; - int charWidth = (int)FontInfo.DefaultCharWidth; - int glyphWidth = (int)FontInfo.DefaultGlyphWidth; - int leftWidth = (int)FontInfo.DefaultLeftWidth; + int charWidth = (int)FontInfo.DefaultCharWidth; + int glyphWidth = (int)FontInfo.DefaultGlyphWidth; + int leftWidth = (int)FontInfo.DefaultLeftWidth; - if (FontInfo.CodeMapDictionary.ContainsKey(character)) - { - var idx = FontInfo.CodeMapDictionary[character]; - if (idx == 0xFFFF) continue; - var charWidthInfo = GetCharWidthInfoByIndex(FontInfo, (ushort)idx); + if (FontInfo.CodeMapDictionary.ContainsKey(character)) + { + var idx = FontInfo.CodeMapDictionary[character]; + if (idx == 0xFFFF) continue; + var charWidthInfo = GetCharWidthInfoByIndex(FontInfo, (ushort)idx); - charWidth = charWidthInfo.CharWidth; - glyphWidth = charWidthInfo.GlyphWidth; - leftWidth = charWidthInfo.Left; - } + charWidth = charWidthInfo.CharWidth; + glyphWidth = charWidthInfo.GlyphWidth; + leftWidth = charWidthInfo.Left; + } - /* Bitmap b = new Bitmap(width, height); - using (Graphics g = Graphics.FromImage(b)) - { - g.DrawImage(); - } - }*/ + /* Bitmap b = new Bitmap(width, height); + using (Graphics g = Graphics.FromImage(b)) + { + g.DrawImage(); + } + }*/ if (bitmapFont == null) bitmapFont = GetBitmapFont(true); diff --git a/File_Format_Library/FileFormats/Font/BXFNT/FINF.cs b/File_Format_Library/FileFormats/Font/BXFNT/FINF.cs index 638d044c..3e2bb3f4 100644 --- a/File_Format_Library/FileFormats/Font/BXFNT/FINF.cs +++ b/File_Format_Library/FileFormats/Font/BXFNT/FINF.cs @@ -23,6 +23,7 @@ namespace FirstPlugin public byte DefaultGlyphWidth { get; set; } public byte DefaultCharWidth { get; set; } public CharacterCode CharEncoding { get; set; } + public GLGR GlyphGroup; public TGLP TextureGlyph; public CMAP CodeMap; public CWDH CharacterWidth; diff --git a/File_Format_Library/FileFormats/Font/BXFNT/GLGR.cs b/File_Format_Library/FileFormats/Font/BXFNT/GLGR.cs new file mode 100644 index 00000000..2d636509 --- /dev/null +++ b/File_Format_Library/FileFormats/Font/BXFNT/GLGR.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox.Library.IO; + +namespace FirstPlugin +{ + public class GLGR + { + public uint SectionSize; + public uint SheetSize; + public uint HeaderSize = 0x20; + public ushort GlyphsPerSheet; + public ushort SetCount; + public ushort SheetCount; + public ushort CWDHCount; + public ushort CMAPCount; + + public void Read(FileReader reader) + { + string Signature = reader.ReadString(4, Encoding.ASCII); + if (Signature != "GLGR") + { + throw new Exception($"Invalid signature {Signature}! Expected GLGR."); + } + SectionSize = reader.ReadUInt32(); + SheetSize = reader.ReadUInt32(); + GlyphsPerSheet = reader.ReadUInt16(); + SetCount = reader.ReadUInt16(); + SheetCount = reader.ReadUInt16(); + CWDHCount = reader.ReadUInt16(); + CMAPCount = reader.ReadUInt16(); + } + } +} diff --git a/File_Format_Library/FileFormats/Font/BXFNT/TGLP.cs b/File_Format_Library/FileFormats/Font/BXFNT/TGLP.cs index 68031eb4..1cce4c61 100644 --- a/File_Format_Library/FileFormats/Font/BXFNT/TGLP.cs +++ b/File_Format_Library/FileFormats/Font/BXFNT/TGLP.cs @@ -32,7 +32,7 @@ namespace FirstPlugin public byte CellWidth { get; set; } public byte CellHeight { get; set; } public byte MaxCharWidth { get; set; } - public byte SheetCount { get; private set; } + public ushort SheetCount { get; private set; } public uint SheetSize { get; set; } public ushort BaseLinePos { get; set; } public ushort Format { get; set; } @@ -53,7 +53,16 @@ namespace FirstPlugin BaseLinePos = reader.ReadByte(); MaxCharWidth = reader.ReadByte(); SheetSize = reader.ReadUInt32(); - SheetCount = (byte)reader.ReadUInt16(); + SheetCount = reader.ReadUInt16(); + if (header.Signature == "RFNA") + { + reader.ReadByte(); // No clue what the value is for + Format = reader.ReadByte(); + } + else + { + Format = reader.ReadUInt16(); + } } else { @@ -61,9 +70,9 @@ namespace FirstPlugin MaxCharWidth = reader.ReadByte(); SheetSize = reader.ReadUInt32(); BaseLinePos = reader.ReadUInt16(); + Format = reader.ReadUInt16(); } - Format = reader.ReadUInt16(); RowCount = reader.ReadUInt16(); ColumnCount = reader.ReadUInt16(); SheetWidth = reader.ReadUInt16(); @@ -74,7 +83,18 @@ namespace FirstPlugin { for (int i = 0; i < SheetCount; i++) { - SheetDataList.Add(reader.ReadBytes((int)SheetSize)); + byte[] decompedData; + uint compSheetSize = 0; + if (header.Signature == "RFNA") // .brfna files have their texture sheets compressed with Huffman. + { + compSheetSize = reader.ReadUInt32(); + decompedData = Huffman_WII.DecompressHuffman(reader.ReadBytes((int)compSheetSize), (int)SheetSize); + } + else + { + decompedData = reader.ReadBytes((int)SheetSize); + } + SheetDataList.Add(decompedData); if (SheetDataList[i].Length != SheetSize) throw new Exception("SheetSize mis match!"); } diff --git a/File_Format_Library/File_Format_Library.csproj b/File_Format_Library/File_Format_Library.csproj index e910a088..7db508d7 100644 --- a/File_Format_Library/File_Format_Library.csproj +++ b/File_Format_Library/File_Format_Library.csproj @@ -273,6 +273,7 @@ + diff --git a/Switch_Toolbox_Library/Compression/Huffman_WII.cs b/Switch_Toolbox_Library/Compression/Huffman_WII.cs new file mode 100644 index 00000000..b7cfbe32 --- /dev/null +++ b/Switch_Toolbox_Library/Compression/Huffman_WII.cs @@ -0,0 +1,260 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Toolbox.Library.IO; + +namespace Toolbox.Library +{ + public class Huffman_WII + { + //Ported from + //https://github.com/Barubary/dsdecmp/blob/4ddd87206bacf4ce7d803b40ff3bd2663327b083/CSharp/DSDecmp/Program.cs#L417 + //(Modified to use byte arrays instead of file paths) + //Copyright (c) 2010 Nick Kraayenbrink + // + //Permission is hereby granted, free of charge, to any person obtaining a copy + //of this software and associated documentation files (the "Software"), to deal + //in the Software without restriction, including without limitation the rights + //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + //copies of the Software, and to permit persons to whom the Software is + //furnished to do so, subject to the following conditions: + // + //The above copyright notice and this permission notice shall be included in + //all copies or substantial portions of the Software. + // + //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + //THE SOFTWARE. + public static byte[] DecompressHuffman(byte[] input, int decompSize) + { + + FileReader br = new FileReader(new MemoryStream(input), true); + + byte firstByte = br.ReadByte(); + + int dataSize = firstByte & 0x0F; + + if ((firstByte & 0xF0) != 0x20) + throw new InvalidDataException(String.Format("Invalid huffman comressed file; invalid tag {0:x}", firstByte)); + + //Console.WriteLine("Data size: {0:x}", dataSize); + if (dataSize != 8 && dataSize != 4) + throw new InvalidDataException(String.Format("Unhandled dataSize {0:x}", dataSize)); + + int decomp_size = 0; + for (int i = 0; i < 3; i++) + { + decomp_size |= br.ReadByte() << (i * 8); + } + + byte treeSize = br.ReadByte(); + HuffTreeNode.maxInpos = 4 + (treeSize + 1) * 2; + + Console.WriteLine("Tree Size: {0:x}", treeSize); + Console.WriteLine("Tee end: 0x{0:X}", HuffTreeNode.maxInpos); + + HuffTreeNode rootNode = new HuffTreeNode(); + rootNode.parseData(br); + + br.BaseStream.Position = 4 + (treeSize + 1) * 2; // go to start of coded bitstream. + // read all data + uint[] indata = new uint[(br.BaseStream.Length - br.BaseStream.Position) / 4]; + for (int i = 0; i < indata.Length; i++) + indata[i] = br.ReadUInt32(); + + long curr_size = 0; + decomp_size *= dataSize == 8 ? 1 : 2; + byte[] outdata = new byte[decomp_size]; + + int idx = -1; + string codestr = ""; + LinkedList code = new LinkedList(); + int value; + + // Overwriting the likely nonsense read with the proper intended texture size. + decomp_size = decompSize; + + while (curr_size < decomp_size) + { + try + { + string newstr = uint_to_bits(indata[++idx]); + codestr += newstr; + Console.WriteLine("next uint: " + newstr); + } + catch (IndexOutOfRangeException e) + { + throw new IndexOutOfRangeException("not enough data.", e); + } + while (codestr.Length > 0 && curr_size < decompSize) // Need to force stop at the max decompSize, otherwise we get IndexOutOfRange Exceptions. + { + code.AddFirst(byte.Parse(codestr[0] + "")); + //Console.Write(code.First.Value); + codestr = codestr.Remove(0, 1); + if (rootNode.getValue(code.Last, out value)) + { + //Console.WriteLine(" -> "+value.ToString("X")); + try + { + outdata[curr_size++] = (byte)value; + } + catch (IndexOutOfRangeException ex) + { + if (code.First.Value != 0) + throw ex; + } + code.Clear(); + } + } + } + + br.Close(); + + byte[] realout; + if (dataSize == 4) + { + realout = new byte[decomp_size / 2]; + for (int i = 0; i < decomp_size / 2; i++) + { + if ((outdata[i * 2] & 0xF0) > 0 + || (outdata[i * 2 + 1] & 0xF0) > 0) + throw new Exception("first 4 bits of data should be 0 if dataSize = 4"); + realout[i] = (byte)((outdata[i * 2] << 4) | outdata[i * 2 + 1]); + } + } + else + { + realout = outdata; + } + Console.WriteLine("Huffman decompressed."); + return realout; + } + + private static string byte_to_bits(byte b) + { + string o = ""; + for (int i = 0; i < 8; i++) + o = (((b & (1 << i)) >> i) & 1) + o; + return o; + } + private static string uint_to_bits(uint u) + { + string o = ""; + for (int i = 3; i > -1; i--) + o += byte_to_bits((byte)((u & (0xFF << (i * 8))) >> (i * 8))); + return o; + } + } + + //Ported from + //https://github.com/Barubary/dsdecmp/blob/4ddd87206bacf4ce7d803b40ff3bd2663327b083/CSharp/DSDecmp/Program.cs#L1367 + class HuffTreeNode + { + internal static int maxInpos = 0; + internal HuffTreeNode node0, node1; + internal int data = -1; // [-1,0xFF] + /// + /// To get a value, provide the last node of a list of bytes < 2. + /// the list will be read from back to front. + /// + internal bool getValue(LinkedListNode code, out int value) + { + value = data; + if (code == null) + return node0 == null && node1 == null && data >= 0; + + if (code.Value > 1) + throw new Exception(String.Format("the list should be a list of bytes < 2. got:{0:g}", code.Value)); + + byte c = code.Value; + bool retVal; + HuffTreeNode n = c == 0 ? node0 : node1; + retVal = n != null && n.getValue(code.Previous, out value); + return retVal; + } + + internal int this[string code] + { + get + { + LinkedList c = new LinkedList(); + foreach (char ch in code) + c.AddFirst((byte)ch); + int val = 1; + return this.getValue(c.Last, out val) ? val : -1; + } + } + + internal void parseData(BinaryReader br) + { + /* + * Tree Table (list of 8bit nodes, starting with the root node) + Root Node and Non-Data-Child Nodes are: + Bit0-5 Offset to next child node, + Next child node0 is at (CurrentAddr AND NOT 1)+Offset*2+2 + Next child node1 is at (CurrentAddr AND NOT 1)+Offset*2+2+1 + Bit6 Node1 End Flag (1=Next child node is data) + Bit7 Node0 End Flag (1=Next child node is data) + Data nodes are (when End Flag was set in parent node): + Bit0-7 Data (upper bits should be zero if Data Size is less than 8) + */ + this.node0 = new HuffTreeNode(); + this.node1 = new HuffTreeNode(); + long currPos = br.BaseStream.Position; + byte b = br.ReadByte(); + long offset = b & 0x3F; + bool end0 = (b & 0x80) > 0, end1 = (b & 0x40) > 0; + + // parse data for node0 + br.BaseStream.Position = (currPos - (currPos & 1)) + offset * 2 + 2; + if (br.BaseStream.Position < maxInpos) + { + if (end0) + node0.data = br.ReadByte(); + else + node0.parseData(br); + } + + // parse data for node1 + br.BaseStream.Position = (currPos - (currPos & 1)) + offset * 2 + 2 + 1; + if (br.BaseStream.Position < maxInpos) + { + if (end1) + node1.data = br.ReadByte(); + else + node1.parseData(br); + } + + // reset position + br.BaseStream.Position = currPos; + } + + public override string ToString() + { + if (data < 0 && node0 != null && node1 != null) + return "<" + node0.ToString() + ", " + node1.ToString() + ">"; + else + return String.Format("[{0:x}]", data); + } + + internal int Depth + { + get + { + if (data < 0) + return 0; + else + return 1 + Math.Max(node0.Depth, node1.Depth); + } + } + } +} diff --git a/Switch_Toolbox_Library/Compression/LZ77_WII.cs b/Switch_Toolbox_Library/Compression/LZ77_WII.cs index 803bb2c1..8588bb9c 100644 --- a/Switch_Toolbox_Library/Compression/LZ77_WII.cs +++ b/Switch_Toolbox_Library/Compression/LZ77_WII.cs @@ -140,6 +140,64 @@ namespace Toolbox.Library return outdata; } + //Ported from + //https://github.com/Barubary/dsdecmp/blob/master/Java/JavaDSDecmp.java#L27 + //Rewrote to C# + public static byte[] Decompress10LZ(byte[] in_data, int decomp_size) + { + byte[] out_data = new byte[decomp_size]; + int curr_size = 0, flags, disp, n, b, cdest; + bool flag; + + var reader = new FileReader(new MemoryStream(in_data), true); + + while (curr_size < decomp_size) + { + try { flags = reader.ReadByte(); } + catch (EndOfStreamException ex) { throw ex; } + for (int i = 0; i < 8; i++) + { + flag = (flags & (0x80 >> i)) > 0; + if (flag) + { + disp = 0; + try { b = reader.ReadByte(); } + catch (EndOfStreamException ex) { throw new InvalidDataException("Incomplete data", ex); } + n = b >> 4; + disp = (b & 0x0F) << 8; + try { disp |= reader.ReadByte(); } + catch (EndOfStreamException ex) { throw new InvalidDataException("Incomplete data", ex); } + n += 3; + cdest = curr_size; + Console.WriteLine(string.Format("disp: 0x{0:x}", disp)); + if (disp > curr_size) { throw new InvalidDataException("Cannot go back more than already written"); } + for (int j = 0; j < n; j++) + { + out_data[curr_size++] = out_data[cdest - disp - 1 + j]; + } + if (curr_size > decomp_size) break; + } + else + { + try { b = reader.ReadByte(); } + catch(EndOfStreamException ex) + { + Console.Error.WriteLine("Incomplete data, " + ex); + break; + } + try { out_data[curr_size++] = (byte)b; } + catch(IndexOutOfRangeException ex) + { if (b == 0) + { + break; + } + } + } + } + } + return out_data; + } + public static byte[] Decompress(byte[] input, bool useMagic = true) { diff --git a/Switch_Toolbox_Library/Toolbox_Library.csproj b/Switch_Toolbox_Library/Toolbox_Library.csproj index 11825169..2a6501d5 100644 --- a/Switch_Toolbox_Library/Toolbox_Library.csproj +++ b/Switch_Toolbox_Library/Toolbox_Library.csproj @@ -231,6 +231,7 @@ +