    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
    018package org.apache.commons.net.util;
    019
    020import java.math.BigInteger;
    021import java.nio.charset.StandardCharsets;
    022
    023
    024/**
    025 * Provides Base64 encoding and decoding as defined by RFC 2045.
    026 *
    027 * <p>
    028 * This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite> from RFC 2045 <cite>Multipurpose
    029 * Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies</cite> by Freed and Borenstein.
    030 * </p>
    031 * <p>
    032 * The class can be parameterized in the following manner with various constructors:
    033 * <ul>
    034 * <li>URL-safe mode: Default off.</li>
    035 * <li>Line length: Default 76. Line length that aren't multiples of 4 will still essentially end up being multiples of
    036 * 4 in the encoded data.
    037 * <li>Line separator: Default is CRLF ("\r\n")</li>
    038 * </ul>
    039 * <p>
    040 * Since this class operates directly on byte streams, and not character streams, it is hard-coded to only encode/decode
    041 * character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252, UTF-8, etc).
    042 * </p>
    043 *
    044 * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>
    045 * @since 2.2
    046 */
    047public class Base64 {
    048    private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2;
    049
    050    private static final int DEFAULT_BUFFER_SIZE = 8192;
    051
    052    /**
    053     * Chunk size per RFC 2045 section 6.8.
    054     *
    055     * <p>
    056     * The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any
    057     * equal signs.
    058     * </p>
    059     *
    060     * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 6.8</a>
    061     */
    062    static final int CHUNK_SIZE = 76;
    063
    064    /**
    065     * Chunk separator per RFC 2045 section 2.1.
    066     *
    067     * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a>
    068     */
    069    private static final byte[] CHUNK_SEPARATOR = {'\r', '\n'};
    070
    071    /**
    072     * This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet"
    073     * equivalents as specified in Table 1 of RFC 2045.
    074     *
    075     * Thanks to "commons" project in ws.apache.org for this code.
    076     * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
    077     */
    078    private static final byte[] STANDARD_ENCODE_TABLE = {
    079            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    080            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    081            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    082            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    083            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
    084    };
    085
    086    /**
    087     * This is a copy of the STANDARD_ENCODE_TABLE above, but with + and /
    088     * changed to - and _ to make the encoded Base64 results more URL-SAFE.
    089     * This table is only used when the Base64's mode is set to URL-SAFE.
    090     */
    091    private static final byte[] URL_SAFE_ENCODE_TABLE = {
    092            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    093            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    094            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    095            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    096            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
    097    };
    098
    099    /**
    100     * Byte used to pad output.
    101     */
    102    private static final byte PAD = '=';
    103
    104    /**
    105     * This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified in
    106     * Table 1 of RFC 2045) into their 6-bit positive integer equivalents. Characters that are not in the Base64
    107     * alphabet but fall within the bounds of the array are translated to -1.
    108     *
    109     * Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder seamlessly handles both
    110     * URL_SAFE and STANDARD base64. (The encoder, on the other hand, needs to know ahead of time what to emit).
    111     *
    112     * Thanks to "commons" project in ws.apache.org for this code.
    113     * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
    114     */
    115    private static final byte[] DECODE_TABLE = {
    116            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    117            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    118            -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 52, 53, 54,
    119            55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
    120            5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
    121            24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
    122            35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
    123    };
    124
    125    /** Mask used to extract 6 bits, used when encoding */
    126    private static final int MASK_6BITS = 0x3f;
    127
    128    /** Mask used to extract 8 bits, used in decoding base64 bytes */
    129    private static final int MASK_8BITS = 0xff;
    130
    131    // The static final fields above are used for the original static byte[] methods on Base64.
    132    // The private member fields below are used with the new streaming approach, which requires
    133    // some state be preserved between calls of encode() and decode().
    134
    135    /**
    136     * Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE above remains static because it is able
    137     * to decode both STANDARD and URL_SAFE streams, but the encodeTable must be a member variable so we can switch
    138     * between the two modes.
    139     */
    140    private final byte[] encodeTable;
    141
    142    /**
    143     * Line length for encoding. Not used when decoding. A value of zero or less implies no chunking of the base64
    144     * encoded data.
    145     */
    146    private final int lineLength;
    147
    148    /**
    149     * Line separator for encoding. Not used when decoding. Only used if lineLength > 0.
    150     */
    151    private final byte[] lineSeparator;
    152
    153    /**
    154     * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
    155     * <code>decodeSize = 3 + lineSeparator.length;</code>
    156     */
    157    private final int decodeSize;
    158
    159    /**
    160     * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
    161     * <code>encodeSize = 4 + lineSeparator.length;</code>
    162     */
    163    private final int encodeSize;
    164
    165    /**
    166     * Buffer for streaming.
    167     */
    168    private byte[] buffer;
    169
    170    /**
    171     * Position where next character should be written in the buffer.
    172     */
    173    private int pos;
    174
    175    /**
    176     * Position where next character should be read from the buffer.
    177     */
    178    private int readPos;
    179
    180    /**
    181     * Variable tracks how many characters have been written to the current line. Only used when encoding. We use it to
    182     * make sure each encoded line never goes beyond lineLength (if lineLength > 0).
    183     */
    184    private int currentLinePos;
    185
    186    /**
    187     * Writes to the buffer only occur after every 3 reads when encoding, an every 4 reads when decoding. This variable
    188     * helps track that.
    189     */
    190    private int modulus;
    191
    192    /**
    193     * Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this Base64 object becomes useless,
    194     * and must be thrown away.
    195     */
    196    private boolean eof;
    197
    198    /**
    199     * Place holder for the 3 bytes we're dealing with for our base64 logic. Bitwise operations store and extract the
    200     * base64 encoding or decoding from this variable.
    201     */
    202    private int x;
    203
    204    /**
    205     * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
    206     * <p>
    207     * When encoding the line length is 76, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE.
    208     * </p>
    209     *
    210     * <p>
    211     * When decoding all variants are supported.
    212     * </p>
    213     */
    214    public Base64() {
    215        this(false);
    216    }
    217
    218    /**
    219     * Creates a Base64 codec used for decoding (all modes) and encoding in the given URL-safe mode.
    220     * <p>
    221     * When encoding the line length is 76, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE.
    222     * </p>
    223     *
    224     * <p>
    225     * When decoding all variants are supported.
    226     * </p>
    227     *
    228     * @param urlSafe
    229     *            if <code>true</code>, URL-safe encoding is used. In most cases this should be set to
    230     *            <code>false</code>.
    231     * @since 1.4
    232     */
    233    public Base64(final boolean urlSafe) {
    234        this(CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe);
    235    }
    236
    237    /**
    238     * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
    239     * <p>
    240     * When encoding the line length is given in the constructor, the line separator is CRLF, and the encoding table is
    241     * STANDARD_ENCODE_TABLE.
    242     * </p>
    243     * <p>
    244     * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
    245     * </p>
    246     * <p>
    247     * When decoding all variants are supported.
    248     * </p>
    249     *
    250     * @param lineLength
    251     *            Each line of encoded data will be at most of the given length (rounded down to nearest multiple of 4).
    252     *            If {@code lineLength <= 0}, then the output will not be divided into lines (chunks). Ignored when decoding.
    253     * @since 1.4
    254     */
    255    public Base64(final int lineLength) {
    256        this(lineLength, CHUNK_SEPARATOR);
    257    }
    258
    259    /**
    260     * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
    261     * <p>
    262     * When encoding the line length and line separator are given in the constructor, and the encoding table is
    263     * STANDARD_ENCODE_TABLE.
    264     * </p>
    265     * <p>
    266     * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
    267     * </p>
    268     * <p>
    269     * When decoding all variants are supported.
    270     * </p>
    271     *
    272     * @param lineLength
    273     *            Each line of encoded data will be at most of the given length (rounded down to nearest multiple of 4).
    274     *            If {@code lineLength <= 0}, then the output will not be divided into lines (chunks). Ignored when decoding.
    275     * @param lineSeparator
    276     *            Each line of encoded data will end with this sequence of bytes.
    277     * @throws IllegalArgumentException
    278     *             Thrown when the provided lineSeparator included some base64 characters.
    279     * @since 1.4
    280     */
    281    public Base64(final int lineLength, final byte[] lineSeparator) {
    282        this(lineLength, lineSeparator, false);
    283    }
    284
    285    /**
    286     * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
    287     * <p>
    288     * When encoding the line length and line separator are given in the constructor, and the encoding table is
    289     * STANDARD_ENCODE_TABLE.
    290     * </p>
    291     * <p>
    292     * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
    293     * </p>
    294     * <p>
    295     * When decoding all variants are supported.
    296     * </p>
    297     *
    298     * @param lineLength
    299     *            Each line of encoded data will be at most of the given length (rounded down to nearest multiple of 4).
    300     *            If {@code lineLength <= 0}, then the output will not be divided into lines (chunks). Ignored when decoding.
    301     * @param lineSeparator
    302     *            Each line of encoded data will end with this sequence of bytes.
    303     * @param urlSafe
    304     *            Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode
    305     *            operations. Decoding seamlessly handles both modes.
    306     * @throws IllegalArgumentException
    307     *             The provided lineSeparator included some base64 characters. That's not going to work!
    308     * @since 1.4
    309     */
    310    public Base64(int lineLength, byte[] lineSeparator, final boolean urlSafe) {
    311        if (lineSeparator == null) {
    312            lineLength = 0;  // disable chunk-separating
    313            lineSeparator = NetConstants.EMPTY_BTYE_ARRAY;  // this just gets ignored
    314        }
    315        this.lineLength = lineLength > 0 ? (lineLength / 4) * 4 : 0;
    316        this.lineSeparator = new byte[lineSeparator.length];
    317        System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length);
    318        if (lineLength > 0) {
    319            this.encodeSize = 4 + lineSeparator.length;
    320        } else {
    321            this.encodeSize = 4;
    322        }
    323        this.decodeSize = this.encodeSize - 1;
    324        if (containsBase64Byte(lineSeparator)) {
    325            final String sep = newStringUtf8(lineSeparator);
    326            throw new IllegalArgumentException("lineSeperator must not contain base64 characters: [" + sep + "]");
    327        }
    328        this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE;
    329    }
    330
    331    /**
    332     * Returns our current encode mode. True if we're URL-SAFE, false otherwise.
    333     *
    334     * @return true if we're in URL-SAFE mode, false otherwise.
    335     * @since 1.4
    336     */
    337    public boolean isUrlSafe() {
    338        return this.encodeTable == URL_SAFE_ENCODE_TABLE;
    339    }
    340
    341    /**
    342     * Returns true if this Base64 object has buffered data for reading.
    343     *
    344     * @return true if there is Base64 object still available for reading.
    345     */
    346    boolean hasData() {
    347        return this.buffer != null;
    348    }
    349
    350    /**
    351     * Returns the amount of buffered data available for reading.
    352     *
    353     * @return The amount of buffered data available for reading.
    354     */
    355    int avail() {
    356        return buffer != null ? pos - readPos : 0;
    357    }
    358
    359    /** Doubles our buffer. */
    360    private void resizeBuffer() {
    361        if (buffer == null) {
    362            buffer = new byte[DEFAULT_BUFFER_SIZE];
    363            pos = 0;
    364            readPos = 0;
    365        } else {
    366            final byte[] b = new byte[buffer.length * DEFAULT_BUFFER_RESIZE_FACTOR];
    367            System.arraycopy(buffer, 0, b, 0, buffer.length);
    368            buffer = b;
    369        }
    370    }
    371
    372    /**
    373     * Extracts buffered data into the provided byte[] array, starting at position bPos, up to a maximum of bAvail
    374     * bytes. Returns how many bytes were actually extracted.
    375     *
    376     * @param b
    377     *            byte[] array to extract the buffered data into.
    378     * @param bPos
    379     *            position in byte[] array to start extraction at.
    380     * @param bAvail
    381     *            amount of bytes we're allowed to extract. We may extract fewer (if fewer are available).
    382     * @return The number of bytes successfully extracted into the provided byte[] array.
    383     */
    384    int readResults(final byte[] b, final int bPos, final int bAvail) {
    385        if (buffer != null) {
    386            final int len = Math.min(avail(), bAvail);
    387            if (buffer != b) {
    388                System.arraycopy(buffer, readPos, b, bPos, len);
    389                readPos += len;
    390                if (readPos >= pos) {
    391                    buffer = null;
    392                }
    393            } else {
    394                // Re-using the original consumer's output array is only
    395                // allowed for one round.
    396                buffer = null;
    397            }
    398            return len;
    399        }
    400        return eof ? -1 : 0;
    401    }
    402
    403    /**
    404     * Sets the streaming buffer. This is a small optimization where we try to buffer directly to the consumer's output
    405     * array for one round (if the consumer calls this method first) instead of starting our own buffer.
    406     *
    407     * @param out
    408     *            byte[] array to buffer directly to.
    409     * @param outPos
    410     *            Position to start buffering into.
    411     * @param outAvail
    412     *            Amount of bytes available for direct buffering.
    413     */
    414    void setInitialBuffer(final byte[] out, final int outPos, final int outAvail) {
    415        // We can re-use consumer's original output array under
    416        // special circumstances, saving on some System.arraycopy().
    417        if (out != null && out.length == outAvail) {
    418            buffer = out;
    419            pos = outPos;
    420            readPos = outPos;
    421        }
    422    }
    423
    424    /**
    425     * <p>
    426     * Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with
    427     * the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been reached, so flush last
    428     * remaining bytes (if not multiple of 3).
    429     * </p>
    430     * <p>
    431     * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach.
    432     * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
    433     * </p>
    434     *
    435     * @param in
    436     *            byte[] array of binary data to base64 encode.
    437     * @param inPos
    438     *            Position to start reading data from.
    439     * @param inAvail
    440     *            Amount of bytes available from input for encoding.
    441     */
    442    void encode(final byte[] in, int inPos, final int inAvail) {
    443        if (eof) {
    444            return;
    445        }
    446        // inAvail < 0 is how we're informed of EOF in the underlying data we're
    447        // encoding.
    448        if (inAvail < 0) {
    449            eof = true;
    450            if (buffer == null || buffer.length - pos < encodeSize) {
    451                resizeBuffer();
    452            }
    453            switch (modulus) {
    454                case 1 :
    455                    buffer[pos++] = encodeTable[(x >> 2) & MASK_6BITS];
    456                    buffer[pos++] = encodeTable[(x << 4) & MASK_6BITS];
    457                    // URL-SAFE skips the padding to further reduce size.
    458                    if (encodeTable == STANDARD_ENCODE_TABLE) {
    459                        buffer[pos++] = PAD;
    460                        buffer[pos++] = PAD;
    461                    }
    462                    break;
    463
    464                case 2 :
    465                    buffer[pos++] = encodeTable[(x >> 10) & MASK_6BITS];
    466                    buffer[pos++] = encodeTable[(x >> 4) & MASK_6BITS];
    467                    buffer[pos++] = encodeTable[(x << 2) & MASK_6BITS];
    468                    // URL-SAFE skips the padding to further reduce size.
    469                    if (encodeTable == STANDARD_ENCODE_TABLE) {
    470                        buffer[pos++] = PAD;
    471                    }
    472                    break;
    473                default:
    474                    break;  // other values ignored
    475            }
    476            if (lineLength > 0 && pos > 0) {
    477                System.arraycopy(lineSeparator, 0, buffer, pos, lineSeparator.length);
    478                pos += lineSeparator.length;
    479            }
    480        } else {
    481            for (int i = 0; i < inAvail; i++) {
    482                if (buffer == null || buffer.length - pos < encodeSize) {
    483                    resizeBuffer();
    484                }
    485                modulus = (++modulus) % 3;
    486                int b = in[inPos++];
    487                if (b < 0) {
    488                    b += 256;
    489                }
    490                x = (x << 8) + b;
    491                if (0 == modulus) {
    492                    buffer[pos++] = encodeTable[(x >> 18) & MASK_6BITS];
    493                    buffer[pos++] = encodeTable[(x >> 12) & MASK_6BITS];
    494                    buffer[pos++] = encodeTable[(x >> 6) & MASK_6BITS];
    495                    buffer[pos++] = encodeTable[x & MASK_6BITS];
    496                    currentLinePos += 4;
    497                    if (lineLength > 0 && lineLength <= currentLinePos) {
    498                        System.arraycopy(lineSeparator, 0, buffer, pos, lineSeparator.length);
    499                        pos += lineSeparator.length;
    500                        currentLinePos = 0;
    501                    }
    502                }
    503            }
    504        }
    505    }
    506
    507    /**
    508     * <p>
    509     * Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once
    510     * with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been reached. The "-1"
    511     * call is not necessary when decoding, but it doesn't hurt, either.
    512     * </p>
    513     * <p>
    514     * Ignores all non-base64 characters. This is how chunked (e.g. 76 character) data is handled, since CR and LF are
    515     * silently ignored, but has implications for other bytes, too. This method subscribes to the garbage-in,
    516     * garbage-out philosophy: it will not check the provided data for validity.
    517     * </p>
    518     * <p>
    519     * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach.
    520     * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
    521     * </p>
    522     *
    523     * @param in
    524     *            byte[] array of ascii data to base64 decode.
    525     * @param inPos
    526     *            Position to start reading data from.
    527     * @param inAvail
    528     *            Amount of bytes available from input for encoding.
    529     */
    530    void decode(final byte[] in, int inPos, final int inAvail) {
    531        if (eof) {
    532            return;
    533        }
    534        if (inAvail < 0) {
    535            eof = true;
    536        }
    537        for (int i = 0; i < inAvail; i++) {
    538            if (buffer == null || buffer.length - pos < decodeSize) {
    539                resizeBuffer();
    540            }
    541            final byte b = in[inPos++];
    542            if (b == PAD) {
    543                // We're done.
    544                eof = true;
    545                break;
    546            }
    547            if (b >= 0 && b < DECODE_TABLE.length) {
    548                final int result = DECODE_TABLE[b];
    549                if (result >= 0) {
    550                    modulus = (++modulus) % 4;
    551                    x = (x << 6) + result;
    552                    if (modulus == 0) {
    553                        buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS);
    554                        buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS);
    555                        buffer[pos++] = (byte) (x & MASK_8BITS);
    556                    }
    557                }
    558            }
    559        }
    560
    561        // Two forms of EOF as far as base64 decoder is concerned: actual
    562        // EOF (-1) and first time '=' character is encountered in stream.
    563        // This approach makes the '=' padding characters completely optional.
    564        if (eof && modulus != 0) {
    565            x = x << 6;
    566            switch (modulus) {
    567                case 2 :
    568                    x = x << 6;
    569                    buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS);
    570                    break;
    571                case 3 :
    572                    buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS);
    573                    buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS);
    574                    break;
    575                default:
    576                    break;  // other values ignored
    577            }
    578        }
    579    }
    580
    581    /**
    582     * Returns whether or not the <code>octet</code> is in the base 64 alphabet.
    583     *
    584     * @param octet
    585     *            The value to test
    586     * @return <code>true</code> if the value is defined in the the base 64 alphabet, <code>false</code> otherwise.
    587     * @since 1.4
    588     */
    589    public static boolean isBase64(final byte octet) {
    590        return octet == PAD || (octet >= 0 && octet < DECODE_TABLE.length && DECODE_TABLE[octet] != -1);
    591    }
    592
    593    /**
    594     * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the
    595     * method treats whitespace as valid.
    596     *
    597     * @param arrayOctet
    598     *            byte array to test
    599     * @return <code>true</code> if all bytes are valid characters in the Base64 alphabet or if the byte array is empty;
    600     *         false, otherwise
    601     */
    602    public static boolean isArrayByteBase64(final byte[] arrayOctet) {
    603        for (final byte element : arrayOctet) {
    604            if (!isBase64(element) && !isWhiteSpace(element)) {
    605                return false;
    606            }
    607        }
    608        return true;
    609    }
    610
    611    /**
    612     * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet.
    613     *
    614     * @param arrayOctet
    615     *            byte array to test
    616     * @return <code>true</code> if any byte is a valid character in the Base64 alphabet; false herwise
    617     */
    618    private static boolean containsBase64Byte(final byte[] arrayOctet) {
    619        for (final byte element : arrayOctet)
    620        {
    621            if (isBase64(element)) {
    622                return true;
    623            }
    624        }
    625        return false;
    626    }
    627
    628    /**
    629     * Encodes binary data using the base64 algorithm but does not chunk the output.
    630     *
    631     * @param binaryData
    632     *            binary data to encode
    633     * @return byte[] containing Base64 characters in their UTF-8 representation.
    634     */
    635    public static byte[] encodeBase64(final byte[] binaryData) {
    636        return encodeBase64(binaryData, false);
    637    }
    638
    639    /**
    640     * Encodes binary data using the base64 algorithm into 76 character blocks separated by CRLF.
    641     * <p>
    642     * For a non-chunking version, see {@link #encodeBase64StringUnChunked(byte[])}.
    643     *
    644     * @param binaryData
    645     *            binary data to encode
    646     * @return String containing Base64 characters.
    647     * @since 1.4
    648     */
    649    public static String encodeBase64String(final byte[] binaryData) {
    650        return newStringUtf8(encodeBase64(binaryData, true));
    651    }
    652
    653    /**
    654     * Encodes binary data using the base64 algorithm, without using chunking.
    655     * <p>
    656     * For a chunking version, see {@link #encodeBase64String(byte[])}.
    657     *
    658     * @param binaryData
    659     *            binary data to encode
    660     * @return String containing Base64 characters.
    661     * @since 3.2
    662     */
    663    public static String encodeBase64StringUnChunked(final byte[] binaryData) {
    664        return newStringUtf8(encodeBase64(binaryData, false));
    665    }
    666
    667    /**
    668     * Encodes binary data using the base64 algorithm.
    669     *
    670     * @param binaryData
    671     *            binary data to encode
    672     * @param useChunking whether to split the output into chunks
    673     * @return String containing Base64 characters.
    674     * @since 3.2
    675     */
    676    public static String encodeBase64String(final byte[] binaryData, final boolean useChunking) {
    677        return newStringUtf8(encodeBase64(binaryData, useChunking));
    678    }
    679
    680    /**
    681     * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The
    682     * url-safe variation emits - and _ instead of + and / characters.
    683     *
    684     * @param binaryData
    685     *            binary data to encode
    686     * @return byte[] containing Base64 characters in their UTF-8 representation.
    687     * @since 1.4
    688     */
    689    public static byte[] encodeBase64URLSafe(final byte[] binaryData) {
    690        return encodeBase64(binaryData, false, true);
    691    }
    692
    693    /**
    694     * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The
    695     * url-safe variation emits - and _ instead of + and / characters.
    696     *
    697     * @param binaryData
    698     *            binary data to encode
    699     * @return String containing Base64 characters
    700     * @since 1.4
    701     */
    702    public static String encodeBase64URLSafeString(final byte[] binaryData) {
    703        return newStringUtf8(encodeBase64(binaryData, false, true));
    704    }
    705
    706    /**
    707     * Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks
    708     *
    709     * @param binaryData
    710     *            binary data to encode
    711     * @return Base64 characters chunked in 76 character blocks
    712     */
    713    public static byte[] encodeBase64Chunked(final byte[] binaryData) {
    714        return encodeBase64(binaryData, true);
    715    }
    716
    717    /**
    718     * Decodes a String containing containing characters in the Base64 alphabet.
    719     *
    720     * @param pArray
    721     *            A String containing Base64 character data
    722     * @return a byte array containing binary data
    723     * @since 1.4
    724     */
    725    public byte[] decode(final String pArray) {
    726        return decode(getBytesUtf8(pArray));
    727    }
    728
    729    private byte[] getBytesUtf8(final String pArray) {
    730        return pArray.getBytes(StandardCharsets.UTF_8);
    731    }
    732
    733    /**
    734     * Decodes a byte[] containing containing characters in the Base64 alphabet.
    735     *
    736     * @param pArray
    737     *            A byte array containing Base64 character data
    738     * @return a byte array containing binary data
    739     */
    740    public byte[] decode(final byte[] pArray) {
    741        reset();
    742        if (pArray == null || pArray.length == 0) {
    743            return pArray;
    744        }
    745        final long len = (pArray.length * 3) / 4;
    746        final byte[] buf = new byte[(int) len];
    747        setInitialBuffer(buf, 0, buf.length);
    748        decode(pArray, 0, pArray.length);
    749        decode(pArray, 0, -1); // Notify decoder of EOF.
    750
    751        // Would be nice to just return buf (like we sometimes do in the encode
    752        // logic), but we have no idea what the line-length was (could even be
    753        // variable).  So we cannot determine ahead of time exactly how big an
    754        // array is necessary.  Hence the need to construct a 2nd byte array to
    755        // hold the final result:
    756
    757        final byte[] result = new byte[pos];
    758        readResults(result, 0, result.length);
    759        return result;
    760    }
    761
    762    /**
    763     * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
    764     *
    765     * @param binaryData
    766     *            Array containing binary data to encode.
    767     * @param isChunked
    768     *            if <code>true</code> this encoder will chunk the base64 output into 76 character blocks
    769     * @return Base64-encoded data.
    770     * @throws IllegalArgumentException
    771     *             Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}
    772     */
    773    public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked) {
    774        return encodeBase64(binaryData, isChunked, false);
    775    }
    776
    777    /**
    778     * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
    779     *
    780     * @param binaryData
    781     *            Array containing binary data to encode.
    782     * @param isChunked
    783     *            if <code>true</code> this encoder will chunk the base64 output into 76 character blocks
    784     * @param urlSafe
    785     *            if <code>true</code> this encoder will emit - and _ instead of the usual + and / characters.
    786     * @return Base64-encoded data.
    787     * @throws IllegalArgumentException
    788     *             Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}
    789     * @since 1.4
    790     */
    791    public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, final boolean urlSafe) {
    792        return encodeBase64(binaryData, isChunked, urlSafe, Integer.MAX_VALUE);
    793    }
    794
    795    /**
    796     * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
    797     *
    798     * @param binaryData
    799     *            Array containing binary data to encode.
    800     * @param isChunked
    801     *            if <code>true</code> this encoder will chunk the base64 output into 76 character blocks
    802     * @param urlSafe
    803     *            if <code>true</code> this encoder will emit - and _ instead of the usual + and / characters.
    804     * @param maxResultSize
    805     *            The maximum result size to accept.
    806     * @return Base64-encoded data.
    807     * @throws IllegalArgumentException
    808     *             Thrown when the input array needs an output array bigger than maxResultSize
    809     * @since 1.4
    810     */
    811    public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, final boolean urlSafe,
    812            final int maxResultSize) {
    813        if (binaryData == null || binaryData.length == 0) {
    814            return binaryData;
    815        }
    816
    817        final long len = getEncodeLength(binaryData, isChunked ? CHUNK_SIZE : 0,
    818                isChunked ? CHUNK_SEPARATOR : NetConstants.EMPTY_BTYE_ARRAY);
    819        if (len > maxResultSize) {
    820            throw new IllegalArgumentException("Input array too big, the output array would be bigger (" + len
    821                    + ") than the specified maxium size of " + maxResultSize);
    822        }
    823
    824        final Base64 b64 = isChunked ? new Base64(urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe);
    825        return b64.encode(binaryData);
    826    }
    827
    828    /**
    829     * Decodes a Base64 String into octets.
    830     *
    831     * @param base64String
    832     *            String containing Base64 data
    833     * @return Array containing decoded data.
    834     * @since 1.4
    835     */
    836    public static byte[] decodeBase64(final String base64String) {
    837        return new Base64().decode(base64String);
    838    }
    839
    840    /**
    841     * Decodes Base64 data into octets.
    842     *
    843     * @param base64Data
    844     *            Byte array containing Base64 data
    845     * @return Array containing decoded data.
    846     */
    847    public static byte[] decodeBase64(final byte[] base64Data) {
    848        return new Base64().decode(base64Data);
    849    }
    850
    851    /**
    852     * Checks if a byte value is whitespace or not.
    853     *
    854     * @param byteToCheck
    855     *            the byte to check
    856     * @return true if byte is whitespace, false otherwise
    857     */
    858    private static boolean isWhiteSpace(final byte byteToCheck) {
    859        switch (byteToCheck) {
    860            case ' ' :
    861            case '\n' :
    862            case '\r' :
    863            case '\t' :
    864                return true;
    865            default :
    866                return false;
    867        }
    868    }
    869
    870    /**
    871     * Encodes a byte[] containing binary data, into a String containing characters in the Base64 alphabet.
    872     *
    873     * @param pArray
    874     *            a byte array containing binary data
    875     * @return A String containing only Base64 character data
    876     * @since 1.4
    877     */
    878    public String encodeToString(final byte[] pArray) {
    879        return newStringUtf8(encode(pArray));
    880    }
    881
    882    private static String newStringUtf8(final byte[] encode) {
    883        return new String(encode, StandardCharsets.UTF_8);
    884    }
    885
    886    /**
    887     * Encodes a byte[] containing binary data, into a byte[] containing characters in the Base64 alphabet.
    888     *
    889     * @param pArray
    890     *            a byte array containing binary data
    891     * @return A byte array containing only Base64 character data
    892     */
    893    public byte[] encode(final byte[] pArray) {
    894        reset();
    895        if (pArray == null || pArray.length == 0) {
    896            return pArray;
    897        }
    898        final long len = getEncodeLength(pArray, lineLength, lineSeparator);
    899        byte[] buf = new byte[(int) len];
    900        setInitialBuffer(buf, 0, buf.length);
    901        encode(pArray, 0, pArray.length);
    902        encode(pArray, 0, -1); // Notify encoder of EOF.
    903        // Encoder might have resized, even though it was unnecessary.
    904        if (buffer != buf) {
    905            readResults(buf, 0, buf.length);
    906        }
    907        // In URL-SAFE mode we skip the padding characters, so sometimes our
    908        // final length is a bit smaller.
    909        if (isUrlSafe() && pos < buf.length) {
    910            final byte[] smallerBuf = new byte[pos];
    911            System.arraycopy(buf, 0, smallerBuf, 0, pos);
    912            buf = smallerBuf;
    913        }
    914        return buf;
    915    }
    916
    917    /**
    918     * Pre-calculates the amount of space needed to base64-encode the supplied array.
    919     *
    920     * @param pArray byte[] array which will later be encoded
    921     * @param chunkSize line-length of the output (<= 0 means no chunking) between each
    922     *        chunkSeparator (e.g. CRLF).
    923     * @param chunkSeparator the sequence of bytes used to separate chunks of output (e.g. CRLF).
    924     *
    925     * @return amount of space needed to encoded the supplied array.  Returns
    926     *         a long since a max-len array will require Integer.MAX_VALUE + 33%.
    927     */
    928    private static long getEncodeLength(final byte[] pArray, int chunkSize, final byte[] chunkSeparator) {
    929        // base64 always encodes to multiples of 4.
    930        chunkSize = (chunkSize / 4) * 4;
    931
    932        long len = (pArray.length * 4) / 3;
    933        final long mod = len % 4;
    934        if (mod != 0) {
    935            len += 4 - mod;
    936        }
    937        if (chunkSize > 0) {
    938            final boolean lenChunksPerfectly = len % chunkSize == 0;
    939            len += (len / chunkSize) * chunkSeparator.length;
    940            if (!lenChunksPerfectly) {
    941                len += chunkSeparator.length;
    942            }
    943        }
    944        return len;
    945    }
    946
    947    // Implementation of integer encoding used for crypto
    948    /**
    949     * Decodes a byte64-encoded integer according to crypto standards such as W3C's XML-Signature
    950     *
    951     * @param pArray
    952     *            a byte array containing base64 character data
    953     * @return A BigInteger
    954     * @since 1.4
    955     */
    956    public static BigInteger decodeInteger(final byte[] pArray) {
    957        return new BigInteger(1, decodeBase64(pArray));
    958    }
    959
    960    /**
    961     * Encodes to a byte64-encoded integer according to crypto standards such as W3C's XML-Signature
    962     *
    963     * @param bigInt
    964     *            a BigInteger
    965     * @return A byte array containing base64 character data
    966     * @throws NullPointerException
    967     *             if null is passed in
    968     * @since 1.4
    969     */
    970    public static byte[] encodeInteger(final BigInteger bigInt) {
    971        if (bigInt == null) {
    972            throw new NullPointerException("encodeInteger called with null parameter");
    973        }
    974        return encodeBase64(toIntegerBytes(bigInt), false);
    975    }
    976
    977    /**
    978     * Returns a byte-array representation of a <code>BigInteger</code> without sign bit.
    979     *
    980     * @param bigInt
    981     *            <code>BigInteger</code> to be converted
    982     * @return a byte array representation of the BigInteger parameter
    983     */
    984    static byte[] toIntegerBytes(final BigInteger bigInt) {
    985        int bitlen = bigInt.bitLength();
    986        // round bitlen
    987        bitlen = ((bitlen + 7) >> 3) << 3;
    988        final byte[] bigBytes = bigInt.toByteArray();
    989
    990        if (((bigInt.bitLength() % 8) != 0) && (((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) {
    991            return bigBytes;
    992        }
    993        // set up params for copying everything but sign bit
    994        int startSrc = 0;
    995        int len = bigBytes.length;
    996
    997        // if bigInt is exactly byte-aligned, just skip signbit in copy
    998        if ((bigInt.bitLength() % 8) == 0) {
    999            startSrc = 1;
    1000            len--;
    1001        }
    1002        final int startDst = bitlen / 8 - len; // to pad w/ nulls as per spec
    1003        final byte[] resizedBytes = new byte[bitlen / 8];
    1004        System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len);
    1005        return resizedBytes;
    1006    }
    1007
    1008    /**
    1009     * Resets this Base64 object to its initial newly constructed state.
    1010     */
    1011    private void reset() {
    1012        buffer = null;
    1013        pos = 0;
    1014        readPos = 0;
    1015        currentLinePos = 0;
    1016        modulus = 0;
    1017        eof = false;
    1018    }
    1019
    1020    // Getters for use in testing
    1021
    1022    int getLineLength() {
    1023        return lineLength;
    1024    }
    1025
    1026    byte[] getLineSeparator() {
    1027        return lineSeparator.clone();
    1028    }
    1029}