/// <summary> /// Reads field definitions. /// </summary> protected FieldDef[] ReadFieldDefs(BinaryReader reader, byte[] buffer, int fieldCount) { FieldDef[] fieldDefs = new FieldDef[fieldCount]; for (int i = 0; i < fieldCount; i++) { ReadData(reader, buffer, 0, FieldDefSize, true); if (ScadaUtils.CRC16(buffer, 0, FieldDefSize - 2) != BitConverter.ToUInt16(buffer, FieldDefSize - 2)) { throw new ScadaException("Field definition CRC error."); } int index = 0; int nameLength = buffer[index++]; string fieldName = Encoding.ASCII.GetString(buffer, index, nameLength); index += MaxFieldNameLength; fieldDefs[i] = new FieldDef( fieldName, GetByte(buffer, ref index), GetBool(buffer, ref index)); } return(fieldDefs); }
/// <summary> /// Copies the event to the buffer. /// </summary> protected void CopyEvent(Event ev, bool textExists, bool dataExists, byte[] buffer, out int textSize, out int dataSize) { textSize = ev.Text == null ? 0 : Math.Min(ev.Text.Length, MaxTextSize); dataSize = ev.Data == null ? 0 : Math.Min(ev.Data.Length, MaxDataSize); int index = 0; CopyUInt16(BlockMarker, buffer, ref index); CopyInt64(ev.EventID, buffer, ref index); CopyTime(ev.Timestamp, buffer, ref index); CopyBool(ev.Hidden, buffer, ref index); CopyInt32(ev.CnlNum, buffer, ref index); CopyInt32(ev.OutCnlNum, buffer, ref index); CopyInt32(ev.ObjNum, buffer, ref index); CopyInt32(ev.DeviceNum, buffer, ref index); CopyDouble(ev.PrevCnlVal, buffer, ref index); CopyUInt16((ushort)ev.PrevCnlStat, buffer, ref index); CopyDouble(ev.CnlVal, buffer, ref index); CopyUInt16((ushort)ev.CnlStat, buffer, ref index); CopyInt32(ev.Severity, buffer, ref index); CopyBool(ev.AckRequired, buffer, ref index); CopyBool(ev.Ack, buffer, ref index); CopyTime(ev.AckTimestamp, buffer, ref index); CopyInt32(ev.AckUserID, buffer, ref index); CopyByte((byte)ev.TextFormat, buffer, ref index); CopyBool(textExists, buffer, ref index); CopyByte((byte)textSize, buffer, ref index); CopyBool(dataExists, buffer, ref index); CopyByte((byte)dataSize, buffer, ref index); Array.Clear(buffer, index, EventSize - index - 2); ushort crc = ScadaUtils.CRC16(buffer, 0, EventSize - 2); CopyUInt16(crc, buffer, EventSize - 2); }
/// <summary> /// Writes the field definintion using the specified writer. /// </summary> protected void WriteFieldDef(BinaryWriter writer, FieldDef fieldDef, byte[] buffer) { Array.Clear(buffer, 0, FieldDefSize); int nameLength = fieldDef.Name.Length; buffer[0] = (byte)nameLength; Encoding.ASCII.GetBytes(fieldDef.Name).CopyTo(buffer, 1); buffer[MaxFieldNameLength + 1] = (byte)fieldDef.DataType; buffer[MaxFieldNameLength + 2] = (byte)(fieldDef.AllowNull ? 1 : 0); ushort crc = ScadaUtils.CRC16(buffer, 0, FieldDefSize - 2); CopyUInt16(crc, buffer, FieldDefSize - 2); writer.Write(buffer, 0, FieldDefSize); }
/// <summary> /// Writes the event acknowledgement information in a file or stream. /// </summary> public void WriteEventAck(Event ev) { if (ev == null) { throw new ArgumentNullException(nameof(ev)); } if (ev.Position < 0) { throw new ScadaException("Event position is undefined."); } Stream stream = null; BinaryReader reader = null; BinaryWriter writer = null; try { stream = Stream ?? new FileStream(FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite); reader = new BinaryReader(stream, Encoding.UTF8, Stream != null); writer = new BinaryWriter(stream, Encoding.UTF8, Stream != null); // read the existing event into the buffer byte[] buffer = new byte[EventSize]; if (stream.Seek(ev.Position, SeekOrigin.Begin) == ev.Position && ReadEvent(reader, buffer, out int index) && GetInt64(buffer, ref index) == ev.EventID) { // update the event in the buffer index = 58; CopyBool(ev.Ack, buffer, ref index); CopyTime(ev.AckTimestamp, buffer, ref index); CopyInt32(ev.AckUserID, buffer, ref index); ushort crc = ScadaUtils.CRC16(buffer, 0, EventSize - 2); CopyUInt16(crc, buffer, EventSize - 2); // write the updated buffer stream.Seek(ev.Position, SeekOrigin.Begin); writer.Write(buffer); } } finally { reader?.Close(); writer?.Close(); } }
/// <summary> /// Reads a row to the buffer. /// </summary> protected void ReadRowToBuffer(BinaryReader reader, ref byte[] buffer) { if (reader.ReadUInt16() != BlockMarker) { throw new ScadaException("Row marker not found."); } int rowDataSize = reader.ReadInt32(); int fullRowSize = rowDataSize + 6; ResizeBuffer(ref buffer, fullRowSize, 2); ReadData(reader, buffer, 6, rowDataSize, true); // copy values to the buffer to calculate CRC CopyUInt16(BlockMarker, buffer, 0); CopyInt32(rowDataSize, buffer, 2); if (ScadaUtils.CRC16(buffer, 0, fullRowSize - 2) != BitConverter.ToUInt16(buffer, fullRowSize - 2)) { throw new ScadaException("Row CRC error."); } }
/// <summary> /// Reads an event into the buffer and validates the event. /// </summary> protected bool ReadEvent(BinaryReader reader, byte[] buffer, out int index) { index = 0; if (reader.Read(buffer, 0, EventSize) == EventSize) { if (GetUInt16(buffer, ref index) != BlockMarker) { throw new ScadaException("Event marker not found."); } if (ScadaUtils.CRC16(buffer, 0, EventSize - 2) != BitConverter.ToUInt16(buffer, EventSize - 2)) { throw new ScadaException("Event CRC error."); } return(true); } else { return(false); } }
/// <summary> /// Updates the configuration database by writing data of the specified table. /// </summary> public void Update(IBaseTable baseTable) { if (baseTable == null) { throw new ArgumentNullException(nameof(baseTable)); } Stream stream; BinaryWriter writer = null; try { stream = Stream ?? new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); writer = new BinaryWriter(stream, Encoding.UTF8, Stream != null); // write header writer.Write(TableType.BaseTable); writer.Write(MajorVersion); writer.Write(MinorVersion); PropertyDescriptorCollection props = TypeDescriptor.GetProperties(baseTable.ItemType); int fieldCount = Math.Min(props.Count, ushort.MaxValue); writer.Write((ushort)fieldCount); writer.Write(ReserveBuffer, 0, 12); if (fieldCount > 0) { // create and write field definitions FieldDef[] fieldDefs = new FieldDef[fieldCount]; byte[] buffer = new byte[FieldDefSize]; for (int i = 0; i < fieldCount; i++) { PropertyDescriptor prop = props[i]; bool isNullable = prop.PropertyType.IsNullable(); FieldDef fieldDef = new FieldDef( prop.Name, isNullable ? Nullable.GetUnderlyingType(prop.PropertyType) : prop.PropertyType, isNullable || prop.PropertyType.IsClass); fieldDefs[i] = fieldDef; WriteFieldDef(writer, fieldDef, buffer); } // write rows byte[][] rowData = new byte[fieldCount][]; bool[] isNullArr = new bool[fieldCount]; foreach (object item in baseTable.EnumerateItems()) { // get row data and size int rowDataSize = 2; // CRC for (int i = 0; i < fieldCount; i++) { object value = props[i].GetValue(item); if (value == null) { isNullArr[i] = true; } else { FieldDef fieldDef = fieldDefs[i]; byte[] fieldData = GetFieldData(fieldDef, value, rowData[i]); rowData[i] = fieldData; isNullArr[i] = false; rowDataSize += (fieldDef.DataSize <= 0 ? 2 : 0) + fieldData.Length; } rowDataSize++; // null flag } // copy row data to the buffer int fullRowSize = rowDataSize + 6; int copyIndex = 0; ResizeBuffer(ref buffer, fullRowSize, 2); CopyUInt16(BlockMarker, buffer, ref copyIndex); CopyInt32(rowDataSize, buffer, ref copyIndex); for (int i = 0; i < fieldCount; i++) { if (isNullArr[i]) { buffer[copyIndex++] = 1; } else { buffer[copyIndex++] = 0; FieldDef fieldDef = fieldDefs[i]; byte[] fieldData = rowData[i]; if (fieldDef.DataSize <= 0) { CopyUInt16((ushort)fieldData.Length, buffer, ref copyIndex); } fieldData.CopyTo(buffer, copyIndex); copyIndex += fieldData.Length; } } ushort crc = ScadaUtils.CRC16(buffer, 0, fullRowSize - 2); CopyUInt16(crc, buffer, fullRowSize - 2); // write row data writer.Write(buffer, 0, fullRowSize); } } } finally { writer?.Close(); } }