Index: modules/nio_char/src/test/java/tests/api/java/nio/charset/CharsetDecoderTest.java =================================================================== --- modules/nio_char/src/test/java/tests/api/java/nio/charset/CharsetDecoderTest.java (revision 486308) +++ modules/nio_char/src/test/java/tests/api/java/nio/charset/CharsetDecoderTest.java (working copy) @@ -717,12 +717,12 @@ String result = new String(input); if (result.startsWith("malform")) { // reset the cursor to the error position - in.position(inPosition + "malform".length()); + in.position(inPosition); // set the error length return CoderResult.malformedForLength("malform".length()); } else if (result.startsWith("unmap")) { // reset the cursor to the error position - in.position(inPosition + "unmap".length()); + in.position(inPosition); // set the error length return CoderResult.unmappableForLength("unmap".length()); } else if (result.startsWith("runtime")) { Index: modules/nio_char/src/test/java/tests/api/java/nio/charset/CharsetEncoderTest.java =================================================================== --- modules/nio_char/src/test/java/tests/api/java/nio/charset/CharsetEncoderTest.java (revision 486308) +++ modules/nio_char/src/test/java/tests/api/java/nio/charset/CharsetEncoderTest.java (working copy) @@ -1033,13 +1033,13 @@ String result = new String(input); if (result.startsWith("malform")) { // reset the cursor to the error position - in.position(inPosition + "malform".length()); + in.position(inPosition); // in.position(0); // set the error length return CoderResult.malformedForLength("malform".length()); } else if (result.startsWith("unmap")) { // reset the cursor to the error position - in.position(inPosition + "unmap".length()); + in.position(inPosition); // in.position(0); // set the error length return CoderResult.unmappableForLength("unmap".length()); Index: modules/nio_char/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/CharsetDecoderTest.java =================================================================== --- modules/nio_char/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/CharsetDecoderTest.java (revision 486308) +++ modules/nio_char/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/CharsetDecoderTest.java (working copy) @@ -197,8 +197,7 @@ result = decoder.decode(in, out, true); out.flip(); assertTrue(result.isUnderflow()); - // TODO: the following assertion fails on the Reference Impl -- see HARMONY-148 - assertEquals("abb", out.toString()); + assertEquals("bb", out.toString()); } /* Index: modules/nio_char/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/CharsetEncoderTest.java =================================================================== --- modules/nio_char/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/CharsetEncoderTest.java (revision 486308) +++ modules/nio_char/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/CharsetEncoderTest.java (working copy) @@ -163,7 +163,7 @@ assertEquals(4, out.remaining()); assertTrue(result.isUnderflow()); result = encoder.encode(in2, out, true); - assertEquals(0, out.remaining()); - assertTrue(result.isUnderflow()); + assertEquals(4, out.remaining()); + assertTrue(result.isMalformed()); } } Index: modules/nio_char/src/main/java/java/nio/charset/CharsetDecoder.java =================================================================== --- modules/nio_char/src/main/java/java/nio/charset/CharsetDecoder.java (revision 486308) +++ modules/nio_char/src/main/java/java/nio/charset/CharsetDecoder.java (working copy) @@ -130,12 +130,6 @@ // the current status private int status; - private byte[] remains = null; - - // replaceString should be put into output by next decode invocation - // if OVERFLOW occurred in current decode invocation. - private boolean needReplace = false; - /* * --------------------------------------- Constructor * --------------------------------------- @@ -266,18 +260,8 @@ } output.flip(); - CharBuffer truncatedBuffer = null; - // truncate elements after limit in the output. - // clippedBuffer has the same value of capacity and limit. - if (output.limit() == output.capacity()) { - truncatedBuffer = output; - } else { - truncatedBuffer = CharBuffer.allocate(output.remaining()); - truncatedBuffer.put(output); - truncatedBuffer.flip(); - } status = FLUSH; - return truncatedBuffer; + return output; } /* @@ -384,43 +368,13 @@ throw new IllegalStateException(); } - // the last decode invocation hasn't put replace string into out - // because of OVERFLOW - if(needReplace){ - if(out.remaining() >= replace.length()){ - out.put(replace); - needReplace = false; - }else{ - return CoderResult.OVERFLOW; - } - } - CoderResult result = null; - // save old values of remains.length and the position of in. - int remainsLength = 0; - int inOldPosition = in.position(); - - // construct decodingBuffer for decode. - // put "remains" and "in" into decodingBuffer. - ByteBuffer decodingBuffer = null; - if (remains != null) { - remainsLength = remains.length; - decodingBuffer = ByteBuffer.allocate(remains.length - + in.remaining()); - decodingBuffer.put(remains); - remains = null; - } else { - decodingBuffer = ByteBuffer.allocate(in.remaining()); - } - decodingBuffer.put(in); - decodingBuffer.flip(); - // begin to decode while (true) { CodingErrorAction action = null; try { - result = decodeLoop(decodingBuffer, out); + result = decodeLoop(in, out); } catch (BufferOverflowException ex) { // unexpected exception throw new CoderMalfunctionError(ex); @@ -432,49 +386,35 @@ /* * result handling */ - if (result.isUnderflow()) { - if (endOfInput) { - if (decodingBuffer.hasRemaining()) { - result = CoderResult.malformedForLength(decodingBuffer - .remaining()); - decodingBuffer.position(decodingBuffer.limit()); - } - } else { - if (decodingBuffer.hasRemaining()) { - remains = new byte[decodingBuffer.remaining()]; - decodingBuffer.get(remains); - } + if(result.isUnderflow()) { + int remaining = in.remaining(); + if(endOfInput && remaining > 0) { + result = CoderResult.malformedForLength(remaining); + }else{ + status = endOfInput ? END : ONGOING; + return result; } + } + if (result.isOverflow()) { + return result; } // set coding error handle action - if (result.isMalformed()) { - action = malformAction; - } else if (result.isUnmappable()) { + action = malformAction; + if(result.isUnmappable()) { action = unmapAction; } // If the action is IGNORE or REPLACE, we should continue decoding. - if (action == CodingErrorAction.IGNORE) { - continue; - } else if (action == CodingErrorAction.REPLACE) { - if (out.remaining() < replace.length()) { - result = CoderResult.OVERFLOW; - needReplace = true; - } else { - out.put(replace); - continue; + if(action == CodingErrorAction.REPLACE) { + if(out.remaining() < replace.length()) { + return CoderResult.OVERFLOW; } + out.put(replace); + }else{ + if(action != CodingErrorAction.IGNORE) + return result; } - // otherwise, the decode process ends. - break; + in.position(in.position() + result.length()); } - // set in new position - int offset = decodingBuffer.position() > remainsLength ? (decodingBuffer - .position() - remainsLength) - : 0; - in.position(inOldPosition + offset); - - status = endOfInput ? END : ONGOING; - return result; } /** @@ -792,7 +732,6 @@ */ public final CharsetDecoder reset() { status = INIT; - remains = null; implReset(); return this; } Index: modules/nio_char/src/main/java/java/nio/charset/CharsetEncoder.java =================================================================== --- modules/nio_char/src/main/java/java/nio/charset/CharsetEncoder.java (revision 486308) +++ modules/nio_char/src/main/java/java/nio/charset/CharsetEncoder.java (working copy) @@ -123,11 +123,6 @@ // internal status private int status; - // - private char[] remains = null; - - private boolean needReplace = false; - // action for malformed input private CodingErrorAction malformAction; @@ -377,18 +372,8 @@ } else if (result.isUnmappable()) { throw new UnmappableCharacterException(result.length()); } - ByteBuffer truncatedBuffer = null; - // truncate elements after limit in the output. - // clippedBuffer has the same value of capacity and limit. - if (output.limit() == output.capacity()) { - truncatedBuffer = output; - } else { - truncatedBuffer = ByteBuffer.allocate(output.remaining()); - truncatedBuffer.put(output); - truncatedBuffer.flip(); - } status = FLUSH; - return truncatedBuffer; + return output; } /* @@ -487,98 +472,45 @@ throw new IllegalStateException(); } - // construct encodingBuffer for encode. - // put "remains" and "in" into encodingBuffer. - int remainsLength = 0; - int inOldPosition = in.position(); - CharBuffer encodingBuffer = null; - - // check whether need to put the last input replace string. - if (needReplace) { - if (out.remaining() >= replace.length) { - out.put(replace); - needReplace = false; - } else { - return CoderResult.OVERFLOW; - } - } - - if (remains != null) { - remainsLength = remains.length; - encodingBuffer = CharBuffer.allocate(remains.length - + in.remaining()); - encodingBuffer.put(remains); - remains = null; - } else { - encodingBuffer = CharBuffer.allocate(in.remaining()); - } - encodingBuffer.put(in); - encodingBuffer.flip(); - - CoderResult result = CoderResult.UNDERFLOW; - if (encodingBuffer.remaining() > 0) { - while (true) { - CodingErrorAction action = null; - try { - result = encodeLoop(encodingBuffer, out); - } catch (BufferOverflowException ex) { - throw new CoderMalfunctionError(ex); - } catch (BufferUnderflowException ex) { - throw new CoderMalfunctionError(ex); - } - /* - * result handling - */ - if (result.isUnderflow()) { - if (endOfInput) { - if (encodingBuffer.hasRemaining()) { - result = CoderResult - .malformedForLength(encodingBuffer - .remaining()); - encodingBuffer.position(encodingBuffer.limit()); - } - } else { - if (encodingBuffer.hasRemaining()) { - remains = new char[encodingBuffer.remaining()]; - encodingBuffer.get(remains); - } - } - } - // set coding error handle action - if (result.isMalformed()) { - action = malformAction; - } else if (result.isUnmappable()) { - action = unmapAction; - } - // If the action is IGNORE or REPLACE, we should continue - // decoding. - if (action == CodingErrorAction.IGNORE) { - continue; - } else if (action == CodingErrorAction.REPLACE) { - if (out.remaining() < replace.length) { - if (!endOfInput) { - // set needReplace flag. - // replace string will be put next time. - needReplace = true; - } - result = CoderResult.OVERFLOW; - } else { - out.put(replace); - continue; - } - } - // otherwise, the decode process ends. - break; - } - } - // set in new position - int offset = encodingBuffer.position() > remainsLength ? (encodingBuffer - .position() - remainsLength) - : 0; - in.position(inOldPosition + offset); - - status = endOfInput ? END : ONGOING; - return result; + CoderResult result; + while(true){ + try{ + result = encodeLoop(in, out); + } catch(BufferOverflowException e){ + throw new CoderMalfunctionError (e); + } catch(BufferUnderflowException e){ + throw new CoderMalfunctionError (e); + } + if(result.isUnderflow()) { + int remaining = in.remaining(); + if(endOfInput && remaining > 0) { + result = CoderResult.malformedForLength(remaining); + }else{ + status = endOfInput ? END : ONGOING; + return result; + } + + } + if (result.isOverflow()) { + return result; + } + CodingErrorAction action = malformAction; + if(result.isUnmappable()) { + action = unmapAction; + } + // If the action is IGNORE or REPLACE, we should continue + // encoding. + if(action == CodingErrorAction.REPLACE) { + if(out.remaining() < replace.length) { + return CoderResult.OVERFLOW; + } + out.put(replace); + }else{ + if(action != CodingErrorAction.IGNORE) + return result; + } + in.position(in.position() + result.length()); + } } /** Index: modules/luni/src/main/java/java/io/BufferedReader.java =================================================================== --- modules/luni/src/main/java/java/io/BufferedReader.java (revision 486308) +++ modules/luni/src/main/java/java/io/BufferedReader.java (working copy) @@ -324,10 +324,35 @@ public String readLine() throws IOException { synchronized (lock) { if (isOpen()) { + /* Are there buffered characters available? */ + if ((pos >= count) && (fillbuf() == -1)) { + return null; + } + for (int charPos = pos; charPos < count; charPos++) { + char ch = buf[charPos]; + if (ch > '\r') + continue; + if (ch == '\n') { + String res = new String(buf, pos, charPos - pos); + pos = charPos + 1; + return res; + } else if (ch == '\r') { + String res = new String(buf, pos, charPos - pos); + pos = charPos + 1; + if (((pos < count) || (fillbuf() != -1)) + && (buf[pos] == '\n')) { + pos++; + } + return res; + } + } + char eol = '\0'; StringBuilder result = new StringBuilder(80); /* Typical Line Length */ + result.append(buf, pos, count - pos); + pos = count; while (true) { /* Are there buffered characters available? */ if (pos >= count) { @@ -342,9 +367,10 @@ } } for (int charPos = pos; charPos < count; charPos++) { - if (eol == '\0' - && (buf[charPos] == '\n' || buf[charPos] == '\r')) { - eol = buf[charPos]; + if (eol == '\0') { + if ((buf[charPos] == '\n' || buf[charPos] == '\r')) { + eol = buf[charPos]; + } } else if (eol == '\r' && (buf[charPos] == '\n')) { if (charPos > pos) { result.append(buf, pos, charPos - pos - 1); @@ -359,11 +385,11 @@ return result.toString(); } } - if (eol != '\0') { - result.append(buf, pos, count - pos - 1); - } else { - result.append(buf, pos, count - pos); - } + if (eol == '\0') { + result.append(buf, pos, count - pos); + } else { + result.append(buf, pos, count - pos - 1); + } pos = count; } } Index: modules/luni/src/main/java/java/io/InputStreamReader.java =================================================================== --- modules/luni/src/main/java/java/io/InputStreamReader.java (revision 486308) +++ modules/luni/src/main/java/java/io/InputStreamReader.java (working copy) @@ -47,12 +47,12 @@ private static final int BUFFER_SIZE = 8192; + private boolean endOfInput = false; + CharsetDecoder decoder; ByteBuffer bytes = ByteBuffer.allocate(BUFFER_SIZE); - CharBuffer chars = CharBuffer.allocate(BUFFER_SIZE); - /** * Constructs a new InputStreamReader on the InputStream in. * Now character reading can be filtered through this InputStreamReader. @@ -71,7 +71,6 @@ decoder = Charset.forName(encoding).newDecoder().onMalformedInput( CodingErrorAction.REPLACE).onUnmappableCharacter( CodingErrorAction.REPLACE); - chars.limit(0); } /** @@ -103,7 +102,6 @@ } catch (IllegalArgumentException e) { throw new UnsupportedEncodingException(); } - chars.limit(0); } /** @@ -121,7 +119,6 @@ dec.averageCharsPerByte(); this.in = in; decoder = dec; - chars.limit(0); } /** @@ -140,7 +137,6 @@ decoder = charset.newDecoder().onMalformedInput( CodingErrorAction.REPLACE).onUnmappableCharacter( CodingErrorAction.REPLACE); - chars.limit(0); } /** @@ -348,17 +344,12 @@ @Override public int read() throws IOException { synchronized (lock) { - if (isOpen()) { - if (chars.limit() == chars.position()) { - fillBuf(); - } - if (chars.limit() == 0) { - return -1; - } - return chars.get(); - } - // K0070=InputStreamReader is closed. - throw new IOException(Msg.getString("K0070")); //$NON-NLS-1$ + if (!isOpen()) + // K0070=InputStreamReader is closed. + throw new IOException(Msg.getString("K0070")); //$NON-NLS-1$ + + char buf[] = new char[1]; + return read(buf, 0, 1) != -1 ? buf[0] : -1; } } @@ -392,34 +383,76 @@ if (length == 0) { return 0; } - // read at least once - if (chars.limit() == chars.position()) { - fillBuf(); - } - int position = chars.position(); - int availableChars = chars.limit() - position; - // read at least once for one byte - int needChars = length; - while (availableChars < needChars) { - System.arraycopy(chars.array(), position, buf, offset, - availableChars); - chars.position(position + availableChars); - needChars -= availableChars; - offset += availableChars; - if (in.available() <= 0) { - return needChars == length ? -1 : length - needChars; - } - fillBuf(); - position = chars.position(); - availableChars = chars.limit(); - if (availableChars == 0) { - return needChars == length ? -1 : length - needChars; - } - } - System.arraycopy(chars.array(), position, buf, offset, - needChars); - chars.position(chars.position() + needChars); - return length; + + CharBuffer out = CharBuffer.wrap(buf, offset, length); + CoderResult result = CoderResult.UNDERFLOW; + byte[] a = bytes.array(); + boolean has_been_read = false; + + + if(!bytes.hasRemaining() || bytes.limit() == bytes.capacity()) { + // Nothing is available in the buffer... + if(!bytes.hasRemaining()) + bytes.clear(); + int readed = in.read(a, bytes.arrayOffset(), bytes.remaining()); + if(readed == -1) { + endOfInput = true; + return -1; + } + bytes.limit(readed); + has_been_read = true; + } + while (out.hasRemaining()) { + if (bytes.hasRemaining()) { + result = decoder.decode(bytes, out, false); + if (!bytes.hasRemaining() && endOfInput) { + decoder.decode(bytes, out, true); + decoder.flush(out); + decoder.reset(); + break; + } + if(!out.hasRemaining() || bytes.position() == bytes.limit()) + bytes.compact(); + } + if(in.available() > 0 && (!has_been_read && out.hasRemaining()) || out.position() == 0 ) { + bytes.compact(); + int to_read = bytes.remaining(); + int off = bytes.arrayOffset() + bytes.position(); + + to_read = in.read(a, off, to_read); + if (to_read == -1) { + if(bytes.hasRemaining()) + bytes.flip(); + endOfInput = true; + break; + } + has_been_read = true; + if(to_read > 0) { + bytes.limit(bytes.position()+to_read); + bytes.position(0); + } + } else + break; + } + + if(result == CoderResult.UNDERFLOW && endOfInput) { + result = decoder.decode(bytes, out, true); + // FIXME: should flush at first, but seems ICU has a bug that + // it will throw IAE if some malform/unmappable bytes found during + // decoding + // result = decoder.flush(chars); + decoder.reset(); + } + if(result.isMalformed()) { + throw new MalformedInputException(result.length()); + }else if(result.isUnmappable()){ + throw new UnmappableCharacterException(result.length()); + } + if(result == CoderResult.OVERFLOW && bytes.position()!=0) + bytes.flip(); + + return out.position() - offset == 0 ? -1 : out.position() - offset; + } // K0070=InputStreamReader is closed. throw new IOException(Msg.getString("K0070")); //$NON-NLS-1$ @@ -434,46 +467,6 @@ return in != null; } - /* - * refill the buffer from wrapped InputStream - */ - private void fillBuf() throws IOException { - chars.clear(); - int read = 0; - do { - try { - read = in.read(bytes.array()); - } catch (IOException e) { - chars.limit(0); - throw e; - } - boolean endOfInput = false; - if (read == -1) { - bytes.limit(0); - endOfInput = true; - } else { - bytes.limit(read); - } - CoderResult result = decoder.decode(bytes, chars, endOfInput); - if (result.isMalformed()) { - throw new MalformedInputException(result.length()); - } else if (result.isUnmappable()) { - throw new UnmappableCharacterException(result.length()); - } - if (endOfInput) { - /* - * FIXME: should flush at first, but seems ICU has a bug that it - * will throw IAE if some malform/unmappable bytes found during - * decoding. - */ - // result = decoder.flush(chars); - decoder.reset(); - } - bytes.clear(); - } while (read > 0 && chars.position() == 0); - chars.flip(); - } - /** * Answers a boolean indicating whether or not this * InputStreamReader is ready to be read without blocking. If the result is @@ -499,7 +492,8 @@ throw new IOException(Msg.getString("K0070")); //$NON-NLS-1$ } try { - return chars.limit() > chars.position() || in.available() > 0; + return bytes.limit() != BUFFER_SIZE + || in.available() > 0; } catch (IOException e) { return false; }