/////////////////////////////////////////////////////////////////////// #region Public Methods /// <summary> /// Reads a value of the specified type from the buffer. /// </summary> /// <param name="buffer">The buffer containing binary data to read.</param> /// <param name="dictionary">The type dictionary that contains a complex type identified with the type name.</param> /// <param name="typeName">The name of the type that describes the data.</param> /// <returns>A structured represenation of the data in the buffer.</returns> public TsCCpxComplexValue Read(byte[] buffer, TypeDictionary dictionary, string typeName) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (dictionary == null) { throw new ArgumentNullException("dictionary"); } if (typeName == null) { throw new ArgumentNullException("typeName"); } TsCCpxContext context = InitializeContext(buffer, dictionary, typeName); TsCCpxComplexValue complexValue = null; int bytesRead = ReadType(context, out complexValue); if (bytesRead == 0) { throw new TsCCpxInvalidSchemaException(String.Format("Type '{0}' not found in dictionary.", typeName)); } return(complexValue); }
/// <summary> /// Reads a complex type from the buffer. /// </summary> private int ReadField(TsCCpxContext context, TypeReference field, out object fieldValue) { fieldValue = null; foreach (TypeDescription type in context.Dictionary.TypeDescription) { if (type.TypeID == field.TypeID) { context.Type = type; if (type.DefaultBigEndianSpecified) { context.BigEndian = type.DefaultBigEndian; } if (type.DefaultCharWidthSpecified) { context.CharWidth = type.DefaultCharWidth; } if (type.DefaultStringEncoding != null) { context.StringEncoding = type.DefaultStringEncoding; } if (type.DefaultFloatFormat != null) { context.FloatFormat = type.DefaultFloatFormat; } break; } } if (context.Type == null) { throw new TsCCpxInvalidSchemaException(String.Format("Reference type '{0}' not found.", field.TypeID)); } TsCCpxComplexValue complexValue = null; int bytesRead = ReadType(context, out complexValue); if (bytesRead == 0) { fieldValue = null; } else { fieldValue = complexValue; } return(bytesRead); }
/// <summary> /// Finds the integer value referenced by the field name. /// </summary> private void WriteReference( TsCCpxContext context, FieldType field, int fieldIndex, TsCCpxComplexValue[] fieldValues, string fieldName, int count ) { TsCCpxComplexValue namedValue = null; if (fieldName.Length == 0) { if (fieldIndex > 0 && fieldIndex - 1 < fieldValues.Length) { namedValue = (TsCCpxComplexValue)fieldValues[fieldIndex - 1]; } } else { for (int ii = 0; ii < fieldIndex; ii++) { namedValue = (TsCCpxComplexValue)fieldValues[ii]; if (namedValue.Name == fieldName) { break; } namedValue = null; } } if (namedValue == null) { throw new TsCCpxInvalidSchemaException(String.Format("Referenced field not found ({0}).", fieldName)); } if (context.Buffer == null) { namedValue.Value = count; } if (!count.Equals(namedValue.Value)) { throw new TsCCpxInvalidDataToWriteException("Reference field value and the actual array length are not equal."); } }
/// <summary> /// Finds the integer value referenced by the field name. /// </summary> private int ReadReference( TsCCpxContext context, FieldType field, int fieldIndex, ArrayList fieldValues, string fieldName ) { TsCCpxComplexValue complexValue = null; if (fieldName.Length == 0) { if (fieldIndex > 0 && fieldIndex - 1 < fieldValues.Count) { complexValue = (TsCCpxComplexValue)fieldValues[fieldIndex - 1]; } } else { for (int ii = 0; ii < fieldIndex; ii++) { complexValue = (TsCCpxComplexValue)fieldValues[ii]; if (complexValue.Name == fieldName) { break; } complexValue = null; } } if (complexValue == null) { throw new TsCCpxInvalidSchemaException(String.Format("Referenced field not found ({0}).", fieldName)); } return(System.Convert.ToInt32(complexValue.Value)); }
/////////////////////////////////////////////////////////////////////// #region Public Methods /// <summary> /// Writes a complex value to a buffer. /// </summary> /// <param name="namedValue">The structured value to write to the buffer.</param> /// <param name="dictionary">The type dictionary that contains a complex type identified with the type name.</param> /// <param name="typeName">The name of the type that describes the data.</param> /// <returns>A buffer containing the binary form of the complex type.</returns> public byte[] Write(TsCCpxComplexValue namedValue, TypeDictionary dictionary, string typeName) { if (namedValue == null) { throw new ArgumentNullException(nameof(namedValue)); } if (dictionary == null) { throw new ArgumentNullException(nameof(dictionary)); } if (typeName == null) { throw new ArgumentNullException(nameof(typeName)); } TsCCpxContext context = InitializeContext(null, dictionary, typeName); // determine the size of buffer required. int bytesRequired = WriteType(context, namedValue); if (bytesRequired == 0) { throw new TsCCpxInvalidDataToWriteException("Could not write value into buffer."); } // allocate buffer. context.Buffer = new byte[bytesRequired]; // write data into buffer. int bytesWritten = WriteType(context, namedValue); if (bytesWritten != bytesRequired) { throw new TsCCpxInvalidDataToWriteException("Could not write value into buffer."); } return(context.Buffer); }
/////////////////////////////////////////////////////////////////////// #region Private Methods /// <summary> /// Reads an instance of a type from the buffer, /// </summary> private int ReadType(TsCCpxContext context, out TsCCpxComplexValue complexValue) { complexValue = null; TypeDescription type = context.Type; int startIndex = context.Index; byte bitOffset = 0; ArrayList fieldValues = new ArrayList(); for (int ii = 0; ii < type.Field.Length; ii++) { FieldType field = type.Field[ii]; TsCCpxComplexValue fieldValue = new TsCCpxComplexValue { Name = (field.Name != null && field.Name.Length != 0) ? field.Name : String.Format("[{0}]", ii), Type = null, Value = null }; // check if additional padding is required after the end of a bit field. if (bitOffset != 0) { if (field.GetType() != typeof(BitString)) { context.Index++; bitOffset = 0; } } int bytesRead = 0; if (IsArrayField(field)) { bytesRead = ReadArrayField(context, field, ii, fieldValues, out fieldValue.Value); } else if (field.GetType() == typeof(TypeReference)) { object typeValue = null; bytesRead = ReadField(context, (TypeReference)field, out typeValue); // assign a name appropriate for the current context. fieldValue.Name = field.Name; fieldValue.Type = ((TsCCpxComplexValue)typeValue).Type; fieldValue.Value = ((TsCCpxComplexValue)typeValue).Value; } else { bytesRead = ReadField(context, field, ii, fieldValues, out fieldValue.Value, ref bitOffset); } if (bytesRead == 0 && bitOffset == 0) { throw new TsCCpxInvalidDataInBufferException(String.Format("Could not read field '{0}' in type '{1}'.", field.Name, type.TypeID)); } context.Index += bytesRead; // assign a value for field type. if (fieldValue.Type == null) { fieldValue.Type = Technosoftware.DaAeHdaClient.OpcConvert.ToString(fieldValue.Value.GetType()); } fieldValues.Add(fieldValue); } // skip padding bits at the end of a type. if (bitOffset != 0) { context.Index++; } complexValue = new TsCCpxComplexValue(); complexValue.Name = type.TypeID; complexValue.Type = type.TypeID; complexValue.Value = (TsCCpxComplexValue[])fieldValues.ToArray(typeof(TsCCpxComplexValue)); return(context.Index - startIndex); }
/////////////////////////////////////////////////////////////////////// #region Private Methods /// <summary> /// Writes an instance of a type to the buffer. /// </summary> private int WriteType(TsCCpxContext context, TsCCpxComplexValue namedValue) { TypeDescription type = context.Type; int startIndex = context.Index; TsCCpxComplexValue[] fieldValues = null; if (namedValue.Value == null || namedValue.Value.GetType() != typeof(TsCCpxComplexValue[])) { throw new TsCCpxInvalidDataToWriteException("Type instance does not contain field values."); } fieldValues = (TsCCpxComplexValue[])namedValue.Value; if (fieldValues.Length != type.Field.Length) { throw new TsCCpxInvalidDataToWriteException("Type instance does not contain the correct number of fields."); } byte bitOffset = 0; for (int ii = 0; ii < type.Field.Length; ii++) { FieldType field = type.Field[ii]; TsCCpxComplexValue fieldValue = fieldValues[ii]; if (bitOffset != 0) { if (field.GetType() != typeof(BitString)) { context.Index++; bitOffset = 0; } } int bytesWritten = 0; if (IsArrayField(field)) { bytesWritten = WriteArrayField(context, field, ii, fieldValues, fieldValue.Value); } else if (field.GetType() == typeof(TypeReference)) { bytesWritten = WriteField(context, (TypeReference)field, fieldValue); } else { bytesWritten = WriteField(context, field, ii, fieldValues, fieldValue.Value, ref bitOffset); } if (bytesWritten == 0 && bitOffset == 0) { throw new TsCCpxInvalidDataToWriteException(String.Format("Could not write field '{0}' in type '{1}'.", field.Name, type.TypeID)); } context.Index += bytesWritten; } if (bitOffset != 0) { context.Index++; } return(context.Index - startIndex); }