/////////////////////////////////////////////////////////////////////// #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> /// Writes a integer value from to the buffer. /// </summary> private int WriteField(TsCCpxContext context, FloatingPoint field, object fieldValue) { byte[] buffer = context.Buffer; // initialize serialization paramters. int length = (field.LengthSpecified) ? (int)field.Length : 4; string format = field.FloatFormat ?? context.FloatFormat; // apply defaults for built in types. if (field.GetType() == typeof(Single)) { length = 4; format = TsCCpxContext.FLOAT_FORMAT_IEEE754; } else if (field.GetType() == typeof(Double)) { length = 8; format = TsCCpxContext.FLOAT_FORMAT_IEEE754; } // only write to the buffer if it has been allocated. if (buffer != null) { // check if there is enough data left. if (buffer.Length - context.Index < length) { throw new TsCCpxInvalidDataToWriteException("Unexpected end of buffer."); } // copy bytes if required. byte[] bytes = null; if (format == TsCCpxContext.FLOAT_FORMAT_IEEE754) { switch (length) { case 4: { bytes = BitConverter.GetBytes(Convert.ToSingle(fieldValue)); break; } case 8: { bytes = BitConverter.GetBytes(Convert.ToDouble(fieldValue)); break; } default: { bytes = (byte[])fieldValue; break; } } } else { bytes = (byte[])fieldValue; } // write bytes to buffer. for (int ii = 0; ii < bytes.Length; ii++) { buffer[context.Index + ii] = bytes[ii]; } } return(length); }
/// <summary> /// Reads a floating point value from the buffer. /// </summary> private int ReadField(TsCCpxContext context, FloatingPoint field, out object fieldValue) { fieldValue = null; byte[] buffer = context.Buffer; // initialize serialization paramters. int length = (field.LengthSpecified) ? (int)field.Length : 4; string format = field.FloatFormat ?? context.FloatFormat; // apply defaults for built in types. if (field.GetType() == typeof(Single)) { length = 4; format = TsCCpxContext.FLOAT_FORMAT_IEEE754; } else if (field.GetType() == typeof(Double)) { length = 8; format = TsCCpxContext.FLOAT_FORMAT_IEEE754; } // check if there is enough data left. if (buffer.Length - context.Index < length) { throw new TsCCpxInvalidDataInBufferException("Unexpected end of buffer."); } // copy bytes. byte[] bytes = new byte[length]; for (int ii = 0; ii < length; ii++) { bytes[ii] = buffer[context.Index + ii]; } // convert to object. if (format == TsCCpxContext.FLOAT_FORMAT_IEEE754) { switch (length) { case 4: { fieldValue = BitConverter.ToSingle(bytes, 0); break; } case 8: { fieldValue = BitConverter.ToDouble(bytes, 0); break; } default: { fieldValue = bytes; break; } } } else { fieldValue = bytes; } return(length); }
/// <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> /// Returns the termininator for the field. /// </summary> internal byte[] GetTerminator(TsCCpxContext context, FieldType field) { if (field.FieldTerminator == null) { throw new TsCCpxInvalidSchemaException(String.Format("{0} is not a terminated subscription.", field.Name)); } string terminator = Convert.ToString(field.FieldTerminator).ToUpper(); byte[] bytes = new byte[terminator.Length / 2]; for (int ii = 0; ii < bytes.Length; ii++) { bytes[ii] = Convert.ToByte(terminator.Substring(ii * 2, 2), 16); } return(bytes); }
/// <summary> /// Writes a complex type from to the buffer. /// </summary> private int WriteField(TsCCpxContext context, TypeReference field, object fieldValue) { 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)); } if (fieldValue.GetType() != typeof(TsCCpxComplexValue)) { throw new TsCCpxInvalidDataToWriteException("Instance of type is not the correct type."); } return(WriteType(context, (TsCCpxComplexValue)fieldValue)); }
/// <summary> /// Looks up the type name in the dictionary and initializes the context. /// </summary> internal TsCCpxContext InitializeContext(byte[] buffer, TypeDictionary dictionary, string typeName) { TsCCpxContext context = new TsCCpxContext(buffer) { Dictionary = dictionary, Type = null, BigEndian = dictionary.DefaultBigEndian, CharWidth = dictionary.DefaultCharWidth, StringEncoding = dictionary.DefaultStringEncoding, FloatFormat = dictionary.DefaultFloatFormat }; foreach (TypeDescription type in dictionary.TypeDescription) { if (type.TypeID == typeName) { 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("Type '{0}' not found in dictionary.", typeName)); } return(context); }
/// <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); }
/// <summary> /// Reads the value contained in a field from the buffer. /// </summary> private int ReadField( TsCCpxContext context, FieldType field, int fieldIndex, ArrayList fieldValues, out object fieldValue, ref byte bitOffset ) { fieldValue = null; Type type = field.GetType(); if (type == typeof(Integer) || type.IsSubclassOf(typeof(Integer))) { return(ReadField(context, (Integer)field, out fieldValue)); } else if (type == typeof(FloatingPoint) || type.IsSubclassOf(typeof(FloatingPoint))) { return(ReadField(context, (FloatingPoint)field, out fieldValue)); } else if (type == typeof(CharString) || type.IsSubclassOf(typeof(CharString))) { return(ReadField(context, (CharString)field, fieldIndex, fieldValues, out fieldValue)); } else if (type == typeof(BitString) || type.IsSubclassOf(typeof(BitString))) { return(ReadField(context, (BitString)field, out fieldValue, ref bitOffset)); } else if (type == typeof(TypeReference)) { return(ReadField(context, (TypeReference)field, out fieldValue)); } else { throw new NotImplementedException(String.Format("Fields of type '{0}' are not implemented yet.", type)); } }
/// <summary> /// Reads a field containing an array of values. /// </summary> private int ReadArrayField( TsCCpxContext context, FieldType field, int fieldIndex, ArrayList fieldValues, out object fieldValue ) { fieldValue = null; int startIndex = context.Index; ArrayList array = new ArrayList(); object elementValue = null; byte bitOffset = 0; // read fixed length array. if (field.ElementCountSpecified) { for (int ii = 0; ii < field.ElementCount; ii++) { int bytesRead = ReadField(context, field, fieldIndex, fieldValues, out elementValue, ref bitOffset); if (bytesRead == 0 && bitOffset == 0) { break; } array.Add(elementValue); context.Index += bytesRead; } } // read variable length array. else if (field.ElementCountRef != null) { int count = ReadReference(context, field, fieldIndex, fieldValues, field.ElementCountRef); for (int ii = 0; ii < count; ii++) { int bytesRead = ReadField(context, field, fieldIndex, fieldValues, out elementValue, ref bitOffset); if (bytesRead == 0 && bitOffset == 0) { break; } array.Add(elementValue); context.Index += bytesRead; } } // read terminated array. else if (field.FieldTerminator != null) { byte[] terminator = GetTerminator(context, field); while (context.Index < context.Buffer.Length) { bool found = true; for (int ii = 0; ii < terminator.Length; ii++) { if (terminator[ii] != context.Buffer[context.Index + ii]) { found = false; break; } } if (found) { context.Index += terminator.Length; break; } int bytesRead = ReadField(context, field, fieldIndex, fieldValues, out elementValue, ref bitOffset); if (bytesRead == 0 && bitOffset == 0) { break; } array.Add(elementValue); context.Index += bytesRead; } } // skip padding bits at the end of an array. if (bitOffset != 0) { context.Index++; } // convert array list to a fixed length array of a single type. Type type = null; foreach (object element in array) { if (type == null) { type = element.GetType(); } else { if (type != element.GetType()) { type = typeof(object); break; } } } fieldValue = array.ToArray(type); // return the total bytes read. return(context.Index - startIndex); }
/// <summary> /// Reads a bit string value from the buffer. /// </summary> private int ReadField(TsCCpxContext context, BitString field, out object fieldValue, ref byte bitOffset) { fieldValue = null; byte[] buffer = context.Buffer; // initialize serialization paramters. int bits = (field.LengthSpecified) ? (int)field.Length : 8; int length = (bits % 8 == 0) ? bits / 8 : bits / 8 + 1; // check if there is enough data left. if (buffer.Length - context.Index < length) { throw new TsCCpxInvalidDataInBufferException("Unexpected end of buffer."); } // allocate space for the value. byte[] bytes = new byte[length]; int bitsLeft = bits; byte mask = (byte)(~((1 << bitOffset) - 1)); // loop until all bits read. for (int ii = 0; bitsLeft >= 0 && ii < length; ii++) { // add the bits from the lower byte. bytes[ii] = (byte)((mask & buffer[context.Index + ii]) >> bitOffset); // check if no more bits need to be read. if (bitsLeft + bitOffset <= 8) { // mask out un-needed bits. bytes[ii] &= (byte)((1 << bitsLeft) - 1); break; } // check if possible to read the next byte. if (context.Index + ii + 1 >= buffer.Length) { throw new TsCCpxInvalidDataInBufferException("Unexpected end of buffer."); } // add the bytes from the higher byte. bytes[ii] += (byte)((~mask & buffer[context.Index + ii + 1]) << (8 - bitOffset)); // check if all done. if (bitsLeft <= 8) { // mask out un-needed bits. bytes[ii] &= (byte)((1 << bitsLeft) - 1); break; } // decrement the bit count. bitsLeft -= 8; } fieldValue = bytes; // update the length bit offset. length = (bits + bitOffset) / 8; bitOffset = (byte)((bits + bitOffset) % 8); // return the bytes read. return(length); }
/// <summary> /// Writes a integer value from to the buffer. /// </summary> private int WriteField(TsCCpxContext context, Integer field, object fieldValue) { byte[] buffer = context.Buffer; // initialize serialization paramters. int length = (field.LengthSpecified) ? (int)field.Length : 4; bool signed = field.Signed; // apply defaults for built in types. if (field.GetType() == typeof(Int8)) { length = 1; signed = true; } else if (field.GetType() == typeof(Int16)) { length = 2; signed = true; } else if (field.GetType() == typeof(Int32)) { length = 4; signed = true; } else if (field.GetType() == typeof(Int64)) { length = 8; signed = true; } else if (field.GetType() == typeof(UInt8)) { length = 1; signed = false; } else if (field.GetType() == typeof(UInt16)) { length = 2; signed = false; } else if (field.GetType() == typeof(UInt32)) { length = 4; signed = false; } else if (field.GetType() == typeof(UInt64)) { length = 8; signed = false; } // only write to the buffer if it has been allocated. if (buffer != null) { // check if there is enough data left. if (buffer.Length - context.Index < length) { throw new TsCCpxInvalidDataToWriteException("Unexpected end of buffer."); } // copy and swap bytes if required. byte[] bytes = null; if (signed) { switch (length) { case 1: { bytes = new byte[1]; sbyte value = Convert.ToSByte(fieldValue); if (value < 0) { bytes[0] = (byte)(Byte.MaxValue + value + 1); } else { bytes[0] = (byte)value; } break; } case 2: { bytes = BitConverter.GetBytes(Convert.ToInt16(fieldValue)); break; } case 4: { bytes = BitConverter.GetBytes(Convert.ToInt32(fieldValue)); break; } case 8: { bytes = BitConverter.GetBytes(Convert.ToInt64(fieldValue)); break; } default: { bytes = (byte[])fieldValue; break; } } } else { switch (length) { case 1: { bytes = new byte[] { Convert.ToByte(fieldValue) }; break; } case 2: { bytes = BitConverter.GetBytes(Convert.ToUInt16(fieldValue)); break; } case 4: { bytes = BitConverter.GetBytes(Convert.ToUInt32(fieldValue)); break; } case 8: { bytes = BitConverter.GetBytes(Convert.ToUInt64(fieldValue)); break; } default: { bytes = (byte[])fieldValue; break; } } } // copy and swap bytes. if (context.BigEndian) { SwapBytes(bytes, 0, length); } // write bytes to buffer. for (int ii = 0; ii < bytes.Length; ii++) { buffer[context.Index + ii] = bytes[ii]; } } return(length); }
/// <summary> /// Reads a char string value from the buffer. /// </summary> private int ReadField( TsCCpxContext context, CharString field, int fieldIndex, ArrayList fieldValues, out object fieldValue ) { fieldValue = null; byte[] buffer = context.Buffer; // initialize serialization parameters. int charWidth = (field.CharWidthSpecified) ? (int)field.CharWidth : (int)context.CharWidth; int charCount = (field.LengthSpecified) ? (int)field.Length : -1; // apply defaults for built in types. if (field.GetType() == typeof(Ascii)) { charWidth = 1; } else if (field.GetType() == typeof(Unicode)) { charWidth = 2; } if (field.CharCountRef != null) { charCount = ReadReference(context, field, fieldIndex, fieldValues, field.CharCountRef); } // find null terminator if (charCount == -1) { charCount = 0; for (int ii = context.Index; ii < context.Buffer.Length - charWidth + 1; ii += charWidth) { charCount++; bool isNull = true; for (int jj = 0; jj < charWidth; jj++) { if (context.Buffer[ii + jj] != 0) { isNull = false; break; } } if (isNull) { break; } } } // check if there is enough data left. if (buffer.Length - context.Index < charWidth * charCount) { throw new TsCCpxInvalidDataInBufferException("Unexpected end of buffer."); } if (charWidth > 2) { // copy bytes. byte[] bytes = new byte[charCount * charWidth]; for (int ii = 0; ii < charCount * charWidth; ii++) { bytes[ii] = buffer[context.Index + ii]; } // swap bytes. if (context.BigEndian) { for (int ii = 0; ii < bytes.Length; ii += charWidth) { SwapBytes(bytes, 0, charWidth); } } fieldValue = bytes; } else { // copy characters. char[] chars = new char[charCount]; for (int ii = 0; ii < charCount; ii++) { if (charWidth == 1) { chars[ii] = System.Convert.ToChar(buffer[context.Index + ii]); } else { byte[] charBytes = new byte[] { buffer[context.Index + 2 * ii], buffer[context.Index + 2 * ii + 1] }; if (context.BigEndian) { SwapBytes(charBytes, 0, 2); } chars[ii] = BitConverter.ToChar(charBytes, 0); } } fieldValue = new string(chars).TrimEnd(new char[] { '\0' }); } return(charCount * charWidth); }
/// <summary> /// Writes a char string value to the buffer. /// </summary> private int WriteField( TsCCpxContext context, CharString field, int fieldIndex, TsCCpxComplexValue[] fieldValues, object fieldValue ) { byte[] buffer = context.Buffer; // initialize serialization parameters. int charWidth = (field.CharWidthSpecified) ? (int)field.CharWidth : (int)context.CharWidth; int charCount = (field.LengthSpecified) ? (int)field.Length : -1; // apply defaults for built in types. if (field.GetType() == typeof(Ascii)) { charWidth = 1; } else if (field.GetType() == typeof(Unicode)) { charWidth = 2; } byte[] bytes = null; if (charCount == -1) { // extra wide characters stored as byte arrays if (charWidth > 2) { if (fieldValue.GetType() != typeof(byte[])) { throw new TsCCpxInvalidDataToWriteException("Field value is not a byte array."); } bytes = (byte[])fieldValue; charCount = bytes.Length / charWidth; } // convert string to byte array. else { if (fieldValue.GetType() != typeof(string)) { throw new TsCCpxInvalidDataToWriteException("Field value is not a string."); } string stringValue = (string)fieldValue; charCount = stringValue.Length + 1; // calculate length of ascii string by forcing pure unicode characters to two ascii chars. if (charWidth == 1) { charCount = 1; foreach (char unicodeChar in stringValue) { charCount++; byte[] charBytes = BitConverter.GetBytes(unicodeChar); if (charBytes[1] != 0) { charCount++; } } } } } // update the char count reference. if (field.CharCountRef != null) { WriteReference(context, field, fieldIndex, fieldValues, field.CharCountRef, charCount); } if (buffer != null) { // copy string to buffer. if (bytes == null) { string stringValue = (string)fieldValue; bytes = new byte[charWidth * charCount]; int index = 0; for (int ii = 0; ii < stringValue.Length; ii++) { if (index >= bytes.Length) { break; } byte[] charBytes = BitConverter.GetBytes(stringValue[ii]); bytes[index++] = charBytes[0]; if (charWidth == 2 || charBytes[1] != 0) { bytes[index++] = charBytes[1]; } } } // check if there is enough data left. if (buffer.Length - context.Index < bytes.Length) { throw new TsCCpxInvalidDataToWriteException("Unexpected end of buffer."); } // write bytes to buffer. for (int ii = 0; ii < bytes.Length; ii++) { buffer[context.Index + ii] = bytes[ii]; } // swap bytes. if (context.BigEndian && charWidth > 1) { for (int ii = 0; ii < bytes.Length; ii += charWidth) { SwapBytes(buffer, context.Index + ii, charWidth); } } } return(charCount * charWidth); }
/// <summary> /// Reads a integer value from the buffer. /// </summary> private int ReadField(TsCCpxContext context, Integer field, out object fieldValue) { fieldValue = null; byte[] buffer = context.Buffer; // initialize serialization paramters. int length = (field.LengthSpecified) ? (int)field.Length : 4; bool signed = field.Signed; // apply defaults for built in types. if (field.GetType() == typeof(Int8)) { length = 1; signed = true; } else if (field.GetType() == typeof(Int16)) { length = 2; signed = true; } else if (field.GetType() == typeof(Int32)) { length = 4; signed = true; } else if (field.GetType() == typeof(Int64)) { length = 8; signed = true; } else if (field.GetType() == typeof(UInt8)) { length = 1; signed = false; } else if (field.GetType() == typeof(UInt16)) { length = 2; signed = false; } else if (field.GetType() == typeof(UInt32)) { length = 4; signed = false; } else if (field.GetType() == typeof(UInt64)) { length = 8; signed = false; } // check if there is enough data left. if (buffer.Length - context.Index < length) { throw new TsCCpxInvalidDataInBufferException("Unexpected end of buffer."); } // copy and swap bytes if required. byte[] bytes = new byte[length]; for (int ii = 0; ii < length; ii++) { bytes[ii] = buffer[context.Index + ii]; } if (context.BigEndian) { SwapBytes(bytes, 0, length); } // convert to object. if (signed) { switch (length) { case 1: { if (bytes[0] < 128) { fieldValue = (sbyte)bytes[0]; } else { fieldValue = (sbyte)(0 - bytes[0]); } break; } case 2: { fieldValue = BitConverter.ToInt16(bytes, 0); break; } case 4: { fieldValue = BitConverter.ToInt32(bytes, 0); break; } case 8: { fieldValue = BitConverter.ToInt64(bytes, 0); break; } default: { fieldValue = bytes; break; } } } else { switch (length) { case 1: { fieldValue = bytes[0]; break; } case 2: { fieldValue = BitConverter.ToUInt16(bytes, 0); break; } case 4: { fieldValue = BitConverter.ToUInt32(bytes, 0); break; } case 8: { fieldValue = BitConverter.ToUInt64(bytes, 0); break; } default: { fieldValue = bytes; break; } } } return(length); }
/// <summary> /// Writes a bit string value to the buffer. /// </summary> private int WriteField(TsCCpxContext context, BitString field, object fieldValue, ref byte bitOffset) { byte[] buffer = context.Buffer; // initialize serialization paramters. int bits = (field.LengthSpecified) ? (int)field.Length : 8; int length = (bits % 8 == 0) ? bits / 8 : bits / 8 + 1; if (fieldValue.GetType() != typeof(byte[])) { throw new TsCCpxInvalidDataToWriteException("Wrong data type to write."); } // allocate space for the value. byte[] bytes = (byte[])fieldValue; if (buffer != null) { // check if there is enough data left. if (buffer.Length - context.Index < length) { throw new TsCCpxInvalidDataToWriteException("Unexpected end of buffer."); } int bitsLeft = bits; byte mask = (bitOffset == 0) ? (byte)0xFF : (byte)((0x80 >> (bitOffset - 1)) - 1); // loop until all bits read. for (int ii = 0; bitsLeft >= 0 && ii < length; ii++) { // add the bits from the lower byte. buffer[context.Index + ii] += (byte)((mask & ((1 << bitsLeft) - 1) & bytes[ii]) << bitOffset); // check if no more bits need to be read. if (bitsLeft + bitOffset <= 8) { break; } // check if possible to read the next byte. if (context.Index + ii + 1 >= buffer.Length) { throw new TsCCpxInvalidDataToWriteException("Unexpected end of buffer."); } // add the bytes from the higher byte. buffer[context.Index + ii + 1] += (byte)((~mask & ((1 << bitsLeft) - 1) & bytes[ii]) >> (8 - bitOffset)); // check if all done. if (bitsLeft <= 8) { break; } // decrement the bit count. bitsLeft -= 8; } } // update the length bit offset. length = (bits + bitOffset) / 8; bitOffset = (byte)((bits + bitOffset) % 8); // return the bytes read. return(length); }
/// <summary> /// Reads a field containing an array of values. /// </summary> private int WriteArrayField( TsCCpxContext context, FieldType field, int fieldIndex, TsCCpxComplexValue[] fieldValues, object fieldValue ) { int startIndex = context.Index; Array array = null; if (!fieldValue.GetType().IsArray) { throw new TsCCpxInvalidDataToWriteException("Array field value is not an array type."); } array = (Array)fieldValue; byte bitOffset = 0; // read fixed length array. if (field.ElementCountSpecified) { int count = 0; foreach (object elementValue in array) { // ignore any excess elements. if (count == field.ElementCount) { break; } int bytesWritten = WriteField(context, field, fieldIndex, fieldValues, elementValue, ref bitOffset); if (bytesWritten == 0 && bitOffset == 0) { break; } context.Index += bytesWritten; count++; } // write a null value for any missing elements. while (count < field.ElementCount) { int bytesWritten = WriteField(context, field, fieldIndex, fieldValues, null, ref bitOffset); if (bytesWritten == 0 && bitOffset == 0) { break; } context.Index += bytesWritten; count++; } } // read variable length array. else if (field.ElementCountRef != null) { int count = 0; foreach (object elementValue in array) { int bytesWritten = WriteField(context, field, fieldIndex, fieldValues, elementValue, ref bitOffset); if (bytesWritten == 0 && bitOffset == 0) { break; } context.Index += bytesWritten; count++; } // update the value of the referenced field with the correct element count. WriteReference(context, field, fieldIndex, fieldValues, field.ElementCountRef, count); } // read terminated array. else if (field.FieldTerminator != null) { foreach (object elementValue in array) { int bytesWritten = WriteField(context, field, fieldIndex, fieldValues, elementValue, ref bitOffset); if (bytesWritten == 0 && bitOffset == 0) { break; } context.Index += bytesWritten; } // get the terminator. byte[] terminator = GetTerminator(context, field); if (context.Buffer != null) { // write the terminator. for (int ii = 0; ii < terminator.Length; ii++) { context.Buffer[context.Index + ii] = terminator[ii]; } } context.Index += terminator.Length; } // clear the bit offset and skip to end of byte at the end of the array. if (bitOffset != 0) { context.Index++; } // return the total bytes read. return(context.Index - startIndex); }
/////////////////////////////////////////////////////////////////////// #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); }