Home | History | Annotate | Download | only in net
      1 /*
      2  * Copyright 2001-2004 The Apache Software Foundation.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package org.apache.commons.codec.net;
     18 
     19 import java.io.ByteArrayOutputStream;
     20 import java.io.UnsupportedEncodingException;
     21 import java.util.BitSet;
     22 import org.apache.commons.codec.BinaryDecoder;
     23 import org.apache.commons.codec.BinaryEncoder;
     24 import org.apache.commons.codec.DecoderException;
     25 import org.apache.commons.codec.EncoderException;
     26 import org.apache.commons.codec.StringDecoder;
     27 import org.apache.commons.codec.StringEncoder;
     28 
     29 /**
     30  * <p>
     31  * Codec for the Quoted-Printable section of <a href="http://www.ietf.org/rfc/rfc1521.txt">RFC 1521 </a>.
     32  * </p>
     33  * <p>
     34  * The Quoted-Printable encoding is intended to represent data that largely consists of octets that correspond to
     35  * printable characters in the ASCII character set. It encodes the data in such a way that the resulting octets are
     36  * unlikely to be modified by mail transport. If the data being encoded are mostly ASCII text, the encoded form of the
     37  * data remains largely recognizable by humans. A body which is entirely ASCII may also be encoded in Quoted-Printable
     38  * to ensure the integrity of the data should the message pass through a character- translating, and/or line-wrapping
     39  * gateway.
     40  * </p>
     41  *
     42  * <p>
     43  * Note:
     44  * </p>
     45  * <p>
     46  * Rules #3, #4, and #5 of the quoted-printable spec are not implemented yet because the complete quoted-printable spec
     47  * does not lend itself well into the byte[] oriented codec framework. Complete the codec once the steamable codec
     48  * framework is ready. The motivation behind providing the codec in a partial form is that it can already come in handy
     49  * for those applications that do not require quoted-printable line formatting (rules #3, #4, #5), for instance Q codec.
     50  * </p>
     51  *
     52  * @see <a href="http://www.ietf.org/rfc/rfc1521.txt"> RFC 1521 MIME (Multipurpose Internet Mail Extensions) Part One:
     53  *          Mechanisms for Specifying and Describing the Format of Internet Message Bodies </a>
     54  *
     55  * @author Apache Software Foundation
     56  * @since 1.3
     57  * @version $Id: QuotedPrintableCodec.java,v 1.7 2004/04/09 22:21:07 ggregory Exp $
     58  *
     59  * @deprecated Please use {@link java.net.URL#openConnection} instead.
     60  *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
     61  *     for further details.
     62  */
     63 @Deprecated
     64 public class QuotedPrintableCodec implements BinaryEncoder, BinaryDecoder, StringEncoder, StringDecoder {
     65     /**
     66      * The default charset used for string decoding and encoding.
     67      */
     68     private String charset = StringEncodings.UTF8;
     69 
     70     /**
     71      * BitSet of printable characters as defined in RFC 1521.
     72      */
     73     private static final BitSet PRINTABLE_CHARS = new BitSet(256);
     74 
     75     private static byte ESCAPE_CHAR = '=';
     76 
     77     private static byte TAB = 9;
     78 
     79     private static byte SPACE = 32;
     80     // Static initializer for printable chars collection
     81     static {
     82         // alpha characters
     83         for (int i = 33; i <= 60; i++) {
     84             PRINTABLE_CHARS.set(i);
     85         }
     86         for (int i = 62; i <= 126; i++) {
     87             PRINTABLE_CHARS.set(i);
     88         }
     89         PRINTABLE_CHARS.set(TAB);
     90         PRINTABLE_CHARS.set(SPACE);
     91     }
     92 
     93     /**
     94      * Default constructor.
     95      */
     96     public QuotedPrintableCodec() {
     97         super();
     98     }
     99 
    100     /**
    101      * Constructor which allows for the selection of a default charset
    102      *
    103      * @param charset
    104      *                  the default string charset to use.
    105      */
    106     public QuotedPrintableCodec(String charset) {
    107         super();
    108         this.charset = charset;
    109     }
    110 
    111     /**
    112      * Encodes byte into its quoted-printable representation.
    113      *
    114      * @param b
    115      *                  byte to encode
    116      * @param buffer
    117      *                  the buffer to write to
    118      */
    119     private static final void encodeQuotedPrintable(int b, ByteArrayOutputStream buffer) {
    120         buffer.write(ESCAPE_CHAR);
    121         char hex1 = Character.toUpperCase(Character.forDigit((b >> 4) & 0xF, 16));
    122         char hex2 = Character.toUpperCase(Character.forDigit(b & 0xF, 16));
    123         buffer.write(hex1);
    124         buffer.write(hex2);
    125     }
    126 
    127     /**
    128      * Encodes an array of bytes into an array of quoted-printable 7-bit characters. Unsafe characters are escaped.
    129      *
    130      * <p>
    131      * This function implements a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in
    132      * RFC 1521 and is suitable for encoding binary data and unformatted text.
    133      * </p>
    134      *
    135      * @param printable
    136      *                  bitset of characters deemed quoted-printable
    137      * @param bytes
    138      *                  array of bytes to be encoded
    139      * @return array of bytes containing quoted-printable data
    140      */
    141     public static final byte[] encodeQuotedPrintable(BitSet printable, byte[] bytes) {
    142         if (bytes == null) {
    143             return null;
    144         }
    145         if (printable == null) {
    146             printable = PRINTABLE_CHARS;
    147         }
    148         ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    149         for (int i = 0; i < bytes.length; i++) {
    150             int b = bytes[i];
    151             if (b < 0) {
    152                 b = 256 + b;
    153             }
    154             if (printable.get(b)) {
    155                 buffer.write(b);
    156             } else {
    157                 encodeQuotedPrintable(b, buffer);
    158             }
    159         }
    160         return buffer.toByteArray();
    161     }
    162 
    163     /**
    164      * Decodes an array quoted-printable characters into an array of original bytes. Escaped characters are converted
    165      * back to their original representation.
    166      *
    167      * <p>
    168      * This function implements a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in
    169      * RFC 1521.
    170      * </p>
    171      *
    172      * @param bytes
    173      *                  array of quoted-printable characters
    174      * @return array of original bytes
    175      * @throws DecoderException
    176      *                  Thrown if quoted-printable decoding is unsuccessful
    177      */
    178     public static final byte[] decodeQuotedPrintable(byte[] bytes) throws DecoderException {
    179         if (bytes == null) {
    180             return null;
    181         }
    182         ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    183         for (int i = 0; i < bytes.length; i++) {
    184             int b = bytes[i];
    185             if (b == ESCAPE_CHAR) {
    186                 try {
    187                     int u = Character.digit((char) bytes[++i], 16);
    188                     int l = Character.digit((char) bytes[++i], 16);
    189                     if (u == -1 || l == -1) {
    190                         throw new DecoderException("Invalid quoted-printable encoding");
    191                     }
    192                     buffer.write((char) ((u << 4) + l));
    193                 } catch (ArrayIndexOutOfBoundsException e) {
    194                     throw new DecoderException("Invalid quoted-printable encoding");
    195                 }
    196             } else {
    197                 buffer.write(b);
    198             }
    199         }
    200         return buffer.toByteArray();
    201     }
    202 
    203     /**
    204      * Encodes an array of bytes into an array of quoted-printable 7-bit characters. Unsafe characters are escaped.
    205      *
    206      * <p>
    207      * This function implements a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in
    208      * RFC 1521 and is suitable for encoding binary data and unformatted text.
    209      * </p>
    210      *
    211      * @param bytes
    212      *                  array of bytes to be encoded
    213      * @return array of bytes containing quoted-printable data
    214      */
    215     public byte[] encode(byte[] bytes) {
    216         return encodeQuotedPrintable(PRINTABLE_CHARS, bytes);
    217     }
    218 
    219     /**
    220      * Decodes an array of quoted-printable characters into an array of original bytes. Escaped characters are converted
    221      * back to their original representation.
    222      *
    223      * <p>
    224      * This function implements a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in
    225      * RFC 1521.
    226      * </p>
    227      *
    228      * @param bytes
    229      *                  array of quoted-printable characters
    230      * @return array of original bytes
    231      * @throws DecoderException
    232      *                  Thrown if quoted-printable decoding is unsuccessful
    233      */
    234     public byte[] decode(byte[] bytes) throws DecoderException {
    235         return decodeQuotedPrintable(bytes);
    236     }
    237 
    238     /**
    239      * Encodes a string into its quoted-printable form using the default string charset. Unsafe characters are escaped.
    240      *
    241      * <p>
    242      * This function implements a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in
    243      * RFC 1521 and is suitable for encoding binary data.
    244      * </p>
    245      *
    246      * @param pString
    247      *                  string to convert to quoted-printable form
    248      * @return quoted-printable string
    249      *
    250      * @throws EncoderException
    251      *                  Thrown if quoted-printable encoding is unsuccessful
    252      *
    253      * @see #getDefaultCharset()
    254      */
    255     public String encode(String pString) throws EncoderException {
    256         if (pString == null) {
    257             return null;
    258         }
    259         try {
    260             return encode(pString, getDefaultCharset());
    261         } catch (UnsupportedEncodingException e) {
    262             throw new EncoderException(e.getMessage());
    263         }
    264     }
    265 
    266     /**
    267      * Decodes a quoted-printable string into its original form using the specified string charset. Escaped characters
    268      * are converted back to their original representation.
    269      *
    270      * @param pString
    271      *                  quoted-printable string to convert into its original form
    272      * @param charset
    273      *                  the original string charset
    274      * @return original string
    275      * @throws DecoderException
    276      *                  Thrown if quoted-printable decoding is unsuccessful
    277      * @throws UnsupportedEncodingException
    278      *                  Thrown if charset is not supported
    279      */
    280     public String decode(String pString, String charset) throws DecoderException, UnsupportedEncodingException {
    281         if (pString == null) {
    282             return null;
    283         }
    284         return new String(decode(pString.getBytes(StringEncodings.US_ASCII)), charset);
    285     }
    286 
    287     /**
    288      * Decodes a quoted-printable string into its original form using the default string charset. Escaped characters are
    289      * converted back to their original representation.
    290      *
    291      * @param pString
    292      *                  quoted-printable string to convert into its original form
    293      * @return original string
    294      * @throws DecoderException
    295      *                  Thrown if quoted-printable decoding is unsuccessful
    296      * @throws UnsupportedEncodingException
    297      *                  Thrown if charset is not supported
    298      * @see #getDefaultCharset()
    299      */
    300     public String decode(String pString) throws DecoderException {
    301         if (pString == null) {
    302             return null;
    303         }
    304         try {
    305             return decode(pString, getDefaultCharset());
    306         } catch (UnsupportedEncodingException e) {
    307             throw new DecoderException(e.getMessage());
    308         }
    309     }
    310 
    311     /**
    312      * Encodes an object into its quoted-printable safe form. Unsafe characters are escaped.
    313      *
    314      * @param pObject
    315      *                  string to convert to a quoted-printable form
    316      * @return quoted-printable object
    317      * @throws EncoderException
    318      *                  Thrown if quoted-printable encoding is not applicable to objects of this type or if encoding is
    319      *                  unsuccessful
    320      */
    321     public Object encode(Object pObject) throws EncoderException {
    322         if (pObject == null) {
    323             return null;
    324         } else if (pObject instanceof byte[]) {
    325             return encode((byte[]) pObject);
    326         } else if (pObject instanceof String) {
    327             return encode((String) pObject);
    328         } else {
    329             throw new EncoderException("Objects of type "
    330                 + pObject.getClass().getName()
    331                 + " cannot be quoted-printable encoded");
    332         }
    333     }
    334 
    335     /**
    336      * Decodes a quoted-printable object into its original form. Escaped characters are converted back to their original
    337      * representation.
    338      *
    339      * @param pObject
    340      *                  quoted-printable object to convert into its original form
    341      * @return original object
    342      * @throws DecoderException
    343      *                  Thrown if quoted-printable decoding is not applicable to objects of this type if decoding is
    344      *                  unsuccessful
    345      */
    346     public Object decode(Object pObject) throws DecoderException {
    347         if (pObject == null) {
    348             return null;
    349         } else if (pObject instanceof byte[]) {
    350             return decode((byte[]) pObject);
    351         } else if (pObject instanceof String) {
    352             return decode((String) pObject);
    353         } else {
    354             throw new DecoderException("Objects of type "
    355                 + pObject.getClass().getName()
    356                 + " cannot be quoted-printable decoded");
    357         }
    358     }
    359 
    360     /**
    361      * Returns the default charset used for string decoding and encoding.
    362      *
    363      * @return the default string charset.
    364      */
    365     public String getDefaultCharset() {
    366         return this.charset;
    367     }
    368 
    369     /**
    370      * Encodes a string into its quoted-printable form using the specified charset. Unsafe characters are escaped.
    371      *
    372      * <p>
    373      * This function implements a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in
    374      * RFC 1521 and is suitable for encoding binary data and unformatted text.
    375      * </p>
    376      *
    377      * @param pString
    378      *                  string to convert to quoted-printable form
    379      * @param charset
    380      *                  the charset for pString
    381      * @return quoted-printable string
    382      *
    383      * @throws UnsupportedEncodingException
    384      *                  Thrown if the charset is not supported
    385      */
    386     public String encode(String pString, String charset) throws UnsupportedEncodingException {
    387         if (pString == null) {
    388             return null;
    389         }
    390         return new String(encode(pString.getBytes(charset)), StringEncodings.US_ASCII);
    391     }
    392 }
    393