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

Print this page




 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
 355          * using the {@link Base64} encoding scheme, writing the resulting
 356          * bytes to the given output byte buffer.
 357          *
 358          * <p>The buffers are read from, and written to, starting at their
 359          * current positions. Upon return, the input and output buffers'
 360          * positions will be advanced to reflect the bytes read and written,
 361          * but their limits will not be modified.
 362          *
 363          * <p>The encoding operation will stop and return if either all
 364          * remaining bytes in the input buffer have been encoded and written
 365          * to the output buffer, or the output buffer has insufficient space
 366          * to encode any more input bytes. The encoding operation can be
 367          * continued, if there is more bytes in input buffer to be encoded,
 368          * by invoking this method again with an output buffer that has more
 369          * {@linkplain java.nio.Buffer#remaining remaining} bytes. This is
 370          * typically done by draining any encoded bytes from the output buffer.
 371          * The value returned from last invocation needs to be passed in as the
 372          * third parameter {@code bytesOut} if it is to continue an unfinished
 373          * encoding, 0 otherwise.
 374          *
 375          * <p><b>Recommended Usage Example</b>
 376          * <pre>
 377          *    ByteBuffer src = ...;
 378          *    ByteBuffer dst = ...;
 379          *    Base64.Encoder enc = Base64.getMimeDecoder();
 380          *
 381          *    int bytesOut = 0;
 382          *    while (src.hasRemaining()) {
 383          *        // clear output buffer for decoding
 384          *        dst.clear();
 385          *        bytesOut = enc.encode(src, dst, bytesOut);
 386          *
 387          *        // read encoded bytes out of "dst"
 388          *        dst.flip();
 389          *        ...
 390          *    }
 391          * </pre>
 392          *
 393          * @param   src
 394          *          the input byte buffer to encode
 395          * @param   dst
 396          *          the output byte buffer
 397          * @param   bytesOut
 398          *          the return value of last invocation if this is to continue
 399          *          an unfinished encoding operation, 0 otherwise
 400          * @return  The sum total of {@code bytesOut} and the number of bytes
 401          *          written to the output ByteBuffer during this invocation.
 402          */
 403         public int encode(ByteBuffer src, ByteBuffer dst, int bytesOut) {
 404             if (src.hasArray() && dst.hasArray())
 405                 return encodeArray(src, dst, bytesOut);
 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);
 465                     }
 466                     dpos = 0;
 467                 }
 468                 sl = sp + (sl - sp) / 3 * 3;
 469                 while (sp < sl) {
 470                     int slen = (linemax > 0) ? (linemax - dpos) / 4 * 3
 471                                              : sl - sp;
 472                     int sl0 = Math.min(sp + slen, sl);
 473                     for (int sp0 = sp, dp0 = dp ; sp0 < sl0; ) {
 474                         if (dp0 + 4 > dl) {
 475                             sp = sp0; dp = dp0;
 476                             return  dp0 - dp00 + bytesOut;
 477                         }
 478                         int bits = (sa[sp0++] & 0xff) << 16 |
 479                                    (sa[sp0++] & 0xff) <<  8 |
 480                                    (sa[sp0++] & 0xff);
 481                         da[dp0++] = (byte)base64[(bits >>> 18) & 0x3f];
 482                         da[dp0++] = (byte)base64[(bits >>> 12) & 0x3f];
 483                         da[dp0++] = (byte)base64[(bits >>> 6)  & 0x3f];
 484                         da[dp0++] = (byte)base64[bits & 0x3f];
 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()) {
 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                 sl = sp + (sl - sp) / 3 * 3;
 546                 while (sp < sl) {
 547                     int slen = (linemax > 0) ? (linemax - dpos) / 4 * 3
 548                                              : sl - sp;
 549                     int sl0 = Math.min(sp + slen, sl);
 550                     for (int sp0 = sp, dp0 = dp ; sp0 < sl0; ) {
 551                         if (dp0 + 4 > dl) {
 552                             sp = sp0; dp = dp0;
 553                             return  dp0 - dp00 + bytesOut;
 554                         }
 555                         int bits = (src.get(sp0++) & 0xff) << 16 |
 556                                    (src.get(sp0++) & 0xff) <<  8 |
 557                                    (src.get(sp0++) & 0xff);
 558                         dst.put(dp0++, (byte)base64[(bits >>> 18) & 0x3f]);
 559                         dst.put(dp0++, (byte)base64[(bits >>> 12) & 0x3f]);
 560                         dst.put(dp0++, (byte)base64[(bits >>> 6)  & 0x3f]);
 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;


 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
 667      * from a Base64 stream) is thrown during decoding.
 668      * <p>
 669      * Decoders that use the <a href="#mime">MIME</a> type base64 scheme
 670      * are more lenient when decoding the padding character(s). If the
 671      * padding character(s) is incorrectly encoded, the first padding
 672      * character encountered is interpreted as the end of the encoded byte
 673      * data, the decoding operation will then end and return normally.
 674      *
 675      * <p> Instances of {@link Decoder} class are safe for use by
 676      * multiple concurrent threads.
 677      *
 678      * <p> Unless otherwise noted, passing a {@code null} argument to
 679      * a method of this class will cause a
 680      * {@link java.lang.NullPointerException NullPointerException} to
 681      * be thrown.
 682      *
 683      * @see     Encoder
 684      * @since   1.8
 685      */
 686     public static class Decoder {
 687 
 688         private final boolean isURL;
 689         private final boolean isMIME;
 690 
 691         private Decoder(boolean isURL, boolean isMIME) {
 692             this.isURL = isURL;
 693             this.isMIME = isMIME;


 793          *          if {@code src} is not in valid Base64 scheme, or {@code dst}
 794          *          does not have enough space for decoding all input bytes.
 795          */
 796         public int decode(byte[] src, byte[] dst) {
 797             int len = outLength(src, 0, src.length);
 798             if (dst.length < len)
 799                 throw new IllegalArgumentException(
 800                     "Output byte array is too small for decoding all input bytes");
 801             return decode0(src, 0, src.length, dst);
 802         }
 803 
 804         /**
 805          * Decodes all bytes from the input byte buffer using the {@link Base64}
 806          * encoding scheme, writing the results into a newly-allocated ByteBuffer.
 807          *
 808          * <p> Upon return, the source buffer's position will be updated to
 809          * its limit; its limit will not have been changed. The returned
 810          * output buffer's position will be zero and its limit will be the
 811          * number of resulting decoded bytes
 812          *




 813          * @param   buffer
 814          *          the ByteBuffer to decode
 815          *
 816          * @return  A newly-allocated byte buffer containing the decoded bytes
 817          *
 818          * @throws  IllegalArgumentException
 819          *          if {@code src} is not in valid Base64 scheme.
 820          */
 821         public ByteBuffer decode(ByteBuffer buffer) {
 822             int pos0 = buffer.position();
 823             try {
 824                 byte[] src;
 825                 int sp, sl;
 826                 if (buffer.hasArray()) {
 827                     src = buffer.array();
 828                     sp = buffer.arrayOffset() + buffer.position();
 829                     sl = buffer.arrayOffset() + buffer.limit();
 830                     buffer.position(buffer.limit());
 831                 } else {
 832                     src = new byte[buffer.remaining()];
 833                     buffer.get(src);
 834                     sp = 0;
 835                     sl = src.length;
 836                 }
 837                 byte[] dst = new byte[outLength(src, sp, sl)];
 838                 return ByteBuffer.wrap(dst, 0, decode0(src, sp, sl, dst));
 839             } catch (IllegalArgumentException iae) {
 840                 buffer.position(pos0);
 841                 throw iae;
 842             }
 843         }
 844 
 845         /**
 846          * Decodes as many bytes as possible from the input byte buffer
 847          * using the {@link Base64} encoding scheme, writing the resulting
 848          * bytes to the given output byte buffer.
 849          *
 850          * <p>The buffers are read from, and written to, starting at their
 851          * current positions. Upon return, the input and output buffers'
 852          * positions will be advanced to reflect the bytes read and written,
 853          * but their limits will not be modified.
 854          *
 855          * <p> If the input buffer is not in valid Base64 encoding scheme
 856          * then some bytes may have been written to the output buffer
 857          * before IllegalArgumentException is thrown. The positions of
 858          * both input and output buffer will not be advanced in this case.
 859          *
 860          * <p>The decoding operation will end and return if all remaining
 861          * bytes in the input buffer have been decoded and written to the
 862          * output buffer.
 863          *
 864          * <p> The decoding operation will stop and return if the output
 865          * buffer has insufficient space to decode any more input bytes.
 866          * The decoding operation can be continued, if there is more bytes
 867          * in input buffer to be decoded, by invoking this method again with
 868          * an output buffer that has more {@linkplain java.nio.Buffer#remaining
 869          * remaining} bytes. This is typically done by draining any decoded
 870          * bytes from the output buffer.
 871          *
 872          * <p><b>Recommended Usage Example</b>
 873          * <pre>
 874          *    ByteBuffer src = ...;
 875          *    ByteBuffer dst = ...;
 876          *    Base64.Decoder dec = Base64.getDecoder();
 877          *
 878          *    while (src.hasRemaining()) {
 879          *
 880          *        // prepare the output byte buffer
 881          *        dst.clear();
 882          *        dec.decode(src, dst);
 883          *
 884          *        // read bytes from the output buffer
 885          *        dst.flip();
 886          *        ...
 887          *    }
 888          * </pre>
 889          *
 890          * @param   src
 891          *          the input byte buffer to decode
 892          * @param   dst
 893          *          the output byte buffer
 894          *
 895          * @return  The number of bytes written to the output byte buffer during
 896          *          this decoding invocation
 897          *
 898          * @throws  IllegalArgumentException
 899          *          if {@code src} is not in valid Base64 scheme.
 900          */
 901         public int decode(ByteBuffer src, ByteBuffer dst) {
 902             int sp0 = src.position();
 903             int dp0 = dst.position();
 904             try {
 905                 if (src.hasArray() && dst.hasArray())
 906                     return decodeArray(src, dst);
 907                 return decodeBuffer(src, dst);
 908             } catch (IllegalArgumentException iae) {
 909                 src.position(sp0);
 910                 dst.position(dp0);
 911                 throw iae;
 912             }
 913         }
 914 
 915         /**
 916          * Returns an input stream for decoding {@link Base64} encoded byte stream.
 917          *
 918          * <p> The {@code read}  methods of the returned {@code InputStream} will
 919          * throw {@code IOException} when reading bytes that cannot be decoded.
 920          *
 921          * <p> Closing the returned input stream will close the underlying
 922          * input stream.
 923          *
 924          * @param   is
 925          *          the input stream
 926          *
 927          * @return  the input stream for decoding the specified Base64 encoded
 928          *          byte stream
 929          */
 930         public InputStream wrap(InputStream is) {
 931             Objects.requireNonNull(is);
 932             return new DecInputStream(is, isURL ? fromBase64URL : fromBase64, isMIME);
 933         }
 934 
 935         private int decodeArray(ByteBuffer src, ByteBuffer dst) {
 936             int[] base64 = isURL ? fromBase64URL : fromBase64;
 937             int   bits = 0;
 938             int   shiftto = 18;       // pos of first byte of 4-byte atom
 939             byte[] sa = src.array();
 940             int    sp = src.arrayOffset() + src.position();
 941             int    sl = src.arrayOffset() + src.limit();
 942             byte[] da = dst.array();
 943             int    dp = dst.arrayOffset() + dst.position();
 944             int    dl = dst.arrayOffset() + dst.limit();
 945             int    dp0 = dp;
 946             int    mark = sp;
 947             try {
 948                 while (sp < sl) {
 949                     int b = sa[sp++] & 0xff;
 950                     if ((b = base64[b]) < 0) {
 951                         if (b == -2) {   // padding byte
 952                             if (!isMIME &&
 953                                 (shiftto == 6 && (sp == sl || sa[sp++] != '=') ||
 954                                  shiftto == 18)) {
 955                                 throw new IllegalArgumentException(
 956                                      "Input byte array has wrong 4-byte ending unit");
 957                             }
 958                             break;
 959                         }
 960                         if (isMIME)     // skip if for rfc2045
 961                             continue;
 962                         else
 963                             throw new IllegalArgumentException(
 964                                 "Illegal base64 character " +
 965                                 Integer.toString(sa[sp - 1], 16));
 966                     }
 967                     bits |= (b << shiftto);
 968                     shiftto -= 6;
 969                     if (shiftto < 0) {
 970                         if (dl < dp + 3)
 971                             return dp - dp0;
 972                         da[dp++] = (byte)(bits >> 16);
 973                         da[dp++] = (byte)(bits >>  8);
 974                         da[dp++] = (byte)(bits);
 975                         shiftto = 18;
 976                         bits = 0;
 977                         mark = sp;
 978                     }
 979                 }
 980                 if (shiftto == 6) {
 981                     if (dl - dp < 1)
 982                         return dp - dp0;
 983                     da[dp++] = (byte)(bits >> 16);
 984                 } else if (shiftto == 0) {
 985                     if (dl - dp < 2)
 986                         return dp - dp0;
 987                     da[dp++] = (byte)(bits >> 16);
 988                     da[dp++] = (byte)(bits >>  8);
 989                 } else if (shiftto == 12) {
 990                     throw new IllegalArgumentException(
 991                         "Last unit does not have enough valid bits");
 992                 }
 993                 if (sp < sl) {
 994                     if (isMIME)
 995                         sp = sl;
 996                     else
 997                         throw new IllegalArgumentException(
 998                             "Input byte array has incorrect ending byte at " + sp);
 999                 }
1000                 mark = sp;
1001                 return dp - dp0;
1002             } finally {
1003                 src.position(mark);
1004                 dst.position(dp);
1005             }
1006         }
1007 
1008         private int decodeBuffer(ByteBuffer src, ByteBuffer dst) {
1009             int[] base64 = isURL ? fromBase64URL : fromBase64;
1010             int   bits = 0;
1011             int   shiftto = 18;       // pos of first byte of 4-byte atom
1012             int    sp = src.position();
1013             int    sl = src.limit();
1014             int    dp = dst.position();
1015             int    dl = dst.limit();
1016             int    dp0 = dp;
1017             int    mark = sp;
1018             try {
1019                 while (sp < sl) {
1020                     int b = src.get(sp++) & 0xff;
1021                     if ((b = base64[b]) < 0) {
1022                         if (b == -2) {  // padding byte
1023                             if (!isMIME &&
1024                                 (shiftto == 6 && (sp == sl || src.get(sp++) != '=') ||
1025                                  shiftto == 18)) {
1026                                 throw new IllegalArgumentException(
1027                                      "Input byte array has wrong 4-byte ending unit");
1028                             }
1029                             break;
1030                         }
1031                         if (isMIME)     // skip if for rfc2045
1032                             continue;
1033                         else
1034                             throw new IllegalArgumentException(
1035                                 "Illegal base64 character " +
1036                                 Integer.toString(src.get(sp - 1), 16));
1037                     }
1038                     bits |= (b << shiftto);
1039                     shiftto -= 6;
1040                     if (shiftto < 0) {
1041                         if (dl < dp + 3)
1042                             return dp - dp0;
1043                         dst.put(dp++, (byte)(bits >> 16));
1044                         dst.put(dp++, (byte)(bits >>  8));
1045                         dst.put(dp++, (byte)(bits));
1046                         shiftto = 18;
1047                         bits = 0;
1048                         mark = sp;
1049                     }
1050                 }
1051                 if (shiftto == 6) {
1052                     if (dl - dp < 1)
1053                         return dp - dp0;
1054                      dst.put(dp++, (byte)(bits >> 16));
1055                 } else if (shiftto == 0) {
1056                     if (dl - dp < 2)
1057                         return dp - dp0;
1058                     dst.put(dp++, (byte)(bits >> 16));
1059                     dst.put(dp++, (byte)(bits >>  8));
1060                 } else if (shiftto == 12) {
1061                     throw new IllegalArgumentException(
1062                         "Last unit does not have enough valid bits");
1063                 }
1064                 if (sp < sl) {
1065                     if (isMIME)
1066                         sp = sl;
1067                     else
1068                         throw new IllegalArgumentException(
1069                             "Input byte array has incorrect ending byte at " + sp);
1070                 }
1071                 mark = sp;
1072                 return dp - dp0;
1073             } finally {
1074                 src.position(mark);
1075                 dst.position(dp);
1076             }
1077         }
1078 
1079         private int outLength(byte[] src, int sp, int sl) {
1080             int[] base64 = isURL ? fromBase64URL : fromBase64;
1081             int paddings = 0;
1082             int len = sl - sp;
1083             if (len == 0)
1084                 return 0;
1085             if (len < 2) {
1086                 if (isMIME && base64[0] == -1)
1087                     return 0;
1088                 throw new IllegalArgumentException(
1089                     "Input byte[] should at least have 2 bytes for base64 bytes");
1090             }
1091             if (isMIME) {
1092                 // scan all bytes to fill out all non-alphabet. a performance
1093                 // trade-off of pre-scan or Arrays.copyOf
1094                 int n = 0;
1095                 while (sp < sl) {
1096                     int b = src[sp++] & 0xff;
1097                     if (b == '=') {
1098                         len -= (sl - sp + 1);


1106                 if (src[sl - 1] == '=') {
1107                     paddings++;
1108                     if (src[sl - 2] == '=')
1109                         paddings++;
1110                 }
1111             }
1112             if (paddings == 0 && (len & 0x3) !=  0)
1113                 paddings = 4 - (len & 0x3);
1114             return 3 * ((len + 3) / 4) - paddings;
1115         }
1116 
1117         private int decode0(byte[] src, int sp, int sl, byte[] dst) {
1118             int[] base64 = isURL ? fromBase64URL : fromBase64;
1119             int dp = 0;
1120             int bits = 0;
1121             int shiftto = 18;       // pos of first byte of 4-byte atom
1122             while (sp < sl) {
1123                 int b = src[sp++] & 0xff;
1124                 if ((b = base64[b]) < 0) {
1125                     if (b == -2) {         // padding byte '='
1126                         if (!isMIME  &&    // be lenient for rfc2045
1127                             // =     shiftto==18 unnecessary padding
1128                             // x=    shiftto==12 a dangling single x
1129                             // x     to be handled together with non-padding case
1130                             // xx=   shiftto==6&&sp==sl missing last =
1131                             // xx=y  shiftto==6 last is not =
1132                             (shiftto == 6 && (sp == sl || src[sp++] != '=') ||
1133                             shiftto == 18)) {
1134                             throw new IllegalArgumentException(
1135                                 "Input byte array has wrong 4-byte ending unit");
1136                         }
1137                         break;
1138                     }
1139                     if (isMIME)    // skip if for rfc2045
1140                         continue;
1141                     else
1142                         throw new IllegalArgumentException(
1143                             "Illegal base64 character " +
1144                             Integer.toString(src[sp - 1], 16));
1145                 }
1146                 bits |= (b << shiftto);
1147                 shiftto -= 6;
1148                 if (shiftto < 0) {
1149                     dst[dp++] = (byte)(bits >> 16);
1150                     dst[dp++] = (byte)(bits >>  8);
1151                     dst[dp++] = (byte)(bits);
1152                     shiftto = 18;
1153                     bits = 0;
1154                 }
1155             }
1156             // reached end of byte array or hit padding '=' characters.
1157             if (shiftto == 6) {
1158                 dst[dp++] = (byte)(bits >> 16);
1159             } else if (shiftto == 0) {
1160                 dst[dp++] = (byte)(bits >> 16);
1161                 dst[dp++] = (byte)(bits >>  8);
1162             } else if (shiftto == 12) {
1163                 // dangling single "x", throw exception even in lenient mode,
1164                 // it's incorrectly encoded.
1165                 throw new IllegalArgumentException(
1166                     "Last unit does not have enough valid bits");
1167             }
1168             // anything left is invalid, if is not MIME.
1169             // if MIME (lenient), just ignore all leftover
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


1350                             if (len == 0) {          // no enough output space
1351                                 bits >>= 8;          // shift to lowest byte
1352                                 nextout = 0;
1353                             } else {
1354                                 b[off++] = (byte) (bits >>  8);
1355                             }
1356                         }
1357                     }
1358                     if (off == oldOff)
1359                         return -1;
1360                     else
1361                         return off - oldOff;
1362                 }
1363                 if (v == '=') {                  // padding byte(s)
1364                     // =     shiftto==18 unnecessary padding
1365                     // x=    shiftto==12 dangling x, invalid unit
1366                     // xx=   shiftto==6 && missing last '='
1367                     // xx=y  or last is not '='
1368                     if (nextin == 18 || nextin == 12 ||
1369                         nextin == 6 && is.read() != '=') {
1370                         if (!isMIME || nextin == 12) {
1371                             throw new IOException("Illegal base64 ending sequence:" + nextin);
1372                         } else if (nextin != 18) {
1373                             // lenient mode for mime
1374                             // (1) handle the "unnecessary padding in "xxxx ="
1375                             //     case as the eof (nextin == 18)
1376                             // (2) decode "xx=" and "xx=y" normally
1377                             b[off++] = (byte)(bits >> (16));
1378                             len--;
1379                         }
1380                     } else {
1381                         b[off++] = (byte)(bits >> (16));
1382                         len--;
1383                         if (nextin == 0) {           // only one padding byte
1384                             if (len == 0) {          // no enough output space
1385                                 bits >>= 8;          // shift to lowest byte
1386                                 nextout = 0;
1387                             } else {
1388                                 b[off++] = (byte) (bits >>  8);
1389                             }
1390                         }
1391                     }
1392                     eof = true;
1393                     break;
1394                 }
1395                 if ((v = base64[v]) == -1) {
1396                     if (isMIME)                 // skip if for rfc2045
1397                         continue;
1398                     else
1399                         throw new IOException("Illegal base64 character " +
1400                             Integer.toString(v, 16));
1401                 }
1402                 bits |= (v << nextin);
1403                 if (nextin == 0) {
1404                     nextin = 18;    // clear for next
1405                     nextout = 16;
1406                     while (nextout >= 0) {
1407                         b[off++] = (byte)(bits >> nextout);
1408                         len--;
1409                         nextout -= 8;
1410                         if (len == 0 && nextout >= 0) {  // don't clean "bits"
1411                             return off - oldOff;




 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          * Wraps an output stream for encoding byte data using the {@link Base64}
 355          * encoding scheme.
 356          *
 357          * <p> It is recommended to promptly close the returned output stream after
 358          * use, during which it will flush all possible leftover bytes to the underlying
 359          * output stream. Closing the returned output stream will close the underlying
 360          * output stream.
 361          *
 362          * @param   os
 363          *          the output stream.
 364          * @return  the output stream for encoding the byte data into the
 365          *          specified Base64 encoded format
 366          */
 367         public OutputStream wrap(OutputStream os) {
 368             Objects.requireNonNull(os);
 369             return new EncOutputStream(os, isURL ? toBase64URL : toBase64,
 370                                        newline, linemax, doPadding);
 371         }
 372 
 373         /**
 374          * Returns an encoder instance that encodes equivalently to this one,
 375          * but without adding any padding character at the end of the encoded
 376          * byte data.
 377          *
 378          * <p> The encoding scheme of this encoder instance is unaffected by
 379          * this invocation. The returned encoder instance should be used for
 380          * non-padding encoding operation.
 381          *
 382          * @return an equivalent encoder that encodes without adding any
 383          *         padding character at the end
 384          */
 385         public Encoder withoutPadding() {
 386             if (!doPadding)
 387                 return this;
 388             return new Encoder(isURL, newline, linemax, false);
 389         }
 390 


























































































































































 391         private int encode0(byte[] src, int off, int end, byte[] dst) {
 392             char[] base64 = isURL ? toBase64URL : toBase64;
 393             int sp = off;
 394             int slen = (end - off) / 3 * 3;
 395             int sl = off + slen;
 396             if (linemax > 0 && slen  > linemax / 4 * 3)
 397                 slen = linemax / 4 * 3;
 398             int dp = 0;
 399             while (sp < sl) {
 400                 int sl0 = Math.min(sp + slen, sl);
 401                 for (int sp0 = sp, dp0 = dp ; sp0 < sl0; ) {
 402                     int bits = (src[sp0++] & 0xff) << 16 |
 403                                (src[sp0++] & 0xff) <<  8 |
 404                                (src[sp0++] & 0xff);
 405                     dst[dp0++] = (byte)base64[(bits >>> 18) & 0x3f];
 406                     dst[dp0++] = (byte)base64[(bits >>> 12) & 0x3f];
 407                     dst[dp0++] = (byte)base64[(bits >>> 6)  & 0x3f];
 408                     dst[dp0++] = (byte)base64[bits & 0x3f];
 409                 }
 410                 int dlen = (sl0 - sp) / 3 * 4;


 430                     dst[dp++] = (byte)base64[(b0 << 4) & 0x3f | (b1 >> 4)];
 431                     dst[dp++] = (byte)base64[(b1 << 2) & 0x3f];
 432                     if (doPadding) {
 433                         dst[dp++] = '=';
 434                     }
 435                 }
 436             }
 437             return dp;
 438         }
 439     }
 440 
 441     /**
 442      * This class implements a decoder for decoding byte data using the
 443      * Base64 encoding scheme as specified in RFC 4648 and RFC 2045.
 444      *
 445      * <p> The Base64 padding character {@code '='} is accepted and
 446      * interpreted as the end of the encoded byte data, but is not
 447      * required. So if the final unit of the encoded byte data only has
 448      * two or three Base64 characters (without the corresponding padding
 449      * character(s) padded), they are decoded as if followed by padding
 450      * character(s). If there is a padding character present in the
 451      * final unit, the correct number of padding character(s) must be
 452      * present, otherwise {@code IllegalArgumentException} (
 453      * {@code IOException} when reading from a Base64 stream) is thrown
 454      * during decoding.









 455      *
 456      * <p> Instances of {@link Decoder} class are safe for use by
 457      * multiple concurrent threads.
 458      *
 459      * <p> Unless otherwise noted, passing a {@code null} argument to
 460      * a method of this class will cause a
 461      * {@link java.lang.NullPointerException NullPointerException} to
 462      * be thrown.
 463      *
 464      * @see     Encoder
 465      * @since   1.8
 466      */
 467     public static class Decoder {
 468 
 469         private final boolean isURL;
 470         private final boolean isMIME;
 471 
 472         private Decoder(boolean isURL, boolean isMIME) {
 473             this.isURL = isURL;
 474             this.isMIME = isMIME;


 574          *          if {@code src} is not in valid Base64 scheme, or {@code dst}
 575          *          does not have enough space for decoding all input bytes.
 576          */
 577         public int decode(byte[] src, byte[] dst) {
 578             int len = outLength(src, 0, src.length);
 579             if (dst.length < len)
 580                 throw new IllegalArgumentException(
 581                     "Output byte array is too small for decoding all input bytes");
 582             return decode0(src, 0, src.length, dst);
 583         }
 584 
 585         /**
 586          * Decodes all bytes from the input byte buffer using the {@link Base64}
 587          * encoding scheme, writing the results into a newly-allocated ByteBuffer.
 588          *
 589          * <p> Upon return, the source buffer's position will be updated to
 590          * its limit; its limit will not have been changed. The returned
 591          * output buffer's position will be zero and its limit will be the
 592          * number of resulting decoded bytes
 593          *
 594          * <p> {@code IllegalArgumentException} is thrown if the input buffer
 595          * is not in valid Base64 encoding scheme. The position of the input
 596          * buffer will not be advanced in this case.
 597          *
 598          * @param   buffer
 599          *          the ByteBuffer to decode
 600          *
 601          * @return  A newly-allocated byte buffer containing the decoded bytes
 602          *
 603          * @throws  IllegalArgumentException
 604          *          if {@code src} is not in valid Base64 scheme.
 605          */
 606         public ByteBuffer decode(ByteBuffer buffer) {
 607             int pos0 = buffer.position();
 608             try {
 609                 byte[] src;
 610                 int sp, sl;
 611                 if (buffer.hasArray()) {
 612                     src = buffer.array();
 613                     sp = buffer.arrayOffset() + buffer.position();
 614                     sl = buffer.arrayOffset() + buffer.limit();
 615                     buffer.position(buffer.limit());
 616                 } else {
 617                     src = new byte[buffer.remaining()];
 618                     buffer.get(src);
 619                     sp = 0;
 620                     sl = src.length;
 621                 }
 622                 byte[] dst = new byte[outLength(src, sp, sl)];
 623                 return ByteBuffer.wrap(dst, 0, decode0(src, sp, sl, dst));
 624             } catch (IllegalArgumentException iae) {
 625                 buffer.position(pos0);
 626                 throw iae;
 627             }
 628         }
 629 
 630         /**






































































 631          * Returns an input stream for decoding {@link Base64} encoded byte stream.
 632          *
 633          * <p> The {@code read}  methods of the returned {@code InputStream} will
 634          * throw {@code IOException} when reading bytes that cannot be decoded.
 635          *
 636          * <p> Closing the returned input stream will close the underlying
 637          * input stream.
 638          *
 639          * @param   is
 640          *          the input stream
 641          *
 642          * @return  the input stream for decoding the specified Base64 encoded
 643          *          byte stream
 644          */
 645         public InputStream wrap(InputStream is) {
 646             Objects.requireNonNull(is);
 647             return new DecInputStream(is, isURL ? fromBase64URL : fromBase64, isMIME);
 648         }
 649 
















































































































































 650         private int outLength(byte[] src, int sp, int sl) {
 651             int[] base64 = isURL ? fromBase64URL : fromBase64;
 652             int paddings = 0;
 653             int len = sl - sp;
 654             if (len == 0)
 655                 return 0;
 656             if (len < 2) {
 657                 if (isMIME && base64[0] == -1)
 658                     return 0;
 659                 throw new IllegalArgumentException(
 660                     "Input byte[] should at least have 2 bytes for base64 bytes");
 661             }
 662             if (isMIME) {
 663                 // scan all bytes to fill out all non-alphabet. a performance
 664                 // trade-off of pre-scan or Arrays.copyOf
 665                 int n = 0;
 666                 while (sp < sl) {
 667                     int b = src[sp++] & 0xff;
 668                     if (b == '=') {
 669                         len -= (sl - sp + 1);


 677                 if (src[sl - 1] == '=') {
 678                     paddings++;
 679                     if (src[sl - 2] == '=')
 680                         paddings++;
 681                 }
 682             }
 683             if (paddings == 0 && (len & 0x3) !=  0)
 684                 paddings = 4 - (len & 0x3);
 685             return 3 * ((len + 3) / 4) - paddings;
 686         }
 687 
 688         private int decode0(byte[] src, int sp, int sl, byte[] dst) {
 689             int[] base64 = isURL ? fromBase64URL : fromBase64;
 690             int dp = 0;
 691             int bits = 0;
 692             int shiftto = 18;       // pos of first byte of 4-byte atom
 693             while (sp < sl) {
 694                 int b = src[sp++] & 0xff;
 695                 if ((b = base64[b]) < 0) {
 696                     if (b == -2) {         // padding byte '='

 697                         // =     shiftto==18 unnecessary padding
 698                         // x=    shiftto==12 a dangling single x
 699                         // x     to be handled together with non-padding case
 700                         // xx=   shiftto==6&&sp==sl missing last =
 701                         // xx=y  shiftto==6 last is not =
 702                         if (shiftto == 6 && (sp == sl || src[sp++] != '=') ||
 703                             shiftto == 18) {
 704                             throw new IllegalArgumentException(
 705                                 "Input byte array has wrong 4-byte ending unit");
 706                         }
 707                         break;
 708                     }
 709                     if (isMIME)    // skip if for rfc2045
 710                         continue;
 711                     else
 712                         throw new IllegalArgumentException(
 713                             "Illegal base64 character " +
 714                             Integer.toString(src[sp - 1], 16));
 715                 }
 716                 bits |= (b << shiftto);
 717                 shiftto -= 6;
 718                 if (shiftto < 0) {
 719                     dst[dp++] = (byte)(bits >> 16);
 720                     dst[dp++] = (byte)(bits >>  8);
 721                     dst[dp++] = (byte)(bits);
 722                     shiftto = 18;
 723                     bits = 0;
 724                 }
 725             }
 726             // reached end of byte array or hit padding '=' characters.
 727             if (shiftto == 6) {
 728                 dst[dp++] = (byte)(bits >> 16);
 729             } else if (shiftto == 0) {
 730                 dst[dp++] = (byte)(bits >> 16);
 731                 dst[dp++] = (byte)(bits >>  8);
 732             } else if (shiftto == 12) {
 733                 // dangling single "x", incorrectly encoded.

 734                 throw new IllegalArgumentException(
 735                     "Last unit does not have enough valid bits");
 736             }
 737             // anything left is invalid, if is not MIME.
 738             // if MIME, ignore all non-base64 character
 739             while (sp < sl) {
 740                 if (isMIME && base64[src[sp++]] < 0)
 741                     continue;
 742                 throw new IllegalArgumentException(
 743                     "Input byte array has incorrect ending byte at " + sp);
 744             }
 745             return dp;
 746         }
 747     }
 748 
 749     /*
 750      * An output stream for encoding bytes into the Base64.
 751      */
 752     private static class EncOutputStream extends FilterOutputStream {
 753 
 754         private int leftover = 0;
 755         private int b0, b1, b2;
 756         private boolean closed = false;
 757 
 758         private final char[] base64;    // byte->base64 mapping
 759         private final byte[] newline;   // line separator, if needed
 760         private final int linemax;
 761         private final boolean doPadding;// whether or not to pad


 921                             if (len == 0) {          // no enough output space
 922                                 bits >>= 8;          // shift to lowest byte
 923                                 nextout = 0;
 924                             } else {
 925                                 b[off++] = (byte) (bits >>  8);
 926                             }
 927                         }
 928                     }
 929                     if (off == oldOff)
 930                         return -1;
 931                     else
 932                         return off - oldOff;
 933                 }
 934                 if (v == '=') {                  // padding byte(s)
 935                     // =     shiftto==18 unnecessary padding
 936                     // x=    shiftto==12 dangling x, invalid unit
 937                     // xx=   shiftto==6 && missing last '='
 938                     // xx=y  or last is not '='
 939                     if (nextin == 18 || nextin == 12 ||
 940                         nextin == 6 && is.read() != '=') {

 941                         throw new IOException("Illegal base64 ending sequence:" + nextin);







 942                     }

 943                     b[off++] = (byte)(bits >> (16));
 944                     len--;
 945                     if (nextin == 0) {           // only one padding byte
 946                         if (len == 0) {          // no enough output space
 947                             bits >>= 8;          // shift to lowest byte
 948                             nextout = 0;
 949                         } else {
 950                             b[off++] = (byte) (bits >>  8);
 951                         }
 952                     }

 953                     eof = true;
 954                     break;
 955                 }
 956                 if ((v = base64[v]) == -1) {
 957                     if (isMIME)                 // skip if for rfc2045
 958                         continue;
 959                     else
 960                         throw new IOException("Illegal base64 character " +
 961                             Integer.toString(v, 16));
 962                 }
 963                 bits |= (v << nextin);
 964                 if (nextin == 0) {
 965                     nextin = 18;    // clear for next
 966                     nextout = 16;
 967                     while (nextout >= 0) {
 968                         b[off++] = (byte)(bits >> nextout);
 969                         len--;
 970                         nextout -= 8;
 971                         if (len == 0 && nextout >= 0) {  // don't clean "bits"
 972                             return off - oldOff;