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 = DBCUtility.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); } }
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); } }
internal static void ReadDBC(DBCFile <T> dbcFile, BinaryReader reader) { if (reader is null) { return; } var info = DBCUtility.GetDBCInfo(reader); // Validate the DBC fields var fields = dbcFile.GetDBCType().GetFields(); int fieldCounts = DBCUtility.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) long headerSize = reader.BaseStream.Position; // Extract all strings and construct string table var stringTable = DBCUtility.GetStringTable(reader, info, headerSize); // 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 (string.IsNullOrEmpty(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 record and use that as the key for the DBC record var firstValue = fields[0].GetValue(instance); var key = (uint)Convert.ChangeType(firstValue, typeof(uint)); dbcFile.AddEntry(key, (T)instance); } }
internal void WriteDBC(DBCFile <T> file, string path, IComparer <T> comparison) { var dirName = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(dirName)) { Directory.CreateDirectory(dirName); } try { FileStream strm = File.OpenWrite(path); BinaryWriter bw = new BinaryWriter(strm); byte[] bytes = Encoding.UTF8.GetBytes("WDBC"); bw.Write(bytes); bw.Write(file.Records.Count); Type type = typeof(T); var fields = type.GetFields(); int fieldCount = DBCHelper.FieldCount(fields, type); var classAttribs = typeof(T).GetCustomAttributes(typeof(NoPrimaryAttribute), false); bw.Write(fieldCount); //The charBaseInfo.dbc is weird, and don't have *4. string charBaseInfoPath = Application.ExecutablePath + "\\DBC\\CharBaseInfo.dbc"; if (path == charBaseInfoPath) { bw.Write(fieldCount); } else { bw.Write(fieldCount * 4); } bw.Write(0); // Ajout d'une string vide afin d'obtenir un format blizzlike AddStringToTable(""); List <T> valueCollection = file.Records.ToList(); if (comparison != null) { valueCollection.Sort(comparison); } // Ecriture de chaque champ de chaque enregistrement foreach (var rec in valueCollection) { foreach (var field in fields) { switch (Type.GetTypeCode(field.FieldType)) { case TypeCode.Int32: { int value = (int)field.GetValue(rec); bw.Write(value); break; } case TypeCode.UInt32: { uint uvalue = (uint)field.GetValue(rec); bw.Write(uvalue); break; } case TypeCode.String: { string str = field.GetValue(rec) as string; bw.Write(AddStringToTable(str)); break; } case TypeCode.Single: { float fvalue = (float)field.GetValue(rec); bw.Write(fvalue); break; } //Added typecode byte for the charbaseinfo, don't work properly case TypeCode.Byte: byte bvalue = (byte)field.GetValue(rec); bw.Write(bvalue); break; case TypeCode.Object: { if (field.FieldType == typeof(LocalizedString)) { int pos = AddStringToTable((LocalizedString)field.GetValue(rec)); for (uint j = 0; j < file.LocalePosition; ++j) { bw.Write((int)0); } bw.Write(pos); for (uint j = file.LocalePosition + 1; j < 16; ++j) { bw.Write((int)0); } // 17ème champ de localisation bw.Write((uint)file.LocaleFlag); } else { int len; Array array; switch (Type.GetTypeCode(field.FieldType.GetElementType())) { case TypeCode.Int32: array = field.GetValue(rec) as Array; len = array.Length; for (var q = 0; q < len; ++q) { bw.Write((int)array.GetValue(q)); } break; case TypeCode.UInt32: array = field.GetValue(rec) as Array; len = array.Length; for (var q = 0; q < len; ++q) { bw.Write((uint)array.GetValue(q)); } break; case TypeCode.Single: array = field.GetValue(rec) as Array; len = array.Length; for (var q = 0; q < len; ++q) { bw.Write((float)array.GetValue(q)); } break; default: throw new NotImplementedException(); } } } break; } } } foreach (var str in _stringTable.Values) { bytes = Encoding.UTF8.GetBytes(str); bw.Write(bytes); bw.Write((byte)0); } bw.BaseStream.Position = 16; if (_stringTable.Count > 0) { bw.Write(_stringTable.Last().Key + Encoding.UTF8.GetByteCount(_stringTable.Last().Value) + 1); } strm.Close(); } catch (IOException ex) { MessageBox.Show(ex.Message); } }