///////////////////////////////////////////////////////////////////////
        #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);
        }
Пример #2
0
        /// <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);
        }
Пример #5
0
        /// <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);
        }
Пример #7
0
        /// <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));
        }
Пример #10
0
        ///////////////////////////////////////////////////////////////////////
        #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);
        }
Пример #14
0
        /// <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);
        }
Пример #16
0
        /// <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);
        }
Пример #18
0
        /// <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);
        }
Пример #19
0
        /// <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);
        }
Пример #21
0
        ///////////////////////////////////////////////////////////////////////
        #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);
        }