/**
   * Tries to read more bytes from the input, making at least {@code n} bytes available in the
   * buffer. Caller must ensure that the requested space is not yet available, and that the
   * requested space is less than BUFFER_SIZE.
   *
   * @return {@code true} if the bytes could be made available; {@code false} if the end of the
   *     stream or the current limit was reached.
   */
  private boolean tryRefillBuffer(int n) throws IOException {
    if (bufferPos + n <= bufferSize) {
      throw new IllegalStateException(
          "refillBuffer() called when " + n + " bytes were already available in buffer");
    }

    if (totalBytesRetired + bufferPos + n > currentLimit) {
      // Oops, we hit a limit.
      return false;
    }

    if (refillCallback != null) {
      refillCallback.onRefill();
    }

    if (input != null) {
      int pos = bufferPos;
      if (pos > 0) {
        if (bufferSize > pos) {
          System.arraycopy(buffer, pos, buffer, 0, bufferSize - pos);
        }
        totalBytesRetired += pos;
        bufferSize -= pos;
        bufferPos = 0;
      }

      int bytesRead = input.read(buffer, bufferSize, buffer.length - bufferSize);
      if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) {
        throw new IllegalStateException(
            "InputStream#read(byte[]) returned invalid result: "
                + bytesRead
                + "\nThe InputStream implementation is buggy.");
      }
      if (bytesRead > 0) {
        bufferSize += bytesRead;
        // Integer-overflow-conscious check against sizeLimit
        if (totalBytesRetired + n - sizeLimit > 0) {
          throw InvalidProtocolBufferException.sizeLimitExceeded();
        }
        recomputeBufferSizeAfterLimit();
        return (bufferSize >= n) ? true : tryRefillBuffer(n);
      }
    }

    return false;
  }
 private void checkSizeLimitExceeded(InvalidProtocolBufferException e) {
   assertEquals(InvalidProtocolBufferException.sizeLimitExceeded().getMessage(), e.getMessage());
 }