/* slices a read only contiguous buffer of chunkLength */ private ByteBuffer slice(int chunkLength) { int len = chunkLength; long oldOffset = currentOffset; ByteBuffer slice; if (compressed.remaining() >= len) { slice = compressed.slice(); // simple case slice.limit(len); currentOffset += len; compressed.position(compressed.position() + len); return slice; } else if (currentRange >= (bytes.Count - 1)) { // nothing has been modified yet throw new IOException("EOF in " + this + " while trying to read " + chunkLength + " bytes"); } if (LOG.isDebugEnabled()) { LOG.debug(String.Format( "Crossing into next BufferChunk because compressed only has %d bytes (needs %d)", compressed.remaining(), len)); } // we need to consolidate 2 or more buffers into 1 // first copy out compressed buffers ByteBuffer copy = allocateBuffer(chunkLength, compressed.isDirect()); currentOffset += compressed.remaining(); len -= compressed.remaining(); copy.put(compressed); for (int i = currentRange; i < bytes.Count && len > 0; i++) { ++currentRange; if (LOG.isDebugEnabled()) { LOG.debug(String.Format("Read slow-path, >1 cross block reads with {0}", this.ToString())); } DiskRange range = bytes[i]; compressed = range.getData().duplicate(); if (compressed.remaining() >= len) { slice = compressed.slice(); slice.limit(len); copy.put(slice); currentOffset += len; compressed.position(compressed.position() + len); return copy; } currentOffset += compressed.remaining(); len -= compressed.remaining(); copy.put(compressed); } // restore offsets for exception clarity seek(oldOffset); throw new IOException("EOF in " + this + " while trying to read " + chunkLength + " bytes"); }
/// <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; } } }
/// <summary> /// Create a new Blob from an existing ByteBuffer. IMPORTANT: If copy is /// false, after calling this constructor, if you keep a pointer to the buffer /// then you must treat it as immutable and promise not to change it. /// </summary> /// /// <param name="buffer"></param> /// <param name="copy"></param> public Blob(ByteBuffer buffer, bool copy) { this.haveHashCode_ = false; if (buffer != null) { if (copy) { buffer_ = ILOG.J2CsMapping.NIO.ByteBuffer.allocate(buffer.remaining()); // Put updates buffer.position(), so save and restore it. int savePosition = buffer.position(); buffer_.put(buffer); buffer.position(savePosition); buffer_.flip(); } else buffer_ = buffer.slice(); } else buffer_ = null; }