VERSION
[nikiroo-utils.git] / src / be / nikiroo / utils / Base64.java
index f123b322b225b869ee19a878c927a6591233b327..784fc929aef19b9f51c3dcb9f891cb9bb59e3122 100644 (file)
@@ -1,5 +1,7 @@
 package be.nikiroo.utils;
 
+import java.io.IOException;
+
 /**
  * <p>Encodes and decodes to and from Base64 notation.</p>
  * <p>Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.</p>
@@ -208,7 +210,7 @@ class Base64
     
     
     /** Preferred encoding. */
-    private final static String PREFERRED_ENCODING = "US-ASCII";
+    private final static String PREFERRED_ENCODING = "UTF-8";
     
        
     private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
@@ -934,62 +936,58 @@ class Base64
         }   // end if: compress
 
         // Else, don't compress. Better not to use streams at all then.
-        else {
-            boolean breakLines = (options & DO_BREAK_LINES) != 0;
-
-            //int    len43   = len * 4 / 3;
-            //byte[] outBuff = new byte[   ( len43 )                      // Main 4:3
-            //                           + ( (len % 3) > 0 ? 4 : 0 )      // Account for padding
-            //                           + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines
-            // Try to determine more precisely how big the array needs to be.
-            // If we get it right, we don't have to do an array copy, and
-            // we save a bunch of memory.
-            int encLen = ( len / 3 ) * 4 + ( len % 3 > 0 ? 4 : 0 ); // Bytes needed for actual encoding
-            if( breakLines ){
-                encLen += encLen / MAX_LINE_LENGTH; // Plus extra newline characters
-            }
-            byte[] outBuff = new byte[ encLen ];
+        boolean breakLines = (options & DO_BREAK_LINES) != 0;
+
+        //int    len43   = len * 4 / 3;
+        //byte[] outBuff = new byte[   ( len43 )                      // Main 4:3
+        //                           + ( (len % 3) > 0 ? 4 : 0 )      // Account for padding
+        //                           + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines
+        // Try to determine more precisely how big the array needs to be.
+        // If we get it right, we don't have to do an array copy, and
+        // we save a bunch of memory.
+        int encLen = ( len / 3 ) * 4 + ( len % 3 > 0 ? 4 : 0 ); // Bytes needed for actual encoding
+        if( breakLines ){
+            encLen += encLen / MAX_LINE_LENGTH; // Plus extra newline characters
+        }
+        byte[] outBuff = new byte[ encLen ];
 
 
-            int d = 0;
-            int e = 0;
-            int len2 = len - 2;
-            int lineLength = 0;
-            for( ; d < len2; d+=3, e+=4 ) {
-                encode3to4( source, d+off, 3, outBuff, e, options );
+        int d = 0;
+        int e = 0;
+        int len2 = len - 2;
+        int lineLength = 0;
+        for( ; d < len2; d+=3, e+=4 ) {
+            encode3to4( source, d+off, 3, outBuff, e, options );
 
-                lineLength += 4;
-                if( breakLines && lineLength >= MAX_LINE_LENGTH )
-                {
-                    outBuff[e+4] = NEW_LINE;
-                    e++;
-                    lineLength = 0;
-                }   // end if: end of line
-            }   // en dfor: each piece of array
-
-            if( d < len ) {
-                encode3to4( source, d+off, len - d, outBuff, e, options );
-                e += 4;
-            }   // end if: some padding needed
-
-
-            // Only resize array if we didn't guess it right.
-            if( e <= outBuff.length - 1 ){
-                // If breaking lines and the last byte falls right at
-                // the line length (76 bytes per line), there will be
-                // one extra byte, and the array will need to be resized.
-                // Not too bad of an estimate on array size, I'd say.
-                byte[] finalOut = new byte[e];
-                System.arraycopy(outBuff,0, finalOut,0,e);
-                //System.err.println("Having to resize array from " + outBuff.length + " to " + e );
-                return finalOut;
-            } else {
-                //System.err.println("No need to resize array.");
-                return outBuff;
-            }
+            lineLength += 4;
+            if( breakLines && lineLength >= MAX_LINE_LENGTH )
+            {
+                outBuff[e+4] = NEW_LINE;
+                e++;
+                lineLength = 0;
+            }   // end if: end of line
+        }   // en dfor: each piece of array
+
+        if( d < len ) {
+            encode3to4( source, d+off, len - d, outBuff, e, options );
+            e += 4;
+        }   // end if: some padding needed
+
+
+        // Only resize array if we didn't guess it right.
+        if( e <= outBuff.length - 1 ){
+            // If breaking lines and the last byte falls right at
+            // the line length (76 bytes per line), there will be
+            // one extra byte, and the array will need to be resized.
+            // Not too bad of an estimate on array size, I'd say.
+            byte[] finalOut = new byte[e];
+            System.arraycopy(outBuff,0, finalOut,0,e);
+            //System.err.println("Having to resize array from " + outBuff.length + " to " + e );
+            return finalOut;
+        }
         
-        }   // end else: don't compress
-
+        //System.err.println("No need to resize array.");
+        return outBuff;
     }   // end encodeBytesToBytes
     
 
