From 467ae9f27cb2b1781b880b771ae93670b0a9b340 Mon Sep 17 00:00:00 2001 From: TOM_RUS Date: Wed, 1 Jun 2016 00:07:51 +0300 Subject: [PATCH 1/2] Fix --- CASCExplorer/CASCViewHelper.cs | 14 +- CascLib/CascLib.csproj | 1 + CascLib/DB3Reader.cs | 13 +- CascLib/DB5Reader.cs | 241 +++++++++++++++++++++++++++++++++ CascLib/WowRootHandler.cs | 6 +- 5 files changed, 254 insertions(+), 21 deletions(-) create mode 100644 CascLib/DB5Reader.cs diff --git a/CASCExplorer/CASCViewHelper.cs b/CASCExplorer/CASCViewHelper.cs index a46292e5..7a51b74e 100644 --- a/CASCExplorer/CASCViewHelper.cs +++ b/CASCExplorer/CASCViewHelper.cs @@ -119,31 +119,31 @@ await Task.Run(() => } } - if (false && _casc.FileExists("DBFilesClient\\SoundKit.db2") && _casc.FileExists("DBFilesClient\\SoundKitEntry.db2")) + if (_casc.FileExists("DBFilesClient\\SoundKit.db2") && _casc.FileExists("DBFilesClient\\SoundKitEntry.db2")) { using (Stream skStream = _casc.OpenFile("DBFilesClient\\SoundKit.db2")) using (Stream skeStream = _casc.OpenFile("DBFilesClient\\SoundKitEntry.db2")) { - DB3Reader sk = new DB3Reader(skStream); - DB3Reader ske = new DB3Reader(skeStream); + DB5Reader sk = new DB5Reader(skStream); + DB5Reader ske = new DB5Reader(skeStream); Dictionary> lookup = new Dictionary>(); foreach (var row in ske) { - int soundKitId = row.Value.GetField(0xC); + int soundKitId = row.Value.GetField(3); if (!lookup.ContainsKey(soundKitId)) lookup[soundKitId] = new List(); - lookup[soundKitId].Add(row.Value.GetField(0x4)); + lookup[soundKitId].Add(row.Value.GetField(0)); } foreach (var row in sk) { - string name = row.Value.GetField(0x4).Replace(':', '_'); + string name = row.Value.GetField(0).Replace(':', '_'); - int type = row.Value.GetField(0x2C); + int type = row.Value.GetField(12); List ske_entries; diff --git a/CascLib/CascLib.csproj b/CascLib/CascLib.csproj index 32fcf671..a807572a 100644 --- a/CascLib/CascLib.csproj +++ b/CascLib/CascLib.csproj @@ -49,6 +49,7 @@ + diff --git a/CascLib/DB3Reader.cs b/CascLib/DB3Reader.cs index d5c1c0d7..fa5f950a 100644 --- a/CascLib/DB3Reader.cs +++ b/CascLib/DB3Reader.cs @@ -68,7 +68,6 @@ public class DB3Reader : IEnumerable> private readonly int HeaderSize; private const uint DB3FmtSig = 0x33424457; // WDB3 private const uint DB4FmtSig = 0x34424457; // WDB4 - private const uint DB5FmtSig = 0x35424457; // WDB5 public int RecordsCount { get; private set; } public int FieldsCount { get; private set; } @@ -94,7 +93,7 @@ public DB3Reader(Stream stream) uint magic = reader.ReadUInt32(); - if (magic != DB3FmtSig && magic != DB4FmtSig && magic != DB5FmtSig) + if (magic != DB3FmtSig && magic != DB4FmtSig) { throw new InvalidDataException(string.Format("DB3 file is corrupted!")); } @@ -114,10 +113,7 @@ public DB3Reader(Stream stream) uint tableHash = reader.ReadUInt32(); uint build = reader.ReadUInt32(); - if (magic != DB5FmtSig) - { - uint unk1 = reader.ReadUInt32(); // timemodified - } + uint unk1 = reader.ReadUInt32(); // timemodified int MinId = reader.ReadInt32(); int MaxId = reader.ReadInt32(); @@ -129,11 +125,6 @@ public DB3Reader(Stream stream) int metaFlags = reader.ReadInt32(); } - if (magic == DB5FmtSig) - { - reader.BaseStream.Position += FieldsCount * 4; - } - int stringTableStart = HeaderSize + RecordsCount * RecordSize; int stringTableEnd = stringTableStart + StringTableSize; diff --git a/CascLib/DB5Reader.cs b/CascLib/DB5Reader.cs new file mode 100644 index 00000000..b354a343 --- /dev/null +++ b/CascLib/DB5Reader.cs @@ -0,0 +1,241 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace CASCExplorer +{ + public class DB5Row + { + private byte[] m_data; + private DB5Reader m_reader; + + public byte[] Data { get { return m_data; } } + + public DB5Row(DB5Reader reader, byte[] data) + { + m_reader = reader; + m_data = data; + } + + public T GetField(int field, int arrayIndex = 0) + { + DB2Meta meta = m_reader.Meta[field]; + + if (meta.Bits != 0x00 && meta.Bits != 0x08 && meta.Bits != 0x10 && meta.Bits != 0x18 && meta.Bits != -32) + throw new Exception("Unknown meta.Flags"); + + int bytesCount = (32 - meta.Bits) >> 3; + + TypeCode code = Type.GetTypeCode(typeof(T)); + + object value = null; + + switch (code) + { + case TypeCode.Byte: + if (meta.Bits != 0x18) + throw new Exception("TypeCode.Byte Unknown meta.Bits"); + value = m_data[meta.Offset + bytesCount * arrayIndex]; + break; + case TypeCode.SByte: + if (meta.Bits != 0x18) + throw new Exception("TypeCode.SByte Unknown meta.Bits"); + value = (sbyte)m_data[meta.Offset + bytesCount * arrayIndex]; + break; + case TypeCode.Int16: + if (meta.Bits != 0x10) + throw new Exception("TypeCode.Int16 Unknown meta.Bits"); + value = BitConverter.ToInt16(m_data, meta.Offset + bytesCount * arrayIndex); + break; + case TypeCode.UInt16: + if (meta.Bits != 0x10) + throw new Exception("TypeCode.UInt16 Unknown meta.Bits"); + value = BitConverter.ToUInt16(m_data, meta.Offset + bytesCount * arrayIndex); + break; + case TypeCode.Int32: + byte[] b1 = new byte[4]; + Array.Copy(m_data, meta.Offset + bytesCount * arrayIndex, b1, 0, bytesCount); + value = BitConverter.ToInt32(b1, 0); + break; + case TypeCode.UInt32: + byte[] b2 = new byte[4]; + Array.Copy(m_data, meta.Offset + bytesCount * arrayIndex, b2, 0, bytesCount); + value = BitConverter.ToUInt32(b2, 0); + break; + case TypeCode.Int64: + byte[] b3 = new byte[8]; + Array.Copy(m_data, meta.Offset + bytesCount * arrayIndex, b3, 0, bytesCount); + value = BitConverter.ToInt64(b3, 0); + break; + case TypeCode.UInt64: + byte[] b4 = new byte[8]; + Array.Copy(m_data, meta.Offset + bytesCount * arrayIndex, b4, 0, bytesCount); + value = BitConverter.ToUInt64(b4, 0); + break; + case TypeCode.String: + if (meta.Bits != 0x00) + throw new Exception("TypeCode.String Unknown meta.Bits"); + byte[] b5 = new byte[4]; + Array.Copy(m_data, meta.Offset + bytesCount * arrayIndex, b5, 0, bytesCount); + int start = BitConverter.ToInt32(b5, 0), len = 0; + while (m_reader.StringTable[start + len] != 0) + len++; + value = Encoding.UTF8.GetString(m_reader.StringTable, start, len); + break; + case TypeCode.Single: + if (meta.Bits != 0x00) + throw new Exception("TypeCode.Single Unknown meta.Bits"); + value = BitConverter.ToSingle(m_data, meta.Offset + bytesCount * arrayIndex); + break; + default: + throw new Exception("Unknown TypeCode " + code); + } + + return (T)value; + } + } + + public class DB2Meta + { + public short Bits { get; set; } + public short Offset { get; set; } + } + + public class DB5Reader : IEnumerable> + { + private const int HeaderSize = 48; + private const uint DB5FmtSig = 0x35424457; // WDB5 + + public int RecordsCount { get; private set; } + public int FieldsCount { get; private set; } + public int RecordSize { get; private set; } + public int StringTableSize { get; private set; } + public int MinIndex { get; private set; } + public int MaxIndex { get; private set; } + + private readonly byte[] m_stringTable; + private readonly DB2Meta[] m_meta; + + public byte[] StringTable => m_stringTable; + public DB2Meta[] Meta => m_meta; + + private Dictionary m_index = new Dictionary(); + + public DB5Reader(string dbcFile) : this(new FileStream(dbcFile, FileMode.Open)) { } + + public DB5Reader(Stream stream) + { + using (var reader = new BinaryReader(stream, Encoding.UTF8)) + { + if (reader.BaseStream.Length < HeaderSize) + { + throw new InvalidDataException(String.Format("DB5 file is corrupted!")); + } + + uint magic = reader.ReadUInt32(); + + if (magic != DB5FmtSig) + { + throw new InvalidDataException(String.Format("DB5 file is corrupted!")); + } + + RecordsCount = reader.ReadInt32(); + FieldsCount = reader.ReadInt32(); + RecordSize = reader.ReadInt32(); + StringTableSize = reader.ReadInt32(); + + uint tableHash = reader.ReadUInt32(); + uint layoutHash = reader.ReadUInt32(); + MinIndex = reader.ReadInt32(); + MaxIndex = reader.ReadInt32(); + int locale = reader.ReadInt32(); + int copyTableSize = reader.ReadInt32(); + int flags = reader.ReadUInt16(); + int idIndex = reader.ReadUInt16(); + + bool isSparse = (flags & 0x1) != 0; + bool hasIndex = (flags & 0x4) != 0; + + m_meta = new DB2Meta[FieldsCount]; + + for (int i = 0; i < m_meta.Length; i++) + { + m_meta[i] = new DB2Meta(); + m_meta[i].Bits = reader.ReadInt16(); + m_meta[i].Offset = reader.ReadInt16(); + } + + DB5Row[] m_rows = new DB5Row[RecordsCount]; + + for (int i = 0; i < RecordsCount; i++) + { + m_rows[i] = new DB5Row(this, reader.ReadBytes(RecordSize)); + } + + m_stringTable = reader.ReadBytes(StringTableSize); + + if (isSparse) + { + // code... + throw new Exception("can't do sparse table"); + } + + if (hasIndex) + { + for (int i = 0; i < RecordsCount; i++) + { + int id = reader.ReadInt32(); + m_index[id] = m_rows[i]; + } + } + else + { + for (int i = 0; i < RecordsCount; i++) + { + int id = m_rows[i].Data.Skip(m_meta[idIndex].Offset).Take((32 - m_meta[idIndex].Bits) >> 3).Select((b, k) => b << k * 8).Sum(); + m_index[id] = m_rows[i]; + } + } + + if (copyTableSize > 0) + { + int copyCount = copyTableSize / 8; + + for (int i = 0; i < copyCount; i++) + { + int newId = reader.ReadInt32(); + int oldId = reader.ReadInt32(); + + m_index[newId] = m_index[oldId]; + } + } + } + } + + public bool HasRow(int id) + { + return m_index.ContainsKey(id); + } + + public DB5Row GetRow(int id) + { + if (!m_index.ContainsKey(id)) + return null; + + return m_index[id]; + } + + public IEnumerator> GetEnumerator() + { + return m_index.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return m_index.GetEnumerator(); + } + } +} diff --git a/CascLib/WowRootHandler.cs b/CascLib/WowRootHandler.cs index 1b2a9db9..981cd3ba 100644 --- a/CascLib/WowRootHandler.cs +++ b/CascLib/WowRootHandler.cs @@ -263,12 +263,12 @@ public void LoadFileDataComplete(CASCHandler casc) using (var s = casc.OpenFile("DBFilesClient\\FileDataComplete.db2")) { - DB3Reader fd = new DB3Reader(s); + DB5Reader fd = new DB5Reader(s); foreach (var row in fd) { - string path = row.Value.GetField(4); - string name = row.Value.GetField(8); + string path = row.Value.GetField(0); + string name = row.Value.GetField(1); string fullname = path + name; From 08b5ad9dba872c45fef6bffb4327c6ce77b3ff00 Mon Sep 17 00:00:00 2001 From: TOM_RUS Date: Fri, 3 Jun 2016 20:35:38 +0300 Subject: [PATCH 2/2] Fix --- CascLib/BLTEHandler.cs | 4 ++-- CascLib/CASCHandler.cs | 4 ++-- CascLib/Extensions.cs | 2 +- CascLib/WowRootHandler.cs | 3 ++- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CascLib/BLTEHandler.cs b/CascLib/BLTEHandler.cs index 29f576eb..8915b467 100644 --- a/CascLib/BLTEHandler.cs +++ b/CascLib/BLTEHandler.cs @@ -251,10 +251,10 @@ private static void Decompress(byte[] data, Stream outStream) public void Dispose() { - _reader.Close(); + _reader.Dispose(); if (!_leaveOpen) - _memStream.Close(); + _memStream.Dispose(); } } } diff --git a/CascLib/CASCHandler.cs b/CascLib/CASCHandler.cs index 863b434c..bf44116f 100644 --- a/CascLib/CASCHandler.cs +++ b/CascLib/CASCHandler.cs @@ -244,7 +244,7 @@ protected override Stream GetLocalDataStream(MD5Hash key) IndexEntry idxInfo = LocalIndex.GetIndexInfo(key); if (idxInfo == null) { - Debug.Print("Local index missing: {0}", key.ToHexString()); + Logger.WriteLine("Local index missing: {0}", key.ToHexString()); } return GetLocalDataStreamInternal(idxInfo, key); } @@ -261,7 +261,7 @@ public void Clear() CDNIndex = null; foreach (var stream in DataStreams) - stream.Value.Close(); + stream.Value.Dispose(); DataStreams.Clear(); diff --git a/CascLib/Extensions.cs b/CascLib/Extensions.cs index 6ee79c2a..94874c10 100644 --- a/CascLib/Extensions.cs +++ b/CascLib/Extensions.cs @@ -99,7 +99,7 @@ public static string ToBinaryString(this BitArray bits) { StringBuilder sb = new StringBuilder(bits.Length); - for (int i = 0; i < bits.Count; ++i) + for (int i = 0; i < bits.Length; ++i) { sb.Append(bits[i] ? "1" : "0"); } diff --git a/CascLib/WowRootHandler.cs b/CascLib/WowRootHandler.cs index 981cd3ba..4e29ed05 100644 --- a/CascLib/WowRootHandler.cs +++ b/CascLib/WowRootHandler.cs @@ -308,7 +308,8 @@ public override void LoadListFile(string path, BackgroundWorkerEx worker = null) using (var fs = new FileStream("listfile.bin", FileMode.Create)) using (var bw = new BinaryWriter(fs)) - using (var sr = new StreamReader(path)) + using (var fs2 = File.Open(path, FileMode.Open)) + using (var sr = new StreamReader(fs2)) { string file;