mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -693,6 +693,25 @@ public class Base64 {
|
||||||
int bits = 0;
|
int bits = 0;
|
||||||
int shiftto = 18; // pos of first byte of 4-byte atom
|
int shiftto = 18; // pos of first byte of 4-byte atom
|
||||||
while (sp < sl) {
|
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;
|
int b = src[sp++] & 0xff;
|
||||||
if ((b = base64[b]) < 0) {
|
if ((b = base64[b]) < 0) {
|
||||||
if (b == -2) { // padding byte '='
|
if (b == -2) { // padding byte '='
|
||||||
|
@ -762,6 +781,7 @@ public class Base64 {
|
||||||
private final int linemax;
|
private final int linemax;
|
||||||
private final boolean doPadding;// whether or not to pad
|
private final boolean doPadding;// whether or not to pad
|
||||||
private int linepos = 0;
|
private int linepos = 0;
|
||||||
|
private byte[] buf;
|
||||||
|
|
||||||
EncOutputStream(OutputStream os, char[] base64,
|
EncOutputStream(OutputStream os, char[] base64,
|
||||||
byte[] newline, int linemax, boolean doPadding) {
|
byte[] newline, int linemax, boolean doPadding) {
|
||||||
|
@ -770,6 +790,7 @@ public class Base64 {
|
||||||
this.newline = newline;
|
this.newline = newline;
|
||||||
this.linemax = linemax;
|
this.linemax = linemax;
|
||||||
this.doPadding = doPadding;
|
this.doPadding = doPadding;
|
||||||
|
this.buf = new byte[linemax <= 0 ? 8124 : linemax];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
@Override
|
||||||
public void write(byte[] b, int off, int len) throws IOException {
|
public void write(byte[] b, int off, int len) throws IOException {
|
||||||
if (closed)
|
if (closed)
|
||||||
|
@ -806,24 +835,33 @@ public class Base64 {
|
||||||
b2 = b[off++] & 0xff;
|
b2 = b[off++] & 0xff;
|
||||||
len--;
|
len--;
|
||||||
checkNewline();
|
checkNewline();
|
||||||
out.write(base64[b0 >> 2]);
|
writeb4(base64[b0 >> 2],
|
||||||
out.write(base64[(b0 << 4) & 0x3f | (b1 >> 4)]);
|
base64[(b0 << 4) & 0x3f | (b1 >> 4)],
|
||||||
out.write(base64[(b1 << 2) & 0x3f | (b2 >> 6)]);
|
base64[(b1 << 2) & 0x3f | (b2 >> 6)],
|
||||||
out.write(base64[b2 & 0x3f]);
|
base64[b2 & 0x3f]);
|
||||||
linepos += 4;
|
linepos += 4;
|
||||||
}
|
}
|
||||||
int nBits24 = len / 3;
|
int nBits24 = len / 3;
|
||||||
leftover = len - (nBits24 * 3);
|
leftover = len - (nBits24 * 3);
|
||||||
while (nBits24-- > 0) {
|
|
||||||
|
while (nBits24 > 0) {
|
||||||
checkNewline();
|
checkNewline();
|
||||||
int bits = (b[off++] & 0xff) << 16 |
|
int dl = linemax <= 0 ? buf.length : buf.length - linepos;
|
||||||
(b[off++] & 0xff) << 8 |
|
int sl = off + Math.min(nBits24, dl / 4) * 3;
|
||||||
(b[off++] & 0xff);
|
int dp = 0;
|
||||||
out.write(base64[(bits >>> 18) & 0x3f]);
|
for (int sp = off; sp < sl; ) {
|
||||||
out.write(base64[(bits >>> 12) & 0x3f]);
|
int bits = (b[sp++] & 0xff) << 16 |
|
||||||
out.write(base64[(bits >>> 6) & 0x3f]);
|
(b[sp++] & 0xff) << 8 |
|
||||||
out.write(base64[bits & 0x3f]);
|
(b[sp++] & 0xff);
|
||||||
linepos += 4;
|
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) {
|
if (leftover == 1) {
|
||||||
b0 = b[off++] & 0xff;
|
b0 = b[off++] & 0xff;
|
||||||
|
@ -889,28 +927,9 @@ public class Base64 {
|
||||||
return read(sbBuf, 0, 1) == -1 ? -1 : sbBuf[0] & 0xff;
|
return read(sbBuf, 0, 1) == -1 ? -1 : sbBuf[0] & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private int eof(byte[] b, int off, int len, int oldOff)
|
||||||
public int read(byte[] b, int off, int len) throws IOException {
|
throws IOException
|
||||||
if (closed)
|
{
|
||||||
throw new IOException("Stream is closed");
|
|
||||||
if (eof && nextout < 0) // eof and no leftover
|
|
||||||
return -1;
|
|
||||||
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 (len > 0) {
|
|
||||||
int v = is.read();
|
|
||||||
if (v == -1) {
|
|
||||||
eof = true;
|
eof = true;
|
||||||
if (nextin != 18) {
|
if (nextin != 18) {
|
||||||
if (nextin == 12)
|
if (nextin == 12)
|
||||||
|
@ -918,9 +937,8 @@ public class Base64 {
|
||||||
// treat ending xx/xxx without padding character legal.
|
// treat ending xx/xxx without padding character legal.
|
||||||
// same logic as v == '=' below
|
// same logic as v == '=' below
|
||||||
b[off++] = (byte)(bits >> (16));
|
b[off++] = (byte)(bits >> (16));
|
||||||
len--;
|
|
||||||
if (nextin == 0) { // only one padding byte
|
if (nextin == 0) { // only one padding byte
|
||||||
if (len == 0) { // no enough output space
|
if (len == 1) { // no enough output space
|
||||||
bits >>= 8; // shift to lowest byte
|
bits >>= 8; // shift to lowest byte
|
||||||
nextout = 0;
|
nextout = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -928,12 +946,12 @@ public class Base64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (off == oldOff)
|
return off == oldOff ? -1 : off - oldOff;
|
||||||
return -1;
|
|
||||||
else
|
|
||||||
return off - oldOff;
|
|
||||||
}
|
}
|
||||||
if (v == '=') { // padding byte(s)
|
|
||||||
|
private int padding(byte[] b, int off, int len, int oldOff)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
// = shiftto==18 unnecessary padding
|
// = shiftto==18 unnecessary padding
|
||||||
// x= shiftto==12 dangling x, invalid unit
|
// x= shiftto==12 dangling x, invalid unit
|
||||||
// xx= shiftto==6 && missing last '='
|
// xx= shiftto==6 && missing last '='
|
||||||
|
@ -943,9 +961,8 @@ public class Base64 {
|
||||||
throw new IOException("Illegal base64 ending sequence:" + nextin);
|
throw new IOException("Illegal base64 ending sequence:" + nextin);
|
||||||
}
|
}
|
||||||
b[off++] = (byte)(bits >> (16));
|
b[off++] = (byte)(bits >> (16));
|
||||||
len--;
|
|
||||||
if (nextin == 0) { // only one padding byte
|
if (nextin == 0) { // only one padding byte
|
||||||
if (len == 0) { // no enough output space
|
if (len == 1) { // no enough output space
|
||||||
bits >>= 8; // shift to lowest byte
|
bits >>= 8; // shift to lowest byte
|
||||||
nextout = 0;
|
nextout = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -953,27 +970,58 @@ public class Base64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
eof = true;
|
eof = true;
|
||||||
break;
|
return off - oldOff;
|
||||||
}
|
}
|
||||||
if ((v = base64[v]) == -1) {
|
|
||||||
if (isMIME) // skip if for rfc2045
|
@Override
|
||||||
continue;
|
public int read(byte[] b, int off, int len) throws IOException {
|
||||||
else
|
if (closed)
|
||||||
throw new IOException("Illegal base64 character " +
|
throw new IOException("Stream is closed");
|
||||||
Integer.toString(v, 16));
|
if (eof && nextout < 0) // eof and no leftover
|
||||||
}
|
return -1;
|
||||||
bits |= (v << nextin);
|
if (off < 0 || len < 0 || len > b.length - off)
|
||||||
if (nextin == 0) {
|
throw new IndexOutOfBoundsException();
|
||||||
nextin = 18; // clear for next
|
int oldOff = off;
|
||||||
nextout = 16;
|
while (nextout >= 0) { // leftover output byte(s) in bits buf
|
||||||
while (nextout >= 0) {
|
if (len == 0)
|
||||||
|
return off - oldOff;
|
||||||
b[off++] = (byte)(bits >> nextout);
|
b[off++] = (byte)(bits >> nextout);
|
||||||
len--;
|
len--;
|
||||||
nextout -= 8;
|
nextout -= 8;
|
||||||
if (len == 0 && nextout >= 0) { // don't clean "bits"
|
|
||||||
return off - oldOff;
|
|
||||||
}
|
}
|
||||||
|
bits = 0;
|
||||||
|
while (len > 0) {
|
||||||
|
int v = is.read();
|
||||||
|
if (v == -1) {
|
||||||
|
return eof(b, off, len, oldOff);
|
||||||
}
|
}
|
||||||
|
if ((v = base64[v]) < 0) {
|
||||||
|
if (v == -2) { // padding byte(s)
|
||||||
|
return padding(b, off, len, oldOff);
|
||||||
|
}
|
||||||
|
if (v == -1) {
|
||||||
|
if (!isMIME)
|
||||||
|
throw new IOException("Illegal base64 character " +
|
||||||
|
Integer.toString(v, 16));
|
||||||
|
continue; // skip if for rfc2045
|
||||||
|
}
|
||||||
|
// neve be here
|
||||||
|
}
|
||||||
|
bits |= (v << nextin);
|
||||||
|
if (nextin == 0) {
|
||||||
|
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;
|
bits = 0;
|
||||||
} else {
|
} else {
|
||||||
nextin -= 6;
|
nextin -= 6;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue