Ejemplo n.º 1
0
        /// <summary>
        /// Read the next <see cref="T:PacketBuffer"/> from the stream.
        /// </summary>
        /// <returns>The next packet extracted from the stream.</returns>
        /// <param name="processedBytes">Incremented by the number of bytes read from the stream. See remarks.</param>
        /// <remarks>
        /// The next packet is returned first from the current <see cref="T:CollatedPacketDecoder"/> if possible.
        /// Otherwise packet data are read from the stream and decoded as required. The <paramref name="processedBytes"/>
        /// value is only adjusted when data are read from the stream, not when a packet is extracted from the
        /// collation buffer.
        /// </remarks>
        public PacketBuffer NextPacket(ref long processedBytes)
        {
            PacketBuffer packet = null;

            // If decoding, just pull from the decoder.
            if (DecodingCollated)
            {
                packet = _decoder.Next();
                if (packet != null)
                {
                    return(packet);
                }
            }

            // Check for transition from raw stream to GZip stream.
            if (!_isGZipStream && GZipUtil.IsGZipStream(_activeStream))
            {
                _isGZipStream = true;
                _activeStream = new GZipStream(_activeStream, CompressionMode.Decompress);
            }

            // Read next packet.
            int bytesRead = 0;

            _headerStream.Position = 0;
            _headerStream.SetLength(PacketHeader.Size);

            if (!_searchForHeader)
            {
                bytesRead = _activeStream.Read(_headerStream.GetBuffer(), 0, PacketHeader.Size);
            }
            else
            {
                _searchForHeader = false;
                // Look for the marker bytes.
                UInt32 marker     = 0;
                int    markerSize = 4;
                while (!EndOfStream && marker != PacketHeader.PacketMarker)
                {
                    bytesRead = _activeStream.Read(_headerStream.GetBuffer(), 0, markerSize);
                    marker    = Endian.FromNetwork(BitConverter.ToUInt32(_headerStream.GetBuffer(), 0));
                }

                if (marker != PacketHeader.PacketMarker)
                {
                    // Failed.
                    EndOfStream = true;
                    return(null);
                }

                bytesRead += _activeStream.Read(_headerStream.GetBuffer(), markerSize, PacketHeader.Size - markerSize);
            }

            if (bytesRead < PacketHeader.Size)
            {
                EndOfStream = true;
                return(null);
            }

            _headerStream.SetLength(bytesRead);

            // Decode header.
            if (!_header.Read(new NetworkReader(_headerStream)))
            {
                // TODO: Throw exception
                _searchForHeader = true;
                return(null);
            }

            // Extract packet.
            int crcSize = ((_header.Flags & (byte)PacketFlag.NoCrc) == 0) ? Crc16.CrcSize : 0;

            packet = new PacketBuffer(_header.PacketSize + crcSize);
            packet.Emplace(_headerStream.GetBuffer(), bytesRead);
            processedBytes += packet.Emplace(_activeStream, _header.PacketSize + crcSize - bytesRead);
            if (packet.Status != PacketBufferStatus.Complete)
            {
                // TODO: throw exception
                _searchForHeader = true;
                return(packet);
            }

            // Decoder packet.
            _decoder.SetPacket(packet);
            packet = _decoder.Next();
            return(packet);
        }