001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021package org.biojava.utils.io; 022 023import java.io.BufferedReader; 024import java.io.IOException; 025import java.io.Reader; 026 027/** 028 * @author Thomas Down 029 */ 030 public class CountedBufferedReader extends BufferedReader { 031 private final static int DEFAULT_BUFFER_SIZE = 1 << 14; 032 033 private long position; 034 035 private Reader stream; 036 private char[] buffer; 037 private int buffPos; 038 private int buffFill; 039 040 private boolean reachedEOF = false; 041 042 private int mark = -1; 043 private int markLimit = -1; 044 045 public long getFilePointer() { 046 return position; 047 } 048 049 public CountedBufferedReader(Reader stream) { 050 super(new Reader() { 051 public void close() {} 052 public int read(char[] cbuf, int off, int len) { return 0; } 053 }); 054 055 this.stream = stream; 056 this.buffer = new char[DEFAULT_BUFFER_SIZE]; 057 position = 0; 058 buffPos = 0; 059 buffFill = 0; 060 } 061 062 public void close() 063 throws IOException 064 { 065 stream.close(); 066 stream = null; 067 } 068 069 public int read() 070 throws IOException 071 { 072 if (buffPos >= buffFill) 073 fillBuffer(); 074 075 if (reachedEOF) { 076 return -1; 077 } else { 078 position++; 079 return buffer[buffPos++]; 080 } 081 } 082 083 private int peek() 084 throws IOException 085 { 086 if (buffPos >= buffFill) 087 fillBuffer(); 088 089 if (reachedEOF) { 090 return -1; 091 } else { 092 return buffer[buffPos]; 093 } 094 } 095 096 public int read(char[] cbuf) 097 throws IOException 098 { 099 return read(cbuf, 0, cbuf.length); 100 } 101 102 public int read(char[] cbuf, int off, int len) 103 throws IOException 104 { 105 if (buffPos >= buffFill) 106 fillBuffer(); 107 108 if (reachedEOF) { 109 return -1; 110 } else { 111 int toReturn = Math.min(len, buffFill - buffPos); 112 System.arraycopy(buffer, buffPos, cbuf, off, toReturn); 113 buffPos += toReturn; 114 position += toReturn; 115 116 return toReturn; 117 } 118 } 119 120 public boolean ready() 121 throws IOException 122 { 123 if (buffPos < buffFill) 124 return true; 125 return stream.ready(); 126 } 127 128 public long skip(long n) 129 throws IOException 130 { 131 int skipInBuffer; 132 if (n < buffer.length) { 133 skipInBuffer = Math.min((int) n, buffFill - buffPos); 134 } else { 135 skipInBuffer = buffFill - buffPos; 136 } 137 position += skipInBuffer; 138 buffPos += skipInBuffer; 139 140 if (n > skipInBuffer) { 141 long skippedInStream; 142 143 if (mark >= 0) { 144 // Yuck, fix this... 145 char[] dummy = new char[(int) (n - skipInBuffer)]; 146 skippedInStream = read(dummy); 147 } else { 148 skippedInStream = stream.skip(n - skipInBuffer); 149 } 150 151 position += skippedInStream; 152 return skippedInStream + skipInBuffer; 153 } else { 154 return skipInBuffer; 155 } 156 } 157 158 public boolean markSupported() { 159 return true; 160 } 161 162 public void mark(int limit) 163 throws IOException 164 { 165 // System.err.println("*** Mark"); 166 167 if (limit + 1> buffer.length) { 168 char[] newBuffer = new char[limit + 1]; 169 System.arraycopy(buffer, buffPos, newBuffer, 0, buffFill - buffPos); 170 buffer = newBuffer; 171 buffFill = buffFill - buffPos; 172 buffPos = 0; 173 } else if (buffPos + limit > buffer.length) { 174 System.arraycopy(buffer, buffPos, buffer, 0, buffFill - buffPos); 175 buffFill = buffFill - buffPos; 176 buffPos = 0; 177 } 178 179 mark = buffPos; 180 markLimit = limit; 181 } 182 183 public void reset() 184 throws IOException 185 { 186 // System.err.println("*** Reset"); 187 188 if (mark < 0) 189 throw new IOException("The mark is not currently in scope"); 190 191 position = position - buffPos + mark; 192 buffPos = mark; 193 } 194 195 public String readLine() 196 throws IOException 197 { 198 String line = null; 199 200 while(!reachedEOF) { 201 for(int i = buffPos; i < buffFill; i++) { 202 char c = buffer[i]; 203 if(c == '\n' || c == '\r') { 204 int len = i - buffPos; 205 String bit = new String(buffer, buffPos, len); 206 position += len; 207 if(line == null) { 208 line = bit; 209 } else { 210 line += bit; 211 } 212 buffPos = i; 213 read(); 214 char d = (char) peek(); 215 if(c == '\r' && d == '\n') { 216 read(); 217 } 218 219 return line; 220 } 221 } 222 int len = buffFill - buffPos; 223 String bit = new String(buffer, buffPos, len); 224 position += len; 225 buffPos = buffFill; 226 if(line == null) { 227 line = bit; 228 } else { 229 line += bit; 230 } 231 fillBuffer(); 232 } 233 234 return line; 235 } 236 237 private void fillBuffer() 238 throws IOException 239 { 240 // System.err.println("*** Fill buffer"); 241 242 if (mark < 0) { 243 buffFill = stream.read(buffer); 244 if (buffFill == -1) { 245 buffFill = 0; 246 reachedEOF = true; 247 } 248 // System.out.println("Filled buffer: " + buffFill); 249 250 buffPos = 0; 251 } else { 252 if (buffPos >= (markLimit + mark)) { 253 // Mark's gone out of scope -- wheee! 254 mark = -1; 255 markLimit = -1; 256 fillBuffer(); 257 return; 258 } 259 260 System.arraycopy(buffer, mark, buffer, 0, buffFill - mark); 261 buffFill = buffFill - mark; 262 mark = 0; 263 buffPos = buffFill; 264 int newChars = stream.read(buffer, buffFill, buffer.length - buffFill); 265 if (newChars == -1) { 266 reachedEOF = true; 267 } else { 268 buffFill = buffFill + newChars; 269 } 270 } 271 } 272 } 273