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