blob: 221cb32ecfb2da5be6972fcad9c7c8ca90eece9e [file] [log] [blame]
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package java.nio.charset;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.util.WeakHashMap;
/**
* Used to indicate the result of encoding/decoding. There are four types of
* results:
* <ol>
* <li>UNDERFLOW indicates that all input has been processed but more input is
* required. It is represented by the unique object
* <code>CoderResult.UNDERFLOW</code>.
* <li>OVERFLOW indicates an insufficient output buffer size. It is represented
* by the unique object <code>CoderResult.OVERFLOW</code>.
* <li>A malformed-input error indicates that an unrecognizable sequence of
* input units has been encountered. Get an instance of this type of result by
* calling <code>CoderResult.malformedForLength(int)</code> with the length of
* the malformed-input.
* <li>An unmappable-character error indicates that a sequence of input units
* can not be mapped to the output charset. Get an instance of this type of
* result by calling <code>CoderResult.unmappableForLength(int)</code> with
* the input sequence size indicating the identity of the unmappable character.
* </ol>
*/
public class CoderResult {
// indicating underflow error type
private static final int TYPE_UNDERFLOW = 1;
// indicating overflow error type
private static final int TYPE_OVERFLOW = 2;
// indicating malformed-input error type
private static final int TYPE_MALFORMED_INPUT = 3;
// indicating unmappable character error type
private static final int TYPE_UNMAPPABLE_CHAR = 4;
/**
* Result object indicating that there is insufficient data in the
* encoding/decoding buffer or that additional data is required.
*/
public static final CoderResult UNDERFLOW = new CoderResult(TYPE_UNDERFLOW,
0);
/**
* Result object used to indicate that the output buffer does not have
* enough space available to store the result of the encoding/decoding.
*/
public static final CoderResult OVERFLOW = new CoderResult(TYPE_OVERFLOW, 0);
/*
* Stores unique result objects for each malformed-input error of a certain
* length
*/
private static WeakHashMap<Integer, CoderResult> _malformedErrors = new WeakHashMap<Integer, CoderResult>();
/*
* Stores unique result objects for each unmappable-character error of a
* certain length
*/
private static WeakHashMap<Integer, CoderResult> _unmappableErrors = new WeakHashMap<Integer, CoderResult>();
// the type of this result
private final int type;
// the length of the erroneous input
private final int length;
/**
* Constructs a <code>CoderResult</code> object with its text description.
*
* @param type
* the type of this result
* @param length
* the length of the erroneous input
*/
private CoderResult(int type, int length) {
this.type = type;
this.length = length;
}
/**
* Gets a <code>CoderResult</code> object indicating a malformed-input
* error.
*
* @param length
* the length of the malformed-input.
* @return a <code>CoderResult</code> object indicating a malformed-input
* error.
* @throws IllegalArgumentException
* if <code>length</code> is non-positive.
*/
public static synchronized CoderResult malformedForLength(int length)
throws IllegalArgumentException {
if (length > 0) {
Integer key = Integer.valueOf(length);
synchronized (_malformedErrors) {
CoderResult r = _malformedErrors.get(key);
if (r == null) {
r = new CoderResult(TYPE_MALFORMED_INPUT, length);
_malformedErrors.put(key, r);
}
return r;
}
}
throw new IllegalArgumentException("Length must be greater than 0; was " + length);
}
/**
* Gets a <code>CoderResult</code> object indicating an unmappable
* character error.
*
* @param length
* the length of the input unit sequence denoting the unmappable
* character.
* @return a <code>CoderResult</code> object indicating an unmappable
* character error.
* @throws IllegalArgumentException
* if <code>length</code> is non-positive.
*/
public static synchronized CoderResult unmappableForLength(int length)
throws IllegalArgumentException {
if (length > 0) {
Integer key = Integer.valueOf(length);
synchronized (_unmappableErrors) {
CoderResult r = _unmappableErrors.get(key);
if (r == null) {
r = new CoderResult(TYPE_UNMAPPABLE_CHAR, length);
_unmappableErrors.put(key, r);
}
return r;
}
}
throw new IllegalArgumentException("Length must be greater than 0; was " + length);
}
/**
* Returns true if this result is an underflow condition.
*
* @return true if an underflow, otherwise false.
*/
public boolean isUnderflow() {
return this.type == TYPE_UNDERFLOW;
}
/**
* Returns true if this result represents a malformed-input error or an
* unmappable-character error.
*
* @return true if this is a malformed-input error or an
* unmappable-character error, otherwise false.
*/
public boolean isError() {
return this.type == TYPE_MALFORMED_INPUT
|| this.type == TYPE_UNMAPPABLE_CHAR;
}
/**
* Returns true if this result represents a malformed-input error.
*
* @return true if this is a malformed-input error, otherwise false.
*/
public boolean isMalformed() {
return this.type == TYPE_MALFORMED_INPUT;
}
/**
* Returns true if this result is an overflow condition.
*
* @return true if this is an overflow, otherwise false.
*/
public boolean isOverflow() {
return this.type == TYPE_OVERFLOW;
}
/**
* Returns true if this result represents an unmappable-character error.
*
* @return true if this is an unmappable-character error, otherwise false.
*/
public boolean isUnmappable() {
return this.type == TYPE_UNMAPPABLE_CHAR;
}
/**
* Gets the length of the erroneous input. The length is only meaningful to
* a malformed-input error or an unmappable character error.
*
* @return the length, as an integer, of this object's erroneous input.
* @throws UnsupportedOperationException
* if this result is an overflow or underflow.
*/
public int length() throws UnsupportedOperationException {
if (this.type == TYPE_MALFORMED_INPUT || this.type == TYPE_UNMAPPABLE_CHAR) {
return this.length;
}
throw new UnsupportedOperationException("length meaningless for " + toString());
}
/**
* Throws an exception corresponding to this coder result.
*
* @throws BufferUnderflowException
* in case this is an underflow.
* @throws BufferOverflowException
* in case this is an overflow.
* @throws UnmappableCharacterException
* in case this is an unmappable-character error.
* @throws MalformedInputException
* in case this is a malformed-input error.
* @throws CharacterCodingException
* the default exception.
*/
public void throwException() throws BufferUnderflowException,
BufferOverflowException, UnmappableCharacterException,
MalformedInputException, CharacterCodingException {
switch (this.type) {
case TYPE_UNDERFLOW:
throw new BufferUnderflowException();
case TYPE_OVERFLOW:
throw new BufferOverflowException();
case TYPE_UNMAPPABLE_CHAR:
throw new UnmappableCharacterException(this.length);
case TYPE_MALFORMED_INPUT:
throw new MalformedInputException(this.length);
default:
throw new CharacterCodingException();
}
}
/**
* Returns a text description of this result.
*
* @return a text description of this result.
*/
@Override
public String toString() {
String dsc = null;
switch (this.type) {
case TYPE_UNDERFLOW:
dsc = "UNDERFLOW error";
break;
case TYPE_OVERFLOW:
dsc = "OVERFLOW error";
break;
case TYPE_UNMAPPABLE_CHAR:
dsc = "Unmappable-character error with erroneous input length "
+ this.length;
break;
case TYPE_MALFORMED_INPUT:
dsc = "Malformed-input error with erroneous input length "
+ this.length;
break;
default:
dsc = "";
break;
}
return getClass().getName() + "[" + dsc + "]";
}
}