栗原です。
えっと、続きです。
BASE64 のエンコーダー/デコーダーを Java のストリームクラス
で利用されている Decorator パターンに変更したものです。
オーバーライドし忘れているメソッドがいくつかありますが、
暫定ということで、ご了承を。
#フリーのやつとかがありそうなんですが、、、
/*
* $Id$
*/
package jp.co.esm.wiki.extremedomo.util;
public abstract interface Base64 {
public static final char PAD_CHAR = '=';
public static final char[] encoding_array = {
'A','B','C','D','E','F','G','H', // 0-7
'I','J','K','L','M','N','O','P', // 8-15
'Q','R','S','T','U','V','W','X', // 16-23
'Y','Z','a','b','c','d','e','f', // 24-31
'g','h','i','j','k','l','m','n', // 32-39
'o','p','q','r','s','t','u','v', // 40-47
'w','x','y','z','0','1','2','3', // 48-55
'4','5','6','7','8','9','+','/' // 56-63
};
}
/*
* $Id$
*/
package jp.co.esm.wiki.extremedomo.util;
import java.io.*;
public class Base64EncoderStream
extends FilterOutputStream implements Base64 {
public Base64EncoderStream(OutputStream out) {
super(out);
}
public void write(byte[] b)
throws IOException {
write(b, 0, b.length);
}
public void write(byte[] b, int off, int len)
throws IOException {
for (int i = 0; i < len; i++)
write(b[off + i]);
}
public void write(int b)
throws IOException {
buffer[bufSize] = (byte)b;
bufSize++;
if (bufSize == 3) {
encode();
bufSize = 0;
}
}
public void flush()
throws IOException {
if (bufSize > 0) {
encode();
bufSize = 0;
}
out.flush();
}
public void close()
throws IOException {
flush();
out.close();
}
private void encode()
throws IOException {
switch (bufSize) {
case 1:
out.write(getEncoded1());
out.write(getEncoded2());
out.write(PAD_CHAR);
out.write(PAD_CHAR);
return;
case 2:
out.write(getEncoded1());
out.write(getEncoded2());
out.write(getEncoded3());
out.write(PAD_CHAR);
return;
case 3:
out.write(getEncoded1());
out.write(getEncoded2());
out.write(getEncoded3());
out.write(getEncoded4());
return;
default:
throw new IllegalStateException(
"invalid state. " + "[bufSize: " + bufSize + "]");
}
}
private char getEncoded1() {
return encoding_array[(buffer[0] & 0xfc) >> 2];
}
private char getEncoded2() {
return encoding_array[
((buffer[0] & 0x3) << 4) | ((buffer[1] & 0xf0) >>> 4)];
}
private char getEncoded3() {
return encoding_array[
((buffer[1] & 0xf) << 2) | ((buffer[2] & 0xc0) >>> 6)];
}
private char getEncoded4() {
return encoding_array[buffer[2] & 0x3f];
}
private byte[] buffer = new byte[3];
private int bufSize = 0;
public static void main(String argv[]) throws Exception {
ByteArrayInputStream in =
new ByteArrayInputStream("abcdefg".getBytes());
Base64EncoderStream encoder = new
Base64EncoderStream(System.out);
int c;
while ((c = in.read()) != -1)
encoder.write(c);
encoder.close();
}
}
/*
* $Id$
*/
package jp.co.esm.wiki.extremedomo.util;
import java.io.*;
public class Base64DecoderStream
extends FilterInputStream implements Base64 {
public Base64DecoderStream(InputStream in) {
super(in);
}
public int read()
throws IOException {
int result = -1;
if (index >= bufSize) {
decode();
if (bufSize == 0)
return -1;
index = 0;
}
result = buffer[index];
index++;
return result;
}
public int read(byte[] b)
throws IOException {
return read(b, 0, b.length);
}
public int read(byte[] b, int off, int len)
throws IOException {
int result = -1;
for (int i = 0; i < len; i++) {
int c = read();
if (c == -1)
break;
b[off + i] = (byte)c;
result = i;
}
return result;
}
private void decode()
throws IOException {
bufSize = 0;
byte[] chunk = new byte[4];
while (true) {
int c = in.read();
if (c == -1)
return;
if (c != '\r' && c != '\n') {
chunk[0] = (byte)c;
break;
}
}
int off = 1;
int ready = 3;
while (true) {
int len = in.read(chunk, off, ready);
if (len == ready)
break;
if (len == -1)
throw new IOException("invalid stream length.");
ready -= len;
off += len;
}
byte[] converted = convertOnEncodeArray(chunk);
buffer[bufSize] = getDecoded1(converted);
bufSize++;
if (chunk[2] == PAD_CHAR
|| converted[2] == OUTSIDE_OF_THE_RANGE)
return;
buffer[bufSize] = getDecoded2(converted);
bufSize++;
if (chunk[3] == PAD_CHAR
|| converted[3] == OUTSIDE_OF_THE_RANGE)
return;
buffer[bufSize] = getDecoded3(converted);
bufSize++;
}
private final byte[] convertOnEncodeArray(byte[] original) {
byte[] result = new byte[4];
result[0] = convert_array[original[0]];
result[1] = convert_array[original[1]];
result[2] = convert_array[original[2]];
result[3] = convert_array[original[3]];
return result;
}
private byte getDecoded1(byte buf[]) {
return (byte)(((buf[0] & 0x3f) << 2) | ((buf[1] & 0x30) >>>
4));
}
private byte getDecoded2(byte buf[]) {
return (byte)(((buf[1] & 0xf) << 4) | ((buf[2] &0x3c) >>> 2));
}
private byte getDecoded3(byte buf[]) {
return (byte)(((buf[2] & 0x3) << 6) | (buf[3] & 0x3f));
}
private static final byte OUTSIDE_OF_THE_RANGE = -1;
private static final byte[] convert_array = new byte[256];
static {
for (int i = 0; i < 256; i++)
convert_array[i] = OUTSIDE_OF_THE_RANGE;
for (int i = 0; i < encoding_array.length; i++)
convert_array[encoding_array[i]] = (byte)i;
}
private byte[] buffer = new byte[4];
private int bufSize = 0;
private int index = 0;
public static void main(String argv[]) throws Exception {
ByteArrayInputStream in =
new
ByteArrayInputStream("GyRCJD0kbCRPOiNJLE1XJEokYiROJEckOSQrISkbKEI=".getBytes
());
Base64DecoderStream decoder = new Base64DecoderStream(in);
byte[] buff = new byte[256];
int readLen = decoder.read(buff);
System.out.println("len:" + readLen + " " + new String(buff,
"iso-2022-jp"));
}
}
---
Tetsuya Kurihara
tetsuya@....jp