/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ using System; using Qpid.Buffer; namespace Qpid.Codec { public abstract class CumulativeProtocolDecoder : IProtocolDecoder { ByteBuffer _remaining; /// /// Creates a new instance with the 65535 bytes initial capacity of /// cumulative buffer. /// Note that capacity is currently fixed as the .NET ByteBuffers does not implement auto-expansion. /// protected CumulativeProtocolDecoder() { // Needs to be as large as the largest frame to be decoded. _remaining = ByteBuffer.Allocate(65535); // FIXME: Probably should not be fixed. } /// /// Cumulates content of in into internal buffer and forwards /// decoding request to {@link #doDecode(IoSession, ByteBuffer, ProtocolDecoderOutput)}. /// doDecode() is invoked repeatedly until it returns false /// and the cumulative buffer is compacted after decoding ends. /// /// /// if your doDecode() returned true not consuming the cumulative buffer. /// public void Decode(ByteBuffer input, IProtocolDecoderOutput output) { if (_remaining.Position != 0) // If there were remaining undecoded bytes { DecodeRemainingAndInput(input, output); } else { DecodeInput(input, output); } } private void DecodeInput(ByteBuffer input, IProtocolDecoderOutput output) { // Just decode the input buffer and remember any remaining undecoded bytes. try { DecodeAll(input, output); } finally { if (input.HasRemaining()) { _remaining.Put(input); } } } private void DecodeRemainingAndInput(ByteBuffer input, IProtocolDecoderOutput output) { // Concatenate input buffer with left-over bytes. _remaining.Put(input); _remaining.Flip(); try { DecodeAll(_remaining, output); } finally { _remaining.Compact(); } } private void DecodeAll(ByteBuffer buf, IProtocolDecoderOutput output) { for (;;) { int oldPos = buf.Position; bool decoded = DoDecode(buf, output); if (decoded) { if (buf.Position == oldPos) { throw new Exception( "doDecode() can't return true when buffer is not consumed."); } if (!buf.HasRemaining()) { break; } } else { break; } } } /// /// Implement this method to consume the specified cumulative buffer and /// decode its content into message(s). /// /// the cumulative buffer /// decoder output /// /// true if and only if there's more to decode in the buffer /// and you want to have doDecode method invoked again. /// Return false if remaining data is not enough to decode, /// then this method will be invoked again when more data is cumulated. /// /// If cannot decode protected abstract bool DoDecode(ByteBuffer input, IProtocolDecoderOutput output); public void Dispose() { _remaining = null; } } }