1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/CharsetEncoder.java Thu Oct 03 15:40:35 2013 +0200
1.3 @@ -0,0 +1,972 @@
1.4 +/*
1.5 + * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
1.6 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
1.7 + *
1.8 + *
1.9 + *
1.10 + *
1.11 + *
1.12 + *
1.13 + *
1.14 + *
1.15 + *
1.16 + *
1.17 + *
1.18 + *
1.19 + *
1.20 + *
1.21 + *
1.22 + *
1.23 + *
1.24 + *
1.25 + *
1.26 + *
1.27 + */
1.28 +
1.29 +// -- This file was mechanically generated: Do not edit! -- //
1.30 +
1.31 +package java.nio.charset;
1.32 +
1.33 +import java.nio.Buffer;
1.34 +import java.nio.ByteBuffer;
1.35 +import java.nio.CharBuffer;
1.36 +import java.nio.BufferOverflowException;
1.37 +import java.nio.BufferUnderflowException;
1.38 +import java.lang.ref.WeakReference;
1.39 +import java.nio.charset.CoderMalfunctionError; // javadoc
1.40 +
1.41 +
1.42 +/**
1.43 + * An engine that can transform a sequence of sixteen-bit Unicode characters into a sequence of
1.44 + * bytes in a specific charset.
1.45 + *
1.46 + * <a name="steps">
1.47 + *
1.48 + * <p> The input character sequence is provided in a character buffer or a series
1.49 + * of such buffers. The output byte sequence is written to a byte buffer
1.50 + * or a series of such buffers. An encoder should always be used by making
1.51 + * the following sequence of method invocations, hereinafter referred to as an
1.52 + * <i>encoding operation</i>:
1.53 + *
1.54 + * <ol>
1.55 + *
1.56 + * <li><p> Reset the encoder via the {@link #reset reset} method, unless it
1.57 + * has not been used before; </p></li>
1.58 + *
1.59 + * <li><p> Invoke the {@link #encode encode} method zero or more times, as
1.60 + * long as additional input may be available, passing <tt>false</tt> for the
1.61 + * <tt>endOfInput</tt> argument and filling the input buffer and flushing the
1.62 + * output buffer between invocations; </p></li>
1.63 + *
1.64 + * <li><p> Invoke the {@link #encode encode} method one final time, passing
1.65 + * <tt>true</tt> for the <tt>endOfInput</tt> argument; and then </p></li>
1.66 + *
1.67 + * <li><p> Invoke the {@link #flush flush} method so that the encoder can
1.68 + * flush any internal state to the output buffer. </p></li>
1.69 + *
1.70 + * </ol>
1.71 + *
1.72 + * Each invocation of the {@link #encode encode} method will encode as many
1.73 + * characters as possible from the input buffer, writing the resulting bytes
1.74 + * to the output buffer. The {@link #encode encode} method returns when more
1.75 + * input is required, when there is not enough room in the output buffer, or
1.76 + * when an encoding error has occurred. In each case a {@link CoderResult}
1.77 + * object is returned to describe the reason for termination. An invoker can
1.78 + * examine this object and fill the input buffer, flush the output buffer, or
1.79 + * attempt to recover from an encoding error, as appropriate, and try again.
1.80 + *
1.81 + * <a name="ce">
1.82 + *
1.83 + * <p> There are two general types of encoding errors. If the input character
1.84 + * sequence is not a legal sixteen-bit Unicode sequence then the input is considered <i>malformed</i>. If
1.85 + * the input character sequence is legal but cannot be mapped to a valid
1.86 + * byte sequence in the given charset then an <i>unmappable character</i> has been encountered.
1.87 + *
1.88 + * <a name="cae">
1.89 + *
1.90 + * <p> How an encoding error is handled depends upon the action requested for
1.91 + * that type of error, which is described by an instance of the {@link
1.92 + * CodingErrorAction} class. The possible error actions are to {@link
1.93 + * CodingErrorAction#IGNORE </code>ignore<code>} the erroneous input, {@link
1.94 + * CodingErrorAction#REPORT </code>report<code>} the error to the invoker via
1.95 + * the returned {@link CoderResult} object, or {@link CodingErrorAction#REPLACE
1.96 + * </code>replace<code>} the erroneous input with the current value of the
1.97 + * replacement byte array. The replacement
1.98 + *
1.99 +
1.100 + * is initially set to the encoder's default replacement, which often
1.101 + * (but not always) has the initial value <tt>{</tt> <tt>(byte)'?'</tt> <tt>}</tt>;
1.102 +
1.103 +
1.104 +
1.105 +
1.106 + *
1.107 + * its value may be changed via the {@link #replaceWith(byte[])
1.108 + * replaceWith} method.
1.109 + *
1.110 + * <p> The default action for malformed-input and unmappable-character errors
1.111 + * is to {@link CodingErrorAction#REPORT </code>report<code>} them. The
1.112 + * malformed-input error action may be changed via the {@link
1.113 + * #onMalformedInput(CodingErrorAction) onMalformedInput} method; the
1.114 + * unmappable-character action may be changed via the {@link
1.115 + * #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter} method.
1.116 + *
1.117 + * <p> This class is designed to handle many of the details of the encoding
1.118 + * process, including the implementation of error actions. An encoder for a
1.119 + * specific charset, which is a concrete subclass of this class, need only
1.120 + * implement the abstract {@link #encodeLoop encodeLoop} method, which
1.121 + * encapsulates the basic encoding loop. A subclass that maintains internal
1.122 + * state should, additionally, override the {@link #implFlush implFlush} and
1.123 + * {@link #implReset implReset} methods.
1.124 + *
1.125 + * <p> Instances of this class are not safe for use by multiple concurrent
1.126 + * threads. </p>
1.127 + *
1.128 + *
1.129 + * @author Mark Reinhold
1.130 + * @author JSR-51 Expert Group
1.131 + * @since 1.4
1.132 + *
1.133 + * @see ByteBuffer
1.134 + * @see CharBuffer
1.135 + * @see Charset
1.136 + * @see CharsetDecoder
1.137 + */
1.138 +
1.139 +public abstract class CharsetEncoder {
1.140 +
1.141 + private final Charset charset;
1.142 + private final float averageBytesPerChar;
1.143 + private final float maxBytesPerChar;
1.144 +
1.145 + private byte[] replacement;
1.146 + private CodingErrorAction malformedInputAction
1.147 + = CodingErrorAction.REPORT;
1.148 + private CodingErrorAction unmappableCharacterAction
1.149 + = CodingErrorAction.REPORT;
1.150 +
1.151 + // Internal states
1.152 + //
1.153 + private static final int ST_RESET = 0;
1.154 + private static final int ST_CODING = 1;
1.155 + private static final int ST_END = 2;
1.156 + private static final int ST_FLUSHED = 3;
1.157 +
1.158 + private int state = ST_RESET;
1.159 +
1.160 + private static String stateNames[]
1.161 + = { "RESET", "CODING", "CODING_END", "FLUSHED" };
1.162 +
1.163 +
1.164 + /**
1.165 + * Initializes a new encoder. The new encoder will have the given
1.166 + * bytes-per-char and replacement values. </p>
1.167 + *
1.168 + * @param averageBytesPerChar
1.169 + * A positive float value indicating the expected number of
1.170 + * bytes that will be produced for each input character
1.171 + *
1.172 + * @param maxBytesPerChar
1.173 + * A positive float value indicating the maximum number of
1.174 + * bytes that will be produced for each input character
1.175 + *
1.176 + * @param replacement
1.177 + * The initial replacement; must not be <tt>null</tt>, must have
1.178 + * non-zero length, must not be longer than maxBytesPerChar,
1.179 + * and must be {@link #isLegalReplacement </code>legal<code>}
1.180 + *
1.181 + * @throws IllegalArgumentException
1.182 + * If the preconditions on the parameters do not hold
1.183 + */
1.184 + protected
1.185 + CharsetEncoder(Charset cs,
1.186 + float averageBytesPerChar,
1.187 + float maxBytesPerChar,
1.188 + byte[] replacement)
1.189 + {
1.190 + this.charset = cs;
1.191 + if (averageBytesPerChar <= 0.0f)
1.192 + throw new IllegalArgumentException("Non-positive "
1.193 + + "averageBytesPerChar");
1.194 + if (maxBytesPerChar <= 0.0f)
1.195 + throw new IllegalArgumentException("Non-positive "
1.196 + + "maxBytesPerChar");
1.197 + if (!Charset.atBugLevel("1.4")) {
1.198 + if (averageBytesPerChar > maxBytesPerChar)
1.199 + throw new IllegalArgumentException("averageBytesPerChar"
1.200 + + " exceeds "
1.201 + + "maxBytesPerChar");
1.202 + }
1.203 + this.replacement = replacement;
1.204 + this.averageBytesPerChar = averageBytesPerChar;
1.205 + this.maxBytesPerChar = maxBytesPerChar;
1.206 + replaceWith(replacement);
1.207 + }
1.208 +
1.209 + /**
1.210 + * Initializes a new encoder. The new encoder will have the given
1.211 + * bytes-per-char values and its replacement will be the
1.212 + * byte array <tt>{</tt> <tt>(byte)'?'</tt> <tt>}</tt>. </p>
1.213 + *
1.214 + * @param averageBytesPerChar
1.215 + * A positive float value indicating the expected number of
1.216 + * bytes that will be produced for each input character
1.217 + *
1.218 + * @param maxBytesPerChar
1.219 + * A positive float value indicating the maximum number of
1.220 + * bytes that will be produced for each input character
1.221 + *
1.222 + * @throws IllegalArgumentException
1.223 + * If the preconditions on the parameters do not hold
1.224 + */
1.225 + protected CharsetEncoder(Charset cs,
1.226 + float averageBytesPerChar,
1.227 + float maxBytesPerChar)
1.228 + {
1.229 + this(cs,
1.230 + averageBytesPerChar, maxBytesPerChar,
1.231 + new byte[] { (byte)'?' });
1.232 + }
1.233 +
1.234 + /**
1.235 + * Returns the charset that created this encoder. </p>
1.236 + *
1.237 + * @return This encoder's charset
1.238 + */
1.239 + public final Charset charset() {
1.240 + return charset;
1.241 + }
1.242 +
1.243 + /**
1.244 + * Returns this encoder's replacement value. </p>
1.245 + *
1.246 + * @return This encoder's current replacement,
1.247 + * which is never <tt>null</tt> and is never empty
1.248 + */
1.249 + public final byte[] replacement() {
1.250 + return replacement;
1.251 + }
1.252 +
1.253 + /**
1.254 + * Changes this encoder's replacement value.
1.255 + *
1.256 + * <p> This method invokes the {@link #implReplaceWith implReplaceWith}
1.257 + * method, passing the new replacement, after checking that the new
1.258 + * replacement is acceptable. </p>
1.259 + *
1.260 + * @param newReplacement
1.261 + *
1.262 +
1.263 +
1.264 +
1.265 +
1.266 +
1.267 + * The new replacement; must not be <tt>null</tt>, must have
1.268 + * non-zero length, must not be longer than the value returned by
1.269 + * the {@link #maxBytesPerChar() maxBytesPerChar} method, and
1.270 + * must be {@link #isLegalReplacement </code>legal<code>}
1.271 +
1.272 + *
1.273 + * @return This encoder
1.274 + *
1.275 + * @throws IllegalArgumentException
1.276 + * If the preconditions on the parameter do not hold
1.277 + */
1.278 + public final CharsetEncoder replaceWith(byte[] newReplacement) {
1.279 + if (newReplacement == null)
1.280 + throw new IllegalArgumentException("Null replacement");
1.281 + int len = newReplacement.length;
1.282 + if (len == 0)
1.283 + throw new IllegalArgumentException("Empty replacement");
1.284 + if (len > maxBytesPerChar)
1.285 + throw new IllegalArgumentException("Replacement too long");
1.286 +
1.287 + if (!isLegalReplacement(newReplacement))
1.288 + throw new IllegalArgumentException("Illegal replacement");
1.289 +
1.290 + this.replacement = newReplacement;
1.291 + implReplaceWith(newReplacement);
1.292 + return this;
1.293 + }
1.294 +
1.295 + /**
1.296 + * Reports a change to this encoder's replacement value.
1.297 + *
1.298 + * <p> The default implementation of this method does nothing. This method
1.299 + * should be overridden by encoders that require notification of changes to
1.300 + * the replacement. </p>
1.301 + *
1.302 + * @param newReplacement
1.303 + */
1.304 + protected void implReplaceWith(byte[] newReplacement) {
1.305 + }
1.306 +
1.307 +
1.308 +
1.309 + private WeakReference<CharsetDecoder> cachedDecoder = null;
1.310 +
1.311 + /**
1.312 + * Tells whether or not the given byte array is a legal replacement value
1.313 + * for this encoder.
1.314 + *
1.315 + * <p> A replacement is legal if, and only if, it is a legal sequence of
1.316 + * bytes in this encoder's charset; that is, it must be possible to decode
1.317 + * the replacement into one or more sixteen-bit Unicode characters.
1.318 + *
1.319 + * <p> The default implementation of this method is not very efficient; it
1.320 + * should generally be overridden to improve performance. </p>
1.321 + *
1.322 + * @param repl The byte array to be tested
1.323 + *
1.324 + * @return <tt>true</tt> if, and only if, the given byte array
1.325 + * is a legal replacement value for this encoder
1.326 + */
1.327 + public boolean isLegalReplacement(byte[] repl) {
1.328 + WeakReference<CharsetDecoder> wr = cachedDecoder;
1.329 + CharsetDecoder dec = null;
1.330 + if ((wr == null) || ((dec = wr.get()) == null)) {
1.331 + dec = charset().newDecoder();
1.332 + dec.onMalformedInput(CodingErrorAction.REPORT);
1.333 + dec.onUnmappableCharacter(CodingErrorAction.REPORT);
1.334 + cachedDecoder = new WeakReference<CharsetDecoder>(dec);
1.335 + } else {
1.336 + dec.reset();
1.337 + }
1.338 + ByteBuffer bb = ByteBuffer.wrap(repl);
1.339 + CharBuffer cb = CharBuffer.allocate((int)(bb.remaining()
1.340 + * dec.maxCharsPerByte()));
1.341 + CoderResult cr = dec.decode(bb, cb, true);
1.342 + return !cr.isError();
1.343 + }
1.344 +
1.345 +
1.346 +
1.347 + /**
1.348 + * Returns this encoder's current action for malformed-input errors. </p>
1.349 + *
1.350 + * @return The current malformed-input action, which is never <tt>null</tt>
1.351 + */
1.352 + public CodingErrorAction malformedInputAction() {
1.353 + return malformedInputAction;
1.354 + }
1.355 +
1.356 + /**
1.357 + * Changes this encoder's action for malformed-input errors. </p>
1.358 + *
1.359 + * <p> This method invokes the {@link #implOnMalformedInput
1.360 + * implOnMalformedInput} method, passing the new action. </p>
1.361 + *
1.362 + * @param newAction The new action; must not be <tt>null</tt>
1.363 + *
1.364 + * @return This encoder
1.365 + *
1.366 + * @throws IllegalArgumentException
1.367 + * If the precondition on the parameter does not hold
1.368 + */
1.369 + public final CharsetEncoder onMalformedInput(CodingErrorAction newAction) {
1.370 + if (newAction == null)
1.371 + throw new IllegalArgumentException("Null action");
1.372 + malformedInputAction = newAction;
1.373 + implOnMalformedInput(newAction);
1.374 + return this;
1.375 + }
1.376 +
1.377 + /**
1.378 + * Reports a change to this encoder's malformed-input action.
1.379 + *
1.380 + * <p> The default implementation of this method does nothing. This method
1.381 + * should be overridden by encoders that require notification of changes to
1.382 + * the malformed-input action. </p>
1.383 + */
1.384 + protected void implOnMalformedInput(CodingErrorAction newAction) { }
1.385 +
1.386 + /**
1.387 + * Returns this encoder's current action for unmappable-character errors.
1.388 + * </p>
1.389 + *
1.390 + * @return The current unmappable-character action, which is never
1.391 + * <tt>null</tt>
1.392 + */
1.393 + public CodingErrorAction unmappableCharacterAction() {
1.394 + return unmappableCharacterAction;
1.395 + }
1.396 +
1.397 + /**
1.398 + * Changes this encoder's action for unmappable-character errors.
1.399 + *
1.400 + * <p> This method invokes the {@link #implOnUnmappableCharacter
1.401 + * implOnUnmappableCharacter} method, passing the new action. </p>
1.402 + *
1.403 + * @param newAction The new action; must not be <tt>null</tt>
1.404 + *
1.405 + * @return This encoder
1.406 + *
1.407 + * @throws IllegalArgumentException
1.408 + * If the precondition on the parameter does not hold
1.409 + */
1.410 + public final CharsetEncoder onUnmappableCharacter(CodingErrorAction
1.411 + newAction)
1.412 + {
1.413 + if (newAction == null)
1.414 + throw new IllegalArgumentException("Null action");
1.415 + unmappableCharacterAction = newAction;
1.416 + implOnUnmappableCharacter(newAction);
1.417 + return this;
1.418 + }
1.419 +
1.420 + /**
1.421 + * Reports a change to this encoder's unmappable-character action.
1.422 + *
1.423 + * <p> The default implementation of this method does nothing. This method
1.424 + * should be overridden by encoders that require notification of changes to
1.425 + * the unmappable-character action. </p>
1.426 + */
1.427 + protected void implOnUnmappableCharacter(CodingErrorAction newAction) { }
1.428 +
1.429 + /**
1.430 + * Returns the average number of bytes that will be produced for each
1.431 + * character of input. This heuristic value may be used to estimate the size
1.432 + * of the output buffer required for a given input sequence. </p>
1.433 + *
1.434 + * @return The average number of bytes produced
1.435 + * per character of input
1.436 + */
1.437 + public final float averageBytesPerChar() {
1.438 + return averageBytesPerChar;
1.439 + }
1.440 +
1.441 + /**
1.442 + * Returns the maximum number of bytes that will be produced for each
1.443 + * character of input. This value may be used to compute the worst-case size
1.444 + * of the output buffer required for a given input sequence. </p>
1.445 + *
1.446 + * @return The maximum number of bytes that will be produced per
1.447 + * character of input
1.448 + */
1.449 + public final float maxBytesPerChar() {
1.450 + return maxBytesPerChar;
1.451 + }
1.452 +
1.453 + /**
1.454 + * Encodes as many characters as possible from the given input buffer,
1.455 + * writing the results to the given output buffer.
1.456 + *
1.457 + * <p> The buffers are read from, and written to, starting at their current
1.458 + * positions. At most {@link Buffer#remaining in.remaining()} characters
1.459 + * will be read and at most {@link Buffer#remaining out.remaining()}
1.460 + * bytes will be written. The buffers' positions will be advanced to
1.461 + * reflect the characters read and the bytes written, but their marks and
1.462 + * limits will not be modified.
1.463 + *
1.464 + * <p> In addition to reading characters from the input buffer and writing
1.465 + * bytes to the output buffer, this method returns a {@link CoderResult}
1.466 + * object to describe its reason for termination:
1.467 + *
1.468 + * <ul>
1.469 + *
1.470 + * <li><p> {@link CoderResult#UNDERFLOW} indicates that as much of the
1.471 + * input buffer as possible has been encoded. If there is no further
1.472 + * input then the invoker can proceed to the next step of the
1.473 + * <a href="#steps">encoding operation</a>. Otherwise this method
1.474 + * should be invoked again with further input. </p></li>
1.475 + *
1.476 + * <li><p> {@link CoderResult#OVERFLOW} indicates that there is
1.477 + * insufficient space in the output buffer to encode any more characters.
1.478 + * This method should be invoked again with an output buffer that has
1.479 + * more {@linkplain Buffer#remaining remaining} bytes. This is
1.480 + * typically done by draining any encoded bytes from the output
1.481 + * buffer. </p></li>
1.482 + *
1.483 + * <li><p> A {@link CoderResult#malformedForLength
1.484 + * </code>malformed-input<code>} result indicates that a malformed-input
1.485 + * error has been detected. The malformed characters begin at the input
1.486 + * buffer's (possibly incremented) position; the number of malformed
1.487 + * characters may be determined by invoking the result object's {@link
1.488 + * CoderResult#length() length} method. This case applies only if the
1.489 + * {@link #onMalformedInput </code>malformed action<code>} of this encoder
1.490 + * is {@link CodingErrorAction#REPORT}; otherwise the malformed input
1.491 + * will be ignored or replaced, as requested. </p></li>
1.492 + *
1.493 + * <li><p> An {@link CoderResult#unmappableForLength
1.494 + * </code>unmappable-character<code>} result indicates that an
1.495 + * unmappable-character error has been detected. The characters that
1.496 + * encode the unmappable character begin at the input buffer's (possibly
1.497 + * incremented) position; the number of such characters may be determined
1.498 + * by invoking the result object's {@link CoderResult#length() length}
1.499 + * method. This case applies only if the {@link #onUnmappableCharacter
1.500 + * </code>unmappable action<code>} of this encoder is {@link
1.501 + * CodingErrorAction#REPORT}; otherwise the unmappable character will be
1.502 + * ignored or replaced, as requested. </p></li>
1.503 + *
1.504 + * </ul>
1.505 + *
1.506 + * In any case, if this method is to be reinvoked in the same encoding
1.507 + * operation then care should be taken to preserve any characters remaining
1.508 + * in the input buffer so that they are available to the next invocation.
1.509 + *
1.510 + * <p> The <tt>endOfInput</tt> parameter advises this method as to whether
1.511 + * the invoker can provide further input beyond that contained in the given
1.512 + * input buffer. If there is a possibility of providing additional input
1.513 + * then the invoker should pass <tt>false</tt> for this parameter; if there
1.514 + * is no possibility of providing further input then the invoker should
1.515 + * pass <tt>true</tt>. It is not erroneous, and in fact it is quite
1.516 + * common, to pass <tt>false</tt> in one invocation and later discover that
1.517 + * no further input was actually available. It is critical, however, that
1.518 + * the final invocation of this method in a sequence of invocations always
1.519 + * pass <tt>true</tt> so that any remaining unencoded input will be treated
1.520 + * as being malformed.
1.521 + *
1.522 + * <p> This method works by invoking the {@link #encodeLoop encodeLoop}
1.523 + * method, interpreting its results, handling error conditions, and
1.524 + * reinvoking it as necessary. </p>
1.525 + *
1.526 + *
1.527 + * @param in
1.528 + * The input character buffer
1.529 + *
1.530 + * @param out
1.531 + * The output byte buffer
1.532 + *
1.533 + * @param endOfInput
1.534 + * <tt>true</tt> if, and only if, the invoker can provide no
1.535 + * additional input characters beyond those in the given buffer
1.536 + *
1.537 + * @return A coder-result object describing the reason for termination
1.538 + *
1.539 + * @throws IllegalStateException
1.540 + * If an encoding operation is already in progress and the previous
1.541 + * step was an invocation neither of the {@link #reset reset}
1.542 + * method, nor of this method with a value of <tt>false</tt> for
1.543 + * the <tt>endOfInput</tt> parameter, nor of this method with a
1.544 + * value of <tt>true</tt> for the <tt>endOfInput</tt> parameter
1.545 + * but a return value indicating an incomplete encoding operation
1.546 + *
1.547 + * @throws CoderMalfunctionError
1.548 + * If an invocation of the encodeLoop method threw
1.549 + * an unexpected exception
1.550 + */
1.551 + public final CoderResult encode(CharBuffer in, ByteBuffer out,
1.552 + boolean endOfInput)
1.553 + {
1.554 + int newState = endOfInput ? ST_END : ST_CODING;
1.555 + if ((state != ST_RESET) && (state != ST_CODING)
1.556 + && !(endOfInput && (state == ST_END)))
1.557 + throwIllegalStateException(state, newState);
1.558 + state = newState;
1.559 +
1.560 + for (;;) {
1.561 +
1.562 + CoderResult cr;
1.563 + try {
1.564 + cr = encodeLoop(in, out);
1.565 + } catch (BufferUnderflowException x) {
1.566 + throw new CoderMalfunctionError(x);
1.567 + } catch (BufferOverflowException x) {
1.568 + throw new CoderMalfunctionError(x);
1.569 + }
1.570 +
1.571 + if (cr.isOverflow())
1.572 + return cr;
1.573 +
1.574 + if (cr.isUnderflow()) {
1.575 + if (endOfInput && in.hasRemaining()) {
1.576 + cr = CoderResult.malformedForLength(in.remaining());
1.577 + // Fall through to malformed-input case
1.578 + } else {
1.579 + return cr;
1.580 + }
1.581 + }
1.582 +
1.583 + CodingErrorAction action = null;
1.584 + if (cr.isMalformed())
1.585 + action = malformedInputAction;
1.586 + else if (cr.isUnmappable())
1.587 + action = unmappableCharacterAction;
1.588 + else
1.589 + assert false : cr.toString();
1.590 +
1.591 + if (action == CodingErrorAction.REPORT)
1.592 + return cr;
1.593 +
1.594 + if (action == CodingErrorAction.REPLACE) {
1.595 + if (out.remaining() < replacement.length)
1.596 + return CoderResult.OVERFLOW;
1.597 + out.put(replacement);
1.598 + }
1.599 +
1.600 + if ((action == CodingErrorAction.IGNORE)
1.601 + || (action == CodingErrorAction.REPLACE)) {
1.602 + // Skip erroneous input either way
1.603 + in.position(in.position() + cr.length());
1.604 + continue;
1.605 + }
1.606 +
1.607 + assert false;
1.608 + }
1.609 +
1.610 + }
1.611 +
1.612 + /**
1.613 + * Flushes this encoder.
1.614 + *
1.615 + * <p> Some encoders maintain internal state and may need to write some
1.616 + * final bytes to the output buffer once the overall input sequence has
1.617 + * been read.
1.618 + *
1.619 + * <p> Any additional output is written to the output buffer beginning at
1.620 + * its current position. At most {@link Buffer#remaining out.remaining()}
1.621 + * bytes will be written. The buffer's position will be advanced
1.622 + * appropriately, but its mark and limit will not be modified.
1.623 + *
1.624 + * <p> If this method completes successfully then it returns {@link
1.625 + * CoderResult#UNDERFLOW}. If there is insufficient room in the output
1.626 + * buffer then it returns {@link CoderResult#OVERFLOW}. If this happens
1.627 + * then this method must be invoked again, with an output buffer that has
1.628 + * more room, in order to complete the current <a href="#steps">encoding
1.629 + * operation</a>.
1.630 + *
1.631 + * <p> If this encoder has already been flushed then invoking this method
1.632 + * has no effect.
1.633 + *
1.634 + * <p> This method invokes the {@link #implFlush implFlush} method to
1.635 + * perform the actual flushing operation. </p>
1.636 + *
1.637 + * @param out
1.638 + * The output byte buffer
1.639 + *
1.640 + * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or
1.641 + * {@link CoderResult#OVERFLOW}
1.642 + *
1.643 + * @throws IllegalStateException
1.644 + * If the previous step of the current encoding operation was an
1.645 + * invocation neither of the {@link #flush flush} method nor of
1.646 + * the three-argument {@link
1.647 + * #encode(CharBuffer,ByteBuffer,boolean) encode} method
1.648 + * with a value of <tt>true</tt> for the <tt>endOfInput</tt>
1.649 + * parameter
1.650 + */
1.651 + public final CoderResult flush(ByteBuffer out) {
1.652 + if (state == ST_END) {
1.653 + CoderResult cr = implFlush(out);
1.654 + if (cr.isUnderflow())
1.655 + state = ST_FLUSHED;
1.656 + return cr;
1.657 + }
1.658 +
1.659 + if (state != ST_FLUSHED)
1.660 + throwIllegalStateException(state, ST_FLUSHED);
1.661 +
1.662 + return CoderResult.UNDERFLOW; // Already flushed
1.663 + }
1.664 +
1.665 + /**
1.666 + * Flushes this encoder.
1.667 + *
1.668 + * <p> The default implementation of this method does nothing, and always
1.669 + * returns {@link CoderResult#UNDERFLOW}. This method should be overridden
1.670 + * by encoders that may need to write final bytes to the output buffer
1.671 + * once the entire input sequence has been read. </p>
1.672 + *
1.673 + * @param out
1.674 + * The output byte buffer
1.675 + *
1.676 + * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or
1.677 + * {@link CoderResult#OVERFLOW}
1.678 + */
1.679 + protected CoderResult implFlush(ByteBuffer out) {
1.680 + return CoderResult.UNDERFLOW;
1.681 + }
1.682 +
1.683 + /**
1.684 + * Resets this encoder, clearing any internal state.
1.685 + *
1.686 + * <p> This method resets charset-independent state and also invokes the
1.687 + * {@link #implReset() implReset} method in order to perform any
1.688 + * charset-specific reset actions. </p>
1.689 + *
1.690 + * @return This encoder
1.691 + *
1.692 + */
1.693 + public final CharsetEncoder reset() {
1.694 + implReset();
1.695 + state = ST_RESET;
1.696 + return this;
1.697 + }
1.698 +
1.699 + /**
1.700 + * Resets this encoder, clearing any charset-specific internal state.
1.701 + *
1.702 + * <p> The default implementation of this method does nothing. This method
1.703 + * should be overridden by encoders that maintain internal state. </p>
1.704 + */
1.705 + protected void implReset() { }
1.706 +
1.707 + /**
1.708 + * Encodes one or more characters into one or more bytes.
1.709 + *
1.710 + * <p> This method encapsulates the basic encoding loop, encoding as many
1.711 + * characters as possible until it either runs out of input, runs out of room
1.712 + * in the output buffer, or encounters an encoding error. This method is
1.713 + * invoked by the {@link #encode encode} method, which handles result
1.714 + * interpretation and error recovery.
1.715 + *
1.716 + * <p> The buffers are read from, and written to, starting at their current
1.717 + * positions. At most {@link Buffer#remaining in.remaining()} characters
1.718 + * will be read, and at most {@link Buffer#remaining out.remaining()}
1.719 + * bytes will be written. The buffers' positions will be advanced to
1.720 + * reflect the characters read and the bytes written, but their marks and
1.721 + * limits will not be modified.
1.722 + *
1.723 + * <p> This method returns a {@link CoderResult} object to describe its
1.724 + * reason for termination, in the same manner as the {@link #encode encode}
1.725 + * method. Most implementations of this method will handle encoding errors
1.726 + * by returning an appropriate result object for interpretation by the
1.727 + * {@link #encode encode} method. An optimized implementation may instead
1.728 + * examine the relevant error action and implement that action itself.
1.729 + *
1.730 + * <p> An implementation of this method may perform arbitrary lookahead by
1.731 + * returning {@link CoderResult#UNDERFLOW} until it receives sufficient
1.732 + * input. </p>
1.733 + *
1.734 + * @param in
1.735 + * The input character buffer
1.736 + *
1.737 + * @param out
1.738 + * The output byte buffer
1.739 + *
1.740 + * @return A coder-result object describing the reason for termination
1.741 + */
1.742 + protected abstract CoderResult encodeLoop(CharBuffer in,
1.743 + ByteBuffer out);
1.744 +
1.745 + /**
1.746 + * Convenience method that encodes the remaining content of a single input
1.747 + * character buffer into a newly-allocated byte buffer.
1.748 + *
1.749 + * <p> This method implements an entire <a href="#steps">encoding
1.750 + * operation</a>; that is, it resets this encoder, then it encodes the
1.751 + * characters in the given character buffer, and finally it flushes this
1.752 + * encoder. This method should therefore not be invoked if an encoding
1.753 + * operation is already in progress. </p>
1.754 + *
1.755 + * @param in
1.756 + * The input character buffer
1.757 + *
1.758 + * @return A newly-allocated byte buffer containing the result of the
1.759 + * encoding operation. The buffer's position will be zero and its
1.760 + * limit will follow the last byte written.
1.761 + *
1.762 + * @throws IllegalStateException
1.763 + * If an encoding operation is already in progress
1.764 + *
1.765 + * @throws MalformedInputException
1.766 + * If the character sequence starting at the input buffer's current
1.767 + * position is not a legal sixteen-bit Unicode sequence and the current malformed-input action
1.768 + * is {@link CodingErrorAction#REPORT}
1.769 + *
1.770 + * @throws UnmappableCharacterException
1.771 + * If the character sequence starting at the input buffer's current
1.772 + * position cannot be mapped to an equivalent byte sequence and
1.773 + * the current unmappable-character action is {@link
1.774 + * CodingErrorAction#REPORT}
1.775 + */
1.776 + public final ByteBuffer encode(CharBuffer in)
1.777 + throws CharacterCodingException
1.778 + {
1.779 + int n = (int)(in.remaining() * averageBytesPerChar());
1.780 + ByteBuffer out = ByteBuffer.allocate(n);
1.781 +
1.782 + if ((n == 0) && (in.remaining() == 0))
1.783 + return out;
1.784 + reset();
1.785 + for (;;) {
1.786 + CoderResult cr = in.hasRemaining() ?
1.787 + encode(in, out, true) : CoderResult.UNDERFLOW;
1.788 + if (cr.isUnderflow())
1.789 + cr = flush(out);
1.790 +
1.791 + if (cr.isUnderflow())
1.792 + break;
1.793 + if (cr.isOverflow()) {
1.794 + n = 2*n + 1; // Ensure progress; n might be 0!
1.795 + ByteBuffer o = ByteBuffer.allocate(n);
1.796 + out.flip();
1.797 + o.put(out);
1.798 + out = o;
1.799 + continue;
1.800 + }
1.801 + cr.throwException();
1.802 + }
1.803 + out.flip();
1.804 + return out;
1.805 + }
1.806 +
1.807 +
1.808 +
1.809 +
1.810 +
1.811 +
1.812 +
1.813 +
1.814 +
1.815 +
1.816 +
1.817 +
1.818 +
1.819 +
1.820 +
1.821 +
1.822 +
1.823 +
1.824 +
1.825 +
1.826 +
1.827 +
1.828 +
1.829 +
1.830 +
1.831 +
1.832 +
1.833 +
1.834 +
1.835 +
1.836 +
1.837 +
1.838 +
1.839 +
1.840 +
1.841 +
1.842 +
1.843 +
1.844 +
1.845 +
1.846 +
1.847 +
1.848 +
1.849 +
1.850 +
1.851 +
1.852 +
1.853 +
1.854 +
1.855 +
1.856 +
1.857 +
1.858 +
1.859 +
1.860 +
1.861 +
1.862 +
1.863 +
1.864 +
1.865 +
1.866 +
1.867 +
1.868 +
1.869 +
1.870 +
1.871 +
1.872 +
1.873 +
1.874 +
1.875 +
1.876 +
1.877 +
1.878 +
1.879 +
1.880 +
1.881 +
1.882 +
1.883 +
1.884 +
1.885 + private boolean canEncode(CharBuffer cb) {
1.886 + if (state == ST_FLUSHED)
1.887 + reset();
1.888 + else if (state != ST_RESET)
1.889 + throwIllegalStateException(state, ST_CODING);
1.890 + CodingErrorAction ma = malformedInputAction();
1.891 + CodingErrorAction ua = unmappableCharacterAction();
1.892 + try {
1.893 + onMalformedInput(CodingErrorAction.REPORT);
1.894 + onUnmappableCharacter(CodingErrorAction.REPORT);
1.895 + encode(cb);
1.896 + } catch (CharacterCodingException x) {
1.897 + return false;
1.898 + } finally {
1.899 + onMalformedInput(ma);
1.900 + onUnmappableCharacter(ua);
1.901 + reset();
1.902 + }
1.903 + return true;
1.904 + }
1.905 +
1.906 + /**
1.907 + * Tells whether or not this encoder can encode the given character.
1.908 + *
1.909 + * <p> This method returns <tt>false</tt> if the given character is a
1.910 + * surrogate character; such characters can be interpreted only when they
1.911 + * are members of a pair consisting of a high surrogate followed by a low
1.912 + * surrogate. The {@link #canEncode(java.lang.CharSequence)
1.913 + * canEncode(CharSequence)} method may be used to test whether or not a
1.914 + * character sequence can be encoded.
1.915 + *
1.916 + * <p> This method may modify this encoder's state; it should therefore not
1.917 + * be invoked if an <a href="#steps">encoding operation</a> is already in
1.918 + * progress.
1.919 + *
1.920 + * <p> The default implementation of this method is not very efficient; it
1.921 + * should generally be overridden to improve performance. </p>
1.922 + *
1.923 + * @return <tt>true</tt> if, and only if, this encoder can encode
1.924 + * the given character
1.925 + *
1.926 + * @throws IllegalStateException
1.927 + * If an encoding operation is already in progress
1.928 + */
1.929 + public boolean canEncode(char c) {
1.930 + CharBuffer cb = CharBuffer.allocate(1);
1.931 + cb.put(c);
1.932 + cb.flip();
1.933 + return canEncode(cb);
1.934 + }
1.935 +
1.936 + /**
1.937 + * Tells whether or not this encoder can encode the given character
1.938 + * sequence.
1.939 + *
1.940 + * <p> If this method returns <tt>false</tt> for a particular character
1.941 + * sequence then more information about why the sequence cannot be encoded
1.942 + * may be obtained by performing a full <a href="#steps">encoding
1.943 + * operation</a>.
1.944 + *
1.945 + * <p> This method may modify this encoder's state; it should therefore not
1.946 + * be invoked if an encoding operation is already in progress.
1.947 + *
1.948 + * <p> The default implementation of this method is not very efficient; it
1.949 + * should generally be overridden to improve performance. </p>
1.950 + *
1.951 + * @return <tt>true</tt> if, and only if, this encoder can encode
1.952 + * the given character without throwing any exceptions and without
1.953 + * performing any replacements
1.954 + *
1.955 + * @throws IllegalStateException
1.956 + * If an encoding operation is already in progress
1.957 + */
1.958 + public boolean canEncode(CharSequence cs) {
1.959 + CharBuffer cb;
1.960 + if (cs instanceof CharBuffer)
1.961 + cb = ((CharBuffer)cs).duplicate();
1.962 + else
1.963 + cb = CharBuffer.wrap(cs.toString());
1.964 + return canEncode(cb);
1.965 + }
1.966 +
1.967 +
1.968 +
1.969 +
1.970 + private void throwIllegalStateException(int from, int to) {
1.971 + throw new IllegalStateException("Current state = " + stateNames[from]
1.972 + + ", new state = " + stateNames[to]);
1.973 + }
1.974 +
1.975 +}