diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj
index 0057045d..979c9b79 100644
--- a/ArcFormats/ArcFormats.csproj
+++ b/ArcFormats/ArcFormats.csproj
@@ -126,6 +126,10 @@
+
+
+ WidgetDXA.xaml
+
@@ -1140,6 +1144,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
diff --git a/ArcFormats/DxLib/ArcDX.cs b/ArcFormats/DxLib/ArcDX.cs
index 12a9e263..8f25ae26 100644
--- a/ArcFormats/DxLib/ArcDX.cs
+++ b/ArcFormats/DxLib/ArcDX.cs
@@ -198,7 +198,7 @@ namespace GameRes.Formats.DxLib
}
}
- byte[] Unpack (Stream stream)
+ protected byte[] Unpack (Stream stream)
{
using (var input = new ArcView.Reader (stream))
{
@@ -262,7 +262,7 @@ namespace GameRes.Formats.DxLib
}
}
- List ReadIndex (ArcView file, int version, byte[] key)
+ protected List ReadIndex (ArcView file, int version, byte[] key)
{
DxHeader dx = null;
if (version <= 4)
@@ -271,7 +271,7 @@ namespace GameRes.Formats.DxLib
dx = ReadArcHeaderV6 (file, version, key);
if (null == dx || dx.DirTable >= dx.IndexSize || dx.FileTable >= dx.IndexSize)
return null;
- using (var encrypted = file.CreateStream (dx.IndexOffset, dx.IndexSize))
+ using (var encrypted = file.CreateStream (dx.IndexOffset, (uint)dx.IndexSize))
using (var index = new EncryptedStream (encrypted, version >= 6 ? 0 : dx.IndexOffset, key))
using (var reader = IndexReader.Create (dx, version, index))
{
@@ -305,21 +305,23 @@ namespace GameRes.Formats.DxLib
IndexSize = LittleEndian.ToUInt32 (header, 0),
BaseOffset = LittleEndian.ToInt64 (header, 4),
IndexOffset = LittleEndian.ToInt64 (header, 0x0C),
- FileTable = (uint)LittleEndian.ToInt64 (header, 0x14),
- DirTable = (uint)LittleEndian.ToInt64 (header, 0x1C),
+ FileTable = LittleEndian.ToInt64 (header, 0x14),
+ DirTable = LittleEndian.ToInt64 (header, 0x1C),
CodePage = LittleEndian.ToInt32 (header, 0x24),
};
}
internal static void Decrypt (byte[] data, int index, int count, long offset, byte[] key)
{
- int key_pos = (int)(offset % key.Length);
- for (int i = 0; i < count; ++i)
- {
- data[index+i] ^= key[key_pos++];
- if (key.Length == key_pos)
- key_pos = 0;
- }
+ if (key.Length == 0)
+ return;
+ int key_pos = (int)(offset % key.Length);
+ for (int i = 0; i < count; ++i)
+ {
+ data[index + i] ^= key[key_pos++];
+ if (key.Length == key_pos)
+ key_pos = 0;
+ }
}
public override ResourceScheme Scheme
@@ -333,9 +335,9 @@ namespace GameRes.Formats.DxLib
{
public long BaseOffset;
public long IndexOffset;
- public uint IndexSize;
- public uint FileTable;
- public uint DirTable;
+ public long IndexSize;
+ public long FileTable;
+ public long DirTable;
public int CodePage;
}
@@ -361,8 +363,10 @@ namespace GameRes.Formats.DxLib
{
if (version <= 4)
return new IndexReaderV2 (header, version, input);
- else if (version >= 6)
+ else if (version >= 6 && version < 8)
return new IndexReaderV6 (header, version, input);
+ else if (version >=8)
+ return new IndexReaderV8 (header, version, input);
else
throw new InvalidFormatException ("Not supported DX archive version.");
}
@@ -545,7 +549,7 @@ namespace GameRes.Formats.DxLib
: base (stream, leave_open)
{
m_key = key;
- m_base_pos = (int)(base_position % m_key.Length);
+ m_base_pos = m_key.Length !=0 ?(int)(base_position % m_key.Length):0;
}
public override int Read (byte[] buffer, int offset, int count)
@@ -559,32 +563,48 @@ namespace GameRes.Formats.DxLib
public override int ReadByte ()
{
- int key_pos = (int)((m_base_pos + Position) % m_key.Length);
int b = BaseStream.ReadByte();
- if (-1 != b)
+ if (m_key.Length !=0)
{
- b ^= m_key[key_pos];
+ int key_pos = (int)((m_base_pos + Position) % m_key.Length);
+ if (-1 != b)
+ {
+ b ^= m_key[key_pos];
+ }
}
return b;
}
public override void Write (byte[] buffer, int offset, int count)
{
- int key_pos = (int)((m_base_pos + Position) % m_key.Length);
+
byte[] write_buf = new byte[count];
- for (int i = 0; i < count; ++i)
+ if (m_key.Length != 0)
{
- write_buf[i] = (byte)(buffer[offset+i] ^ m_key[key_pos++]);
- if (m_key.Length == key_pos)
- key_pos = 0;
+ int key_pos = (int)((m_base_pos + Position) % m_key.Length);
+ for (int i = 0; i < count; ++i)
+ {
+ write_buf[i] = (byte)(buffer[offset + i] ^ m_key[key_pos++]);
+ if (m_key.Length == key_pos)
+ key_pos = 0;
+ }
+ } else
+ {
+ write_buf = buffer;
}
BaseStream.Write (write_buf, 0, count);
}
public override void WriteByte (byte value)
{
- int key_pos = (int)((m_base_pos + Position) % m_key.Length);
- BaseStream.WriteByte ((byte)(value ^ m_key[key_pos]));
+ if(m_key.Length != 0)
+ {
+ int key_pos = (int)((m_base_pos + Position) % m_key.Length);
+ BaseStream.WriteByte((byte)(value ^ m_key[key_pos]));
+ } else
+ {
+ BaseStream.WriteByte ((byte)value);
+ }
}
}
}
diff --git a/ArcFormats/DxLib/ArcDX8.cs b/ArcFormats/DxLib/ArcDX8.cs
index edc05b80..8daf5bfd 100644
--- a/ArcFormats/DxLib/ArcDX8.cs
+++ b/ArcFormats/DxLib/ArcDX8.cs
@@ -23,13 +23,47 @@
// IN THE SOFTWARE.
//
+using GameRes.Formats.Strings;
using System;
+using System.CodeDom;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
+using System.Linq;
+using System.Runtime.Remoting.Messaging;
+using System.Windows.Navigation;
+using static GameRes.Formats.DxLib.Dx8Opener;
+
+
+
namespace GameRes.Formats.DxLib
{
+
+ internal class DXA8PackedEntry : PackedEntry {
+ public bool HuffmanCompressed { get; set; }
+ public uint HuffmanSize { get; set; }
+
+ public uint LZSize { get; set; }
+ }
+
+ internal class DxArchive8 : DxArchive
+ {
+ public byte huffmanMaxKB;
+
+ public DxArchive8(ArcView arc, ArchiveFormat impl, ICollection dir, IDxKey enc, int version,byte huffmanKB) : base(arc, impl, dir, enc, version)
+ {
+ huffmanMaxKB = huffmanKB;
+ }
+ }
+
+ internal class DxHeaderV8 : DxHeader
+ {
+ public DXA8Flags Flags;
+ public byte HuffmanKB; // oddly used only in Compression process not in decompression.
+ //15 bytes of padding.
+ }
+
[Export(typeof(ArchiveFormat))]
public class Dx8Opener : DxOpener
{
@@ -41,30 +75,252 @@ namespace GameRes.Formats.DxLib
public Dx8Opener ()
{
- Extensions = new[] { "bin" };
+ Extensions = new string[] { "dxa", "hud", "usi", "med", "dat", "bin", "bcx", "wolf" };
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() };
+
+
+
+
+ internal enum DXA8Flags : UInt32
+ {
+ DXA_FLAG_NO_KEY=1, //file is not encrypted
+ DXA_FLAG_NO_HEAD_PRESS=1<<1, //do not compress the header after compressing individual entries
+ }
+
+ [Serializable]
+ public class DXAOpts : ResourceOptions
+ {
+ public string Keyword;
+ }
+
+ public override ResourceOptions GetDefaultOptions()
+ {
+ return new DXAOpts
+ {
+ Keyword = Properties.Settings.Default.DXAPassword
+ };
+ }
+
+
+
+
+ public override ResourceOptions GetOptions(object widget)
+ {
+ if (widget is GUI.WidgetDXA)
+ {
+ return new DXAOpts
+ {
+ Keyword = ((GUI.WidgetDXA)widget).Password.Text
+ };
+ }
+ return GetDefaultOptions();
+ }
+
+ public override object GetAccessWidget()
+ {
+ return new GUI.WidgetDXA();
+ }
public override ArcFile TryOpen (ArcView file)
{
- var dx = new DxHeader {
+ var dx = new DxHeaderV8 {
IndexSize = file.View.ReadUInt32 (4),
BaseOffset = file.View.ReadInt64 (8),
IndexOffset = file.View.ReadInt64 (0x10),
- FileTable = (uint)file.View.ReadInt64 (0x18),
- DirTable = (uint)file.View.ReadInt64 (0x20),
+ FileTable = file.View.ReadInt64 (0x18),
+ DirTable = file.View.ReadInt64 (0x20),
CodePage = file.View.ReadInt32 (0x28),
+ Flags = (DXA8Flags)file.View.ReadUInt32(0x2C),
+ HuffmanKB = file.View.ReadByte(0x30)
};
if (dx.DirTable >= dx.IndexSize || dx.FileTable >= dx.IndexSize)
return null;
- var key = DefaultKey;
- var index = file.View.ReadBytes (dx.IndexOffset, dx.IndexSize);
- Decrypt (index, 0, index.Length, 0, key);
- // decrypt-2
- // decompress
- return null;
+ DxKey8 key = null;
+
+ //FIXME: ReadBytes sets hard cap of filesize to 4GB.
+ var headerBuffer = file.View.ReadBytes(dx.IndexOffset, (uint)(file.MaxOffset-dx.IndexOffset));
+ bool isencrypted = (dx.Flags & DXA8Flags.DXA_FLAG_NO_KEY) == 0;
+
+ if (isencrypted)
+ {
+ var keyStr = Query(arcStrings.ZIPEncryptedNotice).Keyword;
+ key = new DxKey8(keyStr,dx.CodePage);
+
+
+ }
+
+ Decrypt(headerBuffer, 0, headerBuffer.Length, 0, key.Key);
+ //Decrypted but might be compressed
+ if ((dx.Flags & DXA8Flags.DXA_FLAG_NO_HEAD_PRESS) == 0)
+ {
+ byte[] huffmanBuffer = new byte[headerBuffer.Length];
+ byte[] lzBuffer;
+ headerBuffer.CopyTo(huffmanBuffer, 0);
+ //huffmanBuffer = headerBuffer;
+ HuffmanDecoder decoder = new HuffmanDecoder(huffmanBuffer, (ulong)huffmanBuffer.LongLength);
+ lzBuffer = decoder.Unpack();
+ MemoryStream lzStream = new MemoryStream(lzBuffer);
+ headerBuffer = Unpack(lzStream);
+
+ }
+
+
+ List entries;
+ //There MAY be the case where the singular file is over 4GB, but it's very rare.
+ using (var reader = IndexReader.Create(dx, 8, new MemoryStream(headerBuffer)))
+ {
+ entries = reader.Read();
+ }
+ return new DxArchive8(file, this,entries ,key, 8,dx.HuffmanKB);
+ //retu rn null;
+ }
+
+ public override Stream OpenEntry(ArcFile arc, Entry entry)
+ {
+ Stream input = arc.File.CreateStream(entry.Offset, entry.Size);
+ var dx_arc = arc as DxArchive8;
+ if (null == dx_arc)
+ return input;
+ var dx_ent = (DXA8PackedEntry)entry;
+ long dec_offset = dx_ent.UnpackedSize;
+ var key = dx_arc.Encryption.GetEntryKey(dx_ent.Name);
+ input = new EncryptedStream(input, dec_offset, key);
+
+ byte[] tmpBuffer = new byte[dx_ent.Size];
+ input.Read(tmpBuffer, 0, tmpBuffer.Length);
+ if (dx_ent.HuffmanCompressed)
+ {
+ byte[] buffer = new byte[dx_ent.HuffmanSize];
+ byte[] outBuffer = new byte[dx_ent.IsPacked ? dx_ent.LZSize : dx_ent.UnpackedSize];
+ Array.Copy(tmpBuffer, buffer, dx_ent.HuffmanSize);
+ HuffmanDecoder decoder = new HuffmanDecoder(buffer,dx_ent.HuffmanSize);
+ byte[] partTmpBuffer = decoder.Unpack();
+ //returned buffer might be partial. Check if this is the case.
+ var outBufSize = dx_ent.IsPacked ? dx_ent.LZSize : dx_ent.UnpackedSize;
+ if(dx_arc.huffmanMaxKB != 0xff && outBufSize > dx_arc.huffmanMaxKB * 1024 * 2)
+ {
+ //What we have here is two huffmanMaxKB KB buffers, that constitute the beginning and end of file respectively.
+ Array.Copy(partTmpBuffer,0, outBuffer, 0,dx_arc.huffmanMaxKB*1024);
+ Array.Copy(partTmpBuffer,dx_arc.huffmanMaxKB*1024,outBuffer,outBuffer.Length-dx_arc.huffmanMaxKB*1024,dx_arc.huffmanMaxKB*1024);
+ //uncompressed part goes into middle.
+ Array.Copy(tmpBuffer, dx_ent.HuffmanSize, outBuffer, dx_arc.huffmanMaxKB * 1024, outBufSize - dx_arc.huffmanMaxKB * 1024 * 2);
+ tmpBuffer = outBuffer;
+ } else
+ {
+ //that is all that needs to be done.
+ tmpBuffer = partTmpBuffer;
+ }
+ }
+ if(dx_ent.IsPacked)
+ {
+ byte[] buffer = new byte[dx_ent.LZSize];
+ tmpBuffer.CopyTo(buffer, 0);
+ var tmpMemStream = new MemoryStream(buffer);
+ tmpBuffer = Unpack(tmpMemStream);
+
+ }
+ return new BinMemoryStream(tmpBuffer, entry.Name);
+
+ /*
+ if (!dx_ent.IsPacked)
+ return input;
+ using (input)
+ {
+ var data = Unpack(input);
+ return new BinMemoryStream(data, entry.Name);
+ }
+ */
+ //return null;
+ }
+ }
+
+ internal sealed class IndexReaderV8 : IndexReader
+ {
+ readonly int m_entry_size;
+ public IndexReaderV8(DxHeader header, int version, Stream input) : base(header, version, input)
+ {
+ m_entry_size = 0x48;
+ }
+ private class DxDirectory
+ {
+ public long DirOffset;
+ public long ParentDirOffset;
+ public int FileCount;
+ public long FileTable;
+ }
+
+ DxDirectory ReadDirEntry()
+ {
+ var dir = new DxDirectory
+ {
+ DirOffset = m_input.ReadInt64(),
+ ParentDirOffset = m_input.ReadInt64(),
+ FileCount = (int)m_input.ReadInt64(),
+ FileTable = m_input.ReadInt64()
+ };
+ return dir;
+ }
+
+ protected override void ReadFileTable(string root, long table_offset)
+ {
+ m_input.Position = m_header.DirTable + table_offset;
+ var dir = ReadDirEntry();
+ if (dir.DirOffset != -1 && dir.ParentDirOffset != -1)
+ {
+ m_input.Position = m_header.FileTable + dir.DirOffset;
+ root = Path.Combine(root, ExtractFileName(m_input.ReadInt64()));
+ }
+ long current_pos = m_header.FileTable + dir.FileTable;
+ for (int i = 0; i < dir.FileCount; ++i)
+ {
+ m_input.Position = current_pos;
+ var name_offset = m_input.ReadInt64();
+ uint attr = (uint)m_input.ReadInt64();
+ m_input.Seek(0x18, SeekOrigin.Current);
+ var offset = m_input.ReadInt64();
+ if (0 != (attr & 0x10)) // FILE_ATTRIBUTE_DIRECTORY
+ {
+ if (0 == offset || table_offset == offset)
+ throw new InvalidFormatException("Infinite recursion in DXA directory index");
+ ReadFileTable(root, offset);
+ }
+ else
+ {
+ var size = m_input.ReadInt64();
+ var packed_size = m_input.ReadInt64();
+ var huffman_packed_size = m_input.ReadInt64();
+ var entry = FormatCatalog.Instance.Create(Path.Combine(root, ExtractFileName(name_offset)));
+ entry.Offset = m_header.BaseOffset + offset;
+ entry.UnpackedSize = (uint)size;
+ entry.IsPacked = -1 != packed_size;
+ entry.HuffmanCompressed = -1 != huffman_packed_size;
+ entry.HuffmanSize = (uint)huffman_packed_size;
+ entry.LZSize = (uint)packed_size;
+ //Huffman compression: huffman_packed_size will not exceed 2*HuffmanKB KB. The rest of data is uncompressed (as far as Huffman compressor is concerned).
+ //Add length of uncompressed data to entry.Size
+ if (entry.HuffmanCompressed)
+ {
+ var outBufSize = entry.IsPacked ? packed_size : size;
+ var dx8_hdr = (DxHeaderV8)m_header;
+ if (outBufSize > dx8_hdr.HuffmanKB * 1024 * 2)
+ {
+ huffman_packed_size += outBufSize - dx8_hdr.HuffmanKB * 1024 * 2;
+ }
+ }
+ if (entry.IsPacked||entry.HuffmanCompressed)
+ entry.Size = (uint)(huffman_packed_size!=-1 ? huffman_packed_size:packed_size);
+ else
+ entry.Size = (uint)size;
+ m_dir.Add(entry);
+ }
+ current_pos += m_entry_size;
+ }
}
}
}
diff --git a/ArcFormats/DxLib/DxKey.cs b/ArcFormats/DxLib/DxKey.cs
index 445f22d1..44c57901 100644
--- a/ArcFormats/DxLib/DxKey.cs
+++ b/ArcFormats/DxLib/DxKey.cs
@@ -26,6 +26,8 @@
using System;
using System.Linq;
using System.Security.Cryptography;
+using System.Text;
+using System.Xml.Linq;
using GameRes.Utility;
namespace GameRes.Formats.DxLib
@@ -153,4 +155,78 @@ namespace GameRes.Formats.DxLib
throw new NotSupportedException ("SHA-256 key cannot be restored.");
}
}
+
+ [Serializable]
+ public class DxKey8 : DxKey
+ {
+ private int codepage;
+ public DxKey8(string password,int codepage) : base(password ?? "DXARC")
+ {
+ this.codepage = codepage;
+ }
+
+ public override byte[] GetEntryKey(string name)
+ {
+ var password = this.Password;
+ var path = name.Split('\\', '/');
+ password += string.Join("", path.Reverse().Select(n => n.ToUpperInvariant()));
+ return CreateKey(password);
+ }
+
+ protected override byte[] CreateKey(string keyword)
+ {
+ //from DxArchive.cpp
+ //first check if the keyword is too short
+ if (keyword.Length < 4)
+ {
+ keyword += "DXARC";
+ }
+ //first split string to bytes. Use original encoding as basis. Otherwise we would fail to decrypt that.
+ Encoding tgtEncoding = Encoding.GetEncoding(codepage);
+ byte[] tgtBytes = tgtEncoding.GetBytes(keyword);
+ byte[] oddBuffer = new byte[(tgtBytes.Length/2)+(tgtBytes.Length%2)]; int oddCounter = 0;
+ byte[] evenBuffer = new byte[(tgtBytes.Length/2)]; int evenCounter = 0;
+ for (int i=0; i i % 2 == 0));
+ evenString = string.Concat(keyword.Where((c, i) => (i+1) % 2 == 0));
+ UInt32 crc_0, crc_1;
+ crc_0 = Crc32.Compute(Encoding.ASCII.GetBytes(oddString), 0, oddString.Length);
+ crc_1 = Crc32.Compute(Encoding.ASCII.GetBytes(evenString), 0, evenString.Length); */
+ /*
+ using (var sha = SHA256.Create())
+ {
+ var bytes = Encodings.cp932.GetBytes(keyword);
+ return sha.ComputeHash(bytes);
+ } */
+ }
+
+ protected override string RestoreKey(byte[] key)
+ {
+ throw new NotSupportedException("CRC key cannot be restored.");
+ }
+ }
}
diff --git a/ArcFormats/DxLib/HuffmanDecoder.cs b/ArcFormats/DxLib/HuffmanDecoder.cs
new file mode 100644
index 00000000..6d334ee0
--- /dev/null
+++ b/ArcFormats/DxLib/HuffmanDecoder.cs
@@ -0,0 +1,368 @@
+//! \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.
+//
+
+//Original file is Huffman.cpp. Creator: 山田 巧 Date: 2018 Dec 16
+
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.CompilerServices;
+using GameRes.Utility;
+
+namespace GameRes.Formats.DxLib
+{
+ internal class 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 DXA8HuffmanNode()
+ {
+ bitArray = new byte[32];
+ ChildNode = new int[2];
+ }
+
+ }
+
+ internal sealed class HuffmanDecoder
+ {
+ byte[] m_input;
+ byte[] m_output;
+
+ int m_src;
+ byte m_bits;
+ int m_bit_count;
+
+ ulong m_readBytes;
+ byte m_readBits;
+
+
+ DXA8HuffmanNode[] nodes; //256+255 nodes
+
+ ulong originalSize;
+ ulong compressedSize;
+ ulong headerSize;
+
+ ulong srcSize;
+
+ //ushort token = 256;
+
+ public HuffmanDecoder (byte[] src,ulong srcSize)
+ {
+ m_input = src;
+ m_output = null;
+
+ this.srcSize = srcSize;
+ 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 data nodes, then 255 hierarchy nodes.
+ for (int i = 0; i < nodes.Length; i++)
+ {
+ nodes[i] = new DXA8HuffmanNode();
+ }
+ }
+
+ public byte[] Unpack ()
+ {
+
+ for (int i=0; i 9) continue;
+
+ BitArrayFirstBatch = (ushort)(nodes[j].bitArray[0] | (nodes[j].bitArray[1] << 8));
+
+ if ((i & bitMask[nodes[j].bitNumber - 1]) == (BitArrayFirstBatch & bitMask[nodes[j].bitNumber-1]))
+ {
+ NodeIndexTable[i] = j;
+ break;
+ }
+ }
+
+ }
+
+ }
+ PressBitData = compressedData[PressBitCounter];
+
+ for (DestSizeCounter = 0;DestSizeCounter < originalSize; DestSizeCounter++)
+ {
+ if (DestSizeCounter>= originalSize - 17)
+ {
+ NodeIndex = 510;
+ }
+ else
+ {
+ if (PressBitCounter==8)
+ {
+ PressSizeCounter++;
+ PressBitData = compressedData[PressSizeCounter];
+ PressBitCounter = 0;
+ }
+
+ PressBitData = (PressBitData | (compressedData[PressSizeCounter+1]<<(8-PressBitCounter))) & 0x1ff;
+ NodeIndex = NodeIndexTable[PressBitData];
+ PressBitCounter += nodes[NodeIndex].bitNumber;
+ if (PressBitCounter >= 16)
+ {
+ PressSizeCounter += 2;
+ PressBitCounter -= 16;
+ PressBitData = compressedData[PressSizeCounter] >> PressBitCounter;
+ }
+ else if (PressBitCounter >=8)
+ {
+ PressSizeCounter ++;
+ PressBitCounter -= 8;
+ PressBitData = compressedData[PressSizeCounter] >> PressBitCounter;
+ }
+ else
+ {
+ PressBitData >>= nodes[NodeIndex].bitNumber;
+ }
+ }
+
+ while (NodeIndex > 255)
+ {
+ if (PressBitCounter == 8)
+ {
+ PressSizeCounter++;
+ PressBitData = compressedData[PressSizeCounter];
+ PressBitCounter = 0;
+ }
+ Index = PressBitData & 1;
+ PressBitData >>= 1;
+ PressBitCounter++;
+ NodeIndex = nodes[NodeIndex].ChildNode[Index];
+ }
+ m_output[DestSizeCounter] = (byte)NodeIndex;
+ }
+
+ }
+
+ private void PopulateDataNodes()
+ {
+ //The data which is populated is path from root to target node in bits.
+ byte[] ScratchSpace = new byte[32];
+ int TempBitIndex, TempBitCount;
+
+ for (int i = 0; i < 256 + 254; i++) //root node is excluded.
+ {
+ nodes[i].bitNumber = 0;
+ TempBitIndex = 0;
+ TempBitCount = 0;
+ ScratchSpace[TempBitIndex] = 0;
+
+ for (int j = i; nodes[j].ParentNode!=-1;j = nodes[j].ParentNode)
+ {
+ if (TempBitCount == 8)
+ {
+ TempBitCount = 0;
+ TempBitIndex++;
+ ScratchSpace[TempBitIndex] = 0;
+ }
+ ScratchSpace[TempBitIndex] <<= 1;
+ ScratchSpace[TempBitIndex] |= (byte)nodes[j].Index;
+ TempBitCount++;
+ nodes[i].bitNumber++;
+
+ }
+ //path is now backwards (target to root). Populate BitPath from root to target.
+ int BitIndex=0, BitCount=0;
+ nodes[i].bitArray[BitIndex] = 0;
+ while (TempBitIndex >= 0)
+ {
+ if (BitCount == 8)
+ {
+ BitCount = 0;
+ BitIndex++;
+ nodes[i].bitArray[BitIndex] = 0;
+ }
+ nodes[i].bitArray[BitIndex] |= (byte)((ScratchSpace[TempBitIndex] & 1) << BitCount);
+ ScratchSpace[TempBitIndex] >>= 1;
+ TempBitCount--;
+ if (TempBitCount == 0)
+ {
+ TempBitIndex--;
+ TempBitCount = 8;
+ }
+ BitCount++;
+ }
+ }
+
+
+ }
+
+ private void SetupWeights()
+ {
+ int sizeA, sizeB;
+ byte BitNum;
+ byte Minus;
+ ushort SaveData;
+ ushort[] weights = new ushort[256];
+ sizeA = (int)GetBits(6) + 1;
+ originalSize = GetBits(sizeA);
+ sizeB = (int)GetBits(6)+1;
+ compressedSize = GetBits(sizeB);
+
+ BitNum = (byte)(((int)GetBits(3) + 1) * 2);
+ Minus = (byte)GetBits(1);
+ SaveData = (ushort)GetBits(BitNum);
+ weights[0] = SaveData;
+ for (int i = 1; i < 256; i++)
+ {
+ BitNum = (byte)(((int)GetBits(3) + 1) * 2);
+ Minus = (byte)GetBits(1);
+ SaveData = (ushort)GetBits(BitNum);
+ weights[i] = (ushort)(Minus == 1 ? weights[i - 1] - SaveData : weights[i - 1] + SaveData);
+ }
+ headerSize = GetReadBytes();
+ for (int i = 0;i < 256; i++)
+ {
+ nodes[i].Weight = weights[i];
+ }
+
+ }
+
+ void CreateTree()
+ {
+ int NodeNum=256, DataNum=256;
+
+ while (DataNum > 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;
+ for (int i = 0; i < count;i++)
+ {
+ if (0 == m_bit_count)
+ {
+ m_bits = m_input[m_src];
+ m_src++;
+ m_bit_count = 8;
+ }
+ //bits are read backwards.
+ bits |= ((ulong)((m_bits >> (7 - m_readBits)) & 1)) <<(count-1-i);
+ --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);
+ }
+ }
+}
diff --git a/ArcFormats/DxLib/WidgetDXA.xaml b/ArcFormats/DxLib/WidgetDXA.xaml
new file mode 100644
index 00000000..25e817e7
--- /dev/null
+++ b/ArcFormats/DxLib/WidgetDXA.xaml
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/ArcFormats/DxLib/WidgetDXA.xaml.cs b/ArcFormats/DxLib/WidgetDXA.xaml.cs
new file mode 100644
index 00000000..1f40f949
--- /dev/null
+++ b/ArcFormats/DxLib/WidgetDXA.xaml.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using GameRes.Formats.DxLib;
+
+namespace GameRes.Formats.GUI
+{
+ ///
+ /// Logika interakcji dla klasy WidgetDXA.xaml
+ ///
+ public partial class WidgetDXA : StackPanel
+ {
+ public WidgetDXA()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/ArcFormats/Properties/Settings.Designer.cs b/ArcFormats/Properties/Settings.Designer.cs
index 60c30c27..7844d50b 100644
--- a/ArcFormats/Properties/Settings.Designer.cs
+++ b/ArcFormats/Properties/Settings.Designer.cs
@@ -12,7 +12,7 @@ namespace GameRes.Formats.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.0.3.0")]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.10.0.0")]
public sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -813,5 +813,17 @@ namespace GameRes.Formats.Properties {
this["AFAEncodingCP"] = value;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("DXARC")]
+ public string DXAPassword {
+ get {
+ return ((string)(this["DXAPassword"]));
+ }
+ set {
+ this["DXAPassword"] = value;
+ }
+ }
}
}
diff --git a/ArcFormats/Properties/Settings.settings b/ArcFormats/Properties/Settings.settings
index 4b4c6753..ebd367cb 100644
--- a/ArcFormats/Properties/Settings.settings
+++ b/ArcFormats/Properties/Settings.settings
@@ -200,5 +200,8 @@
932
+
+ DXARC
+
\ No newline at end of file
diff --git a/ArcFormats/app.config b/ArcFormats/app.config
index dd9cbd38..e78ee4ea 100644
--- a/ArcFormats/app.config
+++ b/ArcFormats/app.config
@@ -202,6 +202,9 @@
932
+
+ DXARC
+
diff --git a/GameRes/ArcView.cs b/GameRes/ArcView.cs
index d1a26bac..4cd3a533 100644
--- a/GameRes/ArcView.cs
+++ b/GameRes/ArcView.cs
@@ -33,7 +33,7 @@ namespace GameRes
{
public static class Encodings
{
- public static readonly Encoding cp932 = Encoding.GetEncoding (932);
+ public static readonly Encoding cp932 = Encoding.GetEncoding(932);
public static Encoding WithFatalFallback (this Encoding enc)
{