test_class.file: java_src/src/test/java/com/google/crypto/tink/subtle/RewindableReadableByteChannelTest.java
test_class.identifier: RewindableReadableByteChannelTest
test_case.body: @Test
    public void testSmallChunksNoDataEveryOtherRead() throws Exception {
      byte[] inputData = "The quick brown fox jumps over the lazy dog.".getBytes(UTF_8);
      ReadableByteChannel baseChannel =
          new ByteBufferChannel(inputData, /*maxChunkSize=*/ 10, /*noDataEveryOtherRead=*/ true);
      RewindableReadableByteChannel rewindableChannel =
          new RewindableReadableByteChannel(baseChannel);
  
      ByteBuffer buffer1 = ByteBuffer.allocate(15);
      assertEquals(0, rewindableChannel.read(buffer1));
      assertEquals(10, rewindableChannel.read(buffer1));
      assertEquals(0, rewindableChannel.read(buffer1));
      assertEquals(5, rewindableChannel.read(buffer1));
      assertArrayEquals(buffer1.array(), Arrays.copyOf(inputData, 15));
    }
test_case.class_method_signature: RewindableReadableByteChannelTest.testSmallChunksNoDataEveryOtherRead()
test_case.full_signature: @Test public void testSmallChunksNoDataEveryOtherRead()
test_case.identifier: testSmallChunksNoDataEveryOtherRead
test_case.invocations: getBytes allocate assertEquals read assertEquals read assertEquals read assertEquals read assertArrayEquals array copyOf
test_case.modifiers: @Test public
test_case.parameters: ()
test_case.return: void
test_case.signature: void testSmallChunksNoDataEveryOtherRead()
focal_class.declarator: baseChannel
focal_class.modifier: @GuardedBy("this")
    final
focal_class.original_string: @GuardedBy("this")
    final ReadableByteChannel baseChannel;
focal_class.type: ReadableByteChannel
focal_class.var_name: baseChannel
focal_class.declarator: buffer
focal_class.modifier: @GuardedBy("this")
focal_class.original_string: @GuardedBy("this")
    ByteBuffer buffer;
focal_class.type: ByteBuffer
focal_class.var_name: buffer
focal_class.declarator: canRewind
focal_class.modifier: @GuardedBy("this")
focal_class.original_string: @GuardedBy("this")
    boolean canRewind;
focal_class.type: boolean
focal_class.var_name: canRewind
focal_class.declarator: directRead
focal_class.modifier: @GuardedBy("this")
focal_class.original_string: @GuardedBy("this")
    boolean directRead;
