Пример #1
0
        internal void WriteDBC(DBCFile <T> dbcFile, string path, string signature)
        {
            using var fileStream = File.OpenWrite(path);
            using var writer     = new BinaryWriter(fileStream);
            // Sign the file with the signature
            var signatureBytes = Encoding.UTF8.GetBytes(signature);

            writer.Write(signatureBytes);
            writer.Write(dbcFile.Records.Count);

            // Get fields of the DBC type and write to the DBC file
            var dbcType    = dbcFile.GetDBCType();
            var fields     = dbcType.GetFields();
            int fieldCount = dbcFile.FieldCount(fields, dbcType);

            writer.Write(fieldCount);
            writer.Write(fieldCount * 4);
            writer.Write(0);

            // Adding an empty string to obtain the correct size
            if (signature == "WDBC")
            {
                AddStringToDictionary(string.Empty);
            }

            foreach (var record in dbcFile.Records)
            {
                foreach (var field in fields)
                {
                    switch (Type.GetTypeCode(field.FieldType))
                    {
                    case TypeCode.Object:
                    {
                        if (field.FieldType == typeof(LocalizedString))
                        {
                            int position = AddStringToDictionary((LocalizedString)field.GetValue(record));

                            // Local strings before the local position
                            for (uint i = 0; i < dbcFile.LocalPosition; ++i)
                            {
                                writer.Write(0);
                            }

                            // Write to the Local Position
                            writer.Write(position);

                            // Local strings after the local position
                            for (uint j = dbcFile.LocalPosition + 1; j < LocalizedString.Size - 1; ++j)
                            {
                                writer.Write(0);
                            }

                            // 17th location field
                            writer.Write(dbcFile.LocalFlag);
                        }
                        else
                        {
                            if (field.GetValue(record) is Array array)
                            {
                                int arrayLength = array.Length;

                                switch (Type.GetTypeCode(field.FieldType.GetElementType()))
                                {
                                case TypeCode.Int32:
                                    for (var i = 0; i < arrayLength; ++i)
                                    {
                                        writer.Write((int)array.GetValue(i));
                                    }
                                    break;

                                case TypeCode.UInt32:
                                    for (var i = 0; i < arrayLength; ++i)
                                    {
                                        writer.Write((uint)array.GetValue(i));
                                    }
                                    break;

                                case TypeCode.Single:
                                    for (var i = 0; i < arrayLength; ++i)
                                    {
                                        writer.Write((float)array.GetValue(i));
                                    }
                                    break;

                                default:
                                    throw new NotImplementedException(Type.GetTypeCode(field.FieldType.GetElementType()).ToString());
                                }
                            }
                        }
                        break;
                    }

                    case TypeCode.Byte:
                    {
                        var value = (byte)field.GetValue(record);
                        writer.Write(value);
                        break;
                    }

                    case TypeCode.Int32:
                    {
                        var value = (int)field.GetValue(record);
                        writer.Write(value);
                        break;
                    }

                    case TypeCode.UInt32:
                    {
                        var value = (uint)field.GetValue(record);
                        writer.Write(value);
                        break;
                    }

                    case TypeCode.String:
                    {
                        var str = field.GetValue(record) as string;
                        writer.Write(AddStringToDictionary(str));
                        break;
                    }

                    case TypeCode.Single:
                    {
                        var value = (float)field.GetValue(record);
                        writer.Write(value);
                        break;
                    }

                    default:
                        throw new NotImplementedException(Type.GetTypeCode(field.FieldType).ToString());
                    }
                }
            }

            // Write all of the strings to the DBC file
            foreach (var stringTableBytes in stringTable.Values.Select(str => Encoding.UTF8.GetBytes(str)))
            {
                writer.Write(stringTableBytes);
                writer.Write((byte)0);
            }

            // TODO: Allow for dynamic header size
            writer.BaseStream.Position = 16;
            if (stringTable.Count > 0)
            {
                writer.Write(stringTable.Last().Key + Encoding.UTF8.GetByteCount(stringTable.Last().Value) + 1);
            }
        }
