diff options
author | Elliott Hughes <enh@google.com> | 2013-09-13 21:38:10 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2013-09-13 21:38:11 +0000 |
commit | 16882522e9c5fd8e153b45b25df6bcf70fabb914 (patch) | |
tree | 4bbb825b10dd31c9547b7079e751a93e1eb591aa | |
parent | 6dc885813d1626e0ff1d41ff1940a1e682a57ff2 (diff) | |
parent | 6ad37f500b023ef09fd177ad8cd8e2ba0b842cae (diff) | |
download | libcore-16882522e9c5fd8e153b45b25df6bcf70fabb914.zip libcore-16882522e9c5fd8e153b45b25df6bcf70fabb914.tar.gz libcore-16882522e9c5fd8e153b45b25df6bcf70fabb914.tar.bz2 |
Merge "Clean up CharsetDecoder and CharsetEncoder."
8 files changed, 235 insertions, 262 deletions
diff --git a/harmony-tests/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/ASCIICharsetEncoderTest.java b/harmony-tests/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/ASCIICharsetEncoderTest.java index 6f59190..a85576c 100644 --- a/harmony-tests/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/ASCIICharsetEncoderTest.java +++ b/harmony-tests/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/ASCIICharsetEncoderTest.java @@ -4,9 +4,9 @@ * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -33,7 +33,7 @@ public class ASCIICharsetEncoderTest extends TestCase { // charset for ascii private static final Charset cs = Charset.forName("ascii"); private static final CharsetEncoder encoder = cs.newEncoder(); - private static final int MAXCODEPOINT = 0x7F; + private static final int MAXCODEPOINT = 0x7F; /* * @see CharsetEncoderTest#setUp() */ @@ -96,21 +96,21 @@ public class ASCIICharsetEncoderTest extends TestCase { public void testEncodeMapping() throws CharacterCodingException { encoder.reset(); - + for (int i =0; i <= MAXCODEPOINT; i++) { char[] chars = Character.toChars(i); CharBuffer cb = CharBuffer.wrap(chars); ByteBuffer bb = encoder.encode(cb); assertEquals(i, bb.get(0)); } - + CharBuffer cb = CharBuffer.wrap("\u0080"); try { encoder.encode(cb); } catch (UnmappableCharacterException e) { //expected } - + cb = CharBuffer.wrap("\ud800"); try { encoder.encode(cb); @@ -128,11 +128,11 @@ public class ASCIICharsetEncoderTest extends TestCase { //expected } } - + public void testInternalState() { CharBuffer in = CharBuffer.wrap("A"); ByteBuffer out = ByteBuffer.allocate(0x10); - + //normal encoding process encoder.reset(); encoder.encode(in, out, false); @@ -140,13 +140,13 @@ public class ASCIICharsetEncoderTest extends TestCase { encoder.encode(in, out, true); encoder.flush(out); } - + //reset could be called at any time public void testInternalState_Reset() { CharsetEncoder newEncoder = cs.newEncoder(); //Init - > reset newEncoder.reset(); - + //reset - > reset newEncoder.reset(); @@ -174,7 +174,7 @@ public class ASCIICharsetEncoderTest extends TestCase { newEncoder.reset(); } } - + public void testInternalState_Encoding() { CharsetEncoder newEncoder = cs.newEncoder(); //Init - > encoding @@ -183,27 +183,27 @@ public class ASCIICharsetEncoderTest extends TestCase { ByteBuffer out = ByteBuffer.allocate(0x10); newEncoder.encode(in, out, false); } - + //reset - > encoding { CharBuffer in = CharBuffer.wrap("A"); ByteBuffer out = ByteBuffer.allocate(0x10); - newEncoder.reset(); + newEncoder.reset(); newEncoder.encode(in, out, false); } //reset - > encoding - > encoding { - newEncoder.reset(); + newEncoder.reset(); CharBuffer in = CharBuffer.wrap("A"); ByteBuffer out = ByteBuffer.allocate(0x10); newEncoder.encode(in, out, false); in = CharBuffer.wrap("BC"); newEncoder.encode(in, out, false); } - + //encoding_end - > encoding { - newEncoder.reset(); + newEncoder.reset(); CharBuffer in = CharBuffer.wrap("A"); ByteBuffer out = ByteBuffer.allocate(0x10); newEncoder.encode(in, out, true); @@ -217,7 +217,7 @@ public class ASCIICharsetEncoderTest extends TestCase { } //flushed - > encoding { - newEncoder.reset(); + newEncoder.reset(); CharBuffer in = CharBuffer.wrap("A"); ByteBuffer out = ByteBuffer.allocate(0x10); newEncoder.encode(in, out, true); @@ -231,7 +231,7 @@ public class ASCIICharsetEncoderTest extends TestCase { } } } - + public void testInternalState_Encoding_END() { CharsetEncoder newEncoder = cs.newEncoder(); @@ -241,7 +241,7 @@ public class ASCIICharsetEncoderTest extends TestCase { ByteBuffer out = ByteBuffer.allocate(0x10); newEncoder.encode(in, out, true); } - + //Reset -> encoding_end { CharBuffer in = CharBuffer.wrap("A"); @@ -259,7 +259,7 @@ public class ASCIICharsetEncoderTest extends TestCase { in = CharBuffer.wrap("BC"); newEncoder.encode(in, out, true); } - + //Reset -> encoding_end { newEncoder.reset(); @@ -269,7 +269,7 @@ public class ASCIICharsetEncoderTest extends TestCase { in = CharBuffer.wrap("BC"); newEncoder.encode(in, out, true); } - + //Flushed -> encoding_end { newEncoder.reset(); @@ -286,10 +286,10 @@ public class ASCIICharsetEncoderTest extends TestCase { } } } - + public void testInternalState_Flushed() { CharsetEncoder newEncoder = cs.newEncoder(); - + // init -> flushed { ByteBuffer out = ByteBuffer.allocate(0x10); @@ -316,7 +316,7 @@ public class ASCIICharsetEncoderTest extends TestCase { //expected } } - + //encoding - > flushed { newEncoder.reset(); @@ -331,7 +331,7 @@ public class ASCIICharsetEncoderTest extends TestCase { // expected } } - + //encoding_end -> flushed { newEncoder.reset(); @@ -340,7 +340,7 @@ public class ASCIICharsetEncoderTest extends TestCase { newEncoder.encode(in, out, true); newEncoder.flush(out); } - + //flushd - > flushed { newEncoder.reset(); @@ -348,15 +348,10 @@ public class ASCIICharsetEncoderTest extends TestCase { ByteBuffer out = ByteBuffer.allocate(0x10); newEncoder.encode(in, out, true); newEncoder.flush(out); - try { - newEncoder.flush(out); - fail("Should throw IllegalStateException"); - } catch (IllegalStateException e) { - // expected - } + newEncoder.flush(out); } } - + public void testInternalState_Encode() throws CharacterCodingException { CharsetEncoder newEncoder = cs.newEncoder(); //Init - > encode @@ -364,14 +359,14 @@ public class ASCIICharsetEncoderTest extends TestCase { CharBuffer in = CharBuffer.wrap("A"); newEncoder.encode(in); } - + //Reset - > encode { newEncoder.reset(); CharBuffer in = CharBuffer.wrap("A"); newEncoder.encode(in); } - + //Encoding -> encode { newEncoder.reset(); @@ -381,7 +376,7 @@ public class ASCIICharsetEncoderTest extends TestCase { in = CharBuffer.wrap("BC"); newEncoder.encode(in); } - + //Encoding_end -> encode { newEncoder.reset(); @@ -391,7 +386,7 @@ public class ASCIICharsetEncoderTest extends TestCase { in = CharBuffer.wrap("BC"); newEncoder.encode(in); } - + //Flushed -> reset { newEncoder.reset(); @@ -403,17 +398,17 @@ public class ASCIICharsetEncoderTest extends TestCase { out = newEncoder.encode(in); } } - + public void testInternalState_from_Encode() throws CharacterCodingException { CharsetEncoder newEncoder = cs.newEncoder(); - + //Encode -> Reset { CharBuffer in = CharBuffer.wrap("A"); newEncoder.encode(in); newEncoder.reset(); } - + // Encode -> encoding { CharBuffer in = CharBuffer.wrap("A"); @@ -426,12 +421,13 @@ public class ASCIICharsetEncoderTest extends TestCase { // expected } } - + //Encode -> Encoding_end { CharBuffer in = CharBuffer.wrap("A"); - newEncoder.encode(in); ByteBuffer out = ByteBuffer.allocate(0x10); + newEncoder.reset(); + newEncoder.encode(in, out, false); newEncoder.encode(in, out, true); } @@ -441,7 +437,7 @@ public class ASCIICharsetEncoderTest extends TestCase { ByteBuffer out = newEncoder.encode(in); newEncoder.flush(out); } - + //Encode - > encode { CharBuffer in = CharBuffer.wrap("A"); diff --git a/harmony-tests/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/CharsetDecoderTest.java b/harmony-tests/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/CharsetDecoderTest.java index 4ed4ab9..1a7b984 100644 --- a/harmony-tests/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/CharsetDecoderTest.java +++ b/harmony-tests/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/CharsetDecoderTest.java @@ -4,9 +4,9 @@ * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -62,7 +62,7 @@ public class CharsetDecoderTest extends TestCase { return null; } } - + /** * @tests java.nio.charset.CharsetDecoder#decode(java.nio.ByteBuffer) */ @@ -86,7 +86,7 @@ public class CharsetDecoderTest extends TestCase { // // charbuf = Charset.forName("UTF-16LE").decode(buf); // assertEquals("Assert 2: charset UTF16LE", 0, charbuf.length()); - + // Regression for HARMONY-99 CharsetDecoder decoder2 = Charset.forName("UTF-16").newDecoder(); decoder2.onMalformedInput(CodingErrorAction.REPORT); @@ -97,9 +97,9 @@ public class CharsetDecoderTest extends TestCase { fail("Assert 3: MalformedInputException should have thrown"); } catch (MalformedInputException e) { //expected - } + } } - + /* * Test malfunction decode(ByteBuffer) */ @@ -124,7 +124,7 @@ public class CharsetDecoderTest extends TestCase { // expected } } - + /* * Mock charset class with malfunction decode & encode. */ @@ -173,8 +173,8 @@ public class CharsetDecoderTest extends TestCase { protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { throw new BufferOverflowException(); } - } - + } + /* * Test the method decode(ByteBuffer) . */ @@ -249,16 +249,16 @@ public class CharsetDecoderTest extends TestCase { CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder(); decoder.onMalformedInput(CodingErrorAction.REPORT); + decoder.onUnmappableCharacter(CodingErrorAction.REPORT); /* * When bytebuffer has a backing array... */ for (byte[] bytes : invalidSequences) { try { - decoder.decode(ByteBuffer.wrap(bytes)); - fail("No exception thrown on " + Arrays.toString(bytes)); - } catch (MalformedInputException e) { - // expected + CharBuffer cb = decoder.decode(ByteBuffer.wrap(bytes)); + fail("No exception thrown on " + Arrays.toString(bytes) + " '" + cb + "'"); + } catch (MalformedInputException expected) { } } @@ -269,10 +269,9 @@ public class CharsetDecoderTest extends TestCase { try { ByteBuffer bb = ByteBuffer.allocateDirect(8); bb.put(bytes).flip(); - decoder.decode(bb); - fail("No exception thrown on " + Arrays.toString(bytes)); - } catch (MalformedInputException e) { - // expected + CharBuffer cb = decoder.decode(bb); + fail("No exception thrown on " + Arrays.toString(bytes) + " '" + cb + "'"); + } catch (MalformedInputException expected) { } } } diff --git a/harmony-tests/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/CharsetEncoderTest.java b/harmony-tests/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/CharsetEncoderTest.java index dd514da..c3f1a8d 100644 --- a/harmony-tests/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/CharsetEncoderTest.java +++ b/harmony-tests/src/test/java/org/apache/harmony/nio_char/tests/java/nio/charset/CharsetEncoderTest.java @@ -157,26 +157,36 @@ public class CharsetEncoderTest extends TestCase { public void test_EncodeLjava_nio_CharBufferLjava_nio_ByteBufferB() throws Exception { Charset utf8 = Charset.forName("utf-8"); CharsetEncoder encoder = utf8.newEncoder(); - CharBuffer in1 = CharBuffer.wrap("\ud800"); - CharBuffer in2 = CharBuffer.wrap("\udc00"); - ByteBuffer out = ByteBuffer.allocate(4); + CharBuffer char1 = CharBuffer.wrap("\ud800"); + CharBuffer char2 = CharBuffer.wrap("\udc00"); + ByteBuffer bytes = ByteBuffer.allocate(4); encoder.reset(); // If we supply just the high surrogate... - CoderResult result = encoder.encode(in1, out, false); + CoderResult result = encoder.encode(char1, bytes, false); // ...we're not done... assertTrue(result.isUnderflow()); - assertEquals(4, out.remaining()); + assertEquals(4, bytes.remaining()); // ...but if we then supply the low surrogate... - result = encoder.encode(in2, out, true); + result = encoder.encode(char2, bytes, true); + assertTrue(result.isUnderflow()); // ...we're done. Note that the RI loses its state in // between the two characters, so it can't do this. - assertEquals(0, out.remaining()); + assertEquals(0, bytes.remaining()); + + // Did we get the UTF-8 for U+10000? + assertEquals(4, bytes.limit()); + assertEquals((byte) 0xf0, bytes.get(0)); + assertEquals((byte) 0x90, bytes.get(1)); + assertEquals((byte) 0x80, bytes.get(2)); + assertEquals((byte) 0x80, bytes.get(3)); // See what we got in the output buffer by decoding and checking that we // get back the same surrogate pair. - out.flip(); - CharBuffer chars = utf8.newDecoder().decode(out); + bytes.flip(); + CharBuffer chars = utf8.newDecoder().decode(bytes); + assertEquals(0, bytes.remaining()); + assertEquals(2, chars.limit()); assertEquals(0xd800, chars.get(0)); assertEquals(0xdc00, chars.get(1)); } diff --git a/harmony-tests/src/test/java/tests/api/java/nio/charset/CharsetDecoderTest.java b/harmony-tests/src/test/java/tests/api/java/nio/charset/CharsetDecoderTest.java index 9cd59ea..7fbe9e7 100644 --- a/harmony-tests/src/test/java/tests/api/java/nio/charset/CharsetDecoderTest.java +++ b/harmony-tests/src/test/java/tests/api/java/nio/charset/CharsetDecoderTest.java @@ -4,9 +4,9 @@ * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -600,6 +600,15 @@ public class CharsetDecoderTest extends TestCase { public void testFlushIllegalState() throws CharacterCodingException { ByteBuffer in = ByteBuffer.wrap(new byte[] { 98, 98 }); CharBuffer out = CharBuffer.allocate(5); + + // Illegal state: after reset. + decoder.reset(); + try { + decoder.flush(out); + fail(); + } catch (IllegalStateException expected) { + } + // Normal case: after decode with endOfInput is true decoder.reset(); decoder.decode(in, out, true); @@ -607,23 +616,19 @@ public class CharsetDecoderTest extends TestCase { CoderResult result = decoder.flush(out); assertSame(result, CoderResult.UNDERFLOW); - // Illegal state: flush twice - try { - decoder.flush(out); - fail("should throw IllegalStateException"); - } catch (IllegalStateException e) { - } + // Good state: flush twice + decoder.flush(out); // Illegal state: flush after decode with endOfInput is false decoder.reset(); decoder.decode(in, out, false); try { decoder.flush(out); - fail("should throw IllegalStateException"); - } catch (IllegalStateException e) { + fail(); + } catch (IllegalStateException expected) { } } - + // test illegal states for decode facade public void testDecodeFacadeIllegalState() throws CharacterCodingException { // decode facade can be execute in anywhere diff --git a/harmony-tests/src/test/java/tests/api/java/nio/charset/CharsetEncoderTest.java b/harmony-tests/src/test/java/tests/api/java/nio/charset/CharsetEncoderTest.java index ef219be..b63f4d9 100644 --- a/harmony-tests/src/test/java/tests/api/java/nio/charset/CharsetEncoderTest.java +++ b/harmony-tests/src/test/java/tests/api/java/nio/charset/CharsetEncoderTest.java @@ -278,34 +278,36 @@ public class CharsetEncoderTest extends TestCase { assertSame(encoder, encoder.reset()); } - public void testFlushIllegalState() throws CharacterCodingException { - CharBuffer in = CharBuffer.wrap("aaa"); - ByteBuffer out = ByteBuffer.allocate(5); - - // Normal case: after encode with endOfInput is true - assertSame(encoder, encoder.reset()); - encoder.encode(in, out, true); - out.rewind(); - CoderResult result = encoder.flush(out); - - // Illegal state: flush twice - try { - encoder.flush(out); - fail("should throw IllegalStateException"); - } catch (IllegalStateException e) { - // Expected - } + public void testFlushIllegalState() throws CharacterCodingException { + CharBuffer in = CharBuffer.wrap("aaa"); + ByteBuffer out = ByteBuffer.allocate(5); + + // Illegal state: after reset. + encoder.reset(); + try { + encoder.flush(out); + fail(); + } catch (IllegalStateException expected) { + } - // Illegal state: flush after encode with endOfInput is false - assertSame(encoder, encoder.reset()); - encoder.encode(in, out, false); - try { - encoder.flush(out); - fail("should throw IllegalStateException"); - } catch (IllegalStateException e) { - // Expected - } - } + // Normal case: after encode with endOfInput is true + assertSame(encoder, encoder.reset()); + encoder.encode(in, out, true); + out.rewind(); + CoderResult result = encoder.flush(out); + + // Good state: flush twice + encoder.flush(out); + + // Illegal state: flush after encode with endOfInput is false + assertSame(encoder, encoder.reset()); + encoder.encode(in, out, false); + try { + encoder.flush(out); + fail(); + } catch (IllegalStateException expected) { + } + } public void testFlushAfterConstructing() { ByteBuffer out = ByteBuffer.allocate(5); diff --git a/harmony-tests/src/test/java/tests/api/java/nio/charset/CharsetTest.java b/harmony-tests/src/test/java/tests/api/java/nio/charset/CharsetTest.java index adee76e..92f230e 100644 --- a/harmony-tests/src/test/java/tests/api/java/nio/charset/CharsetTest.java +++ b/harmony-tests/src/test/java/tests/api/java/nio/charset/CharsetTest.java @@ -136,17 +136,24 @@ public class CharsetTest extends TestCase { } public void test_EUC_JP_replacement_character() throws Exception { - assertEncodes(Charset.forName("EUC-JP"), "\ufffd", 0xf4, 0xfe); + // We have text either side of the replacement character, because all kinds of errors + // could lead to a replacement character being returned. + assertEncodes(Charset.forName("EUC-JP"), " \ufffd ", ' ', 0xf4, 0xfe, ' '); + assertDecodes(Charset.forName("EUC-JP"), " \ufffd ", ' ', 0xf4, 0xfe, ' '); } public void test_SCSU_replacement_character() throws Exception { - assertDecodes(Charset.forName("SCSU"), "\ufffd", 14, 0xff); - assertEncodes(Charset.forName("SCSU"), "\ufffd", 14, 0xff); + // We have text either side of the replacement character, because all kinds of errors + // could lead to a replacement character being returned. + assertEncodes(Charset.forName("SCSU"), " \ufffd ", ' ', 14, 0xff, 0xfd, ' '); + assertDecodes(Charset.forName("SCSU"), " \ufffd ", ' ', 14, 0xff, 0xfd, ' '); } public void test_Shift_JIS_replacement_character() throws Exception { - assertDecodes(Charset.forName("Shift_JIS"), "\ufffd", 0xfc); - assertEncodes(Charset.forName("Shift_JIS"), "\ufffd", 0xfc); + // We have text either side of the replacement character, because all kinds of errors + // could lead to a replacement character being returned. + assertEncodes(Charset.forName("Shift_JIS"), " \ufffd ", ' ', 0xfc, 0xfc, ' '); + assertDecodes(Charset.forName("Shift_JIS"), " \ufffd ", ' ', 0xfc, 0xfc, ' '); } public void test_UTF_16() throws Exception { diff --git a/luni/src/main/java/java/nio/charset/CharsetDecoder.java b/luni/src/main/java/java/nio/charset/CharsetDecoder.java index 7aa546c..7b53ceb 100644 --- a/luni/src/main/java/java/nio/charset/CharsetDecoder.java +++ b/luni/src/main/java/java/nio/charset/CharsetDecoder.java @@ -82,22 +82,22 @@ import java.nio.CharBuffer; * @see java.nio.charset.CharsetEncoder */ public abstract class CharsetDecoder { - private static final int INIT = 0; - private static final int ONGOING = 1; - private static final int END = 2; - private static final int FLUSH = 3; + private static final String RESET = "RESET"; + private static final String ONGOING = "ONGOING"; + private static final String END_OF_INPUT = "END_OF_INPUT"; + private static final String FLUSHED = "FLUSHED"; + + private final Charset charset; private final float averageCharsPerByte; private final float maxCharsPerByte; - private final Charset cs; - - private CodingErrorAction malformedInputAction; - private CodingErrorAction unmappableCharacterAction; + private String replacementChars = "\ufffd"; - private String replacementChars; + private String state = RESET; - private int status; + private CodingErrorAction malformedInputAction = CodingErrorAction.REPORT; + private CodingErrorAction unmappableCharacterAction = CodingErrorAction.REPORT; /** * Constructs a new <code>CharsetDecoder</code> using the given @@ -114,8 +114,7 @@ public abstract class CharsetDecoder { * the maximum number of characters created by this decoder for * one input byte, must be positive. * @throws IllegalArgumentException - * if <code>averageCharsPerByte</code> or - * <code>maxCharsPerByte</code> is negative. + * if {@code averageCharsPerByte <= 0 || maxCharsPerByte <= 0 || averageCharsPerByte > maxCharsPerByte}. */ protected CharsetDecoder(Charset charset, float averageCharsPerByte, float maxCharsPerByte) { if (averageCharsPerByte <= 0 || maxCharsPerByte <= 0) { @@ -126,11 +125,7 @@ public abstract class CharsetDecoder { } this.averageCharsPerByte = averageCharsPerByte; this.maxCharsPerByte = maxCharsPerByte; - cs = charset; - status = INIT; - malformedInputAction = CodingErrorAction.REPORT; - unmappableCharacterAction = CodingErrorAction.REPORT; - replacementChars = "\ufffd"; + this.charset = charset; } /** @@ -145,7 +140,7 @@ public abstract class CharsetDecoder { * Returns the {@link Charset} which this decoder uses. */ public final Charset charset() { - return cs; + return charset; } /** @@ -182,35 +177,30 @@ public abstract class CharsetDecoder { * if another exception happened during the decode operation. */ public final CharBuffer decode(ByteBuffer in) throws CharacterCodingException { - reset(); int length = (int) (in.remaining() * averageCharsPerByte); - CharBuffer output = CharBuffer.allocate(length); - CoderResult result = null; - while (true) { - result = decode(in, output, false); - checkCoderResult(result); - if (result.isUnderflow()) { - break; - } else if (result.isOverflow()) { - output = allocateMore(output); + CharBuffer out = CharBuffer.allocate(length); + + reset(); + + while (state != FLUSHED) { + CoderResult result = decode(in, out, true); + if (result == CoderResult.OVERFLOW) { + out = allocateMore(out); + continue; // No point trying to flush to an already-full buffer. + } else { + checkCoderResult(result); } - } - result = decode(in, output, true); - checkCoderResult(result); - while (true) { - result = flush(output); - checkCoderResult(result); - if (result.isOverflow()) { - output = allocateMore(output); + result = flush(out); + if (result == CoderResult.OVERFLOW) { + out = allocateMore(out); } else { - break; + checkCoderResult(result); } } - output.flip(); - status = FLUSH; - return output; + out.flip(); + return out; } /* @@ -304,54 +294,42 @@ public abstract class CharsetDecoder { * <code>BufferOverflowException</code>. */ public final CoderResult decode(ByteBuffer in, CharBuffer out, boolean endOfInput) { - if (status == FLUSH || (!endOfInput && status == END)) { - throw new IllegalStateException(); + if (state != RESET && state != ONGOING && !(endOfInput && state == END_OF_INPUT)) { + throw illegalStateException(); } - CoderResult result = null; + state = endOfInput ? END_OF_INPUT : ONGOING; - // begin to decode while (true) { - CodingErrorAction action = null; + CoderResult result; try { result = decodeLoop(in, out); } catch (BufferOverflowException ex) { - // unexpected exception throw new CoderMalfunctionError(ex); } catch (BufferUnderflowException ex) { - // unexpected exception throw new CoderMalfunctionError(ex); } - /* - * result handling - */ - if (result.isUnderflow()) { - int remaining = in.remaining(); - status = endOfInput ? END : ONGOING; - if (endOfInput && remaining > 0) { - result = CoderResult.malformedForLength(remaining); + if (result == CoderResult.UNDERFLOW) { + if (endOfInput && in.hasRemaining()) { + result = CoderResult.malformedForLength(in.remaining()); } else { return result; } - } - if (result.isOverflow()) { + } else if (result == CoderResult.OVERFLOW) { return result; } - // set coding error handle action - action = malformedInputAction; - if (result.isUnmappable()) { - action = unmappableCharacterAction; - } - // If the action is IGNORE or REPLACE, we should continue decoding. - if (action == CodingErrorAction.REPLACE) { + + // We have a real error, so do what the appropriate action tells us what to do... + CodingErrorAction action = + result.isUnmappable() ? unmappableCharacterAction : malformedInputAction; + if (action == CodingErrorAction.REPORT) { + return result; + } else if (action == CodingErrorAction.REPLACE) { if (out.remaining() < replacementChars.length()) { return CoderResult.OVERFLOW; } out.put(replacementChars); - } else { - if (action != CodingErrorAction.IGNORE) - return result; } in.position(in.position() + result.length()); } @@ -442,20 +420,15 @@ public abstract class CharsetDecoder { * @return <code>CoderResult.UNDERFLOW</code> or * <code>CoderResult.OVERFLOW</code>. * @throws IllegalStateException - * if this decoder hasn't read all input bytes during one - * decoding process, which means neither after calling - * {@link #decode(ByteBuffer) decode(ByteBuffer)} nor after - * calling {@link #decode(ByteBuffer, CharBuffer, boolean) - * decode(ByteBuffer, CharBuffer, boolean)} with true as value - * for the last boolean parameter. + * if this decoder isn't already flushed or at end of input. */ public final CoderResult flush(CharBuffer out) { - if (status != END && status != INIT) { - throw new IllegalStateException(); + if (state != FLUSHED && state != END_OF_INPUT) { + throw illegalStateException(); } CoderResult result = implFlush(out); if (result == CoderResult.UNDERFLOW) { - status = FLUSH; + state = FLUSHED; } return result; } @@ -582,7 +555,7 @@ public abstract class CharsetDecoder { * the new action on malformed input error. * @return this decoder. * @throws IllegalArgumentException - * if {@code newAction} is {@code null}. + * if {@code newAction == null}. */ public final CharsetDecoder onMalformedInput(CodingErrorAction newAction) { if (newAction == null) { @@ -604,7 +577,7 @@ public abstract class CharsetDecoder { * the new action on unmappable character error. * @return this decoder. * @throws IllegalArgumentException - * if {@code newAction} is {@code null}. + * if {@code newAction == null}. */ public final CharsetDecoder onUnmappableCharacter(CodingErrorAction newAction) { if (newAction == null) { @@ -631,8 +604,8 @@ public abstract class CharsetDecoder { * new replacement as argument. * * @param replacement - * the replacement string, cannot be null or empty. Its length - * cannot be larger than {@link #maxCharsPerByte()}. + * the replacement string cannot be null, empty, or longer + * than {@link #maxCharsPerByte()}. * @return this decoder. * @throws IllegalArgumentException * if the given replacement cannot satisfy the requirement @@ -655,14 +628,12 @@ public abstract class CharsetDecoder { } /** - * Resets this decoder. This method will reset the internal status, and then - * calls <code>implReset()</code> to reset any status related to the + * Resets this decoder. This method will reset the internal state, and then + * calls {@link #implReset} to reset any state related to the * specific charset. - * - * @return this decoder. */ public final CharsetDecoder reset() { - status = INIT; + state = RESET; implReset(); return this; } @@ -674,4 +645,8 @@ public abstract class CharsetDecoder { public CodingErrorAction unmappableCharacterAction() { return unmappableCharacterAction; } + + private IllegalStateException illegalStateException() { + throw new IllegalStateException("State: " + state); + } } diff --git a/luni/src/main/java/java/nio/charset/CharsetEncoder.java b/luni/src/main/java/java/nio/charset/CharsetEncoder.java index 5c4d3b3..9217bba 100644 --- a/luni/src/main/java/java/nio/charset/CharsetEncoder.java +++ b/luni/src/main/java/java/nio/charset/CharsetEncoder.java @@ -76,25 +76,22 @@ import java.util.Arrays; * @see java.nio.charset.CharsetDecoder */ public abstract class CharsetEncoder { - private static final int READY = 0; - private static final int ONGOING = 1; - private static final int END = 2; - private static final int FLUSH = 3; - private static final int INIT = 4; + private static final String RESET = "RESET"; + private static final String ONGOING = "ONGOING"; + private static final String END_OF_INPUT = "END_OF_INPUT"; + private static final String FLUSHED = "FLUSHED"; - private final Charset cs; + private final Charset charset; private final float averageBytesPerChar; private final float maxBytesPerChar; private byte[] replacementBytes; - private int status; - // internal status indicates encode(CharBuffer) operation is finished - private boolean finished; + private String state = RESET; - private CodingErrorAction malformedInputAction; - private CodingErrorAction unmappableCharacterAction; + private CodingErrorAction malformedInputAction = CodingErrorAction.REPORT; + private CodingErrorAction unmappableCharacterAction = CodingErrorAction.REPORT; // decoder instance for this encoder's charset, used for replacement value checking private CharsetDecoder decoder; @@ -139,12 +136,9 @@ public abstract class CharsetEncoder { if (averageBytesPerChar > maxBytesPerChar) { throw new IllegalArgumentException("averageBytesPerChar is greater than maxBytesPerChar"); } - this.cs = cs; + this.charset = cs; this.averageBytesPerChar = averageBytesPerChar; this.maxBytesPerChar = maxBytesPerChar; - status = INIT; - malformedInputAction = CodingErrorAction.REPORT; - unmappableCharacterAction = CodingErrorAction.REPORT; if (trusted) { // The RI enforces unnecessary restrictions on the replacement bytes. We trust ICU to // know what it's doing. Doing so lets us support ICU's EUC-JP, SCSU, and Shift_JIS. @@ -165,7 +159,7 @@ public abstract class CharsetEncoder { /** * Tests whether the given character can be encoded by this encoder. * - * <p>Note that this method may change the internal status of this encoder, so + * <p>Note that this method may change the internal state of this encoder, so * it should not be called when another encoding process is ongoing, * otherwise it will throw an <code>IllegalStateException</code>. * @@ -179,7 +173,7 @@ public abstract class CharsetEncoder { * Tests whether the given <code>CharSequence</code> can be encoded by this * encoder. * - * <p>Note that this method may change the internal status of this encoder, so + * <p>Note that this method may change the internal state of this encoder, so * it should not be called when another encode process is ongoing, otherwise * it will throw an <code>IllegalStateException</code>. * @@ -193,12 +187,13 @@ public abstract class CharsetEncoder { cb = CharBuffer.wrap(sequence); } - if (status == FLUSH || status == INIT) { - status = READY; + if (state == FLUSHED) { + reset(); } - if (status != READY) { - throw new IllegalStateException(); + if (state != RESET) { + throw illegalStateException(); } + CodingErrorAction originalMalformedInputAction = malformedInputAction; CodingErrorAction originalUnmappableCharacterAction = unmappableCharacterAction; onMalformedInput(CodingErrorAction.REPORT); @@ -219,7 +214,7 @@ public abstract class CharsetEncoder { * Returns the {@link Charset} which this encoder uses. */ public final Charset charset() { - return cs; + return charset; } /** @@ -256,37 +251,27 @@ public abstract class CharsetEncoder { public final ByteBuffer encode(CharBuffer in) throws CharacterCodingException { int length = (int) (in.remaining() * averageBytesPerChar); ByteBuffer out = ByteBuffer.allocate(length); - if (in.hasRemaining() == false) { - return out; - } reset(); - while (in.hasRemaining()) { + while (state != FLUSHED) { CoderResult result = encode(in, out, true); - if (result == CoderResult.UNDERFLOW) { - break; - } else if (result == CoderResult.OVERFLOW) { + if (result == CoderResult.OVERFLOW) { out = allocateMore(out); - continue; + continue; // No point trying to flush to an already-full buffer. } else { checkCoderResult(result); } result = flush(out); - if (result == CoderResult.UNDERFLOW) { - break; - } else if (result == CoderResult.OVERFLOW) { + if (result == CoderResult.OVERFLOW) { out = allocateMore(out); - continue; } else { checkCoderResult(result); } } out.flip(); - status = READY; - finished = true; return out; } @@ -371,26 +356,22 @@ public abstract class CharsetEncoder { * <code>BufferUnderflowException</code>. */ public final CoderResult encode(CharBuffer in, ByteBuffer out, boolean endOfInput) { - // If the previous step is encode(CharBuffer), then no more input is needed - // thus endOfInput should not be false - if (status == READY && finished && !endOfInput) { - throw new IllegalStateException(); - } - if (status == FLUSH || (!endOfInput && status == END)) { - throw new IllegalStateException(); + if (state != RESET && state != ONGOING && !(endOfInput && state == END_OF_INPUT)) { + throw illegalStateException(); } - status = endOfInput ? END : ONGOING; + state = endOfInput ? END_OF_INPUT : ONGOING; while (true) { CoderResult result; try { result = encodeLoop(in, out); - } catch (BufferOverflowException e) { - throw new CoderMalfunctionError(e); - } catch (BufferUnderflowException e) { - throw new CoderMalfunctionError(e); + } catch (BufferOverflowException ex) { + throw new CoderMalfunctionError(ex); + } catch (BufferUnderflowException ex) { + throw new CoderMalfunctionError(ex); } + if (result == CoderResult.UNDERFLOW) { if (endOfInput && in.hasRemaining()) { result = CoderResult.malformedForLength(in.remaining()); @@ -400,12 +381,13 @@ public abstract class CharsetEncoder { } else if (result == CoderResult.OVERFLOW) { return result; } + + // We have a real error, so do what the appropriate action tells us what to do... CodingErrorAction action = result.isUnmappable() ? unmappableCharacterAction : malformedInputAction; if (action == CodingErrorAction.REPORT) { return result; - } - if (action == CodingErrorAction.REPLACE) { + } else if (action == CodingErrorAction.REPLACE) { if (out.remaining() < replacementBytes.length) { return CoderResult.OVERFLOW; } @@ -473,20 +455,15 @@ public abstract class CharsetEncoder { * @return <code>CoderResult.UNDERFLOW</code> or * <code>CoderResult.OVERFLOW</code>. * @throws IllegalStateException - * if this encoder hasn't read all input characters during one - * encoding process, which means neither after calling - * {@link #encode(CharBuffer) encode(CharBuffer)} nor after - * calling {@link #encode(CharBuffer, ByteBuffer, boolean) - * encode(CharBuffer, ByteBuffer, boolean)} with {@code true} - * for the last boolean parameter. + * if this encoder isn't already flushed or at end of input. */ public final CoderResult flush(ByteBuffer out) { - if (status != END && status != READY) { - throw new IllegalStateException(); + if (state != FLUSHED && state != END_OF_INPUT) { + throw illegalStateException(); } CoderResult result = implFlush(out); if (result == CoderResult.UNDERFLOW) { - status = FLUSH; + state = FLUSHED; } return result; } @@ -555,7 +532,7 @@ public abstract class CharsetEncoder { */ public boolean isLegalReplacement(byte[] replacement) { if (decoder == null) { - decoder = cs.newDecoder(); + decoder = charset.newDecoder(); decoder.onMalformedInput(CodingErrorAction.REPORT); decoder.onUnmappableCharacter(CodingErrorAction.REPORT); } @@ -671,14 +648,12 @@ public abstract class CharsetEncoder { } /** - * Resets this encoder. This method will reset the internal status and then - * calls <code>implReset()</code> to reset any status related to the + * Resets this encoder. This method will reset the internal state and then + * calls {@link #implReset} to reset any state related to the * specific charset. - * - * @return this encoder. */ public final CharsetEncoder reset() { - status = INIT; + state = RESET; implReset(); return this; } @@ -690,4 +665,8 @@ public abstract class CharsetEncoder { public CodingErrorAction unmappableCharacterAction() { return unmappableCharacterAction; } + + private IllegalStateException illegalStateException() { + throw new IllegalStateException("State: " + state); + } } |