View Javadoc

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