private void ReadIntoFile(DBEntry entry, BinaryWriter bw, IEnumerable <DataRow> rows, ref StringTable st) { TypeCode[] columnTypes = entry.Data.Columns.Cast <DataColumn>().Select(x => Type.GetTypeCode(x.DataType)).ToArray(); int[] padding = entry.TableStructure.Padding.ToArray(); var bits = entry.GetBits(); bool duplicates = false; if (entry.Header.IsTypeOf <WDB2>() && ((WDB2)entry.Header).MaxId != 0) //WDB2 with MaxId > 0 allows duplicates { duplicates = true; } else if (entry.Header.IsTypeOf <WCH7>() && ((WCH7)entry.Header).UnknownWCH7 != 0) //WCH7 with Unknown > 0 allows duplicates { duplicates = true; } var lastrow = rows.Last(); foreach (DataRow row in rows) { long offset = bw.BaseStream.Position; for (int j = 0; j < entry.Data.Columns.Count; j++) { if (entry.Data.Columns[j].ExtendedProperties.ContainsKey(AUTO_GENERATED)) //Autogenerated so skip { continue; } if (entry.Header.HasIndexTable && j == 0) //Inline Id so skip { continue; } if (entry.Header.IsTypeOf <WCH5>() && entry.Header.HasOffsetTable && j == 0) //Inline Id so skip { continue; } switch (columnTypes[j]) { case TypeCode.SByte: bw.Write(row.Field <sbyte>(j)); bw.BaseStream.Position += sizeof(sbyte) * padding[j]; break; case TypeCode.Byte: bw.Write(row.Field <byte>(j)); bw.BaseStream.Position += sizeof(byte) * padding[j]; break; case TypeCode.Int16: bw.Write(row.Field <short>(j)); bw.BaseStream.Position += sizeof(short) * padding[j]; break; case TypeCode.UInt16: bw.Write(row.Field <ushort>(j)); bw.BaseStream.Position += sizeof(ushort) * padding[j]; break; case TypeCode.Int32: bw.WriteInt32(row.Field <int>(j), bits?[j]); bw.BaseStream.Position += sizeof(int) * padding[j]; break; case TypeCode.UInt32: bw.WriteUInt32(row.Field <uint>(j), bits?[j]); bw.BaseStream.Position += sizeof(uint) * padding[j]; break; case TypeCode.Int64: bw.WriteInt64(row.Field <long>(j), bits?[j]); bw.BaseStream.Position += sizeof(long) * padding[j]; break; case TypeCode.UInt64: bw.WriteUInt64(row.Field <ulong>(j), bits?[j]); bw.BaseStream.Position += sizeof(ulong) * padding[j]; break; case TypeCode.Single: bw.Write(row.Field <float>(j)); bw.BaseStream.Position += sizeof(float) * padding[j]; break; case TypeCode.String: if (entry.Header.HasOffsetTable) { bw.Write(Encoding.UTF8.GetBytes(row.Field <string>(j))); bw.Write((byte)0); } else { bw.Write(st.Write(row.Field <string>(j), duplicates)); } break; default: throw new Exception($"Unknown TypeCode {columnTypes[j].ToString()}"); } } //Calculate and write the row's padding entry.Header.WriteRecordPadding(bw, entry, offset); //Store the offset map if (entry.Header.HasOffsetTable) { OffsetMap.Add(new Tuple <int, short>((int)offset, (short)(bw.BaseStream.Position - offset))); } //WDB5 + OffsetMap without SecondIndex for the last row pads to next mod 4 if (entry.Header.IsTypeOf <WDB5>() && entry.Header.HasOffsetTable && !entry.Header.HasSecondIndex && row == lastrow) { long rem = bw.BaseStream.Position % 4; bw.BaseStream.Position += (rem == 0 ? 0 : (4 - rem)); } } }
private static void WriteIntoFile <T>(DBEntry <T> entry, BinaryWriter bw, IEnumerable <T> rows, ref StringTable st) where T : class { TypeCode[] columnTypes = entry.TableStructure.Select(x => Type.GetTypeCode(x.PropertyType)).ToArray(); uint[] padding = entry.Padding.ToArray(); FieldStructureEntry[] bits = entry.GetBits(); bool duplicates = false; duplicates |= (entry.Header.IsTypeOf <WDB2>() && entry.Header.MaxId != 0); //WDB2 with MaxId > 0 allows duplicates duplicates |= (entry.Header.IsTypeOf <WCH7>() && entry.Header.UnknownWCH7 != 0); //WCH7 with Unknown > 0 allows duplicates T lastrow = rows.Last(); foreach (T row in rows) { long offset = bw.BaseStream.Position; for (int j = 0; j < entry.TableStructure.Length; j++) { PropertyInfo field = entry.TableStructure[j]; if (field.GetAttribute <DBKeyAttribute>()?.AutoGenerated == true) //Autogenerated so skip { continue; } if (entry.Header.HasIndexTable && j == 0) //Inline Id so skip { continue; } if (entry.Header.IsTypeOf <WCH5>() && entry.Header.HasOffsetTable && j == 0) //Inline Id so skip { continue; } if (entry.Header.IsTypeOf <WDB6>() && (bits?[j].CommonDataColumn ?? false)) { continue; } if (columnTypes[j] == TypeCode.Object) { if (field.PropertyType.IsArray) { Array array = (Array)field.GetValue(row); for (int x = 0; x < array.Length; x++) { WriteValue(bw, entry, array.GetValue(x), padding[j], st, bits?[j], duplicates); } } else if (field.PropertyType == typeof(LocalizedString)) { ((LocalizedString)field.GetValue(row)).Write(bw, st, duplicates); } else { throw new Exception($"Unknown Type {field.PropertyType.Name}."); } } else { WriteValue(bw, entry, field.GetValue(row), padding[j], st, bits?[j], duplicates); } } //Calculate and write the row's padding entry.Header.WriteRecordPadding(bw, entry, offset); //Store the offset map if (entry.Header.HasOffsetTable) { OffsetMap.Add(new Tuple <int, short>((int)offset, (short)(bw.BaseStream.Position - offset))); } //WDB5 + OffsetMap without SecondIndex for the last row pads to next mod 4 if (entry.Header.IsTypeOf <WDB5>() && entry.Header.HasOffsetTable && !entry.Header.HasSecondIndex && row == lastrow) { long rem = bw.BaseStream.Position % 4; bw.BaseStream.Position += (rem == 0 ? 0 : (4 - rem)); } } }
private void ReadIntoTable(ref DBEntry entry, BinaryReader dbReader, Dictionary <int, string> StringTable) { if (entry.Header.RecordCount == 0) { return; } TypeCode[] columnTypes = entry.Data.Columns.Cast <DataColumn>().Select(x => Type.GetTypeCode(x.DataType)).ToArray(); int[] padding = entry.TableStructure.Padding.ToArray(); FieldStructureEntry[] bits = entry.GetBits(); uint recordsize = entry.Header.RecordSize + (uint)(entry.Header.HasIndexTable ? 4 : 0); int recordcount = Math.Max(entry.Header.OffsetLengths.Length, (int)entry.Header.RecordCount); entry.Data.BeginLoadData(); for (uint i = 0; i < recordcount; i++) { //Offset map has variable record lengths if (entry.Header.HasOffsetTable) { recordsize = (uint)entry.Header.OffsetLengths[i]; } //Store start position long offset = dbReader.BaseStream.Position; //Create row and add data var row = entry.Data.NewRow(); for (int j = 0; j < entry.Data.Columns.Count; j++) { if (entry.Data.Columns[j].ExtendedProperties.ContainsKey(AUTO_GENERATED)) { row.SetField(entry.Data.Columns[j], entry.Data.Rows.Count + 1); continue; } switch (columnTypes[j]) { case TypeCode.Boolean: row.SetField(entry.Data.Columns[j], dbReader.ReadBoolean()); dbReader.BaseStream.Position += sizeof(bool) * padding[j]; break; case TypeCode.SByte: row.SetField(entry.Data.Columns[j], dbReader.ReadSByte()); dbReader.BaseStream.Position += sizeof(sbyte) * padding[j]; break; case TypeCode.Byte: row.SetField(entry.Data.Columns[j], dbReader.ReadByte()); dbReader.BaseStream.Position += sizeof(byte) * padding[j]; break; case TypeCode.Int16: row.SetField(entry.Data.Columns[j], dbReader.ReadInt16()); dbReader.BaseStream.Position += sizeof(short) * padding[j]; break; case TypeCode.UInt16: row.SetField(entry.Data.Columns[j], dbReader.ReadUInt16()); dbReader.BaseStream.Position += sizeof(ushort) * padding[j]; break; case TypeCode.Int32: row.SetField(entry.Data.Columns[j], dbReader.ReadInt32(bits[j])); dbReader.BaseStream.Position += sizeof(int) * padding[j]; break; case TypeCode.UInt32: row.SetField(entry.Data.Columns[j], dbReader.ReadUInt32(bits[j])); dbReader.BaseStream.Position += sizeof(uint) * padding[j]; break; case TypeCode.Int64: row.SetField(entry.Data.Columns[j], dbReader.ReadInt64(bits[j])); dbReader.BaseStream.Position += sizeof(long) * padding[j]; break; case TypeCode.UInt64: row.SetField(entry.Data.Columns[j], dbReader.ReadUInt64(bits[j])); dbReader.BaseStream.Position += sizeof(ulong) * padding[j]; break; case TypeCode.Single: row.SetField(entry.Data.Columns[j], dbReader.ReadSingle()); dbReader.BaseStream.Position += sizeof(float) * padding[j]; break; case TypeCode.String: if (entry.Header.IsTypeOf <WDB>() || entry.Header.HasOffsetTable) { row.SetField(entry.Data.Columns[j], dbReader.ReadStringNull()); } else { int stindex = dbReader.ReadInt32(); try { row.SetField(entry.Data.Columns[j], StringTable[stindex]); } catch { row.SetField(entry.Data.Columns[j], "String not found"); ErrorMessage = "Strings not found in string table"; } } break; default: dbReader.BaseStream.Position += 4; break; } } entry.Data.Rows.Add(row); //Scrub to the end of the record if (dbReader.BaseStream.Position - offset < recordsize) { dbReader.BaseStream.Position += (recordsize - (dbReader.BaseStream.Position - offset)); } else if (dbReader.BaseStream.Position - offset > recordsize) { throw new Exception("Definition exceeds record size"); } } entry.Data.EndLoadData(); }
private static void ReadIntoTable <T>(ref DBEntry <T> entry, BinaryReader dbReader, Dictionary <int, string> stringtable) where T : class { if (entry.Header.RecordCount == 0) { return; } TypeCode[] columnTypes = entry.TableStructure.Select(x => Type.GetTypeCode(x.PropertyType)).ToArray(); uint[] padding = entry.Padding.ToArray(); FieldStructureEntry[] bits = entry.GetBits(); int recordcount = Math.Max(entry.Header.OffsetLengths.Length, (int)entry.Header.RecordCount); uint recordsize = entry.Header.RecordSize + (uint)(entry.Header.HasIndexTable ? 4 : 0); if (entry.Header.CommonDataTableSize > 0) { recordsize = ((WDB6)entry.Header).RawRecordSize; } for (uint i = 0; i < recordcount; i++) { //Offset map has variable record lengths if (entry.Header.HasOffsetTable || entry.Header.IsTypeOf <HTFX>()) { recordsize = (uint)entry.Header.OffsetLengths[i]; } //Store start position long offset = dbReader.BaseStream.Position; //Create row and add data T row = (T)Activator.CreateInstance(typeof(T)); for (int j = 0; j < entry.TableStructure.Length; j++) { PropertyInfo field = entry.TableStructure[j]; if (entry.TableStructure[j].GetAttribute <DBKeyAttribute>()?.AutoGenerated == true) { field.SetValue(row, entry.Rows.Count + 1); continue; } if (columnTypes[j] == TypeCode.Object) { if (field.PropertyType.IsArray) { uint arraySize = field.GetAttribute <DBFieldAttribute>().ArraySize; TypeCode type = Type.GetTypeCode(field.PropertyType.GetElementType()); Array array = Array.CreateInstance(field.PropertyType.GetElementType(), arraySize); for (int x = 0; x < arraySize; x++) { array.SetValue(ReadValue(dbReader, entry, type, padding[j], stringtable, bits[j]), x); } field.SetValue(row, array); } else if (field.PropertyType == typeof(LocalizedString)) { LocalizedString locale = new LocalizedString(entry.Build); locale.Load(dbReader, stringtable); field.SetValue(row, locale); } else { throw new Exception($"Unknown Type {field.PropertyType.Name}"); } } else { field.SetValue(row, ReadValue(dbReader, entry, columnTypes[j], padding[j], stringtable, bits[j])); } } entry.Rows.Add(row); //Scrub to the end of the record if (dbReader.BaseStream.Position - offset < recordsize) { dbReader.BaseStream.Position += (recordsize - (dbReader.BaseStream.Position - offset)); } else if (dbReader.BaseStream.Position - offset > recordsize) { throw new Exception("Definition exceeds record size"); } } }