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    }