src/share/classes/java/util/Base64.java

Print this page




  33 import java.nio.charset.StandardCharsets;
  34 
  35 /**
  36  * This class consists exclusively of static methods for obtaining
  37  * encoders and decoders for the Base64 encoding scheme. The
  38  * implementation of this class supports the following types of Base64
  39  * as specified in
  40  * <a href="http://www.ietf.org/rfc/rfc4648.txt">RFC 4648</a> and
  41  * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>.
  42  *
  43  * <ul>
  44  * <li><a name="basic"><b>Basic</b></a>
  45  * <p> Uses "The Base64 Alphabet" as specified in Table 1 of
  46  *     RFC 4648 and RFC 2045 for encoding and decoding operation.
  47  *     The encoder does not add any line feed (line separator)
  48  *     character. The decoder rejects data that contains characters
  49  *     outside the base64 alphabet.</p></li>
  50  *
  51  * <li><a name="url"><b>URL and Filename safe</b></a>
  52  * <p> Uses the "URL and Filename safe Base64 Alphabet" as specified
  53  *     in Table 2 of RFC 4648 for encoding and decoding. The
  54  *     encoder does not add any line feed (line separator) character.
  55  *     The decoder rejects data that contains characters outside the
  56  *     base64 alphabet.</p></li>
  57  *
  58  * <li><a name="mime"><b>MIME</b></a>
  59  * <p> Uses the "The Base64 Alphabet" as specified in Table 1 of
  60  *     RFC 2045 for encoding and decoding operation. The encoded output
  61  *     must be represented in lines of no more than 76 characters each
  62  *     and uses a carriage return {@code '\r'} followed immediately by
  63  *     a linefeed {@code '\n'} as the line separator. No line separator
  64  *     is added to the end of the encoded output. All line separators
  65  *     or other characters not found in the base64 alphabet table are
  66  *     ignored in decoding operation.</p></li>
  67  * </ul>
  68  *
  69  * <p> Unless otherwise noted, passing a {@code null} argument to a
  70  * method of this class will cause a {@link java.lang.NullPointerException
  71  * NullPointerException} to be thrown.
  72  *
  73  * @author  Xueming Shen


 121      * @param   lineSeparator
 122      *          the line separator for each output line
 123      *
 124      * @return  A Base64 encoder.
 125      *
 126      * @throws  IllegalArgumentException if {@code lineSeparator} includes any
 127      *          character of "The Base64 Alphabet" as specified in Table 1 of
 128      *          RFC 2045.
 129      */
 130     public static Encoder getMimeEncoder(int lineLength, byte[] lineSeparator) {
 131          Objects.requireNonNull(lineSeparator);
 132          int[] base64 = Decoder.fromBase64;
 133          for (byte b : lineSeparator) {
 134              if (base64[b & 0xff] != -1)
 135                  throw new IllegalArgumentException(
 136                      "Illegal base64 line separator character 0x" + Integer.toString(b, 16));
 137          }
 138          if (lineLength <= 0) {
 139              return Encoder.RFC4648;
 140          }
 141          return new Encoder(false, lineSeparator, lineLength >> 2 << 2);
 142     }
 143 
 144     /**
 145      * Returns a {@link Decoder} that decodes using the
 146      * <a href="#basic">Basic</a> type base64 encoding scheme.
 147      *
 148      * @return  A Base64 decoder.
 149      */
 150     public static Decoder getDecoder() {
 151          return Decoder.RFC4648;
 152     }
 153 
 154     /**
 155      * Returns a {@link Decoder} that decodes using the
 156      * <a href="#url">URL and Filename safe</a> type base64
 157      * encoding scheme.
 158      *
 159      * @return  A Base64 decoder.
 160      */
 161     public static Decoder getUrlDecoder() {


 175     /**
 176      * This class implements an encoder for encoding byte data using
 177      * the Base64 encoding scheme as specified in RFC 4648 and RFC 2045.
 178      *
 179      * <p> Instances of {@link Encoder} class are safe for use by
 180      * multiple concurrent threads.
 181      *
 182      * <p> Unless otherwise noted, passing a {@code null} argument to
 183      * a method of this class will cause a
 184      * {@link java.lang.NullPointerException NullPointerException} to
 185      * be thrown.
 186      *
 187      * @see     Decoder
 188      * @since   1.8
 189      */
 190     public static class Encoder {
 191 
 192         private final byte[] newline;
 193         private final int linemax;
 194         private final boolean isURL;

 195 
 196         private Encoder(boolean isURL, byte[] newline, int linemax) {
 197             this.isURL = isURL;
 198             this.newline = newline;
 199             this.linemax = linemax;

 200         }
 201 
 202         /**
 203          * This array is a lookup table that translates 6-bit positive integer
 204          * index values into their "Base64 Alphabet" equivalents as specified
 205          * in "Table 1: The Base64 Alphabet" of RFC 2045 (and RFC 4648).
 206          */
 207         private static final char[] toBase64 = {
 208             'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
 209             'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
 210             'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
 211             'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
 212             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
 213         };
 214 
 215         /**
 216          * It's the lookup table for "URL and Filename safe Base64" as specified
 217          * in Table 2 of the RFC 4648, with the '+' and '/' changed to '-' and
 218          * '_'. This table is used when BASE64_URL is specified.
 219          */
 220         private static final char[] toBase64URL = {
 221             'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
 222             'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
 223             'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
 224             'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
 225             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
 226         };
 227 
 228         private static final int MIMELINEMAX = 76;
 229         private static final byte[] CRLF = new byte[] {'\r', '\n'};
 230 
 231         static final Encoder RFC4648 = new Encoder(false, null, -1);
 232         static final Encoder RFC4648_URLSAFE = new Encoder(true, null, -1);
 233         static final Encoder RFC2045 = new Encoder(false, CRLF, MIMELINEMAX);













 234 
 235         /**
 236          * Encodes all bytes from the specified byte array into a newly-allocated
 237          * byte array using the {@link Base64} encoding scheme. The returned byte
 238          * array is of the length of the resulting bytes.
 239          *
 240          * @param   src
 241          *          the byte array to encode
 242          * @return  A newly-allocated byte array containing the resulting
 243          *          encoded bytes.
 244          */
 245         public byte[] encode(byte[] src) {
 246             int len = 4 * ((src.length + 2) / 3);    // dst array size
 247             if (linemax > 0)                          // line separators
 248                 len += (len - 1) / linemax * newline.length;
 249             byte[] dst = new byte[len];
 250             int ret = encode0(src, 0, src.length, dst);
 251             if (ret != dst.length)
 252                  return Arrays.copyOf(dst, ret);
 253             return dst;
 254         }
 255 
 256         /**
 257          * Encodes all bytes from the specified byte array using the
 258          * {@link Base64} encoding scheme, writing the resulting bytes to the
 259          * given output byte array, starting at offset 0.
 260          *
 261          * <p> It is the responsibility of the invoker of this method to make
 262          * sure the output byte array {@code dst} has enough space for encoding
 263          * all bytes from the input byte array. No bytes will be written to the
 264          * output byte array if the output byte array is not big enough.
 265          *
 266          * @param   src
 267          *          the byte array to encode
 268          * @param   dst
 269          *          the output byte array
 270          * @return  The number of bytes written to the output byte array
 271          *
 272          * @throws  IllegalArgumentException if {@code dst} does not have enough
 273          *          space for encoding all input bytes.
 274          */
 275         public int encode(byte[] src, byte[] dst) {
 276             int len = 4 * ((src.length + 2) / 3);    // dst array size
 277             if (linemax > 0) {
 278                 len += (len - 1) / linemax * newline.length;
 279             }
 280             if (dst.length < len)
 281                 throw new IllegalArgumentException(
 282                     "Output byte array is too small for encoding all input bytes");
 283             return encode0(src, 0, src.length, dst);
 284         }
 285 
 286         /**
 287          * Encodes the specified byte array into a String using the {@link Base64}
 288          * encoding scheme.
 289          *
 290          * <p> This method first encodes all input bytes into a base64 encoded
 291          * byte array and then constructs a new String by using the encoded byte
 292          * array and the {@link java.nio.charset.StandardCharsets#ISO_8859_1
 293          * ISO-8859-1} charset.
 294          *
 295          * <p> In other words, an invocation of this method has exactly the same
 296          * effect as invoking
 297          * {@code new String(encode(src), StandardCharsets.ISO_8859_1)}.
 298          *
 299          * @param   src


 304         public String encodeToString(byte[] src) {
 305             byte[] encoded = encode(src);
 306             return new String(encoded, 0, 0, encoded.length);
 307         }
 308 
 309         /**
 310          * Encodes all remaining bytes from the specified byte buffer into
 311          * a newly-allocated ByteBuffer using the {@link Base64} encoding
 312          * scheme.
 313          *
 314          * Upon return, the source buffer's position will be updated to
 315          * its limit; its limit will not have been changed. The returned
 316          * output buffer's position will be zero and its limit will be the
 317          * number of resulting encoded bytes.
 318          *
 319          * @param   buffer
 320          *          the source ByteBuffer to encode
 321          * @return  A newly-allocated byte buffer containing the encoded bytes.
 322          */
 323         public ByteBuffer encode(ByteBuffer buffer) {
 324             int len = 4 * ((buffer.remaining() + 2) / 3);
 325             if (linemax > 0)
 326                 len += (len - 1) / linemax * newline.length;
 327             byte[] dst = new byte[len];
 328             int ret = 0;
 329             if (buffer.hasArray()) {
 330                 ret = encode0(buffer.array(),
 331                               buffer.arrayOffset() + buffer.position(),
 332                               buffer.arrayOffset() + buffer.limit(),
 333                               dst);
 334                 buffer.position(buffer.limit());
 335             } else {
 336                 byte[] src = new byte[buffer.remaining()];
 337                 buffer.get(src);
 338                 ret = encode0(src, 0, src.length, dst);
 339             }
 340             if (ret != dst.length)
 341                  dst = Arrays.copyOf(dst, ret);
 342             return ByteBuffer.wrap(dst);
 343         }
 344 
 345         /**
 346          * Encodes as many bytes as possible from the input byte buffer


 398             return encodeBuffer(src, dst, bytesOut);
 399         }
 400 
 401         /**
 402          * Wraps an output stream for encoding byte data using the {@link Base64}
 403          * encoding scheme.
 404          *
 405          * <p> It is recommended to promptly close the returned output stream after
 406          * use, during which it will flush all possible leftover bytes to the underlying
 407          * output stream. Closing the returned output stream will close the underlying
 408          * output stream.
 409          *
 410          * @param   os
 411          *          the output stream.
 412          * @return  the output stream for encoding the byte data into the
 413          *          specified Base64 encoded format
 414          */
 415         public OutputStream wrap(OutputStream os) {
 416             Objects.requireNonNull(os);
 417             return new EncOutputStream(os, isURL ? toBase64URL : toBase64,
 418                                        newline, linemax);


















 419         }
 420 
 421         private int encodeArray(ByteBuffer src, ByteBuffer dst, int bytesOut) {
 422             char[] base64 = isURL? toBase64URL : toBase64;
 423             byte[] sa = src.array();
 424             int    sp = src.arrayOffset() + src.position();
 425             int    sl = src.arrayOffset() + src.limit();
 426             byte[] da = dst.array();
 427             int    dp = dst.arrayOffset() + dst.position();
 428             int    dl = dst.arrayOffset() + dst.limit();
 429             int    dp00 = dp;
 430             int    dpos = 0;        // dp of each line
 431             if (linemax > 0 && bytesOut > 0)
 432                 dpos = bytesOut % (linemax + newline.length);
 433             try {
 434                 if (dpos == linemax && sp < src.limit()) {
 435                     if (dp + newline.length > dl)
 436                         return  dp - dp00 + bytesOut;
 437                     for (byte b : newline){
 438                         dst.put(dp++, b);


 459                     }
 460                     int n = (sl0 - sp) / 3 * 4;
 461                     dpos += n;
 462                     dp += n;
 463                     sp = sl0;
 464                     if (dpos == linemax && sp < src.limit()) {
 465                         if (dp + newline.length > dl)
 466                             return  dp - dp00 + bytesOut;
 467                         for (byte b : newline){
 468                             da[dp++] = b;
 469                         }
 470                         dpos = 0;
 471                     }
 472                 }
 473                 sl = src.arrayOffset() + src.limit();
 474                 if (sp < sl && dl >= dp + 4) {       // 1 or 2 leftover bytes
 475                     int b0 = sa[sp++] & 0xff;
 476                     da[dp++] = (byte)base64[b0 >> 2];
 477                     if (sp == sl) {
 478                         da[dp++] = (byte)base64[(b0 << 4) & 0x3f];

 479                         da[dp++] = '=';
 480                         da[dp++] = '=';

 481                     } else {
 482                         int b1 = sa[sp++] & 0xff;
 483                         da[dp++] = (byte)base64[(b0 << 4) & 0x3f | (b1 >> 4)];
 484                         da[dp++] = (byte)base64[(b1 << 2) & 0x3f];

 485                         da[dp++] = '=';
 486                     }
 487                 }

 488                 return dp - dp00 + bytesOut;
 489             } finally {
 490                 src.position(sp - src.arrayOffset());
 491                 dst.position(dp - dst.arrayOffset());
 492             }
 493         }
 494 
 495         private int encodeBuffer(ByteBuffer src, ByteBuffer dst, int bytesOut) {
 496             char[] base64 = isURL? toBase64URL : toBase64;
 497             int sp = src.position();
 498             int sl = src.limit();
 499             int dp = dst.position();
 500             int dl = dst.limit();
 501             int dp00 = dp;
 502 
 503             int dpos = 0;        // dp of each line
 504             if (linemax > 0 && bytesOut > 0)
 505                 dpos = bytesOut % (linemax + newline.length);
 506             try {
 507                 if (dpos == linemax && sp < src.limit()) {


 531                         dst.put(dp0++, (byte)base64[bits & 0x3f]);
 532                     }
 533                     int n = (sl0 - sp) / 3 * 4;
 534                     dpos += n;
 535                     dp += n;
 536                     sp = sl0;
 537                     if (dpos == linemax && sp < src.limit()) {
 538                         if (dp + newline.length > dl)
 539                             return  dp - dp00 + bytesOut;
 540                         for (byte b : newline){
 541                             dst.put(dp++, b);
 542                         }
 543                         dpos = 0;
 544                     }
 545                 }
 546                 if (sp < src.limit() && dl >= dp + 4) {       // 1 or 2 leftover bytes
 547                     int b0 = src.get(sp++) & 0xff;
 548                     dst.put(dp++, (byte)base64[b0 >> 2]);
 549                     if (sp == src.limit()) {
 550                         dst.put(dp++, (byte)base64[(b0 << 4) & 0x3f]);

 551                         dst.put(dp++, (byte)'=');
 552                         dst.put(dp++, (byte)'=');

 553                     } else {
 554                         int b1 = src.get(sp++) & 0xff;
 555                         dst.put(dp++, (byte)base64[(b0 << 4) & 0x3f | (b1 >> 4)]);
 556                         dst.put(dp++, (byte)base64[(b1 << 2) & 0x3f]);

 557                         dst.put(dp++, (byte)'=');
 558                     }
 559                 }

 560                 return dp - dp00 + bytesOut;
 561             } finally {
 562                 src.position(sp);
 563                 dst.position(dp);
 564             }
 565         }
 566 
 567         private int encode0(byte[] src, int off, int end, byte[] dst) {
 568             char[] base64 = isURL ? toBase64URL : toBase64;
 569             int sp = off;
 570             int slen = (end - off) / 3 * 3;
 571             int sl = off + slen;
 572             if (linemax > 0 && slen  > linemax / 4 * 3)
 573                 slen = linemax / 4 * 3;
 574             int dp = 0;
 575             while (sp < sl) {
 576                 int sl0 = Math.min(sp + slen, sl);
 577                 for (int sp0 = sp, dp0 = dp ; sp0 < sl0; ) {
 578                     int bits = (src[sp0++] & 0xff) << 16 |
 579                                (src[sp0++] & 0xff) <<  8 |
 580                                (src[sp0++] & 0xff);
 581                     dst[dp0++] = (byte)base64[(bits >>> 18) & 0x3f];
 582                     dst[dp0++] = (byte)base64[(bits >>> 12) & 0x3f];
 583                     dst[dp0++] = (byte)base64[(bits >>> 6)  & 0x3f];
 584                     dst[dp0++] = (byte)base64[bits & 0x3f];
 585                 }
 586                 int dlen = (sl0 - sp) / 3 * 4;
 587                 dp += dlen;
 588                 sp = sl0;
 589                 if (dlen == linemax && sp < end) {
 590                     for (byte b : newline){
 591                         dst[dp++] = b;
 592                     }
 593                 }
 594             }
 595             if (sp < end) {               // 1 or 2 leftover bytes
 596                 int b0 = src[sp++] & 0xff;
 597                 dst[dp++] = (byte)base64[b0 >> 2];
 598                 if (sp == end) {
 599                     dst[dp++] = (byte)base64[(b0 << 4) & 0x3f];

 600                     dst[dp++] = '=';
 601                     dst[dp++] = '=';

 602                 } else {
 603                     int b1 = src[sp++] & 0xff;
 604                     dst[dp++] = (byte)base64[(b0 << 4) & 0x3f | (b1 >> 4)];
 605                     dst[dp++] = (byte)base64[(b1 << 2) & 0x3f];

 606                     dst[dp++] = '=';
 607                 }
 608             }

 609             return dp;
 610         }
 611     }
 612 
 613     /**
 614      * This class implements a decoder for decoding byte data using the
 615      * Base64 encoding scheme as specified in RFC 4648 and RFC 2045.
 616      *
 617      * <p> The Base64 padding character {@code '='} is accepted and
 618      * interpreted as the end of the encoded byte data, but is not
 619      * required. So if the final unit of the encoded byte data only has
 620      * two or three Base64 characters (without the corresponding padding
 621      * character(s) padded), they are decoded as if followed by padding
 622      * character(s).
 623      * <p>
 624      * For decoders that use the <a href="#basic">Basic</a> and
 625      * <a href="#url">URL and Filename safe</a> type base64 scheme, and
 626      * if there is padding character present in the final unit, the
 627      * correct number of padding character(s) must be present, otherwise
 628      * {@code IllegalArgumentException} ({@code IOException} when reading


1132             if (sp < sl && !isMIME) {
1133                 throw new IllegalArgumentException(
1134                     "Input byte array has incorrect ending byte at " + sp);
1135             }
1136             return dp;
1137         }
1138     }
1139 
1140     /*
1141      * An output stream for encoding bytes into the Base64.
1142      */
1143     private static class EncOutputStream extends FilterOutputStream {
1144 
1145         private int leftover = 0;
1146         private int b0, b1, b2;
1147         private boolean closed = false;
1148 
1149         private final char[] base64;    // byte->base64 mapping
1150         private final byte[] newline;   // line separator, if needed
1151         private final int linemax;

1152         private int linepos = 0;
1153 
1154         EncOutputStream(OutputStream os,
1155                         char[] base64, byte[] newline, int linemax) {
1156             super(os);
1157             this.base64 = base64;
1158             this.newline = newline;
1159             this.linemax = linemax;

1160         }
1161 
1162         @Override
1163         public void write(int b) throws IOException {
1164             byte[] buf = new byte[1];
1165             buf[0] = (byte)(b & 0xff);
1166             write(buf, 0, 1);
1167         }
1168 
1169         private void checkNewline() throws IOException {
1170             if (linepos == linemax) {
1171                 out.write(newline);
1172                 linepos = 0;
1173             }
1174         }
1175 
1176         @Override
1177         public void write(byte[] b, int off, int len) throws IOException {
1178             if (closed)
1179                 throw new IOException("Stream is closed");


1211                 out.write(base64[(bits >>> 6)  & 0x3f]);
1212                 out.write(base64[bits & 0x3f]);
1213                 linepos += 4;
1214            }
1215             if (leftover == 1) {
1216                 b0 = b[off++] & 0xff;
1217             } else if (leftover == 2) {
1218                 b0 = b[off++] & 0xff;
1219                 b1 = b[off++] & 0xff;
1220             }
1221         }
1222 
1223         @Override
1224         public void close() throws IOException {
1225             if (!closed) {
1226                 closed = true;
1227                 if (leftover == 1) {
1228                     checkNewline();
1229                     out.write(base64[b0 >> 2]);
1230                     out.write(base64[(b0 << 4) & 0x3f]);

1231                     out.write('=');
1232                     out.write('=');

1233                 } else if (leftover == 2) {
1234                     checkNewline();
1235                     out.write(base64[b0 >> 2]);
1236                     out.write(base64[(b0 << 4) & 0x3f | (b1 >> 4)]);
1237                     out.write(base64[(b1 << 2) & 0x3f]);

1238                     out.write('=');
1239                 }

1240                 leftover = 0;
1241                 out.close();
1242             }
1243         }
1244     }
1245 
1246     /*
1247      * An input stream for decoding Base64 bytes
1248      */
1249     private static class DecInputStream extends InputStream {
1250 
1251         private final InputStream is;
1252         private final boolean isMIME;
1253         private final int[] base64;      // base64 -> byte mapping
1254         private int bits = 0;            // 24-bit buffer for decoding
1255         private int nextin = 18;         // next available "off" in "bits" for input;
1256                                          // -> 18, 12, 6, 0
1257         private int nextout = -8;        // next available "off" in "bits" for output;
1258                                          // -> 8, 0, -8 (no byte for output)
1259         private boolean eof = false;




  33 import java.nio.charset.StandardCharsets;
  34 
  35 /**
  36  * This class consists exclusively of static methods for obtaining
  37  * encoders and decoders for the Base64 encoding scheme. The
  38  * implementation of this class supports the following types of Base64
  39  * as specified in
  40  * <a href="http://www.ietf.org/rfc/rfc4648.txt">RFC 4648</a> and
  41  * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>.
  42  *
  43  * <ul>
  44  * <li><a name="basic"><b>Basic</b></a>
  45  * <p> Uses "The Base64 Alphabet" as specified in Table 1 of
  46  *     RFC 4648 and RFC 2045 for encoding and decoding operation.
  47  *     The encoder does not add any line feed (line separator)
  48  *     character. The decoder rejects data that contains characters
  49  *     outside the base64 alphabet.</p></li>
  50  *
  51  * <li><a name="url"><b>URL and Filename safe</b></a>
  52  * <p> Uses the "URL and Filename safe Base64 Alphabet" as specified
  53 *     in Table 2 of RFC 4648 for encoding and decoding. The
  54  *     encoder does not add any line feed (line separator) character.
  55  *     The decoder rejects data that contains characters outside the
  56  *     base64 alphabet.</p></li>
  57  *
  58  * <li><a name="mime"><b>MIME</b></a>
  59  * <p> Uses the "The Base64 Alphabet" as specified in Table 1 of
  60  *     RFC 2045 for encoding and decoding operation. The encoded output
  61  *     must be represented in lines of no more than 76 characters each
  62  *     and uses a carriage return {@code '\r'} followed immediately by
  63  *     a linefeed {@code '\n'} as the line separator. No line separator
  64  *     is added to the end of the encoded output. All line separators
  65  *     or other characters not found in the base64 alphabet table are
  66  *     ignored in decoding operation.</p></li>
  67  * </ul>
  68  *
  69  * <p> Unless otherwise noted, passing a {@code null} argument to a
  70  * method of this class will cause a {@link java.lang.NullPointerException
  71  * NullPointerException} to be thrown.
  72  *
  73  * @author  Xueming Shen


 121      * @param   lineSeparator
 122      *          the line separator for each output line
 123      *
 124      * @return  A Base64 encoder.
 125      *
 126      * @throws  IllegalArgumentException if {@code lineSeparator} includes any
 127      *          character of "The Base64 Alphabet" as specified in Table 1 of
 128      *          RFC 2045.
 129      */
 130     public static Encoder getMimeEncoder(int lineLength, byte[] lineSeparator) {
 131          Objects.requireNonNull(lineSeparator);
 132          int[] base64 = Decoder.fromBase64;
 133          for (byte b : lineSeparator) {
 134              if (base64[b & 0xff] != -1)
 135                  throw new IllegalArgumentException(
 136                      "Illegal base64 line separator character 0x" + Integer.toString(b, 16));
 137          }
 138          if (lineLength <= 0) {
 139              return Encoder.RFC4648;
 140          }
 141          return new Encoder(false, lineSeparator, lineLength >> 2 << 2, true);
 142     }
 143 
 144     /**
 145      * Returns a {@link Decoder} that decodes using the
 146      * <a href="#basic">Basic</a> type base64 encoding scheme.
 147      *
 148      * @return  A Base64 decoder.
 149      */
 150     public static Decoder getDecoder() {
 151          return Decoder.RFC4648;
 152     }
 153 
 154     /**
 155      * Returns a {@link Decoder} that decodes using the
 156      * <a href="#url">URL and Filename safe</a> type base64
 157      * encoding scheme.
 158      *
 159      * @return  A Base64 decoder.
 160      */
 161     public static Decoder getUrlDecoder() {


 175     /**
 176      * This class implements an encoder for encoding byte data using
 177      * the Base64 encoding scheme as specified in RFC 4648 and RFC 2045.
 178      *
 179      * <p> Instances of {@link Encoder} class are safe for use by
 180      * multiple concurrent threads.
 181      *
 182      * <p> Unless otherwise noted, passing a {@code null} argument to
 183      * a method of this class will cause a
 184      * {@link java.lang.NullPointerException NullPointerException} to
 185      * be thrown.
 186      *
 187      * @see     Decoder
 188      * @since   1.8
 189      */
 190     public static class Encoder {
 191 
 192         private final byte[] newline;
 193         private final int linemax;
 194         private final boolean isURL;
 195         private final boolean doPadding;
 196 
 197         private Encoder(boolean isURL, byte[] newline, int linemax, boolean doPadding) {
 198             this.isURL = isURL;
 199             this.newline = newline;
 200             this.linemax = linemax;
 201             this.doPadding = doPadding;
 202         }
 203 
 204         /**
 205          * This array is a lookup table that translates 6-bit positive integer
 206          * index values into their "Base64 Alphabet" equivalents as specified
 207          * in "Table 1: The Base64 Alphabet" of RFC 2045 (and RFC 4648).
 208          */
 209         private static final char[] toBase64 = {
 210             'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
 211             'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
 212             'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
 213             'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
 214             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
 215         };
 216 
 217         /**
 218          * It's the lookup table for "URL and Filename safe Base64" as specified
 219          * in Table 2 of the RFC 4648, with the '+' and '/' changed to '-' and
 220          * '_'. This table is used when BASE64_URL is specified.
 221          */
 222         private static final char[] toBase64URL = {
 223             'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
 224             'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
 225             'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
 226             'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
 227             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
 228         };
 229 
 230         private static final int MIMELINEMAX = 76;
 231         private static final byte[] CRLF = new byte[] {'\r', '\n'};
 232 
 233         static final Encoder RFC4648 = new Encoder(false, null, -1, true);
 234         static final Encoder RFC4648_URLSAFE = new Encoder(true, null, -1, true);
 235         static final Encoder RFC2045 = new Encoder(false, CRLF, MIMELINEMAX, true);
 236 
 237         private final int outLength(int srclen) {
 238             int len = 0;
 239             if (doPadding) {
 240                 len = 4 * ((srclen + 2) / 3);
 241             } else {
 242                 int n = srclen % 3;
 243                 len = 4 * (srclen / 3) + (n == 0 ? 0 : n + 1);
 244             }
 245             if (linemax > 0)                                  // line separators
 246                 len += (len - 1) / linemax * newline.length;
 247             return len;
 248         }
 249 
 250         /**
 251          * Encodes all bytes from the specified byte array into a newly-allocated
 252          * byte array using the {@link Base64} encoding scheme. The returned byte
 253          * array is of the length of the resulting bytes.
 254          *
 255          * @param   src
 256          *          the byte array to encode
 257          * @return  A newly-allocated byte array containing the resulting
 258          *          encoded bytes.
 259          */
 260         public byte[] encode(byte[] src) {
 261             int len = outLength(src.length);          // dst array size


 262             byte[] dst = new byte[len];
 263             int ret = encode0(src, 0, src.length, dst);
 264             if (ret != dst.length)
 265                  return Arrays.copyOf(dst, ret);
 266             return dst;
 267         }
 268 
 269         /**
 270          * Encodes all bytes from the specified byte array using the
 271          * {@link Base64} encoding scheme, writing the resulting bytes to the
 272          * given output byte array, starting at offset 0.
 273          *
 274          * <p> It is the responsibility of the invoker of this method to make
 275          * sure the output byte array {@code dst} has enough space for encoding
 276          * all bytes from the input byte array. No bytes will be written to the
 277          * output byte array if the output byte array is not big enough.
 278          *
 279          * @param   src
 280          *          the byte array to encode
 281          * @param   dst
 282          *          the output byte array
 283          * @return  The number of bytes written to the output byte array
 284          *
 285          * @throws  IllegalArgumentException if {@code dst} does not have enough
 286          *          space for encoding all input bytes.
 287          */
 288         public int encode(byte[] src, byte[] dst) {
 289             int len = outLength(src.length);         // dst array size



 290             if (dst.length < len)
 291                 throw new IllegalArgumentException(
 292                     "Output byte array is too small for encoding all input bytes");
 293             return encode0(src, 0, src.length, dst);
 294         }
 295 
 296         /**
 297          * Encodes the specified byte array into a String using the {@link Base64}
 298          * encoding scheme.
 299          *
 300          * <p> This method first encodes all input bytes into a base64 encoded
 301          * byte array and then constructs a new String by using the encoded byte
 302          * array and the {@link java.nio.charset.StandardCharsets#ISO_8859_1
 303          * ISO-8859-1} charset.
 304          *
 305          * <p> In other words, an invocation of this method has exactly the same
 306          * effect as invoking
 307          * {@code new String(encode(src), StandardCharsets.ISO_8859_1)}.
 308          *
 309          * @param   src


 314         public String encodeToString(byte[] src) {
 315             byte[] encoded = encode(src);
 316             return new String(encoded, 0, 0, encoded.length);
 317         }
 318 
 319         /**
 320          * Encodes all remaining bytes from the specified byte buffer into
 321          * a newly-allocated ByteBuffer using the {@link Base64} encoding
 322          * scheme.
 323          *
 324          * Upon return, the source buffer's position will be updated to
 325          * its limit; its limit will not have been changed. The returned
 326          * output buffer's position will be zero and its limit will be the
 327          * number of resulting encoded bytes.
 328          *
 329          * @param   buffer
 330          *          the source ByteBuffer to encode
 331          * @return  A newly-allocated byte buffer containing the encoded bytes.
 332          */
 333         public ByteBuffer encode(ByteBuffer buffer) {
 334             int len = outLength(buffer.remaining());


 335             byte[] dst = new byte[len];
 336             int ret = 0;
 337             if (buffer.hasArray()) {
 338                 ret = encode0(buffer.array(),
 339                               buffer.arrayOffset() + buffer.position(),
 340                               buffer.arrayOffset() + buffer.limit(),
 341                               dst);
 342                 buffer.position(buffer.limit());
 343             } else {
 344                 byte[] src = new byte[buffer.remaining()];
 345                 buffer.get(src);
 346                 ret = encode0(src, 0, src.length, dst);
 347             }
 348             if (ret != dst.length)
 349                  dst = Arrays.copyOf(dst, ret);
 350             return ByteBuffer.wrap(dst);
 351         }
 352 
 353         /**
 354          * Encodes as many bytes as possible from the input byte buffer


 406             return encodeBuffer(src, dst, bytesOut);
 407         }
 408 
 409         /**
 410          * Wraps an output stream for encoding byte data using the {@link Base64}
 411          * encoding scheme.
 412          *
 413          * <p> It is recommended to promptly close the returned output stream after
 414          * use, during which it will flush all possible leftover bytes to the underlying
 415          * output stream. Closing the returned output stream will close the underlying
 416          * output stream.
 417          *
 418          * @param   os
 419          *          the output stream.
 420          * @return  the output stream for encoding the byte data into the
 421          *          specified Base64 encoded format
 422          */
 423         public OutputStream wrap(OutputStream os) {
 424             Objects.requireNonNull(os);
 425             return new EncOutputStream(os, isURL ? toBase64URL : toBase64,
 426                                        newline, linemax, doPadding);
 427         }
 428 
 429         /**
 430          * Returns an encoder instance that encodes equivalently to this one,
 431          * but without adding any padding character at the end of the encoded
 432          * byte data.
 433          *
 434          * <p> The encoding scheme of this encoder instance is unaffected by
 435          * this invocation. The returned encoder instance should be used for
 436          * non-padding encoding operation.
 437          *
 438          * @return an equivalent encoder that encodes without adding any
 439          *         padding character at the end
 440          */
 441         public Encoder withoutPadding() {
 442             if (!doPadding)
 443                 return this;
 444             return new Encoder(isURL, newline, linemax, false);
 445         }
 446 
 447         private int encodeArray(ByteBuffer src, ByteBuffer dst, int bytesOut) {
 448             char[] base64 = isURL? toBase64URL : toBase64;
 449             byte[] sa = src.array();
 450             int    sp = src.arrayOffset() + src.position();
 451             int    sl = src.arrayOffset() + src.limit();
 452             byte[] da = dst.array();
 453             int    dp = dst.arrayOffset() + dst.position();
 454             int    dl = dst.arrayOffset() + dst.limit();
 455             int    dp00 = dp;
 456             int    dpos = 0;        // dp of each line
 457             if (linemax > 0 && bytesOut > 0)
 458                 dpos = bytesOut % (linemax + newline.length);
 459             try {
 460                 if (dpos == linemax && sp < src.limit()) {
 461                     if (dp + newline.length > dl)
 462                         return  dp - dp00 + bytesOut;
 463                     for (byte b : newline){
 464                         dst.put(dp++, b);


 485                     }
 486                     int n = (sl0 - sp) / 3 * 4;
 487                     dpos += n;
 488                     dp += n;
 489                     sp = sl0;
 490                     if (dpos == linemax && sp < src.limit()) {
 491                         if (dp + newline.length > dl)
 492                             return  dp - dp00 + bytesOut;
 493                         for (byte b : newline){
 494                             da[dp++] = b;
 495                         }
 496                         dpos = 0;
 497                     }
 498                 }
 499                 sl = src.arrayOffset() + src.limit();
 500                 if (sp < sl && dl >= dp + 4) {       // 1 or 2 leftover bytes
 501                     int b0 = sa[sp++] & 0xff;
 502                     da[dp++] = (byte)base64[b0 >> 2];
 503                     if (sp == sl) {
 504                         da[dp++] = (byte)base64[(b0 << 4) & 0x3f];
 505                         if (doPadding) {
 506                             da[dp++] = '=';
 507                             da[dp++] = '=';
 508                         }
 509                     } else {
 510                         int b1 = sa[sp++] & 0xff;
 511                         da[dp++] = (byte)base64[(b0 << 4) & 0x3f | (b1 >> 4)];
 512                         da[dp++] = (byte)base64[(b1 << 2) & 0x3f];
 513                         if (doPadding) {
 514                             da[dp++] = '=';
 515                         }
 516                     }
 517                 }
 518                 return dp - dp00 + bytesOut;
 519             } finally {
 520                 src.position(sp - src.arrayOffset());
 521                 dst.position(dp - dst.arrayOffset());
 522             }
 523         }
 524 
 525         private int encodeBuffer(ByteBuffer src, ByteBuffer dst, int bytesOut) {
 526             char[] base64 = isURL? toBase64URL : toBase64;
 527             int sp = src.position();
 528             int sl = src.limit();
 529             int dp = dst.position();
 530             int dl = dst.limit();
 531             int dp00 = dp;
 532 
 533             int dpos = 0;        // dp of each line
 534             if (linemax > 0 && bytesOut > 0)
 535                 dpos = bytesOut % (linemax + newline.length);
 536             try {
 537                 if (dpos == linemax && sp < src.limit()) {


 561                         dst.put(dp0++, (byte)base64[bits & 0x3f]);
 562                     }
 563                     int n = (sl0 - sp) / 3 * 4;
 564                     dpos += n;
 565                     dp += n;
 566                     sp = sl0;
 567                     if (dpos == linemax && sp < src.limit()) {
 568                         if (dp + newline.length > dl)
 569                             return  dp - dp00 + bytesOut;
 570                         for (byte b : newline){
 571                             dst.put(dp++, b);
 572                         }
 573                         dpos = 0;
 574                     }
 575                 }
 576                 if (sp < src.limit() && dl >= dp + 4) {       // 1 or 2 leftover bytes
 577                     int b0 = src.get(sp++) & 0xff;
 578                     dst.put(dp++, (byte)base64[b0 >> 2]);
 579                     if (sp == src.limit()) {
 580                         dst.put(dp++, (byte)base64[(b0 << 4) & 0x3f]);
 581                         if (doPadding) {
 582                             dst.put(dp++, (byte)'=');
 583                             dst.put(dp++, (byte)'=');
 584                         }
 585                     } else {
 586                         int b1 = src.get(sp++) & 0xff;
 587                         dst.put(dp++, (byte)base64[(b0 << 4) & 0x3f | (b1 >> 4)]);
 588                         dst.put(dp++, (byte)base64[(b1 << 2) & 0x3f]);
 589                         if (doPadding) {
 590                             dst.put(dp++, (byte)'=');
 591                         }
 592                     }
 593                 }
 594                 return dp - dp00 + bytesOut;
 595             } finally {
 596                 src.position(sp);
 597                 dst.position(dp);
 598             }
 599         }
 600 
 601         private int encode0(byte[] src, int off, int end, byte[] dst) {
 602             char[] base64 = isURL ? toBase64URL : toBase64;
 603             int sp = off;
 604             int slen = (end - off) / 3 * 3;
 605             int sl = off + slen;
 606             if (linemax > 0 && slen  > linemax / 4 * 3)
 607                 slen = linemax / 4 * 3;
 608             int dp = 0;
 609             while (sp < sl) {
 610                 int sl0 = Math.min(sp + slen, sl);
 611                 for (int sp0 = sp, dp0 = dp ; sp0 < sl0; ) {
 612                     int bits = (src[sp0++] & 0xff) << 16 |
 613                                (src[sp0++] & 0xff) <<  8 |
 614                                (src[sp0++] & 0xff);
 615                     dst[dp0++] = (byte)base64[(bits >>> 18) & 0x3f];
 616                     dst[dp0++] = (byte)base64[(bits >>> 12) & 0x3f];
 617                     dst[dp0++] = (byte)base64[(bits >>> 6)  & 0x3f];
 618                     dst[dp0++] = (byte)base64[bits & 0x3f];
 619                 }
 620                 int dlen = (sl0 - sp) / 3 * 4;
 621                 dp += dlen;
 622                 sp = sl0;
 623                 if (dlen == linemax && sp < end) {
 624                     for (byte b : newline){
 625                         dst[dp++] = b;
 626                     }
 627                 }
 628             }
 629             if (sp < end) {               // 1 or 2 leftover bytes
 630                 int b0 = src[sp++] & 0xff;
 631                 dst[dp++] = (byte)base64[b0 >> 2];
 632                 if (sp == end) {
 633                     dst[dp++] = (byte)base64[(b0 << 4) & 0x3f];
 634                     if (doPadding) {
 635                         dst[dp++] = '=';
 636                         dst[dp++] = '=';
 637                     }
 638                 } else {
 639                     int b1 = src[sp++] & 0xff;
 640                     dst[dp++] = (byte)base64[(b0 << 4) & 0x3f | (b1 >> 4)];
 641                     dst[dp++] = (byte)base64[(b1 << 2) & 0x3f];
 642                     if (doPadding) {
 643                         dst[dp++] = '=';
 644                     }
 645                 }
 646             }
 647             return dp;
 648         }
 649     }
 650 
 651     /**
 652      * This class implements a decoder for decoding byte data using the
 653      * Base64 encoding scheme as specified in RFC 4648 and RFC 2045.
 654      *
 655      * <p> The Base64 padding character {@code '='} is accepted and
 656      * interpreted as the end of the encoded byte data, but is not
 657      * required. So if the final unit of the encoded byte data only has
 658      * two or three Base64 characters (without the corresponding padding
 659      * character(s) padded), they are decoded as if followed by padding
 660      * character(s).
 661      * <p>
 662      * For decoders that use the <a href="#basic">Basic</a> and
 663      * <a href="#url">URL and Filename safe</a> type base64 scheme, and
 664      * if there is padding character present in the final unit, the
 665      * correct number of padding character(s) must be present, otherwise
 666      * {@code IllegalArgumentException} ({@code IOException} when reading


1170             if (sp < sl && !isMIME) {
1171                 throw new IllegalArgumentException(
1172                     "Input byte array has incorrect ending byte at " + sp);
1173             }
1174             return dp;
1175         }
1176     }
1177 
1178     /*
1179      * An output stream for encoding bytes into the Base64.
1180      */
1181     private static class EncOutputStream extends FilterOutputStream {
1182 
1183         private int leftover = 0;
1184         private int b0, b1, b2;
1185         private boolean closed = false;
1186 
1187         private final char[] base64;    // byte->base64 mapping
1188         private final byte[] newline;   // line separator, if needed
1189         private final int linemax;
1190         private final boolean doPadding;// whether or not to pad
1191         private int linepos = 0;
1192 
1193         EncOutputStream(OutputStream os, char[] base64,
1194                         byte[] newline, int linemax, boolean doPadding) {
1195             super(os);
1196             this.base64 = base64;
1197             this.newline = newline;
1198             this.linemax = linemax;
1199             this.doPadding = doPadding;
1200         }
1201 
1202         @Override
1203         public void write(int b) throws IOException {
1204             byte[] buf = new byte[1];
1205             buf[0] = (byte)(b & 0xff);
1206             write(buf, 0, 1);
1207         }
1208 
1209         private void checkNewline() throws IOException {
1210             if (linepos == linemax) {
1211                 out.write(newline);
1212                 linepos = 0;
1213             }
1214         }
1215 
1216         @Override
1217         public void write(byte[] b, int off, int len) throws IOException {
1218             if (closed)
1219                 throw new IOException("Stream is closed");


1251                 out.write(base64[(bits >>> 6)  & 0x3f]);
1252                 out.write(base64[bits & 0x3f]);
1253                 linepos += 4;
1254            }
1255             if (leftover == 1) {
1256                 b0 = b[off++] & 0xff;
1257             } else if (leftover == 2) {
1258                 b0 = b[off++] & 0xff;
1259                 b1 = b[off++] & 0xff;
1260             }
1261         }
1262 
1263         @Override
1264         public void close() throws IOException {
1265             if (!closed) {
1266                 closed = true;
1267                 if (leftover == 1) {
1268                     checkNewline();
1269                     out.write(base64[b0 >> 2]);
1270                     out.write(base64[(b0 << 4) & 0x3f]);
1271                     if (doPadding) {
1272                         out.write('=');
1273                         out.write('=');
1274                     }
1275                 } else if (leftover == 2) {
1276                     checkNewline();
1277                     out.write(base64[b0 >> 2]);
1278                     out.write(base64[(b0 << 4) & 0x3f | (b1 >> 4)]);
1279                     out.write(base64[(b1 << 2) & 0x3f]);
1280                     if (doPadding) {
1281                        out.write('=');
1282                     }
1283                 }
1284                 leftover = 0;
1285                 out.close();
1286             }
1287         }
1288     }
1289 
1290     /*
1291      * An input stream for decoding Base64 bytes
1292      */
1293     private static class DecInputStream extends InputStream {
1294 
1295         private final InputStream is;
1296         private final boolean isMIME;
1297         private final int[] base64;      // base64 -> byte mapping
1298         private int bits = 0;            // 24-bit buffer for decoding
1299         private int nextin = 18;         // next available "off" in "bits" for input;
1300                                          // -> 18, 12, 6, 0
1301         private int nextout = -8;        // next available "off" in "bits" for output;
1302                                          // -> 8, 0, -8 (no byte for output)
1303         private boolean eof = false;