Пример #2
0
        internal void ReadDBC(DBCFile <T> dbcFile, BinaryReader reader, DBCInfo info)
        {
            if (reader is null)
            {
                return;
            }

            // Validate the DBC fields
            var fields      = dbcFile.GetDBCType().GetFields();
            int fieldCounts = dbcFile.FieldCount(fields, dbcFile.GetDBCType());

            if (info.DBCFields != fieldCounts)
            {
                throw new InvalidDBCFields(dbcFile.GetDBCType().ToString());
            }

            // We don't need to read the first bytes again (signature, dbcRecords, dbcFields, recordSize & stringSize)
            long headerSize = reader.BaseStream.Position;

            // Set position of reader
            reader.BaseStream.Position = info.DBCRecords * info.RecordSize + headerSize;

            var    stringData = reader.ReadBytes((int)info.StringSize);
            string fullString = Encoding.UTF8.GetString(stringData);
            var    strings    = fullString.Split(new[] { '\0' }, StringSplitOptions.None);

            var stringTable     = new Dictionary <int, string>();
            var currentPosition = 0;

            foreach (string str in strings)
            {
                stringTable.Add(currentPosition, str);
                currentPosition += Encoding.UTF8.GetByteCount(str) + 1;
            }

            // Reset position to base position
            reader.BaseStream.Position = headerSize;

            // Loop through all of the records in the DBC file
            for (uint i = 0; i < info.DBCRecords; ++i)
            {
                var instance = Activator.CreateInstance(dbcFile.GetDBCType());

                foreach (var field in fields)
                {
                    switch (Type.GetTypeCode(field.FieldType))
                    {
                    case TypeCode.Object:
                    {
                        if (field.FieldType == typeof(LocalizedString))
                        {
                            var value = "";
                            for (uint j = 0; j < LocalizedString.Size - 1; ++j)
                            {
                                int offsetKey = reader.ReadInt32();
                                if (value == "" && offsetKey != 0 && stringTable.TryGetValue(offsetKey, out string stringFromTable))
                                {
                                    value = stringFromTable;
                                    dbcFile.LocalPosition = j;
                                }
                            }

                            dbcFile.LocalFlag = reader.ReadUInt32();

                            field.SetValue(instance, (LocalizedString)value);
                        }
                        else if (field.FieldType.IsArray)
                        {
                            Array array;
                            int   arrayLength;

                            switch (Type.GetTypeCode(field.FieldType.GetElementType()))
                            {
                            case TypeCode.Int32:
                                // Get length of array
                                arrayLength = ((int[])field.GetValue(instance)).Length;

                                // Set Array
                                array = new int[arrayLength];

                                // Set Value of DBC object by looping through the array
                                for (var j = 0; j < arrayLength; ++j)
                                {
                                    array.SetValue(reader.ReadInt32(), j);
                                }
                                field.SetValue(instance, array);
                                break;

                            case TypeCode.UInt32:
                                // Get length of array
                                arrayLength = ((uint[])field.GetValue(instance)).Length;

                                // Set Array
                                array = new uint[arrayLength];

                                // Set Value of DBC object by looping through the array
                                for (var j = 0; j < arrayLength; ++j)
                                {
                                    array.SetValue(reader.ReadUInt32(), j);
                                }
                                field.SetValue(instance, array);
                                break;

                            case TypeCode.Single:
                                // Get length of array
                                arrayLength = ((float[])field.GetValue(instance)).Length;

                                // Set Array
                                array = new float[arrayLength];

                                // Set Value of DBC object by looping through the array
                                for (var j = 0; j < arrayLength; ++j)
                                {
                                    array.SetValue(reader.ReadSingle(), j);
                                }
                                field.SetValue(instance, array);
                                break;

                            default:
                                throw new NotImplementedException(Type.GetTypeCode(field.FieldType.GetElementType()).ToString());
                            }
                        }
                        break;
                    }

                    case TypeCode.Byte:
                    {
                        byte value = reader.ReadByte();
                        field.SetValue(instance, value);
                        break;
                    }

                    case TypeCode.Int32:
                    {
                        int value = reader.ReadInt32();
                        field.SetValue(instance, value);
                        break;
                    }

                    case TypeCode.UInt32:
                    {
                        uint value = reader.ReadUInt32();
                        field.SetValue(instance, value);
                        break;
                    }

                    case TypeCode.Single:
                    {
                        float value = reader.ReadSingle();
                        field.SetValue(instance, value);
                        break;
                    }

                    case TypeCode.String:
                    {
                        // Get offset for string table
                        int offsetKey = reader.ReadInt32();

                        // Check if offset exists in the string table
                        if (!stringTable.TryGetValue(offsetKey, out string stringFromTable))
                        {
                            throw new KeyNotFoundException(offsetKey.ToString());
                        }

                        string value = stringFromTable;
                        field.SetValue(instance, value);
                        break;
                    }

                    default:
                        throw new NotImplementedException(Type.GetTypeCode(field.FieldType).ToString());
                    }
                }

                // Get the first value of the DBC file and use that as key for the DBC record
                var firstValue = fields[0].GetValue(instance);
                var key        = (uint)Convert.ChangeType(firstValue, typeof(uint));
                dbcFile.AddEntry(key, (T)instance);
            }
        }