1d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker/*
2d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Copyright (C) 2010 The Android Open Source Project
3d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker *
4d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Licensed under the Apache License, Version 2.0 (the "License");
5d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * you may not use this file except in compliance with the License.
6d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * You may obtain a copy of the License at
7d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker *
8d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker *      http://www.apache.org/licenses/LICENSE-2.0
9d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker *
10d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * Unless required by applicable law or agreed to in writing, software
11d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * distributed under the License is distributed on an "AS IS" BASIS,
12d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * See the License for the specific language governing permissions and
14d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker * limitations under the License.
15d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */
16d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
17ab69e29c1927bdc6143324eba5ccd78f7c43128dDoug Zongkerpackage android.util;
18d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
199df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongkerimport java.io.UnsupportedEncodingException;
209df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
21d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker/**
229df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker * Utilities for encoding and decoding the Base64 representation of
239df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker * binary data.  See RFCs <a
249df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker * href="http://www.ietf.org/rfc/rfc2045.txt">2045</a> and <a
259df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker * href="http://www.ietf.org/rfc/rfc3548.txt">3548</a>.
26d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker */
27d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongkerpublic class Base64 {
28d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
29d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * Default values for encoder/decoder flags.
30d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
31d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    public static final int DEFAULT = 0;
32d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
33d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
349df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker     * Encoder flag bit to omit the padding '=' characters at the end
359df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker     * of the output (if any).
36d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
37d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    public static final int NO_PADDING = 1;
38d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
39d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
409df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker     * Encoder flag bit to omit all line terminators (i.e., the output
419df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker     * will be on one long line).
42d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
43d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    public static final int NO_WRAP = 2;
44d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
45d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
469df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker     * Encoder flag bit to indicate lines should be terminated with a
479df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker     * CRLF pair instead of just an LF.  Has no effect if {@code
489df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker     * NO_WRAP} is specified as well.
49d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
50d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    public static final int CRLF = 4;
51d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
52d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
539df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker     * Encoder/decoder flag bit to indicate using the "URL and
549df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker     * filename safe" variant of Base64 (see RFC 3548 section 4) where
559df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker     * {@code -} and {@code _} are used in place of {@code +} and
569df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker     * {@code /}.
57d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
589df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker    public static final int URL_SAFE = 8;
59d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
60d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
619df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker     * Flag to pass to {@link Base64OutputStream} to indicate that it
629df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker     * should not close the output stream it is wrapping when it
639df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker     * itself is closed.
64d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
65d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    public static final int NO_CLOSE = 16;
66d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
67d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    //  --------------------------------------------------------
689df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker    //  shared code
69d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    //  --------------------------------------------------------
70d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
719df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker    /* package */ static abstract class Coder {
729df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        public byte[] output;
739df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        public int op;
74d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
759df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        /**
769df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * Encode/decode another block of input data.  this.output is
779df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * provided by the caller, and must be big enough to hold all
789df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * the coded data.  On exit, this.opwill be set to the length
799df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * of the coded data.
809df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         *
819df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * @param finish true if this is the final call to process for
829df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         *        this object.  Will finalize the coder state and
839df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         *        include any final bytes in the output.
849df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         *
859df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * @return true if the input so far is good; false if some
869df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         *         error has been detected in the input stream..
879df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         */
889df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        public abstract boolean process(byte[] input, int offset, int len, boolean finish);
899df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
909df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        /**
919df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * @return the maximum number of bytes a call to process()
929df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * could produce for the given number of input bytes.  This may
939df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * be an overestimate.
949df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         */
959df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        public abstract int maxOutputSize(int len);
969df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker    }
979df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
989df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker    //  --------------------------------------------------------
999df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker    //  decoding
1009df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker    //  --------------------------------------------------------
101d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
102d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
103d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * Decode the Base64-encoded data in input and return the data in
104d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * a new byte array.
105d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *
1069df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker     * <p>The padding '=' characters at the end are considered optional, but
107d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * if any are present, there must be the correct number of them.
108d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *
1098fe5571aa46321a97dd6e7470e9df208a0324103Doug Zongker     * @param str    the input String to decode, which is converted to
110d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *               bytes using the default charset
111d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param flags  controls certain features of the decoded output.
112d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *               Pass {@code DEFAULT} to decode standard Base64.
113d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *
114d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @throws IllegalArgumentException if the input contains
115d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * incorrect padding
116d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
117d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    public static byte[] decode(String str, int flags) {
118d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        return decode(str.getBytes(), flags);
119d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    }
120d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
121d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
122d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * Decode the Base64-encoded data in input and return the data in
123d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * a new byte array.
124d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *
1259df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker     * <p>The padding '=' characters at the end are considered optional, but
126d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * if any are present, there must be the correct number of them.
127d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *
128d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param input the input array to decode
129d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param flags  controls certain features of the decoded output.
130d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *               Pass {@code DEFAULT} to decode standard Base64.
131d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *
132d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @throws IllegalArgumentException if the input contains
133d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * incorrect padding
134d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
135d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    public static byte[] decode(byte[] input, int flags) {
136d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        return decode(input, 0, input.length, flags);
137d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    }
138d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
139d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
140d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * Decode the Base64-encoded data in input and return the data in
141d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * a new byte array.
142d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *
1439df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker     * <p>The padding '=' characters at the end are considered optional, but
144d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * if any are present, there must be the correct number of them.
145d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *
146d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param input  the data to decode
147d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param offset the position within the input array at which to start
148d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param len    the number of bytes of input to decode
149d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param flags  controls certain features of the decoded output.
150d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *               Pass {@code DEFAULT} to decode standard Base64.
151d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *
152d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @throws IllegalArgumentException if the input contains
153d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * incorrect padding
154d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
155d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    public static byte[] decode(byte[] input, int offset, int len, int flags) {
156d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        // Allocate space for the most data the input could represent.
157d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        // (It could contain less if it contains whitespace, etc.)
1589df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        Decoder decoder = new Decoder(flags, new byte[len*3/4]);
159d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
1609df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        if (!decoder.process(input, offset, len, true)) {
161d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            throw new IllegalArgumentException("bad base-64");
162d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        }
163d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
164d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        // Maybe we got lucky and allocated exactly enough output space.
1659df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        if (decoder.op == decoder.output.length) {
1669df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            return decoder.output;
167d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        }
168d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
169d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        // Need to shorten the array, so allocate a new one of the
170d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        // right size and copy.
1719df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        byte[] temp = new byte[decoder.op];
1729df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        System.arraycopy(decoder.output, 0, temp, 0, decoder.op);
173d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        return temp;
174d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    }
175d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
1769df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker    /* package */ static class Decoder extends Coder {
1779df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        /**
1789df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * Lookup table for turning bytes into their position in the
1799df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * Base64 alphabet.
1809df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         */
1819df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        private static final int DECODE[] = {
1829df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1839df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1849df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
1859df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
1869df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
1879df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
1889df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
1899df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
1909df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1919df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1929df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1939df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1949df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1959df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1969df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1979df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1989df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        };
1999df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
2009df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        /**
2019df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * Decode lookup table for the "web safe" variant (RFC 3548
2029df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * sec. 4) where - and _ replace + and /.
2039df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         */
2049df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        private static final int DECODE_WEBSAFE[] = {
2059df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2069df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2079df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
2089df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
2099df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
2109df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
2119df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
2129df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
2139df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2149df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2159df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2169df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2179df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2189df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2199df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2209df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2219df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        };
2229df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
2239df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        /** Non-data values in the DECODE arrays. */
2249df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        private static final int SKIP = -1;
2259df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        private static final int EQUALS = -2;
2269df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
2279df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        /**
2289df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * States 0-3 are reading through the next input tuple.
2299df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * State 4 is having read one '=' and expecting exactly
2309df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * one more.
2319df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * State 5 is expecting no more data or padding characters
2329df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * in the input.
2339df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * State 6 is the error state; an error has been detected
2349df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * in the input and no future input can "fix" it.
2359df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         */
2369df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        private int state;   // state number (0 to 6)
2379df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        private int value;
2389df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
2399df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        final private int[] alphabet;
2409df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
2419df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        public Decoder(int flags, byte[] output) {
242d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            this.output = output;
243d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
2449df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            alphabet = ((flags & URL_SAFE) == 0) ? DECODE : DECODE_WEBSAFE;
245d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            state = 0;
246d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            value = 0;
247d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        }
248d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
2499df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        /**
2509df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * @return an overestimate for the number of bytes {@code
2519df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * len} bytes could decode to.
2529df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         */
2539df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        public int maxOutputSize(int len) {
2549df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            return len * 3/4 + 10;
2559df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        }
256d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
2579df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        /**
2589df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * Decode another block of input data.
2599df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         *
2609df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * @return true if the state machine is still healthy.  false if
2619df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         *         bad base-64 data has been detected in the input stream.
2629df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         */
2639df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        public boolean process(byte[] input, int offset, int len, boolean finish) {
2649df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            if (this.state == 6) return false;
2659df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
2669df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            int p = offset;
2679df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            len += offset;
2689df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
2699df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            // Using local variables makes the decoder about 12%
2709df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            // faster than if we manipulate the member variables in
2719df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            // the loop.  (Even alphabet makes a measurable
2729df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            // difference, which is somewhat surprising to me since
2739df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            // the member variable is final.)
2749df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            int state = this.state;
2759df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            int value = this.value;
2769df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            int op = 0;
2779df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            final byte[] output = this.output;
2789df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            final int[] alphabet = this.alphabet;
2799df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
2809df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            while (p < len) {
2819df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // Try the fast path:  we're starting a new tuple and the
2829df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // next four bytes of the input stream are all data
2839df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // bytes.  This corresponds to going through states
2849df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // 0-1-2-3-0.  We expect to use this method for most of
2859df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // the data.
2869df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                //
2879df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // If any of the next four bytes of input are non-data
2889df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // (whitespace, etc.), value will end up negative.  (All
2899df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // the non-data values in decode are small negative
2909df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // numbers, so shifting any of them up and or'ing them
2919df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // together will result in a value with its top bit set.)
2929df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                //
2939df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // You can remove this whole block and the output should
2949df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // be the same, just slower.
2959df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                if (state == 0) {
2969df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    while (p+4 <= len &&
2979df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                           (value = ((alphabet[input[p] & 0xff] << 18) |
2989df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                                     (alphabet[input[p+1] & 0xff] << 12) |
2999df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                                     (alphabet[input[p+2] & 0xff] << 6) |
3009df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                                     (alphabet[input[p+3] & 0xff]))) >= 0) {
3019df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        output[op+2] = (byte) value;
3029df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        output[op+1] = (byte) (value >> 8);
3039df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        output[op] = (byte) (value >> 16);
3049df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        op += 3;
3059df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        p += 4;
3069df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    }
3079df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    if (p >= len) break;
3089df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                }
309d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
3109df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // The fast path isn't available -- either we've read a
3119df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // partial tuple, or the next four input bytes aren't all
3129df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // data, or whatever.  Fall back to the slower state
3139df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // machine implementation.
314d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
3159df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                int d = alphabet[input[p++] & 0xff];
3169df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
3179df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                switch (state) {
318d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                case 0:
319d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    if (d >= 0) {
320d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        value = d;
321d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        ++state;
322d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    } else if (d != SKIP) {
3239df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        this.state = 6;
324d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        return false;
325d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    }
326d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    break;
327d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
328d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                case 1:
329d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    if (d >= 0) {
330d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        value = (value << 6) | d;
331d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        ++state;
332d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    } else if (d != SKIP) {
3339df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        this.state = 6;
334d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        return false;
335d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    }
336d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    break;
337d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
338d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                case 2:
339d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    if (d >= 0) {
340d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        value = (value << 6) | d;
341d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        ++state;
342d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    } else if (d == EQUALS) {
343d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        // Emit the last (partial) output tuple;
344d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        // expect exactly one more padding character.
345d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        output[op++] = (byte) (value >> 4);
346d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        state = 4;
347d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    } else if (d != SKIP) {
3489df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        this.state = 6;
349d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        return false;
350d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    }
351d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    break;
352d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
353d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                case 3:
354d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    if (d >= 0) {
355d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        // Emit the output triple and return to state 0.
356d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        value = (value << 6) | d;
357d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        output[op+2] = (byte) value;
358d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        output[op+1] = (byte) (value >> 8);
359d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        output[op] = (byte) (value >> 16);
360d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        op += 3;
361d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        state = 0;
362d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    } else if (d == EQUALS) {
363d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        // Emit the last (partial) output tuple;
364d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        // expect no further data or padding characters.
365d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        output[op+1] = (byte) (value >> 2);
366d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        output[op] = (byte) (value >> 10);
367d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        op += 2;
368d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        state = 5;
369d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    } else if (d != SKIP) {
3709df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        this.state = 6;
371d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        return false;
372d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    }
373d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    break;
374d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
375d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                case 4:
376d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    if (d == EQUALS) {
377d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        ++state;
378d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    } else if (d != SKIP) {
3799df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        this.state = 6;
380d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        return false;
381d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    }
382d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    break;
383d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
384d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                case 5:
385d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    if (d != SKIP) {
3869df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        this.state = 6;
387d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                        return false;
388d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    }
389d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    break;
3909df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                }
391d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            }
392d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
3939df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            if (!finish) {
3949df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // We're out of input, but a future call could provide
3959df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // more.
3969df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                this.state = state;
3979df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                this.value = value;
3989df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                this.op = op;
3999df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                return true;
4009df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            }
401d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
4029df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            // Done reading input.  Now figure out where we are left in
4039df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            // the state machine and finish up.
404d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
4059df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            switch (state) {
406d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            case 0:
407d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                // Output length is a multiple of three.  Fine.
408d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                break;
409d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            case 1:
410d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                // Read one extra input byte, which isn't enough to
411d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                // make another output byte.  Illegal.
4129df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                this.state = 6;
413d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                return false;
414d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            case 2:
415d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                // Read two extra input bytes, enough to emit 1 more
416d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                // output byte.  Fine.
417d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                output[op++] = (byte) (value >> 4);
418d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                break;
419d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            case 3:
420d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                // Read three extra input bytes, enough to emit 2 more
421d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                // output bytes.  Fine.
4229df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                output[op++] = (byte) (value >> 10);
4239df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                output[op++] = (byte) (value >> 2);
424d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                break;
425d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            case 4:
426d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                // Read one padding '=' when we expected 2.  Illegal.
4279df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                this.state = 6;
428d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                return false;
429d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            case 5:
430d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                // Read all the padding '='s we expected and no more.
431d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                // Fine.
432d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                break;
4339df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            }
434d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
4359df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            this.state = state;
4369df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            this.op = op;
4379df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            return true;
4389df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        }
439d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    }
440d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
441d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    //  --------------------------------------------------------
442d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    //  encoding
443d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    //  --------------------------------------------------------
444d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
445d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
446d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * Base64-encode the given data and return a newly allocated
447d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * String with the result.
448d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *
449d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param input  the data to encode
450d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param flags  controls certain features of the encoded output.
451d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *               Passing {@code DEFAULT} results in output that
452d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *               adheres to RFC 2045.
453d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
454d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    public static String encodeToString(byte[] input, int flags) {
4559df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        try {
4569df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            return new String(encode(input, flags), "US-ASCII");
4579df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        } catch (UnsupportedEncodingException e) {
4589df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            // US-ASCII is guaranteed to be available.
4599df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            throw new AssertionError(e);
4609df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        }
461d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    }
462d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
463d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
464d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * Base64-encode the given data and return a newly allocated
465d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * String with the result.
466d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *
467d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param input  the data to encode
468d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param offset the position within the input array at which to
469d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *               start
470d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param len    the number of bytes of input to encode
471d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param flags  controls certain features of the encoded output.
472d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *               Passing {@code DEFAULT} results in output that
473d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *               adheres to RFC 2045.
474d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
475d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    public static String encodeToString(byte[] input, int offset, int len, int flags) {
4769df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        try {
4779df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            return new String(encode(input, offset, len, flags), "US-ASCII");
4789df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        } catch (UnsupportedEncodingException e) {
4799df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            // US-ASCII is guaranteed to be available.
4809df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            throw new AssertionError(e);
4819df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        }
482d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    }
483d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
484d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
485d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * Base64-encode the given data and return a newly allocated
486d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * byte[] with the result.
487d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *
488d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param input  the data to encode
489d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param flags  controls certain features of the encoded output.
490d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *               Passing {@code DEFAULT} results in output that
491d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *               adheres to RFC 2045.
492d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
493d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    public static byte[] encode(byte[] input, int flags) {
494d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        return encode(input, 0, input.length, flags);
495d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    }
496d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
497d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    /**
498d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * Base64-encode the given data and return a newly allocated
499d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * byte[] with the result.
500d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *
501d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param input  the data to encode
502d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param offset the position within the input array at which to
503d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *               start
504d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param len    the number of bytes of input to encode
505d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     * @param flags  controls certain features of the encoded output.
506d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *               Passing {@code DEFAULT} results in output that
507d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     *               adheres to RFC 2045.
508d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker     */
509d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    public static byte[] encode(byte[] input, int offset, int len, int flags) {
5109df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        Encoder encoder = new Encoder(flags, null);
511d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
512d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        // Compute the exact length of the array we will produce.
513d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        int output_len = len / 3 * 4;
514d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
515d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        // Account for the tail of the data and the padding bytes, if any.
5169df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        if (encoder.do_padding) {
517d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            if (len % 3 > 0) {
518d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                output_len += 4;
519d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            }
520d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        } else {
521d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            switch (len % 3) {
522d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                case 0: break;
523d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                case 1: output_len += 2; break;
524d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                case 2: output_len += 3; break;
525d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            }
526d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        }
527d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
528d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        // Account for the newlines, if any.
5299df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        if (encoder.do_newline && len > 0) {
5309df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            output_len += (((len-1) / (3 * Encoder.LINE_GROUPS)) + 1) *
5319df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                (encoder.do_cr ? 2 : 1);
532d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        }
533d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
5349df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        encoder.output = new byte[output_len];
5359df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        encoder.process(input, offset, len, true);
536d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
5379df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        assert encoder.op == output_len;
538d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
5399df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        return encoder.output;
540d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    }
541d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
5429df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker    /* package */ static class Encoder extends Coder {
5439df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        /**
5449df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * Emit a new line every this many output tuples.  Corresponds to
5459df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * a 76-character line length (the maximum allowable according to
5469df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>).
5479df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         */
5489df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        public static final int LINE_GROUPS = 19;
5499df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
5509df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        /**
5519df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * Lookup table for turning Base64 alphabet positions (6 bits)
5529df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * into output bytes.
5539df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         */
5549df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        private static final byte ENCODE[] = {
5559df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
5569df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
5579df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
5589df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
5599df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        };
5609df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
5619df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        /**
5629df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * Lookup table for turning Base64 alphabet positions (6 bits)
5639df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * into output bytes.
5649df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         */
5659df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        private static final byte ENCODE_WEBSAFE[] = {
5669df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
5679df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
5689df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
5699df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_',
5709df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        };
5719df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
5729df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        final private byte[] tail;
5739df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        /* package */ int tailLen;
5749df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        private int count;
575d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
576d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        final public boolean do_padding;
577d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        final public boolean do_newline;
578d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        final public boolean do_cr;
5799df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        final private byte[] alphabet;
580d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
5819df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        public Encoder(int flags, byte[] output) {
582d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            this.output = output;
583d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
584d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            do_padding = (flags & NO_PADDING) == 0;
585d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            do_newline = (flags & NO_WRAP) == 0;
586d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            do_cr = (flags & CRLF) != 0;
5879df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            alphabet = ((flags & URL_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE;
588d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
589d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            tail = new byte[2];
590d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            tailLen = 0;
591d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
592d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            count = do_newline ? LINE_GROUPS : -1;
593d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker        }
594d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
5959df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        /**
5969df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * @return an overestimate for the number of bytes {@code
5979df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         * len} bytes could encode to.
5989df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker         */
5999df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        public int maxOutputSize(int len) {
6009df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            return len * 8/5 + 10;
6019df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        }
602d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
6039df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        public boolean process(byte[] input, int offset, int len, boolean finish) {
6049df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            // Using local variables makes the encoder about 9% faster.
6059df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            final byte[] alphabet = this.alphabet;
6069df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            final byte[] output = this.output;
6079df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            int op = 0;
6089df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            int count = this.count;
609d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
6109df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            int p = offset;
6119df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            len += offset;
6129df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            int v = -1;
613d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
6149df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            // First we need to concatenate the tail of the previous call
6159df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            // with any input bytes available now and see if we can empty
6169df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            // the tail.
617d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
6189df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            switch (tailLen) {
6199df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                case 0:
6209df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    // There was no tail.
6219df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    break;
622d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
6239df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                case 1:
6249df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    if (p+2 <= len) {
6259df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        // A 1-byte tail with at least 2 bytes of
6269df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        // input available now.
6279df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        v = ((tail[0] & 0xff) << 16) |
6289df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                            ((input[p++] & 0xff) << 8) |
6299df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                            (input[p++] & 0xff);
6309df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        tailLen = 0;
6319df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    };
6329df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    break;
633d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
6349df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                case 2:
6359df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    if (p+1 <= len) {
6369df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        // A 2-byte tail with at least 1 byte of input.
6379df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        v = ((tail[0] & 0xff) << 16) |
6389df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                            ((tail[1] & 0xff) << 8) |
6399df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                            (input[p++] & 0xff);
6409df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        tailLen = 0;
6419df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    }
6429df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    break;
643d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            }
644d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
6459df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            if (v != -1) {
6469df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                output[op++] = alphabet[(v >> 18) & 0x3f];
6479df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                output[op++] = alphabet[(v >> 12) & 0x3f];
6489df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                output[op++] = alphabet[(v >> 6) & 0x3f];
6499df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                output[op++] = alphabet[v & 0x3f];
6509df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                if (--count == 0) {
6519df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    if (do_cr) output[op++] = '\r';
6529df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    output[op++] = '\n';
6539df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    count = LINE_GROUPS;
6549df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                }
655d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            }
656d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
6579df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            // At this point either there is no tail, or there are fewer
6589df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            // than 3 bytes of input available.
6599df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
6609df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            // The main loop, turning 3 input bytes into 4 output bytes on
6619df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            // each iteration.
6629df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            while (p+3 <= len) {
6639df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                v = ((input[p] & 0xff) << 16) |
6649df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    ((input[p+1] & 0xff) << 8) |
6659df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    (input[p+2] & 0xff);
6669df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                output[op] = alphabet[(v >> 18) & 0x3f];
6679df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                output[op+1] = alphabet[(v >> 12) & 0x3f];
6689df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                output[op+2] = alphabet[(v >> 6) & 0x3f];
6699df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                output[op+3] = alphabet[v & 0x3f];
6709df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                p += 3;
6719df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                op += 4;
6729df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                if (--count == 0) {
673d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    if (do_cr) output[op++] = '\r';
674d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    output[op++] = '\n';
6759df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    count = LINE_GROUPS;
676d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                }
6779df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            }
6789df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
6799df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            if (finish) {
6809df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // Finish up the tail of the input.  Note that we need to
6819df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // consume any bytes in tail before any bytes
6829df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // remaining in input; there should be at most two bytes
6839df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // total.
6849df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
6859df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                if (p-tailLen == len-1) {
6869df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    int t = 0;
6879df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    v = ((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 4;
6889df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    tailLen -= t;
6899df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    output[op++] = alphabet[(v >> 6) & 0x3f];
6909df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    output[op++] = alphabet[v & 0x3f];
6919df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    if (do_padding) {
6929df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        output[op++] = '=';
6939df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        output[op++] = '=';
6949df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    }
6959df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    if (do_newline) {
6969df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        if (do_cr) output[op++] = '\r';
6979df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        output[op++] = '\n';
6989df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    }
6999df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                } else if (p-tailLen == len-2) {
7009df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    int t = 0;
7019df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    v = (((tailLen > 1 ? tail[t++] : input[p++]) & 0xff) << 10) |
7029df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        (((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 2);
7039df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    tailLen -= t;
7049df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    output[op++] = alphabet[(v >> 12) & 0x3f];
7059df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    output[op++] = alphabet[(v >> 6) & 0x3f];
7069df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    output[op++] = alphabet[v & 0x3f];
7079df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    if (do_padding) {
7089df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        output[op++] = '=';
7099df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    }
7109df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    if (do_newline) {
7119df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        if (do_cr) output[op++] = '\r';
7129df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                        output[op++] = '\n';
7139df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    }
7149df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                } else if (do_newline && op > 0 && count != LINE_GROUPS) {
715d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    if (do_cr) output[op++] = '\r';
716d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                    output[op++] = '\n';
717d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker                }
718d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
7199df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                assert tailLen == 0;
7209df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                assert p == len;
7219df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            } else {
7229df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // Save the leftovers in tail to be consumed on the next
7239df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                // call to encodeInternal.
7249df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
7259df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                if (p == len-1) {
7269df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    tail[tailLen++] = input[p];
7279df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                } else if (p == len-2) {
7289df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    tail[tailLen++] = input[p];
7299df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                    tail[tailLen++] = input[p+1];
7309df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker                }
731d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker            }
732d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
7339df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            this.op = op;
7349df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            this.count = count;
7359df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker
7369df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker            return true;
7379df2ffd4205115a68c4fe0651b2072e3e4573dd2Doug Zongker        }
738d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    }
739d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker
740d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker    private Base64() { }   // don't instantiate
741d2affae13dfdb116adaee1bb10aaaac80a885481Doug Zongker}
742