8028397: Undo the lenient MIME BASE64 decoder support change (JDK-8025003) and remove methods de/encode(buf, buf)
Updated the spec and implementation as requested Reviewed-by: alanb
This commit is contained in:
parent
0e30b48211
commit
591834e28d
@ -350,62 +350,6 @@ public class Base64 {
|
||||
return ByteBuffer.wrap(dst);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes as many bytes as possible from the input byte buffer
|
||||
* using the {@link Base64} encoding scheme, writing the resulting
|
||||
* bytes to the given output byte buffer.
|
||||
*
|
||||
* <p>The buffers are read from, and written to, starting at their
|
||||
* current positions. Upon return, the input and output buffers'
|
||||
* positions will be advanced to reflect the bytes read and written,
|
||||
* but their limits will not be modified.
|
||||
*
|
||||
* <p>The encoding operation will stop and return if either all
|
||||
* remaining bytes in the input buffer have been encoded and written
|
||||
* to the output buffer, or the output buffer has insufficient space
|
||||
* to encode any more input bytes. The encoding operation can be
|
||||
* continued, if there is more bytes in input buffer to be encoded,
|
||||
* by invoking this method again with an output buffer that has more
|
||||
* {@linkplain java.nio.Buffer#remaining remaining} bytes. This is
|
||||
* typically done by draining any encoded bytes from the output buffer.
|
||||
* The value returned from last invocation needs to be passed in as the
|
||||
* third parameter {@code bytesOut} if it is to continue an unfinished
|
||||
* encoding, 0 otherwise.
|
||||
*
|
||||
* <p><b>Recommended Usage Example</b>
|
||||
* <pre>
|
||||
* ByteBuffer src = ...;
|
||||
* ByteBuffer dst = ...;
|
||||
* Base64.Encoder enc = Base64.getMimeDecoder();
|
||||
*
|
||||
* int bytesOut = 0;
|
||||
* while (src.hasRemaining()) {
|
||||
* // clear output buffer for decoding
|
||||
* dst.clear();
|
||||
* bytesOut = enc.encode(src, dst, bytesOut);
|
||||
*
|
||||
* // read encoded bytes out of "dst"
|
||||
* dst.flip();
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param src
|
||||
* the input byte buffer to encode
|
||||
* @param dst
|
||||
* the output byte buffer
|
||||
* @param bytesOut
|
||||
* the return value of last invocation if this is to continue
|
||||
* an unfinished encoding operation, 0 otherwise
|
||||
* @return The sum total of {@code bytesOut} and the number of bytes
|
||||
* written to the output ByteBuffer during this invocation.
|
||||
*/
|
||||
public int encode(ByteBuffer src, ByteBuffer dst, int bytesOut) {
|
||||
if (src.hasArray() && dst.hasArray())
|
||||
return encodeArray(src, dst, bytesOut);
|
||||
return encodeBuffer(src, dst, bytesOut);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps an output stream for encoding byte data using the {@link Base64}
|
||||
* encoding scheme.
|
||||
@ -444,160 +388,6 @@ public class Base64 {
|
||||
return new Encoder(isURL, newline, linemax, false);
|
||||
}
|
||||
|
||||
private int encodeArray(ByteBuffer src, ByteBuffer dst, int bytesOut) {
|
||||
char[] base64 = isURL? toBase64URL : toBase64;
|
||||
byte[] sa = src.array();
|
||||
int sp = src.arrayOffset() + src.position();
|
||||
int sl = src.arrayOffset() + src.limit();
|
||||
byte[] da = dst.array();
|
||||
int dp = dst.arrayOffset() + dst.position();
|
||||
int dl = dst.arrayOffset() + dst.limit();
|
||||
int dp00 = dp;
|
||||
int dpos = 0; // dp of each line
|
||||
if (linemax > 0 && bytesOut > 0)
|
||||
dpos = bytesOut % (linemax + newline.length);
|
||||
try {
|
||||
if (dpos == linemax && sp < src.limit()) {
|
||||
if (dp + newline.length > dl)
|
||||
return dp - dp00 + bytesOut;
|
||||
for (byte b : newline){
|
||||
dst.put(dp++, b);
|
||||
}
|
||||
dpos = 0;
|
||||
}
|
||||
sl = sp + (sl - sp) / 3 * 3;
|
||||
while (sp < sl) {
|
||||
int slen = (linemax > 0) ? (linemax - dpos) / 4 * 3
|
||||
: sl - sp;
|
||||
int sl0 = Math.min(sp + slen, sl);
|
||||
for (int sp0 = sp, dp0 = dp ; sp0 < sl0; ) {
|
||||
if (dp0 + 4 > dl) {
|
||||
sp = sp0; dp = dp0;
|
||||
return dp0 - dp00 + bytesOut;
|
||||
}
|
||||
int bits = (sa[sp0++] & 0xff) << 16 |
|
||||
(sa[sp0++] & 0xff) << 8 |
|
||||
(sa[sp0++] & 0xff);
|
||||
da[dp0++] = (byte)base64[(bits >>> 18) & 0x3f];
|
||||
da[dp0++] = (byte)base64[(bits >>> 12) & 0x3f];
|
||||
da[dp0++] = (byte)base64[(bits >>> 6) & 0x3f];
|
||||
da[dp0++] = (byte)base64[bits & 0x3f];
|
||||
}
|
||||
int n = (sl0 - sp) / 3 * 4;
|
||||
dpos += n;
|
||||
dp += n;
|
||||
sp = sl0;
|
||||
if (dpos == linemax && sp < src.limit()) {
|
||||
if (dp + newline.length > dl)
|
||||
return dp - dp00 + bytesOut;
|
||||
for (byte b : newline){
|
||||
da[dp++] = b;
|
||||
}
|
||||
dpos = 0;
|
||||
}
|
||||
}
|
||||
sl = src.arrayOffset() + src.limit();
|
||||
if (sp < sl && dl >= dp + 4) { // 1 or 2 leftover bytes
|
||||
int b0 = sa[sp++] & 0xff;
|
||||
da[dp++] = (byte)base64[b0 >> 2];
|
||||
if (sp == sl) {
|
||||
da[dp++] = (byte)base64[(b0 << 4) & 0x3f];
|
||||
if (doPadding) {
|
||||
da[dp++] = '=';
|
||||
da[dp++] = '=';
|
||||
}
|
||||
} else {
|
||||
int b1 = sa[sp++] & 0xff;
|
||||
da[dp++] = (byte)base64[(b0 << 4) & 0x3f | (b1 >> 4)];
|
||||
da[dp++] = (byte)base64[(b1 << 2) & 0x3f];
|
||||
if (doPadding) {
|
||||
da[dp++] = '=';
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp - dp00 + bytesOut;
|
||||
} finally {
|
||||
src.position(sp - src.arrayOffset());
|
||||
dst.position(dp - dst.arrayOffset());
|
||||
}
|
||||
}
|
||||
|
||||
private int encodeBuffer(ByteBuffer src, ByteBuffer dst, int bytesOut) {
|
||||
char[] base64 = isURL? toBase64URL : toBase64;
|
||||
int sp = src.position();
|
||||
int sl = src.limit();
|
||||
int dp = dst.position();
|
||||
int dl = dst.limit();
|
||||
int dp00 = dp;
|
||||
|
||||
int dpos = 0; // dp of each line
|
||||
if (linemax > 0 && bytesOut > 0)
|
||||
dpos = bytesOut % (linemax + newline.length);
|
||||
try {
|
||||
if (dpos == linemax && sp < src.limit()) {
|
||||
if (dp + newline.length > dl)
|
||||
return dp - dp00 + bytesOut;
|
||||
for (byte b : newline){
|
||||
dst.put(dp++, b);
|
||||
}
|
||||
dpos = 0;
|
||||
}
|
||||
sl = sp + (sl - sp) / 3 * 3;
|
||||
while (sp < sl) {
|
||||
int slen = (linemax > 0) ? (linemax - dpos) / 4 * 3
|
||||
: sl - sp;
|
||||
int sl0 = Math.min(sp + slen, sl);
|
||||
for (int sp0 = sp, dp0 = dp ; sp0 < sl0; ) {
|
||||
if (dp0 + 4 > dl) {
|
||||
sp = sp0; dp = dp0;
|
||||
return dp0 - dp00 + bytesOut;
|
||||
}
|
||||
int bits = (src.get(sp0++) & 0xff) << 16 |
|
||||
(src.get(sp0++) & 0xff) << 8 |
|
||||
(src.get(sp0++) & 0xff);
|
||||
dst.put(dp0++, (byte)base64[(bits >>> 18) & 0x3f]);
|
||||
dst.put(dp0++, (byte)base64[(bits >>> 12) & 0x3f]);
|
||||
dst.put(dp0++, (byte)base64[(bits >>> 6) & 0x3f]);
|
||||
dst.put(dp0++, (byte)base64[bits & 0x3f]);
|
||||
}
|
||||
int n = (sl0 - sp) / 3 * 4;
|
||||
dpos += n;
|
||||
dp += n;
|
||||
sp = sl0;
|
||||
if (dpos == linemax && sp < src.limit()) {
|
||||
if (dp + newline.length > dl)
|
||||
return dp - dp00 + bytesOut;
|
||||
for (byte b : newline){
|
||||
dst.put(dp++, b);
|
||||
}
|
||||
dpos = 0;
|
||||
}
|
||||
}
|
||||
if (sp < src.limit() && dl >= dp + 4) { // 1 or 2 leftover bytes
|
||||
int b0 = src.get(sp++) & 0xff;
|
||||
dst.put(dp++, (byte)base64[b0 >> 2]);
|
||||
if (sp == src.limit()) {
|
||||
dst.put(dp++, (byte)base64[(b0 << 4) & 0x3f]);
|
||||
if (doPadding) {
|
||||
dst.put(dp++, (byte)'=');
|
||||
dst.put(dp++, (byte)'=');
|
||||
}
|
||||
} else {
|
||||
int b1 = src.get(sp++) & 0xff;
|
||||
dst.put(dp++, (byte)base64[(b0 << 4) & 0x3f | (b1 >> 4)]);
|
||||
dst.put(dp++, (byte)base64[(b1 << 2) & 0x3f]);
|
||||
if (doPadding) {
|
||||
dst.put(dp++, (byte)'=');
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp - dp00 + bytesOut;
|
||||
} finally {
|
||||
src.position(sp);
|
||||
dst.position(dp);
|
||||
}
|
||||
}
|
||||
|
||||
private int encode0(byte[] src, int off, int end, byte[] dst) {
|
||||
char[] base64 = isURL ? toBase64URL : toBase64;
|
||||
int sp = off;
|
||||
@ -657,20 +447,11 @@ public class Base64 {
|
||||
* required. So if the final unit of the encoded byte data only has
|
||||
* two or three Base64 characters (without the corresponding padding
|
||||
* character(s) padded), they are decoded as if followed by padding
|
||||
* character(s).
|
||||
* <p>
|
||||
* For decoders that use the <a href="#basic">Basic</a> and
|
||||
* <a href="#url">URL and Filename safe</a> type base64 scheme, and
|
||||
* if there is padding character present in the final unit, the
|
||||
* correct number of padding character(s) must be present, otherwise
|
||||
* {@code IllegalArgumentException} ({@code IOException} when reading
|
||||
* from a Base64 stream) is thrown during decoding.
|
||||
* <p>
|
||||
* Decoders that use the <a href="#mime">MIME</a> type base64 scheme
|
||||
* are more lenient when decoding the padding character(s). If the
|
||||
* padding character(s) is incorrectly encoded, the first padding
|
||||
* character encountered is interpreted as the end of the encoded byte
|
||||
* data, the decoding operation will then end and return normally.
|
||||
* character(s). If there is a padding character present in the
|
||||
* final unit, the correct number of padding character(s) must be
|
||||
* present, otherwise {@code IllegalArgumentException} (
|
||||
* {@code IOException} when reading from a Base64 stream) is thrown
|
||||
* during decoding.
|
||||
*
|
||||
* <p> Instances of {@link Decoder} class are safe for use by
|
||||
* multiple concurrent threads.
|
||||
@ -810,6 +591,10 @@ public class Base64 {
|
||||
* output buffer's position will be zero and its limit will be the
|
||||
* number of resulting decoded bytes
|
||||
*
|
||||
* <p> {@code IllegalArgumentException} is thrown if the input buffer
|
||||
* is not in valid Base64 encoding scheme. The position of the input
|
||||
* buffer will not be advanced in this case.
|
||||
*
|
||||
* @param buffer
|
||||
* the ByteBuffer to decode
|
||||
*
|
||||
@ -842,76 +627,6 @@ public class Base64 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes as many bytes as possible from the input byte buffer
|
||||
* using the {@link Base64} encoding scheme, writing the resulting
|
||||
* bytes to the given output byte buffer.
|
||||
*
|
||||
* <p>The buffers are read from, and written to, starting at their
|
||||
* current positions. Upon return, the input and output buffers'
|
||||
* positions will be advanced to reflect the bytes read and written,
|
||||
* but their limits will not be modified.
|
||||
*
|
||||
* <p> If the input buffer is not in valid Base64 encoding scheme
|
||||
* then some bytes may have been written to the output buffer
|
||||
* before IllegalArgumentException is thrown. The positions of
|
||||
* both input and output buffer will not be advanced in this case.
|
||||
*
|
||||
* <p>The decoding operation will end and return if all remaining
|
||||
* bytes in the input buffer have been decoded and written to the
|
||||
* output buffer.
|
||||
*
|
||||
* <p> The decoding operation will stop and return if the output
|
||||
* buffer has insufficient space to decode any more input bytes.
|
||||
* The decoding operation can be continued, if there is more bytes
|
||||
* in input buffer to be decoded, by invoking this method again with
|
||||
* an output buffer that has more {@linkplain java.nio.Buffer#remaining
|
||||
* remaining} bytes. This is typically done by draining any decoded
|
||||
* bytes from the output buffer.
|
||||
*
|
||||
* <p><b>Recommended Usage Example</b>
|
||||
* <pre>
|
||||
* ByteBuffer src = ...;
|
||||
* ByteBuffer dst = ...;
|
||||
* Base64.Decoder dec = Base64.getDecoder();
|
||||
*
|
||||
* while (src.hasRemaining()) {
|
||||
*
|
||||
* // prepare the output byte buffer
|
||||
* dst.clear();
|
||||
* dec.decode(src, dst);
|
||||
*
|
||||
* // read bytes from the output buffer
|
||||
* dst.flip();
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param src
|
||||
* the input byte buffer to decode
|
||||
* @param dst
|
||||
* the output byte buffer
|
||||
*
|
||||
* @return The number of bytes written to the output byte buffer during
|
||||
* this decoding invocation
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code src} is not in valid Base64 scheme.
|
||||
*/
|
||||
public int decode(ByteBuffer src, ByteBuffer dst) {
|
||||
int sp0 = src.position();
|
||||
int dp0 = dst.position();
|
||||
try {
|
||||
if (src.hasArray() && dst.hasArray())
|
||||
return decodeArray(src, dst);
|
||||
return decodeBuffer(src, dst);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
src.position(sp0);
|
||||
dst.position(dp0);
|
||||
throw iae;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an input stream for decoding {@link Base64} encoded byte stream.
|
||||
*
|
||||
@ -932,150 +647,6 @@ public class Base64 {
|
||||
return new DecInputStream(is, isURL ? fromBase64URL : fromBase64, isMIME);
|
||||
}
|
||||
|
||||
private int decodeArray(ByteBuffer src, ByteBuffer dst) {
|
||||
int[] base64 = isURL ? fromBase64URL : fromBase64;
|
||||
int bits = 0;
|
||||
int shiftto = 18; // pos of first byte of 4-byte atom
|
||||
byte[] sa = src.array();
|
||||
int sp = src.arrayOffset() + src.position();
|
||||
int sl = src.arrayOffset() + src.limit();
|
||||
byte[] da = dst.array();
|
||||
int dp = dst.arrayOffset() + dst.position();
|
||||
int dl = dst.arrayOffset() + dst.limit();
|
||||
int dp0 = dp;
|
||||
int mark = sp;
|
||||
try {
|
||||
while (sp < sl) {
|
||||
int b = sa[sp++] & 0xff;
|
||||
if ((b = base64[b]) < 0) {
|
||||
if (b == -2) { // padding byte
|
||||
if (!isMIME &&
|
||||
(shiftto == 6 && (sp == sl || sa[sp++] != '=') ||
|
||||
shiftto == 18)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Input byte array has wrong 4-byte ending unit");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (isMIME) // skip if for rfc2045
|
||||
continue;
|
||||
else
|
||||
throw new IllegalArgumentException(
|
||||
"Illegal base64 character " +
|
||||
Integer.toString(sa[sp - 1], 16));
|
||||
}
|
||||
bits |= (b << shiftto);
|
||||
shiftto -= 6;
|
||||
if (shiftto < 0) {
|
||||
if (dl < dp + 3)
|
||||
return dp - dp0;
|
||||
da[dp++] = (byte)(bits >> 16);
|
||||
da[dp++] = (byte)(bits >> 8);
|
||||
da[dp++] = (byte)(bits);
|
||||
shiftto = 18;
|
||||
bits = 0;
|
||||
mark = sp;
|
||||
}
|
||||
}
|
||||
if (shiftto == 6) {
|
||||
if (dl - dp < 1)
|
||||
return dp - dp0;
|
||||
da[dp++] = (byte)(bits >> 16);
|
||||
} else if (shiftto == 0) {
|
||||
if (dl - dp < 2)
|
||||
return dp - dp0;
|
||||
da[dp++] = (byte)(bits >> 16);
|
||||
da[dp++] = (byte)(bits >> 8);
|
||||
} else if (shiftto == 12) {
|
||||
throw new IllegalArgumentException(
|
||||
"Last unit does not have enough valid bits");
|
||||
}
|
||||
if (sp < sl) {
|
||||
if (isMIME)
|
||||
sp = sl;
|
||||
else
|
||||
throw new IllegalArgumentException(
|
||||
"Input byte array has incorrect ending byte at " + sp);
|
||||
}
|
||||
mark = sp;
|
||||
return dp - dp0;
|
||||
} finally {
|
||||
src.position(mark);
|
||||
dst.position(dp);
|
||||
}
|
||||
}
|
||||
|
||||
private int decodeBuffer(ByteBuffer src, ByteBuffer dst) {
|
||||
int[] base64 = isURL ? fromBase64URL : fromBase64;
|
||||
int bits = 0;
|
||||
int shiftto = 18; // pos of first byte of 4-byte atom
|
||||
int sp = src.position();
|
||||
int sl = src.limit();
|
||||
int dp = dst.position();
|
||||
int dl = dst.limit();
|
||||
int dp0 = dp;
|
||||
int mark = sp;
|
||||
try {
|
||||
while (sp < sl) {
|
||||
int b = src.get(sp++) & 0xff;
|
||||
if ((b = base64[b]) < 0) {
|
||||
if (b == -2) { // padding byte
|
||||
if (!isMIME &&
|
||||
(shiftto == 6 && (sp == sl || src.get(sp++) != '=') ||
|
||||
shiftto == 18)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Input byte array has wrong 4-byte ending unit");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (isMIME) // skip if for rfc2045
|
||||
continue;
|
||||
else
|
||||
throw new IllegalArgumentException(
|
||||
"Illegal base64 character " +
|
||||
Integer.toString(src.get(sp - 1), 16));
|
||||
}
|
||||
bits |= (b << shiftto);
|
||||
shiftto -= 6;
|
||||
if (shiftto < 0) {
|
||||
if (dl < dp + 3)
|
||||
return dp - dp0;
|
||||
dst.put(dp++, (byte)(bits >> 16));
|
||||
dst.put(dp++, (byte)(bits >> 8));
|
||||
dst.put(dp++, (byte)(bits));
|
||||
shiftto = 18;
|
||||
bits = 0;
|
||||
mark = sp;
|
||||
}
|
||||
}
|
||||
if (shiftto == 6) {
|
||||
if (dl - dp < 1)
|
||||
return dp - dp0;
|
||||
dst.put(dp++, (byte)(bits >> 16));
|
||||
} else if (shiftto == 0) {
|
||||
if (dl - dp < 2)
|
||||
return dp - dp0;
|
||||
dst.put(dp++, (byte)(bits >> 16));
|
||||
dst.put(dp++, (byte)(bits >> 8));
|
||||
} else if (shiftto == 12) {
|
||||
throw new IllegalArgumentException(
|
||||
"Last unit does not have enough valid bits");
|
||||
}
|
||||
if (sp < sl) {
|
||||
if (isMIME)
|
||||
sp = sl;
|
||||
else
|
||||
throw new IllegalArgumentException(
|
||||
"Input byte array has incorrect ending byte at " + sp);
|
||||
}
|
||||
mark = sp;
|
||||
return dp - dp0;
|
||||
} finally {
|
||||
src.position(mark);
|
||||
dst.position(dp);
|
||||
}
|
||||
}
|
||||
|
||||
private int outLength(byte[] src, int sp, int sl) {
|
||||
int[] base64 = isURL ? fromBase64URL : fromBase64;
|
||||
int paddings = 0;
|
||||
@ -1123,14 +694,13 @@ public class Base64 {
|
||||
int b = src[sp++] & 0xff;
|
||||
if ((b = base64[b]) < 0) {
|
||||
if (b == -2) { // padding byte '='
|
||||
if (!isMIME && // be lenient for rfc2045
|
||||
// = shiftto==18 unnecessary padding
|
||||
// x= shiftto==12 a dangling single x
|
||||
// x to be handled together with non-padding case
|
||||
// xx= shiftto==6&&sp==sl missing last =
|
||||
// xx=y shiftto==6 last is not =
|
||||
(shiftto == 6 && (sp == sl || src[sp++] != '=') ||
|
||||
shiftto == 18)) {
|
||||
// = shiftto==18 unnecessary padding
|
||||
// x= shiftto==12 a dangling single x
|
||||
// x to be handled together with non-padding case
|
||||
// xx= shiftto==6&&sp==sl missing last =
|
||||
// xx=y shiftto==6 last is not =
|
||||
if (shiftto == 6 && (sp == sl || src[sp++] != '=') ||
|
||||
shiftto == 18) {
|
||||
throw new IllegalArgumentException(
|
||||
"Input byte array has wrong 4-byte ending unit");
|
||||
}
|
||||
@ -1160,14 +730,15 @@ public class Base64 {
|
||||
dst[dp++] = (byte)(bits >> 16);
|
||||
dst[dp++] = (byte)(bits >> 8);
|
||||
} else if (shiftto == 12) {
|
||||
// dangling single "x", throw exception even in lenient mode,
|
||||
// it's incorrectly encoded.
|
||||
// dangling single "x", incorrectly encoded.
|
||||
throw new IllegalArgumentException(
|
||||
"Last unit does not have enough valid bits");
|
||||
}
|
||||
// anything left is invalid, if is not MIME.
|
||||
// if MIME (lenient), just ignore all leftover
|
||||
if (sp < sl && !isMIME) {
|
||||
// if MIME, ignore all non-base64 character
|
||||
while (sp < sl) {
|
||||
if (isMIME && base64[src[sp++]] < 0)
|
||||
continue;
|
||||
throw new IllegalArgumentException(
|
||||
"Input byte array has incorrect ending byte at " + sp);
|
||||
}
|
||||
@ -1367,26 +938,16 @@ public class Base64 {
|
||||
// xx=y or last is not '='
|
||||
if (nextin == 18 || nextin == 12 ||
|
||||
nextin == 6 && is.read() != '=') {
|
||||
if (!isMIME || nextin == 12) {
|
||||
throw new IOException("Illegal base64 ending sequence:" + nextin);
|
||||
} else if (nextin != 18) {
|
||||
// lenient mode for mime
|
||||
// (1) handle the "unnecessary padding in "xxxx ="
|
||||
// case as the eof (nextin == 18)
|
||||
// (2) decode "xx=" and "xx=y" normally
|
||||
b[off++] = (byte)(bits >> (16));
|
||||
len--;
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
throw new IOException("Illegal base64 ending sequence:" + nextin);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
eof = true;
|
||||
|
@ -51,30 +51,6 @@ public class Base64GetEncoderTest {
|
||||
|
||||
testWrapEncode2(encoder);
|
||||
|
||||
testEncodeWithByteBuffer(encoder);
|
||||
|
||||
}
|
||||
|
||||
private static void testEncodeWithByteBuffer(final Base64.Encoder encoder) {
|
||||
System.err.println("\n\nEncoder.encode with ByteBuffer test ");
|
||||
final byte[] secondTestBuffer =
|
||||
"api/java_util/Base64/index.html#GetEncoderMimeCustom[noLineSeparatorInEncodedString]"
|
||||
.getBytes(US_ASCII);
|
||||
String base64EncodedString;
|
||||
ByteBuffer srcData = ByteBuffer.wrap(secondTestBuffer);
|
||||
ByteBuffer dstData = ByteBuffer.allocate(secondTestBuffer.length * 2);
|
||||
|
||||
encoder.encode(srcData, dstData, 0);
|
||||
dstData.flip();
|
||||
if (dstData.hasArray()) {
|
||||
System.err.println("\nByteBuffer test dstData is Base64 encoding = "
|
||||
+ new String(dstData.array(), US_ASCII) + "\n");
|
||||
}
|
||||
|
||||
base64EncodedString = new String(dstData.array(), US_ASCII);
|
||||
if (base64EncodedString.contains("$$$")) {
|
||||
throw new RuntimeException("Base64 encoding contains line separator after Encoder.encode ByteBuffer ... \n");
|
||||
}
|
||||
}
|
||||
|
||||
private static void testWrapEncode2(final Base64.Encoder encoder)
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/**
|
||||
* @test 4235519 8004212 8005394 8007298 8006295 8006315 8006530 8007379 8008925
|
||||
* 8014217 8025003 8026330
|
||||
* 8014217 8025003 8026330 8028397
|
||||
* @summary tests java.util.Base64
|
||||
*/
|
||||
|
||||
@ -92,6 +92,9 @@ public class TestBase64 {
|
||||
// illegal line separator
|
||||
checkIAE(new Runnable() { public void run() { Base64.getMimeEncoder(10, new byte[]{'\r', 'N'}); }});
|
||||
|
||||
// malformed padding/ending
|
||||
testMalformedPadding();
|
||||
|
||||
// illegal base64 character
|
||||
decoded[2] = (byte)0xe0;
|
||||
checkIAE(new Runnable() {
|
||||
@ -100,34 +103,15 @@ public class TestBase64 {
|
||||
public void run() { Base64.getDecoder().decode(decoded, new byte[1024]); }});
|
||||
checkIAE(new Runnable() { public void run() {
|
||||
Base64.getDecoder().decode(ByteBuffer.wrap(decoded)); }});
|
||||
checkIAE(new Runnable() { public void run() {
|
||||
Base64.getDecoder().decode(ByteBuffer.wrap(decoded), ByteBuffer.allocate(1024)); }});
|
||||
checkIAE(new Runnable() { public void run() {
|
||||
Base64.getDecoder().decode(ByteBuffer.wrap(decoded), ByteBuffer.allocateDirect(1024)); }});
|
||||
|
||||
// illegal ending unit
|
||||
checkIOE(new Testable() { public void test() throws IOException {
|
||||
byte[] bytes = "AA=".getBytes("ASCII");
|
||||
try (InputStream stream =
|
||||
Base64.getDecoder().wrap(new ByteArrayInputStream(bytes))) {
|
||||
while (stream.read() != -1);
|
||||
}
|
||||
}});
|
||||
|
||||
// test return value from decode(ByteBuffer, ByteBuffer)
|
||||
testDecBufRet();
|
||||
|
||||
// test single-non-base64 character for mime decoding
|
||||
testSingleNonBase64MimeDec();
|
||||
|
||||
// test decoding of unpadded data
|
||||
testDecodeUnpadded();
|
||||
|
||||
// test mime decoding with ignored character after padding
|
||||
testDecodeIgnoredAfterPadding();
|
||||
|
||||
// lenient mode for ending unit
|
||||
testLenientPadding();
|
||||
|
||||
}
|
||||
|
||||
private static sun.misc.BASE64Encoder sunmisc = new sun.misc.BASE64Encoder();
|
||||
@ -202,24 +186,6 @@ public class TestBase64 {
|
||||
if (encoded2 != null)
|
||||
testDecode(dec, ByteBuffer.wrap(encoded2), orig);
|
||||
|
||||
// -------- testing encode(Buffer, Buffer)--------
|
||||
testEncode(enc, encoded,
|
||||
ByteBuffer.wrap(orig),
|
||||
ByteBuffer.allocate(encoded.length + 10));
|
||||
|
||||
testEncode(enc, encoded,
|
||||
ByteBuffer.wrap(orig),
|
||||
ByteBuffer.allocateDirect(encoded.length + 10));
|
||||
|
||||
// --------testing decode(Buffer, Buffer);--------
|
||||
testDecode(dec, orig,
|
||||
ByteBuffer.wrap(encoded),
|
||||
ByteBuffer.allocate(orig.length + 10));
|
||||
|
||||
testDecode(dec, orig,
|
||||
ByteBuffer.wrap(encoded),
|
||||
ByteBuffer.allocateDirect(orig.length + 10));
|
||||
|
||||
// --------testing decode.wrap(input stream)--------
|
||||
// 1) random buf length
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(encoded);
|
||||
@ -322,9 +288,7 @@ public class TestBase64 {
|
||||
checkNull(new Runnable() { public void run() { enc.encode(ba_null, new byte[10]); }});
|
||||
checkNull(new Runnable() { public void run() { enc.encode(new byte[10], ba_null); }});
|
||||
checkNull(new Runnable() { public void run() { enc.encode(bb_null); }});
|
||||
checkNull(new Runnable() { public void run() { enc.encode(bb_null, ByteBuffer.allocate(10), 0); }});
|
||||
checkNull(new Runnable() { public void run() { enc.encode(ByteBuffer.allocate(10), bb_null, 0); }});
|
||||
checkNull(new Runnable() { public void run() { enc.wrap(null); }});
|
||||
checkNull(new Runnable() { public void run() { enc.wrap((OutputStream)null); }});
|
||||
}
|
||||
|
||||
private static void testNull(final Base64.Decoder dec) {
|
||||
@ -333,9 +297,7 @@ public class TestBase64 {
|
||||
checkNull(new Runnable() { public void run() { dec.decode(ba_null, new byte[10]); }});
|
||||
checkNull(new Runnable() { public void run() { dec.decode(new byte[10], ba_null); }});
|
||||
checkNull(new Runnable() { public void run() { dec.decode(bb_null); }});
|
||||
checkNull(new Runnable() { public void run() { dec.decode(bb_null, ByteBuffer.allocate(10)); }});
|
||||
checkNull(new Runnable() { public void run() { dec.decode(ByteBuffer.allocate(10), bb_null); }});
|
||||
checkNull(new Runnable() { public void run() { dec.wrap(null); }});
|
||||
checkNull(new Runnable() { public void run() { dec.wrap((InputStream)null); }});
|
||||
}
|
||||
|
||||
private static interface Testable {
|
||||
@ -412,78 +374,63 @@ public class TestBase64 {
|
||||
dec.decode(encoded);
|
||||
throw new RuntimeException("No IAE for non-base64 char");
|
||||
} catch (IllegalArgumentException iae) {}
|
||||
|
||||
// decode(ByteBuffer[], ByteBuffer[])
|
||||
ByteBuffer encodedBB = ByteBuffer.wrap(encoded);
|
||||
ByteBuffer decodedBB = ByteBuffer.allocate(100);
|
||||
int ret = decM.decode(encodedBB, decodedBB);
|
||||
byte[] buf = new byte[ret];
|
||||
decodedBB.flip();
|
||||
decodedBB.get(buf);
|
||||
checkEqual(buf, src[i], "Non-base64 char is not ignored");
|
||||
try {
|
||||
encodedBB.rewind();
|
||||
decodedBB.clear();
|
||||
dec.decode(encodedBB, decodedBB);
|
||||
throw new RuntimeException("No IAE for non-base64 char");
|
||||
} catch (IllegalArgumentException iae) {}
|
||||
// direct
|
||||
encodedBB.rewind();
|
||||
decodedBB = ByteBuffer.allocateDirect(100);
|
||||
ret = decM.decode(encodedBB, decodedBB);
|
||||
buf = new byte[ret];
|
||||
decodedBB.flip();
|
||||
decodedBB.get(buf);
|
||||
checkEqual(buf, src[i], "Non-base64 char is not ignored");
|
||||
try {
|
||||
encodedBB.rewind();
|
||||
decodedBB.clear();
|
||||
dec.decode(encodedBB, decodedBB);
|
||||
throw new RuntimeException("No IAE for non-base64 char");
|
||||
} catch (IllegalArgumentException iae) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void testLenientPadding() throws Throwable {
|
||||
String[] data = new String[] {
|
||||
"=", "", // unnecessary padding
|
||||
"QUJD=", "ABC", //"ABC".encode() -> "QUJD"
|
||||
private static void testMalformedPadding() throws Throwable {
|
||||
Object[] data = new Object[] {
|
||||
"$=#", "", 0, // illegal ending unit
|
||||
"A", "", 0, // dangling single byte
|
||||
"A=", "", 0,
|
||||
"A==", "", 0,
|
||||
"QUJDA", "ABC", 4,
|
||||
"QUJDA=", "ABC", 4,
|
||||
"QUJDA==", "ABC", 4,
|
||||
|
||||
"QQ=", "A", // incomplete padding
|
||||
"QQ=N", "A", // incorrect padding
|
||||
"QQ=?", "A",
|
||||
"QUJDQQ=", "ABCA",
|
||||
"QUJDQQ=N", "ABCA",
|
||||
"QUJDQQ=?", "ABCA",
|
||||
"=", "", 0, // unnecessary padding
|
||||
"QUJD=", "ABC", 4, //"ABC".encode() -> "QUJD"
|
||||
|
||||
"QUI=X", "AB", // incorrect padding
|
||||
"QUI=?", "AB", // incorrect padding
|
||||
"AA=", "", 0, // incomplete padding
|
||||
"QQ=", "", 0,
|
||||
"QQ=N", "", 0, // incorrect padding
|
||||
"QQ=?", "", 0,
|
||||
"QUJDQQ=", "ABC", 4,
|
||||
"QUJDQQ=N", "ABC", 4,
|
||||
"QUJDQQ=?", "ABC", 4,
|
||||
};
|
||||
Base64.Decoder dec = Base64.getMimeDecoder();
|
||||
|
||||
for (int i = 0; i < data.length; i += 2) {
|
||||
byte[] src = data[i].getBytes("ASCII");
|
||||
byte[] expected = data[i + 1].getBytes("ASCII");
|
||||
// decode(byte[])
|
||||
byte[] ret = dec.decode(src);
|
||||
checkEqual(ret, expected, "lenient padding decoding failed!");
|
||||
Base64.Decoder[] decs = new Base64.Decoder[] {
|
||||
Base64.getDecoder(),
|
||||
Base64.getUrlDecoder(),
|
||||
Base64.getMimeDecoder()
|
||||
};
|
||||
|
||||
// decode(String)
|
||||
ret = dec.decode(data[i]);
|
||||
checkEqual(ret, expected, "lenient padding decoding failed!");
|
||||
for (Base64.Decoder dec : decs) {
|
||||
for (int i = 0; i < data.length; i += 3) {
|
||||
final String srcStr = (String)data[i];
|
||||
final byte[] srcBytes = srcStr.getBytes("ASCII");
|
||||
final ByteBuffer srcBB = ByteBuffer.wrap(srcBytes);
|
||||
byte[] expected = ((String)data[i + 1]).getBytes("ASCII");
|
||||
int pos = (Integer)data[i + 2];
|
||||
|
||||
// decode(ByteBuffer)
|
||||
ByteBuffer srcBB = ByteBuffer.wrap(src);
|
||||
ByteBuffer retBB = dec.decode(srcBB);
|
||||
checkEqual(srcBB.remaining(), 0, "lenient padding decoding failed!");
|
||||
checkEqual(Arrays.copyOf(retBB.array(), retBB.remaining()),
|
||||
expected, "lenient padding decoding failed!");
|
||||
// decode(byte[])
|
||||
checkIAE(new Runnable() { public void run() { dec.decode(srcBytes); }});
|
||||
|
||||
// wrap.decode(byte[])
|
||||
ret = new byte[10];
|
||||
int n = dec.wrap(new ByteArrayInputStream(src)).read(ret);
|
||||
checkEqual(Arrays.copyOf(ret, n), expected, "lenient padding decoding failed!");
|
||||
// decode(String)
|
||||
checkIAE(new Runnable() { public void run() { dec.decode(srcStr); }});
|
||||
|
||||
// decode(ByteBuffer)
|
||||
checkIAE(new Runnable() { public void run() { dec.decode(srcBB); }});
|
||||
|
||||
// wrap stream
|
||||
checkIOE(new Testable() {
|
||||
public void test() throws IOException {
|
||||
try (InputStream is = dec.wrap(new ByteArrayInputStream(srcBytes))) {
|
||||
while (is.read() != -1);
|
||||
}
|
||||
}});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -520,51 +467,6 @@ public class TestBase64 {
|
||||
}
|
||||
}
|
||||
|
||||
private static void testDecBufRet() throws Throwable {
|
||||
Random rnd = new java.util.Random();
|
||||
Base64.Encoder encoder = Base64.getEncoder();
|
||||
Base64.Decoder decoder = Base64.getDecoder();
|
||||
// src pos, len expected
|
||||
int[][] tests = { { 6, 3, 3, 3}, // xxx xxx -> yyyy yyyy
|
||||
{ 6, 3, 4, 3},
|
||||
{ 6, 3, 5, 3},
|
||||
{ 6, 3, 6, 6},
|
||||
{ 6, 11, 4, 3},
|
||||
{ 6, 11, 4, 3},
|
||||
{ 6, 11, 5, 3},
|
||||
{ 6, 11, 6, 6},
|
||||
{ 7, 3, 6, 6}, // xxx xxx x -> yyyy yyyy yy==
|
||||
{ 7, 3, 7, 7},
|
||||
{ 7, 11, 6, 6},
|
||||
{ 7, 11, 7, 7},
|
||||
{ 8, 3, 6, 6}, // xxx xxx xx -> yyyy yyyy yyy=
|
||||
{ 8, 3, 7, 6},
|
||||
{ 8, 3, 8, 8},
|
||||
{ 8, 13, 6, 6},
|
||||
{ 8, 13, 7, 6},
|
||||
{ 8, 13, 8, 8},
|
||||
|
||||
};
|
||||
ByteBuffer dstBuf = ByteBuffer.allocate(100);
|
||||
for (boolean direct : new boolean[] { false, true}) {
|
||||
for (int[] test : tests) {
|
||||
byte[] src = new byte[test[0]];
|
||||
rnd.nextBytes(src);
|
||||
ByteBuffer srcBuf = direct ? ByteBuffer.allocate(100)
|
||||
: ByteBuffer.allocateDirect(100);
|
||||
srcBuf.put(encoder.encode(src)).flip();
|
||||
dstBuf.clear().position(test[1]).limit(test[1]+ test[2]);
|
||||
int ret = decoder.decode(srcBuf, dstBuf);
|
||||
if (ret != test[3]) {
|
||||
System.out.printf(" [%6s] src=%d, pos=%d, len=%d, expected=%d, ret=%d%n",
|
||||
direct?"direct":"",
|
||||
test[0], test[1], test[2], test[3], ret);
|
||||
throw new RuntimeException("ret != expected");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final void testEncode(Base64.Encoder enc, ByteBuffer bin, byte[] expected)
|
||||
throws Throwable {
|
||||
|
||||
@ -587,71 +489,6 @@ public class TestBase64 {
|
||||
checkEqual(buf, expected, "Base64 dec.decode(bf) failed!");
|
||||
}
|
||||
|
||||
private static final void testEncode(Base64.Encoder enc, byte[] expected,
|
||||
ByteBuffer ibb, ByteBuffer obb)
|
||||
throws Throwable {
|
||||
Random rnd = new Random();
|
||||
int bytesOut = enc.encode(ibb, obb, 0);
|
||||
if (ibb.hasRemaining()) {
|
||||
throw new RuntimeException(
|
||||
"Base64 enc.encode(bf, bf) failed with wrong return!");
|
||||
}
|
||||
obb.flip();
|
||||
byte[] buf = new byte[obb.remaining()];
|
||||
obb.get(buf);
|
||||
checkEqual(buf, expected, "Base64 enc.encode(bf, bf) failed!");
|
||||
ibb.rewind();
|
||||
obb.position(0);
|
||||
obb.limit(0);
|
||||
bytesOut = 0;
|
||||
|
||||
do { // increase the "limit" incrementally & randomly
|
||||
int n = rnd.nextInt(expected.length - obb.position());
|
||||
if (n == 0)
|
||||
n = 1;
|
||||
obb.limit(obb.limit() + n);
|
||||
//obb.limit(Math.min(obb.limit() + n, expected.length));
|
||||
bytesOut = enc.encode(ibb, obb, bytesOut);
|
||||
} while (ibb.hasRemaining());
|
||||
obb.flip();
|
||||
buf = new byte[obb.remaining()];
|
||||
obb.get(buf);
|
||||
checkEqual(buf, expected, "Base64 enc.encode(bf, bf) failed!");
|
||||
}
|
||||
|
||||
private static final void testDecode(Base64.Decoder dec, byte[] expected,
|
||||
ByteBuffer ibb, ByteBuffer obb)
|
||||
throws Throwable {
|
||||
Random rnd = new Random();
|
||||
|
||||
dec.decode(ibb, obb);
|
||||
if (ibb.hasRemaining()) {
|
||||
throw new RuntimeException(
|
||||
"Base64 dec.decode(bf, bf) failed with un-decoded ibb!");
|
||||
}
|
||||
obb.flip();
|
||||
byte[] buf = new byte[obb.remaining()];
|
||||
obb.get(buf);
|
||||
checkEqual(buf, expected, "Base64 dec.decode(bf, bf) failed!");
|
||||
|
||||
ibb.rewind();
|
||||
obb.position(0);
|
||||
obb.limit(0);
|
||||
do { // increase the "limit" incrementally & randomly
|
||||
int n = rnd.nextInt(expected.length - obb.position());
|
||||
if (n == 0)
|
||||
n = 1;
|
||||
obb.limit(obb.limit() + n);
|
||||
dec.decode(ibb, obb);
|
||||
} while (ibb.hasRemaining());
|
||||
|
||||
|
||||
obb.flip();
|
||||
buf = new byte[obb.remaining()];
|
||||
obb.get(buf);
|
||||
checkEqual(buf, expected, "Base64 dec.decode(bf, bf) failed!");
|
||||
}
|
||||
|
||||
private static final void checkEqual(int v1, int v2, String msg)
|
||||
throws Throwable {
|
||||
if (v1 != v2) {
|
||||
|
@ -55,7 +55,6 @@ public class TestBase64Golden {
|
||||
test0(Base64Type.MIME, Base64.getMimeEncoder(), Base64.getMimeDecoder(),
|
||||
"plain.txt", "mimeEncode.txt");
|
||||
test1();
|
||||
test2();
|
||||
}
|
||||
|
||||
public static void test0(Base64Type type, Encoder encoder, Decoder decoder,
|
||||
@ -113,28 +112,6 @@ public class TestBase64Golden {
|
||||
assertEqual(resBuf, encodedBuf);
|
||||
srcBuf.rewind(); // reset for next test
|
||||
|
||||
// test encode(ByteBuffer, ByteBuffer, bytesOut)
|
||||
resBuf.clear();
|
||||
len = encoder.encode(srcBuf, resBuf, 0);
|
||||
assertEqual(len, encodedArr.length);
|
||||
assertEqual(srcBuf.position(), limit);
|
||||
assertEqual(srcBuf.limit(), limit);
|
||||
assertEqual(resBuf.position(), len);
|
||||
resBuf.flip();
|
||||
assertEqual(resBuf, encodedBuf);
|
||||
srcBuf.rewind();
|
||||
|
||||
// test encode(ByteBuffer, ByteBuffer, bytesOut)[direct]
|
||||
ByteBuffer resBuf_d = ByteBuffer.allocateDirect(encodedArr.length);
|
||||
len = encoder.encode(srcBuf, resBuf_d, 0);
|
||||
assertEqual(len, encodedArr.length);
|
||||
assertEqual(srcBuf.position(), limit);
|
||||
assertEqual(srcBuf.limit(), limit);
|
||||
assertEqual(resBuf_d.position(), len);
|
||||
resBuf_d.flip();
|
||||
assertEqual(resBuf_d, encodedBuf);
|
||||
srcBuf.rewind();
|
||||
|
||||
// test String encodeToString(byte[])
|
||||
String resEncodeStr = encoder.encodeToString(srcArr);
|
||||
assertEqual(resEncodeStr, encodedStr);
|
||||
@ -157,28 +134,6 @@ public class TestBase64Golden {
|
||||
assertEqual(resBuf, srcBuf);
|
||||
encodedBuf.rewind(); // reset for next test
|
||||
|
||||
// test int decode(ByteBuffer, ByteBuffer)
|
||||
resBuf.clear();
|
||||
len = decoder.decode(encodedBuf, resBuf);
|
||||
assertEqual(len, srcArr.length);
|
||||
assertEqual(encodedBuf.position(), limit);
|
||||
assertEqual(encodedBuf.limit(), limit);
|
||||
assertEqual(resBuf.position(), len);
|
||||
resBuf.flip();
|
||||
assertEqual(resBuf, srcBuf);
|
||||
encodedBuf.rewind(); // reset for next test
|
||||
|
||||
// test int decode(ByteBuffer, ByteBuffer)[direct]
|
||||
resBuf_d = ByteBuffer.allocateDirect(srcArr.length);
|
||||
len = decoder.decode(encodedBuf, resBuf_d);
|
||||
assertEqual(len, srcArr.length);
|
||||
assertEqual(encodedBuf.position(), limit);
|
||||
assertEqual(encodedBuf.limit(), limit);
|
||||
assertEqual(resBuf_d.position(), len);
|
||||
resBuf_d.flip();
|
||||
assertEqual(resBuf_d, srcBuf);
|
||||
encodedBuf.rewind(); // reset for next test
|
||||
|
||||
// test byte[] decode(String)
|
||||
resArr = decoder.decode(encodedStr);
|
||||
assertEqual(resArr, srcArr);
|
||||
@ -197,35 +152,6 @@ public class TestBase64Golden {
|
||||
}
|
||||
|
||||
private static void test1() throws Exception {
|
||||
byte[] src = new byte[6];
|
||||
new Random().nextBytes(src);
|
||||
|
||||
ByteBuffer srcBuf = ByteBuffer.allocate(10);
|
||||
srcBuf.position(2);
|
||||
srcBuf.mark();
|
||||
srcBuf.limit(8);
|
||||
srcBuf.put(src);
|
||||
srcBuf.reset();
|
||||
|
||||
ByteBuffer dstBuf = ByteBuffer.allocate((src.length + 2) / 3 * 4);
|
||||
Base64.getEncoder().encode(srcBuf, dstBuf, 0);
|
||||
dstBuf.rewind();
|
||||
byte[] dst = new byte[dstBuf.limit()];
|
||||
dstBuf.get(dst);
|
||||
System.out.printf("%n src[%d]: %s%n", src.length, new String(src));
|
||||
System.out.printf("encoded[%d]: %s%n", dst.length, new String(dst));
|
||||
assertEqual(src, Base64.getDecoder().decode(dst));
|
||||
|
||||
dstBuf = ByteBuffer.allocateDirect((src.length + 2) / 3 * 4);
|
||||
srcBuf.reset();
|
||||
Base64.getEncoder().encode(srcBuf, dstBuf, 0);
|
||||
dstBuf.rewind();
|
||||
dst = new byte[dstBuf.limit()];
|
||||
dstBuf.get(dst);
|
||||
assertEqual(src, Base64.getDecoder().decode(dst));
|
||||
}
|
||||
|
||||
private static void test2() throws Exception {
|
||||
byte[] src = new byte[] {
|
||||
46, -97, -35, -44, 127, -60, -39, -4, -112, 34, -57, 47, -14, 67,
|
||||
40, 18, 90, -59, 68, 112, 23, 121, -91, 94, 35, 49, 104, 17, 30,
|
||||
|
Loading…
x
Reference in New Issue
Block a user