
org.jamon.codegen.EncodingReader Maven / Gradle / Ivy
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.jamon.codegen;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PushbackInputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
public class EncodingReader extends Reader {
public static class Exception extends IOException {
private static final long serialVersionUID = 2006091701L;
public Exception(String message, int pos) {
super(message);
this.pos = pos;
}
public int getPos() {
return pos;
}
private final int pos;
}
public EncodingReader(InputStream stream) throws IOException {
PushbackInputStream pushbackStream = new PushbackInputStream(stream, 50);
if (matches(ONEBYTESIG, pushbackStream)) {
encoding = computeOneByteEncoding(pushbackStream);
}
else if (matches(UTF16LESIG, pushbackStream) || matches(UTF16BESIG, pushbackStream)) {
encoding = computeUtf16Encoding(pushbackStream);
}
else {
encoding = Charset.defaultCharset().name();
}
reader = new InputStreamReader(pushbackStream, encoding);
}
public String getEncoding() {
return encoding;
}
private boolean matches(byte[] match, PushbackInputStream stream) throws IOException {
byte[] data = new byte[match.length];
int len = stream.read(data);
if (len == -1) {
return false;
}
if (len == match.length) {
for (int i = 0; i < len; ++i) {
if (match[i] != data[i]) {
stream.unread(data, 0, len);
return false;
}
}
bytesRead = len;
return true;
}
stream.unread(data, 0, len);
return false;
}
private String computeUtf16Encoding(PushbackInputStream stream) throws IOException {
return computeEncoding(stream, true);
}
private String computeOneByteEncoding(PushbackInputStream stream) throws IOException {
return computeEncoding(stream, false);
}
private String computeEncoding(PushbackInputStream stream, boolean twoBytes)
throws IOException {
StringBuilder encoding = new StringBuilder();
boolean lowByte = true;
int state = 0;
while (true) {
int c = stream.read();
bytesRead++;
if (twoBytes) {
if (lowByte) {
if (c != 0) {
throw new Exception("Malformed encoding name", bytesRead / (twoBytes
? 2
: 1));
}
lowByte = false;
continue;
}
else {
lowByte = true;
}
}
if (c == -1) {
throw new Exception("EOF before encoding tag finished", bytesRead / (twoBytes
? 2
: 1));
}
else if (c == SPACE || c == TAB) {
if (state == INNAME) {
state = WAITFORCLOSE;
}
}
else if (c == CLOSE) {
state = CLOSED;
}
else if (state == CLOSED) {
if (c != '\r' && c != '\n') {
stream.unread(c);
if (twoBytes) {
stream.unread(0);
}
break;
}
}
else if (state != WAITFORCLOSE) {
state = INNAME;
encoding.append((char) c);
}
else {
throw new Exception("Malformed encoding tag; expected '>'", bytesRead / (twoBytes
? 2
: 1));
}
}
return encoding.toString();
}
@Override
public void close() throws IOException {
reader.close();
}
@Override
public int read(char[] buf, int offset, int len) throws IOException {
return reader.read(buf, offset, len);
}
private final Reader reader;
private String encoding;
private int bytesRead;
private static final byte[] ONEBYTESIG;
private static final byte[] UTF16LESIG;
private static final byte[] UTF16BESIG;
static {
try {
ONEBYTESIG = "<%encoding ".getBytes("latin1");
UTF16BESIG = "<%encoding ".getBytes("UTF-16BE");
UTF16LESIG = "<%encoding ".getBytes("UTF-16LE");
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
private final static int SPACE = ' ';
private final static int TAB = '\t';
private final static int CLOSE = '>';
private final static int INNAME = 1;
private final static int WAITFORCLOSE = 2;
private final static int CLOSED = 3;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy