001 /* Copyright 2000, 2001, Compaq Computer Corporation */ 002 003 package javafe.util; 004 005 import javafe.genericfile.GenericFile; 006 import java.io.IOException; 007 008 /** 009 * A reader (aka input stream) that provides an associated 010 * <i>location</i> with each character read. 011 * 012 * <p>See javafe.util.Location for the interpretation of these 013 * locations. 014 * 015 * <p> We also provide a method to create a new 016 * <code>CorrelatedReader</code> for the text between the marked 017 * position and the current point in the stream. Marking is also 018 * allowed on the new <code>CorrelatedReader</code> object. 019 * 020 * @see javafe.util.Location 021 * @author Cormac Flanagan 022 */ 023 024 public class SubCorrelatedReader extends BufferedCorrelatedReader 025 { 026 private /*@ non_null */ GenericFile file; 027 028 /** Returns the file underlying this correlated reader. 029 */ 030 031 public GenericFile getFile() { 032 return file; 033 } 034 035 /** 036 * Creates a sub-reader. <p> 037 * 038 * This method captures the given <code>buf</code>, that is, 039 * callers should no longer use <code>buf</code> after passing it 040 * in to this constructor. 041 */ 042 //@ requires STARTFREELOC-1 <= beforeBufLoc; 043 public SubCorrelatedReader(/*@ non_null @*/ GenericFile file, 044 /*@ non_null @*/ byte[] buf, 045 int beforeBufLoc) { 046 047 // Our locations are exactly [beforeBufLoc+1, beforeBufLoc+1+len): 048 super(/*minLoc*/ beforeBufLoc+1, beforeBufLoc, 049 /*maxLoc*/ beforeBufLoc+1+buf.length); 050 this.file = file; 051 this.buf = buf; 052 this.endBufNdx = buf.length; 053 } 054 055 /* ************************************************ 056 * * 057 * The methods: * 058 * * 059 **************************************************/ 060 061 /** See spec in the abstract <code>CorrelatedReader</code> class. 062 */ 063 064 public int read() throws IOException { 065 if (buf == null) { 066 Assert.precondition("read() called on a closed CorrelatedReader"); 067 } 068 069 if (curNdx == endBufNdx) { 070 // refill buffer 071 if (!refillBuf()) { 072 // EOF 073 // save position of last character 074 lastCharNdx = curNdx; 075 return -1; 076 } 077 } 078 079 // save the position of this character, before it is read: 080 lastCharNdx = curNdx; 081 082 int c = buf[curNdx++]; 083 084 if (c=='\\' && oddSlashLoc+1 != getLocation()) { 085 // Can be a unicode escape sequence (is an odd slash!) 086 if (peek() == 'u') { 087 // is a unicode escape sequence 088 while (peek() == 'u') { 089 curNdx++; 090 } 091 char s[] = new char[4]; 092 for (int i=0; i<4; i++) { 093 s[i] = (char)readRaw(); 094 if (Character.digit(s[i],16)==-1) { 095 throw new IOException("Bad unicode character sequence"); 096 } 097 } 098 c = Integer.parseInt( new String(s), 16 ); 099 } else { 100 // not a unicode 101 oddSlashLoc = getLocation(); 102 } 103 } 104 105 return c; 106 } 107 108 protected boolean refillBuf() throws IOException { 109 // the buffer of a SubCorrelatedReader cannot be refilled 110 return false; 111 } 112 }