//# 2 errors, 167 messages
//#
/*
    //#ReverseFileReader.java:1:1: class: com.dmdirc.addons.logging.ReverseFileReader
    //#ReverseFileReader.java:1:1: method: com.dmdirc.addons.logging.ReverseFileReader.com.dmdirc.addons.logging.ReverseFileReader__static_init
 * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.dmdirc.addons.logging;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
import java.io.IOException;
import java.io.EOFException;
import java.nio.charset.Charset;
import java.util.Stack;
import java.util.ArrayList;

/**
 * Reads a file in reverse.
 *
 * @author Shane 'Dataforce' McCormack
 */
public class ReverseFileReader {
	/** File to manipulate. */
	private RandomAccessFile file;
	/** Number of bytes to skip backwards at a time. */
	private byte seekLength = 50;

	/**
	 * Create a new ReverseFileReader.
	 *
	 * @param filename File to open.
	 * @throws FileNotFoundException If the file is not a regular file.
	 * @throws SecurityException If a security manager exists and its checkRead method denies read access to the file.
	 * @throws IOException If there is an error seeking to the end of the file.
	 */
	public ReverseFileReader(String filename) throws FileNotFoundException, SecurityException, IOException {
    //#ReverseFileReader.java:53: method: void com.dmdirc.addons.logging.ReverseFileReader.com.dmdirc.addons.logging.ReverseFileReader(String)
    //#input(void com.dmdirc.addons.logging.ReverseFileReader(String)): __Descendant_Table[com/dmdirc/addons/logging/ReverseFileReader]
    //#input(void com.dmdirc.addons.logging.ReverseFileReader(String)): __Descendant_Table[others]
    //#input(void com.dmdirc.addons.logging.ReverseFileReader(String)): __Dispatch_Table.reset()V
    //#input(void com.dmdirc.addons.logging.ReverseFileReader(String)): filename
    //#input(void com.dmdirc.addons.logging.ReverseFileReader(String)): this
    //#input(void com.dmdirc.addons.logging.ReverseFileReader(String)): this.__Tag
    //#output(void com.dmdirc.addons.logging.ReverseFileReader(String)): new RandomAccessFile(ReverseFileReader#1) num objects
    //#output(void com.dmdirc.addons.logging.ReverseFileReader(String)): this.file
    //#output(void com.dmdirc.addons.logging.ReverseFileReader(String)): this.seekLength
    //#new obj(void com.dmdirc.addons.logging.ReverseFileReader(String)): new RandomAccessFile(ReverseFileReader#1)
    //#pre[3] (void com.dmdirc.addons.logging.ReverseFileReader(String)): this.__Tag == com/dmdirc/addons/logging/ReverseFileReader
    //#post(void com.dmdirc.addons.logging.ReverseFileReader(String)): this.file == &new RandomAccessFile(ReverseFileReader#1)
    //#post(void com.dmdirc.addons.logging.ReverseFileReader(String)): this.seekLength == 50
    //#post(void com.dmdirc.addons.logging.ReverseFileReader(String)): new RandomAccessFile(ReverseFileReader#1) num objects == 1
    //#unanalyzed(void com.dmdirc.addons.logging.ReverseFileReader(String)): Effects-of-calling:java.io.RandomAccessFile:seek
    //#unanalyzed(void com.dmdirc.addons.logging.ReverseFileReader(String)): Effects-of-calling:java.io.RandomAccessFile:length
		file = new RandomAccessFile(filename, "r");
		reset();
	}
    //#ReverseFileReader.java:56: end of method: void com.dmdirc.addons.logging.ReverseFileReader.com.dmdirc.addons.logging.ReverseFileReader(String)
	
