source: trunk/gcc/libjava/java/nio/charset/CharsetDecoder.java

Last change on this file was 1389, checked in by bird, 21 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 9.1 KB
Line 
1/* CharsetDecoder.java --
2 Copyright (C) 2002 Free Software Foundation, Inc.
3
4This file is part of GNU Classpath.
5
6GNU Classpath is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Classpath is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Classpath; see the file COPYING. If not, write to the
18Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
1902111-1307 USA.
20
21Linking this library statically or dynamically with other modules is
22making a combined work based on this library. Thus, the terms and
23conditions of the GNU General Public License cover the whole
24combination.
25
26As a special exception, the copyright holders of this library give you
27permission to link this library with independent modules to produce an
28executable, regardless of the license terms of these independent
29modules, and to copy and distribute the resulting executable under
30terms of your choice, provided that you also meet, for each linked
31independent module, the terms and conditions of the license of that
32module. An independent module is a module which is not derived from
33or based on this library. If you modify this library, you may extend
34this exception to your version of the library, but you are not
35obligated to do so. If you do not wish to do so, delete this
36exception statement from your version. */
37
38package java.nio.charset;
39
40import java.nio.ByteBuffer;
41import java.nio.CharBuffer;
42
43/**
44 * @author Jesse Rosenstock
45 * @since 1.4
46 */
47public abstract class CharsetDecoder
48{
49 private static final int STATE_RESET = 0;
50 private static final int STATE_CODING = 1;
51 private static final int STATE_END = 2;
52 private static final int STATE_FLUSHED = 3;
53
54 private static final String DEFAULT_REPLACEMENT = "\uFFFD";
55
56 private final Charset charset;
57 private final float averageCharsPerByte;
58 private final float maxCharsPerByte;
59 private String replacement;
60
61 private int state = STATE_RESET;
62
63 private CodingErrorAction malformedInputAction
64 = CodingErrorAction.REPORT;
65 private CodingErrorAction unmappableCharacterAction
66 = CodingErrorAction.REPORT;
67
68 private CharsetDecoder (Charset cs, float averageCharsPerByte,
69 float maxCharsPerByte, String replacement)
70 {
71 if (averageCharsPerByte <= 0.0f)
72 throw new IllegalArgumentException ("Non-positive averageCharsPerByte");
73 if (maxCharsPerByte <= 0.0f)
74 throw new IllegalArgumentException ("Non-positive maxCharsPerByte");
75
76 this.charset = cs;
77 this.averageCharsPerByte
78 = averageCharsPerByte;
79 this.maxCharsPerByte
80 = maxCharsPerByte;
81 this.replacement = replacement;
82 implReplaceWith (replacement);
83 }
84
85 protected CharsetDecoder (Charset cs, float averageCharsPerByte,
86 float maxCharsPerByte)
87 {
88 this (cs, averageCharsPerByte, maxCharsPerByte, DEFAULT_REPLACEMENT);
89 }
90
91 public final float averageCharsPerByte ()
92 {
93 return averageCharsPerByte;
94 }
95
96 public final Charset charset ()
97 {
98 return charset;
99 }
100
101 public final CharBuffer decode (ByteBuffer in)
102 throws CharacterCodingException
103 {
104 // XXX: Sun's Javadoc seems to contradict itself saying an
105 // IllegalStateException is thrown "if a decoding operation is already
106 // in progress" and also that "it resets this Decoder".
107 // Should we check to see that the state is reset, or should we
108 // call reset()?
109 if (state != STATE_RESET)
110 throw new IllegalStateException ();
111
112 // REVIEW: Using max instead of average may allocate a very large
113 // buffer. Maybe we should do something more efficient?
114 int remaining = in.remaining ();
115 int n = (int) (remaining * maxCharsPerByte ());
116 CharBuffer out = CharBuffer.allocate (n);
117
118 if (remaining == 0)
119 {
120 state = STATE_FLUSHED;
121 return out;
122 }
123
124 CoderResult cr = decode (in, out, true);
125 if (cr.isError ())
126 cr.throwException ();
127
128 cr = flush (out);
129 if (cr.isError ())
130 cr.throwException ();
131
132 out.flip ();
133 return out;
134 }
135
136 public final CoderResult decode (ByteBuffer in, CharBuffer out,
137 boolean endOfInput)
138 {
139 int newState = endOfInput ? STATE_END : STATE_CODING;
140 // XXX: Need to check for "previous step was an invocation [not] of
141 // this method with a value of true for the endOfInput parameter but
142 // a return value indicating an incomplete decoding operation"
143 // XXX: We will not check the previous return value, just
144 // that the previous call passed true for endOfInput
145 if (state != STATE_RESET && state != STATE_CODING
146 && !(endOfInput && state == STATE_END))
147 throw new IllegalStateException ();
148 state = newState;
149
150 for (;;)
151 {
152 CoderResult cr;
153 try
154 {
155 cr = decodeLoop (in, out);
156 }
157 catch (RuntimeException e)
158 {
159 throw new CoderMalfunctionError (e);
160 }
161
162 if (cr.isOverflow ())
163 return cr;
164
165 if (cr.isUnderflow ())
166 {
167 if (endOfInput && in.hasRemaining ())
168 cr = CoderResult.malformedForLength (in.remaining ());
169 else
170 return cr;
171 }
172
173 CodingErrorAction action = cr.isMalformed ()
174 ? malformedInputAction
175 : unmappableCharacterAction;
176
177 if (action == CodingErrorAction.REPORT)
178 return cr;
179
180 if (action == CodingErrorAction.REPLACE)
181 {
182 if (out.remaining () < replacement.length ())
183 return CoderResult.OVERFLOW;
184 out.put (replacement);
185 }
186
187 in.position (in.position () + cr.length ());
188 }
189 }
190
191 protected abstract CoderResult decodeLoop (ByteBuffer in, CharBuffer out);
192
193 public Charset detectedCharset ()
194 {
195 throw new UnsupportedOperationException ();
196 }
197
198 public final CoderResult flush (CharBuffer out)
199 {
200 // It seems weird that you can flush after reset, but Sun's javadoc
201 // says an IllegalStateException is thrown "If the previous step of the
202 // current decoding operation was an invocation neither of the reset
203 // method nor ... of the three-argument decode method with a value of
204 // true for the endOfInput parameter."
205 // Further note that flush() only requires that there not be
206 // an IllegalStateException if the previous step was a call to
207 // decode with true as the last argument. It does not require
208 // that the call succeeded. decode() does require that it succeeded.
209 // XXX: test this to see if reality matches javadoc
210 if (state != STATE_RESET && state != STATE_END)
211 throw new IllegalStateException ();
212
213 state = STATE_FLUSHED;
214 return implFlush (out);
215 }
216
217 protected CoderResult implFlush (CharBuffer out)
218 {
219 return CoderResult.UNDERFLOW;
220 }
221
222 public final CharsetDecoder onMalformedInput (CodingErrorAction newAction)
223 {
224 if (newAction == null)
225 throw new IllegalArgumentException ("Null action");
226
227 malformedInputAction = newAction;
228 implOnMalformedInput (newAction);
229 return this;
230 }
231
232 protected void implOnMalformedInput (CodingErrorAction newAction)
233 {
234 // default implementation does nothing
235 }
236
237 protected void implOnUnmappableCharacter (CodingErrorAction newAction)
238 {
239 // default implementation does nothing
240 }
241
242 protected void implReplaceWith (String newReplacement)
243 {
244 // default implementation does nothing
245 }
246
247 protected void implReset ()
248 {
249 // default implementation does nothing
250 }
251
252 public boolean isAutoDetecting ()
253 {
254 return false;
255 }
256
257 public boolean isCharsetDetected ()
258 {
259 throw new UnsupportedOperationException ();
260 }
261
262 public CodingErrorAction malformedInputAction ()
263 {
264 return malformedInputAction;
265 }
266
267 public final float maxCharsPerByte ()
268 {
269 return maxCharsPerByte;
270 }
271
272 public final CharsetDecoder onUnmappableCharacter
273 (CodingErrorAction newAction)
274 {
275 if (newAction == null)
276 throw new IllegalArgumentException ("Null action");
277
278 unmappableCharacterAction = newAction;
279 implOnUnmappableCharacter (newAction);
280 return this;
281 }
282
283 public final String replacement ()
284 {
285 return replacement;
286 }
287
288 public final CharsetDecoder replaceWith (String newReplacement)
289 {
290 if (newReplacement == null)
291 throw new IllegalArgumentException ("Null replacement");
292 if (newReplacement.length () == 0)
293 throw new IllegalArgumentException ("Empty replacement");
294 // XXX: what about maxCharsPerByte?
295
296 this.replacement = newReplacement;
297 implReplaceWith (newReplacement);
298 return this;
299 }
300
301 public final CharsetDecoder reset ()
302 {
303 state = STATE_RESET;
304 implReset ();
305 return this;
306 }
307
308 public CodingErrorAction unmappableCharacterAction ()
309 {
310 return unmappableCharacterAction;
311 }
312}
Note: See TracBrowser for help on using the repository browser.