]> source.dussan.org Git - poi.git/commitdiff
#63745 - Make GenericRecordJsonWriter Json-conformant
authorAndreas Beeker <kiwiwings@apache.org>
Fri, 25 Oct 2019 20:00:06 +0000 (20:00 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Fri, 25 Oct 2019 20:00:06 +0000 (20:00 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1868952 13f79535-47bb-0310-9956-ffa450edef68

19 files changed:
src/java/org/apache/poi/util/GenericRecordJsonWriter.java
src/java/org/apache/poi/util/GenericRecordXmlWriter.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFObjectData.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPictureData.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java
src/testcases/org/apache/poi/ddf/TestEscherBSERecord.java
src/testcases/org/apache/poi/ddf/TestEscherBoolProperty.java
src/testcases/org/apache/poi/ddf/TestEscherChildAnchorRecord.java
src/testcases/org/apache/poi/ddf/TestEscherClientAnchorRecord.java
src/testcases/org/apache/poi/ddf/TestEscherClientDataRecord.java
src/testcases/org/apache/poi/ddf/TestEscherContainerRecord.java
src/testcases/org/apache/poi/ddf/TestEscherDgRecord.java
src/testcases/org/apache/poi/ddf/TestEscherDggRecord.java
src/testcases/org/apache/poi/ddf/TestEscherOptRecord.java
src/testcases/org/apache/poi/ddf/TestEscherSpRecord.java
src/testcases/org/apache/poi/ddf/TestEscherSpgrRecord.java
src/testcases/org/apache/poi/ddf/TestEscherSplitMenuColorsRecord.java
src/testcases/org/apache/poi/ddf/TestUnknownEscherRecord.java
src/testcases/org/apache/poi/hssf/usermodel/TestPolygon.java

index b70fe362a7d8da04979811025cf2dc9fd4f48788..10e6beb314ad5c23228740ee110523c4caa56f4f 100644 (file)
@@ -40,25 +40,39 @@ import java.nio.charset.StandardCharsets;
 import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Base64;
 import java.util.List;
 import java.util.Map;
-import java.util.function.BiConsumer;
 import java.util.function.Supplier;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import javax.xml.bind.DatatypeConverter;
-
 import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.util.GenericRecordUtil.AnnotatedFlag;
 
+@SuppressWarnings({"UnusedReturnValue", "WeakerAccess"})
 @Beta
 public class GenericRecordJsonWriter implements Closeable {
     private static final String TABS;
     private static final String ZEROS = "0000000000000000";
     private static final Pattern ESC_CHARS = Pattern.compile("[\"\\p{Cntrl}\\\\]");
 
-    private static final List<Map.Entry<Class,BiConsumer<GenericRecordJsonWriter,Object>>> handler = new ArrayList<>();
+    @FunctionalInterface
+    protected interface GenericRecordHandler {
+        /**
+         * Handler method
+         *
+         * @param record the parent record, applied via instance method reference
+         * @param name the name of the property
+         * @param object the value of the property
+         * @return {@code true}, if the element was handled and output produced,
+         *   The provided methods can be overridden and a implementation can return {@code false},
+         *   if the element hasn't been written to the stream
+         */
+        boolean print(GenericRecordJsonWriter record, String name, Object object);
+    }
+
+    private static final List<Map.Entry<Class,GenericRecordHandler>> handler = new ArrayList<>();
 
     static {
         char[] t = new char[255];
@@ -81,22 +95,25 @@ public class GenericRecordJsonWriter implements Closeable {
         handler(Object.class, GenericRecordJsonWriter::printObject);
     }
 
-    private static void handler(Class c, BiConsumer<GenericRecordJsonWriter,Object> printer) {
+    private static void handler(Class c, GenericRecordHandler printer) {
         handler.add(new AbstractMap.SimpleEntry<>(c,printer));
     }
 
-    private final PrintWriter fw;
-    private int indent = 0;
-    private boolean withComments = true;
-    private int childIndex = 0;
+    protected final AppendableWriter aw;
+    protected final PrintWriter fw;
+    protected int indent = 0;
+    protected boolean withComments = true;
+    protected int childIndex = 0;
 
     public GenericRecordJsonWriter(File fileName) throws IOException {
         OutputStream os = ("null".equals(fileName.getName())) ? new NullOutputStream() : new FileOutputStream(fileName);
-        fw = new PrintWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8));
+        aw = new AppendableWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8));
+        fw = new PrintWriter(aw);
     }
 
     public GenericRecordJsonWriter(Appendable buffer) {
-        fw = new PrintWriter(new AppendableWriter(buffer));
+        aw = new AppendableWriter(buffer);
+        fw = new PrintWriter(aw);
     }
 
     public static String marshal(GenericRecord record) {
@@ -123,7 +140,7 @@ public class GenericRecordJsonWriter implements Closeable {
         fw.close();
     }
 
-    private String tabs() {
+    protected String tabs() {
         return TABS.substring(0, Math.min(indent, TABS.length()));
     }
 
@@ -144,81 +161,103 @@ public class GenericRecordJsonWriter implements Closeable {
         }
         fw.println();
 
+        boolean hasProperties = writeProperties(record);
+        fw.println();
+
+        writeChildren(record, hasProperties);
+
+        fw.append(tabs);
+        fw.append("}");
+    }
+
+    protected boolean writeProperties(GenericRecord record) {
         Map<String, Supplier<?>> prop = record.getGenericProperties();
-        if (prop != null) {
-            final int oldChildIndex = childIndex;
-            childIndex = 0;
-            prop.forEach(this::writeProp);
-            childIndex = oldChildIndex;
+        if (prop == null || prop.isEmpty()) {
+            return false;
         }
 
-        fw.println();
+        final int oldChildIndex = childIndex;
+        childIndex = 0;
+        long cnt = prop.entrySet().stream().filter(e -> writeProp(e.getKey(),e.getValue())).count();
+        childIndex = oldChildIndex;
+
+        return cnt > 0;
+    }
+
+
+    protected boolean writeChildren(GenericRecord record, boolean hasProperties) {
         List<? extends GenericRecord> list = record.getGenericChildren();
-        if (list != null && !list.isEmpty()) {
-            indent++;
-            fw.append(tabs());
-            if (prop != null && !prop.isEmpty()) {
-                fw.append(", ");
-            }
-            fw.append("children: [");
-            final int oldChildIndex = childIndex;
-            childIndex = 0;
-            list.forEach(l -> { writeValue(l); childIndex++; });
-            childIndex = oldChildIndex;
-            fw.println();
-            fw.append(tabs());
-            fw.append("]");
+        if (list == null || list.isEmpty()) {
+            return false;
+        }
+
+        indent++;
+        aw.setHoldBack(tabs() + (hasProperties ? ", " : "") + "\"children\": [\n");
+        final int oldChildIndex = childIndex;
+        childIndex = 0;
+        long cnt = list.stream().filter(l -> writeValue(null, l) && ++childIndex > 0).count();
+        childIndex = oldChildIndex;
+        aw.setHoldBack(null);
+
+        if (cnt > 0) {
             fw.println();
-            indent--;
+            fw.println(tabs() + "]");
         }
+        indent--;
 
-        fw.append(tabs);
-        fw.append("}");
+        return cnt > 0;
     }
 
     public void writeError(String errorMsg) {
         fw.append("{ error: ");
-        printObject(errorMsg);
+        printObject("error", errorMsg);
         fw.append(" }");
     }
 
-    private void writeProp(String k, Supplier<?> v) {
-        final boolean isNext = (childIndex++>0);
-        if (isNext) {
-            fw.println();
-        }
-        fw.write(tabs());
-        fw.write('\t');
-        fw.write(isNext ? ", " : "  ");
-        fw.write(k);
-        fw.write(": ");
+    protected boolean writeProp(String name, Supplier<?> value) {
+        final boolean isNext = (childIndex>0);
+        aw.setHoldBack(isNext ? "\n" + tabs() + "\t, " : tabs() + "\t  ");
         final int oldChildIndex = childIndex;
         childIndex = 0;
-        writeValue(v.get());
-        childIndex = oldChildIndex;
+        boolean written = writeValue(name, value.get());
+        childIndex = oldChildIndex + (written ? 1 : 0);
+        aw.setHoldBack(null);
+        return written;
     }
 
-    private void writeValue(Object o) {
+    protected boolean writeValue(String name, Object o) {
         if (childIndex > 0) {
-            fw.println(',');
-        }
-        if (o == null) {
-            fw.write("null");
-        } else {
-            handler.stream().
-                filter(h -> matchInstanceOrArray(h.getKey(), o)).
-                findFirst().
-                ifPresent(h -> h.getValue().accept(this, o));
+            aw.setHoldBack(",");
         }
+
+        GenericRecordHandler grh = (o == null)
+            ? GenericRecordJsonWriter::printNull
+            : handler.stream().filter(h -> matchInstanceOrArray(h.getKey(), o)).
+            findFirst().map(Map.Entry::getValue).orElse(null);
+
+        boolean result = grh != null && grh.print(this, name, o);
+        aw.setHoldBack(null);
+        return result;
     }
 
-    private static boolean matchInstanceOrArray(Class key, Object instance) {
+    protected static boolean matchInstanceOrArray(Class key, Object instance) {
         return key.isInstance(instance) || (Array.class.equals(key) && instance.getClass().isArray());
     }
 
-    private void printNumber(Object o) {
+    protected void printName(String name) {
+        fw.print(name != null ? "\""+name+"\": " : "");
+    }
+
+    protected boolean printNull(String name, Object o) {
+        printName(name);
+        fw.write("null");
+        return true;
+    }
+
+    protected boolean printNumber(String name, Object o) {
         Number n = (Number)o;
-        fw.print(n.toString());
+        printName(name);
+        fw.print(n.longValue());
 
         final int size;
         if (n instanceof Byte) {
@@ -239,65 +278,81 @@ public class GenericRecordJsonWriter implements Closeable {
             fw.write(trimHex(l, size));
             fw.write(" */");
         }
+        return true;
     }
 
-    private void printBoolean(Object o) {
+    protected boolean printBoolean(String name, Object o) {
+        printName(name);
         fw.write(((Boolean)o).toString());
+        return true;
     }
 
-    private void printList(Object o) {
-        fw.println('[');
+    protected boolean printList(String name, Object o) {
+        printName(name);
+        fw.println("[");
         int oldChildIndex = childIndex;
         childIndex = 0;
         //noinspection unchecked
-        ((List)o).forEach(e -> { writeValue(e); childIndex++; });
+        ((List)o).forEach(e -> { writeValue(null, e); childIndex++; });
         childIndex = oldChildIndex;
-        fw.write(']');
+        fw.write(tabs() + "\t]");
+        return true;
     }
 
-    private void printGenericRecord(Object o) {
-        fw.println();
+    protected boolean printGenericRecord(String name, Object o) {
+        printName(name);
         this.indent++;
         write((GenericRecord) o);
         this.indent--;
+        return true;
     }
 
-    private void printAnnotatedFlag(Object o) {
+    protected boolean printAnnotatedFlag(String name, Object o) {
+        printName(name);
         AnnotatedFlag af = (AnnotatedFlag) o;
-        fw.write("0x");
-        fw.write(Long.toHexString(af.getValue().get().longValue()));
+        fw.print(af.getValue().get().longValue());
         if (withComments) {
             fw.write(" /* ");
             fw.write(af.getDescription());
             fw.write(" */ ");
         }
+        return true;
     }
 
-    private void printBytes(Object o) {
+    protected boolean printBytes(String name, Object o) {
+        printName(name);
         fw.write('"');
-        fw.write(DatatypeConverter.printBase64Binary((byte[]) o));
+        fw.write(Base64.getEncoder().encodeToString((byte[]) o));
         fw.write('"');
+        return true;
     }
 
-    private void printPoint(Object o) {
+    protected boolean printPoint(String name, Object o) {
+        printName(name);
         Point2D p = (Point2D)o;
-        fw.write("{ x: "+p.getX()+", y: "+p.getY()+" }");
+        fw.write("{ \"x\": "+p.getX()+", \"y\": "+p.getY()+" }");
+        return true;
     }
 
-    private void printDimension(Object o) {
+    protected boolean printDimension(String name, Object o) {
+        printName(name);
         Dimension2D p = (Dimension2D)o;
-        fw.write("{ width: "+p.getWidth()+", height: "+p.getHeight()+" }");
+        fw.write("{ \"width\": "+p.getWidth()+", \"height\": "+p.getHeight()+" }");
+        return true;
     }
 
-    private void printRectangle(Object o) {
+    protected boolean printRectangle(String name, Object o) {
+        printName(name);
         Rectangle2D p = (Rectangle2D)o;
-        fw.write("{ x: "+p.getX()+", y: "+p.getY()+", width: "+p.getWidth()+", height: "+p.getHeight()+" }");
+        fw.write("{ \"x\": "+p.getX()+", \"y\": "+p.getY()+", \"width\": "+p.getWidth()+", \"height\": "+p.getHeight()+" }");
+        return true;
     }
 
-    private void printPath(Object o) {
+    protected boolean printPath(String name, Object o) {
+        printName(name);
         final PathIterator iter = ((Path2D)o).getPathIterator(null);
         final double[] pnts = new double[6];
-        fw.print("[");
+        fw.write("[");
 
         indent += 2;
         String t = tabs();
@@ -309,19 +364,19 @@ public class GenericRecordJsonWriter implements Closeable {
             fw.print(t);
             isNext = true;
             final int segType = iter.currentSegment(pnts);
-            fw.append("{ type: ");
+            fw.append("{ \"type\": ");
             switch (segType) {
                 case PathIterator.SEG_MOVETO:
-                    fw.write("'move', x: "+pnts[0]+", y: "+pnts[1]);
+                    fw.write("'move', \"x\": "+pnts[0]+", \"y\": "+pnts[1]);
                     break;
                 case PathIterator.SEG_LINETO:
-                    fw.write("'lineto', x: "+pnts[0]+", y: "+pnts[1]);
+                    fw.write("'lineto', \"x\": "+pnts[0]+", \"y\": "+pnts[1]);
                     break;
                 case PathIterator.SEG_QUADTO:
-                    fw.write("'quad', x1: "+pnts[0]+", y1: "+pnts[1]+", x2: "+pnts[2]+", y2: "+pnts[3]);
+                    fw.write("'quad', \"x1\": "+pnts[0]+", \"y1\": "+pnts[1]+", \"x2\": "+pnts[2]+", \"y2\": "+pnts[3]);
                     break;
                 case PathIterator.SEG_CUBICTO:
-                    fw.write("'cubic', x1: "+pnts[0]+", y1: "+pnts[1]+", x2: "+pnts[2]+", y2: "+pnts[3]+", x3: "+pnts[4]+", y3: "+pnts[5]);
+                    fw.write("'cubic', \"x1\": "+pnts[0]+", \"y1\": "+pnts[1]+", \"x2\": "+pnts[2]+", \"y2\": "+pnts[3]+", \"x3\": "+pnts[4]+", \"y3\": "+pnts[5]);
                     break;
                 case PathIterator.SEG_CLOSE:
                     fw.write("'close'");
@@ -332,9 +387,11 @@ public class GenericRecordJsonWriter implements Closeable {
         }
 
         fw.write("]");
+        return true;
     }
 
-    private void printObject(Object o) {
+    protected boolean printObject(String name, Object o) {
+        printName(name);
         fw.write('"');
 
         final Matcher m = ESC_CHARS.matcher(o.toString());
@@ -374,20 +431,25 @@ public class GenericRecordJsonWriter implements Closeable {
         fw.write(sb.toString());
 
         fw.write('"');
+        return true;
     }
 
-    private void printAffineTransform(Object o) {
+    protected boolean printAffineTransform(String name, Object o) {
+        printName(name);
         AffineTransform xForm = (AffineTransform)o;
         fw.write(
-            "{ scaleX: "+xForm.getScaleX()+
-            ", shearX: "+xForm.getShearX()+
-            ", transX: "+xForm.getTranslateX()+
-            ", scaleY: "+xForm.getScaleY()+
-            ", shearY: "+xForm.getShearY()+
-            ", transY: "+xForm.getTranslateY()+" }");
+            "{ \"scaleX\": "+xForm.getScaleX()+
+            ", \"shearX\": "+xForm.getShearX()+
+            ", \"transX\": "+xForm.getTranslateX()+
+            ", \"scaleY\": "+xForm.getScaleY()+
+            ", \"shearY\": "+xForm.getShearY()+
+            ", \"transY\": "+xForm.getTranslateY()+" }");
+        return true;
     }
 
-    private void printColor(Object o) {
+    protected boolean printColor(String name, Object o) {
+        printName(name);
+
         final int rgb = ((Color)o).getRGB();
         fw.print(rgb);
 
@@ -396,17 +458,20 @@ public class GenericRecordJsonWriter implements Closeable {
             fw.write(trimHex(rgb, 8));
             fw.write(" */");
         }
+        return true;
     }
 
-    private void printArray(Object o) {
-        fw.println('[');
+    protected boolean printArray(String name, Object o) {
+        printName(name);
+        fw.write("[");
         int length = Array.getLength(o);
         final int oldChildIndex = childIndex;
         for (childIndex=0; childIndex<length; childIndex++) {
-            writeValue(Array.get(o, childIndex));
+            writeValue(null, Array.get(o, childIndex));
         }
         childIndex = oldChildIndex;
-        fw.write(']');
+        fw.write(tabs() + "\t]");
+        return true;
     }
 
     static String trimHex(final long l, final int size) {
@@ -433,30 +498,58 @@ public class GenericRecordJsonWriter implements Closeable {
     }
 
     static class AppendableWriter extends Writer {
-        private Appendable buffer;
+        private final Appendable appender;
+        private final Writer writer;
+        private String holdBack;
 
         AppendableWriter(Appendable buffer) {
             super(buffer);
-            this.buffer = buffer;
+            this.appender = buffer;
+            this.writer = null;
+        }
+
+        AppendableWriter(Writer writer) {
+            super(writer);
+            this.appender = null;
+            this.writer = writer;
+        }
+
+        void setHoldBack(String holdBack) {
+            this.holdBack = holdBack;
         }
 
         @Override
         public void write(char[] cbuf, int off, int len) throws IOException {
-            buffer.append(String.valueOf(cbuf), off, len);
+            if (holdBack != null) {
+                if (appender != null) {
+                    appender.append(holdBack);
+                } else {
+                    writer.write(holdBack);
+                }
+                holdBack = null;
+            }
+
+            if (appender != null) {
+                appender.append(String.valueOf(cbuf), off, len);
+            } else {
+                writer.write(cbuf, off, len);
+            }
         }
 
         @Override
         public void flush() throws IOException {
-            if (buffer instanceof Flushable) {
-                ((Flushable)buffer).flush();
+            Object o = (appender != null) ? appender : writer;
+            if (o instanceof Flushable) {
+                ((Flushable)o).flush();
             }
         }
 
         @Override
         public void close() throws IOException {
             flush();
-            if (buffer instanceof Closeable) {
-                ((Closeable)buffer).close();
+            Object o = (appender != null) ? appender : writer;
+            if (o instanceof Closeable) {
+                ((Closeable)o).close();
             }
         }
     }
index 44ca83f14c135fedc7462483911f5c8d6fe3602f..c5c7877f04052623d1702acb1c25e70ba64845ab 100644 (file)
@@ -39,27 +39,41 @@ import java.nio.charset.StandardCharsets;
 import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Base64;
 import java.util.List;
 import java.util.Map;
-import java.util.function.BiConsumer;
 import java.util.function.Supplier;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import javax.xml.bind.DatatypeConverter;
-
 import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.util.GenericRecordJsonWriter.AppendableWriter;
 import org.apache.poi.util.GenericRecordJsonWriter.NullOutputStream;
 
+@SuppressWarnings("WeakerAccess")
 public class GenericRecordXmlWriter implements Closeable {
     private static final String TABS;
     private static final String ZEROS = "0000000000000000";
     private static final Pattern ESC_CHARS = Pattern.compile("[<>&'\"\\p{Cntrl}]");
 
-    private static final List<Map.Entry<Class, BiConsumer<GenericRecordXmlWriter,Object>>> handler = new ArrayList<>();
+    @FunctionalInterface
+    protected interface GenericRecordHandler {
+        /**
+         * Handler method
+         *
+         * @param record the parent record, applied via instance method reference
+         * @param name the name of the property
+         * @param object the value of the property
+         * @return {@code true}, if the element was handled and output produced,
+         *   The provided methods can be overridden and a implementation can return {@code false},
+         *   if the element hasn't been written to the stream
+         */
+        boolean print(GenericRecordXmlWriter record, String name, Object object);
+    }
+
+    private static final List<Map.Entry<Class, GenericRecordHandler>> handler = new ArrayList<>();
 
     static {
         char[] t = new char[255];
@@ -83,7 +97,7 @@ public class GenericRecordXmlWriter implements Closeable {
         handler(Object.class, GenericRecordXmlWriter::printObject);
     }
 
-    private static void handler(Class c, BiConsumer<GenericRecordXmlWriter,Object> printer) {
+    private static void handler(Class c, GenericRecordHandler printer) {
         handler.add(new AbstractMap.SimpleEntry<>(c, printer));
     }
 
@@ -126,15 +140,15 @@ public class GenericRecordXmlWriter implements Closeable {
         fw.close();
     }
 
-    private String tabs() {
+    protected String tabs() {
         return TABS.substring(0, Math.min(indent, TABS.length()));
     }
 
     public void write(GenericRecord record) {
-        write(record, "record");
+        write("record", record);
     }
 
-    private void write(GenericRecord record, final String name) {
+    protected void write(final String name, GenericRecord record) {
         final String tabs = tabs();
         Enum type = record.getGenericRecordType();
         String recordName = (type != null) ? type.name() : record.getClass().getSimpleName();
@@ -148,49 +162,16 @@ public class GenericRecordXmlWriter implements Closeable {
             fw.append("\"");
         }
 
-        boolean hasChildren = false;
 
-        Map<String, Supplier<?>> prop = record.getGenericProperties();
-        if (prop != null) {
-            final int oldChildIndex = childIndex;
-            childIndex = 0;
-            attributePhase = true;
-            List<Map.Entry<String,Supplier<?>>> complex = prop.entrySet().stream().flatMap(this::writeProp).collect(Collectors.toList());
-            attributePhase = false;
-            if (!complex.isEmpty()) {
-                hasChildren = true;
-                fw.println(">");
-                indent++;
-                complex.forEach(this::writeProp);
-                indent--;
-            }
-            childIndex = oldChildIndex;
-        } else {
-            fw.print(">");
-        }
+        attributePhase = true;
+
+        boolean hasComplex = writeProperties(record);
 
         attributePhase = false;
 
-        List<? extends GenericRecord> list = record.getGenericChildren();
-        if (list != null && !list.isEmpty()) {
-            hasChildren = true;
-            indent++;
-            fw.println();
-            fw.append(tabs());
-            fw.println("<children>");
-            indent++;
-            final int oldChildIndex = childIndex;
-            childIndex = 0;
-            list.forEach(l -> { writeValue("record", l); childIndex++; });
-            childIndex = oldChildIndex;
-            fw.println();
-            indent--;
-            fw.append(tabs());
-            fw.println("</children>");
-            indent--;
-        }
+        hasComplex |= writeChildren(record, hasComplex);
 
-        if (hasChildren) {
+        if (hasComplex) {
             fw.append(tabs);
             fw.println("</" + name + ">");
         } else {
@@ -198,13 +179,61 @@ public class GenericRecordXmlWriter implements Closeable {
         }
     }
 
+    protected boolean writeProperties(GenericRecord record) {
+        Map<String, Supplier<?>> prop = record.getGenericProperties();
+        if (prop == null || prop.isEmpty()) {
+            return false;
+        }
+
+        final int oldChildIndex = childIndex;
+        childIndex = 0;
+        List<Map.Entry<String,Supplier<?>>> complex = prop.entrySet().stream().flatMap(this::writeProp).collect(Collectors.toList());
+
+        attributePhase = false;
+        if (!complex.isEmpty()) {
+            fw.println(">");
+            indent++;
+            complex.forEach(this::writeProp);
+            indent--;
+        }
+        childIndex = oldChildIndex;
+
+        return !complex.isEmpty();
+    }
+
+    protected boolean writeChildren(GenericRecord record, boolean hasComplexProperties) {
+        List<? extends GenericRecord> list = record.getGenericChildren();
+        if (list == null || list.isEmpty()) {
+            return false;
+        }
+        if (!hasComplexProperties) {
+            fw.print(">");
+        }
+
+        indent++;
+        fw.println();
+        fw.println(tabs()+"<children>");
+        indent++;
+        final int oldChildIndex = childIndex;
+        childIndex = 0;
+        list.forEach(l -> {
+            writeValue("record", l);
+            childIndex++;
+        });
+        childIndex = oldChildIndex;
+        fw.println();
+        indent--;
+        fw.println(tabs()+"</children>");
+        indent--;
+
+        return true;
+    }
+
     public void writeError(String errorMsg) {
-        fw.append("<error>");
-        printObject(errorMsg);
-        fw.append("</error>");
+        printObject("error", errorMsg);
     }
 
-    private Stream<Map.Entry<String,Supplier<?>>> writeProp(Map.Entry<String,Supplier<?>> me) {
+    protected Stream<Map.Entry<String,Supplier<?>>> writeProp(Map.Entry<String,Supplier<?>> me) {
         Object obj = me.getValue().get();
         if (obj == null) {
             return Stream.empty();
@@ -223,7 +252,7 @@ public class GenericRecordXmlWriter implements Closeable {
         return Stream.empty();
     }
 
-    private static boolean isComplex(Object obj) {
+    protected static boolean isComplex(Object obj) {
         return !(
             obj instanceof Number ||
             obj instanceof Boolean ||
@@ -233,100 +262,101 @@ public class GenericRecordXmlWriter implements Closeable {
             obj instanceof Enum);
     }
 
-    private void writeValue(String key, Object o) {
-        assert(key != null);
-        if (o instanceof GenericRecord) {
-            printGenericRecord((GenericRecord)o, key);
-        } else if (o != null) {
-            if (key.endsWith(">")) {
+    protected void writeValue(String name, Object value) {
+        assert(name != null);
+        if (value instanceof GenericRecord) {
+            printGenericRecord(name, value);
+        } else if (value != null) {
+            if (name.endsWith(">")) {
                 fw.print("\t");
             }
 
-            fw.print(attributePhase ? " " + key + "=\"" : tabs()+"<" + key);
-            if (key.endsWith(">")) {
-                fw.println();
-            }
-
             handler.stream().
-                filter(h -> matchInstanceOrArray(h.getKey(), o)).
+                filter(h -> matchInstanceOrArray(h.getKey(), value)).
                 findFirst().
-                ifPresent(h -> h.getValue().accept(this, o));
+                ifPresent(h -> h.getValue().print(this, name, value));
 
-            if (attributePhase) {
-                fw.append("\"");
-            }
-
-            if (key.endsWith(">")) {
-                fw.println(tabs()+"\t</"+key);
-            } else if (o instanceof List || o.getClass().isArray()) {
-                fw.println(tabs()+"</"+key+">");
-            }
         }
     }
 
-    private static boolean matchInstanceOrArray(Class key, Object instance) {
+    protected static boolean matchInstanceOrArray(Class key, Object instance) {
         return key.isInstance(instance) || (Array.class.equals(key) && instance.getClass().isArray());
     }
-    private void printNumber(Object o) {
-        assert(attributePhase);
-        Number n = (Number)o;
-        fw.print(n.toString());
 
+    protected void openName(String name) {
+        name = name.replace(">>", ">");
         if (attributePhase) {
-            return;
+            fw.print(" " + name.replace('>',' ').trim() + "=\"");
+        } else {
+            fw.print(tabs() + "<" + name);
+            if (name.endsWith(">")) {
+                fw.println();
+            }
         }
+    }
 
-        final int size;
-        if (n instanceof Byte) {
-            size = 2;
-        } else if (n instanceof Short) {
-            size = 4;
-        } else if (n instanceof Integer) {
-            size = 8;
-        } else if (n instanceof Long) {
-            size = 16;
+    protected void closeName(String name) {
+        name = name.replace(">>", ">");
+        if (attributePhase) {
+            fw.append("\"");
         } else {
-            size = -1;
+            if (name.endsWith(">")) {
+                fw.println(tabs() + "\t</" + name);
+            } else {
+                fw.println("/>");
+            }
         }
+    }
 
-        long l = n.longValue();
-        if (withComments && size > 0 && (l < 0 || l > 9)) {
-            fw.write(" /* 0x");
-            fw.write(trimHex(l, size));
-            fw.write(" */");
-        }
+    protected boolean printNumber(String name, Object o) {
+        assert(attributePhase);
+
+        openName(name);
+        Number n = (Number)o;
+        fw.print(n.toString());
+        closeName(name);
+
+        return true;
     }
 
-    private void printBoolean(Object o) {
+    protected boolean printBoolean(String name, Object o) {
+        assert (attributePhase);
+        openName(name);
         fw.write(((Boolean)o).toString());
+        closeName(name);
+        return true;
     }
 
-    private void printList(Object o) {
+    protected boolean printList(String name, Object o) {
         assert (!attributePhase);
-        fw.println(">");
+        openName(name+">");
         int oldChildIndex = childIndex;
         childIndex = 0;
         //noinspection unchecked
         ((List)o).forEach(e -> { writeValue("item>", e); childIndex++; });
         childIndex = oldChildIndex;
+        closeName(name+">");
+        return true;
     }
 
-    private void printArray(Object o) {
+    protected boolean printArray(String name, Object o) {
         assert (!attributePhase);
-        fw.println(">");
+        openName(name+">");
         int length = Array.getLength(o);
         final int oldChildIndex = childIndex;
         for (childIndex=0; childIndex<length; childIndex++) {
             writeValue("item>", Array.get(o, childIndex));
         }
         childIndex = oldChildIndex;
+        closeName(name+">");
+        return true;
     }
 
-    private void printGenericRecord(Object o, String name) {
-        write((GenericRecord) o, name);
+    protected void printGenericRecord(String name, Object value) {
+        write(name, (GenericRecord) value);
     }
 
-    private void printAnnotatedFlag(Object o) {
+    protected boolean printAnnotatedFlag(String name, Object o) {
         assert (!attributePhase);
         GenericRecordUtil.AnnotatedFlag af = (GenericRecordUtil.AnnotatedFlag) o;
         Number n = af.getValue().get();
@@ -341,6 +371,7 @@ public class GenericRecordXmlWriter implements Closeable {
             len = 16;
         }
 
+        openName(name);
         fw.print(" flag=\"0x");
         fw.print(trimHex(n.longValue(), len));
         fw.print('"');
@@ -349,35 +380,50 @@ public class GenericRecordXmlWriter implements Closeable {
             fw.print(af.getDescription());
             fw.print("\"");
         }
-        fw.println("/>");
+        closeName(name);
+        return true;
     }
 
-    private void printBytes(Object o) {
+    protected boolean printBytes(String name, Object o) {
         assert (!attributePhase);
-        fw.write(">");
-        fw.write(DatatypeConverter.printBase64Binary((byte[]) o));
+        openName(name+">");
+        fw.write(Base64.getEncoder().encodeToString((byte[]) o));
+        closeName(name+">");
+        return true;
     }
 
-    private void printPoint(Object o) {
+    protected boolean printPoint(String name, Object o) {
         assert (!attributePhase);
+        openName(name);
         Point2D p = (Point2D)o;
         fw.println(" x=\""+p.getX()+"\" y=\""+p.getY()+"\"/>");
+        closeName(name);
+        return true;
     }
 
-    private void printDimension(Object o) {
+    protected boolean printDimension(String name, Object o) {
         assert (!attributePhase);
+        openName(name);
         Dimension2D p = (Dimension2D)o;
         fw.println(" width=\""+p.getWidth()+"\" height=\""+p.getHeight()+"\"/>");
+        closeName(name);
+        return true;
     }
 
-    private void printRectangle(Object o) {
+    protected boolean printRectangle(String name, Object o) {
         assert (!attributePhase);
+        openName(name);
         Rectangle2D p = (Rectangle2D)o;
         fw.println(" x=\""+p.getX()+"\" y=\""+p.getY()+"\" width=\""+p.getWidth()+"\" height=\""+p.getHeight()+"\"/>");
+        closeName(name);
+        return true;
     }
 
-    private void printPath(Object o) {
+    protected boolean printPath(String name, Object o) {
         assert (!attributePhase);
+
+        openName(name+">");
+
         final PathIterator iter = ((Path2D)o).getPathIterator(null);
         final double[] pnts = new double[6];
 
@@ -385,10 +431,8 @@ public class GenericRecordXmlWriter implements Closeable {
         String t = tabs();
         indent -= 2;
 
-        boolean isNext = false;
         while (!iter.isDone()) {
             fw.print(t);
-            isNext = true;
             final int segType = iter.currentSegment(pnts);
             fw.print("<pathelement ");
             switch (segType) {
@@ -412,9 +456,12 @@ public class GenericRecordXmlWriter implements Closeable {
             iter.next();
         }
 
+        closeName(name+">");
+        return true;
     }
 
-    private void printObject(Object o) {
+    protected boolean printObject(String name, Object o) {
+        openName(name+">");
         final Matcher m = ESC_CHARS.matcher(o.toString());
         final StringBuffer sb = new StringBuffer();
         while (m.find()) {
@@ -444,34 +491,44 @@ public class GenericRecordXmlWriter implements Closeable {
         }
         m.appendTail(sb);
         fw.write(sb.toString());
+        closeName(name+">");
+        return true;
     }
 
-    private void printAffineTransform(Object o) {
+    protected boolean printAffineTransform(String name, Object o) {
         assert (!attributePhase);
+        openName(name);
         AffineTransform xForm = (AffineTransform)o;
-        fw.write(
+        fw.write("<"+name+
             " scaleX=\""+xForm.getScaleX()+"\" "+
             "shearX=\""+xForm.getShearX()+"\" "+
             "transX=\""+xForm.getTranslateX()+"\" "+
             "scaleY=\""+xForm.getScaleY()+"\" "+
             "shearY=\""+xForm.getShearY()+"\" "+
             "transY=\""+xForm.getTranslateY()+"\"/>");
+        closeName(name);
+        return true;
     }
 
-    private void printColor(Object o) {
+    protected boolean printColor(String name, Object o) {
         assert (attributePhase);
+        openName(name);
         final int rgb = ((Color)o).getRGB();
-        fw.print("0x");
-        fw.print(trimHex(rgb, 8));
+        fw.print("0x"+trimHex(rgb, 8));
+        closeName(name);
+        return true;
     }
 
-    private void printBufferedImage(Object o) {
+    protected boolean printBufferedImage(String name, Object o) {
         assert (!attributePhase);
+        openName(name);
         BufferedImage bi = (BufferedImage)o;
-        fw.println(" width=\""+bi.getWidth()+"\" height=\""+bi.getHeight()+"\" bands=\""+bi.getColorModel().getNumComponents()+"\"/>");
+        fw.println(" width=\""+bi.getWidth()+"\" height=\""+bi.getHeight()+"\" bands=\""+bi.getColorModel().getNumComponents()+"\"");
+        closeName(name);
+        return true;
     }
 
-    private String trimHex(final long l, final int size) {
+    protected String trimHex(final long l, final int size) {
         final String b = Long.toHexString(l);
         int len = b.length();
         return ZEROS.substring(0, Math.max(0,size-len)) + b.substring(Math.max(0,len-size), len);
index b1cb5a4324b8300669e7fc082601eb3221aa9987..c07323dad671f7e423a10efc7c48780f508fe02b 100644 (file)
@@ -20,11 +20,13 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
 
+import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hslf.record.ExOleObjStg;
-import org.apache.poi.poifs.filesystem.DirectoryEntry;
-import org.apache.poi.poifs.filesystem.FileMagic;
-import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.sl.usermodel.ObjectData;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
@@ -32,7 +34,7 @@ import org.apache.poi.util.POILogger;
 /**
  * A class that represents object data embedded in a slide show.
  */
-public class HSLFObjectData implements ObjectData {
+public class HSLFObjectData implements ObjectData, GenericRecord {
     private static final POILogger LOG = POILogFactory.getLogger(HSLFObjectData.class);
     
     /**
@@ -91,4 +93,14 @@ public class HSLFObjectData implements ObjectData {
     public String getFileName() {
         return null;
     }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return null;
+    }
+
+    @Override
+    public List<? extends GenericRecord> getGenericChildren() {
+        return Collections.singletonList(getExOleObjStg());
+    }
 }
index 1a8061d3c9c99928d5daaced3009e28d469892bd..df3de7229a74bfcf6c0137889940c0a91f3c0473 100644 (file)
@@ -21,17 +21,28 @@ import java.awt.Dimension;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.security.MessageDigest;
-
-import org.apache.poi.hslf.blip.*;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.common.usermodel.GenericRecord;
+import org.apache.poi.hslf.blip.DIB;
+import org.apache.poi.hslf.blip.EMF;
+import org.apache.poi.hslf.blip.JPEG;
+import org.apache.poi.hslf.blip.PICT;
+import org.apache.poi.hslf.blip.PNG;
+import org.apache.poi.hslf.blip.WMF;
 import org.apache.poi.poifs.crypt.CryptoFunctions;
 import org.apache.poi.poifs.crypt.HashAlgorithm;
 import org.apache.poi.sl.usermodel.PictureData;
-import org.apache.poi.util.*;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.Units;
 
 /**
  * A class that represents image data contained in a slide show.
  */
-public abstract class HSLFPictureData implements PictureData {
+public abstract class HSLFPictureData implements PictureData, GenericRecord {
 
     /**
      * Size of the image checksum calculated using MD5 algorithm.
@@ -226,4 +237,19 @@ public abstract class HSLFPictureData implements PictureData {
             Units.pointsToPixel(dim.getHeight())
         );
     }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        final Map<String,Supplier<?>> m = new LinkedHashMap<>();
+        m.put("type", this::getType);
+        m.put("imageDimension", this::getImageDimension);
+        m.put("signature", this::getSignature);
+        m.put("uidInstanceCount", this::getUIDInstanceCount);
+        m.put("offset", this::getOffset);
+        m.put("uid", this::getUID);
+        m.put("checksum", this::getChecksum);
+        m.put("index", this::getIndex);
+        m.put("rawData", this::getRawData);
+        return Collections.unmodifiableMap(m);
+    }
 }
index 490a590d3060c935c0b051444828123da0a9e2d9..5f182d5886ea1ef54ad45881eb1240453c07967f 100644 (file)
@@ -53,6 +53,7 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.sl.usermodel.MasterSheet;
 import org.apache.poi.sl.usermodel.PictureData.PictureType;
 import org.apache.poi.sl.usermodel.SlideShow;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.POILogFactory;
@@ -1168,7 +1169,10 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap
 
        @Override
        public Map<String, Supplier<?>> getGenericProperties() {
-               return null;
+               return GenericRecordUtil.getGenericProperties(
+                       "pictures", this::getPictureData,
+                       "embeddedObjects", this::getEmbeddedObjects
+               );
        }
 
        @Override
index 8b47a299f46029be524268a2d02f734e4ec8bf0a..0a86ef149f78318170b62f1f225788b6d3b456fb 100644 (file)
@@ -86,26 +86,26 @@ public final class TestEscherBSERecord {
         EscherBSERecord record = createRecord();
         String expected =
             "{   /* BSE */\n" +
-            "\t  recordId: -4089 /* 0xf007 */\n" +
-            "\t, version: 1\n" +
-            "\t, instance: 0\n" +
-            "\t, options: 1\n" +
-            "\t, recordSize: 44 /* 0x0000002c */\n" +
-            "\t, blipTypeWin32: 5\n" +
-            "\t, pictureTypeWin32: \"JPEG\"\n" +
-            "\t, blipTypeMacOS: 5\n" +
-            "\t, pictureTypeMacOS: \"JPEG\"\n" +
-            "\t, suid: \"AQIDBAUGBwgJCgsMDQ4PAA==\"\n" +
-            "\t, tag: 1\n" +
-            "\t, size: 0\n" +
-            "\t, ref: 2\n" +
-            "\t, offset: 3\n" +
-            "\t, usage: 4\n" +
-            "\t, name: 5\n" +
-            "\t, unused2: 6\n" +
-            "\t, unused3: 7\n" +
-            "\t, blipRecord: null\n" +
-            "\t, remainingData: \"\"\n" +
+            "\t  \"recordId\": -4089 /* 0xf007 */\n" +
+            "\t, \"version\": 1\n" +
+            "\t, \"instance\": 0\n" +
+            "\t, \"options\": 1\n" +
+            "\t, \"recordSize\": 44 /* 0x0000002c */\n" +
+            "\t, \"blipTypeWin32\": 5\n" +
+            "\t, \"pictureTypeWin32\": \"JPEG\"\n" +
+            "\t, \"blipTypeMacOS\": 5\n" +
+            "\t, \"pictureTypeMacOS\": \"JPEG\"\n" +
+            "\t, \"suid\": \"AQIDBAUGBwgJCgsMDQ4PAA==\"\n" +
+            "\t, \"tag\": 1\n" +
+            "\t, \"size\": 0\n" +
+            "\t, \"ref\": 2\n" +
+            "\t, \"offset\": 3\n" +
+            "\t, \"usage\": 4\n" +
+            "\t, \"name\": 5\n" +
+            "\t, \"unused2\": 6\n" +
+            "\t, \"unused3\": 7\n" +
+            "\t, \"blipRecord\": null\n" +
+            "\t, \"remainingData\": \"\"\n" +
             "}";
         expected = expected.replace("\n", System.getProperty("line.separator"));
         String actual = record.toString();
index 5aa14bf3915858cfbf68b93374e63332ee9248c8..3b0578057509559fbedeced24492ee89ec6a5b93 100644 (file)
@@ -27,12 +27,12 @@ public final class TestEscherBoolProperty {
         EscherBoolProperty p = new EscherBoolProperty(EscherPropertyTypes.GEOMETRY__FILLOK, 1);
         String expected =
             "{   /* GEOMETRY__FILLOK */\n" +
-            "\t  id: 383 /* 0x017f */\n" +
-            "\t, name: \"geometry.fillok\"\n" +
-            "\t, propertyNumber: 383 /* 0x017f */\n" +
-            "\t, propertySize: 6\n" +
-            "\t, flags: 0x17f /*  */ \n" +
-            "\t, value: 1\n" +
+            "\t  \"id\": 383 /* 0x017f */\n" +
+            "\t, \"name\": \"geometry.fillok\"\n" +
+            "\t, \"propertyNumber\": 383 /* 0x017f */\n" +
+            "\t, \"propertySize\": 6\n" +
+            "\t, \"flags\": 383 /*  */ \n" +
+            "\t, \"value\": 1\n" +
             "}";
         expected = expected.replace("\n", System.getProperty("line.separator"));
         assertEquals(expected, p.toString());
index 5278ce990c36f10050497c55a5492dec9b931455..457accfa4d43f421c0309d64413d81ccf9381b1a 100644 (file)
@@ -66,15 +66,15 @@ public final class TestEscherChildAnchorRecord {
     public void testToString(){
         String expected =
             "{   /* CHILD_ANCHOR */\n" +
-            "\t  recordId: -4081 /* 0xf00f */\n" +
-            "\t, version: 1\n" +
-            "\t, instance: 0\n" +
-            "\t, options: 1\n" +
-            "\t, recordSize: 24 /* 0x00000018 */\n" +
-            "\t, x1: 1\n" +
-            "\t, y1: 2\n" +
-            "\t, x2: 3\n" +
-            "\t, y2: 4\n" +
+            "\t  \"recordId\": -4081 /* 0xf00f */\n" +
+            "\t, \"version\": 1\n" +
+            "\t, \"instance\": 0\n" +
+            "\t, \"options\": 1\n" +
+            "\t, \"recordSize\": 24 /* 0x00000018 */\n" +
+            "\t, \"x1\": 1\n" +
+            "\t, \"y1\": 2\n" +
+            "\t, \"x2\": 3\n" +
+            "\t, \"y2\": 4\n" +
             "}";
         expected = expected.replace("\n", System.getProperty("line.separator"));
         assertEquals( expected, createRecord().toString() );
index 64d0a6fd8f23ae8b0b6a0879710f39f17bf841b4..5077118286e9bfee52aec5e137d149047ca6a261 100644 (file)
@@ -72,21 +72,21 @@ public class TestEscherClientAnchorRecord {
     public void testToString() {
         String expected =
             "{   /* CLIENT_ANCHOR */\n" +
-            "\t  recordId: -4080 /* 0xf010 */\n" +
-            "\t, version: 1\n" +
-            "\t, instance: 0\n" +
-            "\t, options: 1\n" +
-            "\t, recordSize: 28 /* 0x0000001c */\n" +
-            "\t, flag: 77 /* 0x004d */\n" +
-            "\t, col1: 55 /* 0x0037 */\n" +
-            "\t, dx1: 33 /* 0x0021 */\n" +
-            "\t, row1: 88 /* 0x0058 */\n" +
-            "\t, dy1: 11 /* 0x000b */\n" +
-            "\t, col2: 44 /* 0x002c */\n" +
-            "\t, dx2: 22 /* 0x0016 */\n" +
-            "\t, row2: 99 /* 0x0063 */\n" +
-            "\t, dy2: 66 /* 0x0042 */\n" +
-            "\t, remainingData: \"/90=\"\n" +
+            "\t  \"recordId\": -4080 /* 0xf010 */\n" +
+            "\t, \"version\": 1\n" +
+            "\t, \"instance\": 0\n" +
+            "\t, \"options\": 1\n" +
+            "\t, \"recordSize\": 28 /* 0x0000001c */\n" +
+            "\t, \"flag\": 77 /* 0x004d */\n" +
+            "\t, \"col1\": 55 /* 0x0037 */\n" +
+            "\t, \"dx1\": 33 /* 0x0021 */\n" +
+            "\t, \"row1\": 88 /* 0x0058 */\n" +
+            "\t, \"dy1\": 11 /* 0x000b */\n" +
+            "\t, \"col2\": 44 /* 0x002c */\n" +
+            "\t, \"dx2\": 22 /* 0x0016 */\n" +
+            "\t, \"row2\": 99 /* 0x0063 */\n" +
+            "\t, \"dy2\": 66 /* 0x0042 */\n" +
+            "\t, \"remainingData\": \"/90=\"\n" +
             "}";
         expected = expected.replace("\n", System.getProperty("line.separator"));
         assertEquals( expected, createRecord().toString() );
index 63b21b89f4917bbfd37dbca4a02c90e6f9e240fd..3c0285931e5044eded9ba32be68047a941e28b61 100644 (file)
@@ -55,12 +55,12 @@ public class TestEscherClientDataRecord {
     public void testToString() {
         String expected =
             "{   /* CLIENT_DATA */\n" +
-            "\t  recordId: -4079 /* 0xf011 */\n" +
-            "\t, version: 2\n" +
-            "\t, instance: 0\n" +
-            "\t, options: 2\n" +
-            "\t, recordSize: 8\n" +
-            "\t, remainingData: \"\"\n" +
+            "\t  \"recordId\": -4079 /* 0xf011 */\n" +
+            "\t, \"version\": 2\n" +
+            "\t, \"instance\": 0\n" +
+            "\t, \"options\": 2\n" +
+            "\t, \"recordSize\": 8\n" +
+            "\t, \"remainingData\": \"\"\n" +
             "}";
         expected = expected.replace("\n", System.getProperty("line.separator"));
         assertEquals( expected, createRecord().toString() );
index 83244e827353fd2c4826ce6e588004ac1fcd229b..8c263b8bd266a90ceb77c1785458f642024f59bd 100644 (file)
@@ -83,12 +83,12 @@ public final class TestEscherContainerRecord {
                r.setOptions((short) 0x000F);
         String expected =
             "{   /* SP_CONTAINER */\n" +
-                       "\t  recordId: -4092 /* 0xf004 */\n" +
-                       "\t, version: 15 /* 0x000f */\n" +
-                       "\t, instance: 0\n" +
-                       "\t, options: 15 /* 0x000f */\n" +
-                       "\t, recordSize: 8\n" +
-                       "\t, isContainer: true\n" +
+                       "\t  \"recordId\": -4092 /* 0xf004 */\n" +
+                       "\t, \"version\": 15 /* 0x000f */\n" +
+                       "\t, \"instance\": 0\n" +
+                       "\t, \"options\": 15 /* 0x000f */\n" +
+                       "\t, \"recordSize\": 8\n" +
+                       "\t, \"isContainer\": true\n" +
                        "}";
                expected = expected.replace("\n", System.getProperty("line.separator"));
                assertEquals(expected, r.toString());
@@ -101,22 +101,22 @@ public final class TestEscherContainerRecord {
                r.addChildRecord(r2);
                expected =
                "{   /* SP_CONTAINER */\n" +
-                       "\t  recordId: -4092 /* 0xf004 */\n" +
-                       "\t, version: 15 /* 0x000f */\n" +
-                       "\t, instance: 0\n" +
-                       "\t, options: 15 /* 0x000f */\n" +
-                       "\t, recordSize: 16 /* 0x00000010 */\n" +
-                       "\t, isContainer: true\n" +
-                       "\t, children: [\n" +
+                       "\t  \"recordId\": -4092 /* 0xf004 */\n" +
+                       "\t, \"version\": 15 /* 0x000f */\n" +
+                       "\t, \"instance\": 0\n" +
+                       "\t, \"options\": 15 /* 0x000f */\n" +
+                       "\t, \"recordSize\": 16 /* 0x00000010 */\n" +
+                       "\t, \"isContainer\": true\n" +
+                       "\t, \"children\": [\n" +
                        "\t\t{   /* OPT */\n" +
-                       "\t\t\t  recordId: -4085 /* 0xf00b */\n" +
-                       "\t\t\t, version: 3\n" +
-                       "\t\t\t, instance: 0\n" +
-                       "\t\t\t, options: 3\n" +
-                       "\t\t\t, recordSize: 8\n" +
-                       "\t\t\t, isContainer: false\n" +
-                       "\t\t\t, properties: [\n" +
-                       "]\n" +
+                       "\t\t\t  \"recordId\": -4085 /* 0xf00b */\n" +
+                       "\t\t\t, \"version\": 3\n" +
+                       "\t\t\t, \"instance\": 0\n" +
+                       "\t\t\t, \"options\": 3\n" +
+                       "\t\t\t, \"recordSize\": 8\n" +
+                       "\t\t\t, \"isContainer\": false\n" +
+                       "\t\t\t, \"properties\": [\n" +
+                       "\t\t\t]\n" +
                        "\t\t}\n" +
                        "\t]\n" +
                        "}";
@@ -126,33 +126,31 @@ public final class TestEscherContainerRecord {
                r.addChildRecord(r2);
                expected =
                "{   /* SP_CONTAINER */\n" +
-                       "\t  recordId: -4092 /* 0xf004 */\n" +
-                       "\t, version: 15 /* 0x000f */\n" +
-                       "\t, instance: 0\n" +
-                       "\t, options: 15 /* 0x000f */\n" +
-                       "\t, recordSize: 24 /* 0x00000018 */\n" +
-                       "\t, isContainer: true\n" +
-                       "\t, children: [\n" +
+                       "\t  \"recordId\": -4092 /* 0xf004 */\n" +
+                       "\t, \"version\": 15 /* 0x000f */\n" +
+                       "\t, \"instance\": 0\n" +
+                       "\t, \"options\": 15 /* 0x000f */\n" +
+                       "\t, \"recordSize\": 24 /* 0x00000018 */\n" +
+                       "\t, \"isContainer\": true\n" +
+                       "\t, \"children\": [\n" +
                        "\t\t{   /* OPT */\n" +
-                       "\t\t\t  recordId: -4085 /* 0xf00b */\n" +
-                       "\t\t\t, version: 3\n" +
-                       "\t\t\t, instance: 0\n" +
-                       "\t\t\t, options: 3\n" +
-                       "\t\t\t, recordSize: 8\n" +
-                       "\t\t\t, isContainer: false\n" +
-                       "\t\t\t, properties: [\n" +
-                       "]\n" +
-                       "\t\t},\n" +
-                       "\n" +
-                       "\t\t{   /* OPT - index: 1 */\n" +
-                       "\t\t\t  recordId: -4085 /* 0xf00b */\n" +
-                       "\t\t\t, version: 3\n" +
-                       "\t\t\t, instance: 0\n" +
-                       "\t\t\t, options: 3\n" +
-                       "\t\t\t, recordSize: 8\n" +
-                       "\t\t\t, isContainer: false\n" +
-                       "\t\t\t, properties: [\n" +
-                       "]\n" +
+                       "\t\t\t  \"recordId\": -4085 /* 0xf00b */\n" +
+                       "\t\t\t, \"version\": 3\n" +
+                       "\t\t\t, \"instance\": 0\n" +
+                       "\t\t\t, \"options\": 3\n" +
+                       "\t\t\t, \"recordSize\": 8\n" +
+                       "\t\t\t, \"isContainer\": false\n" +
+                       "\t\t\t, \"properties\": [\n" +
+                       "\t\t\t]\n" +
+                       "\t\t},\t\t{   /* OPT - index: 1 */\n" +
+                       "\t\t\t  \"recordId\": -4085 /* 0xf00b */\n" +
+                       "\t\t\t, \"version\": 3\n" +
+                       "\t\t\t, \"instance\": 0\n" +
+                       "\t\t\t, \"options\": 3\n" +
+                       "\t\t\t, \"recordSize\": 8\n" +
+                       "\t\t\t, \"isContainer\": false\n" +
+                       "\t\t\t, \"properties\": [\n" +
+                       "\t\t\t]\n" +
                        "\t\t}\n" +
                        "\t]\n" +
                        "}";
index ac7f4bf0f2dae8e674911c8ce6b42aa55e5be95a..a8735a068ed41f5b07118f025132aabf2fd31cd4 100644 (file)
@@ -59,14 +59,14 @@ public final class TestEscherDgRecord {
     public void testToString() {
         String expected =
             "{   /* DG */\n" +
-            "\t  recordId: -4088 /* 0xf008 */\n" +
-            "\t, version: 0\n" +
-            "\t, instance: 1\n" +
-            "\t, options: 16 /* 0x0010 */\n" +
-            "\t, recordSize: 16 /* 0x00000010 */\n" +
-            "\t, numShapes: 2\n" +
-            "\t, lastMSOSPID: 1025 /* 0x00000401 */\n" +
-            "\t, drawingGroupId: 1\n" +
+            "\t  \"recordId\": -4088 /* 0xf008 */\n" +
+            "\t, \"version\": 0\n" +
+            "\t, \"instance\": 1\n" +
+            "\t, \"options\": 16 /* 0x0010 */\n" +
+            "\t, \"recordSize\": 16 /* 0x00000010 */\n" +
+            "\t, \"numShapes\": 2\n" +
+            "\t, \"lastMSOSPID\": 1025 /* 0x00000401 */\n" +
+            "\t, \"drawingGroupId\": 1\n" +
             "}";
         expected = expected.replace("\n", System.getProperty("line.separator"));
         assertEquals( expected, createRecord().toString() );
index bcd5025c840e0f5e1ab50c7d996ff13f905c1a4d..d06979dab9d828566f86b3be5c3624a15ac77995 100644 (file)
@@ -70,21 +70,20 @@ public final class TestEscherDggRecord {
     public void testToString() {
         String expected =
             "{   /* DGG */\n" +
-            "\t  recordId: -4090 /* 0xf006 */\n" +
-            "\t, version: 0\n" +
-            "\t, instance: 0\n" +
-            "\t, options: 0\n" +
-            "\t, recordSize: 32 /* 0x00000020 */\n" +
-            "\t, fileIdClusters: [\n" +
-            "\n" +
+            "\t  \"recordId\": -4090 /* 0xf006 */\n" +
+            "\t, \"version\": 0\n" +
+            "\t, \"instance\": 0\n" +
+            "\t, \"options\": 0\n" +
+            "\t, \"recordSize\": 32 /* 0x00000020 */\n" +
+            "\t, \"fileIdClusters\": [\n" +
             "\t{   /* FileIdCluster */\n" +
-            "\t\t  drawingGroupId: 1\n" +
-            "\t\t, numShapeIdUsed: 2\n" +
-            "\t}]\n" +
-            "\t, shapeIdMax: 1026 /* 0x00000402 */\n" +
-            "\t, numIdClusters: 2\n" +
-            "\t, numShapesSaved: 2\n" +
-            "\t, drawingsSaved: 1\n" +
+            "\t\t  \"drawingGroupId\": 1\n" +
+            "\t\t, \"numShapeIdUsed\": 2\n" +
+            "\t}\t]\n" +
+            "\t, \"shapeIdMax\": 1026 /* 0x00000402 */\n" +
+            "\t, \"numIdClusters\": 2\n" +
+            "\t, \"numShapesSaved\": 2\n" +
+            "\t, \"drawingsSaved\": 1\n" +
             "}";
         expected = expected.replace("\n", System.getProperty("line.separator"));
         assertEquals( expected, createRecord().toString() );
index 96c57e6ec6ddd61996ecabfb4e46181d0063e737..33af04b3bad9ad0e2d167cc704cca41eb47db467 100644 (file)
@@ -148,22 +148,21 @@ public final class TestEscherOptRecord {
         r.addEscherProperty(prop1);
         String expected =
             "{   /* OPT */\n" +
-            "\t  recordId: -4085 /* 0xf00b */\n" +
-            "\t, version: 3\n" +
-            "\t, instance: 1\n" +
-            "\t, options: 19 /* 0x0013 */\n" +
-            "\t, recordSize: 14 /* 0x0000000e */\n" +
-            "\t, isContainer: false\n" +
-            "\t, properties: [\n" +
-            "\n" +
+            "\t  \"recordId\": -4085 /* 0xf00b */\n" +
+            "\t, \"version\": 3\n" +
+            "\t, \"instance\": 1\n" +
+            "\t, \"options\": 19 /* 0x0013 */\n" +
+            "\t, \"recordSize\": 14 /* 0x0000000e */\n" +
+            "\t, \"isContainer\": false\n" +
+            "\t, \"properties\": [\n" +
             "\t{   /* GEOMETRY__FILLOK */\n" +
-            "\t\t  id: 383 /* 0x017f */\n" +
-            "\t\t, name: \"geometry.fillok\"\n" +
-            "\t\t, propertyNumber: 383 /* 0x017f */\n" +
-            "\t\t, propertySize: 6\n" +
-            "\t\t, flags: 0x17f /*  */ \n" +
-            "\t\t, value: 1\n" +
-            "\t}]\n" +
+            "\t\t  \"id\": 383 /* 0x017f */\n" +
+            "\t\t, \"name\": \"geometry.fillok\"\n" +
+            "\t\t, \"propertyNumber\": 383 /* 0x017f */\n" +
+            "\t\t, \"propertySize\": 6\n" +
+            "\t\t, \"flags\": 383 /*  */ \n" +
+            "\t\t, \"value\": 1\n" +
+            "\t}\t]\n" +
             "}";
         expected = expected.replace("\n", System.getProperty("line.separator"));
         assertEquals( expected, r.toString());
index 099022877f5f1182fef1d783f0c469c1b1cbb4d6..786cf0917b13039aba61a4b5622583a13a39eebc 100644 (file)
@@ -59,14 +59,14 @@ public class TestEscherSpRecord {
     public void testToString() {
         String expected =
             "{   /* SP */\n" +
-            "\t  recordId: -4086 /* 0xf00a */\n" +
-            "\t, version: 2\n" +
-            "\t, instance: 0\n" +
-            "\t, options: 2\n" +
-            "\t, recordSize: 16 /* 0x00000010 */\n" +
-            "\t, shapeType: 0\n" +
-            "\t, shapeId: 1024 /* 0x00000400 */\n" +
-            "\t, flags: 0x5 /* GROUP | PATRIARCH */ \n" +
+            "\t  \"recordId\": -4086 /* 0xf00a */\n" +
+            "\t, \"version\": 2\n" +
+            "\t, \"instance\": 0\n" +
+            "\t, \"options\": 2\n" +
+            "\t, \"recordSize\": 16 /* 0x00000010 */\n" +
+            "\t, \"shapeType\": 0\n" +
+            "\t, \"shapeId\": 1024 /* 0x00000400 */\n" +
+            "\t, \"flags\": 5 /* GROUP | PATRIARCH */ \n" +
             "}";
         expected = expected.replace("\n", System.getProperty("line.separator"));
         assertEquals( expected, createRecord().toString() );
index 6c04df66ecaa2ba4caa2af6ecba03d67d9646f65..0e8e356ff2590506f1a7c9d4768ad1c17f917e1b 100644 (file)
@@ -65,15 +65,15 @@ public final class TestEscherSpgrRecord {
     public void testToString() {
         String expected =
             "{   /* SPGR */\n" +
-            "\t  recordId: -4087 /* 0xf009 */\n" +
-            "\t, version: 0\n" +
-            "\t, instance: 1\n" +
-            "\t, options: 16 /* 0x0010 */\n" +
-            "\t, recordSize: 24 /* 0x00000018 */\n" +
-            "\t, rectX1: 1\n" +
-            "\t, rectY1: 2\n" +
-            "\t, rectX2: 3\n" +
-            "\t, rectY2: 4\n" +
+            "\t  \"recordId\": -4087 /* 0xf009 */\n" +
+            "\t, \"version\": 0\n" +
+            "\t, \"instance\": 1\n" +
+            "\t, \"options\": 16 /* 0x0010 */\n" +
+            "\t, \"recordSize\": 24 /* 0x00000018 */\n" +
+            "\t, \"rectX1\": 1\n" +
+            "\t, \"rectY1\": 2\n" +
+            "\t, \"rectX2\": 3\n" +
+            "\t, \"rectY2\": 4\n" +
             "}";
         expected = expected.replace("\n", System.getProperty("line.separator"));
         assertEquals( expected, createRecord().toString() );
index 7571dcd6fe7d93a466a47b1445936c1e68bc0a62..6df9fd6122271dcbe14fc037d1db69da65bc1acd 100644 (file)
@@ -65,15 +65,15 @@ public final class TestEscherSplitMenuColorsRecord {
     public void testToString() {
         String expected =
             "{   /* SPLIT_MENU_COLORS */\n" +
-            "\t  recordId: -3810 /* 0xf11e */\n" +
-            "\t, version: 0\n" +
-            "\t, instance: 4\n" +
-            "\t, options: 64 /* 0x0040 */\n" +
-            "\t, recordSize: 24 /* 0x00000018 */\n" +
-            "\t, color1: 1026 /* 0x00000402 */\n" +
-            "\t, color2: 2\n" +
-            "\t, color3: 2\n" +
-            "\t, color4: 1\n" +
+            "\t  \"recordId\": -3810 /* 0xf11e */\n" +
+            "\t, \"version\": 0\n" +
+            "\t, \"instance\": 4\n" +
+            "\t, \"options\": 64 /* 0x0040 */\n" +
+            "\t, \"recordSize\": 24 /* 0x00000018 */\n" +
+            "\t, \"color1\": 1026 /* 0x00000402 */\n" +
+            "\t, \"color2\": 2\n" +
+            "\t, \"color3\": 2\n" +
+            "\t, \"color4\": 1\n" +
             "}";
         expected = expected.replace("\n", System.getProperty("line.separator"));
         assertEquals( expected, createRecord().toString() );
index 5a9c1aa45949e1a44163303c8005918bc9cd97ea..d354c5d887e1e04c161afa6f355bd4e49fd4a5b2 100644 (file)
@@ -152,12 +152,12 @@ public final class TestUnknownEscherRecord {
         r.serialize( 0, data, new NullEscherSerializationListener() );
         String expected =
             "{   /* UNKNOWN */\n" +
-            "\t  recordId: -3822 /* 0xf112 */\n" +
-            "\t, version: 4\n" +
-            "\t, instance: 291 /* 0x0123 */\n" +
-            "\t, options: 4660 /* 0x1234 */\n" +
-            "\t, recordSize: 8\n" +
-            "\t, data: \"\"\n" +
+            "\t  \"recordId\": -3822 /* 0xf112 */\n" +
+            "\t, \"version\": 4\n" +
+            "\t, \"instance\": 291 /* 0x0123 */\n" +
+            "\t, \"options\": 4660 /* 0x1234 */\n" +
+            "\t, \"recordSize\": 8\n" +
+            "\t, \"data\": \"\"\n" +
             "}";
         expected = expected.replace("\n", System.getProperty("line.separator"));
         assertEquals(expected, r.toString() );
index 252273076cc4c128f853b6e7b1e67ac77aceebca..b47443b1b8b2223875654c5fa0639d0c972841e1 100644 (file)
@@ -92,11 +92,11 @@ public class TestPolygon {
             "<flags flag=\"0x8145\" description=\"IS_COMPLEX\"/>" +
             "<data>BQAFAPD/AAAFAFoABQAyACwAWgBYAAAABQA=</data>" +
             "<elements>" +
-            "<item>>AAAFAA==</item>" +
-            "<item>>WgAFAA==</item>" +
-            "<item>>MgAsAA==</item>" +
-            "<item>>WgBYAA==</item>" +
-            "<item>>AAAFAA==</item>" +
+            "<item>AAAFAA==</item>" +
+            "<item>WgAFAA==</item>" +
+            "<item>MgAsAA==</item>" +
+            "<item>WgBYAA==</item>" +
+            "<item>AAAFAA==</item>" +
             "</elements>" +
             "</record>";
         String actual = verticesProp1.toXml("").replaceAll("[\r\n\t]","");
@@ -115,10 +115,10 @@ public class TestPolygon {
             "<flags flag=\"0x8145\" description=\"IS_COMPLEX\"/>" +
             "<data>BAAEAPD/AQAEAAIABQADAAYAAQAEAA==</data>" +
             "<elements>" +
-            "<item>>AQAEAA==</item>" +
-            "<item>>AgAFAA==</item>" +
-            "<item>>AwAGAA==</item>" +
-            "<item>>AQAEAA==</item>" +
+            "<item>AQAEAA==</item>" +
+            "<item>AgAFAA==</item>" +
+            "<item>AwAGAA==</item>" +
+            "<item>AQAEAA==</item>" +
             "</elements></record>";
         actual = verticesProp1.toXml("").replaceAll("[\r\n\t]","");