	/**
	 * Create a new ReverseFileReader.
	 *
	 * @param myFile Existing file to use.
	 * @throws FileNotFoundException If the file is not a regular file.
	 * @throws SecurityException If a security manager exists and its checkRead method denies read access to the file.
	 * @throws IOException If there is an error seeking to the end of the file.
	 */
	public ReverseFileReader(File myFile) throws FileNotFoundException, SecurityException, IOException {
    //#ReverseFileReader.java:66: method: void com.dmdirc.addons.logging.ReverseFileReader.com.dmdirc.addons.logging.ReverseFileReader(File)
    //#input(void com.dmdirc.addons.logging.ReverseFileReader(File)): __Descendant_Table[com/dmdirc/addons/logging/ReverseFileReader]
    //#input(void com.dmdirc.addons.logging.ReverseFileReader(File)): __Descendant_Table[others]
    //#input(void com.dmdirc.addons.logging.ReverseFileReader(File)): __Dispatch_Table.reset()V
    //#input(void com.dmdirc.addons.logging.ReverseFileReader(File)): myFile
    //#input(void com.dmdirc.addons.logging.ReverseFileReader(File)): this
    //#input(void com.dmdirc.addons.logging.ReverseFileReader(File)): this.__Tag
    //#output(void com.dmdirc.addons.logging.ReverseFileReader(File)): new RandomAccessFile(ReverseFileReader#1) num objects
    //#output(void com.dmdirc.addons.logging.ReverseFileReader(File)): this.file
    //#output(void com.dmdirc.addons.logging.ReverseFileReader(File)): this.seekLength
    //#new obj(void com.dmdirc.addons.logging.ReverseFileReader(File)): new RandomAccessFile(ReverseFileReader#1)
    //#pre[3] (void com.dmdirc.addons.logging.ReverseFileReader(File)): this.__Tag == com/dmdirc/addons/logging/ReverseFileReader
    //#post(void com.dmdirc.addons.logging.ReverseFileReader(File)): this.file == &new RandomAccessFile(ReverseFileReader#1)
    //#post(void com.dmdirc.addons.logging.ReverseFileReader(File)): this.seekLength == 50
    //#post(void com.dmdirc.addons.logging.ReverseFileReader(File)): new RandomAccessFile(ReverseFileReader#1) num objects == 1
    //#unanalyzed(void com.dmdirc.addons.logging.ReverseFileReader(File)): Effects-of-calling:java.io.RandomAccessFile:seek
    //#unanalyzed(void com.dmdirc.addons.logging.ReverseFileReader(File)): Effects-of-calling:java.io.RandomAccessFile:length
		file = new RandomAccessFile(myFile, "r");
		reset();
	}
    //#ReverseFileReader.java:69: end of method: void com.dmdirc.addons.logging.ReverseFileReader.com.dmdirc.addons.logging.ReverseFileReader(File)
	
	/**
	 * Reset the file pointer to the end of the file.
	 *
	 * @throws IOException If there is an error seeking, or the file is closed.
	 */
	public void reset() throws IOException {
		if (file == null) { throw new IOException("File has been closed."); }
    //#ReverseFileReader.java:77: method: void com.dmdirc.addons.logging.ReverseFileReader.reset()
    //#input(void reset()): this
    //#input(void reset()): this.file
    //#pre[2] (void reset()): this.file != null
		file.seek(file.length());
	}
    //#ReverseFileReader.java:79: end of method: void com.dmdirc.addons.logging.ReverseFileReader.reset()
	
	/**
	 * Get the current seekLength.
	 *
	 * @return current seekLength
	 */
	public byte getSeekLength() {
		return seekLength;
    //#ReverseFileReader.java:87: method: byte com.dmdirc.addons.logging.ReverseFileReader.getSeekLength()
    //#input(byte getSeekLength()): this
    //#input(byte getSeekLength()): this.seekLength
    //#output(byte getSeekLength()): return_value
    //#pre[2] (byte getSeekLength()): init'ed(this.seekLength)
    //#post(byte getSeekLength()): return_value == this.seekLength
    //#post(byte getSeekLength()): init'ed(return_value)
    //#ReverseFileReader.java:87: end of method: byte com.dmdirc.addons.logging.ReverseFileReader.getSeekLength()
	}
	
	/**
	 * Set the seekLength.
	 *
	 * @param newValue New value for seekLength
	 */
	public void setSeekLength(final byte newValue) {
		seekLength = newValue;
    //#ReverseFileReader.java:96: method: void com.dmdirc.addons.logging.ReverseFileReader.setSeekLength(byte)
    //#input(void setSeekLength(byte)): newValue
    //#input(void setSeekLength(byte)): this
    //#output(void setSeekLength(byte)): this.seekLength
    //#post(void setSeekLength(byte)): this.seekLength == newValue
    //#post(void setSeekLength(byte)): init'ed(this.seekLength)
	}
    //#ReverseFileReader.java:97: end of method: void com.dmdirc.addons.logging.ReverseFileReader.setSeekLength(byte)
	
