ResettableFileInputStream extends ResettableInputStream implements RemoteMarkable, LengthMeasurable { @Override public synchronized int readChar() throws IOException { if (hasLowSurrogate) { hasLowSurrogate = false; return lowSurrogate; } if (buf.remaining() < maxCharWidth) { buf.clear(); buf.flip(); refillBuf(); } int start = buf.position(); charBuf.clear(); charBuf.limit(1); boolean isEndOfInput = false; if (position >= fileSize) { isEndOfInput = true; } CoderResult res = decoder.decode(buf, charBuf, isEndOfInput); if (res.isMalformed() || res.isUnmappable()) { res.throwException(); } int delta = buf.position() - start; charBuf.flip(); if (charBuf.hasRemaining()) { char c = charBuf.get(); incrPosition(delta, true); return c; } if (buf.hasRemaining()) { charBuf.clear(); charBuf.limit(2); res = decoder.decode(buf, charBuf, isEndOfInput); if (res.isMalformed() || res.isUnmappable()) { res.throwException(); } charBuf.flip(); if (charBuf.remaining() == 2) { char highSurrogate = charBuf.get(); lowSurrogate = charBuf.get(); if (!Character.isHighSurrogate(highSurrogate) || !Character.isLowSurrogate(lowSurrogate)) { logger.warn("Decoded a pair of chars, but it does not seem to be a surrogate pair: {} {}", (int)highSurrogate, (int)lowSurrogate); } hasLowSurrogate = true; delta = buf.position() - start; incrPosition(delta, true); return highSurrogate; } } incrPosition(delta, false); return -1; } ResettableFileInputStream(File file, PositionTracker tracker);  ResettableFileInputStream(File file, PositionTracker tracker,
      int bufSize, Charset charset, DecodeErrorPolicy decodeErrorPolicy); @Override synchronized int read(); @Override synchronized int read(byte[] b, int off, int len); @Override synchronized int readChar(); @Override void mark(); @Override void markPosition(long position); @Override long getMarkPosition(); @Override void reset(); @Override long length(); @Override long tell(); @Override synchronized void seek(long newPos); @Override void close(); static final int DEFAULT_BUF_SIZE; static final int MIN_BUF_SIZE; }
@Test(expected = MalformedInputException.class) public void testUtf8DecodeErrorHandlingFailMalformed() throws IOException { ResettableInputStream in = initUtf8DecodeTest(DecodeErrorPolicy.FAIL); while (in.readChar() != -1) { } fail("Expected MalformedInputException!"); }
@Test public void testUtf8DecodeErrorHandlingIgnore() throws IOException { ResettableInputStream in = initUtf8DecodeTest(DecodeErrorPolicy.IGNORE); int c; StringBuilder sb = new StringBuilder(); while ((c = in.readChar()) != -1) { sb.append((char)c); } assertEquals("Latin1: ()\nLong: ()\nNonUnicode: ()\n", sb.toString()); }
@Test public void testUtf8DecodeErrorHandlingReplace() throws IOException { ResettableInputStream in = initUtf8DecodeTest(DecodeErrorPolicy.REPLACE); int c; StringBuilder sb = new StringBuilder(); while ((c = in.readChar()) != -1) { sb.append((char)c); } String preJdk8ExpectedStr = "Latin1: (X)\nLong: (XXX)\nNonUnicode: (X)\n"; String expectedStr = "Latin1: (X)\nLong: (XXX)\nNonUnicode: (XXXXX)\n"; String javaVersionStr = System.getProperty("java.version"); double javaVersion = Double.parseDouble(javaVersionStr.substring(0, 3)); if (javaVersion < 1.8) { assertTrue(preJdk8ExpectedStr.replaceAll("X", "\ufffd").equals(sb.toString())); } else { assertTrue(expectedStr.replaceAll("X", "\ufffd").equals(sb.toString())); } }
@Test(expected = MalformedInputException.class) public void testLatin1DecodeErrorHandlingFailMalformed() throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); generateLatin1InvalidSequence(out); Files.write(out.toByteArray(), file); ResettableInputStream in = initInputStream(DecodeErrorPolicy.FAIL); while (in.readChar() != -1) { } fail("Expected MalformedInputException!"); }
@Test public void testLatin1DecodeErrorHandlingReplace() throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); generateLatin1InvalidSequence(out); Files.write(out.toByteArray(), file); ResettableInputStream in = initInputStream(DecodeErrorPolicy.REPLACE); int c; StringBuilder sb = new StringBuilder(); while ((c = in.readChar()) != -1) { sb.append((char)c); } assertEquals("Invalid: (X)\n".replaceAll("X", "\ufffd"), sb.toString()); }