Use Tree Navigation
public abstract class

CharToByteConverter

extends Object
/*
 * Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */


package sun.io;

import java.io.*;


/**
 * An abstract base class for subclasses which convert Unicode
 * characters into an external encoding.
 *
 * @author Asmus Freytag
 * @author Lloyd Honomichl, Novell, Inc.
 *
 * @deprecated Replaced by {@link java.nio.charset}.  THIS API WILL BE
 * REMOVED IN J2SE 1.6.
 */

@Deprecated
public abstract class CharToByteConverter {

   
/**
     * Substitution mode flag.
     */

   
protected boolean subMode = true;

   
/**
     * Bytes to substitute for unmappable input.
     */

   
protected byte[] subBytes = { (byte)'?' };

   
/**
     * Offset of next character to be converted.
     */

   
protected int charOff;

   
/**
     * Offset of next byte to be output.
     */

   
protected int byteOff;

   
/**
     * Length of bad input that caused conversion to stop.
     */

   
protected int badInputLength;

   
/**
     * Create an instance of the default CharToByteConverter subclass.
     */

   
public static CharToByteConverter getDefault() {
       
Object cvt;
        cvt
= Converters.newDefaultConverter(Converters.CHAR_TO_BYTE);
       
return (CharToByteConverter)cvt;
   
}

   
/**
     * Returns appropriate CharToByteConverter subclass instance.
     * @param string represets encoding
     */

   
public static CharToByteConverter getConverter(String encoding)
       
throws UnsupportedEncodingException
   
{
       
Object cvt;
        cvt
= Converters.newConverter(Converters.CHAR_TO_BYTE, encoding);
       
return (CharToByteConverter)cvt;
   
}

   
/**
     * Returns the character set id for the conversion.
     */

   
public abstract String getCharacterEncoding();

   
/**
     * Converts an array of Unicode characters into an array of bytes
     * in the target character encoding.  This method allows a buffer by
     * buffer conversion of a data stream.  The state of the conversion is
     * saved between calls to convert.  If a call to convert results in
     * an exception, the conversion may be continued by calling convert again
     * with suitably modified parameters.  All conversions should be finished
     * with a call to the flush method.
     *
     * @return the number of bytes written to output.
     * @param input array containing Unicode characters to be converted.
     * @param inStart begin conversion at this offset in input array.
     * @param inEnd stop conversion at this offset in input array (exclusive).
     * @param output byte array to receive conversion result.
     * @param outStart start writing to output array at this offset.
     * @param outEnd stop writing to output array at this offset (exclusive).
     * @exception MalformedInputException if the input buffer contains any
     * sequence of chars that is illegal in Unicode (principally unpaired
     * surrogates and \uFFFF or \uFFFE). After this exception is thrown,
     * the method nextCharIndex can be called to obtain the index of the
     * first invalid input character.  The MalformedInputException can
     * be queried for the length of the invalid input.
     * @exception UnknownCharacterException for any character that
     * that cannot be converted to the external character encoding. Thrown
     * only when converter is not in substitution mode.
     * @exception ConversionBufferFullException if output array is filled prior
     * to converting all the input.
     */

   
public abstract int convert(char[] input, int inStart, int inEnd,
                               
byte[] output, int outStart, int outEnd)
       
throws MalformedInputException,
               
UnknownCharacterException,
               
ConversionBufferFullException;

   
/*
     * Converts any array of characters, including malformed surrogate
     * pairs, into an array of bytes in the target character encoding.
     * A precondition is that substitution mode is turned on. This method
     * allows a buffer by buffer conversion of a data stream.
     * The state of the conversion is saved between calls to convert.
     * All conversions should be finished with a call to the flushAny method.
     *
     * @return the number of bytes written to output.
     * @param input array containing Unicode characters to be converted.
     * @param inStart begin conversion at this offset in input array.
     * @param inEnd stop conversion at this offset in input array (exclusive).
     * @param output byte array to receive conversion result.
     * @param outStart start writing to output array at this offset.
     * @param outEnd stop writing to output array at this offset (exclusive).
     * @exception ConversionBufferFullException if output array is filled prior
     * to converting all the input.
     */

   
public int convertAny(char[] input, int inStart, int inEnd,
                         
byte[] output, int outStart, int outEnd)
       
throws ConversionBufferFullException
   
{
       
if (!subMode) {             /* Precondition: subMode == true */
           
throw new IllegalStateException("Substitution mode is not on");
       
}
       
/* Rely on the untested precondition that the indices are meaningful */
       
/* For safety, use the public interface to charOff and byteOff, but
           badInputLength is directly modified.*/

       
int localInOff = inStart;
       
int localOutOff = outStart;
       
while(localInOff < inEnd) {
           
try {
               
int discard = convert(input, localInOff, inEnd,
                                      output
, localOutOff, outEnd);
               
return (nextByteIndex() - outStart);
           
} catch (MalformedInputException e) {
               
byte[] s = subBytes;
               
int subSize = s.length;
                localOutOff
= nextByteIndex();
               
if ((localOutOff + subSize) > outEnd)
                   
throw new ConversionBufferFullException();
               
for (int i = 0; i < subSize; i++)
                    output
[localOutOff++] = s[i];
                localInOff
= nextCharIndex();
                localInOff
+= badInputLength;
                badInputLength
= 0;
               
if (localInOff >= inEnd){
                    byteOff
= localOutOff;
                   
return (byteOff - outStart);
               
}
               
continue;
           
}catch (UnknownCharacterException e) {
               
/* Should never occur, since subMode == true */
               
throw new Error("UnknownCharacterException thrown "
                               
+ "in substititution mode",
                                e
);
           
}
       
}
       
return (nextByteIndex() - outStart);
   
}



   
/**
     * Converts an array of Unicode characters into an array of bytes
     * in the target character encoding.  Unlike convert, this method
     * does not do incremental conversion.  It assumes that the given
     * input array contains all the characters to be converted. The
     * state of the converter is reset at the beginning of this method
     * and is left in the reset state on successful termination.
     * The converter is not reset if an exception is thrown.
     * This allows the caller to determine where the bad input
     * was encountered by calling nextCharIndex.
     * <p>
     * This method uses substitution mode when performing the conversion.
     * The method setSubstitutionBytes may be used to determine what
     * bytes are substituted.  Even though substitution mode is used,
     * the state of the converter's substitution mode is not changed
     * at the end of this method.
     *
     * @return an array of bytes containing the converted characters.
     * @param input array containing Unicode characters to be converted.
     * @exception MalformedInputException if the input buffer contains any
     * sequence of chars that is illegal in Unicode (principally unpaired
     * surrogates and \uFFFF or \uFFFE). After this exception is thrown,
     * the method nextCharIndex can be called to obtain the index of the
     * first invalid input character and getBadInputLength can be called
     * to determine the length of the invalid input.
     *
     * @see   #nextCharIndex
     * @see   #setSubstitutionMode
     * @see   #setSubstitutionBytes
     * @see   #getBadInputLength
     */

   
public byte[] convertAll( char input[] ) throws MalformedInputException {
        reset
();
       
boolean savedSubMode = subMode;
        subMode
= true;

       
byte[] output = new byte[ getMaxBytesPerChar() * input.length ];

       
try {
           
int outputLength = convert( input, 0, input.length,
                                        output
, 0, output.length );
            outputLength
+= flush( output, nextByteIndex(), output.length );

           
byte [] returnedOutput = new byte[ outputLength ];
           
System.arraycopy( output, 0, returnedOutput, 0, outputLength );
           
return returnedOutput;
       
}
       
catch( ConversionBufferFullException e ) {
           
//Not supposed to happen.  If it does, getMaxBytesPerChar() lied.
           
throw new
               
InternalError("this.getMaxBytesPerChar returned bad value");
       
}
       
catch( UnknownCharacterException e ) {
           
// Not supposed to happen since we're in substitution mode.
           
throw new InternalError();
       
}
       
finally {
            subMode
= savedSubMode;
       
}
   
}

   
/**
     * Writes any remaining output to the output buffer and resets the
     * converter to its initial state.
     *
     * @param output byte array to receive flushed output.
     * @param outStart start writing to output array at this offset.
     * @param outEnd stop writing to output array at this offset (exclusive).
     * @exception MalformedInputException if the output to be flushed contained
     * a partial or invalid multibyte character sequence.  Will occur if the
     * input buffer on the last call to convert ended with the first character
     * of a surrogate pair. flush will write what it can to the output buffer
     * and reset the converter before throwing this exception.  An additional
     * call to flush is not required.
     * @exception ConversionBufferFullException if output array is filled
     * before all the output can be flushed. flush will write what it can
     * to the output buffer and remember its state.  An additional call to
     * flush with a new output buffer will conclude the operation.
     */

   
public abstract int flush( byte[] output, int outStart, int outEnd )
       
throws MalformedInputException, ConversionBufferFullException;

   
/**
     * Writes any remaining output to the output buffer and resets the
     * converter to its initial state. May only be called when substitution
     * mode is turned on, and never complains about malformed input (always
     * substitutes).
     *
     * @param output byte array to receive flushed output.
     * @param outStart start writing to output array at this offset.
     * @param outEnd stop writing to output array at this offset (exclusive).
     * @return number of bytes writter into output.
     * @exception ConversionBufferFullException if output array is filled
     * before all the output can be flushed. flush will write what it can
     * to the output buffer and remember its state.  An additional call to
     * flush with a new output buffer will conclude the operation.
     */

   
public int flushAny( byte[] output, int outStart, int outEnd )
       
throws ConversionBufferFullException
   
{
       
if (!subMode) {             /* Precondition: subMode == true */
           
throw new IllegalStateException("Substitution mode is not on");
       
}
       
try {
           
return flush(output, outStart, outEnd);
       
} catch (MalformedInputException e) {
           
/* Assume that if a malformed input exception has occurred,
               no useful data has been placed in the output buffer.
               i.e. there is no mixture of left over good + some bad data.
               Usually occurs with a trailing high surrogate pair element.
               Special cases occur in Cp970, 949c and 933 that seem
               to be covered, but may require further investigation */

           
int subSize = subBytes.length;
           
byte[] s = subBytes;
           
int outIndex = outStart;
           
if ((outStart + subSize) > outEnd)
               
throw new ConversionBufferFullException();
           
for (int i = 0; i < subSize; i++)
                output
[outIndex++] = s[i];
            byteOff
= charOff = 0; // Reset the internal state.
            badInputLength
= 0;
           
return subSize;
       
}
   
}

   
/**
     * Resets converter to its initial state.
     */

   
public abstract void reset();

   
/**
     * Returns true if the given character can be converted to the
     * target character encoding.
     * @return true if given character is translatable, false otherwise.
     * @param c character to test
     */

   
public boolean canConvert(char c) {
       
try {
           
//FIXME output buffer size should use getMaxBytesPerChar value.
           
char[] input = new char[1];
           
byte[] output = new byte[3];
            input
[0] = c;
            convert
(input, 0, 1, output, 0, 3);
           
return true;
       
} catch(CharConversionException e){
           
return false;
       
}
   
}

   
/**
     * Returns the maximum number of bytes needed to convert a char. Useful
     * for calculating the maximum output buffer size needed for a particular
     * input buffer.
     */

   
public abstract int getMaxBytesPerChar();

   
/**
     * Returns the length, in chars, of the input which caused a
     * MalformedInputException.  Always refers to the last
     * MalformedInputException thrown by the converter.  If none have
     * ever been thrown, returns 0.
     */

   
public int getBadInputLength() {
       
return badInputLength;
   
}

   
/**
     * Returns the index of the character just past
     * the last character successfully converted by the previous call
     * to convert.
     */

   
public int nextCharIndex() {
       
return charOff;
   
}

   
/**
     * Returns the index of the byte just past the last byte written by
     * the previous call to convert.
     */

   
public int nextByteIndex() {
       
return byteOff;
   
}

   
/**
     * Sets converter into substitution mode.  In substitution mode,
     * the converter will replace untranslatable characters in the source
     * encoding with the substitution character set by setSubstitutionBytes.
     * When not in substitution mode, the converter will throw an
     * UnknownCharacterException when it encounters untranslatable input.
     *
     * @param doSub if true, enable substitution mode.
     * @see #setSubstitutionBytes
     */

   
public void setSubstitutionMode(boolean doSub) {
        subMode
= doSub;
   
}

   
/**
     * Sets the substitution bytes to use when the converter is in
     * substitution mode.  The given bytes should represent a valid
     * character in the target character encoding and must not be
     * longer than the value returned by getMaxBytesPerChar for this
     * converter.
     *
     * @param newSubBytes the substitution bytes
     * @exception IllegalArgumentException if given byte array is longer than
     *    the value returned by the method getMaxBytesPerChar.
     * @see #setSubstitutionMode
     * @see #getMaxBytesPerChar
     */

   
public void setSubstitutionBytes( byte[] newSubBytes )
       
throws IllegalArgumentException
   
{
       
if( newSubBytes.length > getMaxBytesPerChar() ) {
           
throw new IllegalArgumentException();
       
}

        subBytes
= new byte[ newSubBytes.length ];
       
System.arraycopy( newSubBytes, 0, subBytes, 0, newSubBytes.length );
   
}

   
/**
     * Returns a string representation of the class.
     */

   
public String toString() {
       
return "CharToByteConverter: " + getCharacterEncoding();
   
}
}