src/java.base/share/classes/java/util/Base64.java
changeset 48898 fdd4a131d766
parent 48689 e704f48d8277
child 48900 276b0604eab3
equal deleted inserted replaced
48897:3f19b5965355 48898:fdd4a131d766
     1 /*
     1 /*
     2  * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
     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.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
   691             int[] base64 = isURL ? fromBase64URL : fromBase64;
   691             int[] base64 = isURL ? fromBase64URL : fromBase64;
   692             int dp = 0;
   692             int dp = 0;
   693             int bits = 0;
   693             int bits = 0;
   694             int shiftto = 18;       // pos of first byte of 4-byte atom
   694             int shiftto = 18;       // pos of first byte of 4-byte atom
   695             while (sp < sl) {
   695             while (sp < sl) {
       
   696                 if (bits == 0 && sp + 4 < sl) {           // fast path
       
   697                     int sl0 = sp + ((sl - sp) & ~0b11);
       
   698                     while (sp < sl0) {
       
   699                         int b1 = base64[src[sp++] & 0xff];
       
   700                         int b2 = base64[src[sp++] & 0xff];
       
   701                         int b3 = base64[src[sp++] & 0xff];
       
   702                         int b4 = base64[src[sp++] & 0xff];
       
   703                         if ((b1 | b2 | b3 | b4) < 0) {    // non base64 byte
       
   704                             sp -= 4;
       
   705                             break;
       
   706                         }
       
   707                         int bits0 = b1 << 18 | b2 << 12 | b3 << 6 | b4;
       
   708                         dst[dp++] = (byte)(bits0 >> 16);
       
   709                         dst[dp++] = (byte)(bits0 >>  8);
       
   710                         dst[dp++] = (byte)(bits0);
       
   711                     }
       
   712                     if (sp >= sl)
       
   713                         break;
       
   714                 }
   696                 int b = src[sp++] & 0xff;
   715                 int b = src[sp++] & 0xff;
   697                 if ((b = base64[b]) < 0) {
   716                 if ((b = base64[b]) < 0) {
   698                     if (b == -2) {         // padding byte '='
   717                     if (b == -2) {         // padding byte '='
   699                         // =     shiftto==18 unnecessary padding
   718                         // =     shiftto==18 unnecessary padding
   700                         // x=    shiftto==12 a dangling single x
   719                         // x=    shiftto==12 a dangling single x
   760         private final char[] base64;    // byte->base64 mapping
   779         private final char[] base64;    // byte->base64 mapping
   761         private final byte[] newline;   // line separator, if needed
   780         private final byte[] newline;   // line separator, if needed
   762         private final int linemax;
   781         private final int linemax;
   763         private final boolean doPadding;// whether or not to pad
   782         private final boolean doPadding;// whether or not to pad
   764         private int linepos = 0;
   783         private int linepos = 0;
       
   784         private byte[] buf;
   765 
   785 
   766         EncOutputStream(OutputStream os, char[] base64,
   786         EncOutputStream(OutputStream os, char[] base64,
   767                         byte[] newline, int linemax, boolean doPadding) {
   787                         byte[] newline, int linemax, boolean doPadding) {
   768             super(os);
   788             super(os);
   769             this.base64 = base64;
   789             this.base64 = base64;
   770             this.newline = newline;
   790             this.newline = newline;
   771             this.linemax = linemax;
   791             this.linemax = linemax;
   772             this.doPadding = doPadding;
   792             this.doPadding = doPadding;
       
   793             this.buf = new byte[linemax <= 0 ? 8124 : linemax];
   773         }
   794         }
   774 
   795 
   775         @Override
   796         @Override
   776         public void write(int b) throws IOException {
   797         public void write(int b) throws IOException {
   777             byte[] buf = new byte[1];
   798             byte[] buf = new byte[1];
   782         private void checkNewline() throws IOException {
   803         private void checkNewline() throws IOException {
   783             if (linepos == linemax) {
   804             if (linepos == linemax) {
   784                 out.write(newline);
   805                 out.write(newline);
   785                 linepos = 0;
   806                 linepos = 0;
   786             }
   807             }
       
   808         }
       
   809 
       
   810         private void writeb4(char b1, char b2, char b3, char b4) throws IOException {
       
   811             buf[0] = (byte)b1;
       
   812             buf[1] = (byte)b2;
       
   813             buf[2] = (byte)b3;
       
   814             buf[3] = (byte)b4;
       
   815             out.write(buf, 0, 4);
   787         }
   816         }
   788 
   817 
   789         @Override
   818         @Override
   790         public void write(byte[] b, int off, int len) throws IOException {
   819         public void write(byte[] b, int off, int len) throws IOException {
   791             if (closed)
   820             if (closed)
   804                     }
   833                     }
   805                 }
   834                 }
   806                 b2 = b[off++] & 0xff;
   835                 b2 = b[off++] & 0xff;
   807                 len--;
   836                 len--;
   808                 checkNewline();
   837                 checkNewline();
   809                 out.write(base64[b0 >> 2]);
   838                 writeb4(base64[b0 >> 2],
   810                 out.write(base64[(b0 << 4) & 0x3f | (b1 >> 4)]);
   839                         base64[(b0 << 4) & 0x3f | (b1 >> 4)],
   811                 out.write(base64[(b1 << 2) & 0x3f | (b2 >> 6)]);
   840                         base64[(b1 << 2) & 0x3f | (b2 >> 6)],
   812                 out.write(base64[b2 & 0x3f]);
   841                         base64[b2 & 0x3f]);
   813                 linepos += 4;
   842                 linepos += 4;
   814             }
   843             }
   815             int nBits24 = len / 3;
   844             int nBits24 = len / 3;
   816             leftover = len - (nBits24 * 3);
   845             leftover = len - (nBits24 * 3);
   817             while (nBits24-- > 0) {
   846 
       
   847             while (nBits24 > 0) {
   818                 checkNewline();
   848                 checkNewline();
   819                 int bits = (b[off++] & 0xff) << 16 |
   849                 int dl = linemax <= 0 ? buf.length : buf.length - linepos;
   820                            (b[off++] & 0xff) <<  8 |
   850                 int sl = off + Math.min(nBits24, dl / 4) * 3;
   821                            (b[off++] & 0xff);
   851                 int dp = 0;
   822                 out.write(base64[(bits >>> 18) & 0x3f]);
   852                 for (int sp = off; sp < sl; ) {
   823                 out.write(base64[(bits >>> 12) & 0x3f]);
   853                     int bits = (b[sp++] & 0xff) << 16 |
   824                 out.write(base64[(bits >>> 6)  & 0x3f]);
   854                                (b[sp++] & 0xff) <<  8 |
   825                 out.write(base64[bits & 0x3f]);
   855                                (b[sp++] & 0xff);
   826                 linepos += 4;
   856                     buf[dp++] = (byte)base64[(bits >>> 18) & 0x3f];
   827            }
   857                     buf[dp++] = (byte)base64[(bits >>> 12) & 0x3f];
       
   858                     buf[dp++] = (byte)base64[(bits >>> 6)  & 0x3f];
       
   859                     buf[dp++] = (byte)base64[bits & 0x3f];
       
   860                 }
       
   861                 out.write(buf, 0, dp);
       
   862                 off = sl;
       
   863                 linepos += dp;
       
   864                 nBits24 -= dp / 4;
       
   865             }
   828             if (leftover == 1) {
   866             if (leftover == 1) {
   829                 b0 = b[off++] & 0xff;
   867                 b0 = b[off++] & 0xff;
   830             } else if (leftover == 2) {
   868             } else if (leftover == 2) {
   831                 b0 = b[off++] & 0xff;
   869                 b0 = b[off++] & 0xff;
   832                 b1 = b[off++] & 0xff;
   870                 b1 = b[off++] & 0xff;
   887         @Override
   925         @Override
   888         public int read() throws IOException {
   926         public int read() throws IOException {
   889             return read(sbBuf, 0, 1) == -1 ? -1 : sbBuf[0] & 0xff;
   927             return read(sbBuf, 0, 1) == -1 ? -1 : sbBuf[0] & 0xff;
   890         }
   928         }
   891 
   929 
       
   930         private int eof(byte[] b, int off, int len, int oldOff)
       
   931             throws IOException
       
   932         {
       
   933             eof = true;
       
   934             if (nextin != 18) {
       
   935                 if (nextin == 12)
       
   936                     throw new IOException("Base64 stream has one un-decoded dangling byte.");
       
   937                 // treat ending xx/xxx without padding character legal.
       
   938                 // same logic as v == '=' below
       
   939                 b[off++] = (byte)(bits >> (16));
       
   940                 if (nextin == 0) {           // only one padding byte
       
   941                     if (len == 1) {          // no enough output space
       
   942                         bits >>= 8;          // shift to lowest byte
       
   943                         nextout = 0;
       
   944                     } else {
       
   945                         b[off++] = (byte) (bits >>  8);
       
   946                     }
       
   947                 }
       
   948             }
       
   949             return off == oldOff ? -1 : off - oldOff;
       
   950         }
       
   951 
       
   952         private int padding(byte[] b, int off, int len, int oldOff)
       
   953             throws IOException
       
   954         {
       
   955             // =     shiftto==18 unnecessary padding
       
   956             // x=    shiftto==12 dangling x, invalid unit
       
   957             // xx=   shiftto==6 && missing last '='
       
   958             // xx=y  or last is not '='
       
   959             if (nextin == 18 || nextin == 12 ||
       
   960                 nextin == 6 && is.read() != '=') {
       
   961                 throw new IOException("Illegal base64 ending sequence:" + nextin);
       
   962             }
       
   963             b[off++] = (byte)(bits >> (16));
       
   964             if (nextin == 0) {           // only one padding byte
       
   965                 if (len == 1) {          // no enough output space
       
   966                     bits >>= 8;          // shift to lowest byte
       
   967                     nextout = 0;
       
   968                 } else {
       
   969                     b[off++] = (byte) (bits >>  8);
       
   970                 }
       
   971             }
       
   972             eof = true;
       
   973             return off - oldOff;
       
   974         }
       
   975 
   892         @Override
   976         @Override
   893         public int read(byte[] b, int off, int len) throws IOException {
   977         public int read(byte[] b, int off, int len) throws IOException {
   894             if (closed)
   978             if (closed)
   895                 throw new IOException("Stream is closed");
   979                 throw new IOException("Stream is closed");
   896             if (eof && nextout < 0)    // eof and no leftover
   980             if (eof && nextout < 0)    // eof and no leftover
   897                 return -1;
   981                 return -1;
   898             if (off < 0 || len < 0 || len > b.length - off)
   982             if (off < 0 || len < 0 || len > b.length - off)
   899                 throw new IndexOutOfBoundsException();
   983                 throw new IndexOutOfBoundsException();
   900             int oldOff = off;
   984             int oldOff = off;
   901             if (nextout >= 0) {       // leftover output byte(s) in bits buf
   985             while (nextout >= 0) {       // leftover output byte(s) in bits buf
   902                 do {
   986                 if (len == 0)
   903                     if (len == 0)
   987                     return off - oldOff;
   904                         return off - oldOff;
   988                 b[off++] = (byte)(bits >> nextout);
   905                     b[off++] = (byte)(bits >> nextout);
   989                 len--;
   906                     len--;
   990                 nextout -= 8;
   907                     nextout -= 8;
   991             }
   908                 } while (nextout >= 0);
   992             bits = 0;
   909                 bits = 0;
       
   910             }
       
   911             while (len > 0) {
   993             while (len > 0) {
   912                 int v = is.read();
   994                 int v = is.read();
   913                 if (v == -1) {
   995                 if (v == -1) {
   914                     eof = true;
   996                     return eof(b, off, len, oldOff);
   915                     if (nextin != 18) {
   997                 }
   916                         if (nextin == 12)
   998                 if ((v = base64[v]) < 0) {
   917                             throw new IOException("Base64 stream has one un-decoded dangling byte.");
   999                     if (v == -2) {       // padding byte(s)
   918                         // treat ending xx/xxx without padding character legal.
  1000                         return padding(b, off, len, oldOff);
   919                         // same logic as v == '=' below
  1001                     }
   920                         b[off++] = (byte)(bits >> (16));
  1002                     if (v == -1) {
   921                         len--;
  1003                         if (!isMIME)
   922                         if (nextin == 0) {           // only one padding byte
  1004                             throw new IOException("Illegal base64 character " +
   923                             if (len == 0) {          // no enough output space
  1005                                 Integer.toString(v, 16));
   924                                 bits >>= 8;          // shift to lowest byte
  1006                         continue;        // skip if for rfc2045
   925                                 nextout = 0;
  1007                     }
   926                             } else {
  1008                     // neve be here
   927                                 b[off++] = (byte) (bits >>  8);
       
   928                             }
       
   929                         }
       
   930                     }
       
   931                     if (off == oldOff)
       
   932                         return -1;
       
   933                     else
       
   934                         return off - oldOff;
       
   935                 }
       
   936                 if (v == '=') {                  // padding byte(s)
       
   937                     // =     shiftto==18 unnecessary padding
       
   938                     // x=    shiftto==12 dangling x, invalid unit
       
   939                     // xx=   shiftto==6 && missing last '='
       
   940                     // xx=y  or last is not '='
       
   941                     if (nextin == 18 || nextin == 12 ||
       
   942                         nextin == 6 && is.read() != '=') {
       
   943                         throw new IOException("Illegal base64 ending sequence:" + nextin);
       
   944                     }
       
   945                     b[off++] = (byte)(bits >> (16));
       
   946                     len--;
       
   947                     if (nextin == 0) {           // only one padding byte
       
   948                         if (len == 0) {          // no enough output space
       
   949                             bits >>= 8;          // shift to lowest byte
       
   950                             nextout = 0;
       
   951                         } else {
       
   952                             b[off++] = (byte) (bits >>  8);
       
   953                         }
       
   954                     }
       
   955                     eof = true;
       
   956                     break;
       
   957                 }
       
   958                 if ((v = base64[v]) == -1) {
       
   959                     if (isMIME)                 // skip if for rfc2045
       
   960                         continue;
       
   961                     else
       
   962                         throw new IOException("Illegal base64 character " +
       
   963                             Integer.toString(v, 16));
       
   964                 }
  1009                 }
   965                 bits |= (v << nextin);
  1010                 bits |= (v << nextin);
   966                 if (nextin == 0) {
  1011                 if (nextin == 0) {
   967                     nextin = 18;    // clear for next
  1012                     nextin = 18;         // clear for next in
   968                     nextout = 16;
  1013                     b[off++] = (byte)(bits >> 16);
   969                     while (nextout >= 0) {
  1014                     if (len == 1) {
   970                         b[off++] = (byte)(bits >> nextout);
  1015                         nextout = 8;    // 2 bytes left in bits
   971                         len--;
  1016                         break;
   972                         nextout -= 8;
  1017                     }
   973                         if (len == 0 && nextout >= 0) {  // don't clean "bits"
  1018                     b[off++] = (byte)(bits >> 8);
   974                             return off - oldOff;
  1019                     if (len == 2) {
   975                         }
  1020                         nextout = 0;    // 1 byte left in bits
   976                     }
  1021                         break;
       
  1022                     }
       
  1023                     b[off++] = (byte)bits;
       
  1024                     len -= 3;
   977                     bits = 0;
  1025                     bits = 0;
   978                 } else {
  1026                 } else {
   979                     nextin -= 6;
  1027                     nextin -= 6;
   980                 }
  1028                 }
   981             }
  1029             }