diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj index 155e2339..979c9b79 100644 --- a/ArcFormats/ArcFormats.csproj +++ b/ArcFormats/ArcFormats.csproj @@ -126,6 +126,7 @@ + WidgetDXA.xaml diff --git a/ArcFormats/DxLib/ArcDX8.cs b/ArcFormats/DxLib/ArcDX8.cs index d67651ea..6ceb9827 100644 --- a/ArcFormats/DxLib/ArcDX8.cs +++ b/ArcFormats/DxLib/ArcDX8.cs @@ -39,18 +39,10 @@ namespace GameRes.Formats.DxLib internal class DXA8PackedEntry : PackedEntry { public bool HuffmanCompressed { get; set; } + public uint HuffmanSize { get; set; } } - internal struct DXA8HuffmanNode - { - UInt64 Weight; - int bitNumber; - byte[] bitArray; //32 bytes here - int Index; - - int ParentNode; // index of parent node. - int[] ChildNode; //two children nodes, -1 if not existent. - } + [Export(typeof(ArchiveFormat))] public class Dx8Opener : DxOpener @@ -67,7 +59,7 @@ namespace GameRes.Formats.DxLib Signatures = new[] { 0x00085844u }; } - static readonly byte[] DefaultKey = new byte[] { 0xBE, 0xC8, 0x8A, 0xF5, 0x28, 0x50, 0xC9 }; + //static readonly byte[] DefaultKey = new byte[] { 0xBE, 0xC8, 0x8A, 0xF5, 0x28, 0x50, 0xC9 }; DxScheme DefaultScheme = new DxScheme { KnownKeys = new List() }; @@ -100,11 +92,8 @@ namespace GameRes.Formats.DxLib }; } - string QueryPassword(ArcView file) - { - var options = Query(arcStrings.ZIPEncryptedNotice); - return options.Keyword; - } + + public override ResourceOptions GetOptions(object widget) { @@ -191,11 +180,13 @@ namespace GameRes.Formats.DxLib DxDirectory ReadDirEntry() { - var dir = new DxDirectory(); - dir.DirOffset = m_input.ReadInt64(); - dir.ParentDirOffset = m_input.ReadInt64(); - dir.FileCount = (int)m_input.ReadInt64(); - dir.FileTable = m_input.ReadInt64(); + var dir = new DxDirectory + { + DirOffset = m_input.ReadInt64(), + ParentDirOffset = m_input.ReadInt64(), + FileCount = (int)m_input.ReadInt64(), + FileTable = m_input.ReadInt64() + }; return dir; } @@ -232,6 +223,7 @@ namespace GameRes.Formats.DxLib entry.UnpackedSize = (uint)size; entry.IsPacked = -1 != packed_size; entry.HuffmanCompressed = -1 != huffman_packed_size; + entry.HuffmanSize = (uint)huffman_packed_size; if (entry.IsPacked) entry.Size = (uint)(huffman_packed_size!=-1 ? huffman_packed_size:packed_size); else diff --git a/ArcFormats/DxLib/HuffmanDecoder.cs b/ArcFormats/DxLib/HuffmanDecoder.cs new file mode 100644 index 00000000..5a4a9cdc --- /dev/null +++ b/ArcFormats/DxLib/HuffmanDecoder.cs @@ -0,0 +1,195 @@ +//! \file HuffmanDecoder.cs +//! \date 2024 Aug 2 +//! \brief Custom Huffman decoder for DXA archives. +// +// Copyright (C) 2017 by morkt - GetBits function +// Copyright (C) 2024 by MrSoup678 +// +// 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. +// + + +using System; +using System.IO; +using System.Runtime.CompilerServices; +using GameRes.Utility; + +namespace GameRes.Formats.DxLib +{ + internal struct DXA8HuffmanNode + { + public UInt64 Weight; + public int bitNumber; + public byte[] bitArray; //32 bytes here + public int Index; + + public int ParentNode; // index of parent node. + public int[] ChildNode; //two children nodes, -1 if not existent. + } + + internal sealed class HuffmanDecoder + { + byte[] m_input; + byte[] m_output; + + int m_src; + ulong m_bits; + int m_bit_count; + + ulong m_readBytes; + ulong m_readBits; + + + DXA8HuffmanNode[] nodes; //256+255 nodes + + ulong originalSize; + ulong compressedSize; + ulong headerSize; + + //ushort token = 256; + + public HuffmanDecoder (byte[] src, byte[] dst) + { + m_input = src; + m_output = dst; + + m_src = 0; + m_bit_count = 0; + m_readBytes = 0; + m_readBits = 0; + originalSize = compressedSize = headerSize = 0; + ushort[] weights = new ushort[256]; + nodes = new DXA8HuffmanNode[256+255]; //256 "base" nodes, then 255 nodes making a pyramid. + } + + public byte[] Unpack () + { + + for (int i=0; i 1) + { + int MinNode1 = -1; + int MinNode2 = -1; + int NodeIndex = 0; + + + for (int i = 0; i < DataNum; NodeIndex++) { + //don't do anything if we already have a parent set. + if (nodes[NodeIndex].ParentNode != -1) continue; + i++; + //we need to get the two lowest numbers for parenting. + if (MinNode1 == -1 || nodes[MinNode1].Weight > nodes[NodeIndex].Weight) + { + { + MinNode2 = MinNode1; + MinNode1 = NodeIndex; + } + } else if (MinNode2 == -1 || nodes[MinNode2].Weight > nodes[NodeIndex].Weight) + { + MinNode2 = NodeIndex; + } + } + nodes[NodeNum].ParentNode = -1; + nodes[NodeNum].Weight = nodes[MinNode1].Weight + nodes[MinNode2].Weight; + nodes[NodeNum].ChildNode[0] = MinNode1; + nodes[NodeNum].ChildNode[1] = MinNode2; + nodes[MinNode1].Index = 0; + nodes[MinNode2].Index = 1; + nodes[MinNode1].ParentNode = NodeNum; + nodes[MinNode2].ParentNode = NodeNum; + + NodeNum++; + DataNum--; + } + } + + ulong GetBits (int count) + { + ulong bits = 0; + while (count --> 0) + { + if (0 == m_bit_count) + { + m_bits = LittleEndian.ToUInt64 (m_input, m_src); + m_src += 8; + m_bit_count = 64; + } + bits = bits << 1 | (m_bits & 1); + m_bits >>= 1; + --m_bit_count; + m_readBits++; + if (m_readBits ==8) + { + m_readBits = 0; + m_readBytes++; + } + } + return bits; + } + + ulong GetReadBytes() + { + return m_readBytes + (m_readBits != 0 ? 1ul : 0ul); + } + } +}