	/**
	 * Close the file pointer.
	 * This should be called before removing the reference to this object
	 *
	 * @throws IOException If there is an error closing the file, or if it has been closed already.
	 */
	public void close() throws IOException {
		if (file == null) { throw new IOException("File has been closed."); }
    //#ReverseFileReader.java:106: method: void com.dmdirc.addons.logging.ReverseFileReader.close()
    //#input(void close()): this
    //#input(void close()): this.file
    //#output(void close()): this.file
    //#pre[1] (void close()): this.file != null
    //#post(void close()): this.file == null
		file.close();
		file = null;
	}
    //#ReverseFileReader.java:109: end of method: void com.dmdirc.addons.logging.ReverseFileReader.close()

	/**
	 * Get the next full line.
	 *
	 * @return The next full line.
	 * @throws EOFException If there is no more lines.
	 * @throws IOException If an error reading or seeking occured, or if the fiel is closed.
	 */
	public String getNextLine() throws EOFException, IOException {
		if (file == null) { throw new IOException("File has been closed."); }
    //#ReverseFileReader.java:119: method: String com.dmdirc.addons.logging.ReverseFileReader.getNextLine()
    //#input(String getNextLine()): this
    //#input(String getNextLine()): this.file
    //#input(String getNextLine()): this.seekLength
    //#output(String getNextLine()): new String(getNextLine#4) num objects
    //#output(String getNextLine()): return_value
    //#new obj(String getNextLine()): new String(getNextLine#4)
    //#pre[2] (String getNextLine()): this.file != null
    //#pre[3] (String getNextLine()): init'ed(this.seekLength)
    //#presumption(String getNextLine()): java.io.RandomAccessFile:getFilePointer(...)@134 != 0
    //#presumption(String getNextLine()): java.io.RandomAccessFile:getFilePointer(...)@145 >= -2_147_483_648
    //#presumption(String getNextLine()): java.io.RandomAccessFile:getFilePointer(...)@145 - this.seekLength in {-2_147_483_903..18_446_744_073_709_551_615}
    //#presumption(String getNextLine()): java.util.ArrayList:get(...)@205 != null
    //#presumption(String getNextLine()): java.util.ArrayList:size(...)@204 >= 1
    //#presumption(String getNextLine()): java.util.ArrayList:size(...)@205 - java.util.ArrayList:size(...)@204 in {-6_442_450_943..0}
    //#post(String getNextLine()): return_value == &new String(getNextLine#4)
    //#post(String getNextLine()): new String(getNextLine#4) num objects == 1
    //#test_vector(String getNextLine()): bytes[i]@162: {13}, {10}, {-128..9, 11,12, 14..255}
    //#test_vector(String getNextLine()): java.io.RandomAccessFile:getFilePointer(...)@145 - this.seekLength: {1..18_446_744_073_709_551_615}, {-2_147_483_903..-1}
		// Used to store result to output.
//		StringBuilder line = new StringBuilder();
		final ArrayList<Byte> line = new ArrayList<Byte>(seekLength);
		// Used to store position in file pre-read
		long fp = 0;
    //#ReverseFileReader.java:124: Warning: unused assignment
    //#    Unused assignment into fp
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.addons.logging.ReverseFileReader
    //#    method: String getNextLine()
    //#    Attribs:  Uncertain
		// Used to store position in file when this is called
		long startfp = 0;
    //#ReverseFileReader.java:126: Warning: unused assignment
    //#    Unused assignment into startfp
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.addons.logging.ReverseFileReader
    //#    method: String getNextLine()
    //#    Attribs:  Uncertain
		// Used to store read bytes
		byte[] bytes;
		// Distance seeked
		int seekDistance = 0;
    //#ReverseFileReader.java:130: Warning: unused assignment
    //#    Unused assignment into seekDistance
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.addons.logging.ReverseFileReader
    //#    method: String getNextLine()
    //#    Attribs:  Uncertain
		
		// Check current position, if 0 we are at the start of the file
		// and should throw an exception.
		startfp = file.getFilePointer();
		if (startfp == 0) {
			throw new EOFException("Reached Start of file");
		}
		
		// Keep looping untill we get a full line, or the end of the file
		boolean keepLooping = true;
		boolean gotNewLine;
		while (keepLooping) {
			gotNewLine = false;
			// Get Current Position
			fp = file.getFilePointer();
			
			// Check how far to seek backwards (seekLength or to the start of the file)
			if (fp < seekLength) {
				// Seek to the start of the file;
				seekDistance = (int)fp;
				fp = 0;
			} else {
				// Seek to position current-seekLength
				seekDistance = seekLength;
				fp = fp - seekDistance;
			}
			// Seek!
			file.seek(fp);
			
			bytes = new byte[seekDistance];
    //#ReverseFileReader.java:160: ?overflow
    //#    seekDistance >= 0
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.addons.logging.ReverseFileReader
    //#    method: String getNextLine()
    //#    basic block: bb_6
    //#    assertion: seekDistance >= 0
    //#    VN: seekDistance
    //#    Expected: {0..+Inf, Invalid}
    //#    Bad: {-2_147_483_648..-1}
    //#    Attribs:  Int  Bad overlaps +/-1000  Bad < Exp  Uncertain
			// Read into the bytes array
			file.read(bytes);
			
			// And loop looking for data
			// This uses seekDistance so that only wanted data is checked.
			for (int i = seekDistance-1; i >= 0; --i) {
				// Check for New line Character, or a non carraige-return char
				if (bytes[i] == '\n') {
					// Seek to the location of this character and exit this loop.
					file.seek(fp+i);
    //#ReverseFileReader.java:170: ?overflow
    //#    fp + i in {-9_223_372_036_854_775_808..18_446_744_073_709_551_615}
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.addons.logging.ReverseFileReader
    //#    method: String getNextLine()
    //#    basic block: bb_9
    //#    assertion: fp + i in {-9_223_372_036_854_775_808..18_446_744_073_709_551_615}
    //#    VN: i + fp
    //#    Expected: {-9_223_372_036_854_775_808..18_446_744_073_709_551_615, Invalid}
    //#    Bad: {18_446_744_073_709_551_616..18_446_744_073_709_551_869}
    //#    Attribs:  Int  Bad > Exp
					gotNewLine = true;
					break;
				} else if (bytes[i] != '\r') {
					// Add to the result, the loop will continue going.
					line.add(0, bytes[i]);
				}
			}
			
			// We have now processed the data we read (Either added it all to the
			// buffer, or found a newline character.)
			
			if (fp == 0 && !gotNewLine) {
				// This part of the loop started from the start of the file, but didn't
				// find a new line anywhere. no more loops are posssible, so Treat
				// this as "got new line"
				gotNewLine = true;
				file.seek(0);
			}
			
			// Do we need to continue?
			if (gotNewLine) {
				// We have found a new line somewhere, thus we don't need
				// to read any more bytes, so exit the while loop!
				keepLooping = false;
			} else {
				// We have not found a new line anywhere,
				// Seek to the pre-read position, and repeat.
				file.seek(fp);
			}
			
		}
		
		// Return the data obtained.
		byte[] result = new byte[line.size()];
		for (int i = 0; i < line.size(); ++i) { result[i] = line.get(i); }
		return new String(result, Charset.forName("UTF-8"));
    //#ReverseFileReader.java:206: end of method: String com.dmdirc.addons.logging.ReverseFileReader.getNextLine()
	}

