001/* 002 * gnu/regexp/CharIndexedReader.java 003 * Copyright (C) 1998-2001 Wes Biggs 004 * 005 * This library is free software; you can redistribute it and/or modify 006 * it under the terms of the GNU Lesser General Public License as published 007 * by the Free Software Foundation; either version 2.1 of the License, or 008 * (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public License 016 * along with this program; if not, write to the Free Software 017 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 018 */ 019 020package gnu.regexp; 021import java.io.InputStream; 022import java.io.BufferedInputStream; 023import java.io.IOException; 024 025// TODO: move(x) shouldn't rely on calling next() x times 026 027class CharIndexedInputStream implements CharIndexed { 028 private static final int BUFFER_INCREMENT = 1024; 029 private static final int UNKNOWN = Integer.MAX_VALUE; // value for end 030 031 private BufferedInputStream br; 032 033 // so that we don't try to reset() right away 034 private int index = -1; 035 036 private int bufsize = BUFFER_INCREMENT; 037 038 private int end = UNKNOWN; 039 040 private char cached = OUT_OF_BOUNDS; 041 042 // Big enough for a \r\n pair 043 // lookBehind[0] = most recent 044 // lookBehind[1] = second most recent 045 private char[] lookBehind = new char[] { OUT_OF_BOUNDS, OUT_OF_BOUNDS }; 046 047 CharIndexedInputStream(InputStream str, int index) { 048 if (str instanceof BufferedInputStream) br = (BufferedInputStream) str; 049 else br = new BufferedInputStream(str,BUFFER_INCREMENT); 050 next(); 051 if (index > 0) move(index); 052 } 053 054 private boolean next() { 055 if (end == 1) return false; 056 end--; // closer to end 057 058 try { 059 if (index != -1) { 060 br.reset(); 061 } 062 int i = br.read(); 063 br.mark(bufsize); 064 if (i == -1) { 065 end = 1; 066 cached = OUT_OF_BOUNDS; 067 return false; 068 } 069 cached = (char) i; 070 index = 1; 071 } catch (IOException e) { 072 e.printStackTrace(); 073 cached = OUT_OF_BOUNDS; 074 return false; 075 } 076 return true; 077 } 078 079 public char charAt(int index) { 080 if (index == 0) { 081 return cached; 082 } else if (index >= end) { 083 return OUT_OF_BOUNDS; 084 } else if (index == -1) { 085 return lookBehind[0]; 086 } else if (index == -2) { 087 return lookBehind[1]; 088 } else if (index < -2) { 089 return OUT_OF_BOUNDS; 090 } else if (index >= bufsize) { 091 // Allocate more space in the buffer. 092 try { 093 while (bufsize <= index) bufsize += BUFFER_INCREMENT; 094 br.reset(); 095 br.mark(bufsize); 096 br.skip(index-1); 097 } catch (IOException e) { } 098 } else if (this.index != index) { 099 try { 100 br.reset(); 101 br.skip(index-1); 102 } catch (IOException e) { } 103 } 104 char ch = OUT_OF_BOUNDS; 105 106 try { 107 int i = br.read(); 108 this.index = index+1; // this.index is index of next pos relative to charAt(0) 109 if (i == -1) { 110 // set flag that next should fail next time? 111 end = index; 112 return ch; 113 } 114 ch = (char) i; 115 } catch (IOException ie) { } 116 117 return ch; 118 } 119 120 public boolean move(int index) { 121 // move read position [index] clicks from 'charAt(0)' 122 boolean retval = true; 123 while (retval && (index-- > 0)) retval = next(); 124 return retval; 125 } 126 127 public boolean isValid() { 128 return (cached != OUT_OF_BOUNDS); 129 } 130} 131