// Copyright 1996, Marimba Inc. All Rights Reserved.


// @(#)DecoderStream.java, 1.8, 10/30/96





package marimba.io;





import java.io.*;





/**


 * A simple stream to decode a base64-like stream into a


 * binary stream.


 *


 * @author Arthur van Hoff


 * @version 1.8, 10/30/96


 */


public class DecoderStream extends FilterInputStream {


    int value;


    int bits;





    /**


     * Constructor


     */


    public DecoderStream(InputStream in) {


	super(in);


    }





    /**


     * Read a character.


     */


    public int read() throws IOException {


	while (bits < 8) {


	    int ch = in.read();


	    if (ch < 0) {


		return -1;


	    }





	    value = (value << 6) | (ch - 32);


	    bits += 6;


	}





	bits -= 8;


	return (value >> bits) & 0xFF;


    }





    byte inbuf[];





    /**


     * Read a buffer


     */


    public int read(byte buf[], int off, int len) throws IOException {





	// How many new bytes do I have to read?


	// nbits that we need to read = len * 8 - bits


	// n bytes that we need to read = (nbits + 5) / 6;





	int bits = this.bits;


	byte inbuf[] = this.inbuf;


	int amnt = (((len * 8) - bits) + 5) / 6;


	if (inbuf == null || inbuf.length < amnt) {


	    inbuf = this.inbuf = new byte[amnt];


	}


	int n = in.read(inbuf, 0, amnt);


	if (n <= 0) {


	    return n;


	}





	int count = 0;


	int i = 0;


	int io = off;


	int value = this.value;


	while (i < n) {


	    while ((bits < 8) && (i < n)) {


		value = (value << 6) | ((inbuf[i++] & 0xFF) - 32);


		bits += 6;


	    }


	    if (bits >= 8) {


		bits -= 8;


		count += 1;


		buf[io++] = (byte)(value >> bits);


	    }


	}


	this.bits = bits;


	this.value = value;


	return (count == 0) ? read(buf, off, len) : count;


    }





    /**


     * How many character remain


     */


    public int available() throws IOException {


	return ((in.available() * 6) + bits + 7) / 8;


    }





    /**


     * Test program.


     */


    public static void main(String argv[]) {


	try {


	    FastInputStream in = new FastInputStream(argv[0]);


	    FastOutputStream out = new FastOutputStream();





	    byte buf[] = new byte[1024*4];


	    int n = in.read(buf, 0, buf.length);


	    while (n > 0) {


		out.write(buf, 0, n);


		n = in.read(buf, 0, buf.length);


	    }


	    in.close();





	    byte data[] = out.toByteArray();


	    byte newbuf[] = EncoderStream.encode(data, data.length);


	    out = new FastOutputStream(argv[1]);


	    out.write(newbuf, 0, newbuf.length);


	    out.close();





	    out = new FastOutputStream(argv[2]);


	    in = new FastInputStream(new DecoderStream(new FastInputStream(newbuf)));





	    n = in.read(buf, 0, buf.length);


	    while (n > 0) {


		out.write(buf, 0, n);


		n = in.read(buf, 0, buf.length);


	    }


	    out.close();


	    


	} catch (IOException e) {


	    e.printStackTrace();


	}


    }


}


