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: 1.3 $
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
93 c = reader.read();
94 if (c != 'u') {
95 hasNextChar = true;
96 nextChar = c;
97 write('//');
98 return '//';
99 }
100
101
102 do {
103 c = reader.read();
104 } while (c == 'u');
105
106
107 checkHexDigit(c);
108 StringBuffer charNum = new StringBuffer();
109 charNum.append((char) c);
110
111
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
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 }