/// <summary>
        /// Parse TS_UPDATE_PALETTE
        /// </summary>
        /// <param name="updateData">update data (decompressed if were compressed)</param>
        /// <param name="shareDataHeader">share data header</param>
        /// <returns>TS_UPDATE_PALETTE</returns>
        private TS_UPDATE_PALETTE ParseTsUpdatePalettePduData(
            byte[] updateData,
            TS_SHAREDATAHEADER shareDataHeader)
        {
            // index of update data
            int index = 0;
            TS_UPDATE_PALETTE pduData = new TS_UPDATE_PALETTE();

            // TS_UPDATE_PALETTE: shareDataHeader
            pduData.shareDataHeader = shareDataHeader;

            // TS_UPDATE_PALETTE: paletteData
            pduData.paletteData = ParseTsUpdatePaletteData(updateData, ref index);

            // [Commented out for TDI #41402]
            // Check if data length exceeded expectation
            // VerifyDataLength(updateData.Length, index, ConstValue.ERROR_MESSAGE_DATA_LENGTH_EXCEEDED);
            return pduData;
        }
        /// <summary>
        /// Parse TS_UPDATE_SYNC
        /// </summary>
        /// <param name="updateData">update data (decompressed if were compressed)</param>
        /// <param name="shareDataHeader">share data header</param>
        /// <returns>TS_UPDATE_SYNC</returns>
        private TS_UPDATE_SYNC ParseTsUpdateSyncPduData(
            byte[] updateData,
            TS_SHAREDATAHEADER shareDataHeader)
        {
            // index of update data
            int index = 0;
            TS_UPDATE_SYNC pduData = new TS_UPDATE_SYNC();

            // TS_UPDATE_SYNC: shareDataHeader
            pduData.shareDataHeader = shareDataHeader;

            // TS_UPDATE_SYNC: updateType
            pduData.updateType = ParseUInt16(updateData, ref index, false);

            // TS_UPDATE_SYNC: pad2Octets
            pduData.pad2Octets = ParseUInt16(updateData, ref index, false);

            // Check if data length exceeded expectation
            VerifyDataLength(updateData.Length, index, ConstValue.ERROR_MESSAGE_DATA_LENGTH_EXCEEDED);
            return pduData;
        }
        /// <summary>
        /// Parse TS_UPDATE_ORDERS
        /// </summary>
        /// <param name="updateData">update data (decompressed if were compressed)</param>
        /// <param name="shareDataHeader">share data header</param>
        /// <returns>TS_UPDATE_ORDERS</returns>
        private TS_UPDATE_ORDERS ParseTsUpdateOrdersPduData(
            byte[] updateData,
            TS_SHAREDATAHEADER shareDataHeader)
        {
            // index of update data
            int index = 0;
            TS_UPDATE_ORDERS pduData = new TS_UPDATE_ORDERS();

            // TS_UPDATE_ORDERS: shareDataHeader
            pduData.shareDataHeader = shareDataHeader;

            // TS_UPDATE_ORDERS: updateType
            pduData.updateType = (updateType_Values)ParseUInt16(updateData, ref index, false);

            // TS_UPDATE_ORDERS: pad2OctetA
            pduData.pad2OctetA = ParseUInt16(updateData, ref index, false);

            // TS_UPDATE_ORDERS: numberOrders
            pduData.numberOrders = ParseUInt16(updateData, ref index, false);

            // TS_UPDATE_ORDERS: pad2OctetsB
            pduData.pad2OctetsB = ParseUInt16(updateData, ref index, false);

            // TS_UPDATE_ORDERS: orderData
            pduData.orderData = GetBytes(updateData, ref index, (updateData.Length - index));

            return pduData;
        }
        /// <summary>
        /// Parse TS_UPDATE_BITMAP
        /// </summary>
        /// <param name="updateData">update data (decompressed if were compressed)</param>
        /// <param name="shareDataHeader">share data header</param>
        /// <returns>TS_UPDATE_BITMAP</returns>
        private TS_UPDATE_BITMAP ParseTsUpdateBitmapPduData(
            byte[] updateData,
            TS_SHAREDATAHEADER shareDataHeader)
        {
            // index of update data
            int index = 0;
            TS_UPDATE_BITMAP pduData = new TS_UPDATE_BITMAP();

            // TS_UPDATE_BITMAP: shareDataHeader
            pduData.shareDataHeader = shareDataHeader;

            // TS_UPDATE_BITMAP: bitmapData
            pduData.bitmapData = ParseTsUpdateBitmapData(updateData, ref index);

            // Check if data length exceeded expectation
            VerifyDataLength(updateData.Length, index, ConstValue.ERROR_MESSAGE_DATA_LENGTH_EXCEEDED);
            return pduData;
        }
        /// <summary>
        /// Parse TS_SHAREDATAHEADER
        /// (parser index is updated according to parsed length)
        /// </summary>
        /// <param name="data">data to be parsed</param>
        /// <param name="currentIndex">current parser index</param>
        /// <returns>TS_SHAREDATAHEADER</returns>
        private TS_SHAREDATAHEADER ParseTsShareDataHeader(byte[] data, ref int currentIndex)
        {
            TS_SHAREDATAHEADER header = new TS_SHAREDATAHEADER();

            // TS_SHAREDATAHEADER: shareControlHeader
            header.shareControlHeader = ParseTsShareControlHeader(data, ref currentIndex);

            // TS_SHAREDATAHEADER: shareId
            header.shareId = ParseUInt32(data, ref currentIndex, false);

            // TS_SHAREDATAHEADER: pad1
            header.pad1 = ParseByte(data, ref currentIndex);

            // TS_SHAREDATAHEADER: streamId
            header.streamId = (streamId_Values)ParseByte(data, ref currentIndex);

            // TS_SHAREDATAHEADER: uncompressedLength
            header.uncompressedLength = ParseUInt16(data, ref currentIndex, false);

            // TS_SHAREDATAHEADER: pduType2
            header.pduType2 = (pduType2_Values)ParseByte(data, ref currentIndex);

            // TS_SHAREDATAHEADER: compressedType
            header.compressedType = (compressedType_Values)ParseByte(data, ref currentIndex);

            // TS_SHAREDATAHEADER: compressedLength
            header.compressedLength = ParseUInt16(data, ref currentIndex, false);

            return header;
        }
        /// <summary>
        /// Parse Slow-Path Graphics Update PDU
        /// </summary>
        /// <param name="updateData">update data (decompressed if were compressed</param>
        /// <param name="shareDataHeader">share data header</param>
        /// <returns>Slow-path Graphics Update PDU</returns>
        private RdpbcgrSlowPathUpdatePdu ParseTsGraphicsUpdatePdu(
            byte[] updateData,
            TS_SHAREDATAHEADER shareDataHeader)
        {
            // Get update type
            int tempIndex = 0;
            updateType_Values updateType = (updateType_Values)ParseUInt16(updateData, ref tempIndex, false);

            // Parse pdu by update type
            RdpbcgrSlowPathUpdatePdu pdu;
            switch (updateType)
            {
                // TS_UPDATE_ORDERS_PDU_DATA
                case updateType_Values.UPDATETYPE_ORDERS:
                    pdu = ParseTsUpdateOrdersPduData(updateData, shareDataHeader);
                    break;

                // TS_UPDATE_BITMAP_PDU_DATA
                case updateType_Values.UPDATETYPE_BITMAP:
                    pdu = ParseTsUpdateBitmapPduData(updateData, shareDataHeader);
                    break;

                // TS_UPDATE_PALETTE_PDU_DATA
                case updateType_Values.UPDATETYPE_PALETTE:
                    pdu = ParseTsUpdatePalettePduData(updateData, shareDataHeader);
                    break;

                // TS_UPDATE_SYNC_PDU_DATA
                case updateType_Values.UPDATETYPE_SYNCHRONIZE:
                    pdu = ParseTsUpdateSyncPduData(updateData, shareDataHeader);
                    break;

                default:
                    throw new FormatException(ConstValue.ERROR_MESSAGE_ENUM_UNRECOGNIZED);
            }
            return pdu;
        }
        /// <summary>
        /// Parse Slow-Path Pointer Update PDU
        /// </summary>
        /// <param name="updateData">update data (decompressed if were compressed</param>
        /// <param name="shareDataHeader">share data header</param>
        /// <returns>Slow-Path Pointer Update PDU</returns>
        public TS_POINTER_PDU ParseTsPointerPdu(
            byte[] updateData,
            TS_SHAREDATAHEADER shareDataHeader)
        {
            // index of update data
            int index = 0;
            TS_POINTER_PDU pdu = new TS_POINTER_PDU();

            // TS_POINTER_PDU: shareDataHeader
            pdu.shareDataHeader = shareDataHeader;

            // TS_POINTER_PDU: messageType
            pdu.messageType = ParseUInt16(updateData, ref index, false);

            // TS_POINTER_PDU: pad2Octets
            pdu.pad2Octets = ParseUInt16(updateData, ref index, false);

            // TS_POINTER_PDU: pointerAttributeData
            int remainLength = updateData.Length - index;
            switch (pdu.messageType)
            {
                // TS_PTRMSGTYPE_SYSTEM: 4 bytes
                case (ushort)TS_POINTER_PDU_messageType_Values.TS_PTRMSGTYPE_SYSTEM:
                    pdu.pointerAttributeData = GetBytes(updateData, ref index,
                        ConstValue.TS_PTRMSGTYPE_SYSTEM_DATA_LENGTH);
                    break;

                // TS_PTRMSGTYPE_POSITION: 4 bytes
                case (ushort)TS_POINTER_PDU_messageType_Values.TS_PTRMSGTYPE_POSITION:
                    pdu.pointerAttributeData = GetBytes(updateData, ref index,
                        ConstValue.TS_PTRMSGTYPE_POSITION_DATA_LENGTH);
                    break;

                // TS_PTRMSGTYPE_COLOR: variable number of bytes
                case (ushort)TS_POINTER_PDU_messageType_Values.TS_PTRMSGTYPE_COLOR:
                    pdu.pointerAttributeData = GetBytes(updateData, ref index, remainLength);
                    break;

                // TS_PTRMSGTYPE_CACHED: 2 bytes
                case (ushort)TS_POINTER_PDU_messageType_Values.TS_PTRMSGTYPE_CACHED:
                    pdu.pointerAttributeData = GetBytes(updateData, ref index,
                        ConstValue.TS_PTRMSGTYPE_CACHED_DATA_LENGTH);
                    break;

                // TS_PTRMSGTYPE_POINTER: variable number of bytes
                case (ushort)TS_POINTER_PDU_messageType_Values.TS_PTRMSGTYPE_POINTER:
                    pdu.pointerAttributeData = GetBytes(updateData, ref index, remainLength);
                    break;

                default:
                    throw new FormatException(ConstValue.ERROR_MESSAGE_ENUM_UNRECOGNIZED);
            }

            // Check if data length exceeded expectation
            VerifyDataLength(updateData.Length, index, ConstValue.ERROR_MESSAGE_DATA_LENGTH_EXCEEDED);
            return pdu;
        }