CharsetDecoder.java [plain text]
package java.nio.charset;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
public abstract class CharsetDecoder
{
private static final int STATE_RESET = 0;
private static final int STATE_CODING = 1;
private static final int STATE_END = 2;
private static final int STATE_FLUSHED = 3;
private static final String DEFAULT_REPLACEMENT = "\uFFFD";
private final Charset charset;
private final float averageCharsPerByte;
private final float maxCharsPerByte;
private String replacement;
private int state = STATE_RESET;
private CodingErrorAction malformedInputAction
= CodingErrorAction.REPORT;
private CodingErrorAction unmappableCharacterAction
= CodingErrorAction.REPORT;
private CharsetDecoder (Charset cs, float averageCharsPerByte,
float maxCharsPerByte, String replacement)
{
if (averageCharsPerByte <= 0.0f)
throw new IllegalArgumentException ("Non-positive averageCharsPerByte");
if (maxCharsPerByte <= 0.0f)
throw new IllegalArgumentException ("Non-positive maxCharsPerByte");
this.charset = cs;
this.averageCharsPerByte
= averageCharsPerByte;
this.maxCharsPerByte
= maxCharsPerByte;
this.replacement = replacement;
implReplaceWith (replacement);
}
protected CharsetDecoder (Charset cs, float averageCharsPerByte,
float maxCharsPerByte)
{
this (cs, averageCharsPerByte, maxCharsPerByte, DEFAULT_REPLACEMENT);
}
public final float averageCharsPerByte ()
{
return averageCharsPerByte;
}
public final Charset charset ()
{
return charset;
}
public final CharBuffer decode (ByteBuffer in)
throws CharacterCodingException
{
if (state != STATE_RESET)
throw new IllegalStateException ();
int remaining = in.remaining ();
int n = (int) (remaining * maxCharsPerByte ());
CharBuffer out = CharBuffer.allocate (n);
if (remaining == 0)
{
state = STATE_FLUSHED;
return out;
}
CoderResult cr = decode (in, out, true);
if (cr.isError ())
cr.throwException ();
cr = flush (out);
if (cr.isError ())
cr.throwException ();
reset();
out.flip ();
return out;
}
public final CoderResult decode (ByteBuffer in, CharBuffer out,
boolean endOfInput)
{
int newState = endOfInput ? STATE_END : STATE_CODING;
if (state != STATE_RESET && state != STATE_CODING
&& !(endOfInput && state == STATE_END))
throw new IllegalStateException ();
state = newState;
for (;;)
{
CoderResult cr;
try
{
cr = decodeLoop (in, out);
}
catch (RuntimeException e)
{
throw new CoderMalfunctionError (e);
}
if (cr.isOverflow ())
return cr;
if (cr.isUnderflow ())
{
if (endOfInput && in.hasRemaining ())
cr = CoderResult.malformedForLength (in.remaining ());
else
return cr;
}
CodingErrorAction action = cr.isMalformed ()
? malformedInputAction
: unmappableCharacterAction;
if (action == CodingErrorAction.REPORT)
return cr;
if (action == CodingErrorAction.REPLACE)
{
if (out.remaining () < replacement.length ())
return CoderResult.OVERFLOW;
out.put (replacement);
}
in.position (in.position () + cr.length ());
}
}
protected abstract CoderResult decodeLoop (ByteBuffer in, CharBuffer out);
public Charset detectedCharset ()
{
throw new UnsupportedOperationException ();
}
public final CoderResult flush (CharBuffer out)
{
if (state != STATE_RESET && state != STATE_END)
throw new IllegalStateException ();
state = STATE_FLUSHED;
return implFlush (out);
}
protected CoderResult implFlush (CharBuffer out)
{
return CoderResult.UNDERFLOW;
}
public final CharsetDecoder onMalformedInput (CodingErrorAction newAction)
{
if (newAction == null)
throw new IllegalArgumentException ("Null action");
malformedInputAction = newAction;
implOnMalformedInput (newAction);
return this;
}
protected void implOnMalformedInput (CodingErrorAction newAction)
{
}
protected void implOnUnmappableCharacter (CodingErrorAction newAction)
{
}
protected void implReplaceWith (String newReplacement)
{
}
protected void implReset ()
{
}
public boolean isAutoDetecting ()
{
return false;
}
public boolean isCharsetDetected ()
{
throw new UnsupportedOperationException ();
}
public CodingErrorAction malformedInputAction ()
{
return malformedInputAction;
}
public final float maxCharsPerByte ()
{
return maxCharsPerByte;
}
public final CharsetDecoder onUnmappableCharacter
(CodingErrorAction newAction)
{
if (newAction == null)
throw new IllegalArgumentException ("Null action");
unmappableCharacterAction = newAction;
implOnUnmappableCharacter (newAction);
return this;
}
public final String replacement ()
{
return replacement;
}
public final CharsetDecoder replaceWith (String newReplacement)
{
if (newReplacement == null)
throw new IllegalArgumentException ("Null replacement");
if (newReplacement.length () == 0)
throw new IllegalArgumentException ("Empty replacement");
this.replacement = newReplacement;
implReplaceWith (newReplacement);
return this;
}
public final CharsetDecoder reset ()
{
state = STATE_RESET;
implReset ();
return this;
}
public CodingErrorAction unmappableCharacterAction ()
{
return unmappableCharacterAction;
}
}