1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file or at 6 // https://developers.google.com/open-source/licenses/bsd 7 8 package com.google.protobuf; 9 10 import static com.google.protobuf.Internal.EMPTY_BYTE_BUFFER; 11 12 import java.io.IOException; 13 import java.io.InputStream; 14 import java.nio.ByteBuffer; 15 import java.util.Iterator; 16 17 class IterableByteBufferInputStream extends InputStream { 18 /** The {@link Iterator} with type {@link ByteBuffer} of {@code input} */ 19 private Iterator<ByteBuffer> iterator; 20 /** The current ByteBuffer; */ 21 private ByteBuffer currentByteBuffer; 22 /** The number of ByteBuffers in the input data. */ 23 private int dataSize; 24 /** 25 * Current {@code ByteBuffer}'s index 26 * 27 * <p>If index equals dataSize, then all the data in the InputStream has been consumed 28 */ 29 private int currentIndex; 30 /** The current position for current ByteBuffer */ 31 private int currentByteBufferPos; 32 /** Whether current ByteBuffer has an array */ 33 private boolean hasArray; 34 /** 35 * If the current ByteBuffer is unsafe-direct based, currentArray is null; otherwise should be the 36 * array inside ByteBuffer. 37 */ 38 private byte[] currentArray; 39 /** Current ByteBuffer's array offset */ 40 private int currentArrayOffset; 41 /** 42 * If the current ByteBuffer is unsafe-direct based, currentAddress is the start address of this 43 * ByteBuffer; otherwise should be zero. 44 */ 45 private long currentAddress; 46 IterableByteBufferInputStream(Iterable<ByteBuffer> data)47 IterableByteBufferInputStream(Iterable<ByteBuffer> data) { 48 iterator = data.iterator(); 49 dataSize = 0; 50 for (ByteBuffer unused : data) { 51 dataSize++; 52 } 53 currentIndex = -1; 54 55 if (!getNextByteBuffer()) { 56 currentByteBuffer = EMPTY_BYTE_BUFFER; 57 currentIndex = 0; 58 currentByteBufferPos = 0; 59 currentAddress = 0; 60 } 61 } 62 getNextByteBuffer()63 private boolean getNextByteBuffer() { 64 currentIndex++; 65 if (!iterator.hasNext()) { 66 return false; 67 } 68 currentByteBuffer = iterator.next(); 69 currentByteBufferPos = currentByteBuffer.position(); 70 if (currentByteBuffer.hasArray()) { 71 hasArray = true; 72 currentArray = currentByteBuffer.array(); 73 currentArrayOffset = currentByteBuffer.arrayOffset(); 74 } else { 75 hasArray = false; 76 currentAddress = UnsafeUtil.addressOffset(currentByteBuffer); 77 currentArray = null; 78 } 79 return true; 80 } 81 updateCurrentByteBufferPos(int numberOfBytesRead)82 private void updateCurrentByteBufferPos(int numberOfBytesRead) { 83 currentByteBufferPos += numberOfBytesRead; 84 if (currentByteBufferPos == currentByteBuffer.limit()) { 85 getNextByteBuffer(); 86 } 87 } 88 89 @Override read()90 public int read() throws IOException { 91 if (currentIndex == dataSize) { 92 return -1; 93 } 94 if (hasArray) { 95 int result = currentArray[currentByteBufferPos + currentArrayOffset] & 0xFF; 96 updateCurrentByteBufferPos(1); 97 return result; 98 } else { 99 int result = UnsafeUtil.getByte(currentByteBufferPos + currentAddress) & 0xFF; 100 updateCurrentByteBufferPos(1); 101 return result; 102 } 103 } 104 105 @Override read(byte[] output, int offset, int length)106 public int read(byte[] output, int offset, int length) throws IOException { 107 if (currentIndex == dataSize) { 108 return -1; 109 } 110 int remaining = currentByteBuffer.limit() - currentByteBufferPos; 111 if (length > remaining) { 112 length = remaining; 113 } 114 if (hasArray) { 115 System.arraycopy( 116 currentArray, currentByteBufferPos + currentArrayOffset, output, offset, length); 117 updateCurrentByteBufferPos(length); 118 } else { 119 int prevPos = currentByteBuffer.position(); 120 Java8Compatibility.position(currentByteBuffer, currentByteBufferPos); 121 currentByteBuffer.get(output, offset, length); 122 Java8Compatibility.position(currentByteBuffer, prevPos); 123 updateCurrentByteBufferPos(length); 124 } 125 return length; 126 } 127 } 128