View Javadoc

    1   /***
    2    * Copyright 2005 Alan Green
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    * http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   */
    17
    18
    19  package org.codehaus.groovy.antlr;
    20
    21  import java.io.IOException;
    22  import java.io.Reader;
    23
    24  import antlr.CharScanner;
    25
    26  /***
    27   * Translates GLS-defined unicode escapes into characters. Throws an exception
    28   * in the event of an invalid unicode escape being detected.
    29   *
    30   * <p>No attempt has been made to optimise this class for speed or
    31   * space.</p>
    32   *
    33   * @version $Revision: 2222 $
    34   */
    35  public class UnicodeEscapingReader extends Reader {
    36
    37      private Reader reader;
    38      private CharScanner lexer;
    39      private boolean hasNextChar = false;
    40      private int nextChar;
    41      private SourceBuffer sourceBuffer;
    42
    43      /***
    44       * Constructor.
    45       * @param reader The reader that this reader will filter over.
    46       */
    47      public UnicodeEscapingReader(Reader reader,SourceBuffer sourceBuffer) {
    48          this.reader = reader;
    49          this.sourceBuffer = sourceBuffer;
    50      }
    51
    52      /***
    53       * Sets the lexer that is using this reader. Must be called before the
    54       * lexer is used.
    55       */
    56      public void setLexer(CharScanner lexer) {
    57          this.lexer = lexer;
    58      }
    59
    60      /***
    61       * Reads characters from the underlying reader.
    62       * @see java.io.Reader#read(char[],int,int)
    63       */
    64      public int read(char cbuf[], int off, int len) throws IOException {
    65          int c = 0;
    66          int count = 0;
    67          while (count < len && (c = read())!= -1) {
    68              cbuf[off + count] = (char) c;
    69              count++;
    70          }
    71          return (count == 0 && c == -1) ? -1 : count;
    72      }
    73
    74      /***
    75       * Gets the next character from the underlying reader,
    76       * translating escapes as required.
    77       * @see java.io.Reader#close()
    78       */
    79      public int read() throws IOException {
    80          if (hasNextChar) {
    81              hasNextChar = false;
    82              write(nextChar);
    83              return nextChar;
    84          }
    85
    86          int c = reader.read();
    87          if (c != '//') {
    88              write(c);
    89              return c;
    90          }
    91
    92          // Have one backslash, continue if next char is 'u'
    93          c = reader.read();
    94          if (c != 'u') {
    95              hasNextChar = true;
    96              nextChar = c;
    97              write('//');
    98              return '//';
    99          }
    100
    101         // Swallow multiple 'u's
    102         do {
    103             c = reader.read();
    104         } while (c == 'u');
    105
    106         // Get first hex digit
    107         checkHexDigit(c);
    108         StringBuffer charNum = new StringBuffer();
    109         charNum.append((char) c);
    110
    111         // Must now be three more hex digits
    112         for (int i = 0; i < 3; i++) {
    113             c = reader.read();
    114             checkHexDigit(c);
    115             charNum.append((char) c);
    116         }
    117         int rv = Integer.parseInt(charNum.toString(), 16);
    118         write(rv);
    119         return rv;
    120     }
    121     private void write(int c) {
    122         if (sourceBuffer != null) {sourceBuffer.write(c);}
    123     }
    124     /***
    125      * Checks that the given character is indeed a hex digit.
    126      */
    127     private void checkHexDigit(int c) throws IOException {
    128         if (c >= '0' && c <= '9') {
    129             return;
    130         }
    131         if (c >= 'a' && c <= 'f') {
    132             return;
    133         }
    134         if (c >= 'A' && c <= 'F') {
    135             return;
    136         }
    137         // Causes the invalid escape to be skipped
    138         hasNextChar = true;
    139         nextChar = c;
    140         throw new IOException("Did not find four digit hex character code."
    141                 + " line: " + lexer.getLine() + " col:" + lexer.getColumn());
    142     }
    143
    144     /***
    145      * Closes this reader by calling close on the underlying reader.
    146      * @see java.io.Reader#close()
    147      */
    148     public void close() throws IOException {
    149         reader.close();
    150     }
    151 }