KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > nio > charset > CharsetEncoder


1 /*
2  * @(#)Charset-X-Coder.java 1.42 05/03/03
3  *
4  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 // -- This file was mechanically generated: Do not edit! -- //
9

10 package java.nio.charset;
11
12 import java.nio.Buffer JavaDoc;
13 import java.nio.ByteBuffer JavaDoc;
14 import java.nio.CharBuffer JavaDoc;
15 import java.nio.BufferOverflowException JavaDoc;
16 import java.nio.BufferUnderflowException JavaDoc;
17 import java.lang.ref.WeakReference JavaDoc;
18 import java.nio.charset.CoderMalfunctionError JavaDoc; // javadoc
19

20
21 /**
22  * An engine that can transform a sequence of sixteen-bit Unicode characters into a sequence of
23  * bytes in a specific charset.
24  *
25  * <a name="steps">
26  *
27  * <p> The input character sequence is provided in a character buffer or a series
28  * of such buffers. The output byte sequence is written to a byte buffer
29  * or a series of such buffers. An encoder should always be used by making
30  * the following sequence of method invocations, hereinafter referred to as an
31  * <i>encoding operation</i>:
32  *
33  * <ol>
34  *
35  * <li><p> Reset the encoder via the {@link #reset reset} method, unless it
36  * has not been used before; </p></li>
37  *
38  * <li><p> Invoke the {@link #encode encode} method zero or more times, as
39  * long as additional input may be available, passing <tt>false</tt> for the
40  * <tt>endOfInput</tt> argument and filling the input buffer and flushing the
41  * output buffer between invocations; </p></li>
42  *
43  * <li><p> Invoke the {@link #encode encode} method one final time, passing
44  * <tt>true</tt> for the <tt>endOfInput</tt> argument; and then </p></li>
45  *
46  * <li><p> Invoke the {@link #flush flush} method so that the encoder can
47  * flush any internal state to the output buffer. </p></li>
48  *
49  * </ol>
50  *
51  * Each invocation of the {@link #encode encode} method will encode as many
52  * characters as possible from the input buffer, writing the resulting bytes
53  * to the output buffer. The {@link #encode encode} method returns when more
54  * input is required, when there is not enough room in the output buffer, or
55  * when an encoding error has occurred. In each case a {@link CoderResult}
56  * object is returned to describe the reason for termination. An invoker can
57  * examine this object and fill the input buffer, flush the output buffer, or
58  * attempt to recover from an encoding error, as appropriate, and try again.
59  *
60  * <a name="ce">
61  *
62  * <p> There are two general types of encoding errors. If the input character
63  * sequence is not a legal sixteen-bit Unicode sequence then the input is considered <i>malformed</i>. If
64  * the input character sequence is legal but cannot be mapped to a valid
65  * byte sequence in the given charset then an <i>unmappable character</i> has been encountered.
66  *
67  * <a name="cae">
68  *
69  * <p> How an encoding error is handled depends upon the action requested for
70  * that type of error, which is described by an instance of the {@link
71  * CodingErrorAction} class. The possible error actions are to {@link
72  * CodingErrorAction#IGNORE </code>ignore<code>} the erroneous input, {@link
73  * CodingErrorAction#REPORT </code>report<code>} the error to the invoker via
74  * the returned {@link CoderResult} object, or {@link CodingErrorAction#REPLACE
75  * </code>replace<code>} the erroneous input with the current value of the
76  * replacement byte array. The replacement
77  *
78
79  * is initially set to the encoder's default replacement, which often
80  * (but not always) has the initial value&nbsp;<tt>{</tt>&nbsp;<tt>(byte)'?'</tt>&nbsp;<tt>}</tt>;
81
82
83
84
85  *
86  * its value may be changed via the {@link #replaceWith(byte[])
87  * replaceWith} method.
88  *
89  * <p> The default action for malformed-input and unmappable-character errors
90  * is to {@link CodingErrorAction#REPORT </code>report<code>} them. The
91  * malformed-input error action may be changed via the {@link
92  * #onMalformedInput(CodingErrorAction) onMalformedInput} method; the
93  * unmappable-character action may be changed via the {@link
94  * #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter} method.
95  *
96  * <p> This class is designed to handle many of the details of the encoding
97  * process, including the implementation of error actions. An encoder for a
98  * specific charset, which is a concrete subclass of this class, need only
99  * implement the abstract {@link #encodeLoop encodeLoop} method, which
100  * encapsulates the basic encoding loop. A subclass that maintains internal
101  * state should, additionally, override the {@link #flush flush} and {@link
102  * #reset reset} methods.
103  *
104  * <p> Instances of this class are not safe for use by multiple concurrent
105  * threads. </p>
106  *
107  *
108  * @version 1.42, 05/03/03
109  * @author Mark Reinhold
110  * @author JSR-51 Expert Group
111  * @since 1.4
112  *
113  * @see ByteBuffer
114  * @see CharBuffer
115  * @see Charset
116  * @see CharsetDecoder
117  */

