1 /*
2 * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.nio.charset;
27
28 import java.nio.BufferOverflowException;
29 import java.nio.BufferUnderflowException;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.Map;
32
33 /**
34 * A description of the result state of a coder.
35 *
36 * <p> A charset coder, that is, either a decoder or an encoder, consumes bytes
37 * (or characters) from an input buffer, translates them, and writes the
38 * resulting characters (or bytes) to an output buffer. A coding process
39 * terminates for one of four categories of reasons, which are described by
40 * instances of this class:
41 *
42 * <ul>
43 *
44 * <li><p> <i>Underflow</i> is reported when there is no more input to be
45 * processed, or there is insufficient input and additional input is
46 * required. This condition is represented by the unique result object
47 * {@link #UNDERFLOW}, whose {@link #isUnderflow() isUnderflow} method
48 * returns {@code true}. </p></li>
49 *
50 * <li><p> <i>Overflow</i> is reported when there is insufficient room
51 * remaining in the output buffer. This condition is represented by the
52 * unique result object {@link #OVERFLOW}, whose {@link #isOverflow()
53 * isOverflow} method returns {@code true}. </p></li>
54 *
55 * <li><p> A <i>malformed-input error</i> is reported when a sequence of
56 * input units is not well-formed. Such errors are described by instances of
57 * this class whose {@link #isMalformed() isMalformed} method returns
58 * {@code true} and whose {@link #length() length} method returns the length
59 * of the malformed sequence. There is one unique instance of this class for
60 * all malformed-input errors of a given length. </p></li>
61 *
62 * <li><p> An <i>unmappable-character error</i> is reported when a sequence
63 * of input units denotes a character that cannot be represented in the
64 * output charset. Such errors are described by instances of this class
65 * whose {@link #isUnmappable() isUnmappable} method returns {@code true} and
66 * whose {@link #length() length} method returns the length of the input
67 * sequence denoting the unmappable character. There is one unique instance
68 * of this class for all unmappable-character errors of a given length.
69 * </p></li>
70 *
71 * </ul>
72 *
73 * <p> For convenience, the {@link #isError() isError} method returns {@code true}
74 * for result objects that describe malformed-input and unmappable-character
75 * errors but {@code false} for those that describe underflow or overflow
76 * conditions. </p>
77 *
78 *
79 * @author Mark Reinhold
80 * @author JSR-51 Expert Group
81 * @since 1.4
82 */
83
84 public class CoderResult {
85
86 private static final int CR_UNDERFLOW = 0;
87 private static final int CR_OVERFLOW = 1;
88 private static final int CR_ERROR_MIN = 2;
89 private static final int CR_MALFORMED = 2;
90 private static final int CR_UNMAPPABLE = 3;
91
92 private static final String[] names
93 = { "UNDERFLOW", "OVERFLOW", "MALFORMED", "UNMAPPABLE" };
94
95 private final int type;
96 private final int length;
97
98 private CoderResult(int type, int length) {
99 this.type = type;
100 this.length = length;
101 }
102
103 /**
104 * Returns a string describing this coder result.
105 *
106 * @return A descriptive string
107 */
108 public String toString() {
109 String nm = names[type];
110 return isError() ? nm + "[" + length + "]" : nm;
111 }
112
113 /**
114 * Tells whether or not this object describes an underflow condition.
115 *
116 * @return {@code true} if, and only if, this object denotes underflow
117 */
118 public boolean isUnderflow() {
119 return (type == CR_UNDERFLOW);
120 }
121
122 /**
123 * Tells whether or not this object describes an overflow condition.
124 *
125 * @return {@code true} if, and only if, this object denotes overflow
126 */
127 public boolean isOverflow() {
128 return (type == CR_OVERFLOW);
129 }
130
131 /**
132 * Tells whether or not this object describes an error condition.
133 *
134 * @return {@code true} if, and only if, this object denotes either a
135 * malformed-input error or an unmappable-character error
136 */
137 public boolean isError() {
138 return (type >= CR_ERROR_MIN);
139 }
140
141 /**
142 * Tells whether or not this object describes a malformed-input error.
143 *
144 * @return {@code true} if, and only if, this object denotes a
145 * malformed-input error
146 */
147 public boolean isMalformed() {
148 return (type == CR_MALFORMED);
149 }
150
151 /**
152 * Tells whether or not this object describes an unmappable-character
153 * error.
154 *
155 * @return {@code true} if, and only if, this object denotes an
156 * unmappable-character error
157 */
158 public boolean isUnmappable() {
159 return (type == CR_UNMAPPABLE);
160 }
161
162 /**
163 * Returns the length of the erroneous input described by this
164 * object <i>(optional operation)</i>.
165 *
166 * @return The length of the erroneous input, a positive integer
167 *
168 * @throws UnsupportedOperationException
169 * If this object does not describe an error condition, that is,
170 * if the {@link #isError() isError} does not return {@code true}
171 */
172 public int length() {
173 if (!isError())
174 throw new UnsupportedOperationException();
175 return length;
176 }
177
178 /**
179 * Result object indicating underflow, meaning that either the input buffer
180 * has been completely consumed or, if the input buffer is not yet empty,
181 * that additional input is required.
182 */
183 public static final CoderResult UNDERFLOW
184 = new CoderResult(CR_UNDERFLOW, 0);
185
186 /**
187 * Result object indicating overflow, meaning that there is insufficient
188 * room in the output buffer.
189 */
190 public static final CoderResult OVERFLOW
191 = new CoderResult(CR_OVERFLOW, 0);
192
193 private static final class Cache {
194 static final Cache INSTANCE = new Cache();
195 private Cache() {}
196
197 final Map<Integer, CoderResult> unmappable = new ConcurrentHashMap<>();
198 final Map<Integer, CoderResult> malformed = new ConcurrentHashMap<>();
199 }
200
201 private static final CoderResult[] malformed4 = new CoderResult[] {
202 new CoderResult(CR_MALFORMED, 1),
203 new CoderResult(CR_MALFORMED, 2),
204 new CoderResult(CR_MALFORMED, 3),
205 new CoderResult(CR_MALFORMED, 4),
206 };
207
208 /**
209 * Static factory method that returns the unique object describing a
210 * malformed-input error of the given length.
211 *
212 * @param length
213 * The given length
214 *
215 * @return The requested coder-result object
216 */
217 public static CoderResult malformedForLength(int length) {
218 if (length <= 0)
219 throw new IllegalArgumentException("Non-positive length");
220 if (length <= 4)
221 return malformed4[length - 1];
222 return Cache.INSTANCE.malformed.computeIfAbsent(length,
223 n -> new CoderResult(CR_MALFORMED, n));
224 }
225
226 private static final CoderResult[] unmappable4 = new CoderResult[] {
227 new CoderResult(CR_UNMAPPABLE, 1),
228 new CoderResult(CR_UNMAPPABLE, 2),
229 new CoderResult(CR_UNMAPPABLE, 3),
230 new CoderResult(CR_UNMAPPABLE, 4),
231 };
232
233 /**
234 * Static factory method that returns the unique result object describing
235 * an unmappable-character error of the given length.
236 *
237 * @param length
238 * The given length
239 *
240 * @return The requested coder-result object
241 */
242 public static CoderResult unmappableForLength(int length) {
243 if (length <= 0)
244 throw new IllegalArgumentException("Non-positive length");
245 if (length <= 4)
246 return unmappable4[length - 1];
247 return Cache.INSTANCE.unmappable.computeIfAbsent(length,
248 n -> new CoderResult(CR_UNMAPPABLE, n));
249 }
250
251 /**
252 * Throws an exception appropriate to the result described by this object.
253 *
254 * @throws BufferUnderflowException
255 * If this object is {@link #UNDERFLOW}
256 *
257 * @throws BufferOverflowException
258 * If this object is {@link #OVERFLOW}
259 *
260 * @throws MalformedInputException
261 * If this object represents a malformed-input error; the
262 * exception's length value will be that of this object
263 *
264 * @throws UnmappableCharacterException
265 * If this object represents an unmappable-character error; the
266 * exceptions length value will be that of this object
267 */
268 public void throwException()
269 throws CharacterCodingException
270 {
271 switch (type) {
272 case CR_UNDERFLOW: throw new BufferUnderflowException();
273 case CR_OVERFLOW: throw new BufferOverflowException();
274 case CR_MALFORMED: throw new MalformedInputException(length);
275 case CR_UNMAPPABLE: throw new UnmappableCharacterException(length);
276 default:
277 assert false;
278 }
279 }
280
281 }
282