/* * Copyright 2007 T-Rank AS * * 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. */ package no.trank.openpipe.solr.analysis.io; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.io.StringReader; /** * @version $Revision$ */ public class Base64InputStream extends InputStream { private static final int[] B64_VALS = new int['z' + 1]; private static final int MASK = 0x3f; private final char[] buf = new char[4096]; private final Reader in; private int pos; private int size; private int off = 8; private int rest; private boolean eof; public Base64InputStream(Reader in) { this.in = in; } public Base64InputStream(String externalVal) { this(new StringReader(externalVal)); } @Override public int read() throws IOException { final boolean need2Bytes = off > 6; if (!fillBuffer(need2Bytes ? 2 : 1)) { return -1; } if (need2Bytes) { final int b = decode(buf[pos++]); if (eof) { return -1; } rest = b << 2; off = 2; } final int b = decode(buf[pos++]); if (eof) { return -1; } final int result = rest | (b >> (6 - off)); rest = ((b << off) & MASK) << 2; off += 2; return result; } private boolean fillBuffer(int wantedSize) throws IOException { if (eof) { return false; } if (pos + wantedSize > size) { if (pos < size) { size -= pos; System.arraycopy(buf, pos, buf, 0, size); } else { size = 0; } pos = 0; final int len = in.read(buf, pos, buf.length - size); if (len < 0 && size == 0) { size = -1; eof = true; } else { size += len; } } return pos + wantedSize <= size; } private int decode(int b) { if (b >= 0 && b < B64_VALS.length) { return B64_VALS[b]; } eof = true; return -1; } @Override public long skip(final long n) throws IOException { long skipped = 0; while (skipped < n && read() >= 0) { skipped++; } return skipped; } @Override public void close() throws IOException { in.close(); } static { for (int i = 0; i < B64_VALS.length; i++) { B64_VALS[i] = -1; } for (int i = 0; i < Base64OutputStream.B64_CHARS.length; i++) { B64_VALS[Base64OutputStream.B64_CHARS[i]] = i; } } }