/// <summary>
        /// Decompress payload of slow path or fast path output.
        /// </summary>
        /// <param name="data">The data to be decompressed.</param>
        /// <param name="type">The type to decompress.</param>
        /// <returns>The decompressed data.</returns>
        internal byte[] Decompress(compressedType_Values type, byte[] data)
        {
            if (data == null)
            {
                return null;
            }

            lock (contextLock)
            {
                CompressMode flag = CompressMode.None;

                if ((type & compressedType_Values.PACKET_AT_FRONT) == compressedType_Values.PACKET_AT_FRONT)
                {
                    flag |= CompressMode.SetToFront;
                }

                if ((type & compressedType_Values.PACKET_COMPRESSED) == compressedType_Values.PACKET_COMPRESSED)
                {
                    flag |= CompressMode.Compressed;
                }

                if ((type & compressedType_Values.PACKET_FLUSHED) == compressedType_Values.PACKET_FLUSHED)
                {
                    flag |= CompressMode.Flush;
                }

                if (ioDecompressor != null && flag != CompressMode.None)
                {
                    return ioDecompressor.Decompress(data, flag);
                }

                // no compression
                return data;
            }
        }
        /// <summary>
        /// Parse TS_FP_UPDATE_PALETTE
        /// </summary>
        /// <param name="updateHeader">update header</param>
        /// <param name="compressionFlags">compression flags</param>
        /// <param name="size">update data size(before decompression)</param>
        /// <param name="updateData">update data(decompressed)</param>
        /// <returns>TS_FP_UPDATE_PALETTE</returns>
        private TS_FP_UPDATE_PALETTE ParseTsFpUpdatePalette(
            byte updateHeader,
            compressedType_Values compressionFlags,
            UInt16 size,
            byte[] updateData)
        {
            TS_FP_UPDATE_PALETTE palette = new TS_FP_UPDATE_PALETTE();

            // TS_FP_UPDATE_PALETTE: updateHeader
            palette.updateHeader = updateHeader;

            // TS_FP_UPDATE_PALETTE: compressionFlags
            palette.compressionFlags = compressionFlags;

            // TS_FP_UPDATE_PALETTE: size
            palette.size = size;

            // TS_FP_UPDATE_PALETTE: paletteUpdateData
            int index = 0;
            palette.paletteUpdateData = ParseTsUpdatePaletteData(updateData, ref index);

            // Check if data length exceeded expectation
            VerifyDataLength(updateData.Length, index, ConstValue.ERROR_MESSAGE_DATA_LENGTH_EXCEEDED);
            return palette;
        }
        /// <summary>
        /// Parse TS_FP_UPDATE_SYNCHRONIZE
        /// </summary>
        /// <param name="updateHeader">update header</param>
        /// <param name="compressionFlags">compression flags</param>
        /// <param name="size">update data size(before decompression)</param>
        /// <returns>TS_FP_UPDATE_SYNCHRONIZE</returns>
        private TS_FP_UPDATE_SYNCHRONIZE ParseTsFpUpdateSynchronize(
            byte updateHeader,
            compressedType_Values compressionFlags,
            UInt16 size)
        {
            TS_FP_UPDATE_SYNCHRONIZE sync = new TS_FP_UPDATE_SYNCHRONIZE();

            // TS_FP_UPDATE_SYNCHRONIZE: updateHeader
            sync.updateHeader = updateHeader;

            // TS_FP_UPDATE_SYNCHRONIZE: compressionFlags
            sync.compressionFlags = compressionFlags;

            // TS_FP_UPDATE_SYNCHRONIZE: size
            sync.size = size;

            return sync;
        }
        /// <summary>
        /// Parse TS_FP_UPDATE_BITMAP
        /// </summary>
        /// <param name="updateHeader">update header</param>
        /// <param name="compressionFlags">compression flags</param>
        /// <param name="size">update data size(before decompression)</param>
        /// <param name="updateData">update data(decompressed)</param>
        /// <returns>TS_FP_UPDATE_BITMAP</returns>
        private TS_FP_UPDATE_BITMAP ParseTsFpUpdateBitmap(
            byte updateHeader,
            compressedType_Values compressionFlags,
            UInt16 size,
            byte[] updateData)
        {
            TS_FP_UPDATE_BITMAP bitmap = new TS_FP_UPDATE_BITMAP();

            // TS_FP_UPDATE_BITMAP: updateHeader
            bitmap.updateHeader = updateHeader;

            // TS_FP_UPDATE_BITMAP: compressionFlags
            bitmap.compressionFlags = compressionFlags;

            // TS_FP_UPDATE_BITMAP: size
            bitmap.size = size;

            // TS_FP_UPDATE_BITMAP: bitmapUpdateData
            int index = 0;
            bitmap.bitmapUpdateData = ParseTsUpdateBitmapData(updateData, ref index);

            // Check if data length exceeded expectation
            VerifyDataLength(updateData.Length, index, ConstValue.ERROR_MESSAGE_DATA_LENGTH_EXCEEDED);
            return bitmap;
        }
        /// <summary>
        /// Parse TS_FP_UPDATE_ORDERS
        /// </summary>
        /// <param name="updateHeader">update header</param>
        /// <param name="compressionFlags">compression flags</param>
        /// <param name="size">update data size(before decompression)</param>
        /// <param name="updateData">update data(decompressed)</param>
        /// <returns>TS_FP_UPDATE_ORDERS</returns>
        private TS_FP_UPDATE_ORDERS ParseTsFpUpdateOrders(
            byte updateHeader,
            compressedType_Values compressionFlags,
            UInt16 size,
            byte[] updateData)
        {
            TS_FP_UPDATE_ORDERS orders = new TS_FP_UPDATE_ORDERS();

            // TS_FP_UPDATE_ORDERS: updateHeader
            orders.updateHeader = updateHeader;

            // TS_FP_UPDATE_ORDERS: compressionFlags
            orders.compressionFlags = compressionFlags;

            // TS_FP_UPDATE_ORDERS: size
            orders.size = size;

            // TS_FP_UPDATE_ORDERS: updateOrders
            orders.updateOrders = updateData;

            return orders;
        }
        /// <summary>
        /// Parse TS_FP_SYSTEMPOINTERHIDDENATTRIBUTE
        /// </summary>
        /// <param name="updateHeader">update header</param>
        /// <param name="compressionFlags">compression flags</param>
        /// <param name="size">update data size(before decompression)</param>
        /// <returns>TS_FP_SYSTEMPOINTERHIDDENATTRIBUTE</returns>
        private TS_FP_SYSTEMPOINTERHIDDENATTRIBUTE ParseTsFpSystemPointerHiddenAttribute(
            byte updateHeader,
            compressedType_Values compressionFlags,
            UInt16 size)
        {
            TS_FP_SYSTEMPOINTERHIDDENATTRIBUTE hiddenAttribute = new TS_FP_SYSTEMPOINTERHIDDENATTRIBUTE();

            // TS_FP_SYSTEMPOINTERHIDDENATTRIBUTE: updateHeader
            hiddenAttribute.updateHeader = updateHeader;

            // TS_FP_SYSTEMPOINTERHIDDENATTRIBUTE: compressionFlags
            hiddenAttribute.compressionFlags = compressionFlags;

            // TS_FP_SYSTEMPOINTERHIDDENATTRIBUTE: size
            hiddenAttribute.size = size;

            return hiddenAttribute;
        }
        /// <summary>
        /// Parse TS_FP_SYSTEMPOINTERDEFAULTATTRIBUTE
        /// </summary>
        /// <param name="updateHeader">update header</param>
        /// <param name="compressionFlags">compression flags</param>
        /// <param name="size">update data size(before decompression)</param>
        /// <returns>TS_FP_SYSTEMPOINTERDEFAULTATTRIBUTE</returns>
        private TS_FP_SYSTEMPOINTERDEFAULTATTRIBUTE ParseTsFpSystemPointerDefaultAttribute(
            byte updateHeader,
            compressedType_Values compressionFlags,
            UInt16 size)
        {
            TS_FP_SYSTEMPOINTERDEFAULTATTRIBUTE defaultAttribute = new TS_FP_SYSTEMPOINTERDEFAULTATTRIBUTE();

            // TS_FP_SYSTEMPOINTERDEFAULTATTRIBUTE: updateHeader
            defaultAttribute.updateHeader = updateHeader;

            // TS_FP_SYSTEMPOINTERDEFAULTATTRIBUTE: compressionFlags
            defaultAttribute.compressionFlags = compressionFlags;

            // TS_FP_SYSTEMPOINTERDEFAULTATTRIBUTE: size
            defaultAttribute.size = size;

            return defaultAttribute;
        }
        /// <summary>
        /// Parse TS_FP_SURFCMDS
        /// </summary>
        /// <param name="updateHeader">update header</param>
        /// <param name="compressionFlags">compression flags</param>
        /// <param name="size">update data size(before decompression)</param>
        /// <param name="updateData">update data(decompressed)</param>
        /// <returns>TS_FP_SURFCMDS</returns>
        private TS_FP_SURFCMDS ParseTsFpSurfCmds(
            byte updateHeader,
            compressedType_Values compressionFlags,
            UInt16 size,
            byte[] updateData)
        {
            TS_FP_SURFCMDS cmds = new TS_FP_SURFCMDS();

            // TS_FP_SURFCMDS: updateHeader
            cmds.updateHeader = updateHeader;

            // TS_FP_SURFCMDS: compressionFlags
            cmds.compressionFlags = compressionFlags;

            // TS_FP_SURFCMDS: size
            cmds.size = size;

            // TS_FP_SURFCMDS: surfaceCommands
            int index = 0;
            cmds.surfaceCommands = ParseTsSurfCmd(updateData, ref index);

            // Check if data length exceeded expectation
            VerifyDataLength(updateData.Length, index, ConstValue.ERROR_MESSAGE_DATA_LENGTH_EXCEEDED);
            return cmds;
        }
        /// <summary>
        /// Parse TS_FP_POINTERPOSATTRIBUTE
        /// </summary>
        /// <param name="updateHeader">update header</param>
        /// <param name="compressionFlags">compression flags</param>
        /// <param name="size">update data size(before decompression)</param>
        /// <param name="updateData">update data(decompressed)</param>
        /// <returns>TS_FP_POINTERPOSATTRIBUTE</returns>
        private TS_FP_POINTERPOSATTRIBUTE ParseTsFpPointerPosAttribute(
            byte updateHeader,
            compressedType_Values compressionFlags,
            UInt16 size,
            byte[] updateData)
        {
            TS_FP_POINTERPOSATTRIBUTE positionAttribute = new TS_FP_POINTERPOSATTRIBUTE();

            // TS_FP_POINTERPOSATTRIBUTE: updateHeader
            positionAttribute.updateHeader = updateHeader;

            // TS_FP_POINTERPOSATTRIBUTE: compressionFlags
            positionAttribute.compressionFlags = compressionFlags;

            // TS_FP_POINTERPOSATTRIBUTE: size
            positionAttribute.size = size;

            // TS_FP_POINTERPOSATTRIBUTE: pointerPositionUpdateData
            int index = 0;
            positionAttribute.pointerPositionUpdateData = ParseTsPointerPosAttribute(updateData, ref index);

            // Check if data length exceeded expectation
            VerifyDataLength(updateData.Length, index, ConstValue.ERROR_MESSAGE_DATA_LENGTH_EXCEEDED);
            return positionAttribute;
        }
        /// <summary>
        /// Parse TS_FP_POINTERATTRIBUTE
        /// </summary>
        /// <param name="updateHeader">update header</param>
        /// <param name="compressionFlags">compression flags</param>
        /// <param name="size">update data size(before decompression)</param>
        /// <param name="updateData">update data(decompressed)</param>
        /// <returns>TS_FP_POINTERATTRIBUTE</returns>
        private TS_FP_POINTERATTRIBUTE ParseTsFpPointerAttribute(
            byte updateHeader,
            compressedType_Values compressionFlags,
            UInt16 size,
            byte[] updateData)
        {
            TS_FP_POINTERATTRIBUTE attribute = new TS_FP_POINTERATTRIBUTE();

            // TS_FP_POINTERATTRIBUTE: updateHeader
            attribute.updateHeader = updateHeader;

            // TS_FP_POINTERATTRIBUTE: compressionFlags
            attribute.compressionFlags = compressionFlags;

            // TS_FP_POINTERATTRIBUTE: size
            attribute.size = size;

            // TS_FP_POINTERATTRIBUTE: newPointerUpdateData
            int index = 0;
            attribute.newPointerUpdateData = ParseTsPointerAttribute(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 attribute;
        }