private void WriteIntoFile(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.GetPadding(); var bits = entry.GetBits(); bool duplicates = false; if (entry.Header.IsTypeOf <WDB2>() && entry.Header.MaxId != 0) //WDB2 with MaxId > 0 allows duplicates { duplicates = true; } else if (entry.Header.IsTypeOf <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; } if (entry.Header.IsTypeOf <WDB6>() && (bits?[j].CommonDataColumn ?? false)) { continue; } switch (columnTypes[j]) { case TypeCode.SByte: bw.Write(row.Field <sbyte>(j)); break; case TypeCode.Byte: bw.Write(row.Field <byte>(j)); break; case TypeCode.Int16: bw.Write(row.Field <short>(j)); break; case TypeCode.UInt16: bw.Write(row.Field <ushort>(j)); break; case TypeCode.Int32: bw.WriteInt32(row.Field <int>(j), bits?[j]); break; case TypeCode.UInt32: bw.WriteUInt32(row.Field <uint>(j), bits?[j]); break; case TypeCode.Int64: bw.WriteInt64(row.Field <long>(j), bits?[j]); break; case TypeCode.UInt64: bw.WriteUInt64(row.Field <ulong>(j), bits?[j]); break; case TypeCode.Single: bw.Write(row.Field <float>(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()}"); } if (columnTypes[j] != TypeCode.String) { bw.BaseStream.Position += padding[j]; } } //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)); } } }
public 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.GetPadding(); 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.InternalRecordSize > 0) { recordsize = entry.Header.InternalRecordSize; } entry.Data.BeginLoadData(); for (uint i = 0; i < recordcount; i++) { //Offset map has variable record lengths if (entry.Header.IsTypeOf <HTFX>() || 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()); break; case TypeCode.SByte: row.SetField(entry.Data.Columns[j], dbReader.ReadSByte()); break; case TypeCode.Byte: row.SetField(entry.Data.Columns[j], dbReader.ReadByte()); break; case TypeCode.Int16: row.SetField(entry.Data.Columns[j], dbReader.ReadInt16()); break; case TypeCode.UInt16: row.SetField(entry.Data.Columns[j], dbReader.ReadUInt16()); break; case TypeCode.Int32: row.SetField(entry.Data.Columns[j], dbReader.ReadInt32(bits[j])); break; case TypeCode.UInt32: row.SetField(entry.Data.Columns[j], dbReader.ReadUInt32(bits[j])); break; case TypeCode.Int64: row.SetField(entry.Data.Columns[j], dbReader.ReadInt64(bits[j])); break; case TypeCode.UInt64: row.SetField(entry.Data.Columns[j], dbReader.ReadUInt64(bits[j])); break; case TypeCode.Single: row.SetField(entry.Data.Columns[j], dbReader.ReadSingle()); break; case TypeCode.String: if (entry.Header.IsTypeOf <WDB>() || entry.Header.IsTypeOf <HTFX>() || entry.Header.HasOffsetTable) { row.SetField(entry.Data.Columns[j], dbReader.ReadStringNull()); } else { int stindex = dbReader.ReadInt32(); if (StringTable.ContainsKey(stindex)) { row.SetField(entry.Data.Columns[j], StringTable[stindex]); } else { row.SetField(entry.Data.Columns[j], "String not found"); ErrorMessage = "Strings not found in string table"; } } break; default: dbReader.BaseStream.Position += 4; break; } dbReader.BaseStream.Position += padding[j]; } 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(); }