mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
8164278: java.util.Base64.EncOutputStream/DecInputStream is slower than corresponding version in javax.mail package
Reviewed-by: rriggs
This commit is contained in:
parent
abb7e3a52a
commit
f6ca24c05f
1 changed files with 128 additions and 80 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -693,6 +693,25 @@ public class Base64 {
|
|||
int bits = 0;
|
||||
int shiftto = 18; // pos of first byte of 4-byte atom
|
||||
while (sp < sl) {
|
||||
if (bits == 0 && sp + 4 < sl) { // fast path
|
||||
int sl0 = sp + ((sl - sp) & ~0b11);
|
||||
while (sp < sl0) {
|
||||
int b1 = base64[src[sp++] & 0xff];
|
||||
int b2 = base64[src[sp++] & 0xff];
|
||||
int b3 = base64[src[sp++] & 0xff];
|
||||
int b4 = base64[src[sp++] & 0xff];
|
||||
if ((b1 | b2 | b3 | b4) < 0) { // non base64 byte
|
||||
sp -= 4;
|
||||
break;
|
||||
}
|
||||
int bits0 = b1 << 18 | b2 << 12 | b3 << 6 | b4;
|
||||
dst[dp++] = (byte)(bits0 >> 16);
|
||||
dst[dp++] = (byte)(bits0 >> 8);
|
||||
dst[dp++] = (byte)(bits0);
|
||||
}
|
||||
if (sp >= sl)
|
||||
break;
|
||||
}
|
||||
int b = src[sp++] & 0xff;
|
||||
if ((b = base64[b]) < 0) {
|
||||
if (b == -2) { // padding byte '='
|
||||
|
@ -762,6 +781,7 @@ public class Base64 {
|
|||
private final int linemax;
|
||||
private final boolean doPadding;// whether or not to pad
|
||||
private int linepos = 0;
|
||||
private byte[] buf;
|
||||
|
||||
EncOutputStream(OutputStream os, char[] base64,
|
||||
byte[] newline, int linemax, boolean doPadding) {
|
||||
|
@ -770,6 +790,7 @@ public class Base64 {
|
|||
this.newline = newline;
|
||||
this.linemax = linemax;
|
||||
this.doPadding = doPadding;
|
||||
this.buf = new byte[linemax <= 0 ? 8124 : linemax];
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -786,6 +807,14 @@ public class Base64 {
|
|||
}
|
||||
}
|
||||
|
||||
private void writeb4(char b1, char b2, char b3, char b4) throws IOException {
|
||||
buf[0] = (byte)b1;
|
||||
buf[1] = (byte)b2;
|
||||
buf[2] = (byte)b3;
|
||||
buf[3] = (byte)b4;
|
||||
out.write(buf, 0, 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
if (closed)
|
||||
|
@ -806,25 +835,34 @@ public class Base64 {
|
|||
b2 = b[off++] & 0xff;
|
||||
len--;
|
||||
checkNewline();
|
||||
out.write(base64[b0 >> 2]);
|
||||
out.write(base64[(b0 << 4) & 0x3f | (b1 >> 4)]);
|
||||
out.write(base64[(b1 << 2) & 0x3f | (b2 >> 6)]);
|
||||
out.write(base64[b2 & 0x3f]);
|
||||
writeb4(base64[b0 >> 2],
|
||||
base64[(b0 << 4) & 0x3f | (b1 >> 4)],
|
||||
base64[(b1 << 2) & 0x3f | (b2 >> 6)],
|
||||
base64[b2 & 0x3f]);
|
||||
linepos += 4;
|
||||
}
|
||||
int nBits24 = len / 3;
|
||||
leftover = len - (nBits24 * 3);
|
||||
while (nBits24-- > 0) {
|
||||
|
||||
while (nBits24 > 0) {
|
||||
checkNewline();
|
||||
int bits = (b[off++] & 0xff) << 16 |
|
||||
(b[off++] & 0xff) << 8 |
|
||||
(b[off++] & 0xff);
|
||||
out.write(base64[(bits >>> 18) & 0x3f]);
|
||||
out.write(base64[(bits >>> 12) & 0x3f]);
|
||||
out.write(base64[(bits >>> 6) & 0x3f]);
|
||||
out.write(base64[bits & 0x3f]);
|
||||
linepos += 4;
|
||||
}
|
||||
int dl = linemax <= 0 ? buf.length : buf.length - linepos;
|
||||
int sl = off + Math.min(nBits24, dl / 4) * 3;
|
||||
int dp = 0;
|
||||
for (int sp = off; sp < sl; ) {
|
||||
int bits = (b[sp++] & 0xff) << 16 |
|
||||
(b[sp++] & 0xff) << 8 |
|
||||
(b[sp++] & 0xff);
|
||||
buf[dp++] = (byte)base64[(bits >>> 18) & 0x3f];
|
||||
buf[dp++] = (byte)base64[(bits >>> 12) & 0x3f];
|
||||
buf[dp++] = (byte)base64[(bits >>> 6) & 0x3f];
|
||||
buf[dp++] = (byte)base64[bits & 0x3f];
|
||||
}
|
||||
out.write(buf, 0, dp);
|
||||
off = sl;
|
||||
linepos += dp;
|
||||
nBits24 -= dp / 4;
|
||||
}
|
||||
if (leftover == 1) {
|
||||
b0 = b[off++] & 0xff;
|
||||
} else if (leftover == 2) {
|
||||
|
@ -889,6 +927,52 @@ public class Base64 {
|
|||
return read(sbBuf, 0, 1) == -1 ? -1 : sbBuf[0] & 0xff;
|
||||
}
|
||||
|
||||
private int eof(byte[] b, int off, int len, int oldOff)
|
||||
throws IOException
|
||||
{
|
||||
eof = true;
|
||||
if (nextin != 18) {
|
||||
if (nextin == 12)
|
||||
throw new IOException("Base64 stream has one un-decoded dangling byte.");
|
||||
// treat ending xx/xxx without padding character legal.
|
||||
// same logic as v == '=' below
|
||||
b[off++] = (byte)(bits >> (16));
|
||||
if (nextin == 0) { // only one padding byte
|
||||
if (len == 1) { // no enough output space
|
||||
bits >>= 8; // shift to lowest byte
|
||||
nextout = 0;
|
||||
} else {
|
||||
b[off++] = (byte) (bits >> 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
return off == oldOff ? -1 : off - oldOff;
|
||||
}
|
||||
|
||||
private int padding(byte[] b, int off, int len, int oldOff)
|
||||
throws IOException
|
||||
{
|
||||
// = shiftto==18 unnecessary padding
|
||||
// x= shiftto==12 dangling x, invalid unit
|
||||
// xx= shiftto==6 && missing last '='
|
||||
// xx=y or last is not '='
|
||||
if (nextin == 18 || nextin == 12 ||
|
||||
nextin == 6 && is.read() != '=') {
|
||||
throw new IOException("Illegal base64 ending sequence:" + nextin);
|
||||
}
|
||||
b[off++] = (byte)(bits >> (16));
|
||||
if (nextin == 0) { // only one padding byte
|
||||
if (len == 1) { // no enough output space
|
||||
bits >>= 8; // shift to lowest byte
|
||||
nextout = 0;
|
||||
} else {
|
||||
b[off++] = (byte) (bits >> 8);
|
||||
}
|
||||
}
|
||||
eof = true;
|
||||
return off - oldOff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
if (closed)
|
||||
|
@ -898,82 +982,46 @@ public class Base64 {
|
|||
if (off < 0 || len < 0 || len > b.length - off)
|
||||
throw new IndexOutOfBoundsException();
|
||||
int oldOff = off;
|
||||
if (nextout >= 0) { // leftover output byte(s) in bits buf
|
||||
do {
|
||||
if (len == 0)
|
||||
return off - oldOff;
|
||||
b[off++] = (byte)(bits >> nextout);
|
||||
len--;
|
||||
nextout -= 8;
|
||||
} while (nextout >= 0);
|
||||
bits = 0;
|
||||
while (nextout >= 0) { // leftover output byte(s) in bits buf
|
||||
if (len == 0)
|
||||
return off - oldOff;
|
||||
b[off++] = (byte)(bits >> nextout);
|
||||
len--;
|
||||
nextout -= 8;
|
||||
}
|
||||
bits = 0;
|
||||
while (len > 0) {
|
||||
int v = is.read();
|
||||
if (v == -1) {
|
||||
eof = true;
|
||||
if (nextin != 18) {
|
||||
if (nextin == 12)
|
||||
throw new IOException("Base64 stream has one un-decoded dangling byte.");
|
||||
// treat ending xx/xxx without padding character legal.
|
||||
// same logic as v == '=' below
|
||||
b[off++] = (byte)(bits >> (16));
|
||||
len--;
|
||||
if (nextin == 0) { // only one padding byte
|
||||
if (len == 0) { // no enough output space
|
||||
bits >>= 8; // shift to lowest byte
|
||||
nextout = 0;
|
||||
} else {
|
||||
b[off++] = (byte) (bits >> 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (off == oldOff)
|
||||
return -1;
|
||||
else
|
||||
return off - oldOff;
|
||||
return eof(b, off, len, oldOff);
|
||||
}
|
||||
if (v == '=') { // padding byte(s)
|
||||
// = shiftto==18 unnecessary padding
|
||||
// x= shiftto==12 dangling x, invalid unit
|
||||
// xx= shiftto==6 && missing last '='
|
||||
// xx=y or last is not '='
|
||||
if (nextin == 18 || nextin == 12 ||
|
||||
nextin == 6 && is.read() != '=') {
|
||||
throw new IOException("Illegal base64 ending sequence:" + nextin);
|
||||
if ((v = base64[v]) < 0) {
|
||||
if (v == -2) { // padding byte(s)
|
||||
return padding(b, off, len, oldOff);
|
||||
}
|
||||
b[off++] = (byte)(bits >> (16));
|
||||
len--;
|
||||
if (nextin == 0) { // only one padding byte
|
||||
if (len == 0) { // no enough output space
|
||||
bits >>= 8; // shift to lowest byte
|
||||
nextout = 0;
|
||||
} else {
|
||||
b[off++] = (byte) (bits >> 8);
|
||||
}
|
||||
if (v == -1) {
|
||||
if (!isMIME)
|
||||
throw new IOException("Illegal base64 character " +
|
||||
Integer.toString(v, 16));
|
||||
continue; // skip if for rfc2045
|
||||
}
|
||||
eof = true;
|
||||
break;
|
||||
}
|
||||
if ((v = base64[v]) == -1) {
|
||||
if (isMIME) // skip if for rfc2045
|
||||
continue;
|
||||
else
|
||||
throw new IOException("Illegal base64 character " +
|
||||
Integer.toString(v, 16));
|
||||
// neve be here
|
||||
}
|
||||
bits |= (v << nextin);
|
||||
if (nextin == 0) {
|
||||
nextin = 18; // clear for next
|
||||
nextout = 16;
|
||||
while (nextout >= 0) {
|
||||
b[off++] = (byte)(bits >> nextout);
|
||||
len--;
|
||||
nextout -= 8;
|
||||
if (len == 0 && nextout >= 0) { // don't clean "bits"
|
||||
return off - oldOff;
|
||||
}
|
||||
nextin = 18; // clear for next in
|
||||
b[off++] = (byte)(bits >> 16);
|
||||
if (len == 1) {
|
||||
nextout = 8; // 2 bytes left in bits
|
||||
break;
|
||||
}
|
||||
b[off++] = (byte)(bits >> 8);
|
||||
if (len == 2) {
|
||||
nextout = 0; // 1 byte left in bits
|
||||
break;
|
||||
}
|
||||
b[off++] = (byte)bits;
|
||||
len -= 3;
|
||||
bits = 0;
|
||||
} else {
|
||||
nextin -= 6;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue