
package heasarc.db.votable;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileReader;

/**
 * This class decodes a Base64 encoded string.
 * Taken from Xamin colde.
 * @author tmcglynn
 */
public class Base64 {


    ByteArrayOutputStream bi = new ByteArrayOutputStream();

    /** Build up the string that will be decoded. */
    public void append(String input) {
        if (input == null) {
            return;
        }
        for (int i=0; i<input.length(); i += 1) {
            char c = input.charAt(i);
            if (c >= 'A' && c <= 'Z' ) {
                bi.write((byte)(c-'A'));
            } else if (c >= 'a' && c <= 'z') {
                bi.write((byte)(c-'a' + 26));
            } else if (c >= '0'  && c <= '9') {
                bi.write((byte)(c-'0'+52));
            } else if (c == '+') {
                bi.write((byte) 62);
            } else if (c == '/') {
                bi.write((byte) 63);
            } else if (c == '=') {
                bi.write(-1);
            }
        }
    }

    /** Return an InputStream to the decoded data */
    public ByteArrayInputStream getAsStream() {
        return new ByteArrayInputStream(translate());
    }

    /** Translate the encoded stream to a byte array */
    public byte[] translate() {
        while (bi.size() % 4 != 0) {
            bi.write('=');
        }
        byte[] b = bi.toByteArray();

        int last = 0;
        if (b.length > 0) {
            for (int i= b.length-1; i>0; i-= 1) {
                if (b[i] == -1) {
                    last += 1;
                } else {
                    break;
                }
            }
        }

        if (last > 2) {
            System.err.println("Too many = at end");
            return null;
        }
        int threes = (b.length / 4);

        byte[] out = new byte[3*threes - last];
        for (int i=0; i<threes; i += 1) {
            if (i == threes-1) {
                handleGroup(b, out, i, last);
            } else {
                handleGroup(b, out, i, 0);
            }
        }
        return out;
    }

    /** Handle each group of 4 input bytes.  The encoding encodes
     *  six bits in each character so we get three bytes out for each
     *  four bytes in.  The last group may have fewer output bytes.
     */
    void handleGroup(byte[] in, byte[] out, int i, int last) {
        int x = 0;

        // Skip process of 'last' pixels.
        for (int j=0; j<4-last; j += 1) {
            x = 64*x + in[4*i+j];
        }
        // Add in shifts that we missed because we didn't process 'last' bytes.
        x = x<<(6*last);

        // Only get 3-last output bytes
        for (int j=0; j<3-last; j += 1) {
            int shift = 8*(2-j);
            out[3*i + j]   = (byte)((x >> shift)&0xFF);
        }
    }

    public static void main(String[] args) throws Exception {

        BufferedReader rdr = new BufferedReader(new FileReader(args[0]));
        Base64 b = new Base64();
        String line;
        while ((line=rdr.readLine()) != null) {
            b.append(line);
        }
        byte[] result = b.translate();
        for (int i=0; i<result.length; i += 1) {
            System.out.print(i+": "+result[i]);
            if (result[i] >= 32 && result[i] < 127) {
                System.out.print(", "+(char)result[i]);
            }
            System.out.println();
        }
    }
}
