/**
   * Try to read a specified number of bytes.
   *
   * @param amountToRead is the number of bytes we need
   * @param collectData is true if we need to actually look at the data. If false, we know we're
   *     skipping this entry, and all we need to do is to count until we get to the right spot.
   * @return a byte buffer positioned at the head of the desired portion, or null if we reached eof.
   */
  private ByteBuffer readData(int amountToRead, boolean collectData)
      throws ChecksumException, EOFException, FileNotFoundException, DatabaseException {

    int alreadyRead = 0;
    ByteBuffer completeBuffer = null;
    saveBuffer.clear();

    while ((alreadyRead < amountToRead) && !eof) {

      int bytesNeeded = amountToRead - alreadyRead;
      if (window.hasRemaining()) {

        /* There's data in the window, process it. */
        if (collectData) {

          /*
           * Save data in a buffer for processing.
           */
          if ((alreadyRead > 0) || (window.remaining() < bytesNeeded)) {

            /* We need to piece an entry together. */
            copyToSaveBuffer(bytesNeeded);
            alreadyRead = threadSafeBufferPosition(saveBuffer);
            completeBuffer = saveBuffer;
          } else {

            /* A complete entry is available in this buffer. */
            completeBuffer = window.getBuffer();
            alreadyRead = amountToRead;
          }
        } else {

          /*
           * We're not processing the data, so need to save it. just
           * move buffer positions.
           */
          int positionIncrement =
              (window.remaining() > bytesNeeded) ? bytesNeeded : window.remaining();

          alreadyRead += positionIncrement;
          window.incrementBufferPosition(positionIncrement);
          completeBuffer = window.getBuffer();
        }
      } else {

        /*
         * Look for more data.
         */
        if (window.fillNext(singleFile, bytesNeeded)) {
          /* This call to fillNext slid the window to a new file. */
          nextEntryOffset = 0;
        }
      }
    }

    /* Flip the save buffer just in case we've been accumulating in it. */
    threadSafeBufferFlip(saveBuffer);

    return completeBuffer;
  }