Source code
Description: source: package: org.apache.commons.codec.binary, class: Base64, class: Builder

    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.binary;
    019
    020import java.math.BigInteger;
    021import java.util.Arrays;
    022import java.util.Objects;
    023
    024import org.apache.commons.codec.CodecPolicy;
    025
    026/**
    027 * Provides Base64 encoding and decoding as defined by <a href="https://www.ietf.org/rfc/rfc2045">RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part
    028 * One: Format of Internet Message Bodies</a> and portions of <a href="https://datatracker.ietf.org/doc/html/rfc4648">RFC 4648 The Base16, Base32, and Base64
    029 * Data Encodings</a>
    030 *
    031 * <p>
    032 * This class implements <a href="https://www.ietf.org/rfc/rfc2045#section-6.8">RFC 2045 6.8. Base64 Content-Transfer-Encoding</a>.
    033 * </p>
    034 * <p>
    035 * The class can be parameterized in the following manner with its {@link Builder}:
    036 * </p>
    037 * <ul>
    038 * <li>URL-safe mode: Default off.</li>
    039 * <li>Line length: Default 76. Line length that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
    040 * <li>Line separator: Default is CRLF ({@code "\r\n"})</li>
    041 * <li>Strict or lenient decoding policy; default is {@link CodecPolicy#LENIENT}.</li>
    042 * <li>Custom decoding table.</li>
    043 * <li>Custom encoding table.</li>
    044 * <li>Padding; defaults is {@code '='}.</li>
    045 * </ul>
    046 * <p>
    047 * The URL-safe parameter is only applied to encode operations. Decoding seamlessly handles both modes, see also
    048 * {@code Builder#setDecodeTableFormat(DecodeTableFormat)}.
    049 * </p>
    050 * <p>
    051 * Since this class operates directly on byte streams, and not character streams, it is hard-coded to only encode/decode character encodings which are
    052 * compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252, UTF-8, etc).
    053 * </p>
    054 * <p>
    055 * This class is thread-safe.
    056 * </p>
    057 * <p>
    058 * To configure a new instance, use a {@link Builder}. For example:
    059 * </p>
    060 *
    061 * <pre>
    062 * Base64 base64 = Base64.builder()
    063 *   .setDecodingPolicy(CodecPolicy.LENIENT)    // default is lenient, null resets to default
    064 *   .setEncodeTable(customEncodeTable)         // default is built in, null resets to default
    065 *   .setLineLength(0)                          // default is none
    066 *   .setLineSeparator('\r', '\n')              // default is CR LF, null resets to default
    067 *   .setPadding('=')                           // default is '='
    068 *   .setUrlSafe(false)                         // default is false
    069 *   .get()
    070 * </pre>
    071 *
    072 * @see Base64InputStream
    073 * @see Base64OutputStream
    074 * @see <a href="https://www.ietf.org/rfc/rfc2045">RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies</a>
    075 * @see <a href="https://datatracker.ietf.org/doc/html/rfc4648">RFC 4648 The Base16, Base32, and Base64 Data Encodings</a>
    076 * @since 1.0
    077 */
    078public class Base64 extends BaseNCodec {
    079
    080    /**
    081     * Builds {@link Base64} instances.
    082     *
    083     * <p>
    084     * To configure a new instance, use a {@link Builder}. For example:
    085     * </p>
    086     *
    087     * <pre>
    088     * Base64 base64 = Base64.builder()
    089     *   .setCodecPolicy(CodecPolicy.LENIENT)       // default is lenient, null resets to default
    090     *   .setEncodeTable(customEncodeTable)         // default is built in, null resets to default
    091     *   .setLineLength(0)                          // default is none
    092     *   .setLineSeparator('\r', '\n')              // default is CR LF, null resets to default
    093     *   .setPadding('=')                           // default is '='
    094     *   .setUrlSafe(false)                         // default is false
    095     *   .get()
    096     * </pre>
    097     *
    098     * @since 1.17.0
    099     */
    100    public static class Builder extends AbstractBuilder<Base64, Builder> {
    101
    102        /**
    103         * Constructs a new instance.
    104         */
    105        public Builder() {
    106            super(STANDARD_ENCODE_TABLE);
    107            setDecodeTableRaw(DECODE_TABLE);
    108            setEncodeTableRaw(STANDARD_ENCODE_TABLE);
    109            setEncodedBlockSize(BYTES_PER_ENCODED_BLOCK);
    110            setUnencodedBlockSize(BYTES_PER_UNENCODED_BLOCK);
    111        }
    112
    113        @Override
    114        public Base64 get() {
    115            return new Base64(this);
    116        }
    117
    118        /**
    119         * Sets the format of the decoding table. This method allows to explicitly state whether a standard or URL-safe Base64 decoding is expected. This method
    120         * does not modify behavior on encoding operations. For configuration of the encoding behavior, please use {@link #setUrlSafe(boolean)} method.
    121         * <p>
    122         * By default, the implementation uses the {@link DecodeTableFormat#MIXED} approach, allowing a seamless handling of both
    123         * {@link DecodeTableFormat#URL_SAFE} and {@link DecodeTableFormat#STANDARD} base64.
    124         * </p>
    125         *
    126         * @param format table format to be used on Base64 decoding. Use {@link DecodeTableFormat#MIXED} or null to reset to the default behavior.
    127         * @return {@code this} instance.
    128         * @since 1.21
    129         */
    130        public Builder setDecodeTableFormat(final DecodeTableFormat format) {
    131            if (format == null) {
    132                return setDecodeTableRaw(DECODE_TABLE);
    133            }
    134            switch (format) {
    135                case STANDARD:
    136                    return setDecodeTableRaw(STANDARD_DECODE_TABLE);
    137                case URL_SAFE:
    138                    return setDecodeTableRaw(URL_SAFE_DECODE_TABLE);
    139                case MIXED:
    140                default:
    141                    return setDecodeTableRaw(DECODE_TABLE);
    142            }
    143        }
    144
    145        /**
    146         * Sets the encode table.
    147         *
    148         * @param encodeTable The encode table with exactly 64 unique entries, null resets to the default.
    149         * @return {@code this} instance.
    150         * @throws IllegalArgumentException if {@code encodeTable} does not contain exactly 64 unique entries.
    151         */
    152        @Override
    153        public Builder setEncodeTable(final byte... encodeTable) {
    154            setDecodeTableRaw(toDecodeTable(encodeTable));
    155            return super.setEncodeTable(encodeTable);
    156        }
    157
    158        /**
    159         * Sets the URL-safe encoding policy.
    160         * <p>
    161         * This method does not modify behavior on decoding operations. For configuration of the decoding behavior, please use
    162         * {@code Builder.setDecodeTableFormat(DecodeTableFormat)} method.
    163         * </p>
    164         *
    165         * @param urlSafe URL-safe encoding policy.
    166         * @return {@code this} instance.
    167         */
    168        public Builder setUrlSafe(final boolean urlSafe) {
    169            // Javadoc 8 can't find {@link #setDecodeTableFormat(DecodeTableFormat)}
    170            return setEncodeTable(toUrlSafeEncodeTable(urlSafe));
    171        }
    172
    173    }
    174
    175    /**
    176     * Enumerates the Base64 table format to be used on decoding.
    177     * <p>
    178     * By default, the method uses {@link DecodeTableFormat#MIXED} approach, allowing a seamless handling of both {@link DecodeTableFormat#URL_SAFE} and
    179     * {@link DecodeTableFormat#STANDARD} base64 options.
    180     * </p>
    181     *
    182     * @since 1.21
    183     */
    184    public enum DecodeTableFormat {
    185
    186        /**
    187         * Corresponds to the standard Base64 coding table, as specified in
    188         * <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The Base64 Alphabet</a>.
    189         */
    190        STANDARD,
    191
    192        /**
    193         * Corresponds to the URL-safe Base64 coding table, as specified in
    194         * <a href="https://datatracker.ietf.org/doc/html/rfc4648#:~:text=Table%202%3A%20The%20%22URL%20and%20Filename%20safe%22%20Base%2064%20Alphabet">RFC
    195         * 4648 Table 2: The "URL and Filename safe" Base 64 Alphabet</a>.
    196         */
    197        URL_SAFE,
    198
    199        /**
    200         * Represents a joint approach, allowing a seamless decoding of both character sets, corresponding to either
    201         * <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The Base64 Alphabet</a> or
    202         * <a href="https://datatracker.ietf.org/doc/html/rfc4648#:~:text=Table%202%3A%20The%20%22URL%20and%20Filename%20safe%22%20Base%2064%20Alphabet">RFC
    203         * 4648 Table 2: The "URL and Filename safe" Base 64 Alphabet</a>. This decoding table is used by default.
    204         */
    205        MIXED
    206    }
    207
    208    /**
    209     * BASE64 characters are 6 bits in length.
    210     * They are formed by taking a block of 3 octets to form a 24-bit string,
    211     * which is converted into 4 BASE64 characters.
    212     */
    213    private static final int BITS_PER_ENCODED_BYTE = 6;
    214    private static final int BYTES_PER_UNENCODED_BLOCK = 3;
    215    private static final int BYTES_PER_ENCODED_BLOCK = 4;
    216    private static final int DECODING_TABLE_LENGTH = 256;
    217
    218    /**
    219     * This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet" equivalents as specified in
    220     * <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The Base64 Alphabet</a>.
    221     * <p>
    222     * Thanks to "commons" project in ws.apache.org for this code. https://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
    223     * </p>
    224     */
    225    // @formatter:off
    226    private static final byte[] STANDARD_ENCODE_TABLE = {
    227            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    228            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    229            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    230            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    231            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
    232    };
    233
    234    /**
    235     * This is a copy of the STANDARD_ENCODE_TABLE above, but with + and / changed to - and _ to make the encoded Base64 results more URL-SAFE. This table is
    236     * only used when the Base64's mode is set to URL-SAFE.
    237     */
    238    // @formatter:off
    239    private static final byte[] URL_SAFE_ENCODE_TABLE = {
    240            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    241            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    242            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    243            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    244            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
    245    };
    246    // @formatter:on
    247
    248    /**
    249     * This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified in
    250     * <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The Base64 Alphabet</a>) into their 6-bit
    251     * positive integer equivalents. Characters that are not in the Base64 or Base64 URL-safe alphabets but fall within the bounds of the array are translated
    252     * to -1.
    253     * <p>
    254     * The characters '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder seamlessly handles both URL_SAFE and STANDARD base64.
    255     * (The encoder, on the other hand, needs to know ahead of time what to emit).
    256     * </p>
    257     * <p>
    258     * Thanks to "commons" project in ws.apache.org for this code. https://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
    259     * </p>
    260     */
    261    private static final byte[] DECODE_TABLE = {
    262        //   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    263            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f
    264            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f
    265            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, // 20-2f + - /
    266            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 30-3f 0-9
    267            -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, // 40-4f A-O
    268            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, // 50-5f P-Z _
    269            -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 60-6f a-o
    270            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51                      // 70-7a p-z
    271    };
    272
    273    /**
    274     * This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified in
    275     * <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The Base64 Alphabet</a>) into their 6-bit
    276     * positive integer equivalents. Characters that are not in the Base64 alphabet but fall within the bounds of the array are translated to -1. This decoding
    277     * table handles only the standard base64 characters, such as '+' and '/'. The "url-safe" characters such as '-' and '_' are not supported by the table.
    278     */
    279    private static final byte[] STANDARD_DECODE_TABLE = {
    280        //   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    281            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f
    282            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f
    283            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, // 20-2f + /
    284            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 30-3f 0-9
    285            -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, // 40-4f A-O
    286            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, // 50-5f P-Z
    287            -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 60-6f a-o
    288            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51                      // 70-7a p-z
    289    };
    290
    291    /**
    292     * This array is a lookup table that translates Unicode characters drawn from the "Base64 URL-safe Alphabet" (as specified in
    293     * <a href="https://datatracker.ietf.org/doc/html/rfc4648#:~:text=Table%202%3A%20The%20%22URL%20and%20Filename%20safe%22%20Base%2064%20Alphabet">RFC 4648
    294     * Table 2: The "URL and Filename safe" Base 64 Alphabet</a>) into their 6-bit positive integer equivalents. Characters that are not in the Base64 URL-safe
    295     * alphabet but fall within the bounds of the array are translated to -1. This decoding table handles only the URL-safe base64 characters, such as '-' and
    296     * '_'. The standard characters such as '+' and '/' are not supported by the table.
    297     */
    298    private static final byte[] URL_SAFE_DECODE_TABLE = {
    299            //   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    300            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f
    301            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f
    302            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, // 20-2f -
    303            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 30-3f 0-9
    304            -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, // 40-4f A-O
    305            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, // 50-5f P-Z _
    306            -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 60-6f a-o
    307            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51                      // 70-7a p-z
    308    };
    309
    310    /**
    311     * Base64 uses 6-bit fields.
    312     */
    313
    314    /** Mask used to extract 6 bits, used when encoding */
    315    private static final int MASK_6_BITS = 0x3f;
    316
    317    // The static final fields above are used for the original static byte[] methods on Base64.
    318    // The private member fields below are used with the new streaming approach, which requires
    319    // some state be preserved between calls of encode() and decode().
    320
    321    /** Mask used to extract 4 bits, used when decoding final trailing character. */
    322    private static final int MASK_4_BITS = 0xf;
    323
    324    /** Mask used to extract 2 bits, used when decoding final trailing character. */
    325    private static final int MASK_2_BITS = 0x3;
    326
    327    /**
    328     * Creates a new Builder.
    329     *
    330     * <p>
    331     * To configure a new instance, use a {@link Builder}. For example:
    332     * </p>
    333     *
    334     * <pre>
    335     * Base64 base64 = Base64.builder()
    336     *   .setDecodingPolicy(CodecPolicy.LENIENT) // default is lenient, null resets to default
    337     *   .setEncodeTable(customEncodeTable)         // default is built in, null resets to default
    338     *   .setLineLength(0)                          // default is none
    339     *   .setLineSeparator('\r', '\n')              // default is CR LF, null resets to default
    340     *   .setPadding('=')                           // default is '='
    341     *   .setUrlSafe(false)                         // default is false
    342     *   .get()
    343     * </pre>
    344     *
    345     * @return A new Builder.
    346     * @since 1.17.0
    347     */
    348    public static Builder builder() {
    349        return new Builder();
    350    }
    351
    352    /**
    353     * Calculates a decode table for a given encode table.
    354     *
    355     * @param encodeTable that is used to determine decode lookup table.
    356     * @return A new decode table.
    357     */
    358    private static byte[] calculateDecodeTable(final byte[] encodeTable) {
    359        if (encodeTable.length != STANDARD_ENCODE_TABLE.length) {
    360            throw new IllegalArgumentException("encodeTable must have exactly 64 entries.");
    361        }
    362        final byte[] decodeTable = new byte[DECODING_TABLE_LENGTH];
    363        Arrays.fill(decodeTable, (byte) -1);
    364        for (int i = 0; i < encodeTable.length; i++) {
    365            final int encodedByte = encodeTable[i] & 0xff;
    366            if (decodeTable[encodedByte] != -1) {
    367                throw new IllegalArgumentException("encodeTable must not contain duplicate entries.");
    368            }
    369            decodeTable[encodedByte] = (byte) i;
    370        }
    371        return decodeTable;
    372    }
    373
    374    private static boolean contains(final byte[] bytes, final byte value) {
    375        for (final byte element : bytes) {
    376            if (element == value) {
    377                return true;
    378            }
    379        }
    380        return false;
    381    }
    382
    383    /**
    384     * Decodes Base64 data into octets.
    385     * <p>
    386     * This method seamlessly handles data encoded in URL-safe or normal mode. For enforcing verification against strict standard Base64 or Base64 URL-safe
    387     * tables, please use {@link #decodeBase64Standard(byte[])} or {@link #decodeBase64UrlSafe(byte[])} methods respectively. This method skips unknown or
    388     * unsupported bytes.
    389     * </p>
    390     *
    391     * @param base64Data Byte array containing Base64 data.
    392     * @return New array containing decoded data.
    393     */
    394    public static byte[] decodeBase64(final byte[] base64Data) {
    395        return new Base64().decode(base64Data);
    396    }
    397
    398    /**
    399     * Decodes a Base64 String into octets.
    400     * <p>
    401     * This method seamlessly handles data encoded in URL-safe or normal mode. For enforcing verification against strict standard Base64 or Base64 URL-safe
    402     * tables, please use {@link #decodeBase64Standard(String)} or {@link #decodeBase64UrlSafe(String)} methods respectively. This method skips unknown or
    403     * unsupported bytes.
    404     * </p>
    405     *
    406     * @param base64String String containing Base64 data.
    407     * @return New array containing decoded data.
    408     * @since 1.4
    409     */
    410    public static byte[] decodeBase64(final String base64String) {
    411        return new Base64().decode(base64String);
    412    }
    413
    414    /**
    415     * Decodes standard Base64 data into octets.
    416     * <p>
    417     * This implementation is aligned with the <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The
    418     * Base64 Alphabet</a>. This method skips unknown or unsupported bytes.
    419     * </p>
    420     *
    421     * @param base64Data Byte array containing Base64 data.
    422     * @return New array containing decoded data.
    423     * @since 1.21
    424     */
    425    public static byte[] decodeBase64Standard(final byte[] base64Data) {
    426        return builder().setDecodeTableFormat(DecodeTableFormat.STANDARD).get().decode(base64Data);
    427    }
    428
    429    /**
    430     * Decodes a standard Base64 String into octets.
    431     * <p>
    432     * This implementation is aligned with the <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The
    433     * Base64 Alphabet</a>. This method skips unknown or unsupported characters.
    434     * </p>
    435     *
    436     * @param base64String String containing Base64 data.
    437     * @return New array containing decoded data.
    438     * @since 1.21
    439     */
    440    public static byte[] decodeBase64Standard(final String base64String) {
    441        return builder().setDecodeTableFormat(DecodeTableFormat.STANDARD).get().decode(base64String);
    442    }
    443
    444    /**
    445     * Decodes URL-safe Base64 data into octets.
    446     * <p>
    447     * This implementation is aligned with
    448     * <a href="https://datatracker.ietf.org/doc/html/rfc4648#:~:text=Table%202%3A%20The%20%22URL%20and%20Filename%20safe%22%20Base%2064%20Alphabet">RFC 4648
    449     * Table 2: The "URL and Filename safe" Base 64 Alphabet</a>. This method skips unknown or unsupported characters.
    450     * </p>
    451     *
    452     * @param base64Data Byte array containing Base64 data.
    453     * @return New array containing decoded data.
    454     * @since 1.21
    455     */
    456    public static byte[] decodeBase64UrlSafe(final byte[] base64Data) {
    457        return builder().setDecodeTableFormat(DecodeTableFormat.URL_SAFE).get().decode(base64Data);
    458    }
    459
    460    /**
    461     * Decodes a URL-safe Base64 String into octets.
    462     * <p>
    463     * This implementation is aligned with
    464     * <a href="https://datatracker.ietf.org/doc/html/rfc4648#:~:text=Table%202%3A%20The%20%22URL%20and%20Filename%20safe%22%20Base%2064%20Alphabet">RFC 4648
    465     * Table 2: The "URL and Filename safe" Base 64 Alphabet</a>. This method skips unknown or unsupported characters.
    466     * </p>
    467     *
    468     * @param base64String String containing Base64 data.
    469     * @return New array containing decoded data.
    470     * @since 1.21
    471     */
    472    public static byte[] decodeBase64UrlSafe(final String base64String) {
    473        return builder().setDecodeTableFormat(DecodeTableFormat.URL_SAFE).get().decode(base64String);
    474    }
    475
    476    /**
    477     * Decodes a byte64-encoded integer according to crypto standards such as W3C's XML-Signature.
    478     *
    479     * @param array A byte array containing base64 character data.
    480     * @return A BigInteger.
    481     * @since 1.4
    482     */
    483    public static BigInteger decodeInteger(final byte[] array) {
    484        return new BigInteger(1, decodeBase64(array));
    485    }
    486
    487    /**
    488     * Encodes binary data using the base64 algorithm but does not chunk the output.
    489     *
    490     * @param binaryData binary data to encode.
    491     * @return byte[] containing Base64 characters in their UTF-8 representation.
    492     */
    493    public static byte[] encodeBase64(final byte[] binaryData) {
    494        return encodeBase64(binaryData, false);
    495    }
    496
    497    /**
    498     * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
    499     *
    500     * @param binaryData Array containing binary data to encode.
    501     * @param isChunked  if {@code true} this encoder will chunk the base64 output into 76 character blocks.
    502     * @return Base64-encoded data.
    503     * @throws IllegalArgumentException Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}.
    504     */
    505    public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked) {
    506        return encodeBase64(binaryData, isChunked, false);
    507    }
    508
    509    /**
    510     * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
    511     *
    512     * @param binaryData Array containing binary data to encode.
    513     * @param isChunked  if {@code true} this encoder will chunk the base64 output into 76 character blocks.
    514     * @param urlSafe    if {@code true} this encoder will emit - and _ instead of the usual + and / characters. <strong>No padding is added when encoding using
    515     *                   the URL-safe alphabet.</strong>
    516     * @return Base64-encoded data.
    517     * @throws IllegalArgumentException Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}.
    518     * @since 1.4
    519     */
    520    public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, final boolean urlSafe) {
    521        return encodeBase64(binaryData, isChunked, urlSafe, Integer.MAX_VALUE);
    522    }
    523
    524    /**
    525     * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
    526     *
    527     * @param binaryData    Array containing binary data to encode.
    528     * @param isChunked     if {@code true} this encoder will chunk the base64 output into 76 character blocks.
    529     * @param urlSafe       if {@code true} this encoder will emit - and _ instead of the usual + and / characters. <strong>No padding is added when encoding
    530     *                      using the URL-safe alphabet.</strong>
    531     * @param maxResultSize The maximum result size to accept.
    532     * @return Base64-encoded data.
    533     * @throws IllegalArgumentException Thrown when the input array needs an output array bigger than maxResultSize.
    534     * @since 1.4
    535     */
    536    public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, final boolean urlSafe, final int maxResultSize) {
    537        if (BinaryCodec.isEmpty(binaryData)) {
    538            return binaryData;
    539        }
    540        // Create this so can use the super-class method
    541        // Also ensures that the same roundings are performed by the ctor and the code
    542        final Base64 b64 = isChunked ? new Base64(urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe);
    543        final long len = b64.getEncodedLength(binaryData);
    544        if (len > maxResultSize) {
    545            throw new IllegalArgumentException(
    546                    "Input array too big, the output array would be bigger (" + len + ") than the specified maximum size of " + maxResultSize);
    547        }
    548        return b64.encode(binaryData);
    549    }
    550
    551    /**
    552     * Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks
    553     *
    554     * @param binaryData binary data to encode.
    555     * @return Base64 characters chunked in 76 character blocks.
    556     */
    557    public static byte[] encodeBase64Chunked(final byte[] binaryData) {
    558        return encodeBase64(binaryData, true);
    559    }
    560
    561    /**
    562     * Encodes binary data using the base64 algorithm but does not chunk the output.
    563     * <p>
    564     * <strong> We changed the behavior of this method from multi-line chunking (1.4) to single-line non-chunking (1.5).</strong>
    565     * </p>
    566     *
    567     * @param binaryData binary data to encode.
    568     * @return String containing Base64 characters.
    569     * @since 1.4 (NOTE: 1.4 chunked the output, whereas 1.5 does not).
    570     */
    571    public static String encodeBase64String(final byte[] binaryData) {
    572        return StringUtils.newStringUsAscii(encodeBase64(binaryData, false));
    573    }
    574
    575    /**
    576     * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The url-safe variation emits - and _ instead of +
    577     * and / characters. <strong>No padding is added.</strong>
    578     *
    579     * @param binaryData binary data to encode.
    580     * @return byte[] containing Base64 characters in their UTF-8 representation.
    581     * @since 1.4
    582     */
    583    public static byte[] encodeBase64URLSafe(final byte[] binaryData) {
    584        return encodeBase64(binaryData, false, true);
    585    }
    586
    587    /**
    588     * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The url-safe variation emits - and _ instead of +
    589     * and / characters. <strong>No padding is added.</strong>
    590     *
    591     * @param binaryData binary data to encode.
    592     * @return String containing Base64 characters.
    593     * @since 1.4
    594     */
    595    public static String encodeBase64URLSafeString(final byte[] binaryData) {
    596        return StringUtils.newStringUsAscii(encodeBase64(binaryData, false, true));
    597    }
    598
    599    /**
    600     * Encodes to a byte64-encoded integer according to crypto standards such as W3C's XML-Signature.
    601     *
    602     * @param bigInteger A BigInteger.
    603     * @return A byte array containing base64 character data.
    604     * @throws NullPointerException if null is passed in.
    605     * @since 1.4
    606     */
    607    public static byte[] encodeInteger(final BigInteger bigInteger) {
    608        Objects.requireNonNull(bigInteger, "bigInteger");
    609        return encodeBase64(toUnsignedBytes(bigInteger), false);
    610    }
    611
    612    /**
    613     * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the method treats whitespace as valid.
    614     *
    615     * @param arrayOctet byte array to test.
    616     * @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty; {@code false}, otherwise.
    617     * @deprecated 1.5 Use {@link #isBase64(byte[])}, will be removed in 2.0.
    618     */
    619    @Deprecated
    620    public static boolean isArrayByteBase64(final byte[] arrayOctet) {
    621        return isBase64(arrayOctet);
    622    }
    623
    624    /**
    625     * Tests whether or not the {@code octet} is in the Base64 alphabet.
    626     * <p>
    627     * This method threats all characters included within standard base64 and base64url encodings as valid base64 characters. This includes the '+' and '/'
    628     * (standard base64), as well as '-' and '_' (URL-safe base64) characters. For enforcing verification against strict standard Base64 or Base64 URL-safe
    629     * tables, please use {@link #isBase64Standard(byte)} or {@link #isBase64Url(byte)} methods respectively.
    630     * </p>
    631     *
    632     * @param octet The value to test.
    633     * @return {@code true} if the value is defined in the Base64 alphabet, {@code false} otherwise.
    634     * @since 1.4
    635     */
    636    public static boolean isBase64(final byte octet) {
    637        return octet == PAD_DEFAULT || octet >= 0 && octet < DECODE_TABLE.length && DECODE_TABLE[octet] != -1;
    638    }
    639
    640    /**
    641     * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the method treats whitespace as valid.
    642     * <p>
    643     * This method treats all characters included within standard base64 and base64url encodings as valid base64 characters. This includes the '+' and '/'
    644     * (standard base64), as well as '-' and '_' (URL-safe base64) characters. For enforcing verification against strict standard Base64 or Base64 URL-safe
    645     * tables, please use {@link #isBase64Standard(byte[])} or {@link #isBase64Url(byte[])} methods respectively.
    646     * </p>
    647     *
    648     * @param arrayOctet byte array to test.
    649     * @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty; {@code false}, otherwise.
    650     * @since 1.5
    651     */
    652    public static boolean isBase64(final byte[] arrayOctet) {
    653        for (final byte element : arrayOctet) {
    654            if (!isBase64(element) && !Character.isWhitespace(element)) {
    655                return false;
    656            }
    657        }
    658        return true;
    659    }
    660
    661    /**
    662     * Tests a given String to see if it contains only valid characters within the Base64 alphabet. Currently the method treats whitespace as valid.
    663     * <p>
    664     * This method threats all characters included within standard base64 and base64url encodings as valid base64 characters. This includes the '+' and '/'
    665     * (standard base64), as well as '-' and '_' (URL-safe base64) characters. For enforcing verification against strict standard Base64 or Base64 URL-safe
    666     * tables, please use {@link #isBase64Standard(String)} or {@link #isBase64Url(String)} methods respectively.
    667     * </p>
    668     *
    669     * @param base64 String to test.
    670     * @return {@code true} if all characters in the String are valid characters in the Base64 alphabet or if the String is empty; {@code false}, otherwise.
    671     * @since 1.5
    672     */
    673    public static boolean isBase64(final String base64) {
    674        return isBase64(StringUtils.getBytesUtf8(base64));
    675    }
    676
    677    /**
    678     * Tests whether or not the {@code octet} is in the standard Base64 alphabet.
    679     * <p>
    680     * This implementation is aligned with <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The
    681     * Base64 Alphabet</a>.
    682     * </p>
    683     *
    684     * @param octet The value to test.
    685     * @return {@code true} if the value is defined in the standard Base64 alphabet, {@code false} otherwise.
    686     * @since 1.21
    687     */
    688    public static boolean isBase64Standard(final byte octet) {
    689        return octet == PAD_DEFAULT || octet >= 0 && octet < STANDARD_DECODE_TABLE.length && STANDARD_DECODE_TABLE[octet] != -1;
    690    }
    691
    692    /**
    693     * Tests a given byte array to see if it contains only valid characters within the standard Base64 alphabet. The method treats whitespace as valid.
    694     * <p>
    695     * This implementation is aligned with <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The
    696     * Base64 Alphabet</a>.
    697     * </p>
    698     *
    699     * @param arrayOctet byte array to test.
    700     * @return {@code true} if all bytes are valid characters in the standard Base64 alphabet. {@code false}, otherwise.
    701     * @since 1.21
    702     */
    703    public static boolean isBase64Standard(final byte[] arrayOctet) {
    704        for (final byte element : arrayOctet) {
    705            if (!isBase64Standard(element) && !Character.isWhitespace(element)) {
    706                return false;
    707            }
    708        }
    709        return true;
    710    }
    711
    712    /**
    713     * Tests a given String to see if it contains only valid characters within the standard Base64 alphabet. The method treats whitespace as valid.
    714     * <p>
    715     * This implementation is aligned with <a href="https://www.ietf.org/rfc/rfc2045#:~:text=Table%201%3A%20The%20Base64%20Alphabet">RFC 2045 Table 1: The
    716     * Base64 Alphabet</a>.
    717     * </p>
    718     *
    719     * @param base64 String to test.
    720     * @return {@code true} if all characters in the String are valid characters in the standard Base64 alphabet or if the String is empty; {@code false},
    721     *         otherwise.
    722     * @since 1.21
    723     */
    724    public static boolean isBase64Standard(final String base64) {
    725        return isBase64Standard(StringUtils.getBytesUtf8(base64));
    726    }
    727
    728    /**
    729     * Tests whether or not the {@code octet} is in the URL-safe Base64 alphabet.
    730     * <p>
    731     * This implementation is aligned with
    732     * <a href="https://datatracker.ietf.org/doc/html/rfc4648#:~:text=Table%202%3A%20The%20%22URL%20and%20Filename%20safe%22%20Base%2064%20Alphabet">RFC 4648
    733     * Table 2: The "URL and Filename safe" Base 64 Alphabet</a>.
    734     * </p>
    735     *
    736     * @param octet The value to test.
    737     * @return {@code true} if the value is defined in the URL-safe Base64 alphabet, {@code false} otherwise.
    738     * @since 1.21
    739     */
    740    public static boolean isBase64Url(final byte octet) {
    741        return octet == PAD_DEFAULT || octet >= 0 && octet < URL_SAFE_DECODE_TABLE.length && URL_SAFE_DECODE_TABLE[octet] != -1;
    742    }
    743
    744    /**
    745     * Tests a given byte array to see if it contains only valid characters within the URL-safe Base64 alphabet. The method treats whitespace as valid.
    746     * <p>
    747     * This implementation is aligned with
    748     * <a href="https://datatracker.ietf.org/doc/html/rfc4648#:~:text=Table%202%3A%20The%20%22URL%20and%20Filename%20safe%22%20Base%2064%20Alphabet">RFC 4648
    749     * Table 2: The "URL and Filename safe" Base 64 Alphabet</a>.
    750     * </p>
    751     *
    752     * @param arrayOctet byte array to test.
    753     * @return {@code true} if all bytes are valid characters in the URL-safe Base64 alphabet, {@code false}, otherwise.
    754     * @since 1.21
    755     */
    756    public static boolean isBase64Url(final byte[] arrayOctet) {
    757        for (final byte element : arrayOctet) {
    758            if (!isBase64Url(element) && !Character.isWhitespace(element)) {
    759                return false;
    760            }
    761        }
    762        return true;
    763    }
    764
    765    /**
    766     * Tests a given String to see if it contains only valid characters within the URL-safe Base64 alphabet. The method treats whitespace as valid.
    767     * <p>
    768     * This implementation is aligned with
    769     * <a href="https://datatracker.ietf.org/doc/html/rfc4648#:~:text=Table%202%3A%20The%20%22URL%20and%20Filename%20safe%22%20Base%2064%20Alphabet">RFC 4648
    770     * Table 2: The "URL and Filename safe" Base 64 Alphabet</a>.
    771     * </p>
    772     *
    773     * @param base64 String to test.
    774     * @return {@code true} if all characters in the String are valid characters in the URL-safe Base64 alphabet or if the String is empty; {@code false},
    775     *         otherwise.
    776     * @since 1.21
    777     */
    778    public static boolean isBase64Url(final String base64) {
    779        return isBase64Url(StringUtils.getBytesUtf8(base64));
    780    }
    781
    782    private static byte[] toDecodeTable(final byte[] encodeTable) {
    783        final byte[] table = encodeTable != null ? encodeTable : STANDARD_ENCODE_TABLE;
    784        if (Arrays.equals(table, STANDARD_ENCODE_TABLE) || Arrays.equals(table, URL_SAFE_ENCODE_TABLE)) {
    785            return DECODE_TABLE;
    786        }
    787        return calculateDecodeTable(table);
    788    }
    789
    790    static byte[] toUrlSafeEncodeTable(final boolean urlSafe) {
    791        return urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE;
    792    }
    793
    794    /**
    795     * Line separator for encoding. Not used when decoding. Only used if lineLength &gt; 0.
    796     */
    797    private final byte[] lineSeparator;
    798
    799    /**
    800     * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing. {@code encodeSize = 4 + lineSeparator.length;}
    801     */
    802    private final int encodeSize;
    803    private final boolean isUrlSafe;
    804    private final boolean isStandardEncodeTable;
    805
    806    /**
    807     * Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
    808     * <p>
    809     * When encoding the line length is 0 (no chunking), and the encoding table is STANDARD_ENCODE_TABLE.
    810     * </p>
    811     * <p>
    812     * When decoding all variants are supported.
    813     * </p>
    814     */
    815    public Base64() {
    816        this(0);
    817    }
    818
    819    /**
    820     * Constructs a Base64 codec used for decoding (all modes) and encoding in the given URL-safe mode.
    821     * <p>
    822     * When encoding the line length is 76, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE.
    823     * </p>
    824     * <p>
    825     * When decoding all variants are supported.
    826     * </p>
    827     *
    828     * @param urlSafe if {@code true}, URL-safe encoding is used. In most cases this should be set to {@code false}.
    829     * @since 1.4
    830     * @deprecated Use {@link #builder()} and {@link Builder}.
    831     */
    832    @Deprecated
    833    public Base64(final boolean urlSafe) {
    834        this(MIME_CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe);
    835    }
    836
    837    private Base64(final Builder builder) {
    838        super(builder);
    839        final byte[] encTable = builder.getEncodeTable();
    840        if (encTable.length != STANDARD_ENCODE_TABLE.length) {
    841            throw new IllegalArgumentException("encodeTable must have exactly 64 entries.");
    842        }
    843        if (contains(encTable, pad)) {
    844            throw new IllegalArgumentException("encodeTable must not contain the padding byte.");
    845        }
    846        this.isStandardEncodeTable = Arrays.equals(encTable, STANDARD_ENCODE_TABLE);
    847        this.isUrlSafe = Arrays.equals(encTable, URL_SAFE_ENCODE_TABLE);
    848        // TODO could be simplified if there is no requirement to reject invalid line sep when length <=0
    849        // @see test case Base64Test.testConstructors()
    850        if (builder.getLineSeparator().length > 0) {
    851            final byte[] lineSeparatorB = builder.getLineSeparator();
    852            if (containsAlphabetOrPad(lineSeparatorB)) {
    853                final String sep = StringUtils.newStringUtf8(lineSeparatorB);
    854                throw new IllegalArgumentException("lineSeparator must not contain base64 characters: [" + sep + "]");
    855            }
    856            if (builder.getLineLength() > 0) { // null line-sep forces no chunking rather than throwing IAE
    857                this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparatorB.length;
    858                this.lineSeparator = lineSeparatorB;
    859            } else {
    860                this.encodeSize = BYTES_PER_ENCODED_BLOCK;
    861                this.lineSeparator = null;
    862            }
    863        } else {
    864            this.encodeSize = BYTES_PER_ENCODED_BLOCK;
    865            this.lineSeparator = null;
    866        }
    867    }
    868
    869    /**
    870     * Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
    871     * <p>
    872     * When encoding the line length is given in the constructor, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE.
    873     * </p>
    874     * <p>
    875     * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
    876     * </p>
    877     * <p>
    878     * When decoding all variants are supported.
    879     * </p>
    880     *
    881     * @param lineLength Each line of encoded data will be at most of the given length (rounded down to the nearest multiple of 4). If lineLength &lt;= 0, then
    882     *                   the output will not be divided into lines (chunks). Ignored when decoding.
    883     * @since 1.4
    884     * @deprecated Use {@link #builder()} and {@link Builder}.
    885     */
    886    @Deprecated
    887    public Base64(final int lineLength) {
    888        this(lineLength, CHUNK_SEPARATOR);
    889    }
    890
    891    /**
    892     * Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
    893     * <p>
    894     * When encoding the line length and line separator are given in the constructor, and the encoding table is STANDARD_ENCODE_TABLE.
    895     * </p>
    896     * <p>
    897     * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
    898     * </p>
    899     * <p>
    900     * When decoding all variants are supported.
    901     * </p>
    902     *
    903     * @param lineLength    Each line of encoded data will be at most of the given length (rounded down to the nearest multiple of 4). If lineLength &lt;= 0,
    904     *                      then the output will not be divided into lines (chunks). Ignored when decoding.
    905     * @param lineSeparator Each line of encoded data will end with this sequence of bytes.
    906     * @throws IllegalArgumentException Thrown when the provided lineSeparator included some base64 characters.
    907     * @since 1.4
    908     * @deprecated Use {@link #builder()} and {@link Builder}.
    909     */
    910    @Deprecated
    911    public Base64(final int lineLength, final byte[] lineSeparator) {
    912        this(lineLength, lineSeparator, false);
    913    }
    914
    915    /**
    916     * Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
    917     * <p>
    918     * When encoding the line length and line separator are given in the constructor, and the encoding table is STANDARD_ENCODE_TABLE.
    919     * </p>
    920     * <p>
    921     * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
    922     * </p>
    923     * <p>
    924     * When decoding all variants are supported.
    925     * </p>
    926     *
    927     * @param lineLength    Each line of encoded data will be at most of the given length (rounded down to the nearest multiple of 4). If lineLength &lt;= 0,
    928     *                      then the output will not be divided into lines (chunks). Ignored when decoding.
    929     * @param lineSeparator Each line of encoded data will end with this sequence of bytes.
    930     * @param urlSafe       Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode operations. Decoding seamlessly
    931     *                      handles both modes. <strong>No padding is added when using the URL-safe alphabet.</strong>
    932     * @throws IllegalArgumentException Thrown when the {@code lineSeparator} contains Base64 characters.
    933     * @since 1.4
    934     * @deprecated Use {@link #builder()} and {@link Builder}.
    935     */
    936    @Deprecated
    937    public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe) {
    938        this(builder().setLineLength(lineLength).setLineSeparator(lineSeparator != null ? lineSeparator : EMPTY_BYTE_ARRAY).setPadding(PAD_DEFAULT)
    939                .setEncodeTableRaw(toUrlSafeEncodeTable(urlSafe)).setDecodingPolicy(DECODING_POLICY_DEFAULT));
    940    }
    941
    942    /**
    943     * Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
    944     * <p>
    945     * When encoding the line length and line separator are given in the constructor, and the encoding table is STANDARD_ENCODE_TABLE.
    946     * </p>
    947     * <p>
    948     * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
    949     * </p>
    950     * <p>
    951     * When decoding all variants are supported.
    952     * </p>
    953     *
    954     * @param lineLength     Each line of encoded data will be at most of the given length (rounded down to the nearest multiple of 4). If lineLength &lt;= 0,
    955     *                       then the output will not be divided into lines (chunks). Ignored when decoding.
    956     * @param lineSeparator  Each line of encoded data will end with this sequence of bytes.
    957     * @param urlSafe        Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode operations. Decoding seamlessly
    958     *                       handles both modes. <strong>No padding is added when using the URL-safe alphabet.</strong>
    959     * @param decodingPolicy The decoding policy.
    960     * @throws IllegalArgumentException Thrown when the {@code lineSeparator} contains Base64 characters.
    961     * @since 1.15
    962     * @deprecated Use {@link #builder()} and {@link Builder}.
    963     */
    964    @Deprecated
    965    public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe, final CodecPolicy decodingPolicy) {
    966        this(builder().setLineLength(lineLength).setLineSeparator(lineSeparator).setPadding(PAD_DEFAULT).setEncodeTableRaw(toUrlSafeEncodeTable(urlSafe))
    967                .setDecodingPolicy(decodingPolicy));
    968    }
    969
    970    /**
    971     * <p>
    972     * Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once with the data to decode, and once with
    973     * inAvail set to "-1" to alert decoder that EOF has been reached. The "-1" call is not necessary when decoding, but it doesn't hurt, either.
    974     * </p>
    975     * <p>
    976     * Ignores all non-base64 characters. This is how chunked (for example 76 character) data is handled, since CR and LF are silently ignored, but has
    977     * implications for other bytes, too. This method subscribes to the garbage-in, garbage-out philosophy: it will not check the provided data for validity.
    978     * </p>
    979     * <p>
    980     * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach.
    981     * https://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
    982     * </p>
    983     *
    984     * @param input   byte[] array of ASCII data to base64 decode.
    985     * @param inPos   Position to start reading data from.
    986     * @param inAvail Amount of bytes available from input for decoding.
    987     * @param context The context to be used.
    988     */
    989    @Override
    990    void decode(final byte[] input, int inPos, final int inAvail, final Context context) {
    991        if (context.eof) {
    992            return;
    993        }
    994        if (inAvail < 0) {
    995            context.eof = true;
    996        }
    997        final int decodeSize = this.encodeSize - 1;
    998        for (int i = 0; i < inAvail; i++) {
    999            final int b = input[inPos++] & 0xff;
    1000            if (b == (pad & 0xff)) {
    1001                // We're done.
    1002                context.eof = true;
    1003                break;
    1004            }
    1005            final byte[] buffer = ensureBufferSize(decodeSize, context);
    1006            if (b < decodeTable.length) {
    1007                final int result = decodeTable[b];
    1008                if (result >= 0) {
    1009                    context.modulus = (context.modulus + 1) % BYTES_PER_ENCODED_BLOCK;
    1010                    context.ibitWorkArea = (context.ibitWorkArea << BITS_PER_ENCODED_BYTE) + result;
    1011                    if (context.modulus == 0) {
    1012                        buffer[context.pos++] = (byte) (context.ibitWorkArea >> 16 & MASK_8BITS);
    1013                        buffer[context.pos++] = (byte) (context.ibitWorkArea >> 8 & MASK_8BITS);
    1014                        buffer[context.pos++] = (byte) (context.ibitWorkArea & MASK_8BITS);
    1015                    }
    1016                }
    1017            }
    1018        }
    1019
    1020        // Two forms of EOF as far as base64 decoder is concerned: actual
    1021        // EOF (-1) and first time '=' character is encountered in stream.
    1022        // This approach makes the '=' padding characters completely optional.
    1023        if (context.eof && context.modulus != 0) {
    1024            final byte[] buffer = ensureBufferSize(decodeSize, context);
    1025
    1026            // We have some spare bits remaining
    1027            // Output all whole multiples of 8 bits and ignore the rest
    1028            switch (context.modulus) {
    1029//              case 0 : // impossible, as excluded above
    1030                case 1 : // 6 bits - either ignore entirely, or raise an exception
    1031                    validateTrailingCharacter();
    1032                    break;
    1033                case 2 : // 12 bits = 8 + 4
    1034                    validateCharacter(MASK_4_BITS, context);
    1035                    context.ibitWorkArea = context.ibitWorkArea >> 4; // dump the extra 4 bits
    1036                    buffer[context.pos++] = (byte) (context.ibitWorkArea & MASK_8BITS);
    1037                    break;
    1038                case 3 : // 18 bits = 8 + 8 + 2
    1039                    validateCharacter(MASK_2_BITS, context);
    1040                    context.ibitWorkArea = context.ibitWorkArea >> 2; // dump 2 bits
    1041                    buffer[context.pos++] = (byte) (context.ibitWorkArea >> 8 & MASK_8BITS);
    1042                    buffer[context.pos++] = (byte) (context.ibitWorkArea & MASK_8BITS);
    1043                    break;
    1044                default:
    1045                    throw new IllegalStateException("Impossible modulus " + context.modulus);
    1046            }
    1047        }
    1048    }
    1049
    1050    /**
    1051     * <p>
    1052     * Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with the data to encode, and once with
    1053     * inAvail set to "-1" to alert encoder that EOF has been reached, to flush last remaining bytes (if not multiple of 3).
    1054     * </p>
    1055     * <p>
    1056     * <strong>No padding is added when encoding using the URL-safe alphabet.</strong>
    1057     * </p>
    1058     * <p>
    1059     * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach.
    1060     * https://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
    1061     * </p>
    1062     *
    1063     * @param in      byte[] array of binary data to base64 encode.
    1064     * @param inPos   Position to start reading data from.
    1065     * @param inAvail Amount of bytes available from input for encoding.
    1066     * @param context The context to be used.
    1067     */
    1068    @Override
    1069    void encode(final byte[] in, int inPos, final int inAvail, final Context context) {
    1070        if (context.eof) {
    1071            return;
    1072        }
    1073        // inAvail < 0 is how we're informed of EOF in the underlying data we're
    1074        // encoding.
    1075        if (inAvail < 0) {
    1076            context.eof = true;
    1077            if (0 == context.modulus && lineLength == 0) {
    1078                return; // no leftovers to process and not using chunking
    1079            }
    1080            final byte[] buffer = ensureBufferSize(encodeSize, context);
    1081            final int savedPos = context.pos;
    1082            switch (context.modulus) { // 0-2
    1083                case 0 : // nothing to do here
    1084                    break;
    1085                case 1 : // 8 bits = 6 + 2
    1086                    // top 6 bits:
    1087                    buffer[context.pos++] = encodeTable[context.ibitWorkArea >> 2 & MASK_6_BITS];
    1088                    // remaining 2:
    1089                    buffer[context.pos++] = encodeTable[context.ibitWorkArea << 4 & MASK_6_BITS];
    1090                    // URL-SAFE skips the padding to further reduce size.
    1091                    if (isStandardEncodeTable) {
    1092                        buffer[context.pos++] = pad;
    1093                        buffer[context.pos++] = pad;
    1094                    }
    1095                    break;
    1096
    1097                case 2 : // 16 bits = 6 + 6 + 4
    1098                    buffer[context.pos++] = encodeTable[context.ibitWorkArea >> 10 & MASK_6_BITS];
    1099                    buffer[context.pos++] = encodeTable[context.ibitWorkArea >> 4 & MASK_6_BITS];
    1100                    buffer[context.pos++] = encodeTable[context.ibitWorkArea << 2 & MASK_6_BITS];
    1101                    // URL-SAFE skips the padding to further reduce size.
    1102                    if (isStandardEncodeTable) {
    1103                        buffer[context.pos++] = pad;
    1104                    }
    1105                    break;
    1106                default:
    1107                    throw new IllegalStateException("Impossible modulus " + context.modulus);
    1108            }
    1109            context.currentLinePos += context.pos - savedPos; // keep track of current line position
    1110            // if currentPos == 0 we are at the start of a line, so don't add CRLF
    1111            if (lineLength > 0 && context.currentLinePos > 0) {
    1112                System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length);
    1113                context.pos += lineSeparator.length;
    1114            }
    1115        } else {
    1116            for (int i = 0; i < inAvail; i++) {
    1117                final byte[] buffer = ensureBufferSize(encodeSize, context);
    1118                context.modulus = (context.modulus + 1) % BYTES_PER_UNENCODED_BLOCK;
    1119                int b = in[inPos++];
    1120                if (b < 0) {
    1121                    b += 256;
    1122                }
    1123                context.ibitWorkArea = (context.ibitWorkArea << 8) + b; // BITS_PER_BYTE
    1124                if (0 == context.modulus) { // 3 bytes = 24 bits = 4 * 6 bits to extract
    1125                    buffer[context.pos++] = encodeTable[context.ibitWorkArea >> 18 & MASK_6_BITS];
    1126                    buffer[context.pos++] = encodeTable[context.ibitWorkArea >> 12 & MASK_6_BITS];
    1127                    buffer[context.pos++] = encodeTable[context.ibitWorkArea >> 6 & MASK_6_BITS];
    1128                    buffer[context.pos++] = encodeTable[context.ibitWorkArea & MASK_6_BITS];
    1129                    context.currentLinePos += BYTES_PER_ENCODED_BLOCK;
    1130                    if (lineLength > 0 && lineLength <= context.currentLinePos) {
    1131                        System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length);
    1132                        context.pos += lineSeparator.length;
    1133                        context.currentLinePos = 0;
    1134                    }
    1135                }
    1136            }
    1137        }
    1138    }
    1139
    1140    /**
    1141     * Gets the line separator (for testing only).
    1142     *
    1143     * @return The line separator.
    1144     */
    1145    byte[] getLineSeparator() {
    1146        return lineSeparator;
    1147    }
    1148
    1149    /**
    1150     * Returns whether or not the {@code octet} is in the Base64 alphabet.
    1151     *
    1152     * @param octet The value to test.
    1153     * @return {@code true} if the value is defined in the Base64 alphabet {@code false} otherwise.
    1154     */
    1155    @Override
    1156    protected boolean isInAlphabet(final byte octet) {
    1157        final int value = octet & 0xff;
    1158        return value < decodeTable.length && decodeTable[value] != -1;
    1159    }
    1160
    1161    /**
    1162     * Returns our current encode mode. True if we're URL-safe, false otherwise.
    1163     *
    1164     * @return true if we're in URL-safe mode, false otherwise.
    1165     * @since 1.4
    1166     */
    1167    public boolean isUrlSafe() {
    1168        return isUrlSafe;
    1169    }
    1170
    1171    /**
    1172     * Validates whether decoding the final trailing character is possible in the context of the set of possible Base64 values.
    1173     * <p>
    1174     * The character is valid if the lower bits within the provided mask are zero. This is used to test the final trailing base-64 digit is zero in the bits
    1175     * that will be discarded.
    1176     * </p>
    1177     *
    1178     * @param emptyBitsMask The mask of the lower bits that should be empty.
    1179     * @param context       The context to be used.
    1180     * @throws IllegalArgumentException if the bits being checked contain any non-zero value.
    1181     */
    1182    private void validateCharacter(final int emptyBitsMask, final Context context) {
    1183        if (isStrictDecoding() && (context.ibitWorkArea & emptyBitsMask) != 0) {
    1184            throw new IllegalArgumentException("Strict decoding: Last encoded character (before the paddings if any) is a valid " +
    1185                    "Base64 alphabet but not a possible encoding. Expected the discarded bits from the character to be zero.");
    1186        }
    1187    }
    1188
    1189    /**
    1190     * Validates whether decoding allows an entire final trailing character that cannot be used for a complete byte.
    1191     *
    1192     * @throws IllegalArgumentException if strict decoding is enabled.
    1193     */
    1194    private void validateTrailingCharacter() {
    1195        if (isStrictDecoding()) {
    1196            throw new IllegalArgumentException("Strict decoding: Last encoded character (before the paddings if any) is a valid " +
    1197                    "Base64 alphabet but not a possible encoding. Decoding requires at least two trailing 6-bit characters to create bytes.");
    1198        }
    1199    }
    1200
    1201}