001: /**
002: * Copyright 2005 Alan Green
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: *
016: */package org.codehaus.groovy.antlr;
017:
018: import java.io.IOException;
019: import java.io.Reader;
020:
021: import antlr.CharScanner;
022:
023: /**
024: * Translates GLS-defined unicode escapes into characters. Throws an exception
025: * in the event of an invalid unicode escape being detected.
026: *
027: * <p>No attempt has been made to optimise this class for speed or
028: * space.</p>
029: *
030: * @version $Revision: 2222 $
031: */
032: public class UnicodeEscapingReader extends Reader {
033:
034: private Reader reader;
035: private CharScanner lexer;
036: private boolean hasNextChar = false;
037: private int nextChar;
038: private SourceBuffer sourceBuffer;
039:
040: /**
041: * Constructor.
042: * @param reader The reader that this reader will filter over.
043: */
044: public UnicodeEscapingReader(Reader reader,
045: SourceBuffer sourceBuffer) {
046: this .reader = reader;
047: this .sourceBuffer = sourceBuffer;
048: }
049:
050: /**
051: * Sets the lexer that is using this reader. Must be called before the
052: * lexer is used.
053: */
054: public void setLexer(CharScanner lexer) {
055: this .lexer = lexer;
056: }
057:
058: /**
059: * Reads characters from the underlying reader.
060: * @see java.io.Reader#read(char[],int,int)
061: */
062: public int read(char cbuf[], int off, int len) throws IOException {
063: int c = 0;
064: int count = 0;
065: while (count < len && (c = read()) != -1) {
066: cbuf[off + count] = (char) c;
067: count++;
068: }
069: return (count == 0 && c == -1) ? -1 : count;
070: }
071:
072: /**
073: * Gets the next character from the underlying reader,
074: * translating escapes as required.
075: * @see java.io.Reader#close()
076: */
077: public int read() throws IOException {
078: if (hasNextChar) {
079: hasNextChar = false;
080: write(nextChar);
081: return nextChar;
082: }
083:
084: int c = reader.read();
085: if (c != '\\') {
086: write(c);
087: return c;
088: }
089:
090: // Have one backslash, continue if next char is 'u'
091: c = reader.read();
092: if (c != 'u') {
093: hasNextChar = true;
094: nextChar = c;
095: write('\\');
096: return '\\';
097: }
098:
099: // Swallow multiple 'u's
100: do {
101: c = reader.read();
102: } while (c == 'u');
103:
104: // Get first hex digit
105: checkHexDigit(c);
106: StringBuffer charNum = new StringBuffer();
107: charNum.append((char) c);
108:
109: // Must now be three more hex digits
110: for (int i = 0; i < 3; i++) {
111: c = reader.read();
112: checkHexDigit(c);
113: charNum.append((char) c);
114: }
115: int rv = Integer.parseInt(charNum.toString(), 16);
116: write(rv);
117: return rv;
118: }
119:
120: private void write(int c) {
121: if (sourceBuffer != null) {
122: sourceBuffer.write(c);
123: }
124: }
125:
126: /**
127: * Checks that the given character is indeed a hex digit.
128: */
129: private void checkHexDigit(int c) throws IOException {
130: if (c >= '0' && c <= '9') {
131: return;
132: }
133: if (c >= 'a' && c <= 'f') {
134: return;
135: }
136: if (c >= 'A' && c <= 'F') {
137: return;
138: }
139: // Causes the invalid escape to be skipped
140: hasNextChar = true;
141: nextChar = c;
142: throw new IOException(
143: "Did not find four digit hex character code."
144: + " line: " + lexer.getLine() + " col:"
145: + lexer.getColumn());
146: }
147:
148: /**
149: * Closes this reader by calling close on the underlying reader.
150: * @see java.io.Reader#close()
151: */
152: public void close() throws IOException {
153: reader.close();
154: }
155: }
|