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 */ CoderResult(int type, int length)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 */ malformedForLength(int length)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 */ unmappableForLength(int length)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 */ isUnderflow()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 */ isError()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 */ isMalformed()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 */ isOverflow()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 */ isUnmappable()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 */ length()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 */ throwException()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 toString()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