    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    }