    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017
    018    package org.apache.commons.codec.net;
    019
    020    import java.io.UnsupportedEncodingException;
    021    import java.nio.charset.Charset;
    022
    023    import org.apache.commons.codec.Charsets;
    024    import org.apache.commons.codec.DecoderException;
    025    import org.apache.commons.codec.EncoderException;
    026    import org.apache.commons.codec.StringDecoder;
    027    import org.apache.commons.codec.StringEncoder;
    028    import org.apache.commons.codec.binary.Base64;
    029
    030    /**
    031     * Identical to the Base64 encoding defined by <a href="http://www.ietf.org/rfc/rfc1521.txt">RFC 1521</a>
    032     * and allows a character set to be specified.
    033     * <p>
    034     * <a href="http://www.ietf.org/rfc/rfc1522.txt">RFC 1522</a> describes techniques to allow the encoding of non-ASCII
    035     * text in various portions of a RFC 822 [2] message header, in a manner which is unlikely to confuse existing message
    036     * handling software.
    037     * <p>
    038     * This class is immutable and thread-safe.
    039     *
    040     * @see <a href="http://www.ietf.org/rfc/rfc1522.txt">MIME (Multipurpose Internet Mail Extensions) Part Two: Message
    041     *          Header Extensions for Non-ASCII Text</a>
    042     *
    043     * @since 1.3
    044     * @version $Id: BCodec.java 1429868 2013-01-07 16:08:05Z ggregory $
    045     */
    046    public class BCodec extends RFC1522Codec implements StringEncoder, StringDecoder {
    047        /**
    048         * The default charset used for string decoding and encoding.
    049         */
    050        private final Charset charset;
    051
    052        /**
    053         * Default constructor.
    054         */
    055        public BCodec() {
    056            this(Charsets.UTF_8);
    057        }
    058
    059        /**
    060         * Constructor which allows for the selection of a default charset
    061         *
    062         * @param charset
    063         *            the default string charset to use.
    064         *
    065         * @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
    066         * @since 1.7
    067         */
    068        public BCodec(final Charset charset) {
    069            this.charset = charset;
    070        }
    071
    072        /**
    073         * Constructor which allows for the selection of a default charset
    074         *
    075         * @param charsetName
    076         *            the default charset to use.
    077         * @throws java.nio.charset.UnsupportedCharsetException
    078         *             If the named charset is unavailable
    079         * @since 1.7 throws UnsupportedCharsetException if the named charset is unavailable
    080         * @see <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Standard charsets</a>
    081         */
    082        public BCodec(final String charsetName) {
    083            this(Charset.forName(charsetName));
    084        }
    085
    086        @Override
    087        protected String getEncoding() {
    088            return "B";
    089        }
    090
    091        @Override
    092        protected byte[] doEncoding(final byte[] bytes) {
    093            if (bytes == null) {
    094                return null;
    095            }
    096            return Base64.encodeBase64(bytes);
    097        }
    098
    099        @Override
    100        protected byte[] doDecoding(final byte[] bytes) {
    101            if (bytes == null) {
    102                return null;
    103            }
    104            return Base64.decodeBase64(bytes);
    105        }
    106
    107        /**
    108         * Encodes a string into its Base64 form using the specified charset. Unsafe characters are escaped.
    109         *
    110         * @param value
    111         *            string to convert to Base64 form
    112         * @param charset
    113         *            the charset for <code>value</code>
    114         * @return Base64 string
    115         * @throws EncoderException
    116         *             thrown if a failure condition is encountered during the encoding process.
    117         * @since 1.7
    118         */
    119        public String encode(final String value, final Charset charset) throws EncoderException {
    120            if (value == null) {
    121                return null;
    122            }
    123            return encodeText(value, charset);
    124        }
    125
    126        /**
    127         * Encodes a string into its Base64 form using the specified charset. Unsafe characters are escaped.
    128         *
    129         * @param value
    130         *            string to convert to Base64 form
    131         * @param charset
    132         *            the charset for <code>value</code>
    133         * @return Base64 string
    134         * @throws EncoderException
    135         *             thrown if a failure condition is encountered during the encoding process.
    136         */
    137        public String encode(final String value, final String charset) throws EncoderException {
    138            if (value == null) {
    139                return null;
    140            }
    141            try {
    142                return this.encodeText(value, charset);
    143            } catch (final UnsupportedEncodingException e) {
    144                throw new EncoderException(e.getMessage(), e);
    145            }
    146        }
    147
    148        /**
    149         * Encodes a string into its Base64 form using the default charset. Unsafe characters are escaped.
    150         *
    151         * @param value
    152         *            string to convert to Base64 form
    153         * @return Base64 string
    154         * @throws EncoderException
    155         *             thrown if a failure condition is encountered during the encoding process.
    156         */
    157        @Override
    158        public String encode(final String value) throws EncoderException {
    159            if (value == null) {
    160                return null;
    161            }
    162            return encode(value, this.getCharset());
    163        }
    164
    165        /**
    166         * Decodes a Base64 string into its original form. Escaped characters are converted back to their original
    167         * representation.
    168         *
    169         * @param value
    170         *            Base64 string to convert into its original form
    171         * @return original string
    172         * @throws DecoderException
    173         *             A decoder exception is thrown if a failure condition is encountered during the decode process.
    174         */
    175        @Override
    176        public String decode(final String value) throws DecoderException {
    177            if (value == null) {
    178                return null;
    179            }
    180            try {
    181                return this.decodeText(value);
    182            } catch (final UnsupportedEncodingException e) {
    183                throw new DecoderException(e.getMessage(), e);
    184            }
    185        }
    186
    187        /**
    188         * Encodes an object into its Base64 form using the default charset. Unsafe characters are escaped.
    189         *
    190         * @param value
    191         *            object to convert to Base64 form
    192         * @return Base64 object
    193         * @throws EncoderException
    194         *             thrown if a failure condition is encountered during the encoding process.
    195         */
    196        @Override
    197        public Object encode(final Object value) throws EncoderException {
    198            if (value == null) {
    199                return null;
    200            } else if (value instanceof String) {
    201                return encode((String) value);
    202            } else {
    203                throw new EncoderException("Objects of type " +
    204                      value.getClass().getName() +
    205                      " cannot be encoded using BCodec");
    206            }
    207        }
    208
    209        /**
    210         * Decodes a Base64 object into its original form. Escaped characters are converted back to their original
    211         * representation.
    212         *
    213         * @param value
    214         *            Base64 object to convert into its original form
    215         * @return original object
    216         * @throws DecoderException
    217         *             Thrown if the argument is not a <code>String</code>. Thrown if a failure condition is encountered
    218         *             during the decode process.
    219         */
    220        @Override
    221        public Object decode(final Object value) throws DecoderException {
    222            if (value == null) {
    223                return null;
    224            } else if (value instanceof String) {
    225                return decode((String) value);
    226            } else {
    227                throw new DecoderException("Objects of type " +
    228                      value.getClass().getName() +
    229                      " cannot be decoded using BCodec");
    230            }
    231        }
    232
    233        /**
    234         * Gets the default charset name used for string decoding and encoding.
    235         *
    236         * @return the default charset name
    237         * @since 1.7
    238         */
    239        public Charset getCharset() {
    240            return this.charset;
    241        }
    242
    243        /**
    244         * Gets the default charset name used for string decoding and encoding.
    245         *
    246         * @return the default charset name
    247         */
    248        public String getDefaultCharset() {
    249            return this.charset.name();
    250        }
    251    }