Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4744247

(cs) StreamDecoder.CharsetSD.read does not invoke CharsetDecoder.flush

XMLWordPrintable

    • Cause Known
    • x86
    • linux_2.6, windows_2000

      Name: gm110360 Date: 09/09/2002


      FULL PRODUCT VERSION :
      java version "1.4.1-rc"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-rc-b19)
      Java HotSpot(TM) Client VM (build 1.4.1-rc-b19, mixed mode)


      FULL OPERATING SYSTEM VERSION :

      Microsoft Windows 2000 [Version 5.00.2195] (sp2)



      A DESCRIPTION OF THE PROBLEM :
      bug: InputStreamReader doesn't call CharsetDecoder.flush
      when it reaches the end of stream.

      This is a problem for decoders which keep internal state and
      need to
      know when the end of stream is reached to flush the final
      characters to the char buffer.

      See CharsetDecoder
      http://java.sun.com/j2se/1.4/docs/api/java/nio/charset/CharsetDecoder.html

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        To verify this problem, run the code below. It uses a very
      simple Charset that is instrumented to show calls to
      implReset and implFlush.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      Actual: In j2se1.4.1rc1, I get the following output.
      Decoder receives call to implReset at end of input stream.

      Expected: Decoder should receive a call to implFlush at end
      of input stream.

          <pre>

      Testing Encoder...
      before start: EncoderState: reset=true, flushed=true
      between write and flush: EncoderState: reset=false,
      flushed=false
      after flush: EncoderState: reset=false, flushed=false
      flushed encoder
      after close: EncoderState: reset=false, flushed=true

      Testing Decoder...
      before start: DecoderState: reset=true, flushed=true
      after read: DecoderState: reset=false, flushed=false
      after read: DecoderState: reset=false, flushed=false
      after read: DecoderState: reset=false, flushed=false
      reset decoder <-----???
      after done: DecoderState: reset=true, flushed=false
           </pre>


      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      This stack trace shows that reset is being called from read.

      java.lang.Exception: Stack trace
      at java.lang.Thread.dumpStack(Thread.java:1071)
      at
      TestReaderFlushesCharset$TestDecoder.implReset(TestReaderFlushesCharset.java:123)
      at java.nio.charset.CharsetDecoder.reset(CharsetDecoder.java:656)
      at sun.nio.cs.StreamDecoder$CharsetSD.implRead(StreamDecoder.java:464)
      at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:180)
      at java.io.InputStreamReader.read(InputStreamReader.java:167)
      at TestReaderFlushesCharset.testDecoder(TestReaderFlushesCharset.java:63)
      at TestReaderFlushesCharset.main(TestReaderFlushesCharset.java:37)


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.io.*;
      import java.nio.*;
      import java.nio.charset.*;

      /** bug: InputStreamReader doesn't call CharsetDecoder.flush.

          <p>This is a problem for decoders which keep internal state and need to
          know when the end of stream is reached.

          <p>To verify this problem, run the code below.
          In j2se1.4.1rc1, I get the following output. Notice decoder
          receives call to implReset where it should receive a call to implFlush.

          <pre>

      Testing Encoder...
      before start: EncoderState: reset=true, flushed=true
      between write and flush: EncoderState: reset=false, flushed=false
      after flush: EncoderState: reset=false, flushed=false
      flushed encoder
      after close: EncoderState: reset=false, flushed=true

      Testing Decoder...
      before start: DecoderState: reset=true, flushed=true
      after read: DecoderState: reset=false, flushed=false
      after read: DecoderState: reset=false, flushed=false
      after read: DecoderState: reset=false, flushed=false
      reset decoder <-----???
      after done: DecoderState: reset=true, flushed=false
           </pre>
      **/

      public class TestReaderFlushesCharset extends Charset{
        static TestReaderFlushesCharset testCharset = new TestReaderFlushesCharset();
        public static void main(String[] ignore) {
          testEncoder();
          testDecoder();
        }
        private static void testEncoder() {
          System.out.println("\nTesting Encoder...");
          ByteArrayOutputStream outStream = new ByteArrayOutputStream();
          TestEncoder testEncoder = (TestEncoder) testCharset.newEncoder();
          OutputStreamWriter writer = new OutputStreamWriter(outStream, testEncoder);
          try {
            System.out.println("before start: "+testEncoder.state());
            writer.write("hello world");
            System.out.println("between write and flush: "+testEncoder.state());
            writer.flush();
            System.out.println("after flush: "+testEncoder.state());
            writer.close();
            System.out.println("after close: "+testEncoder.state());
          } catch (IOException e) { e.printStackTrace(); }
        }
        private static void testDecoder() {
          System.out.println("\nTesting Decoder...");
          ByteArrayInputStream inStream = new ByteArrayInputStream
            (new byte[]{'h','i',' ','w','o','r','l','d'});
          TestDecoder testDecoder = (TestDecoder) testCharset.newDecoder();
          InputStreamReader reader = new InputStreamReader(inStream, testDecoder);
          try {
            System.out.println("before start: "+testDecoder.state());
            char[] buf = new char[3];
            while( reader.read(buf, 0, buf.length) > 0)
      System.out.println("after read: "+testDecoder.state());
            System.out.println("after done: "+testDecoder.state());
          } catch (IOException e) { e.printStackTrace(); }
        }

        TestReaderFlushesCharset() { super("X-TestCharSet", new String[]{}); }
        public boolean contains(Charset cs) {
          return cs instanceof TestReaderFlushesCharset;
        }
        public CharsetEncoder newEncoder() {
          return new TestEncoder();
        }
        public CharsetDecoder newDecoder() {
          return new TestDecoder();
        }
        class TestEncoder extends CharsetEncoder {
          // some dummy internal state;
          boolean reset = true;
          boolean flushed = true;

          TestEncoder() {
            super(TestReaderFlushesCharset.this, 1.0f, 2.0f);
          }
          public String state() {
            return "EncoderState: reset="+reset+", flushed="+flushed; }

          protected void implReset() {
            reset = true;
            System.err.println("reset encoder");
          }
          protected CoderResult implFlush(ByteBuffer out) {
            flushed = true;
            System.err.println("flushed encoder");
            return CoderResult.UNDERFLOW;
          }
          protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
            // System.err.println("encode loop in.remaining="+in.remaining());
            while (in.hasRemaining()) {
      if (!out.hasRemaining())
      return CoderResult.OVERFLOW;
      reset = false;
      flushed = false;
      out.put((byte) (in.get() & 0xff)); // test works only for latin-1.
            }
            return CoderResult.UNDERFLOW;
          }
        }
        class TestDecoder extends CharsetDecoder {
          // some dummy internal state;
          boolean reset = true;
          boolean flushed = true;

          TestDecoder() {
            super(TestReaderFlushesCharset.this, 1.0f, 1.0f);
          }
          public String state() {
            return "DecoderState: reset="+reset+", flushed="+flushed; }

          protected void implReset() {
            //Thread.dumpStack();
            reset = true;
            System.err.println("reset decoder");
          }
          protected CoderResult implFlush(CharBuffer out) {
            flushed = true;
            System.err.println("flushed decoder");
            return CoderResult.UNDERFLOW;
          }
          protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
            // System.err.println("decode loop in.remaining="+in.remaining());
            while (in.hasRemaining()) {
      if (!out.hasRemaining())
      return CoderResult.OVERFLOW;
      reset = false;
      flushed = false;
      out.put((char) in.get()); // test works only for latin-1.
            }
            return CoderResult.UNDERFLOW;
          }
        }
      }

      ---------- END SOURCE ----------
      (Review ID: 164238)
      ======================================================================

            sherman Xueming Shen
            gmanwanisunw Girish Manwani (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Imported:
              Indexed: