Home | History | Annotate | Download | only in charset
      1 /* Licensed to the Apache Software Foundation (ASF) under one or more
      2  * contributor license agreements.  See the NOTICE file distributed with
      3  * this work for additional information regarding copyright ownership.
      4  * The ASF licenses this file to You under the Apache License, Version 2.0
      5  * (the "License"); you may not use this file except in compliance with
      6  * the License.  You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package java.nio.charset;
     18 
     19 import java.nio.BufferOverflowException;
     20 import java.nio.BufferUnderflowException;
     21 import java.util.WeakHashMap;
     22 
     23 /**
     24  * Used to indicate the result of encoding/decoding. There are four types of
     25  * results:
     26  * <ol>
     27  * <li>UNDERFLOW indicates that all input has been processed but more input is
     28  * required. It is represented by the unique object
     29  * <code>CoderResult.UNDERFLOW</code>.
     30  * <li>OVERFLOW indicates an insufficient output buffer size. It is represented
     31  * by the unique object <code>CoderResult.OVERFLOW</code>.
     32  * <li>A malformed-input error indicates that an unrecognizable sequence of
     33  * input units has been encountered. Get an instance of this type of result by
     34  * calling <code>CoderResult.malformedForLength(int)</code> with the length of
     35  * the malformed-input.
     36  * <li>An unmappable-character error indicates that a sequence of input units
     37  * can not be mapped to the output charset. Get an instance of this type of
     38  * result by calling <code>CoderResult.unmappableForLength(int)</code> with
     39  * the input sequence size indicating the identity of the unmappable character.
     40  * </ol>
     41  */
     42 public class CoderResult {
     43 
     44     // indicating underflow error type
     45     private static final int TYPE_UNDERFLOW = 1;
     46 
     47     // indicating overflow error type
     48     private static final int TYPE_OVERFLOW = 2;
     49 
     50     // indicating malformed-input error type
     51     private static final int TYPE_MALFORMED_INPUT = 3;
     52 
     53     // indicating unmappable character error type
     54     private static final int TYPE_UNMAPPABLE_CHAR = 4;
     55 
     56     /**
     57      * Result object indicating that there is insufficient data in the
     58      * encoding/decoding buffer or that additional data is required.
     59      */
     60     public static final CoderResult UNDERFLOW = new CoderResult(TYPE_UNDERFLOW,
     61             0);
     62 
     63     /**
     64      * Result object used to indicate that the output buffer does not have
     65      * enough space available to store the result of the encoding/decoding.
     66      */
     67     public static final CoderResult OVERFLOW = new CoderResult(TYPE_OVERFLOW, 0);
     68 
     69     /*
     70      * Stores unique result objects for each malformed-input error of a certain
     71      * length
     72      */
     73     private static WeakHashMap<Integer, CoderResult> _malformedErrors = new WeakHashMap<Integer, CoderResult>();
     74 
     75     /*
     76      * Stores unique result objects for each unmappable-character error of a
     77      * certain length
     78      */
     79     private static WeakHashMap<Integer, CoderResult> _unmappableErrors = new WeakHashMap<Integer, CoderResult>();
     80 
     81     // the type of this result
     82     private final int type;
     83 
     84     // the length of the erroneous input
     85     private final int length;
     86 
     87     /**
     88      * Constructs a <code>CoderResult</code> object with its text description.
     89      *
     90      * @param type
     91      *            the type of this result
     92      * @param length
     93      *            the length of the erroneous input
     94      */
     95     private CoderResult(int type, int length) {
     96         this.type = type;
     97         this.length = length;
     98     }
     99 
    100     /**
    101      * Gets a <code>CoderResult</code> object indicating a malformed-input
    102      * error.
    103      *
    104      * @param length
    105      *            the length of the malformed-input.
    106      * @return a <code>CoderResult</code> object indicating a malformed-input
    107      *         error.
    108      * @throws IllegalArgumentException
    109      *             if <code>length</code> is non-positive.
    110      */
    111     public static synchronized CoderResult malformedForLength(int length)
    112             throws IllegalArgumentException {
    113         if (length > 0) {
    114             Integer key = Integer.valueOf(length);
    115             synchronized (_malformedErrors) {
    116                 CoderResult r = _malformedErrors.get(key);
    117                 if (r == null) {
    118                     r = new CoderResult(TYPE_MALFORMED_INPUT, length);
    119                     _malformedErrors.put(key, r);
    120                 }
    121                 return r;
    122             }
    123         }
    124         throw new IllegalArgumentException("length <= 0: " + length);
    125     }
    126 
    127     /**
    128      * Gets a <code>CoderResult</code> object indicating an unmappable
    129      * character error.
    130      *
    131      * @param length
    132      *            the length of the input unit sequence denoting the unmappable
    133      *            character.
    134      * @return a <code>CoderResult</code> object indicating an unmappable
    135      *         character error.
    136      * @throws IllegalArgumentException
    137      *             if <code>length</code> is non-positive.
    138      */
    139     public static synchronized CoderResult unmappableForLength(int length)
    140             throws IllegalArgumentException {
    141         if (length > 0) {
    142             Integer key = Integer.valueOf(length);
    143             synchronized (_unmappableErrors) {
    144                 CoderResult r = _unmappableErrors.get(key);
    145                 if (r == null) {
    146                     r = new CoderResult(TYPE_UNMAPPABLE_CHAR, length);
    147                     _unmappableErrors.put(key, r);
    148                 }
    149                 return r;
    150             }
    151         }
    152         throw new IllegalArgumentException("length <= 0: " + length);
    153     }
    154 
    155     /**
    156      * Returns true if this result is an underflow condition.
    157      */
    158     public boolean isUnderflow() {
    159         return this.type == TYPE_UNDERFLOW;
    160     }
    161 
    162     /**
    163      * Returns true if this result represents a malformed-input error or an
    164      * unmappable-character error.
    165      */
    166     public boolean isError() {
    167         return this.type == TYPE_MALFORMED_INPUT || this.type == TYPE_UNMAPPABLE_CHAR;
    168     }
    169 
    170     /**
    171      * Returns true if this result represents a malformed-input error.
    172      */
    173     public boolean isMalformed() {
    174         return this.type == TYPE_MALFORMED_INPUT;
    175     }
    176 
    177     /**
    178      * Returns true if this result is an overflow condition.
    179      */
    180     public boolean isOverflow() {
    181         return this.type == TYPE_OVERFLOW;
    182     }
    183 
    184     /**
    185      * Returns true if this result represents an unmappable-character error.
    186      */
    187     public boolean isUnmappable() {
    188         return this.type == TYPE_UNMAPPABLE_CHAR;
    189     }
    190 
    191     /**
    192      * Returns the length of the erroneous input. The length is only meaningful for
    193      * a malformed-input error or an unmappable character error.
    194      *
    195      * @throws UnsupportedOperationException
    196      *             if this result is an overflow or underflow.
    197      */
    198     public int length() throws UnsupportedOperationException {
    199         if (this.type == TYPE_MALFORMED_INPUT || this.type == TYPE_UNMAPPABLE_CHAR) {
    200             return this.length;
    201         }
    202         throw new UnsupportedOperationException("length meaningless for " + toString());
    203     }
    204 
    205     /**
    206      * Throws an exception corresponding to this coder result.
    207      *
    208      * @throws BufferUnderflowException
    209      *             in case this is an underflow.
    210      * @throws BufferOverflowException
    211      *             in case this is an overflow.
    212      * @throws UnmappableCharacterException
    213      *             in case this is an unmappable-character error.
    214      * @throws MalformedInputException
    215      *             in case this is a malformed-input error.
    216      * @throws CharacterCodingException
    217      *             the default exception.
    218      */
    219     public void throwException() throws BufferUnderflowException,
    220             BufferOverflowException, UnmappableCharacterException,
    221             MalformedInputException, CharacterCodingException {
    222         switch (this.type) {
    223             case TYPE_UNDERFLOW:
    224                 throw new BufferUnderflowException();
    225             case TYPE_OVERFLOW:
    226                 throw new BufferOverflowException();
    227             case TYPE_UNMAPPABLE_CHAR:
    228                 throw new UnmappableCharacterException(this.length);
    229             case TYPE_MALFORMED_INPUT:
    230                 throw new MalformedInputException(this.length);
    231             default:
    232                 throw new CharacterCodingException();
    233         }
    234     }
    235 
    236     /**
    237      * Returns a text description of this result.
    238      *
    239      * @return a text description of this result.
    240      */
    241     @Override
    242     public String toString() {
    243         String dsc = null;
    244         switch (this.type) {
    245             case TYPE_UNDERFLOW:
    246                 dsc = "UNDERFLOW error";
    247                 break;
    248             case TYPE_OVERFLOW:
    249                 dsc = "OVERFLOW error";
    250                 break;
    251             case TYPE_UNMAPPABLE_CHAR:
    252                 dsc = "Unmappable-character error with erroneous input length "
    253                         + this.length;
    254                 break;
    255             case TYPE_MALFORMED_INPUT:
    256                 dsc = "Malformed-input error with erroneous input length "
    257                         + this.length;
    258                 break;
    259             default:
    260                 dsc = "";
    261                 break;
    262         }
    263         return getClass().getName() + "[" + dsc + "]";
    264     }
    265 }
    266