private void InitializeUtfSchema(Stream sourceStream, Stream tableDataStream, long schemaOffset) { var header = _utfHeader; var rows = _rows; var baseOffset = _offset; for (uint i = 0; i < header.RowCount; i++) { var currentOffset = schemaOffset; var row = new Dictionary <string, UtfField>(); rows[i] = row; long currentRowOffset = 0; long currentRowBase = header.PerRowDataOffset + header.RowSize * i; for (var j = 0; j < header.FieldCount; j++) { var field = new UtfField { Type = tableDataStream.PeekByte(currentOffset) }; long nameOffset = tableDataStream.PeekInt32BE(currentOffset + 1); field.Name = tableDataStream.PeekZeroEndedStringAsAscii(header.StringTableOffset + nameOffset); var union = new NumericUnion(); var constrainedStorage = (ColumnStorage)(field.Type & (byte)ColumnStorage.Mask); var constrainedType = (ColumnType)(field.Type & (byte)ColumnType.Mask); switch (constrainedStorage) { case ColumnStorage.Constant: case ColumnStorage.Constant2: var constantOffset = currentOffset + 5; long dataOffset; switch (constrainedType) { case ColumnType.String: dataOffset = tableDataStream.PeekInt32BE(constantOffset); field.StringValue = tableDataStream.PeekZeroEndedStringAsAscii(header.StringTableOffset + dataOffset); currentOffset += 4; break; case ColumnType.Int64: union.S64 = tableDataStream.PeekInt64BE(constantOffset); currentOffset += 8; break; case ColumnType.UInt64: union.U64 = tableDataStream.PeekUInt64BE(constantOffset); currentOffset += 8; break; case ColumnType.Data: dataOffset = tableDataStream.PeekUInt32BE(constantOffset); long dataSize = tableDataStream.PeekUInt32BE(constantOffset + 4); field.Offset = baseOffset + header.ExtraDataOffset + dataOffset; field.Size = dataSize; // don't think this is encrypted, need to check field.DataValue = sourceStream.PeekBytes(field.Offset, (int)dataSize); currentOffset += 8; break; case ColumnType.Double: union.R64 = tableDataStream.PeekDoubleBE(constantOffset); currentOffset += 8; break; case ColumnType.Single: union.R32 = tableDataStream.PeekSingleBE(constantOffset); currentOffset += 4; break; case ColumnType.Int32: union.S32 = tableDataStream.PeekInt32BE(constantOffset); currentOffset += 4; break; case ColumnType.UInt32: union.U32 = tableDataStream.PeekUInt32BE(constantOffset); currentOffset += 4; break; case ColumnType.Int16: union.S16 = tableDataStream.PeekInt16BE(constantOffset); currentOffset += 2; break; case ColumnType.UInt16: union.U16 = tableDataStream.PeekUInt16BE(constantOffset); currentOffset += 2; break; case ColumnType.SByte: union.S8 = tableDataStream.PeekSByte(constantOffset); currentOffset += 1; break; case ColumnType.Byte: union.U8 = tableDataStream.PeekByte(constantOffset); currentOffset += 1; break; default: throw new FormatException($"Unknown column type at offset: 0x{currentOffset:x8}"); } break; case ColumnStorage.PerRow: // read the constant depending on the type long rowDataOffset; switch (constrainedType) { case ColumnType.String: rowDataOffset = tableDataStream.PeekUInt32BE(currentRowBase + currentRowOffset); field.StringValue = tableDataStream.PeekZeroEndedStringAsAscii(header.StringTableOffset + rowDataOffset); currentRowOffset += 4; break; case ColumnType.Int64: union.S64 = tableDataStream.PeekInt64BE(currentRowBase + currentRowOffset); currentRowOffset += 8; break; case ColumnType.UInt64: union.U64 = tableDataStream.PeekUInt64BE(currentRowBase + currentRowOffset); currentRowOffset += 8; break; case ColumnType.Data: rowDataOffset = tableDataStream.PeekUInt32BE(currentRowBase + currentRowOffset); long rowDataSize = tableDataStream.PeekUInt32BE(currentRowBase + currentRowOffset + 4); field.Offset = baseOffset + header.ExtraDataOffset + rowDataOffset; field.Size = rowDataSize; // don't think this is encrypted field.DataValue = sourceStream.PeekBytes(field.Offset, (int)rowDataSize); currentRowOffset += 8; break; case ColumnType.Double: union.R64 = tableDataStream.PeekDoubleBE(currentRowBase + currentRowOffset); currentRowOffset += 8; break; case ColumnType.Single: union.R32 = tableDataStream.PeekSingleBE(currentRowBase + currentRowOffset); currentRowOffset += 4; break; case ColumnType.Int32: union.S32 = tableDataStream.PeekInt32BE(currentRowBase + currentRowOffset); currentRowOffset += 4; break; case ColumnType.UInt32: union.U32 = tableDataStream.PeekUInt32BE(currentRowBase + currentRowOffset); currentRowOffset += 4; break; case ColumnType.Int16: union.S16 = tableDataStream.PeekInt16BE(currentRowBase + currentRowOffset); currentRowOffset += 2; break; case ColumnType.UInt16: union.U16 = tableDataStream.PeekUInt16BE(currentRowBase + currentRowOffset); currentRowOffset += 2; break; case ColumnType.SByte: union.S8 = tableDataStream.PeekSByte(currentRowBase + currentRowOffset); currentRowOffset += 1; break; case ColumnType.Byte: union.U8 = tableDataStream.PeekByte(currentRowBase + currentRowOffset); currentRowOffset += 1; break; default: throw new FormatException($"Unknown column type at offset: 0x{currentOffset:x8}"); } field.ConstrainedType = (ColumnType)field.Type; break; default: throw new FormatException($"Unknown column storage at offset: 0x{currentOffset:x8}"); } // Union polyfill field.ConstrainedType = constrainedType; switch (constrainedType) { case ColumnType.String: case ColumnType.Data: break; default: field.NumericValue = union; break; } row.Add(field.Name, field); currentOffset += 5; // sizeof(CriField.Type + CriField.NameOffset) } } }
public void SetValue(object value) { ColumnType type; var union = new NumericUnion(); if (value is byte) { type = ColumnType.Byte; union.U8 = (byte)value; } else if (value is sbyte) { type = ColumnType.SByte; union.S8 = (sbyte)value; } else if (value is ushort) { type = ColumnType.UInt16; union.U16 = (ushort)value; } else if (value is short) { type = ColumnType.Int16; union.S16 = (short)value; } else if (value is uint) { type = ColumnType.UInt32; union.U32 = (uint)value; } else if (value is int) { type = ColumnType.Int32; union.S32 = (int)value; } else if (value is ulong) { type = ColumnType.UInt64; union.U64 = (ulong)value; } else if (value is long) { type = ColumnType.Int64; union.S64 = (long)value; } else if (value is string) { type = ColumnType.String; StringValue = (string)value; } else if (value is byte[]) { type = ColumnType.Data; DataValue = (byte[])value; } else { throw new ArgumentException("Unsupported argument type.", nameof(value)); } ConstrainedType = type; Type = (byte)type; switch (type) { case ColumnType.String: case ColumnType.Data: break; default: NumericValue = union; break; } }