@@ -1145,7 +1143,8 @@ class Base64
      * @throws java.io.IOException If bogus characters exist in source data
      * @since 1.3
      */
-    public static byte[] decode( byte[] source, int off, int len, int options )
+    @SuppressWarnings("cast")
+       public static byte[] decode( byte[] source, int off, int len, int options )
     throws java.io.IOException {
         
         // Lots of error checking and exception throwing
@@ -1252,15 +1251,32 @@ class Base64
         }   // end catch
                //</change>
         
+        return niki_decode(bytes, 0, bytes.length, options);
+    }
+     
+    /**
+     * Decodes data from Base64 notation, automatically
+     * detecting gzip-compressed data and decompressing it.
+     *
+     * @param s the string to decode
+     * @param options encode options such as URL_SAFE
+     * @return the decoded data
+     * @throws java.io.IOException if there is an error
+     * @throws NullPointerException if <tt>s</tt> is null
+     * @since niki
+     */
+    public static byte[] niki_decode( byte[] bytes, int offset, int count, int options ) throws java.io.IOException {
+        
         // Decode
-        bytes = decode( bytes, 0, bytes.length, options );
+        bytes = decode( bytes, offset, count, options );
         
         // Check to see if it's gzip-compressed
         // GZIP Magic Two-Byte Number: 0x8b1f (35615)
         boolean dontGunzip = (options & DONT_GUNZIP) != 0;
         if( (bytes != null) && (bytes.length >= 4) && (!dontGunzip) ) {
             
-            int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
+            @SuppressWarnings("cast")
+                       int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
             if( java.util.zip.GZIPInputStream.GZIP_MAGIC == head )  {
                 java.io.ByteArrayInputStream  bais = null;
                 java.util.zip.GZIPInputStream gzis = null;
@@ -1359,12 +1375,12 @@ class Base64
                     @Override
                     public Class<?> resolveClass(java.io.ObjectStreamClass streamClass)
                     throws java.io.IOException, ClassNotFoundException {
-                        Class c = Class.forName(streamClass.getName(), false, loader);
+                        @SuppressWarnings("rawtypes")
+                                               Class c = Class.forName(streamClass.getName(), false, loader);
                         if( c == null ){
                             return super.resolveClass(streamClass);
-                        } else {
-                            return c;   // Class loader knows of this class.
-                        }   // end else: not null
+                        }
+                        return c;   // Class loader knows of this class.
                     }   // end resolveClass
                 };  // end ois
             }   // end else: no custom class loader
@@ -1776,26 +1792,21 @@ class Base64
                     lineLength = 0;
                     return '\n';
                 }   // end if
-                else {
-                    lineLength++;   // This isn't important when decoding
-                                    // but throwing an extra "if" seems
-                                    // just as wasteful.
-                    
-                    int b = buffer[ position++ ];
+                lineLength++;   // This isn't important when decoding
+                                // but throwing an extra "if" seems
+                                // just as wasteful.
+                
+                int b = buffer[ position++ ];
 
-                    if( position >= bufferLength ) {
-                        position = -1;
-                    }   // end if: end
+                if( position >= bufferLength ) {
+                    position = -1;
+                }   // end if: end
 
-                    return b & 0xFF; // This is how you "cast" a byte that's
-                                     // intended to be unsigned.
-                }   // end else
+                return b & 0xFF; // This is how you "cast" a byte that's
+                                 // intended to be unsigned.
             }   // end if: position >= 0
             
-            // Else error
-            else {
-                throw new java.io.IOException( "Error in Base64 code reading stream." );
-            }   // end else
+            throw new java.io.IOException( "Error in Base64 code reading stream." );
         }   // end read
         
         
@@ -2020,7 +2031,9 @@ class Base64
         @Override
         public void close() throws java.io.IOException {
             // 1. Ensure that pending characters are written
-            flushBase64();
+            
+               // niki: removed since it is now in flush()
+               //flushBase64();
 
             // 2. Actually close the stream
             // Base class both flushes and closes.
@@ -2057,7 +2070,12 @@ class Base64
             this.suspendEncoding = false;
         }   // end resumeEncoding
         
-        
+        @Override
+        // added by niki
+        public void flush() throws IOException {
+               flushBase64();
+               super.flush();
+        }
         
     }   // end inner class OutputStream