// revised from runcc 0.7
import java.io.*;
/**
* Reads away UNICODE Byte Order Mark on construction. See
* http://www.unicode.org/unicode/faq/utf_bom.html
*
*
* 00 00 FE FF = UTF-32, big-endian
* FF FE 00 00 = UTF-32, little-endian
* FE FF = UTF-16, big-endian
* FF FE = UTF-16, little-endian
* EF BB BF = UTF-8
*
*/
public class UnicodeReader extends Reader
{
private static final int BOM_MAX_SIZE = 4;
private InputStreamReader delegate;
public UnicodeReader(InputStream in) throws IOException {
init(in, null);
}
public UnicodeReader(InputStream in, String defaultEnc) throws IOException {
init(in, defaultEnc);
}
/** Returns the encoding that was read from byte order mark if there was one. */
public String getEncoding() {
return delegate.getEncoding();
}
/**
* Read-ahead four bytes and check for BOM marks. Extra bytes are unread back
* to the stream, only BOM bytes are skipped.
*/
private void init(InputStream in, String defaultEnc) throws IOException {
String encoding;
byte bom[] = new byte[BOM_MAX_SIZE];
int n, unread;
PushbackInputStream internalIn = new PushbackInputStream(in, BOM_MAX_SIZE);
n = internalIn.read(bom, 0, bom.length);
if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF)) {
encoding = "UTF-8";
unread = n - 3;
}
else
if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) {
encoding = "UTF-16BE";
unread = n - 2;
}
else
if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) {
encoding = "UTF-16LE";
unread = n - 2;
}
else
if ((bom[0] == (byte) 0x00) && (bom[1] == (byte) 0x00) && (bom[2] == (byte) 0xFE) && (bom[3] == (byte) 0xFF)) {
encoding = "UTF-32BE";
unread = n - 4;
}
else
if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE) && (bom[2] == (byte) 0x00) && (bom[3] == (byte) 0x00)) {
encoding = "UTF-32LE";
unread = n - 4;
}
else {
// Unicode BOM mark not found, unread all bytes
encoding = defaultEnc;
unread = n;
}
if (unread > 0)
internalIn.unread(bom, (n - unread), unread);
else
if (unread < -1)
internalIn.unread(bom, 0, 0);
// Use BOM or default encoding
if (encoding == null) {
delegate = new InputStreamReader(internalIn);
}
else {
delegate = new InputStreamReader(internalIn, encoding);
}
}
/** Overridden to use delegate reader. */
public void close() throws IOException {
delegate.close();
}
/** Overridden to use delegate reader. */
public int read(char[] cbuf, int off, int len) throws IOException {
return delegate.read(cbuf, off, len);
}
}