Esempio n. 1
0
        public static DataTable Read(MemoryStream dbStream, Type type)
        {
            var table = new DataTable();

            try
            {
                var dbReader = new BinaryReader(dbStream);

                var header = new DBHeader
                {
                    Signature   = dbReader.ReadString(4),
                    RecordCount = dbReader.Read<uint>(),
                    FieldCount  = dbReader.Read<uint>(),
                    RecordSize  = dbReader.Read<uint>(),
                    BlockValue  = dbReader.Read<uint>()
                };

                var hasDataOffsetBlock = false;
                var hasIndex = false;
                var recordSizeList = new List<ushort>();

                if (header.IsValidDb4File)
                {
                    header.Hash    = dbReader.Read<uint>();
                    header.Build   = dbReader.Read<uint>();
                    header.Unknown = dbReader.Read<uint>();

                    header.Min = dbReader.Read<int>();
                    header.Max = dbReader.Read<int>();
                    header.Locale = dbReader.Read<int>();
                    header.ReferenceDataSize = dbReader.Read<int>();

                    if (header.IsValidDb4File)
                        header.FileFlags = (Constants.FileFlags)dbReader.Read<int>();

                    var dataSize = header.RecordCount * header.RecordSize;
                    var indexDataSize = header.RecordCount * 4;
                    var indexDataStart = 0;

                    hasDataOffsetBlock = header.FileFlags.HasFlag(FileFlags.DataOffset);

                    if (hasDataOffsetBlock)
                    {
                        dbReader.BaseStream.Position = header.BlockValue;

                        while (header.DataBlockOffsets.Count < header.RecordCount)
                        {
                            var offset = dbReader.ReadUInt32();
                            var size = dbReader.ReadUInt16();

                            if (offset > 0 && !header.DataBlockOffsets.ContainsKey(offset))
                                header.DataBlockOffsets.Add(offset, size);
                        }

                        indexDataStart = (int)dbReader.BaseStream.Position;

                        var dataBlockWriter = new BinaryWriter(new MemoryStream());

                        foreach (var dataBlockOffset in header.DataBlockOffsets)
                        {
                            dbReader.BaseStream.Position = dataBlockOffset.Key;

                            dataBlockWriter.Write(dbReader.ReadBytes(dataBlockOffset.Value));

                            recordSizeList.Add(dataBlockOffset.Value);
                        }

                        header.Data = (dataBlockWriter.BaseStream as MemoryStream).ToArray();

                        dbReader.BaseStream.Position = indexDataStart;
                    }
                    else
                        header.Data = dbReader.ReadBytes((int)dataSize);

                    hasIndex = header.FileFlags.HasFlag(FileFlags.Index);

                    if (!header.FileFlags.HasFlag(FileFlags.DataOffset))
                        header.StringData = dbReader.ReadBytes((int)header.BlockValue);

                    // Some index data stuff?!
                    if (header.FileFlags.HasFlag(FileFlags.Unknown))
                        dbReader.ReadBytes((int)indexDataSize);

                    if (hasIndex)
                        header.IndexData = dbReader.ReadBytes((int)indexDataSize);

                    if (header.ReferenceDataSize > 0)
                        header.ReferenceDataBlock = dbReader.ReadBytes(header.ReferenceDataSize);

                    var data = new BinaryWriter(new MemoryStream());
                    var dataReader = new BinaryReader(new MemoryStream(header.Data));
                    var indexDataReader = new BinaryReader(new MemoryStream(header.IndexData));

                    if (!hasIndex)
                    {
                        for (var i = 0; i < header.RecordCount; i++)
                            data.Write(dataReader.ReadBytes((int)header.RecordSize));
                    }
                    else
                    {
                        if (hasDataOffsetBlock)
                        {
                            for (var i = 0; i < header.RecordCount; i++)
                            {
                                data.Write(indexDataReader.ReadBytes(4));
                                data.Write(dataReader.ReadBytes(recordSizeList[i]));
                            }
                        }
                        else
                        {
                            for (var i = 0; i < header.RecordCount; i++)
                            {
                                data.Write(indexDataReader.ReadBytes(4));
                                data.Write(dataReader.ReadBytes((int)header.RecordSize));
                            }
                        }
                    }

                    data.Write(header.StringData);

                    dataReader.Dispose();
                    indexDataReader.Dispose();

                    dbReader = new BinaryReader(data.BaseStream);
                    dbReader.BaseStream.Position = 0;
                }


                if (header.IsValidDbcFile || header.IsValidDb4File)
                {
                    var fields = type.GetFields();

                    if (hasIndex)
                        fields = typeof(AutoId).GetFields().Concat(fields).ToArray();

                    var lastStringOffset = 0;
                    var lastString = "";
                    var headerSize = header.IsValidDbcFile ? 20 : 0;

                    table.BeginLoadData();

                    foreach (var f in fields)
                    {
                        if (f.FieldType == typeof(Unused) || f.FieldType == typeof(UnusedByte) || f.FieldType == typeof(UnusedShort) || f.FieldType == typeof(UnusedLong) ||
                            f.FieldType == typeof(Unused[]) || f.FieldType == typeof(UnusedByte[]) || f.FieldType == typeof(UnusedShort[]) || f.FieldType == typeof(UnusedLong[]))
                            continue;

                        if (f.FieldType.IsArray)
                        {
                            var arr = f.GetValue(Activator.CreateInstance(type)) as Array;

                            for (var i = 0; i < arr.Length; i++)
                            {
                                if (arr.GetType().GetElementType() == typeof(int))
                                    table.Columns.Add(f.Name + i);
                                else
                                    table.Columns.Add(f.Name + i, arr.GetType().GetElementType());
                            }
                        }
                        else
                            table.Columns.Add(f.Name, f.FieldType);
                    }

                    table.PrimaryKey = new[] { table.Columns[0] };

                    var hasPadding = recordSizeList.Any(v => v > header.RecordSize);
                    var recordSize = 0;

                    for (var i = 0; i < header.RecordCount; i++)
                    {
                        var newObj = Activator.CreateInstance(type);
                        var row = table.NewRow();

                        if (!hasPadding)
                        {
                            dbReader.BaseStream.Position = i * header.RecordSize;

                            if (header.IsValidDbcFile)
                                dbReader.BaseStream.Position += 20;
                            else if (hasIndex)
                                dbReader.BaseStream.Position += i * 4;
                        }

                        var lastFieldType = "";

                        foreach (var f in fields)
                        {
                            // Check for remaining bytes after 8 bit fields.
                            if (header.IsValidDbcFile && f.FieldType.Name != "Byte" && lastFieldType == "Byte")
                            {
                                var padding = dbReader.BaseStream.Position % 4;

                                if (padding > 0)
                                    dbReader.BaseStream.Position += (4 - padding);
                            }

                            lastFieldType = f.FieldType.Name;

                            switch (lastFieldType)
                            {
                                case "Unused":
                                    dbReader.BaseStream.Position += 4;
                                    break;
                                case "UnusedByte":
                                    dbReader.BaseStream.Position += 1;
                                    break;
                                case "UnusedShort":
                                    dbReader.BaseStream.Position += 2;
                                    break;
                                case "UnusedLong":
                                    dbReader.BaseStream.Position += 8;
                                    break;
                                case "SByte":
                                    row[f.Name] = dbReader.ReadSByte();
                                    break;
                                case "Byte":
                                    row[f.Name] = dbReader.ReadByte();
                                    break;
                                case "Int16":
                                    row[f.Name] = dbReader.ReadInt16();
                                    break;
                                case "UInt16":
                                    row[f.Name] = dbReader.ReadUInt16();
                                    break;
                                case "Int32":
                                    row[f.Name] = dbReader.ReadInt32();
                                    break;
                                case "UInt32":
                                    row[f.Name] = dbReader.ReadUInt32();
                                    break;
                                case "Int64":
                                    row[f.Name] = dbReader.ReadInt64();
                                    break;
                                case "UInt64":
                                    row[f.Name] = dbReader.ReadUInt64();
                                    break;
                                case "Single":
                                    row[f.Name] = dbReader.ReadSingle();
                                    break;
                                case "Boolean":
                                    row[f.Name] = dbReader.ReadBoolean();
                                    break;
                                case "Unused[]":
                                    var length = ((Unused[])f.GetValue(newObj)).Length;

                                    for (var j = 0; j < length; j++)
                                        dbReader.BaseStream.Position += 4;
                                    break;
                                case "UnusedByte[]":
                                    length = ((Unused[])f.GetValue(newObj)).Length;

                                    for (var j = 0; j < length; j++)
                                        dbReader.BaseStream.Position += 4;
                                    break;
                                case "UnusedLong[]":
                                    length = ((Unused[])f.GetValue(newObj)).Length;

                                    for (var j = 0; j < length; j++)
                                        dbReader.BaseStream.Position += 4;
                                    break;
                                case "UnusedShort[]":
                                    length = ((Unused[])f.GetValue(newObj)).Length;

                                    for (var j = 0; j < length; j++)
                                        dbReader.BaseStream.Position += 4;
                                    break;
                                case "SByte[]":
                                    length = ((sbyte[])f.GetValue(newObj)).Length;

                                    for (var j = 0; j < length; j++)
                                        row[f.Name + j] = dbReader.ReadSByte();
                                    break;
                                case "Byte[]":
                                    length = ((byte[])f.GetValue(newObj)).Length;

                                    for (var j = 0; j < length; j++)
                                        row[f.Name + j] = dbReader.ReadByte();
                                    break;
                                case "Int16[]":
                                    length = ((short[])f.GetValue(newObj)).Length;

                                    for (var j = 0; j < length; j++)
                                        row[f.Name + j] = dbReader.ReadInt16();
                                    break;
                                case "UInt16[]":
                                    length = ((ushort[])f.GetValue(newObj)).Length;

                                    for (var j = 0; j < length; j++)
                                        row[f.Name + j] = dbReader.ReadUInt16();
                                    break;
                                case "Int32[]":
                                    length = ((int[])f.GetValue(newObj)).Length;

                                    for (var j = 0; j < length; j++)
                                        row[f.Name + j] = dbReader.ReadInt32();
                                    break;
                                case "UInt32[]":
                                    length = ((uint[])f.GetValue(newObj)).Length;

                                    for (var j = 0; j < length; j++)
                                        row[f.Name + j] = dbReader.ReadUInt32();
                                    break;
                                case "Single[]":
                                    length = ((float[])f.GetValue(newObj)).Length;

                                    for (var j = 0; j < length; j++)
                                        row[f.Name + j] = dbReader.ReadSingle();
                                    break;
                                case "Int64[]":
                                    length = ((long[])f.GetValue(newObj)).Length;

                                    for (var j = 0; j < length; j++)
                                        row[f.Name + j] = dbReader.ReadInt64();
                                    break;
                                case "UInt64[]":
                                    length = ((ulong[])f.GetValue(newObj)).Length;

                                    for (var j = 0; j < length; j++)
                                        row[f.Name + j] = dbReader.ReadUInt64();
                                    break;
                                case "String[]":
                                {
                                    length = ((string[])f.GetValue(newObj)).Length;

                                    for (var j = 0; j < length; j++)
                                    {
                                        if (hasDataOffsetBlock)
                                        {
                                            row[f.Name + j] = dbReader.ReadCString();
                                        }
                                        else
                                        {
                                            var stringOffset = dbReader.ReadUInt32();

                                            if (stringOffset == 0)
                                                break;

                                            if (stringOffset != lastStringOffset)
                                            {
                                                var currentPos = dbReader.BaseStream.Position;
                                                var stringStart = (header.RecordCount * header.RecordSize) + headerSize + stringOffset;

                                                if (header.IsValidDb4File && hasIndex)
                                                    stringStart += (header.RecordCount * 4);

                                                dbReader.BaseStream.Seek(stringStart, 0);

                                                row[f.Name + j] = lastString = dbReader.ReadCString();

                                                dbReader.BaseStream.Seek(currentPos, 0);
                                            }
                                            else
                                                row[f.Name + j] = lastString;
                                        }
                                    }

                                    break;
                                }
                                case "String":
                                {
                                    if (hasDataOffsetBlock)
                                    {
                                        row[f.Name] = dbReader.ReadCString();
                                    }
                                    else
                                    {
                                        var stringOffset = dbReader.ReadUInt32();

                                        if (stringOffset == 0)
                                            break;

                                        if (stringOffset != lastStringOffset)
                                        {
                                            var currentPos = dbReader.BaseStream.Position;
                                            var stringStart = (header.RecordCount * header.RecordSize) + headerSize + stringOffset;

                                            if (header.IsValidDb4File && hasIndex)
                                                stringStart += (header.RecordCount * 4);

                                            dbReader.BaseStream.Seek(stringStart, 0);

                                            row[f.Name] = lastString = dbReader.ReadCString();

                                            dbReader.BaseStream.Seek(currentPos, 0);
                                        }
                                        else
                                            row[f.Name] = lastString;
                                    }

                                    break;
                                }
                                default:
                                    dbReader.BaseStream.Position += 4;
                                    break;
                            }
                        }

                        if (hasPadding)
                        {
                            recordSize += recordSizeList[i];

                            if (hasIndex)
                                recordSize += 4;

                            dbReader.BaseStream.Position = recordSize;
                        }

                        table.Rows.Add(row);
                    }

                    table.EndLoadData();
                }

                var refReader = new BinaryReader(new MemoryStream(header.ReferenceDataBlock));

                if (header.ReferenceDataBlock.Length > 0)
                {
                    while (refReader.BaseStream.Position != refReader.BaseStream.Length)
                    {
                        var id = refReader.ReadUInt32();
                        var referenceId = refReader.ReadUInt32();
                        var referenceRow = table.Rows.Find(referenceId);

                        if (referenceRow != null)
                        {
                            var row = table.NewRow();

                            row.ItemArray = referenceRow.ItemArray;
                            row[0] = id;

                            table.Rows.Add(row);
                        }
                    }
                }
            }
            catch
            {
                Console.WriteLine($"Error while loading {type.Name}");
            }

            return table;
        }
Esempio n. 2
0
        public static DataTable Read(MemoryStream dbStream, Type type)
        {
            var table = new DataTable();

            try
            {
                using (var dbReader = new BinaryReader(dbStream))
                {
                    var header = new DBHeader
                    {
                        Signature = dbReader.ReadString(4),
                        RecordCount = dbReader.Read<uint>(),
                        FieldCount = dbReader.Read<uint>(),
                        RecordSize = dbReader.Read<uint>(),
                        StringBlockSize = dbReader.Read<uint>()
                    };

                    if (header.IsValidDb2File)
                    {
                        header.Hash = dbReader.Read<uint>();
                        header.Build = dbReader.Read<uint>();
                        header.Unknown = dbReader.Read<uint>();
                        header.Min = dbReader.Read<int>();
                        header.Max = dbReader.Read<int>();
                        header.Locale = dbReader.Read<int>();
                        header.Unknown2 = dbReader.Read<int>();

                        if (header.Max != 0)
                        {
                            var diff = (header.Max - header.Min) + 1;

                            header.Bytes = dbReader.ReadBytes(diff * 4);
                            header.Bytes2 = dbReader.ReadBytes(diff * 2);
                        }
                    }

                    if (header.IsValidDbcFile || header.IsValidDb2File)
                    {
                        var fields = type.GetFields();
                        var headerLength = dbReader.BaseStream.Position;
                        var lastStringOffset = 0;
                        var lastString = "";
                        var stringOffsetAdd = header.IsValidDbcFile ? 20 : 48;

                        table.BeginLoadData();

                        foreach (var f in fields)
                        {
                            if (f.FieldType == typeof(Unused) || f.FieldType == typeof(UnusedByte) || f.FieldType == typeof(UnusedShort) || f.FieldType == typeof(UnusedLong) ||
                                f.FieldType == typeof(Unused[]) || f.FieldType == typeof(UnusedByte[]) || f.FieldType == typeof(UnusedShort[]) || f.FieldType == typeof(UnusedLong[]))
                                continue;

                                if (f.FieldType.IsArray)
                                {
                                    var arr = f.GetValue(Activator.CreateInstance(type)) as Array;

                                    for (var i = 0; i < arr.Length; i++)
                                        table.Columns.Add(f.Name + i, arr.GetValue(0).GetType());
                                }
                                else
                                    table.Columns.Add(f.Name, f.FieldType);
                            }

                        for (int i = 0; i < header.RecordCount; i++)
                        {
                            var newObj = Activator.CreateInstance(type);
                            var row = table.NewRow();

                            foreach (var f in fields)
                            {
                                switch (f.FieldType.Name)
                                {
                                    case "Unused":
                                        dbReader.BaseStream.Position += 4;
                                        break;
                                    case "UnusedByte":
                                        dbReader.BaseStream.Position += 1;
                                        break;
                                    case "UnusedShort":
                                        dbReader.BaseStream.Position += 2;
                                        break;
                                    case "UnusedLong":
                                        dbReader.BaseStream.Position += 8;
                                        break;
                                    case "SByte":
                                        row[f.Name] = dbReader.ReadSByte();
                                        break;
                                    case "Byte":
                                        row[f.Name] = dbReader.ReadByte();
                                        break;
                                    case "Int32":
                                        row[f.Name] = dbReader.ReadInt32();
                                        break;
                                    case "UInt32":
                                        row[f.Name] = dbReader.ReadUInt32();
                                        break;
                                    case "Int64":
                                        row[f.Name] = dbReader.ReadInt64();
                                        break;
                                    case "UInt64":
                                        row[f.Name] = dbReader.ReadUInt64();
                                        break;
                                    case "Single":
                                        row[f.Name] = dbReader.ReadSingle();
                                        break;
                                    case "Boolean":
                                        row[f.Name] = dbReader.ReadBoolean();
                                        break;
                                    case "Unused[]":
                                        var length = ((Unused[])f.GetValue(newObj)).Length;

                                        for (var j = 0; j < length; j++)
                                            dbReader.BaseStream.Position += 4;
                                        break;
                                    case "UnusedByte[]":
                                        length = ((Unused[])f.GetValue(newObj)).Length;

                                        for (var j = 0; j < length; j++)
                                            dbReader.BaseStream.Position += 4;
                                        break;
                                    case "UnusedLong[]":
                                        length = ((Unused[])f.GetValue(newObj)).Length;

                                        for (var j = 0; j < length; j++)
                                            dbReader.BaseStream.Position += 4;
                                        break;
                                    case "UnusedShort[]":
                                        length = ((Unused[])f.GetValue(newObj)).Length;

                                        for (var j = 0; j < length; j++)
                                            dbReader.BaseStream.Position += 4;
                                        break;
                                    case "SByte[]":
                                        length = ((sbyte[])f.GetValue(newObj)).Length;

                                        for (var j = 0; j < length; j++)
                                            row[f.Name + j] = dbReader.ReadSByte();
                                        break;
                                    case "Byte[]":
                                        length = ((byte[])f.GetValue(newObj)).Length;

                                        for (var j = 0; j < length; j++)
                                            row[f.Name + j] = dbReader.ReadByte();
                                        break;
                                    case "Int32[]":
                                        length = ((int[])f.GetValue(newObj)).Length;

                                        for (var j = 0; j < length; j++)
                                            row[f.Name + j] = dbReader.ReadInt32();
                                        break;
                                    case "UInt32[]":
                                        length = ((uint[])f.GetValue(newObj)).Length;

                                        for (var j = 0; j < length; j++)
                                            row[f.Name + j] = dbReader.ReadUInt32();
                                        break;
                                    case "Single[]":
                                        length = ((float[])f.GetValue(newObj)).Length;

                                        for (var j = 0; j < length; j++)
                                            row[f.Name + j] = dbReader.ReadSingle();
                                        break;
                                    case "Int64[]":
                                        length = ((long[])f.GetValue(newObj)).Length;

                                        for (var j = 0; j < length; j++)
                                            row[f.Name + j] = dbReader.ReadInt64();
                                        break;
                                    case "UInt64[]":
                                        length = ((ulong[])f.GetValue(newObj)).Length;

                                        for (var j = 0; j < length; j++)
                                            row[f.Name + j] = dbReader.ReadUInt64();
                                        break;
                                    case "String":
                                        {
                                            var stringOffset = dbReader.ReadUInt32();

                                            if (stringOffset != lastStringOffset)
                                            {
                                                var currentPos = dbReader.BaseStream.Position;
                                                var stringStart = (header.RecordCount * header.RecordSize) + stringOffsetAdd + stringOffset;
                                                dbReader.BaseStream.Seek(stringStart, 0);
                                                row[f.Name] = lastString = dbReader.ReadCString();

                                                dbReader.BaseStream.Seek(currentPos, 0);
                                            }
                                            else
                                                row[f.Name] = lastString;

                                            break;
                                        }
                                    default:
                                        dbReader.BaseStream.Position += 4;
                                        break;
                                }
                            }

                            // Read remaining bytes if needed
                            var remainingBytes = (int)(dbReader.BaseStream.Position - headerLength) % 4;

                            dbReader.ReadBytes(remainingBytes);

                            table.Rows.Add(row);
                        }

                        table.EndLoadData();
                    }
                }
            }
            catch
            {
            }

            return table;
        }
