UnicodeReader.java 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /*
  2. * Original pseudocode : Thomas Weidenfeller
  3. * Implementation tweaked: Aki Nieminen
  4. *
  5. * http://www.unicode.org/unicode/faq/utf_bom.html
  6. * BOMs:
  7. * 00 00 FE FF = UTF-32, big-endian
  8. * FF FE 00 00 = UTF-32, little-endian
  9. * FE FF = UTF-16, big-endian
  10. * FF FE = UTF-16, little-endian
  11. * EF BB BF = UTF-8
  12. *
  13. * Win2k Notepad:
  14. * Unicode format = UTF-16LE
  15. */
  16. package jplag;
  17. import java.io.IOException;
  18. import java.io.InputStream;
  19. import java.io.InputStreamReader;
  20. import java.io.PushbackInputStream;
  21. import java.io.Reader;
  22. /**
  23. * Generic unicode text reader, which will use BOM mark to identify the encoding to be used. If BOM is not found then
  24. * use a given default encoding. System default is used if: BOM mark is not found and defaultEnc is NULL.<br />
  25. * Usage pattern:
  26. *
  27. * <pre>
  28. * String defaultEnc = "UTF-8"; // or NULL to use system default
  29. * FileInputStream fis = new FileInputStream(file);
  30. * Reader in = new UnicodeReader(fis, defaultEnc);
  31. * </pre>
  32. */
  33. public class UnicodeReader extends Reader {
  34. PushbackInputStream internalIn;
  35. InputStreamReader internalIn2 = null;
  36. String defaultEnc;
  37. private static final int BOM_SIZE = 4;
  38. public UnicodeReader(InputStream in, String defaultEnc) {
  39. internalIn = new PushbackInputStream(in, BOM_SIZE);
  40. this.defaultEnc = defaultEnc;
  41. }
  42. public String getDefaultEncoding() {
  43. return defaultEnc;
  44. }
  45. public String getEncoding() {
  46. if (internalIn2 == null)
  47. return null;
  48. return internalIn2.getEncoding();
  49. }
  50. /**
  51. * Read-ahead four bytes and check for BOM marks. Extra bytes are unread back to the stream, only BOM bytes are skipped.
  52. */
  53. protected void init() throws IOException {
  54. if (internalIn2 != null)
  55. return;
  56. String encoding;
  57. byte bom[] = new byte[BOM_SIZE];
  58. int n, unread;
  59. n = internalIn.read(bom, 0, bom.length);
  60. if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF)) {
  61. encoding = "UTF-8";
  62. unread = n - 3;
  63. } else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) {
  64. encoding = "UTF-16BE";
  65. unread = n - 2;
  66. } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) {
  67. encoding = "UTF-16LE";
  68. unread = n - 2;
  69. } else if ((bom[0] == (byte) 0x00) && (bom[1] == (byte) 0x00) && (bom[2] == (byte) 0xFE) && (bom[3] == (byte) 0xFF)) {
  70. encoding = "UTF-32BE";
  71. unread = n - 4;
  72. } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE) && (bom[2] == (byte) 0x00) && (bom[3] == (byte) 0x00)) {
  73. encoding = "UTF-32LE";
  74. unread = n - 4;
  75. } else {
  76. // Unicode BOM mark not found, unread all bytes
  77. encoding = defaultEnc;
  78. unread = n;
  79. }
  80. if (unread > 0)
  81. internalIn.unread(bom, (n - unread), unread);
  82. // Use given encoding
  83. if (encoding == null) {
  84. internalIn2 = new InputStreamReader(internalIn);
  85. } else {
  86. internalIn2 = new InputStreamReader(internalIn, encoding);
  87. }
  88. }
  89. @Override
  90. public void close() throws IOException {
  91. init();
  92. internalIn2.close();
  93. }
  94. @Override
  95. public int read(char[] cbuf, int off, int len) throws IOException {
  96. init();
  97. return internalIn2.read(cbuf, off, len);
  98. }
  99. }