118
119 public abstract class CharsetEncoder {
120
121     private final Charset JavaDoc charset;
122     private final float averageBytesPerChar;
123     private final float maxBytesPerChar;
124
125     private byte[] replacement;
126     private CodingErrorAction JavaDoc malformedInputAction
127     = CodingErrorAction.REPORT;
128     private CodingErrorAction JavaDoc unmappableCharacterAction
129     = CodingErrorAction.REPORT;
130
131     // Internal states
132
//
133
private static final int ST_RESET = 0;
134     private static final int ST_CODING = 1;
135     private static final int ST_END = 2;
136     private static final int ST_FLUSHED = 3;
137
138     private int state = ST_RESET;
139
140     private static String JavaDoc stateNames[]
141     = { "RESET", "CODING", "CODING_END", "FLUSHED" };
142
143
144     /**
145      * Initializes a new encoder. The new encoder will have the given
146      * bytes-per-char and replacement values. </p>
147      *
148      * @param averageBytesPerChar
149      * A positive float value indicating the expected number of
150      * bytes that will be produced for each input character
151      *
152      * @param maxBytesPerChar
153      * A positive float value indicating the maximum number of
154      * bytes that will be produced for each input character
155      *
156      * @param replacement
157      * The initial replacement; must not be <tt>null</tt>, must have
158      * non-zero length, must not be longer than maxBytesPerChar,
159      * and must be {@link #isLegalReplacement </code>legal<code>}
160      *
161      * @throws IllegalArgumentException
162      * If the preconditions on the parameters do not hold
163      */

164     protected
165     CharsetEncoder(Charset JavaDoc cs,
166            float averageBytesPerChar,
167            float maxBytesPerChar,
168            byte[] replacement)
169     {
170     this.charset = cs;
171     if (averageBytesPerChar <= 0.0f)
172         throw new IllegalArgumentException JavaDoc("Non-positive "
173                            + "averageBytesPerChar");
174     if (maxBytesPerChar <= 0.0f)
175         throw new IllegalArgumentException JavaDoc("Non-positive "
176                            + "maxBytesPerChar");
177     if (!Charset.atBugLevel("1.4")) {
178         if (averageBytesPerChar > maxBytesPerChar)
179         throw new IllegalArgumentException JavaDoc("averageBytesPerChar"
180                            + " exceeds "
181                            + "maxBytesPerChar");
182     }
183     this.replacement = replacement;
184     this.averageBytesPerChar = averageBytesPerChar;
185     this.maxBytesPerChar = maxBytesPerChar;
186     replaceWith(replacement);
187     }
188
189     /**
190      * Initializes a new encoder. The new encoder will have the given
191      * bytes-per-char values and its replacement will be the
192      * byte array <tt>{</tt>&nbsp;<tt>(byte)'?'</tt>&nbsp;<tt>}</tt>. </p>
193      *
194      * @param averageBytesPerChar
195      * A positive float value indicating the expected number of
196      * bytes that will be produced for each input character
197      *
198      * @param maxBytesPerChar
199      * A positive float value indicating the maximum number of
200      * bytes that will be produced for each input character
201      *
202      * @throws IllegalArgumentException
203      * If the preconditions on the parameters do not hold
204      */

205     protected CharsetEncoder(Charset JavaDoc cs,
206                  float averageBytesPerChar,
207                  float maxBytesPerChar)
208     {
209     this(cs,
210          averageBytesPerChar, maxBytesPerChar,
211          new byte[] { (byte)'?' });
212     }
213
214     /**
215      * Returns the charset that created this encoder. </p>
216      *
217      * @return This encoder's charset
218      */

219     public final Charset JavaDoc charset() {
220     return charset;
221     }
222
223     /**
224      * Returns this encoder's replacement value. </p>
225      *
226      * @return This encoder's current replacement,
227      * which is never <tt>null</tt> and is never empty
228      */

229     public final byte[] replacement() {
230     return replacement;
231     }
232
233     /**
234      * Changes this encoder's replacement value.
235      *
236      * <p> This method invokes the {@link #implReplaceWith implReplaceWith}
237      * method, passing the new replacement, after checking that the new
238      * replacement is acceptable. </p>
239      *
240      * @param newReplacement
241      *
242
243
244
245
246
247      * The new replacement; must not be <tt>null</tt>, must have
248      * non-zero length, must not be longer than the value returned by
249      * the {@link #maxBytesPerChar maxBytesPerChar} method, and
250      * must be {@link #isLegalReplacement </code>legal<code>}
251
252      *
253      * @return This encoder
254      *
255      * @throws IllegalArgumentException
256      * If the preconditions on the parameter do not hold
257      */

258     public final CharsetEncoder JavaDoc replaceWith(byte[] newReplacement) {
259     if (newReplacement == null)
260         throw new IllegalArgumentException JavaDoc("Null replacement");
261     int len = newReplacement.length;
262     if (len == 0)
263         throw new IllegalArgumentException JavaDoc("Empty replacement");
264     if (len > maxBytesPerChar)
265         throw new IllegalArgumentException JavaDoc("Replacement too long");
266
267     if (!isLegalReplacement(newReplacement))
268         throw new IllegalArgumentException JavaDoc("Illegal replacement");
269
270     this.replacement = newReplacement;
271     implReplaceWith(newReplacement);
272     return this;
273     }
274
275     /**
276      * Reports a change to this encoder's replacement value.
277      *
278      * <p> The default implementation of this method does nothing. This method
279      * should be overridden by encoders that require notification of changes to
280      * the replacement. </p>
281      *
282      * @param newReplacement
283      */

284     protected void implReplaceWith(byte[] newReplacement) {
285     }
286
287
288
289     private WeakReference JavaDoc cachedDecoder = null;
290
291     /**
292      * Tells whether or not the given byte array is a legal replacement value
293      * for this encoder.
294      *
295      * <p> A replacement is legal if, and only if, it is a legal sequence of
296      * bytes in this encoder's charset; that is, it must be possible to decode
297      * the replacement into one or more sixteen-bit Unicode characters.
298      *
299      * <p> The default implementation of this method is not very efficient; it
300      * should generally be overridden to improve performance. </p>
301      *
302      * @param repl The byte array to be tested
303      *
304      * @return <tt>true</tt> if, and only if, the given byte array
305      * is a legal replacement value for this encoder
306      */

307     public boolean isLegalReplacement(byte[] repl) {
308     WeakReference JavaDoc wr = cachedDecoder;
309     CharsetDecoder JavaDoc dec = null;
310     if ((wr == null) || ((dec = (CharsetDecoder JavaDoc)wr.get()) == null)) {
311         dec = charset().newDecoder();
312         dec.onMalformedInput(CodingErrorAction.REPORT);
313         dec.onUnmappableCharacter(CodingErrorAction.REPORT);
314         cachedDecoder = new WeakReference JavaDoc(dec);
315     } else {
316         dec.reset();
317     }
318     ByteBuffer JavaDoc bb = ByteBuffer.wrap(repl);
319     // We need to perform double, not float, arithmetic; otherwise
320
// we lose low order bits when src is larger than 2**24.
321
CharBuffer JavaDoc cb = CharBuffer.allocate((int)(bb.remaining()
322                           * (double)dec.maxCharsPerByte()));
323     CoderResult JavaDoc cr = dec.decode(bb, cb, true);
324     return !cr.isError();
325     }
326
327
328
329     /**
330      * Returns this encoder's current action for malformed-input errors. </p>
331      *
332      * @return The current malformed-input action, which is never <tt>null</tt>
333      */

334     public CodingErrorAction JavaDoc malformedInputAction() {
335     return malformedInputAction;
336     }
337
338     /**
339      * Changes this encoder's action for malformed-input errors. </p>
340      *
341      * <p> This method invokes the {@link #implOnMalformedInput
342      * implOnMalformedInput} method, passing the new action. </p>
343      *
344      * @param newAction The new action; must not be <tt>null</tt>
345      *
346      * @return This encoder
347      *
348      * @throws IllegalArgumentException
349      * If the precondition on the parameter does not hold
350      */

351     public final CharsetEncoder JavaDoc onMalformedInput(CodingErrorAction JavaDoc newAction) {
352     if (newAction == null)
353         throw new IllegalArgumentException JavaDoc("Null action");
354     malformedInputAction = newAction;
355     implOnMalformedInput(newAction);
356     return this;
357     }
358
359     /**
360      * Reports a change to this encoder's malformed-input action.
361      *
362      * <p> The default implementation of this method does nothing. This method
363      * should be overridden by encoders that require notification of changes to
364      * the malformed-input action. </p>
365      */

366     protected void implOnMalformedInput(CodingErrorAction JavaDoc newAction) { }
367
368     /**
369      * Returns this encoder's current action for unmappable-character errors.
370      * </p>
371      *
372      * @return The current unmappable-character action, which is never
373      * <tt>null</tt>
374      */

375     public CodingErrorAction JavaDoc unmappableCharacterAction() {
376     return unmappableCharacterAction;
377     }
378
379     /**
380      * Changes this encoder's action for unmappable-character errors.
381      *
382      * <p> This method invokes the {@link #implOnUnmappableCharacter
383      * implOnUnmappableCharacter} method, passing the new action. </p>
384      *
385      * @param newAction The new action; must not be <tt>null</tt>
386      *
387      * @return This encoder
388      *
389      * @throws IllegalArgumentException
390      * If the precondition on the parameter does not hold
391      */

392     public final CharsetEncoder JavaDoc onUnmappableCharacter(CodingErrorAction JavaDoc
393                               newAction)
394     {
395     if (newAction == null)
396         throw new IllegalArgumentException JavaDoc("Null action");
397     unmappableCharacterAction = newAction;
398     implOnUnmappableCharacter(newAction);
399     return this;
400     }
401
402     /**
403      * Reports a change to this encoder's unmappable-character action.
404      *
405      * <p> The default implementation of this method does nothing. This method
406      * should be overridden by encoders that require notification of changes to
407      * the unmappable-character action. </p>
408      */

409     protected void implOnUnmappableCharacter(CodingErrorAction JavaDoc newAction) { }
410
411     /**
412      * Returns the average number of bytes that will be produced for each
413      * character of input. This heuristic value may be used to estimate the size
414      * of the output buffer required for a given input sequence. </p>
415      *
416      * @return The average number of bytes produced
417      * per character of input
418      */

419     public final float averageBytesPerChar() {
420     return averageBytesPerChar;
421     }
422
423     /**
424      * Returns the maximum number of bytes that will be produced for each
425      * character of input. This value may be used to compute the worst-case size
426      * of the output buffer required for a given input sequence. </p>
427      *
428      * @return The maximum number of bytes that will be produced per
429      * character of input
430      */

431     public final float maxBytesPerChar() {
432     return maxBytesPerChar;
433     }
434
435     /**
436      * Encodes as many characters as possible from the given input buffer,
437      * writing the results to the given output buffer.
438      *
439      * <p> The buffers are read from, and written to, starting at their current
440      * positions. At most {@link Buffer#remaining in.remaining()} characters
441      * will be read and at most {@link Buffer#remaining out.remaining()}
442      * bytes will be written. The buffers' positions will be advanced to
443      * reflect the characters read and the bytes written, but their marks and
444      * limits will not be modified.
445      *
446      * <p> In addition to reading characters from the input buffer and writing
447      * bytes to the output buffer, this method returns a {@link CoderResult}
448      * object to describe its reason for termination:
449      *
450      * <ul>
451      *
452      * <li><p> {@link CoderResult#UNDERFLOW} indicates that as much of the
453      * input buffer as possible has been encoded. If there are no characters
454      * remaining and the invoker has no further input then the encoding
455      * operation is complete. Otherwise there is insufficient input for the
456      * operation to proceed, so this method should be invoked again with
457      * further input. </p></li>
458      *
459      * <li><p> {@link CoderResult#OVERFLOW} indicates that the output buffer
460      * is full. This method should be invoked again with a non-full output
461      * buffer. </p></li>
462      *
463      * <li><p> A {@link CoderResult#malformedForLength
464      * </code>malformed-input<code>} result indicates that a malformed-input
465      * error has been detected. The malformed characters begin at the input
466      * buffer's (possibly incremented) position; the number of malformed
467      * characters may be determined by invoking the result object's {@link
468      * CoderResult#length length} method. This case applies only if the
469      * {@link #onMalformedInput </code>malformed action<code>} of this encoder
470      * is {@link CodingErrorAction#REPORT}; otherwise the malformed input
471      * will be ignored or replaced, as requested. </p></li>
472      *
473      * <li><p> An {@link CoderResult#unmappableForLength
474      * </code>unmappable-character<code>} result indicates that an
475      * unmappable-character error has been detected. The characters that
476      * encode the unmappable character begin at the input buffer's (possibly
477      * incremented) position; the number of such characters may be determined
478      * by invoking the result object's {@link CoderResult#length length}
479      * method. This case applies only if the {@link #onUnmappableCharacter
480      * </code>unmappable action<code>} of this encoder is {@link
481      * CodingErrorAction#REPORT}; otherwise the unmappable character will be
482      * ignored or replaced, as requested. </p></li>
483      *
484      * </ul>
485      *
486      * In any case, if this method is to be reinvoked in the same encoding
487      * operation then care should be taken to preserve any characters remaining
488      * in the input buffer so that they are available to the next invocation.
489      *
490      * <p> The <tt>endOfInput</tt> parameter advises this method as to whether
491      * the invoker can provide further input beyond that contained in the given
492      * input buffer. If there is a possibility of providing additional input
493      * then the invoker should pass <tt>false</tt> for this parameter; if there
494      * is no possibility of providing further input then the invoker should
495      * pass <tt>true</tt>. It is not erroneous, and in fact it is quite
496      * common, to pass <tt>false</tt> in one invocation and later discover that
497      * no further input was actually available. It is critical, however, that
498      * the final invocation of this method in a sequence of invocations always
499      * pass <tt>true</tt> so that any remaining unencoded input will be treated
500      * as being malformed.
501      *
502      * <p> This method works by invoking the {@link #encodeLoop encodeLoop}
503      * method, interpreting its results, handling error conditions, and
504      * reinvoking it as necessary. </p>
505      *
506      *
507      * @param in
508      * The input character buffer
509      *
510      * @param out
511      * The output byte buffer
512      *
513      * @param endOfInput
514      * <tt>true</tt> if, and only if, the invoker can provide no
515      * additional input characters beyond those in the given buffer
516      *
517      * @return A coder-result object describing the reason for termination
518      *
519      * @throws IllegalStateException
520      * If an encoding operation is already in progress and the previous
521      * step was an invocation neither of the {@link #reset reset}
522      * method, nor of this method with a value of <tt>false</tt> for
523      * the <tt>endOfInput</tt> parameter, nor of this method with a
524      * value of <tt>true</tt> for the <tt>endOfInput</tt> parameter
525      * but a return value indicating an incomplete encoding operation
526      *
527      * @throws CoderMalfunctionError
528      * If an invocation of the encodeLoop method threw
529      * an unexpected exception
530      */

531     public final CoderResult JavaDoc encode(CharBuffer JavaDoc in, ByteBuffer JavaDoc out,
532                     boolean endOfInput)
533     {
534     int newState = endOfInput ? ST_END : ST_CODING;
535     if ((state != ST_RESET) && (state != ST_CODING)
536         && !(endOfInput && (state == ST_END)))
537         throwIllegalStateException(state, newState);
538     state = newState;
539
540     for (;;) {
541
542         CoderResult JavaDoc cr;
543         try {
544         cr = encodeLoop(in, out);
545         } catch (BufferUnderflowException JavaDoc x) {
546         throw new CoderMalfunctionError JavaDoc(x);
547         } catch (BufferOverflowException JavaDoc x) {
548         throw new CoderMalfunctionError JavaDoc(x);
549         }
550
551         if (cr.isOverflow())
552         return cr;
553
554         if (cr.isUnderflow()) {
555         if (endOfInput && in.hasRemaining()) {
556             cr = CoderResult.malformedForLength(in.remaining());
557             // Fall through to malformed-input case
558
} else {
559             return cr;
560         }
561         }
562
563         CodingErrorAction JavaDoc action = null;
564         if (cr.isMalformed())
565         action = malformedInputAction;
566         else if (cr.isUnmappable())
567         action = unmappableCharacterAction;
568         else
569         assert false : cr.toString();
570
571         if (action == CodingErrorAction.REPORT)
572         return cr;
573
574         if (action == CodingErrorAction.REPLACE) {
575         if (out.remaining() < replacement.length)
576             return CoderResult.OVERFLOW;
577         out.put(replacement);
578         }
579
580         if ((action == CodingErrorAction.IGNORE)
581         || (action == CodingErrorAction.REPLACE)) {
582         // Skip erroneous input either way
583
in.position(in.position() + cr.length());
584         continue;
585         }
586
587         assert false;
588     }
589
590     }
591
592     /**
593      * Flushes this encoder.
594      *
595      * <p> Some encoders maintain internal state and may need to write some
596      * final bytes to the output buffer once the overall input sequence has
597      * been read.
598      *
599      * <p> Any additional output is written to the output buffer beginning at
600      * its current position. At most {@link Buffer#remaining out.remaining()}
601      * bytes will be written. The buffer's position will be advanced
602      * appropriately, but its mark and limit will not be modified.
603      *
604      * <p> If this method completes successfully then it returns {@link
605      * CoderResult#UNDERFLOW}. If there is insufficient room in the output
606      * buffer then it returns {@link CoderResult#OVERFLOW}. If this happens
607      * then this method must be invoked again, with an output buffer that has
608      * more room, in order to complete the current <a HREF="#steps">encoding
609      * operation</a>.
610      *
611      * <p> This method invokes the {@link #implFlush implFlush} method to
612      * perform the actual flushing operation. </p>
613      *
614      * @param out
615      * The output byte buffer
616      *
617      * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or
618      * {@link CoderResult#OVERFLOW}
619      *
620      * @throws IllegalStateException
621      * If the previous step of the current encoding operation was an
622      * invocation neither of the {@link #reset reset} method nor of
623      * the three-argument {@link
624      * #encode(CharBuffer,ByteBuffer,boolean) encode} method
625      * with a value of <tt>true</tt> for the <tt>endOfInput</tt>
626      * parameter
627      */

628     public final CoderResult JavaDoc flush(ByteBuffer JavaDoc out) {
629     if (state != ST_END)
630         throwIllegalStateException(state, ST_FLUSHED);
631     state = ST_FLUSHED;
632     return implFlush(out);
633     }
634
635     /**
636      * Flushes this encoder.
637      *
638      * <p> The default implementation of this method does nothing, and always
639      * returns {@link CoderResult#UNDERFLOW}. This method should be overridden
640      * by encoders that may need to write final bytes to the output buffer
641      * once the entire input sequence has been read. </p>
642      *
643      * @param out
644      * The output byte buffer
645      *
646      * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or
647      * {@link CoderResult#OVERFLOW}
648      */

649     protected CoderResult JavaDoc implFlush(ByteBuffer JavaDoc out) {
650     return CoderResult.UNDERFLOW;
651     }
652
653     /**
654      * Resets this encoder, clearing any internal state.
655      *
656      * <p> This method resets charset-independent state and also invokes the
657      * {@link #implReset() implReset} method in order to perform any
658      * charset-specific reset actions. </p>
659      *
660      * @return This encoder
661      *
662      */

663     public final CharsetEncoder JavaDoc reset() {
664     implReset();
665     state = ST_RESET;
666     return this;
667     }
668
669     /**
670      * Resets this encoder, clearing any charset-specific internal state.
671      *
672      * <p> The default implementation of this method does nothing. This method
673      * should be overridden by encoders that maintain internal state. </p>
674      */

675     protected void implReset() { }
676
677     /**
678      * Encodes one or more characters into one or more bytes.
679      *
680      * <p> This method encapsulates the basic encoding loop, encoding as many
681      * characters as possible until it either runs out of input, runs out of room
682      * in the output buffer, or encounters an encoding error. This method is
683      * invoked by the {@link #encode encode} method, which handles result
684      * interpretation and error recovery.
685      *
686      * <p> The buffers are read from, and written to, starting at their current
687      * positions. At most {@link Buffer#remaining in.remaining()} characters
688      * will be read, and at most {@link Buffer#remaining out.remaining()}
689      * bytes will be written. The buffers' positions will be advanced to
690      * reflect the characters read and the bytes written, but their marks and
691      * limits will not be modified.
692      *
693      * <p> This method returns a {@link CoderResult} object to describe its
694      * reason for termination, in the same manner as the {@link #encode encode}
695      * method. Most implementations of this method will handle encoding errors
696      * by returning an appropriate result object for interpretation by the
697      * {@link #encode encode} method. An optimized implementation may instead
698      * examine the relevant error action and implement that action itself.
699      *
700      * <p> An implementation of this method may perform arbitrary lookahead by
701      * returning {@link CoderResult#UNDERFLOW} until it receives sufficient
702      * input. </p>
703      *
704      * @param in
705      * The input character buffer
706      *
707      * @param out
708      * The output byte buffer
709      *
710      * @return A coder-result object describing the reason for termination
711      */

712     protected abstract CoderResult JavaDoc encodeLoop(CharBuffer JavaDoc in,
713                           ByteBuffer JavaDoc out);
714
715     /**
716      * Convenience method that encodes the remaining content of a single input
717      * character buffer into a newly-allocated byte buffer.
718      *
719      * <p> This method implements an entire <a HREF="#steps">encoding
720      * operation</a>; that is, it resets this encoder, then it encodes the
721      * characters in the given character buffer, and finally it flushes this
722      * encoder. This method should therefore not be invoked if an encoding
723      * operation is already in progress. </p>
724      *
725      * @param in
726      * The input character buffer
727      *
728      * @return A newly-allocated byte buffer containing the result of the
729      * encoding operation. The buffer's position will be zero and its
730      * limit will follow the last byte written.
731      *
732      * @throws IllegalStateException
733      * If an encoding operation is already in progress
734      *
735      * @throws MalformedInputException
736      * If the character sequence starting at the input buffer's current
737      * position is not a legal sixteen-bit Unicode sequence and the current malformed-input action
738      * is {@link CodingErrorAction#REPORT}
739      *
740      * @throws UnmappableCharacterException
741      * If the character sequence starting at the input buffer's current
742      * position cannot be mapped to an equivalent byte sequence and
743      * the current unmappable-character action is {@link
744      * CodingErrorAction#REPORT}
745      */

746     public final ByteBuffer JavaDoc encode(CharBuffer JavaDoc in)
747     throws CharacterCodingException JavaDoc
748     {
749     int n = (int)(in.remaining() * averageBytesPerChar());
750     ByteBuffer JavaDoc out = ByteBuffer.allocate(n);
751
752     if (n == 0)
753         return out;
754     reset();
755     for (;;) {
756         CoderResult JavaDoc cr;
757         if (in.hasRemaining())
758         cr = encode(in, out, true);
759         else
760         cr = flush(out);
761         if (cr.isUnderflow())
762         break;
763         if (cr.isOverflow()) {
764         n *= 2;
765         ByteBuffer JavaDoc o = ByteBuffer.allocate(n);
766         out.flip();
767         o.put(out);
768         out = o;
769         continue;
770         }
771         cr.throwException();
772     }
773     out.flip();
774     return out;
775     }
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855     private boolean canEncode(CharBuffer JavaDoc cb) {
856     if (state == ST_FLUSHED)
857         reset();
858     else if (state != ST_RESET)
859         throwIllegalStateException(state, ST_CODING);
860     CodingErrorAction JavaDoc ma = malformedInputAction();
861     CodingErrorAction JavaDoc ua = unmappableCharacterAction();
862     try {
863         onMalformedInput(CodingErrorAction.REPORT);
864         onUnmappableCharacter(CodingErrorAction.REPORT);
865         encode(cb);
866     } catch (CharacterCodingException JavaDoc x) {
867         return false;
868     } finally {
869         onMalformedInput(ma);
870         onUnmappableCharacter(ua);
871         reset();
872     }
873     return true;
874     }
875
876     /**
877      * Tells whether or not this encoder can encode the given character.
878      *
879      * <p> This method returns <tt>false</tt> if the given character is a
880      * surrogate character; such characters can be interpreted only when they
881      * are members of a pair consisting of a high surrogate followed by a low
882      * surrogate. The {@link #canEncode(java.lang.CharSequence)
883      * canEncode(CharSequence)} method may be used to test whether or not a
884      * character sequence can be encoded.
885      *
886      * <p> This method may modify this encoder's state; it should therefore not
887      * be invoked if an <a HREF="#steps">encoding operation</a> is already in
888      * progress.
889      *
890      * <p> The default implementation of this method is not very efficient; it
891      * should generally be overridden to improve performance. </p>
892      *
893      * @return <tt>true</tt> if, and only if, this encoder can encode
894      * the given character
895      *
896      * @throws IllegalStateException
897      * If an encoding operation is already in progress
898      */

899     public boolean canEncode(char c) {
900     CharBuffer JavaDoc cb = CharBuffer.allocate(1);
901     cb.put(c);
902     cb.flip();
903     return canEncode(cb);
904     }
905
906     /**
907      * Tells whether or not this encoder can encode the given character
908      * sequence.
909      *
910      * <p> If this method returns <tt>false</tt> for a particular character
911      * sequence then more information about why the sequence cannot be encoded
912      * may be obtained by performing a full <a HREF="#steps">encoding
913      * operation</a>.
914      *
915      * <p> This method may modify this encoder's state; it should therefore not
916      * be invoked if an encoding operation is already in progress.
917      *
918      * <p> The default implementation of this method is not very efficient; it
919      * should generally be overridden to improve performance. </p>
920      *
921      * @return <tt>true</tt> if, and only if, this encoder can encode
922      * the given character without throwing any exceptions and without
923      * performing any replacements
924      *
925      * @throws IllegalStateException
926      * If an encoding operation is already in progress
927      */

928     public boolean canEncode(CharSequence JavaDoc cs) {
929     CharBuffer JavaDoc cb;
930     if (cs instanceof CharBuffer JavaDoc)
931         cb = ((CharBuffer JavaDoc)cs).duplicate();
932     else
933         cb = CharBuffer.wrap(cs.toString());
934     return canEncode(cb);
935     }
936
937
938
939
940     private void throwIllegalStateException(int from, int to) {
941     throw new IllegalStateException JavaDoc("Current state = " + stateNames[from]
942                     + ", new state = " + stateNames[to]);
943     }
944
945 }
946
Popular Tags