org.krysalis.barcode4j.tools.Base64InputStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of barcode4j Show documentation
Show all versions of barcode4j Show documentation
Barcode4J is a flexible generator for barcodes written in Java.
The newest version!
/*
* Copyright 2008 Jeremias Maerki.
*
* Licensed 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: Base64InputStream.java,v 1.1 2008/09/15 07:10:28 jmaerki Exp $ */
package org.krysalis.barcode4j.tools;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Arrays;
/**
* Base64-implementation as an {@code InputStream} reading Base64-encoded data
* from a {@code Reader}.
*/
public class Base64InputStream extends InputStream {
private static final int EOF = -1;
private static final byte[] LOOKUP = new byte[128];
static {
Arrays.fill(LOOKUP, (byte)-1);
int idx = 0;
for (char ch = 'A'; ch <= 'Z'; ch++) {
LOOKUP[ch] = (byte)idx++;
}
for (char ch = 'a'; ch <= 'z'; ch++) {
LOOKUP[ch] = (byte)idx++;
}
for (char ch = '0'; ch <= '9'; ch++) {
LOOKUP[ch] = (byte)idx++;
}
LOOKUP['-'] = (byte)idx; //URL- & filename-safe
LOOKUP['+'] = (byte)idx++;
LOOKUP['_'] = (byte)idx; //URL- & filename-safe
LOOKUP['/'] = (byte)idx++;
}
private Reader source;
private char[] quadBuffer = new char[4];
private byte[] triple = new byte[3];
private int tripleIndex = 4;
private int tripleFilled;
/**
* Constructs a new instance.
* @param source the Reader to read the Base64-encoded data from
*/
public Base64InputStream(Reader source) {
if (source == null) {
throw new NullPointerException("source must not be null");
}
this.source = source;
}
/** {@inheritDoc} */
public int read() throws IOException {
checkOpen();
if (tripleIndex >= tripleFilled) {
if (!readNextTriple()) {
return EOF;
}
}
return triple[tripleIndex++];
}
private boolean readNextTriple() throws IOException {
int offset = 0;
while (offset < 4) {
int ch = source.read();
if (ch < 0) {
return false;
} else if (ch == '\r' || ch == '\n' || ch == ' ') {
continue;
}
quadBuffer[offset++] = (char)ch;
}
int quad = 0;
tripleFilled = 3;
for (int i = 0; i < 4; i++) {
byte b = -1;
char ch = quadBuffer[i];
if ('=' == ch) {
if (i < 2) {
throw new IOException("Padding character at invalid position");
} else {
tripleFilled = Math.min(i - 1, tripleFilled);
break;
}
}
if (ch < 128) {
b = LOOKUP[ch];
}
if (b < 0) {
throw new IOException("Illegal Base64 character encountered: " + ch);
}
quad |= b << ((3 - i) * 6);
}
triple[0] = (byte)((quad & 0xFF0000) >> 16);
triple[1] = (byte)((quad & 0xFF00) >> 8);
triple[2] = (byte)(quad & 0xFF);
tripleIndex = 0;
return true;
}
private void checkOpen() throws IOException {
if (this.source == null) {
throw new IOException("Stream is already closed");
}
}
/** {@inheritDoc} */
public void close() throws IOException {
this.source.close();
this.source = null;
}
}