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 super(); 97 this.type = type; 98 this.length = length; 99 } 100 101 /** 102 * Gets a <code>CoderResult</code> object indicating a malformed-input 103 * error. 104 * 105 * @param length 106 * the length of the malformed-input. 107 * @return a <code>CoderResult</code> object indicating a malformed-input 108 * error. 109 * @throws IllegalArgumentException 110 * if <code>length</code> is non-positive. 111 */ 112 public static synchronized CoderResult malformedForLength(int length) 113 throws IllegalArgumentException { 114 if (length > 0) { 115 Integer key = Integer.valueOf(length); 116 synchronized (_malformedErrors) { 117 CoderResult r = _malformedErrors.get(key); 118 if (null == r) { 119 r = new CoderResult(TYPE_MALFORMED_INPUT, length); 120 _malformedErrors.put(key, r); 121 } 122 return r; 123 } 124 } 125 throw new IllegalArgumentException("Length must be greater than 0; was " + length); 126 } 127 128 /** 129 * Gets a <code>CoderResult</code> object indicating an unmappable 130 * character error. 131 * 132 * @param length 133 * the length of the input unit sequence denoting the unmappable 134 * character. 135 * @return a <code>CoderResult</code> object indicating an unmappable 136 * character error. 137 * @throws IllegalArgumentException 138 * if <code>length</code> is non-positive. 139 */ 140 public static synchronized CoderResult unmappableForLength(int length) 141 throws IllegalArgumentException { 142 if (length > 0) { 143 Integer key = Integer.valueOf(length); 144 synchronized (_unmappableErrors) { 145 CoderResult r = _unmappableErrors.get(key); 146 if (null == r) { 147 r = new CoderResult(TYPE_UNMAPPABLE_CHAR, length); 148 _unmappableErrors.put(key, r); 149 } 150 return r; 151 } 152 } 153 throw new IllegalArgumentException("Length must be greater than 0; was " + length); 154 } 155 156 /** 157 * Returns true if this result is an underflow condition. 158 * 159 * @return true if an underflow, otherwise false. 160 */ 161 public boolean isUnderflow() { 162 return this.type == TYPE_UNDERFLOW; 163 } 164 165 /** 166 * Returns true if this result represents a malformed-input error or an 167 * unmappable-character error. 168 * 169 * @return true if this is a malformed-input error or an 170 * unmappable-character error, otherwise false. 171 */ 172 public boolean isError() { 173 return this.type == TYPE_MALFORMED_INPUT 174 || this.type == TYPE_UNMAPPABLE_CHAR; 175 } 176 177 /** 178 * Returns true if this result represents a malformed-input error. 179 * 180 * @return true if this is a malformed-input error, otherwise false. 181 */ 182 public boolean isMalformed() { 183 return this.type == TYPE_MALFORMED_INPUT; 184 } 185 186 /** 187 * Returns true if this result is an overflow condition. 188 * 189 * @return true if this is an overflow, otherwise false. 190 */ 191 public boolean isOverflow() { 192 return this.type == TYPE_OVERFLOW; 193 } 194 195 /** 196 * Returns true if this result represents an unmappable-character error. 197 * 198 * @return true if this is an unmappable-character error, otherwise false. 199 */ 200 public boolean isUnmappable() { 201 return this.type == TYPE_UNMAPPABLE_CHAR; 202 } 203 204 /** 205 * Gets the length of the erroneous input. The length is only meaningful to 206 * a malformed-input error or an unmappable character error. 207 * 208 * @return the length, as an integer, of this object's erroneous input. 209 * @throws UnsupportedOperationException 210 * if this result is an overflow or underflow. 211 */ 212 public int length() throws UnsupportedOperationException { 213 if (this.type == TYPE_MALFORMED_INPUT || this.type == TYPE_UNMAPPABLE_CHAR) { 214 return this.length; 215 } 216 throw new UnsupportedOperationException("length meaningless for " + toString()); 217 } 218 219 /** 220 * Throws an exception corresponding to this coder result. 221 * 222 * @throws BufferUnderflowException 223 * in case this is an underflow. 224 * @throws BufferOverflowException 225 * in case this is an overflow. 226 * @throws UnmappableCharacterException 227 * in case this is an unmappable-character error. 228 * @throws MalformedInputException 229 * in case this is a malformed-input error. 230 * @throws CharacterCodingException 231 * the default exception. 232 */ 233 public void throwException() throws BufferUnderflowException, 234 BufferOverflowException, UnmappableCharacterException, 235 MalformedInputException, CharacterCodingException { 236 switch (this.type) { 237 case TYPE_UNDERFLOW: 238 throw new BufferUnderflowException(); 239 case TYPE_OVERFLOW: 240 throw new BufferOverflowException(); 241 case TYPE_UNMAPPABLE_CHAR: 242 throw new UnmappableCharacterException(this.length); 243 case TYPE_MALFORMED_INPUT: 244 throw new MalformedInputException(this.length); 245 default: 246 throw new CharacterCodingException(); 247 } 248 } 249 250 /** 251 * Returns a text description of this result. 252 * 253 * @return a text description of this result. 254 */ 255 @Override 256 public String toString() { 257 String dsc = null; 258 switch (this.type) { 259 case TYPE_UNDERFLOW: 260 dsc = "UNDERFLOW error"; 261 break; 262 case TYPE_OVERFLOW: 263 dsc = "OVERFLOW error"; 264 break; 265 case TYPE_UNMAPPABLE_CHAR: 266 dsc = "Unmappable-character error with erroneous input length " 267 + this.length; 268 break; 269 case TYPE_MALFORMED_INPUT: 270 dsc = "Malformed-input error with erroneous input length " 271 + this.length; 272 break; 273 default: 274 dsc = ""; 275 break; 276 } 277 return getClass().getName() + "[" + dsc + "]"; 278 } 279 } 280