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 }