public synchronized String readLine() throws IOException {

		// If we're at the beginning of the file, there's nothing to read.
		if (raf.getFilePointer() == 0) {
			return null;
		}

		// Set the start/end positions we'll be reading from. The start is the lower byte
		// position and the end is the higher (where we'll actually start reading from).
		long end = raf.getFilePointer();
		long start = end - BUFFER_SIZE;

		// Make sure we aren't trying to read past the beginning of the file. If so, just set
		// our start to 0 so we'll stop there.
		if (start < 0) {
			start = 0;
		}

		// Now create a byte array to hold the line we'll read.
		byte[] linePlus = new byte[(int) (end - start)];

		// Move the file pointer to our start location and read.
		raf.seek(start);
		raf.read(linePlus);

		// And finally move backwards from the end, writing characters to our outputs stream
		// as we go until we see a newline character.
		for (int i = linePlus.length - 1; i >= -1; i--) {

			if (i == -1) {
				raf.seek(0);
				String str = bufToString();
				return str;
			}

			byte c = linePlus[i];

			if (c == '\r' || c == '\n') {
				String str = bufToString();
				int newlineSubtrahend = 0;
				if (c == '\n' && i > 0 && linePlus[i - 1] == '\r') {
					// Need to subtract off another character for Windows newlines (\r\n)
					newlineSubtrahend = 1;
				}
				raf.seek(raf.getFilePointer() - (linePlus.length - i) - newlineSubtrahend);
				return str;
			}

			baos.write(c);
		}

		return null;
	}
Reads a single line from the current file pointer position, in reverse.  To do this we do
the following:

1. Read a 'large enough' number of bytes into a buffer (enough to guarantee a full line of
   text.
2. Move backwards through the bytes just read until a newline or carriage return is found.
3. Throw away the rest of the bytes and return the line found.

@return
@throws IOException
Ghidra/Framework/Project/src/main/java/ghidra/framework/main/logviewer/model/ReverseLineReader.java