Version 4.5.0
authorNiki Roo <niki@nikiroo.be>
Sun, 3 Mar 2019 15:51:34 +0000 (16:51 +0100)
committerNiki Roo <niki@nikiroo.be>
Sun, 3 Mar 2019 15:51:34 +0000 (16:51 +0100)
VERSION
changelog.md
src/be/nikiroo/utils/StringUtils.java
src/be/nikiroo/utils/serial/Exporter.java
src/be/nikiroo/utils/serial/Importer.java
src/be/nikiroo/utils/serial/SerialUtils.java
src/be/nikiroo/utils/serial/server/ConnectAction.java
src/be/nikiroo/utils/serial/server/ServerBridge.java
src/be/nikiroo/utils/test/StringUtilsTest.java

diff --git a/VERSION b/VERSION
index fa1ba0458a1510feff742c365f6f4097fc92bf24..a84947d6ffe7bdf361dfd679a8e931b44f0e9001 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-4.4.5
+4.5.0
index 085898e37f065bfc2dcadce8581113ede917528e..643d0b1f3305107fdf650dde6943ae0e0bbca493 100644 (file)
@@ -1,5 +1,11 @@
 # nikiroo-utils
 
+## Version 4.5.0
+
+- Base64: allow access to streams
+- Deprecated: do not use our on deprecated functions
+- Serial: fix ZIP/noZIP error
+
 ## Version 4.4.5
 
 - Base64: allow access to not-zipped Base64 utilities
