/* * Copyright (c) 1995, 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.misc; import java.io.OutputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.PushbackInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.ByteBuffer; /** * This class defines the decoding half of character encoders. * A character decoder is an algorithim for transforming 8 bit * binary data that has been encoded into text by a character * encoder, back into original binary form. * * The character encoders, in general, have been structured * around a central theme that binary data can be encoded into * text that has the form: * *
 *      [Buffer Prefix]
 *      [Line Prefix][encoded data atoms][Line Suffix]
 *      [Buffer Suffix]
 * 
* * Of course in the simplest encoding schemes, the buffer has no * distinct prefix of suffix, however all have some fixed relationship * between the text in an 'atom' and the binary data itself. * * In the CharacterEncoder and CharacterDecoder classes, one complete * chunk of data is referred to as a buffer. Encoded buffers * are all text, and decoded buffers (sometimes just referred to as * buffers) are binary octets. * * To create a custom decoder, you must, at a minimum, overide three * abstract methods in this class. *
*
bytesPerAtom which tells the decoder how many bytes to * expect from decodeAtom *
decodeAtom which decodes the bytes sent to it as text. *
bytesPerLine which tells the encoder the maximum number of * bytes per line. *
* * In general, the character decoders return error in the form of a * CEFormatException. The syntax of the detail string is *
 *      DecoderClassName: Error message.
 * 
* * Several useful decoders have already been written and are * referenced in the See Also list below. * * @author Chuck McManis * @see CEFormatException * @see CharacterEncoder * @see UCDecoder * @see UUDecoder * @see BASE64Decoder */ public abstract class CharacterDecoder { /** Return the number of bytes per atom of decoding */ abstract protected int bytesPerAtom(); /** Return the maximum number of bytes that can be encoded per line */ abstract protected int bytesPerLine(); /** decode the beginning of the buffer, by default this is a NOP. */ protected void decodeBufferPrefix(PushbackInputStream aStream, OutputStream bStream) throws IOException { } /** decode the buffer suffix, again by default it is a NOP. */ protected void decodeBufferSuffix(PushbackInputStream aStream, OutputStream bStream) throws IOException { } /** * This method should return, if it knows, the number of bytes * that will be decoded. Many formats such as uuencoding provide * this information. By default we return the maximum bytes that * could have been encoded on the line. */ protected int decodeLinePrefix(PushbackInputStream aStream, OutputStream bStream) throws IOException { return (bytesPerLine()); } /** * This method post processes the line, if there are error detection * or correction codes in a line, they are generally processed by * this method. The simplest version of this method looks for the * (newline) character. */ protected void decodeLineSuffix(PushbackInputStream aStream, OutputStream bStream) throws IOException { } /** * This method does an actual decode. It takes the decoded bytes and * writes them to the OutputStream. The integer l tells the * method how many bytes are required. This is always <= bytesPerAtom(). */ protected void decodeAtom(PushbackInputStream aStream, OutputStream bStream, int l) throws IOException { throw new CEStreamExhausted(); } /** * This method works around the bizarre semantics of BufferedInputStream's * read method. */ protected int readFully(InputStream in, byte buffer[], int offset, int len) throws java.io.IOException { for (int i = 0; i < len; i++) { int q = in.read(); if (q == -1) return ((i == 0) ? -1 : i); buffer[i+offset] = (byte)q; } return len; } /** * Decode the text from the InputStream and write the decoded * octets to the OutputStream. This method runs until the stream * is exhausted. * @exception CEFormatException An error has occured while decoding * @exception CEStreamExhausted The input stream is unexpectedly out of data */ public void decodeBuffer(InputStream aStream, OutputStream bStream) throws IOException { int i; int totalBytes = 0; PushbackInputStream ps = new PushbackInputStream (aStream); decodeBufferPrefix(ps, bStream); while (true) { int length; try { length = decodeLinePrefix(ps, bStream); for (i = 0; (i+bytesPerAtom()) < length; i += bytesPerAtom()) { decodeAtom(ps, bStream, bytesPerAtom()); totalBytes += bytesPerAtom(); } if ((i + bytesPerAtom()) == length) { decodeAtom(ps, bStream, bytesPerAtom()); totalBytes += bytesPerAtom(); } else { decodeAtom(ps, bStream, length - i); totalBytes += (length - i); } decodeLineSuffix(ps, bStream); } catch (CEStreamExhausted e) { break; } } decodeBufferSuffix(ps, bStream); } /** * Alternate decode interface that takes a String containing the encoded * buffer and returns a byte array containing the data. * @exception CEFormatException An error has occured while decoding */ public byte decodeBuffer(String inputString)[] throws IOException { byte inputBuffer[] = new byte[inputString.length()]; ByteArrayInputStream inStream; ByteArrayOutputStream outStream; inputString.getBytes(0, inputString.length(), inputBuffer, 0); inStream = new ByteArrayInputStream(inputBuffer); outStream = new ByteArrayOutputStream(); decodeBuffer(inStream, outStream); return (outStream.toByteArray()); } /** * Decode the contents of the inputstream into a buffer. */ public byte decodeBuffer(InputStream in)[] throws IOException { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); decodeBuffer(in, outStream); return (outStream.toByteArray()); } /** * Decode the contents of the String into a ByteBuffer. */ public ByteBuffer decodeBufferToByteBuffer(String inputString) throws IOException { return ByteBuffer.wrap(decodeBuffer(inputString)); } /** * Decode the contents of the inputStream into a ByteBuffer. */ public ByteBuffer decodeBufferToByteBuffer(InputStream in) throws IOException { return ByteBuffer.wrap(decodeBuffer(in)); } }