001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.util;
020:
021: import java.io.IOException;
022: import java.io.InputStream;
023:
024: /**
025: * This class implements a Base64 Character decoder as specified in RFC1113.
026: * Unlike some other encoding schemes there is nothing in this encoding that
027: * tells the decoder where a buffer starts or stops, so to use it you will need
028: * to isolate your encoded data into a single chunk and then feed them
029: * this decoder. The simplest way to do that is to read all of the encoded
030: * data into a string and then use:
031: * <pre>
032: * byte data[];
033: * InputStream is = new ByteArrayInputStream(data);
034: * is = new Base64DecodeStream(is);
035: * </pre>
036: *
037: * On errors, this class throws a IOException with the following detail
038: * strings:
039: * <pre>
040: * "Base64DecodeStream: Bad Padding byte (2)."
041: * "Base64DecodeStream: Bad Padding byte (1)."
042: * </pre>
043: *
044: * @author <a href="mailto:thomas.deweese@kodak.com">Thomas DeWeese</a>
045: * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
046: * @author Chuck McManis
047: * @version $Id: Base64DecodeStream.java 501495 2007-01-30 18:00:36Z dvholten $
048: */
049: public class Base64DecodeStream extends InputStream {
050:
051: InputStream src;
052:
053: public Base64DecodeStream(InputStream src) {
054: this .src = src;
055: }
056:
057: private static final byte[] pem_array = new byte[256];
058:
059: static {
060: for (int i = 0; i < pem_array.length; i++)
061: pem_array[i] = -1;
062:
063: int idx = 0;
064: for (char c = 'A'; c <= 'Z'; c++) {
065: pem_array[c] = (byte) idx++;
066: }
067: for (char c = 'a'; c <= 'z'; c++) {
068: pem_array[c] = (byte) idx++;
069: }
070:
071: for (char c = '0'; c <= '9'; c++) {
072: pem_array[c] = (byte) idx++;
073: }
074:
075: pem_array['+'] = (byte) idx++;
076: pem_array['/'] = (byte) idx++;
077: }
078:
079: public boolean markSupported() {
080: return false;
081: }
082:
083: public void close() throws IOException {
084: EOF = true;
085: }
086:
087: public int available() throws IOException {
088: return 3 - out_offset;
089: }
090:
091: byte[] decode_buffer = new byte[4];
092: byte[] out_buffer = new byte[3];
093: int out_offset = 3;
094: boolean EOF = false;
095:
096: public int read() throws IOException {
097:
098: if (out_offset == 3) {
099: if (EOF || getNextAtom()) {
100: EOF = true;
101: return -1;
102: }
103: }
104:
105: return ((int) out_buffer[out_offset++]) & 0xFF;
106: }
107:
108: public int read(byte[] out, int offset, int len) throws IOException {
109:
110: int idx = 0;
111: while (idx < len) {
112: if (out_offset == 3) {
113: if (EOF || getNextAtom()) {
114: EOF = true;
115: if (idx == 0)
116: return -1;
117: else
118: return idx;
119: }
120: }
121:
122: out[offset + idx] = out_buffer[out_offset++];
123:
124: idx++;
125: }
126: return idx;
127: }
128:
129: final boolean getNextAtom() throws IOException {
130: int count, a, b, c, d;
131:
132: int off = 0;
133: while (off != 4) {
134: count = src.read(decode_buffer, off, 4 - off);
135: if (count == -1)
136: return true;
137:
138: int in = off, out = off;
139: while (in < off + count) {
140: if ((decode_buffer[in] != '\n')
141: && (decode_buffer[in] != '\r')
142: && (decode_buffer[in] != ' '))
143: decode_buffer[out++] = decode_buffer[in];
144: in++;
145: }
146:
147: off = out;
148: }
149:
150: a = pem_array[((int) decode_buffer[0]) & 0xFF];
151: b = pem_array[((int) decode_buffer[1]) & 0xFF];
152: c = pem_array[((int) decode_buffer[2]) & 0xFF];
153: d = pem_array[((int) decode_buffer[3]) & 0xFF];
154:
155: out_buffer[0] = (byte) ((a << 2) | (b >>> 4));
156: out_buffer[1] = (byte) ((b << 4) | (c >>> 2));
157: out_buffer[2] = (byte) ((c << 6) | d);
158:
159: if (decode_buffer[3] != '=') {
160: // All three bytes are good.
161: out_offset = 0;
162: } else if (decode_buffer[2] == '=') {
163: // Only one byte of output.
164: out_buffer[2] = out_buffer[0];
165: out_offset = 2;
166: EOF = true;
167: } else {
168: // Only two bytes of output.
169: out_buffer[2] = out_buffer[1];
170: out_buffer[1] = out_buffer[0];
171: out_offset = 1;
172: EOF = true;
173: }
174:
175: return false;
176: }
177: }
|