/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id: Base64DecodeStream.java 1732018 2016-02-24 04:51:06Z gadams $ */
package org.apache.xmlgraphics.util.io;
import java.io.IOException;
import java.io.InputStream;
// CSOFF: ConstantName
// CSOFF: MemberName
// CSOFF: MultipleVariableDeclarations
// CSOFF: NeedBraces
// CSOFF: OperatorWrap
// CSOFF: WhitespaceAround
This class implements a Base64 Character decoder as specified in RFC1113.
Unlike some other encoding schemes there is nothing in this encoding that
tells the decoder where a buffer starts or stops, so to use it you will need
to isolate your encoded data into a single chunk and then feed them
this decoder. The simplest way to do that is to read all of the encoded
data into a string and then use:
byte data[];
InputStream is = new ByteArrayInputStream(data);
is = new Base64DecodeStream(is);
On errors, this class throws a IOException with the following detail
strings:
"Base64DecodeStream: Bad Padding byte (2)."
"Base64DecodeStream: Bad Padding byte (1)."
Version: $Id: Base64DecodeStream.java 1732018 2016-02-24 04:51:06Z gadams $
Originally authored by Thomas DeWeese, Vincent Hardy, and Chuck McManis.
/**
* This class implements a Base64 Character decoder as specified in RFC1113.
* Unlike some other encoding schemes there is nothing in this encoding that
* tells the decoder where a buffer starts or stops, so to use it you will need
* to isolate your encoded data into a single chunk and then feed them
* this decoder. The simplest way to do that is to read all of the encoded
* data into a string and then use:
* <pre>
* byte data[];
* InputStream is = new ByteArrayInputStream(data);
* is = new Base64DecodeStream(is);
* </pre>
*
* On errors, this class throws a IOException with the following detail
* strings:
* <pre>
* "Base64DecodeStream: Bad Padding byte (2)."
* "Base64DecodeStream: Bad Padding byte (1)."
* </pre>
*
* @version $Id: Base64DecodeStream.java 1732018 2016-02-24 04:51:06Z gadams $
*
* Originally authored by Thomas DeWeese, Vincent Hardy, and Chuck McManis.
*/
public class Base64DecodeStream extends InputStream {
InputStream src;
public Base64DecodeStream(InputStream src) {
this.src = src;
}
private static final byte[] PEM_ARRAY = new byte[256];
static {
for (int i = 0; i < PEM_ARRAY.length; i++) {
PEM_ARRAY[i] = -1;
}
int idx = 0;
for (char c = 'A'; c <= 'Z'; c++) {
PEM_ARRAY[c] = (byte)idx++;
}
for (char c = 'a'; c <= 'z'; c++) {
PEM_ARRAY[c] = (byte)idx++;
}
for (char c = '0'; c <= '9'; c++) {
PEM_ARRAY[c] = (byte)idx++;
}
PEM_ARRAY['+'] = (byte)idx++;
PEM_ARRAY['/'] = (byte)idx++;
}
public boolean markSupported() {
return false;
}
public void close()
throws IOException {
eof = true;
}
public int available()
throws IOException {
return 3 - outOffset;
}
byte[] decodeBuffer = new byte[4];
byte[] outBuffer = new byte[3];
int outOffset = 3;
boolean eof;
public int read() throws IOException {
if (outOffset == 3) {
if (eof || getNextAtom()) {
eof = true;
return -1;
}
}
return ((int)outBuffer[outOffset++]) & 0xFF;
}
public int read(byte []out, int offset, int len)
throws IOException {
int idx = 0;
while (idx < len) {
if (outOffset == 3) {
if (eof || getNextAtom()) {
eof = true;
if (idx == 0) {
return -1;
} else {
return idx;
}
}
}
out[offset + idx] = outBuffer[outOffset++];
idx++;
}
return idx;
}
final boolean getNextAtom() throws IOException {
int count;
int a;
int b;
int c;
int d;
int off = 0;
while (off != 4) {
count = src.read(decodeBuffer, off, 4 - off);
if (count == -1) {
return true;
}
int in = off;
int out = off;
while (in < off + count) {
if ((decodeBuffer[in] != '\n')
&& (decodeBuffer[in] != '\r')
&& (decodeBuffer[in] != ' ')) {
decodeBuffer[out++] = decodeBuffer[in];
}
in++;
}
off = out;
}
a = PEM_ARRAY[((int)decodeBuffer[0]) & 0xFF];
b = PEM_ARRAY[((int)decodeBuffer[1]) & 0xFF];
c = PEM_ARRAY[((int)decodeBuffer[2]) & 0xFF];
d = PEM_ARRAY[((int)decodeBuffer[3]) & 0xFF];
outBuffer[0] = (byte)((a << 2) | (b >>> 4));
outBuffer[1] = (byte)((b << 4) | (c >>> 2));
outBuffer[2] = (byte)((c << 6) | d);
if (decodeBuffer[3] != '=') {
// All three bytes are good.
outOffset = 0;
} else if (decodeBuffer[2] == '=') {
// Only one byte of output.
outBuffer[2] = outBuffer[0];
outOffset = 2;
eof = true;
} else {
// Only two bytes of output.
outBuffer[2] = outBuffer[1];
outBuffer[1] = outBuffer[0];
outOffset = 1;
eof = true;
}
return false;
}
}