1:
37:
38: package ;
39:
40: import ;
41: import ;
42:
43:
47: public 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:
105:
106:
107:
108:
109: if (state != STATE_RESET)
110: throw new IllegalStateException ();
111:
112:
113:
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: reset();
133: out.flip ();
134:
135:
136: char[] resized = new char[out.remaining()];
137: out.get(resized);
138: return CharBuffer.wrap(resized);
139: }
140:
141: public final CoderResult decode (ByteBuffer in, CharBuffer out,
142: boolean endOfInput)
143: {
144: int newState = endOfInput ? STATE_END : STATE_CODING;
145:
146:
147:
148:
149:
150: if (state != STATE_RESET && state != STATE_CODING
151: && !(endOfInput && state == STATE_END))
152: throw new IllegalStateException ();
153: state = newState;
154:
155: for (;;)
156: {
157: CoderResult cr;
158: try
159: {
160: cr = decodeLoop (in, out);
161: }
162: catch (RuntimeException e)
163: {
164: throw new CoderMalfunctionError (e);
165: }
166:
167: if (cr.isOverflow ())
168: return cr;
169:
170: if (cr.isUnderflow ())
171: {
172: if (endOfInput && in.hasRemaining ())
173: cr = CoderResult.malformedForLength (in.remaining ());
174: else
175: return cr;
176: }
177:
178: CodingErrorAction action = cr.isMalformed ()
179: ? malformedInputAction
180: : unmappableCharacterAction;
181:
182: if (action == CodingErrorAction.REPORT)
183: return cr;
184:
185: if (action == CodingErrorAction.REPLACE)
186: {
187: if (out.remaining () < replacement.length ())
188: return CoderResult.OVERFLOW;
189: out.put (replacement);
190: }
191:
192: in.position (in.position () + cr.length ());
193: }
194: }
195:
196: protected abstract CoderResult decodeLoop (ByteBuffer in, CharBuffer out);
197:
198: public Charset detectedCharset ()
199: {
200: throw new UnsupportedOperationException ();
201: }
202:
203: public final CoderResult flush (CharBuffer out)
204: {
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215: if (state != STATE_RESET && state != STATE_END)
216: throw new IllegalStateException ();
217:
218: state = STATE_FLUSHED;
219: return implFlush (out);
220: }
221:
222: protected CoderResult implFlush (CharBuffer out)
223: {
224: return CoderResult.UNDERFLOW;
225: }
226:
227: public final CharsetDecoder onMalformedInput (CodingErrorAction newAction)
228: {
229: if (newAction == null)
230: throw new IllegalArgumentException ("Null action");
231:
232: malformedInputAction = newAction;
233: implOnMalformedInput (newAction);
234: return this;
235: }
236:
237: protected void implOnMalformedInput (CodingErrorAction newAction)
238: {
239:
240: }
241:
242: protected void implOnUnmappableCharacter (CodingErrorAction newAction)
243: {
244:
245: }
246:
247: protected void implReplaceWith (String newReplacement)
248: {
249:
250: }
251:
252: protected void implReset ()
253: {
254:
255: }
256:
257: public boolean isAutoDetecting ()
258: {
259: return false;
260: }
261:
262: public boolean isCharsetDetected ()
263: {
264: throw new UnsupportedOperationException ();
265: }
266:
267: public CodingErrorAction malformedInputAction ()
268: {
269: return malformedInputAction;
270: }
271:
272: public final float maxCharsPerByte ()
273: {
274: return maxCharsPerByte;
275: }
276:
277: public final CharsetDecoder onUnmappableCharacter
278: (CodingErrorAction newAction)
279: {
280: if (newAction == null)
281: throw new IllegalArgumentException ("Null action");
282:
283: unmappableCharacterAction = newAction;
284: implOnUnmappableCharacter (newAction);
285: return this;
286: }
287:
288: public final String replacement ()
289: {
290: return replacement;
291: }
292:
293: public final CharsetDecoder replaceWith (String newReplacement)
294: {
295: if (newReplacement == null)
296: throw new IllegalArgumentException ("Null replacement");
297: if (newReplacement.length () == 0)
298: throw new IllegalArgumentException ("Empty replacement");
299:
300:
301: this.replacement = newReplacement;
302: implReplaceWith (newReplacement);
303: return this;
304: }
305:
306: public final CharsetDecoder reset ()
307: {
308: state = STATE_RESET;
309: implReset ();
310: return this;
311: }
312:
313: public CodingErrorAction unmappableCharacterAction ()
314: {
315: return unmappableCharacterAction;
316: }
317: }