...
[nikiroo-utils.git] / src / be / nikiroo / utils / serial / SerialUtils.java
index e88337b0a7f68ac03fd10ce2696909bb0cf8a187..c65463281ea51eca82729db53f40370942ab55f6 100644 (file)
@@ -1,5 +1,6 @@
 package be.nikiroo.utils.serial;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.NotSerializableException;
@@ -16,7 +17,11 @@ import java.util.List;
 import java.util.Map;
 import java.util.UnknownFormatConversionException;
 
+import be.nikiroo.utils.IOUtils;
 import be.nikiroo.utils.Image;
+import be.nikiroo.utils.StringUtils;
+import be.nikiroo.utils.streams.NextableInputStream;
+import be.nikiroo.utils.streams.NextableInputStreamStep;
 
 /**
  * Small class to help with serialisation.
@@ -58,51 +63,56 @@ public class SerialUtils {
                        @Override
                        protected void toStream(OutputStream out, Object value)
                                        throws IOException {
+
+                               // TODO: we use \n to separate, and b64 to un-\n
+                               // -- but we could use \\n ?
                                String type = value.getClass().getCanonicalName();
                                type = type.substring(0, type.length() - 2); // remove the []
 
-                               write(out,type);
-                               write(out,"\n");
+                               write(out, type);
                                try {
                                        for (int i = 0; true; i++) {
                                                Object item = Array.get(value, i);
+
                                                // encode it normally if direct value
+                                               write(out, "\r");
                                                if (!SerialUtils.encode(out, item)) {
                                                        try {
-                                                               // TODO: use ZIP: if not?
-                                                               new Exporter(out).append(item);
+                                                               // TODO: bad escaping?
+                                                               write(out, "B64:");
+                                                               OutputStream bout = StringUtils.base64(out,
+                                                                               false, false);
+                                                               new Exporter(bout).append(item);
                                                        } catch (NotSerializableException e) {
                                                                throw new UnknownFormatConversionException(e
                                                                                .getMessage());
                                                        }
                                                }
-                                               write(out,"\n");
                                        }
                                } catch (ArrayIndexOutOfBoundsException e) {
                                        // Done.
                                }
                        }
 
-                       @Override
-                       protected String getType() {
-                               return "[]";
-                       }
-                       
                        @Override
                        protected Object fromStream(InputStream in) throws IOException {
-                               return null;
-                       }
-
-                       @Override
-                       protected Object fromString(String content) throws IOException {
-                               String[] tab = content.split("\n");
+                               NextableInputStream stream = new NextableInputStream(in,
+                                               new NextableInputStreamStep('\r'));
 
                                try {
+                                       List<Object> list = new ArrayList<Object>();
+                                       stream.next();
+                                       String type = IOUtils.readSmallStream(stream);
+
+                                       while (stream.next()) {
+                                               Object value = new Importer().read(stream).getValue();
+                                               list.add(value);
+                                       }
+
                                        Object array = Array.newInstance(
-                                                       SerialUtils.getClass(tab[0]), tab.length - 1);
-                                       for (int i = 1; i < tab.length; i++) {
-                                               Object value = new Importer().read(tab[i]).getValue();
-                                               Array.set(array, i - 1, value);
+                                                       SerialUtils.getClass(type), list.size());
+                                       for (int i = 0; i < list.size(); i++) {
+                                               Array.set(array, i, list.get(i));
                                        }
 
                                        return array;
@@ -113,23 +123,33 @@ public class SerialUtils {
                                        throw new IOException(e.getMessage());
                                }
                        }
+
+                       @Override
+                       protected String getType() {
+                               return "[]";
+                       }
                });
 
                // URL:
                customTypes.put("java.net.URL", new CustomSerializer() {
                        @Override
-                       protected String toString(Object value) {
+                       protected void toStream(OutputStream out, Object value)
+                                       throws IOException {
+                               String val = "";
                                if (value != null) {
-                                       return ((URL) value).toString();
+                                       val = ((URL) value).toString();
                                }
-                               return null;
+
+                               out.write(val.getBytes("UTF-8"));
                        }
 
                        @Override
-                       protected Object fromString(String content) throws IOException {
-                               if (content != null) {
-                                       return new URL(content);
+                       protected Object fromStream(InputStream in) throws IOException {
+                               String val = IOUtils.readSmallStream(in);
+                               if (!val.isEmpty()) {
+                                       return new URL(val);
                                }
+
                                return null;
                        }
 
@@ -142,8 +162,20 @@ public class SerialUtils {
                // Images (this is currently the only supported image type by default)
                customTypes.put("be.nikiroo.utils.Image", new CustomSerializer() {
                        @Override
-                       protected String toString(Object value) {
-                               return ((Image) value).toBase64();
+                       protected void toStream(OutputStream out, Object value)
+                                       throws IOException {
+                               Image img = (Image) value;
+                               OutputStream encoded = StringUtils.base64(out, false, false);
+                               try {
+                                       InputStream in = img.newInputStream();
+                                       try {
+                                               IOUtils.write(in, encoded);
+                                       } finally {
+                                               in.close();
+                                       }
+                               } finally {
+                                       encoded.close();
+                               }
                        }
 
                        @Override
@@ -152,9 +184,9 @@ public class SerialUtils {
                        }
 
                        @Override
-                       protected Object fromString(String content) {
+                       protected Object fromStream(InputStream in) throws IOException {
                                try {
-                                       return new Image(content);
+                                       return new Image(in);
                                } catch (IOException e) {
                                        throw new UnknownFormatConversionException(e.getMessage());
                                }
@@ -218,7 +250,7 @@ public class SerialUtils {
                                        ctor = clazz.getDeclaredConstructor(classes
                                                        .toArray(new Class[] {}));
                                } catch (NoSuchMethodException nsme) {
-                                       // TODO: it seems e do not always need a parameter for each
+                                       // TODO: it seems we do not always need a parameter for each
                                        // level, so we currently try "ALL" levels or "FIRST" level
                                        // only -> we should check the actual rule and use it
                                        ctor = clazz.getDeclaredConstructor(classes.get(0));
@@ -342,7 +374,6 @@ public class SerialUtils {
                                                                                // setAccessible)
                        }
                }
-               write(out, "\n}");
        }
 
        /**
@@ -372,9 +403,9 @@ public class SerialUtils {
                } else if (value.getClass().getSimpleName().endsWith("[]")) {
                        // Simple name does support [] suffix and do not return NULL for
                        // inner anonymous classes
-                       return customTypes.get("[]").encode(out, value);
+                       customTypes.get("[]").encode(out, value);
                } else if (customTypes.containsKey(value.getClass().getCanonicalName())) {
-                       return customTypes.get(value.getClass().getCanonicalName())//
+                       customTypes.get(value.getClass().getCanonicalName())//
                                        .encode(out, value);
                } else if (value instanceof String) {
                        encodeString(out, (String) value);
@@ -441,7 +472,14 @@ public class SerialUtils {
                                // custom:TYPE_NAME:"content is String-encoded"
                                String type = CustomSerializer.typeOf(encodedValue);
                                if (customTypes.containsKey(type)) {
-                                       return customTypes.get(type).decode(encodedValue);
+                                       // TODO: we should start with a stream
+                                       InputStream streamEncodedValue = new ByteArrayInputStream(
+                                                       encodedValue.getBytes("UTF-8"));
+                                       try {
+                                               return customTypes.get(type).decode(streamEncodedValue);
+                                       } finally {
+                                               streamEncodedValue.close();
+                                       }
                                }
                                throw new IOException("Unknown custom type: " + type);
                        } else if (encodedValue.equals("NULL")
@@ -566,6 +604,7 @@ public class SerialUtils {
 
        // aa bb -> "aa\tbb"
        static void encodeString(OutputStream out, String raw) throws IOException {
+               // TODO: not. efficient.
                out.write('\"');
                // TODO !! utf-8 required
                for (char car : raw.toCharArray()) {
@@ -578,7 +617,7 @@ public class SerialUtils {
        static void encodeString(OutputStream out, InputStream raw)
                        throws IOException {
                out.write('\"');
-               byte buffer[] = new byte[4069];
+               byte buffer[] = new byte[4096];
                for (int len = 0; (len = raw.read(buffer)) > 0;) {
                        for (int i = 0; i < len; i++) {
                                // TODO: not 100% correct, look up howto for UTF-8