	/**
	 * Try and get x number of lines.
	 * If the file is closed, an empty stack will be returned.
	 *
	 * @param numLines Number of lines to try and get.
	 * @return The requested lines
	 */
	public Stack<String> getLines(final int numLines) {
		final Stack<String> result = new Stack<String>();
    //#ReverseFileReader.java:217: method: Stack com.dmdirc.addons.logging.ReverseFileReader.getLines(int)
    //#input(Stack getLines(int)): __Descendant_Table[com/dmdirc/addons/logging/ReverseFileReader]
    //#input(Stack getLines(int)): __Descendant_Table[others]
    //#input(Stack getLines(int)): __Dispatch_Table.getNextLine()Ljava/lang/String;
    //#input(Stack getLines(int)): numLines
    //#input(Stack getLines(int)): this
    //#input(Stack getLines(int)): this.__Tag
    //#input(Stack getLines(int)): this.file
    //#input(Stack getLines(int)): this.seekLength
    //#output(Stack getLines(int)): new Stack(getLines#1) num objects
    //#output(Stack getLines(int)): return_value
    //#new obj(Stack getLines(int)): new Stack(getLines#1)
    //#pre[3] (Stack getLines(int)): (soft) this.__Tag == com/dmdirc/addons/logging/ReverseFileReader
    //#pre[4] (Stack getLines(int)): (soft) this.file != null
    //#pre[5] (Stack getLines(int)): (soft) init'ed(this.seekLength)
    //#post(Stack getLines(int)): return_value == &new Stack(getLines#1)
    //#post(Stack getLines(int)): new Stack(getLines#1) num objects == 1
    //#unanalyzed(Stack getLines(int)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(Stack getLines(int)): Effects-of-calling:java.io.RandomAccessFile:getFilePointer
    //#unanalyzed(Stack getLines(int)): Effects-of-calling:java.io.RandomAccessFile:seek
    //#unanalyzed(Stack getLines(int)): Effects-of-calling:java.io.RandomAccessFile:read
    //#unanalyzed(Stack getLines(int)): Effects-of-calling:java.lang.Byte:valueOf
    //#unanalyzed(Stack getLines(int)): Effects-of-calling:java.util.ArrayList:add
    //#unanalyzed(Stack getLines(int)): Effects-of-calling:java.util.ArrayList:size
    //#unanalyzed(Stack getLines(int)): Effects-of-calling:java.util.ArrayList:get
    //#unanalyzed(Stack getLines(int)): Effects-of-calling:java.lang.Byte:byteValue
    //#unanalyzed(Stack getLines(int)): Effects-of-calling:java.nio.charset.Charset:forName
    //#unanalyzed(Stack getLines(int)): Effects-of-calling:java.lang.String
		for (int i = 0; i < numLines; ++i) {
			try {
				result.push(getNextLine());
			} catch (IOException e) {
				break;
			}
		}
		return result;
    //#ReverseFileReader.java:225: end of method: Stack com.dmdirc.addons.logging.ReverseFileReader.getLines(int)
	}
	
