< prev index next >

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

Print this page


   1 /*
   2  * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.util;
  27 
  28 import java.io.FilterOutputStream;
  29 import java.io.InputStream;
  30 import java.io.IOException;
  31 import java.io.OutputStream;
  32 import java.nio.ByteBuffer;

  33 import java.nio.charset.StandardCharsets;
  34 import jdk.internal.HotSpotIntrinsicCandidate;
  35 
  36 /**
  37  * This class consists exclusively of static methods for obtaining
  38  * encoders and decoders for the Base64 encoding scheme. The
  39  * implementation of this class supports the following types of Base64
  40  * as specified in
  41  * <a href="http://www.ietf.org/rfc/rfc4648.txt">RFC 4648</a> and
  42  * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>.
  43  *
  44  * <ul>
  45  * <li><a id="basic"><b>Basic</b></a>
  46  * <p> Uses "The Base64 Alphabet" as specified in Table 1 of
  47  *     RFC 4648 and RFC 2045 for encoding and decoding operation.
  48  *     The encoder does not add any line feed (line separator)
  49  *     character. The decoder rejects data that contains characters
  50  *     outside the base64 alphabet.</p></li>
  51  *
  52  * <li><a id="url"><b>URL and Filename safe</b></a>


 169      * Returns a {@link Decoder} that decodes using the
 170      * <a href="#mime">MIME</a> type base64 decoding scheme.
 171      *
 172      * @return  A Base64 decoder.
 173      */
 174     public static Decoder getMimeDecoder() {
 175          return Decoder.RFC2045;
 176     }
 177 
 178     /**
 179      * This class implements an encoder for encoding byte data using
 180      * the Base64 encoding scheme as specified in RFC 4648 and RFC 2045.
 181      *
 182      * <p> Instances of {@link Encoder} class are safe for use by
 183      * multiple concurrent threads.
 184      *
 185      * <p> Unless otherwise noted, passing a {@code null} argument to
 186      * a method of this class will cause a
 187      * {@link java.lang.NullPointerException NullPointerException} to
 188      * be thrown.




 189      *
 190      * @see     Decoder
 191      * @since   1.8
 192      */
 193     public static class Encoder {
 194 
 195         private final byte[] newline;
 196         private final int linemax;
 197         private final boolean isURL;
 198         private final boolean doPadding;
 199 
 200         private Encoder(boolean isURL, byte[] newline, int linemax, boolean doPadding) {
 201             this.isURL = isURL;
 202             this.newline = newline;
 203             this.linemax = linemax;
 204             this.doPadding = doPadding;
 205         }
 206 
 207         /**
 208          * This array is a lookup table that translates 6-bit positive integer


 220         /**
 221          * It's the lookup table for "URL and Filename safe Base64" as specified
 222          * in Table 2 of the RFC 4648, with the '+' and '/' changed to '-' and
 223          * '_'. This table is used when BASE64_URL is specified.
 224          */
 225         private static final char[] toBase64URL = {
 226             'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
 227             'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
 228             'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
 229             'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
 230             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
 231         };
 232 
 233         private static final int MIMELINEMAX = 76;
 234         private static final byte[] CRLF = new byte[] {'\r', '\n'};
 235 
 236         static final Encoder RFC4648 = new Encoder(false, null, -1, true);
 237         static final Encoder RFC4648_URLSAFE = new Encoder(true, null, -1, true);
 238         static final Encoder RFC2045 = new Encoder(false, CRLF, MIMELINEMAX, true);
 239 
 240         private final int outLength(int srclen) {
 241             int len = 0;

 242             if (doPadding) {
 243                 len = 4 * ((srclen + 2) / 3);
 244             } else {
 245                 int n = srclen % 3;
 246                 len = 4 * (srclen / 3) + (n == 0 ? 0 : n + 1);












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







 320         }
 321 
 322         /**
 323          * Encodes all remaining bytes from the specified byte buffer into
 324          * a newly-allocated ByteBuffer using the {@link Base64} encoding
 325          * scheme.
 326          *
 327          * Upon return, the source buffer's position will be updated to
 328          * its limit; its limit will not have been changed. The returned
 329          * output buffer's position will be zero and its limit will be the
 330          * number of resulting encoded bytes.
 331          *
 332          * @param   buffer
 333          *          the source ByteBuffer to encode
 334          * @return  A newly-allocated byte buffer containing the encoded bytes.
 335          */
 336         public ByteBuffer encode(ByteBuffer buffer) {
 337             int len = outLength(buffer.remaining());
 338             byte[] dst = new byte[len];
 339             int ret = 0;
 340             if (buffer.hasArray()) {
 341                 ret = encode0(buffer.array(),
 342                               buffer.arrayOffset() + buffer.position(),
 343                               buffer.arrayOffset() + buffer.limit(),
 344                               dst);
 345                 buffer.position(buffer.limit());
 346             } else {
 347                 byte[] src = new byte[buffer.remaining()];
 348                 buffer.get(src);
 349                 ret = encode0(src, 0, src.length, dst);
 350             }
 351             if (ret != dst.length)
 352                  dst = Arrays.copyOf(dst, ret);
 353             return ByteBuffer.wrap(dst);
 354         }
 355 
 356         /**
 357          * Wraps an output stream for encoding byte data using the {@link Base64}


 452      * Base64 encoding scheme as specified in RFC 4648 and RFC 2045.
 453      *
 454      * <p> The Base64 padding character {@code '='} is accepted and
 455      * interpreted as the end of the encoded byte data, but is not
 456      * required. So if the final unit of the encoded byte data only has
 457      * two or three Base64 characters (without the corresponding padding
 458      * character(s) padded), they are decoded as if followed by padding
 459      * character(s). If there is a padding character present in the
 460      * final unit, the correct number of padding character(s) must be
 461      * present, otherwise {@code IllegalArgumentException} (
 462      * {@code IOException} when reading from a Base64 stream) is thrown
 463      * during decoding.
 464      *
 465      * <p> Instances of {@link Decoder} class are safe for use by
 466      * multiple concurrent threads.
 467      *
 468      * <p> Unless otherwise noted, passing a {@code null} argument to
 469      * a method of this class will cause a
 470      * {@link java.lang.NullPointerException NullPointerException} to
 471      * be thrown.




 472      *
 473      * @see     Encoder
 474      * @since   1.8
 475      */
 476     public static class Decoder {
 477 
 478         private final boolean isURL;
 479         private final boolean isMIME;
 480 
 481         private Decoder(boolean isURL, boolean isMIME) {
 482             this.isURL = isURL;
 483             this.isMIME = isMIME;
 484         }
 485 
 486         /**
 487          * Lookup table for decoding unicode characters drawn from the
 488          * "Base64 Alphabet" (as specified in Table 1 of RFC 2045) into
 489          * their 6-bit positive integer equivalents.  Characters that
 490          * are not in the Base64 alphabet but fall within the bounds of
 491          * the array are encoded to -1.


 514 
 515         static final Decoder RFC4648         = new Decoder(false, false);
 516         static final Decoder RFC4648_URLSAFE = new Decoder(true, false);
 517         static final Decoder RFC2045         = new Decoder(false, true);
 518 
 519         /**
 520          * Decodes all bytes from the input byte array using the {@link Base64}
 521          * encoding scheme, writing the results into a newly-allocated output
 522          * byte array. The returned byte array is of the length of the resulting
 523          * bytes.
 524          *
 525          * @param   src
 526          *          the byte array to decode
 527          *
 528          * @return  A newly-allocated byte array containing the decoded bytes.
 529          *
 530          * @throws  IllegalArgumentException
 531          *          if {@code src} is not in valid Base64 scheme
 532          */
 533         public byte[] decode(byte[] src) {
 534             byte[] dst = new byte[outLength(src, 0, src.length)];
 535             int ret = decode0(src, 0, src.length, dst);
 536             if (ret != dst.length) {
 537                 dst = Arrays.copyOf(dst, ret);
 538             }
 539             return dst;
 540         }
 541 
 542         /**
 543          * Decodes a Base64 encoded String into a newly-allocated byte array
 544          * using the {@link Base64} encoding scheme.
 545          *
 546          * <p> An invocation of this method has exactly the same effect as invoking
 547          * {@code decode(src.getBytes(StandardCharsets.ISO_8859_1))}
 548          *
 549          * @param   src
 550          *          the string to decode
 551          *
 552          * @return  A newly-allocated byte array containing the decoded bytes.
 553          *
 554          * @throws  IllegalArgumentException


 567          * sure the output byte array {@code dst} has enough space for decoding
 568          * all bytes from the input byte array. No bytes will be written to
 569          * the output byte array if the output byte array is not big enough.
 570          *
 571          * <p> If the input byte array is not in valid Base64 encoding scheme
 572          * then some bytes may have been written to the output byte array before
 573          * IllegalargumentException is thrown.
 574          *
 575          * @param   src
 576          *          the byte array to decode
 577          * @param   dst
 578          *          the output byte array
 579          *
 580          * @return  The number of bytes written to the output byte array
 581          *
 582          * @throws  IllegalArgumentException
 583          *          if {@code src} is not in valid Base64 scheme, or {@code dst}
 584          *          does not have enough space for decoding all input bytes.
 585          */
 586         public int decode(byte[] src, byte[] dst) {
 587             int len = outLength(src, 0, src.length);
 588             if (dst.length < len)
 589                 throw new IllegalArgumentException(
 590                     "Output byte array is too small for decoding all input bytes");
 591             return decode0(src, 0, src.length, dst);
 592         }
 593 
 594         /**
 595          * Decodes all bytes from the input byte buffer using the {@link Base64}
 596          * encoding scheme, writing the results into a newly-allocated ByteBuffer.
 597          *
 598          * <p> Upon return, the source buffer's position will be updated to
 599          * its limit; its limit will not have been changed. The returned
 600          * output buffer's position will be zero and its limit will be the
 601          * number of resulting decoded bytes
 602          *
 603          * <p> {@code IllegalArgumentException} is thrown if the input buffer
 604          * is not in valid Base64 encoding scheme. The position of the input
 605          * buffer will not be advanced in this case.
 606          *
 607          * @param   buffer
 608          *          the ByteBuffer to decode
 609          *
 610          * @return  A newly-allocated byte buffer containing the decoded bytes
 611          *
 612          * @throws  IllegalArgumentException
 613          *          if {@code src} is not in valid Base64 scheme.
 614          */
 615         public ByteBuffer decode(ByteBuffer buffer) {
 616             int pos0 = buffer.position();
 617             try {
 618                 byte[] src;
 619                 int sp, sl;
 620                 if (buffer.hasArray()) {
 621                     src = buffer.array();
 622                     sp = buffer.arrayOffset() + buffer.position();
 623                     sl = buffer.arrayOffset() + buffer.limit();
 624                     buffer.position(buffer.limit());
 625                 } else {
 626                     src = new byte[buffer.remaining()];
 627                     buffer.get(src);
 628                     sp = 0;
 629                     sl = src.length;
 630                 }
 631                 byte[] dst = new byte[outLength(src, sp, sl)];
 632                 return ByteBuffer.wrap(dst, 0, decode0(src, sp, sl, dst));
 633             } catch (IllegalArgumentException iae) {
 634                 buffer.position(pos0);
 635                 throw iae;
 636             }
 637         }
 638 
 639         /**
 640          * Returns an input stream for decoding {@link Base64} encoded byte stream.
 641          *
 642          * <p> The {@code read}  methods of the returned {@code InputStream} will
 643          * throw {@code IOException} when reading bytes that cannot be decoded.
 644          *
 645          * <p> Closing the returned input stream will close the underlying
 646          * input stream.
 647          *
 648          * @param   is
 649          *          the input stream
 650          *
 651          * @return  the input stream for decoding the specified Base64 encoded
 652          *          byte stream
 653          */
 654         public InputStream wrap(InputStream is) {
 655             Objects.requireNonNull(is);
 656             return new DecInputStream(is, isURL ? fromBase64URL : fromBase64, isMIME);
 657         }
 658 
 659         private int outLength(byte[] src, int sp, int sl) {
 660             int[] base64 = isURL ? fromBase64URL : fromBase64;
 661             int paddings = 0;
 662             int len = sl - sp;
 663             if (len == 0)
 664                 return 0;
 665             if (len < 2) {
 666                 if (isMIME && base64[0] == -1)
 667                     return 0;
 668                 throw new IllegalArgumentException(
 669                     "Input byte[] should at least have 2 bytes for base64 bytes");
 670             }
 671             if (isMIME) {
 672                 // scan all bytes to fill out all non-alphabet. a performance
 673                 // trade-off of pre-scan or Arrays.copyOf
 674                 int n = 0;
 675                 while (sp < sl) {
 676                     int b = src[sp++] & 0xff;
 677                     if (b == '=') {
 678                         len -= (sl - sp + 1);
 679                         break;
 680                     }
 681                     if ((b = base64[b]) == -1)
 682                         n++;
 683                 }
 684                 len -= n;
 685             } else {
 686                 if (src[sl - 1] == '=') {
 687                     paddings++;
 688                     if (src[sl - 2] == '=')
 689                         paddings++;
 690                 }
 691             }
 692             if (paddings == 0 && (len & 0x3) !=  0)
 693                 paddings = 4 - (len & 0x3);
 694             return 3 * ((len + 3) / 4) - paddings;












 695         }
 696 
 697         private int decode0(byte[] src, int sp, int sl, byte[] dst) {
 698             int[] base64 = isURL ? fromBase64URL : fromBase64;
 699             int dp = 0;
 700             int bits = 0;
 701             int shiftto = 18;       // pos of first byte of 4-byte atom
 702 
 703             while (sp < sl) {
 704                 if (shiftto == 18 && sp + 4 < sl) {       // fast path
 705                     int sl0 = sp + ((sl - sp) & ~0b11);
 706                     while (sp < sl0) {
 707                         int b1 = base64[src[sp++] & 0xff];
 708                         int b2 = base64[src[sp++] & 0xff];
 709                         int b3 = base64[src[sp++] & 0xff];
 710                         int b4 = base64[src[sp++] & 0xff];
 711                         if ((b1 | b2 | b3 | b4) < 0) {    // non base64 byte
 712                             sp -= 4;
 713                             break;
 714                         }


   1 /*
   2  * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.util;
  27 
  28 import java.io.FilterOutputStream;
  29 import java.io.InputStream;
  30 import java.io.IOException;
  31 import java.io.OutputStream;
  32 import java.nio.ByteBuffer;
  33 import java.nio.charset.CharacterCodingException;
  34 import java.nio.charset.StandardCharsets;
  35 import jdk.internal.HotSpotIntrinsicCandidate;
  36 
  37 /**
  38  * This class consists exclusively of static methods for obtaining
  39  * encoders and decoders for the Base64 encoding scheme. The
  40  * implementation of this class supports the following types of Base64
  41  * as specified in
  42  * <a href="http://www.ietf.org/rfc/rfc4648.txt">RFC 4648</a> and
  43  * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>.
  44  *
  45  * <ul>
  46  * <li><a id="basic"><b>Basic</b></a>
  47  * <p> Uses "The Base64 Alphabet" as specified in Table 1 of
  48  *     RFC 4648 and RFC 2045 for encoding and decoding operation.
  49  *     The encoder does not add any line feed (line separator)
  50  *     character. The decoder rejects data that contains characters
  51  *     outside the base64 alphabet.</p></li>
  52  *
  53  * <li><a id="url"><b>URL and Filename safe</b></a>


 170      * Returns a {@link Decoder} that decodes using the
 171      * <a href="#mime">MIME</a> type base64 decoding scheme.
 172      *
 173      * @return  A Base64 decoder.
 174      */
 175     public static Decoder getMimeDecoder() {
 176          return Decoder.RFC2045;
 177     }
 178 
 179     /**
 180      * This class implements an encoder for encoding byte data using
 181      * the Base64 encoding scheme as specified in RFC 4648 and RFC 2045.
 182      *
 183      * <p> Instances of {@link Encoder} class are safe for use by
 184      * multiple concurrent threads.
 185      *
 186      * <p> Unless otherwise noted, passing a {@code null} argument to
 187      * a method of this class will cause a
 188      * {@link java.lang.NullPointerException NullPointerException} to
 189      * be thrown.
 190      * <p> If the encoded byte output of the needed size can not
 191      *     be allocated, the encode methods of this class will
 192      *     cause an {@link java.lang.OutOfMemoryError OutOfMemoryError}
 193      *     to be thrown.
 194      *
 195      * @see     Decoder
 196      * @since   1.8
 197      */
 198     public static class Encoder {
 199 
 200         private final byte[] newline;
 201         private final int linemax;
 202         private final boolean isURL;
 203         private final boolean doPadding;
 204 
 205         private Encoder(boolean isURL, byte[] newline, int linemax, boolean doPadding) {
 206             this.isURL = isURL;
 207             this.newline = newline;
 208             this.linemax = linemax;
 209             this.doPadding = doPadding;
 210         }
 211 
 212         /**
 213          * This array is a lookup table that translates 6-bit positive integer


 225         /**
 226          * It's the lookup table for "URL and Filename safe Base64" as specified
 227          * in Table 2 of the RFC 4648, with the '+' and '/' changed to '-' and
 228          * '_'. This table is used when BASE64_URL is specified.
 229          */
 230         private static final char[] toBase64URL = {
 231             'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
 232             'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
 233             'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
 234             'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
 235             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
 236         };
 237 
 238         private static final int MIMELINEMAX = 76;
 239         private static final byte[] CRLF = new byte[] {'\r', '\n'};
 240 
 241         static final Encoder RFC4648 = new Encoder(false, null, -1, true);
 242         static final Encoder RFC4648_URLSAFE = new Encoder(true, null, -1, true);
 243         static final Encoder RFC2045 = new Encoder(false, CRLF, MIMELINEMAX, true);
 244 
 245         private final int outLength(int srclen, boolean withOutputParam) {
 246             int len = 0;
 247             try {
 248                 if (doPadding) {
 249                     len = Math.multiplyExact(4, (Math.addExact(srclen, 2) / 3));
 250                 } else {
 251                     int n = srclen % 3;
 252                     len = Math.addExact(Math.multiplyExact(4, (srclen / 3)), (n == 0 ? 0 : n + 1));
 253                 }
 254                 if (linemax > 0) {                             // line separators
 255                     len = Math.addExact(len, (len - 1) / linemax * newline.length);
 256                 }
 257             } catch (ArithmeticException ex) {
 258                 if (!withOutputParam) {
 259                     throw new OutOfMemoryError("Encoded size is too large");
 260                 } else {
 261                     // let the caller know that encoded bytes can not fit
 262                     // in the passed output array param
 263                     len = -1;
 264                 }
 265             }


 266             return len;
 267         }
 268 
 269         /**
 270          * Encodes all bytes from the specified byte array into a newly-allocated
 271          * byte array using the {@link Base64} encoding scheme. The returned byte
 272          * array is of the length of the resulting bytes.
 273          *
 274          * @param   src
 275          *          the byte array to encode
 276          * @return  A newly-allocated byte array containing the resulting
 277          *          encoded bytes.
 278          */
 279         public byte[] encode(byte[] src) {
 280             int len = outLength(src.length, false);          // dst array size
 281             byte[] dst = new byte[len];
 282             int ret = encode0(src, 0, src.length, dst);
 283             if (ret != dst.length)
 284                  return Arrays.copyOf(dst, ret);
 285             return dst;
 286         }
 287 
 288         /**
 289          * Encodes all bytes from the specified byte array using the
 290          * {@link Base64} encoding scheme, writing the resulting bytes to the
 291          * given output byte array, starting at offset 0.
 292          *
 293          * <p> It is the responsibility of the invoker of this method to make
 294          * sure the output byte array {@code dst} has enough space for encoding
 295          * all bytes from the input byte array. No bytes will be written to the
 296          * output byte array if the output byte array is not big enough.
 297          *
 298          * @param   src
 299          *          the byte array to encode
 300          * @param   dst
 301          *          the output byte array
 302          * @return  The number of bytes written to the output byte array
 303          *
 304          * @throws  IllegalArgumentException if {@code dst} does not have enough
 305          *          space for encoding all input bytes.
 306          */
 307         public int encode(byte[] src, byte[] dst) {
 308             int len = outLength(src.length, true);         // dst array size
 309             if (dst.length < len || len == -1)
 310                 throw new IllegalArgumentException(
 311                     "Output byte array is too small for encoding all input bytes");
 312             return encode0(src, 0, src.length, dst);
 313         }
 314 
 315         /**
 316          * Encodes the specified byte array into a String using the {@link Base64}
 317          * encoding scheme.
 318          *
 319          * <p> This method first encodes all input bytes into a base64 encoded
 320          * byte array and then constructs a new String by using the encoded byte
 321          * array and the {@link java.nio.charset.StandardCharsets#ISO_8859_1
 322          * ISO-8859-1} charset.
 323          *
 324          * <p> In other words, an invocation of this method has exactly the same
 325          * effect as invoking
 326          * {@code new String(encode(src), StandardCharsets.ISO_8859_1)}.
 327          *
 328          * @param   src
 329          *          the byte array to encode
 330          * @return  A String containing the resulting Base64 encoded characters
 331          */
 332         @SuppressWarnings("deprecation")
 333         public String encodeToString(byte[] src) {
 334             byte[] encoded = encode(src);
 335             try {
 336                 return jdk.internal.access.SharedSecrets.getJavaLangAccess()
 337                         .newStringNoRepl(encoded, StandardCharsets.ISO_8859_1);
 338             } catch(CharacterCodingException ex) {
 339                 // This exception never occurs, as there are
 340                 // no chances of encoded array being malformed
 341                 throw new RuntimeException("malformed encoded array", ex);
 342             }
 343         }
 344 
 345         /**
 346          * Encodes all remaining bytes from the specified byte buffer into
 347          * a newly-allocated ByteBuffer using the {@link Base64} encoding
 348          * scheme.
 349          *
 350          * Upon return, the source buffer's position will be updated to
 351          * its limit; its limit will not have been changed. The returned
 352          * output buffer's position will be zero and its limit will be the
 353          * number of resulting encoded bytes.
 354          *
 355          * @param   buffer
 356          *          the source ByteBuffer to encode
 357          * @return  A newly-allocated byte buffer containing the encoded bytes.
 358          */
 359         public ByteBuffer encode(ByteBuffer buffer) {
 360             int len = outLength(buffer.remaining(), false);
 361             byte[] dst = new byte[len];
 362             int ret = 0;
 363             if (buffer.hasArray()) {
 364                 ret = encode0(buffer.array(),
 365                               buffer.arrayOffset() + buffer.position(),
 366                               buffer.arrayOffset() + buffer.limit(),
 367                               dst);
 368                 buffer.position(buffer.limit());
 369             } else {
 370                 byte[] src = new byte[buffer.remaining()];
 371                 buffer.get(src);
 372                 ret = encode0(src, 0, src.length, dst);
 373             }
 374             if (ret != dst.length)
 375                  dst = Arrays.copyOf(dst, ret);
 376             return ByteBuffer.wrap(dst);
 377         }
 378 
 379         /**
 380          * Wraps an output stream for encoding byte data using the {@link Base64}


 475      * Base64 encoding scheme as specified in RFC 4648 and RFC 2045.
 476      *
 477      * <p> The Base64 padding character {@code '='} is accepted and
 478      * interpreted as the end of the encoded byte data, but is not
 479      * required. So if the final unit of the encoded byte data only has
 480      * two or three Base64 characters (without the corresponding padding
 481      * character(s) padded), they are decoded as if followed by padding
 482      * character(s). If there is a padding character present in the
 483      * final unit, the correct number of padding character(s) must be
 484      * present, otherwise {@code IllegalArgumentException} (
 485      * {@code IOException} when reading from a Base64 stream) is thrown
 486      * during decoding.
 487      *
 488      * <p> Instances of {@link Decoder} class are safe for use by
 489      * multiple concurrent threads.
 490      *
 491      * <p> Unless otherwise noted, passing a {@code null} argument to
 492      * a method of this class will cause a
 493      * {@link java.lang.NullPointerException NullPointerException} to
 494      * be thrown.
 495      * <p> If the decoded byte output of the needed size can not
 496      *     be allocated, the decode methods of this class will
 497      *     cause an {@link java.lang.OutOfMemoryError OutOfMemoryError}
 498      *     to be thrown.
 499      *
 500      * @see     Encoder
 501      * @since   1.8
 502      */
 503     public static class Decoder {
 504 
 505         private final boolean isURL;
 506         private final boolean isMIME;
 507 
 508         private Decoder(boolean isURL, boolean isMIME) {
 509             this.isURL = isURL;
 510             this.isMIME = isMIME;
 511         }
 512 
 513         /**
 514          * Lookup table for decoding unicode characters drawn from the
 515          * "Base64 Alphabet" (as specified in Table 1 of RFC 2045) into
 516          * their 6-bit positive integer equivalents.  Characters that
 517          * are not in the Base64 alphabet but fall within the bounds of
 518          * the array are encoded to -1.


 541 
 542         static final Decoder RFC4648         = new Decoder(false, false);
 543         static final Decoder RFC4648_URLSAFE = new Decoder(true, false);
 544         static final Decoder RFC2045         = new Decoder(false, true);
 545 
 546         /**
 547          * Decodes all bytes from the input byte array using the {@link Base64}
 548          * encoding scheme, writing the results into a newly-allocated output
 549          * byte array. The returned byte array is of the length of the resulting
 550          * bytes.
 551          *
 552          * @param   src
 553          *          the byte array to decode
 554          *
 555          * @return  A newly-allocated byte array containing the decoded bytes.
 556          *
 557          * @throws  IllegalArgumentException
 558          *          if {@code src} is not in valid Base64 scheme
 559          */
 560         public byte[] decode(byte[] src) {
 561             byte[] dst = new byte[outLength(src, 0, src.length, false)];
 562             int ret = decode0(src, 0, src.length, dst);
 563             if (ret != dst.length) {
 564                 dst = Arrays.copyOf(dst, ret);
 565             }
 566             return dst;
 567         }
 568 
 569         /**
 570          * Decodes a Base64 encoded String into a newly-allocated byte array
 571          * using the {@link Base64} encoding scheme.
 572          *
 573          * <p> An invocation of this method has exactly the same effect as invoking
 574          * {@code decode(src.getBytes(StandardCharsets.ISO_8859_1))}
 575          *
 576          * @param   src
 577          *          the string to decode
 578          *
 579          * @return  A newly-allocated byte array containing the decoded bytes.
 580          *
 581          * @throws  IllegalArgumentException


 594          * sure the output byte array {@code dst} has enough space for decoding
 595          * all bytes from the input byte array. No bytes will be written to
 596          * the output byte array if the output byte array is not big enough.
 597          *
 598          * <p> If the input byte array is not in valid Base64 encoding scheme
 599          * then some bytes may have been written to the output byte array before
 600          * IllegalargumentException is thrown.
 601          *
 602          * @param   src
 603          *          the byte array to decode
 604          * @param   dst
 605          *          the output byte array
 606          *
 607          * @return  The number of bytes written to the output byte array
 608          *
 609          * @throws  IllegalArgumentException
 610          *          if {@code src} is not in valid Base64 scheme, or {@code dst}
 611          *          does not have enough space for decoding all input bytes.
 612          */
 613         public int decode(byte[] src, byte[] dst) {
 614             int len = outLength(src, 0, src.length, true);
 615             if (dst.length < len || len == -1)
 616                 throw new IllegalArgumentException(
 617                     "Output byte array is too small for decoding all input bytes");
 618             return decode0(src, 0, src.length, dst);
 619         }
 620 
 621         /**
 622          * Decodes all bytes from the input byte buffer using the {@link Base64}
 623          * encoding scheme, writing the results into a newly-allocated ByteBuffer.
 624          *
 625          * <p> Upon return, the source buffer's position will be updated to
 626          * its limit; its limit will not have been changed. The returned
 627          * output buffer's position will be zero and its limit will be the
 628          * number of resulting decoded bytes
 629          *
 630          * <p> {@code IllegalArgumentException} is thrown if the input buffer
 631          * is not in valid Base64 encoding scheme. The position of the input
 632          * buffer will not be advanced in this case.
 633          *
 634          * @param   buffer
 635          *          the ByteBuffer to decode
 636          *
 637          * @return  A newly-allocated byte buffer containing the decoded bytes
 638          *
 639          * @throws  IllegalArgumentException
 640          *          if {@code buffer} is not in valid Base64 scheme
 641          */
 642         public ByteBuffer decode(ByteBuffer buffer) {
 643             int pos0 = buffer.position();
 644             try {
 645                 byte[] src;
 646                 int sp, sl;
 647                 if (buffer.hasArray()) {
 648                     src = buffer.array();
 649                     sp = buffer.arrayOffset() + buffer.position();
 650                     sl = buffer.arrayOffset() + buffer.limit();
 651                     buffer.position(buffer.limit());
 652                 } else {
 653                     src = new byte[buffer.remaining()];
 654                     buffer.get(src);
 655                     sp = 0;
 656                     sl = src.length;
 657                 }
 658                 byte[] dst = new byte[outLength(src, sp, sl, false)];
 659                 return ByteBuffer.wrap(dst, 0, decode0(src, sp, sl, dst));
 660             } catch (IllegalArgumentException iae) {
 661                 buffer.position(pos0);
 662                 throw iae;
 663             }
 664         }
 665 
 666         /**
 667          * Returns an input stream for decoding {@link Base64} encoded byte stream.
 668          *
 669          * <p> The {@code read}  methods of the returned {@code InputStream} will
 670          * throw {@code IOException} when reading bytes that cannot be decoded.
 671          *
 672          * <p> Closing the returned input stream will close the underlying
 673          * input stream.
 674          *
 675          * @param   is
 676          *          the input stream
 677          *
 678          * @return  the input stream for decoding the specified Base64 encoded
 679          *          byte stream
 680          */
 681         public InputStream wrap(InputStream is) {
 682             Objects.requireNonNull(is);
 683             return new DecInputStream(is, isURL ? fromBase64URL : fromBase64, isMIME);
 684         }
 685 
 686         private int outLength(byte[] src, int sp, int sl, boolean withOutputParam) {
 687             int[] base64 = isURL ? fromBase64URL : fromBase64;
 688             int paddings = 0;
 689             int len = sl - sp;
 690             if (len == 0)
 691                 return 0;
 692             if (len < 2) {
 693                 if (isMIME && base64[0] == -1)
 694                     return 0;
 695                 throw new IllegalArgumentException(
 696                     "Input byte[] should at least have 2 bytes for base64 bytes");
 697             }
 698             if (isMIME) {
 699                 // scan all bytes to fill out all non-alphabet. a performance
 700                 // trade-off of pre-scan or Arrays.copyOf
 701                 int n = 0;
 702                 while (sp < sl) {
 703                     int b = src[sp++] & 0xff;
 704                     if (b == '=') {
 705                         len -= (sl - sp + 1);
 706                         break;
 707                     }
 708                     if ((b = base64[b]) == -1)
 709                         n++;
 710                 }
 711                 len -= n;
 712             } else {
 713                 if (src[sl - 1] == '=') {
 714                     paddings++;
 715                     if (src[sl - 2] == '=')
 716                         paddings++;
 717                 }
 718             }
 719             if (paddings == 0 && (len & 0x3) !=  0)
 720                 paddings = 4 - (len & 0x3);
 721 
 722             try {
 723                 len = Math.multiplyExact(3, (Math.addExact(len, 3) / 4)) - paddings;
 724             } catch (ArithmeticException ex) {
 725                 if (!withOutputParam) {
 726                     throw new OutOfMemoryError("Decoded size is too large");
 727                 } else {
 728                     // let the caller know that the decoded bytes can not
 729                     // fit in the passed output array param
 730                     len = -1;
 731                 }
 732             }
 733             return len;
 734         }
 735 
 736         private int decode0(byte[] src, int sp, int sl, byte[] dst) {
 737             int[] base64 = isURL ? fromBase64URL : fromBase64;
 738             int dp = 0;
 739             int bits = 0;
 740             int shiftto = 18;       // pos of first byte of 4-byte atom
 741 
 742             while (sp < sl) {
 743                 if (shiftto == 18 && sp + 4 < sl) {       // fast path
 744                     int sl0 = sp + ((sl - sp) & ~0b11);
 745                     while (sp < sl0) {
 746                         int b1 = base64[src[sp++] & 0xff];
 747                         int b2 = base64[src[sp++] & 0xff];
 748                         int b3 = base64[src[sp++] & 0xff];
 749                         int b4 = base64[src[sp++] & 0xff];
 750                         if ((b1 | b2 | b3 | b4) < 0) {    // non base64 byte
 751                             sp -= 4;
 752                             break;
 753                         }


< prev index next >