Mega Code Archive

 
Categories / Java / File Input Output
 

Decode a BASE64 encoded input stream to some output stream

/*  * Copyright Â© World Wide Web Consortium, (Massachusetts Institute of Technology,   * Institut National de Recherche en Informatique et en Automatique, Keio University).  * All Rights Reserved. http://www.w3.org/Consortium/Legal/  */ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; /**  * Decode a BASE64 encoded input stream to some output stream.  * This class implements BASE64 decoding, as specified in the  * <a href="http://ds.internic.net/rfc/rfc1521.txt">MIME specification</a>.  * @see org.w3c.tools.codec.Base64Encoder  */ public class Base64Decoder {   private static final int BUFFER_SIZE = 1024;   InputStream in = null;   OutputStream out = null;   boolean stringp = false;   private void printHex(int x)   {     int h = (x & 0xf0) >> 4;     int l = (x & 0x0f);     System.out.print(       (new Character((char) ((h > 9) ? 'A' + h - 10 : '0' + h)))         .toString()         + (new Character((char) ((l > 9) ? 'A' + l - 10 : '0' + l)))           .toString());   }   private void printHex(byte buf[], int off, int len)   {     while (off < len)     {       printHex(buf[off++]);       System.out.print(" ");     }     System.out.println("");   }   private void printHex(String s)   {     byte bytes[];     try     {       bytes = s.getBytes("ISO-8859-1");     }     catch (UnsupportedEncodingException ex)     {       throw new RuntimeException(         this.getClass().getName()           + "[printHex] Unable to convert"           + "properly char to bytes");     }     printHex(bytes, 0, bytes.length);   }   private final int get1(byte buf[], int off)   {     return ((buf[off] & 0x3f) << 2) | ((buf[off + 1] & 0x30) >>> 4);   }   private final int get2(byte buf[], int off)   {     return ((buf[off + 1] & 0x0f) << 4) | ((buf[off + 2] & 0x3c) >>> 2);   }   private final int get3(byte buf[], int off)   {     return ((buf[off + 2] & 0x03) << 6) | (buf[off + 3] & 0x3f);   }   private final int check(int ch)   {     if ((ch >= 'A') && (ch <= 'Z'))     {       return ch - 'A';     }     else if ((ch >= 'a') && (ch <= 'z'))     {       return ch - 'a' + 26;     }     else if ((ch >= '0') && (ch <= '9'))     {       return ch - '0' + 52;     }     else     {       switch (ch)       {         case '=' :           return 65;         case '+' :           return 62;         case '/' :           return 63;         default :           return -1;       }     }   }   /**    * Do the actual decoding.    * Process the input stream by decoding it and emiting the resulting bytes    * into the output stream.    * @exception IOException If the input or output stream accesses failed.    * @exception Base64FormatException If the input stream is not compliant    *    with the BASE64 specification.    */   public void process() throws IOException, Exception   {     byte buffer[] = new byte[BUFFER_SIZE];     byte chunk[] = new byte[4];     int got = -1;     int ready = 0;     fill : while ((got = in.read(buffer)) > 0)     {       int skiped = 0;       while (skiped < got)       {         // Check for un-understood characters:         while (ready < 4)         {           if (skiped >= got)             continue fill;           int ch = check(buffer[skiped++]);           if (ch >= 0)             chunk[ready++] = (byte) ch;         }         if (chunk[2] == 65)         {           out.write(get1(chunk, 0));           return;         }         else if (chunk[3] == 65)         {           out.write(get1(chunk, 0));           out.write(get2(chunk, 0));           return;         }         else         {           out.write(get1(chunk, 0));           out.write(get2(chunk, 0));           out.write(get3(chunk, 0));         }         ready = 0;       }     }     if (ready != 0)       throw new Exception("Invalid length.");     out.flush();   }   /**    * Do the decoding, and return a String.    * This methods should be called when the decoder is used in    * <em>String</em> mode. It decodes the input string to an output string    * that is returned.    * @exception RuntimeException If the object wasn't constructed to    *    decode a String.    * @exception Base64FormatException If the input string is not compliant     *     with the BASE64 specification.    */   public String processString() throws Exception   {     if (!stringp)       throw new RuntimeException(         this.getClass().getName()           + "[processString]"           + "invalid call (not a String)");     try     {       process();     }     catch (IOException e)     {     }     String s;     try     {       s = ((ByteArrayOutputStream) out).toString("ISO-8859-1");     }     catch (UnsupportedEncodingException ex)     {       throw new RuntimeException(         this.getClass().getName()           + "[processString] Unable to convert"           + "properly char to bytes");     }     return s;   }   /**    * Create a decoder to decode a String.    * @param input The string to be decoded.    */   public Base64Decoder(String input)   {     byte bytes[];     try     {       bytes = input.getBytes("ISO-8859-1");     }     catch (UnsupportedEncodingException ex)     {       throw new RuntimeException(         this.getClass().getName()           + "[Constructor] Unable to convert"           + "properly char to bytes");     }     this.stringp = true;     this.in = new ByteArrayInputStream(bytes);     this.out = new ByteArrayOutputStream();   }   /**    * Create a decoder to decode a stream.    * @param in The input stream (to be decoded).    * @param out The output stream, to write decoded data to.    */   public Base64Decoder(InputStream in, OutputStream out)   {     this.in = in;     this.out = out;     this.stringp = false;   }   /**    * Test the decoder.    * Run it with one argument: the string to be decoded, it will print out    * the decoded value.    */   public static void main(String args[])   {     if (args.length == 1)     {       try       {         Base64Decoder b = new Base64Decoder(args[0]);         System.out.println("[" + b.processString() + "]");       }       catch (Exception e)       {         System.out.println("Invalid Base64 format !");         System.exit(1);       }     }     else if ((args.length == 2) && (args[0].equals("-f")))     {       try       {         FileInputStream in = new FileInputStream(args[1]);         Base64Decoder b = new Base64Decoder(in, System.out);         b.process();       }       catch (Exception ex)       {         System.out.println("error: " + ex.getMessage());         System.exit(1);       }     }     else     {       System.out.println("Base64Decoder [strong] [-f file]");     }     System.exit(0);   } }