/// <summary>
        /// Continue scanning input starting from offset_ to find the element end.
        /// If the end of the element which started at offset 0 is found, this returns
        /// true and getOffset() is the length of the element.  Otherwise, this returns
        /// false which means you should read more into input and call again.
        /// </summary>
        ///
        /// <param name="input">You have to pass in input each time because the buffer could be reallocated.</param>
        /// <returns>true if found the element end, false if not.</returns>
        public bool findElementEnd(ByteBuffer input)
        {
            if (gotElementEnd_)
                // Someone is calling when we already got the end.
                return true;

            TlvDecoder decoder = new TlvDecoder(input);

            while (true) {
                if (offset_ >= input.limit())
                    // All the cases assume we have some input. Return and wait for more.
                    return false;

                if (state_ == TlvStructureDecoder.READ_TYPE) {
                    int firstOctet = (int) input.get(offset_) & 0xff;
                    offset_ += 1;
                    if (firstOctet < 253)
                        // The value is simple, so we can skip straight to reading the length.
                        state_ = TlvStructureDecoder.READ_LENGTH;
                    else {
                        // Set up to skip the type bytes.
                        if (firstOctet == 253)
                            nBytesToRead_ = 2;
                        else if (firstOctet == 254)
                            nBytesToRead_ = 4;
                        else
                            // value == 255.
                            nBytesToRead_ = 8;

                        state_ = TlvStructureDecoder.READ_TYPE_BYTES;
                    }
                } else if (state_ == TlvStructureDecoder.READ_TYPE_BYTES) {
                    int nRemainingBytes = input.limit() - offset_;
                    if (nRemainingBytes < nBytesToRead_) {
                        // Need more.
                        offset_ += nRemainingBytes;
                        nBytesToRead_ -= nRemainingBytes;
                        return false;
                    }

                    // Got the type bytes. Move on to read the length.
                    offset_ += nBytesToRead_;
                    state_ = TlvStructureDecoder.READ_LENGTH;
                } else if (state_ == TlvStructureDecoder.READ_LENGTH) {
                    int firstOctet_0 = (int) input.get(offset_) & 0xff;
                    offset_ += 1;
                    if (firstOctet_0 < 253) {
                        // The value is simple, so we can skip straight to reading
                        //  the value bytes.
                        nBytesToRead_ = firstOctet_0;
                        if (nBytesToRead_ == 0) {
                            // No value bytes to read. We're finished.
                            gotElementEnd_ = true;
                            return true;
                        }

                        state_ = TlvStructureDecoder.READ_VALUE_BYTES;
                    } else {
                        // We need to read the bytes in the extended encoding of
                        //  the length.
                        if (firstOctet_0 == 253)
                            nBytesToRead_ = 2;
                        else if (firstOctet_0 == 254)
                            nBytesToRead_ = 4;
                        else
                            // value == 255.
                            nBytesToRead_ = 8;

                        // We need to use firstOctet in the next state.
                        firstOctet_ = firstOctet_0;
                        state_ = TlvStructureDecoder.READ_LENGTH_BYTES;
                    }
                } else if (state_ == TlvStructureDecoder.READ_LENGTH_BYTES) {
                    int nRemainingBytes_1 = input.limit() - offset_;
                    if (!useHeaderBuffer_ && nRemainingBytes_1 >= nBytesToRead_) {
                        // We don't have to use the headerBuffer. Set nBytesToRead.
                        decoder.seek(offset_);

                        nBytesToRead_ = decoder.readExtendedVarNumber(firstOctet_);
                        // Update offset_ to the decoder's offset after reading.
                        offset_ = decoder.getOffset();
                    } else {
                        useHeaderBuffer_ = true;

                        int nNeededBytes = nBytesToRead_ - headerBuffer_.position();
                        if (nNeededBytes > nRemainingBytes_1) {
                            // We can't get all of the header bytes from this input.
                            // Save in headerBuffer.
                            if (headerBuffer_.position() + nRemainingBytes_1 > headerBuffer_
                                    .limit())
                                // We don't expect this to happen.
                                throw new Exception(
                                        "Cannot store more header bytes than the size of headerBuffer");
                            ByteBuffer remainingInput = input.duplicate();
                            remainingInput.position(offset_);
                            headerBuffer_.put(remainingInput);
                            offset_ += nRemainingBytes_1;

                            return false;
                        }

                        // Copy the remaining bytes into headerBuffer, read the
                        //   length and set nBytesToRead.
                        if (headerBuffer_.position() + nNeededBytes > headerBuffer_
                                .limit())
                            // We don't expect this to happen.
                            throw new Exception(
                                    "Cannot store more header bytes than the size of headerBuffer");
                        ByteBuffer remainingLengthBytes = input.duplicate();
                        remainingLengthBytes.position(offset_);
                        remainingLengthBytes.limit(offset_ + nNeededBytes);
                        headerBuffer_.put(remainingLengthBytes);
                        offset_ += nNeededBytes;

                        // Use a local decoder just for the headerBuffer.
                        headerBuffer_.flip();
                        TlvDecoder bufferDecoder = new TlvDecoder(headerBuffer_);
                        // Replace nBytesToRead with the length of the value.
                        nBytesToRead_ = bufferDecoder
                                .readExtendedVarNumber(firstOctet_);
                    }

                    if (nBytesToRead_ == 0) {
                        // No value bytes to read. We're finished.
                        gotElementEnd_ = true;
                        return true;
                    }

                    // Get ready to read the value bytes.
                    state_ = TlvStructureDecoder.READ_VALUE_BYTES;
                } else if (state_ == TlvStructureDecoder.READ_VALUE_BYTES) {
                    int nRemainingBytes_2 = input.limit() - offset_;
                    if (nRemainingBytes_2 < nBytesToRead_) {
                        // Need more.
                        offset_ += nRemainingBytes_2;
                        nBytesToRead_ -= nRemainingBytes_2;
                        return false;
                    }

                    // Got the bytes. We're finished.
                    offset_ += nBytesToRead_;
                    gotElementEnd_ = true;
                    return true;
                } else
                    // We don't expect this to happen.
                    throw new Exception("findElementEnd: unrecognized state");
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Continue to read data until the end of an element, then call
        /// elementListener.onReceivedElement(element ). The buffer passed to
        /// onReceivedElement is only valid during this call.  If you need the data
        /// later, you must copy.
        /// </summary>
        ///
        /// <param name="data"></param>
        /// <exception cref="EncodingException">For invalid encoding.</exception>
        public void onReceivedData(ByteBuffer data)
        {
            // We may repeatedly set data to a slice as we read elements.
            data = data.slice();

            // Process multiple objects in the data.
            while (true) {
                bool gotElementEnd;
                int offset;

                try {
                    if (!usePartialData_) {
                        // This is the beginning of an element.
                        if (data.remaining() <= 0)
                            // Wait for more data.
                            return;
                    }

                    // Scan the input to check if a whole TLV object has been read.
                    tlvStructureDecoder_.seek(0);
                    gotElementEnd = tlvStructureDecoder_.findElementEnd(data);
                    offset = tlvStructureDecoder_.getOffset();
                } catch (EncodingException ex) {
                    // Reset to read a new element on the next call.
                    usePartialData_ = false;
                    tlvStructureDecoder_ = new TlvStructureDecoder();

                    throw ex;
                }

                if (gotElementEnd) {
                    // Got the remainder of an element.  Report to the caller.
                    ByteBuffer element;
                    if (usePartialData_) {
                        // We have partial data from a previous call, so append this data and point to partialData.
                        partialData_.ensuredPut(data, 0, offset);

                        element = partialData_.flippedBuffer();
                        // Assume we don't need to use partialData anymore until needed.
                        usePartialData_ = false;
                    } else {
                        // We are not using partialData, so just point to the input data buffer.
                        element = data.duplicate();
                        element.limit(offset);
                    }

                    // Reset to read a new object. Do this before calling onReceivedElement
                    // in case it throws an exception.
                    data.position(offset);
                    data = data.slice();
                    tlvStructureDecoder_ = new TlvStructureDecoder();

                    elementListener_.onReceivedElement(element);
                    if (data.remaining() <= 0)
                        // No more data in the packet.
                        return;

                    // else loop back to decode.
                } else {
                    // Save remaining data for a later call.
                    if (!usePartialData_) {
                        usePartialData_ = true;
                        partialData_.position(0);
                    }

                    if (partialData_.buffer().position() + data.remaining() > net.named_data.jndn.util.Common.MAX_NDN_PACKET_SIZE) {
                        // Reset to read a new element on the next call.
                        usePartialData_ = false;
                        tlvStructureDecoder_ = new TlvStructureDecoder();

                        throw new EncodingException(
                                "The incoming packet exceeds the maximum limit Face.getMaxNdnPacketSize()");
                    }

                    partialData_.ensuredPut(data);
                    return;
                }
            }
        }
Esempio n. 3
0
 /// <summary>
 /// Create a new TlvDecoder to decode the input.
 /// </summary>
 ///
 /// <param name="input">the underlying buffer whose contents must remain valid during the life of this object.</param>
 public TlvDecoder(ByteBuffer input)
 {
     input_ = input.duplicate();
 }