Source code
Description: source: package: org.apache.commons.codec.net, class: BCodec

    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 *      https://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
    018package org.apache.commons.codec.net;
    019
    020import java.io.UnsupportedEncodingException;
    021import java.nio.charset.Charset;
    022import java.nio.charset.StandardCharsets;
    023import java.nio.charset.UnsupportedCharsetException;
    024
    025import org.apache.commons.codec.CodecPolicy;
    026import org.apache.commons.codec.DecoderException;
    027import org.apache.commons.codec.EncoderException;
    028import org.apache.commons.codec.StringDecoder;
    029import org.apache.commons.codec.StringEncoder;
    030import org.apache.commons.codec.binary.Base64;
    031import org.apache.commons.codec.binary.BaseNCodec;
    032
    033/**
    034 * Identical to the Base64 encoding defined by <a href="https://www.ietf.org/rfc/rfc1521.txt">RFC 1521</a>
    035 * and allows a character set to be specified.
    036 * <p>
    037 * <a href="https://www.ietf.org/rfc/rfc1522.txt">RFC 1522</a> describes techniques to allow the encoding of non-ASCII
    038 * text in various portions of a RFC 822 [2] message header, in a manner which is unlikely to confuse existing message
    039 * handling software.
    040 * </p>
    041 * <p>
    042 * This class is immutable and thread-safe.
    043 * </p>
    044 *
    045 * @see <a href="https://www.ietf.org/rfc/rfc1522.txt">MIME (Multipurpose Internet Mail Extensions) Part Two: Message
    046 *          Header Extensions for Non-ASCII Text</a>
    047 *
    048 * @since 1.3
    049 */
    050public class BCodec extends RFC1522Codec implements StringEncoder, StringDecoder {
    051
    052    /**
    053     * The default decoding policy is lenient.
    054     */
    055    private static final CodecPolicy DECODING_POLICY_DEFAULT = CodecPolicy.LENIENT;
    056
    057    /**
    058     * If true then decoding should throw an exception for impossible combinations of bits at the
    059     * end of the byte input. The default is to decode as much of them as possible.
    060     */
    061    private final CodecPolicy decodingPolicy;
    062
    063    /**
    064     * Constructs a new instance.
    065     */
    066    public BCodec() {
    067        this(StandardCharsets.UTF_8);
    068    }
    069
    070    /**
    071     * Constructs a new instance for the selection of a default Charset.
    072     *
    073     * @param charset
    074     *            the default string Charset to use.
    075     *
    076     * @see Charset
    077     * @since 1.7
    078     */
    079    public BCodec(final Charset charset) {
    080        this(charset, DECODING_POLICY_DEFAULT);
    081    }
    082
    083    /**
    084     * Constructs a new instance for the selection of a default Charset.
    085     *
    086     * @param charset
    087     *            the default string Charset to use.
    088     * @param decodingPolicy The decoding policy.
    089     * @see Charset
    090     * @since 1.15
    091     */
    092    public BCodec(final Charset charset, final CodecPolicy decodingPolicy) {
    093        super(charset);
    094        this.decodingPolicy = decodingPolicy;
    095    }
    096
    097    /**
    098     * Constructs a new instance for the selection of a default Charset.
    099     *
    100     * @param charsetName
    101     *            the default Charset to use.
    102     * @throws java.nio.charset.UnsupportedCharsetException
    103     *             If the named Charset is unavailable.
    104     * @since 1.7 throws UnsupportedCharsetException if the named Charset is unavailable
    105     * @see Charset
    106     */
    107    public BCodec(final String charsetName) {
    108        this(Charset.forName(charsetName));
    109    }
    110
    111    /**
    112     * Decodes a Base64 object into its original form. Escaped characters are converted back to their original
    113     * representation.
    114     *
    115     * @param value
    116     *            Base64 object to convert into its original form.
    117     * @return original object.
    118     * @throws DecoderException
    119     *             Thrown if the argument is not a {@code String}. Thrown if a failure condition is encountered
    120     *             during the decode process.
    121     */
    122    @Override
    123    public Object decode(final Object value) throws DecoderException {
    124        if (value == null) {
    125            return null;
    126        }
    127        if (value instanceof String) {
    128            return decode((String) value);
    129        }
    130        throw new DecoderException("Objects of type " + value.getClass().getName() + " cannot be decoded using BCodec");
    131    }
    132
    133    /**
    134     * Decodes a Base64 string into its original form. Escaped characters are converted back to their original
    135     * representation.
    136     *
    137     * @param value
    138     *            Base64 string to convert into its original form.
    139     * @return original string.
    140     * @throws DecoderException
    141     *             A decoder exception is thrown if a failure condition is encountered during the decode process.
    142     */
    143    @Override
    144    public String decode(final String value) throws DecoderException {
    145        try {
    146            return decodeText(value);
    147        } catch (final UnsupportedEncodingException | IllegalArgumentException e) {
    148            throw new DecoderException(e.getMessage(), e);
    149        }
    150    }
    151
    152    @Override
    153    protected byte[] doDecoding(final byte[] bytes) {
    154        if (bytes == null) {
    155            return null;
    156        }
    157        return Base64.builder().setLineLength(0).setLineSeparator(BaseNCodec.getChunkSeparator()).setUrlSafe(false).setDecodingPolicy(decodingPolicy).get()
    158                .decode(bytes);
    159    }
    160
    161    @Override
    162    protected byte[] doEncoding(final byte[] bytes) {
    163        if (bytes == null) {
    164            return null;
    165        }
    166        return Base64.encodeBase64(bytes);
    167    }
    168
    169    /**
    170     * Encodes an object into its Base64 form using the default Charset. Unsafe characters are escaped.
    171     *
    172     * @param value
    173     *            object to convert to Base64 form.
    174     * @return Base64 object.
    175     * @throws EncoderException
    176     *             thrown if a failure condition is encountered during the encoding process.
    177     */
    178    @Override
    179    public Object encode(final Object value) throws EncoderException {
    180        if (value == null) {
    181            return null;
    182        }
    183        if (value instanceof String) {
    184            return encode((String) value);
    185        }
    186        throw new EncoderException("Objects of type " + value.getClass().getName() + " cannot be encoded using BCodec");
    187    }
    188
    189    /**
    190     * Encodes a string into its Base64 form using the default Charset. Unsafe characters are escaped.
    191     *
    192     * @param strSource
    193     *            string to convert to Base64 form.
    194     * @return Base64 string.
    195     * @throws EncoderException
    196     *             thrown if a failure condition is encountered during the encoding process.
    197     */
    198    @Override
    199    public String encode(final String strSource) throws EncoderException {
    200        return encode(strSource, getCharset());
    201    }
    202
    203    /**
    204     * Encodes a string into its Base64 form using the specified Charset. Unsafe characters are escaped.
    205     *
    206     * @param strSource
    207     *            string to convert to Base64 form.
    208     * @param sourceCharset
    209     *            the Charset for {@code value}.
    210     * @return Base64 string.
    211     * @throws EncoderException
    212     *             thrown if a failure condition is encountered during the encoding process.
    213     * @since 1.7
    214     */
    215    public String encode(final String strSource, final Charset sourceCharset) throws EncoderException {
    216        return encodeText(strSource, sourceCharset);
    217    }
    218
    219    /**
    220     * Encodes a string into its Base64 form using the specified Charset. Unsafe characters are escaped.
    221     *
    222     * @param strSource
    223     *            string to convert to Base64 form.
    224     * @param sourceCharset
    225     *            the Charset for {@code value}.
    226     * @return Base64 string.
    227     * @throws EncoderException
    228     *             thrown if a failure condition is encountered during the encoding process.
    229     */
    230    public String encode(final String strSource, final String sourceCharset) throws EncoderException {
    231        try {
    232            return encodeText(strSource, sourceCharset);
    233        } catch (final UnsupportedCharsetException e) {
    234            throw new EncoderException(e.getMessage(), e);
    235        }
    236    }
    237
    238    @Override
    239    protected String getEncoding() {
    240        return "B";
    241    }
    242
    243    /**
    244     * Returns true if decoding behavior is strict. Decoding will raise a
    245     * {@link DecoderException} if trailing bits are not part of a valid Base64 encoding.
    246     *
    247     * <p>The default is false for lenient encoding. Decoding will compose trailing bits
    248     * into 8-bit bytes and discard the remainder.
    249     *
    250     * @return true if using strict decoding.
    251     * @since 1.15
    252     */
    253    public boolean isStrictDecoding() {
    254        return decodingPolicy == CodecPolicy.STRICT;
    255    }
    256}