Esempio n. 3
0
        public static DataTable Read(MemoryStream dbStream, Type type)
        {
            var table = new DataTable();

            try
            {
                var dbReader = new BinaryReader(dbStream);

                var header = new DBHeader
                {
                    Signature   = dbReader.ReadString(4),
                    RecordCount = dbReader.Read <uint>(),
                    FieldCount  = dbReader.Read <uint>(),
                    RecordSize  = dbReader.Read <uint>(),
                    BlockValue  = dbReader.Read <uint>()
                };

                var hasDataOffsetBlock = false;
                var hasIndex           = false;
                var recordSizeList     = new List <ushort>();

                if (header.IsValidDb4File)
                {
                    header.Hash    = dbReader.Read <uint>();
                    header.Build   = dbReader.Read <uint>();
                    header.Unknown = dbReader.Read <uint>();

                    header.Min               = dbReader.Read <int>();
                    header.Max               = dbReader.Read <int>();
                    header.Locale            = dbReader.Read <int>();
                    header.ReferenceDataSize = dbReader.Read <int>();

                    if (header.IsValidDb4File)
                    {
                        header.FileFlags = (Constants.FileFlags)dbReader.Read <int>();
                    }

                    var dataSize       = header.RecordCount * header.RecordSize;
                    var indexDataSize  = header.RecordCount * 4;
                    var indexDataStart = 0;

                    hasDataOffsetBlock = header.FileFlags.HasFlag(FileFlags.DataOffset);

                    if (hasDataOffsetBlock)
                    {
                        dbReader.BaseStream.Position = header.BlockValue;

                        while (header.DataBlockOffsets.Count < header.RecordCount)
                        {
                            var offset = dbReader.ReadUInt32();
                            var size   = dbReader.ReadUInt16();

                            if (offset > 0 && !header.DataBlockOffsets.ContainsKey(offset))
                            {
                                header.DataBlockOffsets.Add(offset, size);
                            }
                        }

                        indexDataStart = (int)dbReader.BaseStream.Position;

                        var dataBlockWriter = new BinaryWriter(new MemoryStream());

                        foreach (var dataBlockOffset in header.DataBlockOffsets)
                        {
                            dbReader.BaseStream.Position = dataBlockOffset.Key;

                            dataBlockWriter.Write(dbReader.ReadBytes(dataBlockOffset.Value));

                            recordSizeList.Add(dataBlockOffset.Value);
                        }

                        header.Data = (dataBlockWriter.BaseStream as MemoryStream).ToArray();

                        dbReader.BaseStream.Position = indexDataStart;
                    }
                    else
                    {
                        header.Data = dbReader.ReadBytes((int)dataSize);
                    }

                    hasIndex = header.FileFlags.HasFlag(FileFlags.Index);

                    if (!header.FileFlags.HasFlag(FileFlags.DataOffset))
                    {
                        header.StringData = dbReader.ReadBytes((int)header.BlockValue);
                    }

                    // Some index data stuff?!
                    if (header.FileFlags.HasFlag(FileFlags.Unknown))
                    {
                        dbReader.ReadBytes((int)indexDataSize);
                    }

                    if (hasIndex)
                    {
                        header.IndexData = dbReader.ReadBytes((int)indexDataSize);
                    }

                    if (header.ReferenceDataSize > 0)
                    {
                        header.ReferenceDataBlock = dbReader.ReadBytes(header.ReferenceDataSize);
                    }

                    var data            = new BinaryWriter(new MemoryStream());
                    var dataReader      = new BinaryReader(new MemoryStream(header.Data));
                    var indexDataReader = new BinaryReader(new MemoryStream(header.IndexData));

                    if (!hasIndex)
                    {
                        for (var i = 0; i < header.RecordCount; i++)
                        {
                            data.Write(dataReader.ReadBytes((int)header.RecordSize));
                        }
                    }
                    else
                    {
                        if (hasDataOffsetBlock)
                        {
                            for (var i = 0; i < header.RecordCount; i++)
                            {
                                data.Write(indexDataReader.ReadBytes(4));
                                data.Write(dataReader.ReadBytes(recordSizeList[i]));
                            }
                        }
                        else
                        {
                            for (var i = 0; i < header.RecordCount; i++)
                            {
                                data.Write(indexDataReader.ReadBytes(4));
                                data.Write(dataReader.ReadBytes((int)header.RecordSize));
                            }
                        }
                    }

                    data.Write(header.StringData);

                    dataReader.Dispose();
                    indexDataReader.Dispose();

                    dbReader = new BinaryReader(data.BaseStream);
                    dbReader.BaseStream.Position = 0;
                }


                if (header.IsValidDbcFile || header.IsValidDb4File)
                {
                    var fields = type.GetFields();

                    if (hasIndex)
                    {
                        fields = typeof(AutoId).GetFields().Concat(fields).ToArray();
                    }

                    var lastStringOffset = 0;
                    var lastString       = "";
                    var headerSize       = header.IsValidDbcFile ? 20 : 0;

                    table.BeginLoadData();

                    foreach (var f in fields)
                    {
                        if (f.FieldType == typeof(Unused) || f.FieldType == typeof(UnusedByte) || f.FieldType == typeof(UnusedShort) || f.FieldType == typeof(UnusedLong) ||
                            f.FieldType == typeof(Unused[]) || f.FieldType == typeof(UnusedByte[]) || f.FieldType == typeof(UnusedShort[]) || f.FieldType == typeof(UnusedLong[]))
                        {
                            continue;
                        }

                        if (f.FieldType.IsArray)
                        {
                            var arr = f.GetValue(Activator.CreateInstance(type)) as Array;

                            for (var i = 0; i < arr.Length; i++)
                            {
                                if (arr.GetType().GetElementType() == typeof(int))
                                {
                                    table.Columns.Add(f.Name + i);
                                }
                                else
                                {
                                    table.Columns.Add(f.Name + i, arr.GetType().GetElementType());
                                }
                            }
                        }
                        else if (f.FieldType == typeof(int))
                        {
                            table.Columns.Add(f.Name);
                        }
                        else
                        {
                            table.Columns.Add(f.Name, f.FieldType);
                        }
                    }

                    table.PrimaryKey = new[] { table.Columns[0] };

                    var hasPadding = recordSizeList.Any(v => v > header.RecordSize);
                    var recordSize = 0;

                    for (var i = 0; i < header.RecordCount; i++)
                    {
                        var newObj = Activator.CreateInstance(type);
                        var row    = table.NewRow();

                        if (!hasPadding)
                        {
                            dbReader.BaseStream.Position = i * header.RecordSize;

                            if (header.IsValidDbcFile)
                            {
                                dbReader.BaseStream.Position += 20;
                            }
                            else if (hasIndex)
                            {
                                dbReader.BaseStream.Position += i * 4;
                            }
                        }

                        var lastFieldType = "";

                        foreach (var f in fields)
                        {
                            // Check for remaining bytes after 8 bit fields.
                            if (header.IsValidDbcFile && f.FieldType.Name != "Byte" && lastFieldType == "Byte")
                            {
                                var padding = dbReader.BaseStream.Position % 4;

                                if (padding > 0)
                                {
                                    dbReader.BaseStream.Position += (4 - padding);
                                }
                            }

                            lastFieldType = f.FieldType.Name;

                            switch (lastFieldType)
                            {
                            case "Unused":
                                dbReader.BaseStream.Position += 4;
                                break;

                            case "UnusedByte":
                                dbReader.BaseStream.Position += 1;
                                break;

                            case "UnusedShort":
                                dbReader.BaseStream.Position += 2;
                                break;

                            case "UnusedLong":
                                dbReader.BaseStream.Position += 8;
                                break;

                            case "SByte":
                                row[f.Name] = dbReader.ReadSByte();
                                break;

                            case "Byte":
                                row[f.Name] = dbReader.ReadByte();
                                break;

                            case "Int16":
                                row[f.Name] = dbReader.ReadInt16();
                                break;

                            case "UInt16":
                                row[f.Name] = dbReader.ReadUInt16();
                                break;

                            case "Int32":
                                var dword = dbReader.ReadDword();

                                if (dword.Item2 > int.MaxValue)
                                {
                                    row[f.Name] = dword.Item2;
                                }
                                else
                                {
                                    row[f.Name] = dword.Item1;
                                }

                                break;

                            case "UInt32":
                                row[f.Name] = dbReader.ReadUInt32();
                                break;

                            case "Int64":
                                row[f.Name] = dbReader.ReadInt64();
                                break;

                            case "UInt64":
                                row[f.Name] = dbReader.ReadUInt64();
                                break;

                            case "Single":
                                row[f.Name] = dbReader.ReadSingle();
                                break;

                            case "Boolean":
                                row[f.Name] = dbReader.ReadBoolean();
                                break;

                            case "Unused[]":
                                var length = ((Unused[])f.GetValue(newObj)).Length;

                                for (var j = 0; j < length; j++)
                                {
                                    dbReader.BaseStream.Position += 4;
                                }
                                break;

                            case "UnusedByte[]":
                                length = ((Unused[])f.GetValue(newObj)).Length;

                                for (var j = 0; j < length; j++)
                                {
                                    dbReader.BaseStream.Position += 4;
                                }
                                break;

                            case "UnusedLong[]":
                                length = ((Unused[])f.GetValue(newObj)).Length;

                                for (var j = 0; j < length; j++)
                                {
                                    dbReader.BaseStream.Position += 4;
                                }
                                break;

                            case "UnusedShort[]":
                                length = ((Unused[])f.GetValue(newObj)).Length;

                                for (var j = 0; j < length; j++)
                                {
                                    dbReader.BaseStream.Position += 4;
                                }
                                break;

                            case "SByte[]":
                                length = ((sbyte[])f.GetValue(newObj)).Length;

                                for (var j = 0; j < length; j++)
                                {
                                    row[f.Name + j] = dbReader.ReadSByte();
                                }
                                break;

                            case "Byte[]":
                                length = ((byte[])f.GetValue(newObj)).Length;

                                for (var j = 0; j < length; j++)
                                {
                                    row[f.Name + j] = dbReader.ReadByte();
                                }
                                break;

                            case "Int16[]":
                                length = ((short[])f.GetValue(newObj)).Length;

                                for (var j = 0; j < length; j++)
                                {
                                    row[f.Name + j] = dbReader.ReadInt16();
                                }
                                break;

                            case "UInt16[]":
                                length = ((ushort[])f.GetValue(newObj)).Length;

                                for (var j = 0; j < length; j++)
                                {
                                    row[f.Name + j] = dbReader.ReadUInt16();
                                }
                                break;

                            case "Int32[]":
                                length = ((int[])f.GetValue(newObj)).Length;

                                for (var j = 0; j < length; j++)
                                {
                                    dword = dbReader.ReadDword();

                                    if (dword.Item2 > int.MaxValue)
                                    {
                                        row[f.Name + j] = dword.Item2;
                                    }
                                    else
                                    {
                                        row[f.Name + j] = dword.Item1;
                                    }
                                }
                                break;

                            case "UInt32[]":
                                length = ((uint[])f.GetValue(newObj)).Length;

                                for (var j = 0; j < length; j++)
                                {
                                    row[f.Name + j] = dbReader.ReadUInt32();
                                }
                                break;

                            case "Single[]":
                                length = ((float[])f.GetValue(newObj)).Length;

                                for (var j = 0; j < length; j++)
                                {
                                    row[f.Name + j] = dbReader.ReadSingle();
                                }
                                break;

                            case "Int64[]":
                                length = ((long[])f.GetValue(newObj)).Length;

                                for (var j = 0; j < length; j++)
                                {
                                    row[f.Name + j] = dbReader.ReadInt64();
                                }
                                break;

                            case "UInt64[]":
                                length = ((ulong[])f.GetValue(newObj)).Length;

                                for (var j = 0; j < length; j++)
                                {
                                    row[f.Name + j] = dbReader.ReadUInt64();
                                }
                                break;

                            case "String[]":
                            {
                                length = ((string[])f.GetValue(newObj)).Length;

                                for (var j = 0; j < length; j++)
                                {
                                    if (hasDataOffsetBlock)
                                    {
                                        row[f.Name + j] = dbReader.ReadCString();
                                    }
                                    else
                                    {
                                        var stringOffset = dbReader.ReadUInt32();

                                        if (stringOffset == 0)
                                        {
                                            break;
                                        }

                                        if (stringOffset != lastStringOffset)
                                        {
                                            var currentPos  = dbReader.BaseStream.Position;
                                            var stringStart = (header.RecordCount * header.RecordSize) + headerSize + stringOffset;

                                            if (header.IsValidDb4File && hasIndex)
                                            {
                                                stringStart += (header.RecordCount * 4);
                                            }

                                            dbReader.BaseStream.Seek(stringStart, 0);

                                            row[f.Name + j] = lastString = dbReader.ReadCString();

                                            dbReader.BaseStream.Seek(currentPos, 0);
                                        }
                                        else
                                        {
                                            row[f.Name + j] = lastString;
                                        }
                                    }
                                }

                                break;
                            }

                            case "String":
                            {
                                if (hasDataOffsetBlock)
                                {
                                    row[f.Name] = dbReader.ReadCString();
                                }
                                else
                                {
                                    var stringOffset = dbReader.ReadUInt32();

                                    if (stringOffset == 0)
                                    {
                                        break;
                                    }

                                    if (stringOffset != lastStringOffset)
                                    {
                                        var currentPos  = dbReader.BaseStream.Position;
                                        var stringStart = (header.RecordCount * header.RecordSize) + headerSize + stringOffset;

                                        if (header.IsValidDb4File && hasIndex)
                                        {
                                            stringStart += (header.RecordCount * 4);
                                        }

                                        dbReader.BaseStream.Seek(stringStart, 0);

                                        row[f.Name] = lastString = dbReader.ReadCString();

                                        dbReader.BaseStream.Seek(currentPos, 0);
                                    }
                                    else
                                    {
                                        row[f.Name] = lastString;
                                    }
                                }

                                break;
                            }

                            default:
                                dbReader.BaseStream.Position += 4;
                                break;
                            }
                        }

                        if (hasPadding)
                        {
                            recordSize += recordSizeList[i];

                            if (hasIndex)
                            {
                                recordSize += 4;
                            }

                            dbReader.BaseStream.Position = recordSize;
                        }

                        table.Rows.Add(row);
                    }

                    table.EndLoadData();
                }

                var refReader = new BinaryReader(new MemoryStream(header.ReferenceDataBlock));

                if (header.ReferenceDataBlock.Length > 0)
                {
                    while (refReader.BaseStream.Position != refReader.BaseStream.Length)
                    {
                        var id           = refReader.ReadUInt32();
                        var referenceId  = refReader.ReadUInt32();
                        var referenceRow = table.Rows.Find(referenceId);

                        if (referenceRow != null)
                        {
                            var row = table.NewRow();

                            row.ItemArray = referenceRow.ItemArray;
                            row[0]        = id;

                            table.Rows.Add(row);
                        }
                    }
                }
            }
            catch
            {
                Console.WriteLine($"Error while loading {type.Name}");
            }

            return(table);
        }