public void Build(Stream s, Endianness endian = Endianness.BigEndian) { DataChunk stringTable = new DataChunk(); stringTable.Add("<NULL>"); DataChunk dataTable = new DataChunk(); ushort colcount = (ushort)Columns.Count; ushort rowwidth = CalculateRowWidth(); uint rowcount = (uint)Rows.Count; long baseOffset = s.Position; s.WriteUInt32(0x46545540, Endianness.LittleEndian); s.WriteUInt32(0); // size of this chunk, fill in later long offset = s.Position; s.WriteUInt32(0); // rowsLocation s.WriteUInt32(0); // stringTableLocation s.WriteUInt32(0); // dataTableLocation s.WriteUInt32(stringTable.Add(Name), endian); s.WriteUInt16(colcount, endian); s.WriteUInt16(rowwidth, endian); s.WriteUInt32(rowcount, endian); for (int i = 0; i < colcount; ++i) { ColumnData col = Columns[i]; s.WriteUInt8(col.Type); s.WriteUInt32(stringTable.Add(col.Name), endian); if ((col.Type & utf_tab_sharp.UtfTab.COLUMN_STORAGE_MASK) == utf_tab_sharp.UtfTab.COLUMN_STORAGE_CONSTANT) { switch (col.Type & utf_tab_sharp.UtfTab.COLUMN_TYPE_MASK) { case utf_tab_sharp.UtfTab.COLUMN_TYPE_STRING: s.WriteUInt32(stringTable.Add((string)col.Data), endian); break; case utf_tab_sharp.UtfTab.COLUMN_TYPE_8BYTE: s.WriteUInt64((ulong)col.Data, endian); break; case utf_tab_sharp.UtfTab.COLUMN_TYPE_DATA: byte[] b = (byte[])col.Data; uint dataOffset = dataTable.Add(b); uint dataSize = (uint)b.LongLength; s.WriteUInt32(dataOffset, endian); s.WriteUInt32(dataSize, endian); break; case utf_tab_sharp.UtfTab.COLUMN_TYPE_FLOAT: s.WriteUInt32(BitConverter.ToUInt32(BitConverter.GetBytes(((float)col.Data)), 0), endian); break; case utf_tab_sharp.UtfTab.COLUMN_TYPE_4BYTE2: case utf_tab_sharp.UtfTab.COLUMN_TYPE_4BYTE: s.WriteUInt32((uint)col.Data, endian); break; case utf_tab_sharp.UtfTab.COLUMN_TYPE_2BYTE2: case utf_tab_sharp.UtfTab.COLUMN_TYPE_2BYTE: s.WriteUInt16((ushort)col.Data, endian); break; case utf_tab_sharp.UtfTab.COLUMN_TYPE_1BYTE2: case utf_tab_sharp.UtfTab.COLUMN_TYPE_1BYTE: s.WriteByte((byte)col.Data); break; default: throw new Exception("unknown type for constant"); } } } uint rowsLocation = (uint)(s.Position - offset); for (long i = 0; i < rowcount; ++i) { var row = Rows[(int)i]; for (int j = 0; j < colcount; ++j) { byte type = Columns[j].Type; var cell = row.Cells[j]; switch ((type & utf_tab_sharp.UtfTab.COLUMN_STORAGE_MASK)) { case utf_tab_sharp.UtfTab.COLUMN_STORAGE_PERROW: switch (type & utf_tab_sharp.UtfTab.COLUMN_TYPE_MASK) { case utf_tab_sharp.UtfTab.COLUMN_TYPE_STRING: s.WriteUInt32(stringTable.Add((string)cell.Data), endian); break; case utf_tab_sharp.UtfTab.COLUMN_TYPE_8BYTE: s.WriteUInt64((ulong)cell.Data, endian); break; case utf_tab_sharp.UtfTab.COLUMN_TYPE_DATA: byte[] b = (byte[])cell.Data; uint dataOffset = dataTable.Add(b); uint dataSize = (uint)b.LongLength; s.WriteUInt32(dataOffset, endian); s.WriteUInt32(dataSize, endian); break; case utf_tab_sharp.UtfTab.COLUMN_TYPE_FLOAT: s.WriteUInt32(BitConverter.ToUInt32(BitConverter.GetBytes(((float)cell.Data)), 0), endian); break; case utf_tab_sharp.UtfTab.COLUMN_TYPE_4BYTE2: case utf_tab_sharp.UtfTab.COLUMN_TYPE_4BYTE: s.WriteUInt32((uint)cell.Data, endian); break; case utf_tab_sharp.UtfTab.COLUMN_TYPE_2BYTE2: case utf_tab_sharp.UtfTab.COLUMN_TYPE_2BYTE: s.WriteUInt16((ushort)cell.Data, endian); break; case utf_tab_sharp.UtfTab.COLUMN_TYPE_1BYTE2: case utf_tab_sharp.UtfTab.COLUMN_TYPE_1BYTE: s.WriteByte((byte)cell.Data); break; default: throw new Exception("unknown type for value"); } break; case utf_tab_sharp.UtfTab.COLUMN_STORAGE_CONSTANT: case utf_tab_sharp.UtfTab.COLUMN_STORAGE_ZERO: break; default: throw new Exception("unknown storage for value"); } } } var stringTableStream = stringTable.GetData(); stringTableStream.Position = 0; uint stringTableLocation = (uint)(s.Position - offset); StreamUtils.CopyStream(stringTableStream, s); s.WriteAlign(8, 0, offset); var dataTableStream = dataTable.GetData(); dataTableStream.Position = 0; uint dataTableLocation = (uint)(s.Position - offset); StreamUtils.CopyStream(dataTableStream, s); s.WriteAlign(8, 0, offset); uint size = (uint)(s.Position - offset); long endpos = s.Position; s.Position = baseOffset + 4; s.WriteUInt32(size, endian); s.WriteUInt32(rowsLocation, endian); s.WriteUInt32(stringTableLocation, endian); s.WriteUInt32(dataTableLocation, endian); s.Position = endpos; return; }