index 79bccec76f26ba9148c3b7658e219e863ec7ac65..1884c21ff47a98fce6864c0c6a7c801727f0cb05 100644 (file)
@@ -2,6 +2,8 @@ package be.nikiroo.utils;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
@@ -523,7 +525,7 @@ public class StringUtils {
        @Deprecated
        public static String zip64(String data) {
                try {
-                       return Base64.encodeBytes(data.getBytes(), Base64.GZIP);
+                       return Base64.encodeBytes(data.getBytes("UTF-8"), Base64.GZIP);
                } catch (IOException e) {
                        e.printStackTrace();
                        return null;
@@ -558,6 +560,25 @@ public class StringUtils {
                }
        }
 
+       /**
+        * Convert the given data to Base64 format.
+        * 
+        * @param data
+        *            the data to convert
+        * @param zip
+        *            TRUE to also compress the data in GZIP format; remember that
+        *            compressed and not-compressed content are different; you need
+        *            to know which is which when decoding
+        * 
+        * @return the Base64 {@link String} representation of the data
+        * 
+        * @throws IOException
+        *             in case of I/O errors
+        */
+       public static String base64(String data, boolean zip) throws IOException {
+               return base64(data.getBytes("UTF-8"), zip);
+       }
+
        /**
         * Convert the given data to Base64 format.
         * 
@@ -578,7 +599,64 @@ public class StringUtils {
        }
 
        /**
-        * Unonvert the given data from Base64 format back to a raw array of bytes.
+        * Convert the given data to Base64 format.
+        * 
+        * @param data
+        *            the data to convert
+        * @param zip
+        *            TRUE to also uncompress the data from a GZIP format; take care
+        *            about this flag, as it could easily cause errors in the
+        *            returned content or an {@link IOException}
+        * @param breakLines
+        *            TRUE to break lines on every 76th character
+        * 
+        * @return the Base64 {@link String} representation of the data
+        * 
+        * @throws IOException
+        *             in case of I/O errors
+        */
+       public static OutputStream base64(OutputStream data, boolean zip,
+                       boolean breakLines) throws IOException {
+               OutputStream out = new Base64.OutputStream(data,
+                               breakLines ? Base64.DO_BREAK_LINES & Base64.ENCODE
+                                               : Base64.ENCODE);
+
+               if (zip) {
+                       out = new java.util.zip.GZIPOutputStream(out);
+               }
+
+               return out;
+       }
+
+       /**
+        * Convert the given data to Base64 format.
+        * 
+        * @param data
+        *            the data to convert
+        * @param zip
+        *            TRUE to also uncompress the data from a GZIP format; take care
+        *            about this flag, as it could easily cause errors in the
+        *            returned content or an {@link IOException}
+        * @param breakLines
+        *            TRUE to break lines on every 76th character
+        * 
+        * @return the Base64 {@link String} representation of the data
+        * 
+        * @throws IOException
+        *             in case of I/O errors
+        */
+       public static InputStream base64(InputStream data, boolean zip,
+                       boolean breakLines) throws IOException {
+               if (zip) {
+                       data = new java.util.zip.GZIPInputStream(data);
+               }
+
+               return new Base64.InputStream(data, breakLines ? Base64.DO_BREAK_LINES
+                               & Base64.ENCODE : Base64.ENCODE);
+       }
+
+       /**
+        * Unconvert the given data from Base64 format back to a raw array of bytes.
         * 
         * @param data
         *            the data to unconvert
@@ -597,6 +675,63 @@ public class StringUtils {
                return Base64.decode(data, zip ? Base64.GZIP : Base64.NO_OPTIONS);
        }
 
+       /**
+        * Unconvert the given data from Base64 format back to a raw array of bytes.
+        * 
+        * @param data
+        *            the data to unconvert
+        * @param zip
+        *            TRUE to also uncompress the data from a GZIP format; take care
+        *            about this flag, as it could easily cause errors in the
+        *            returned content or an {@link IOException}
+        * @param breakLines
+        *            TRUE to break lines on every 76th character
+        * 
+        * @return the raw data represented by the given Base64 {@link String}
+        * 
+        * @throws IOException
+        *             in case of I/O errors
+        */
+       public static OutputStream unbase64(OutputStream data, boolean zip,
+                       boolean breakLines) throws IOException {
+               OutputStream out = new Base64.OutputStream(data,
+                               breakLines ? Base64.DO_BREAK_LINES & Base64.ENCODE
+                                               : Base64.ENCODE);
+
+               if (zip) {
+                       out = new java.util.zip.GZIPOutputStream(out);
+               }
+
+               return out;
+       }
+
+       /**
+        * Unconvert the given data from Base64 format back to a raw array of bytes.
+        * 
+        * @param data
+        *            the data to unconvert
+        * @param zip
+        *            TRUE to also uncompress the data from a GZIP format; take care
+        *            about this flag, as it could easily cause errors in the
+        *            returned content or an {@link IOException}
+        * @param breakLines
+        *            TRUE to break lines on every 76th character
+        * 
+        * @return the raw data represented by the given Base64 {@link String}
+        * 
+        * @throws IOException
+        *             in case of I/O errors
+        */
+       public static InputStream unbase64(InputStream data, boolean zip,
+                       boolean breakLines) throws IOException {
+               if (zip) {
+                       data = new java.util.zip.GZIPInputStream(data);
+               }
+
+               return new Base64.InputStream(data, breakLines ? Base64.DO_BREAK_LINES
+                               & Base64.ENCODE : Base64.ENCODE);
+       }
+
        /**
         * Unonvert the given data from Base64 format back to a {@link String}.
         * 
@@ -616,7 +751,7 @@ public class StringUtils {
        public static String unbase64s(String data, boolean zip) throws IOException {
                ByteArrayInputStream in = new ByteArrayInputStream(unbase64(data, zip));
 
-               Scanner scan = new Scanner(in);
+               Scanner scan = new Scanner(in, "UTF-8");
                scan.useDelimiter("\\A");
                try {
                        return scan.next();
index 3a6e025739c9faf0893fa2a65f07970012ae8f0e..d5f3a5fdc72e47219f3a70a0fb15c0480bf72045 100644 (file)
@@ -1,5 +1,6 @@
 package be.nikiroo.utils.serial;
 
+import java.io.IOException;
 import java.io.NotSerializableException;
 import java.util.HashMap;
 import java.util.Map;
@@ -55,37 +56,84 @@ public class Exporter {
                map.clear();
        }
 
+       /**
+        * Append the exported items in a serialised form into the given
+        * {@link StringBuilder}.
+        * 
+        * @param toBuilder
+        *            the {@link StringBuilder}
+        * @param b64
+        *            TRUE to have BASE64-coded content, FALSE to have raw content,
+        *            NULL to let the system decide
+        * @param zip
+        *            TRUE to zip the BASE64 output if the output is indeed in
+        *            BASE64 format, FALSE not to
+        */
+       public void appendTo(StringBuilder toBuilder, Boolean b64, boolean zip) {
+               if (b64 == null && builder.length() < 128) {
+                       b64 = false;
+               }
+
+               if (b64 != null || b64) {
+                       try {
+                               String zipped = StringUtils.base64(builder.toString(), zip);
+                               if (b64 != null || zipped.length() < builder.length() - 4) {
+                                       toBuilder.append(zip ? "ZIP:" : "B64:");
+                                       toBuilder.append(zipped);
+                                       return;
+                               }
+                       } catch (IOException e) {
+                               throw new RuntimeException(
+                                               "Base64 conversion of data failed, maybe not enough memory?",
+                                               e);
+                       }
+               }
+
+               toBuilder.append(builder);
+       }
+
        /**
         * The exported items in a serialised form.
         * 
+        * @deprecated use {@link Exporter#toString(Boolean, boolean)} instead
+        * 
         * @param zip
         *            TRUE to have zipped (and BASE64-coded) content, FALSE to have
         *            raw content, NULL to let the system decide
         * 
         * @return the items currently in this {@link Exporter}
         */
+       @Deprecated
        public String toString(Boolean zip) {
-               if (zip == null && builder.length() > 128) {
-                       zip = false;
-               }
-
-               if (zip == null || zip) {
-                       String zipped = "ZIP:" + StringUtils.zip64(builder.toString());
-
-                       if (zip != null || builder.length() < zipped.length())
-                               return zipped;
-               }
+               return toString(zip, zip == null || zip);
+       }
 
-               return builder.toString();
+       /**
+        * The exported items in a serialised form.
+        * 
+        * @param b64
+        *            TRUE to have BASE64-coded content, FALSE to have raw content,
+        *            NULL to let the system decide
+        * @param zip
+        *            TRUE to zip the BASE64 output if the output is indeed in
+        *            BASE64 format, FALSE not to
+        * 
+        * @return the items currently in this {@link Exporter}
+        */
+       public String toString(Boolean b64, boolean zip) {
+               StringBuilder toBuilder = new StringBuilder();
+               appendTo(toBuilder, b64, zip);
+               return toBuilder.toString();
        }
 
        /**
-        * The exported items in a serialised form (possibly zipped).
+        * The exported items in a serialised form (possibly BASE64-coded, possibly
+        * zipped).
         * 
         * @return the items currently in this {@link Exporter}
         */
        @Override
        public String toString() {
-               return toString(null);
+               return toString(null, true);
        }
 }
\ No newline at end of file
index e7285c42ca329c7a6e84c73fba0189c228493781..84fb5aae5742f49bcf68cd915906a2b7322a399b 100644 (file)
@@ -70,13 +70,22 @@ public class Importer {
 
                                if (line.startsWith("ZIP:")) {
                                        try {
-                                               line = StringUtils.unzip64(line.substring("ZIP:"
-                                                               .length()));
+                                               line = StringUtils.unbase64s(
+                                                               line.substring("ZIP:".length()), true);
                                        } catch (IOException e) {
                                                throw new IOException(
                                                                "Internal error when decoding ZIP content: input may be corrupt");
                                        }
                                        read(line);
+                               } else if (line.startsWith("B64:")) {
+                                       try {
+                                               line = StringUtils.unbase64s(
+                                                               line.substring("B64:".length()), false);
+                                       } catch (IOException e) {
+                                               throw new IOException(
+                                                               "Internal error when decoding B64 content: input may be corrupt");
+                                       }
+                                       read(line);
                                } else {
                                        processLine(line);
                                }
index 502d0ba72ccdd0da2b77cfca67e4cc5e3c25a87c..706d579970f9456fd430d4ae2020185aa8c7ed24 100644 (file)
@@ -66,8 +66,8 @@ public class SerialUtils {
                                                if (!SerialUtils.encode(builder, item)) {
                                                        try {
                                                                // use ZIP: if not
-                                                               builder.append(new Exporter().append(item)
-                                                                               .toString(true));
+                                                               new Exporter().append(item).appendTo(builder,
+                                                                               true, false);
                                                        } catch (NotSerializableException e) {
                                                                throw new UnknownFormatConversionException(e
                                                                                .getMessage());
index 97243d567a2ed9f39dfcaddbf8deeaee51bac575..10435e299d70febcdeb83f2f10086c41d85339c3 100644 (file)
@@ -175,7 +175,8 @@ abstract class ConnectAction {
        protected Object sendObject(Object data) throws IOException,
                        NoSuchFieldException, NoSuchMethodException, ClassNotFoundException {
                synchronized (lock) {
-                       String rep = sendString(new Exporter().append(data).toString(true));
+                       String rep = sendString(new Exporter().append(data).toString(true,
+                                       true));
                        if (rep != null) {
                                return new Importer().read(rep).getValue();
                        }
index ea9fd1b3d3514439d813299b9a77128d6e4f6f9d..db50876b32aafb144bc89047e73073c391c569f8 100644 (file)
@@ -238,8 +238,12 @@ public class ServerBridge extends Server {
 
                if (getTraceHandler().getTraceLevel() >= 2) {
                        try {
-                               if (data.startsWith("ZIP:")) {
-                                       data = StringUtils.unzip64(data.substring(4));
+                               while (data.startsWith("ZIP:") || data.startsWith("B64:")) {
+                                       if (data.startsWith("ZIP:")) {
+                                               data = StringUtils.unbase64s(data.substring(4), true);
+                                       } else if (data.startsWith("B64:")) {
+                                               data = StringUtils.unbase64s(data.substring(4), false);
+                                       }
                                }
 
                                Object obj = new Importer().read(data).getValue();
index 29f5bf3d8936b9f9c48637ddbe7af43057fc238c..e35be4fc366f4c12650de731286d104790a2e953 100644 (file)
@@ -223,8 +223,8 @@ class StringUtilsTest extends TestLauncher {
                        @Override
                        public void test() throws Exception {
                                String orig = "test";
-                               String zipped = StringUtils.zip64(orig);
-                               String unzipped = StringUtils.unzip64(zipped);
+                               String zipped = StringUtils.base64(orig, true);
+                               String unzipped = StringUtils.unbase64s(zipped, true);
                                assertEquals(orig, unzipped);
                        }
                });