	/**
	 * Try and get x number of lines and return a \n delimited String.
	 * If the file is closed, an empty string will be returned.
	 *
	 * @param numLines Number of lines to try and get.
	 * @return The requested lines
	 */
	public String getLinesAsString(final int numLines) {
		final StringBuilder result = new StringBuilder();
    //#ReverseFileReader.java:236: method: String com.dmdirc.addons.logging.ReverseFileReader.getLinesAsString(int)
    //#input(String getLinesAsString(int)): __Descendant_Table[com/dmdirc/addons/logging/ReverseFileReader]
    //#input(String getLinesAsString(int)): __Descendant_Table[others]
    //#input(String getLinesAsString(int)): __Dispatch_Table.getNextLine()Ljava/lang/String;
    //#input(String getLinesAsString(int)): numLines
    //#input(String getLinesAsString(int)): this
    //#input(String getLinesAsString(int)): this.__Tag
    //#input(String getLinesAsString(int)): this.file
    //#input(String getLinesAsString(int)): this.seekLength
    //#output(String getLinesAsString(int)): java.lang.StringBuilder:toString(...)._tainted
    //#output(String getLinesAsString(int)): return_value
    //#new obj(String getLinesAsString(int)): java.lang.StringBuilder:toString(...)
    //#pre[3] (String getLinesAsString(int)): (soft) this.__Tag == com/dmdirc/addons/logging/ReverseFileReader
    //#pre[4] (String getLinesAsString(int)): (soft) this.file != null
    //#pre[5] (String getLinesAsString(int)): (soft) init'ed(this.seekLength)
    //#post(String getLinesAsString(int)): java.lang.StringBuilder:toString(...)._tainted == 0
    //#post(String getLinesAsString(int)): return_value == &java.lang.StringBuilder:toString(...)
    //#unanalyzed(String getLinesAsString(int)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(String getLinesAsString(int)): Effects-of-calling:java.io.RandomAccessFile:getFilePointer
    //#unanalyzed(String getLinesAsString(int)): Effects-of-calling:java.io.RandomAccessFile:seek
    //#unanalyzed(String getLinesAsString(int)): Effects-of-calling:java.io.RandomAccessFile:read
    //#unanalyzed(String getLinesAsString(int)): Effects-of-calling:java.lang.Byte:valueOf
    //#unanalyzed(String getLinesAsString(int)): Effects-of-calling:java.util.ArrayList:add
    //#unanalyzed(String getLinesAsString(int)): Effects-of-calling:java.util.ArrayList:size
    //#unanalyzed(String getLinesAsString(int)): Effects-of-calling:java.util.ArrayList:get
    //#unanalyzed(String getLinesAsString(int)): Effects-of-calling:java.lang.Byte:byteValue
    //#unanalyzed(String getLinesAsString(int)): Effects-of-calling:java.nio.charset.Charset:forName
    //#unanalyzed(String getLinesAsString(int)): Effects-of-calling:java.lang.String
    //#test_vector(String getLinesAsString(int)): java.lang.StringBuilder:charAt(...)@245: {0..9, 11..65_535}, {10}
		for (int i = 0; i < numLines; ++i) {
			try {
				result.insert(0, "\n");
				result.insert(0, getNextLine());
			} catch (IOException e) {
				break;
			}
		}
		if (result.charAt(0) == '\n') {
			result.deleteCharAt(0);
		}
		return result.toString();
    //#ReverseFileReader.java:248: end of method: String com.dmdirc.addons.logging.ReverseFileReader.getLinesAsString(int)
	}
}
    //#output(com.dmdirc.addons.logging.ReverseFileReader__static_init): __Descendant_Table[com/dmdirc/addons/logging/ReverseFileReader]
    //#output(com.dmdirc.addons.logging.ReverseFileReader__static_init): __Dispatch_Table.close()V
    //#output(com.dmdirc.addons.logging.ReverseFileReader__static_init): __Dispatch_Table.getLines(I)Ljava/util/Stack;
    //#output(com.dmdirc.addons.logging.ReverseFileReader__static_init): __Dispatch_Table.getLinesAsString(I)Ljava/lang/String;
    //#output(com.dmdirc.addons.logging.ReverseFileReader__static_init): __Dispatch_Table.getNextLine()Ljava/lang/String;
    //#output(com.dmdirc.addons.logging.ReverseFileReader__static_init): __Dispatch_Table.getSeekLength()B
    //#output(com.dmdirc.addons.logging.ReverseFileReader__static_init): __Dispatch_Table.reset()V
    //#output(com.dmdirc.addons.logging.ReverseFileReader__static_init): __Dispatch_Table.setSeekLength(B)V
    //#post(com.dmdirc.addons.logging.ReverseFileReader__static_init): __Descendant_Table[com/dmdirc/addons/logging/ReverseFileReader] == &__Dispatch_Table
    //#post(com.dmdirc.addons.logging.ReverseFileReader__static_init): __Dispatch_Table.close()V == &close
    //#post(com.dmdirc.addons.logging.ReverseFileReader__static_init): __Dispatch_Table.getLines(I)Ljava/util/Stack; == &getLines
    //#post(com.dmdirc.addons.logging.ReverseFileReader__static_init): __Dispatch_Table.getLinesAsString(I)Ljava/lang/String; == &getLinesAsString
    //#post(com.dmdirc.addons.logging.ReverseFileReader__static_init): __Dispatch_Table.getNextLine()Ljava/lang/String; == &getNextLine
    //#post(com.dmdirc.addons.logging.ReverseFileReader__static_init): __Dispatch_Table.getSeekLength()B == &getSeekLength
    //#post(com.dmdirc.addons.logging.ReverseFileReader__static_init): __Dispatch_Table.reset()V == &reset
    //#post(com.dmdirc.addons.logging.ReverseFileReader__static_init): __Dispatch_Table.setSeekLength(B)V == &setSeekLength
    //#ReverseFileReader.java:: end of method: com.dmdirc.addons.logging.ReverseFileReader.com.dmdirc.addons.logging.ReverseFileReader__static_init
    //#ReverseFileReader.java:: end of class: com.dmdirc.addons.logging.ReverseFileReader
