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 @@
+