focal_class.type: boolean
focal_class.var_name: directRead
focal_class.file: java_src/src/main/java/com/google/crypto/tink/subtle/RewindableReadableByteChannel.java
focal_class.identifier: RewindableReadableByteChannel
focal_class.interfaces: implements ReadableByteChannel
focal_class.class_method_signature: RewindableReadableByteChannel.RewindableReadableByteChannel(ReadableByteChannel baseChannel)
focal_class.full_signature: public  RewindableReadableByteChannel(ReadableByteChannel baseChannel)
focal_class.identifier: RewindableReadableByteChannel
focal_class.modifiers: public
focal_class.parameters: (ReadableByteChannel baseChannel)
focal_class.signature:  RewindableReadableByteChannel(ReadableByteChannel baseChannel)
focal_class.class_method_signature: RewindableReadableByteChannel.disableRewinding()
focal_class.full_signature: public synchronized void disableRewinding()
focal_class.identifier: disableRewinding
focal_class.modifiers: public synchronized
focal_class.parameters: ()
focal_class.return: void
focal_class.signature: void disableRewinding()
focal_class.class_method_signature: RewindableReadableByteChannel.rewind()
focal_class.full_signature: public synchronized void rewind()
focal_class.identifier: rewind
focal_class.modifiers: public synchronized
focal_class.parameters: ()
focal_class.return: void
focal_class.signature: void rewind()
focal_class.class_method_signature: RewindableReadableByteChannel.setBufferLimit(int newLimit)
focal_class.full_signature: private synchronized void setBufferLimit(int newLimit)
focal_class.identifier: setBufferLimit
focal_class.modifiers: private synchronized
focal_class.parameters: (int newLimit)
focal_class.return: void
focal_class.signature: void setBufferLimit(int newLimit)
focal_class.class_method_signature: RewindableReadableByteChannel.read(ByteBuffer dst)
focal_class.full_signature: @Override public synchronized int read(ByteBuffer dst)
focal_class.identifier: read
focal_class.modifiers: @Override public synchronized
focal_class.parameters: (ByteBuffer dst)
focal_class.return: int
focal_class.signature: int read(ByteBuffer dst)
focal_class.class_method_signature: RewindableReadableByteChannel.close()
focal_class.full_signature: @Override public synchronized void close()
focal_class.identifier: close
focal_class.modifiers: @Override public synchronized
focal_class.parameters: ()
focal_class.return: void
focal_class.signature: void close()
focal_class.class_method_signature: RewindableReadableByteChannel.isOpen()
focal_class.full_signature: @Override public synchronized boolean isOpen()
focal_class.identifier: isOpen
focal_class.modifiers: @Override public synchronized
focal_class.parameters: ()
focal_class.return: boolean
focal_class.signature: boolean isOpen()
focal_method.body: @Override
    public synchronized int read(ByteBuffer dst) throws IOException {
      if (directRead) {
        return baseChannel.read(dst);
      }
      int bytesToReadCount = dst.remaining();
      if (bytesToReadCount == 0) {
        return 0;
      }
      if (buffer == null) {  // The first read, no cached data yet.
        if (!canRewind) {
          directRead = true;
          return baseChannel.read(dst);
        }
        buffer = ByteBuffer.allocate(bytesToReadCount);
        int baseReadResult = baseChannel.read(buffer);
        // put buffer in draining mode
        buffer.flip();
        if (baseReadResult > 0) {
          dst.put(buffer);
        }
        return baseReadResult;
      }
      // Subsequent read
      if (buffer.remaining() >= bytesToReadCount) {
        // buffer has all data needed.
        // dst.put expects buffer.remaining() <= dst.remaining(). So we have to temporarily lower
        // buffer.limit. Note that
        // buffer.position() + bytesToReadCount <= buffer.position() + buffer.remaining()
        // = buffer.position() + buffer.limit() - buffer.position() = buffer.limit().
        int limit = buffer.limit();
        buffer.limit(buffer.position() + bytesToReadCount);
        dst.put(buffer);
        buffer.limit(limit);
        if (!canRewind && !buffer.hasRemaining()) {
          buffer = null;
          directRead = true;
        }
        return bytesToReadCount;
      }
      int bytesFromBufferCount = buffer.remaining();
      int stillToReadCount = bytesToReadCount - bytesFromBufferCount;
  
      // buffer is in draining mode.
      int currentReadPos = buffer.position();
      int contentLimit = buffer.limit();
      // Put the buffer into into filling mode by hand. The filling should start right after the
      // current limit, and at most stillToReadCount bytes should be written.
      setBufferLimit(contentLimit + stillToReadCount);
      buffer.position(contentLimit);
      int baseReadResult = baseChannel.read(buffer);
      // Put buffer in draining mode.
      buffer.flip();
      buffer.position(currentReadPos); // restore reading position.
      dst.put(buffer);
      if (bytesFromBufferCount == 0 && baseReadResult < 0) {
        return -1;  // EOF
      }
      int bytesCount = buffer.position() - currentReadPos;
      if (!canRewind && !buffer.hasRemaining()) {
        buffer = null;
        directRead = true;
      }
      return bytesCount;
    }
focal_method.class_method_signature: RewindableReadableByteChannel.read(ByteBuffer dst)
focal_method.full_signature: @Override public synchronized int read(ByteBuffer dst)
focal_method.identifier: read
focal_method.invocations: read remaining read allocate read flip put remaining limit limit position put limit hasRemaining remaining position limit setBufferLimit position read flip position put position hasRemaining
focal_method.modifiers: @Override public synchronized
focal_method.parameters: (ByteBuffer dst)
focal_method.return: int
focal_method.signature: int read(ByteBuffer dst)