#63745 - Make GenericRecordJsonWriter Json-conformant

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1868952 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2019-10-25 20:00:06 +00:00
parent 468346fca8
commit 6e32d853be
19 changed files with 612 additions and 424 deletions

View File

@ -40,25 +40,39 @@ import java.nio.charset.StandardCharsets;
import java.util.AbstractMap; import java.util.AbstractMap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Base64;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.xml.bind.DatatypeConverter;
import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.util.GenericRecordUtil.AnnotatedFlag; import org.apache.poi.util.GenericRecordUtil.AnnotatedFlag;
@SuppressWarnings({"UnusedReturnValue", "WeakerAccess"})
@Beta @Beta
public class GenericRecordJsonWriter implements Closeable { public class GenericRecordJsonWriter implements Closeable {
private static final String TABS; private static final String TABS;
private static final String ZEROS = "0000000000000000"; private static final String ZEROS = "0000000000000000";
private static final Pattern ESC_CHARS = Pattern.compile("[\"\\p{Cntrl}\\\\]"); 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 { static {
char[] t = new char[255]; char[] t = new char[255];
@ -81,22 +95,25 @@ public class GenericRecordJsonWriter implements Closeable {
handler(Object.class, GenericRecordJsonWriter::printObject); 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)); handler.add(new AbstractMap.SimpleEntry<>(c,printer));
} }
private final PrintWriter fw; protected final AppendableWriter aw;
private int indent = 0; protected final PrintWriter fw;
private boolean withComments = true; protected int indent = 0;
private int childIndex = 0; protected boolean withComments = true;
protected int childIndex = 0;
public GenericRecordJsonWriter(File fileName) throws IOException { public GenericRecordJsonWriter(File fileName) throws IOException {
OutputStream os = ("null".equals(fileName.getName())) ? new NullOutputStream() : new FileOutputStream(fileName); 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) { public GenericRecordJsonWriter(Appendable buffer) {
fw = new PrintWriter(new AppendableWriter(buffer)); aw = new AppendableWriter(buffer);
fw = new PrintWriter(aw);
} }
public static String marshal(GenericRecord record) { public static String marshal(GenericRecord record) {
@ -123,7 +140,7 @@ public class GenericRecordJsonWriter implements Closeable {
fw.close(); fw.close();
} }
private String tabs() { protected String tabs() {
return TABS.substring(0, Math.min(indent, TABS.length())); return TABS.substring(0, Math.min(indent, TABS.length()));
} }
@ -144,81 +161,103 @@ public class GenericRecordJsonWriter implements Closeable {
} }
fw.println(); fw.println();
Map<String, Supplier<?>> prop = record.getGenericProperties(); boolean hasProperties = writeProperties(record);
if (prop != null) {
final int oldChildIndex = childIndex;
childIndex = 0;
prop.forEach(this::writeProp);
childIndex = oldChildIndex;
}
fw.println(); fw.println();
List<? extends GenericRecord> list = record.getGenericChildren();
if (list != null && !list.isEmpty()) { writeChildren(record, hasProperties);
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("]");
fw.println();
indent--;
}
fw.append(tabs); fw.append(tabs);
fw.append("}"); fw.append("}");
} }
protected boolean writeProperties(GenericRecord record) {
Map<String, Supplier<?>> prop = record.getGenericProperties();
if (prop == null || prop.isEmpty()) {
return false;
}
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()) {
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();
fw.println(tabs() + "]");
}
indent--;
return cnt > 0;
}
public void writeError(String errorMsg) { public void writeError(String errorMsg) {
fw.append("{ error: "); fw.append("{ error: ");
printObject(errorMsg); printObject("error", errorMsg);
fw.append(" }"); fw.append(" }");
} }
private void writeProp(String k, Supplier<?> v) { protected boolean writeProp(String name, Supplier<?> value) {
final boolean isNext = (childIndex++>0); final boolean isNext = (childIndex>0);
if (isNext) { aw.setHoldBack(isNext ? "\n" + tabs() + "\t, " : tabs() + "\t ");
fw.println();
}
fw.write(tabs());
fw.write('\t');
fw.write(isNext ? ", " : " ");
fw.write(k);
fw.write(": ");
final int oldChildIndex = childIndex; final int oldChildIndex = childIndex;
childIndex = 0; childIndex = 0;
writeValue(v.get()); boolean written = writeValue(name, value.get());
childIndex = oldChildIndex; 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) { if (childIndex > 0) {
fw.println(','); aw.setHoldBack(",");
}
if (o == null) {
fw.write("null");
} else {
handler.stream().
filter(h -> matchInstanceOrArray(h.getKey(), o)).
findFirst().
ifPresent(h -> h.getValue().accept(this, o));
} }
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()); 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; Number n = (Number)o;
fw.print(n.toString()); printName(name);
fw.print(n.longValue());
final int size; final int size;
if (n instanceof Byte) { if (n instanceof Byte) {
@ -239,65 +278,81 @@ public class GenericRecordJsonWriter implements Closeable {
fw.write(trimHex(l, size)); fw.write(trimHex(l, size));
fw.write(" */"); fw.write(" */");
} }
return true;
} }
private void printBoolean(Object o) { protected boolean printBoolean(String name, Object o) {
printName(name);
fw.write(((Boolean)o).toString()); fw.write(((Boolean)o).toString());
return true;
} }
private void printList(Object o) { protected boolean printList(String name, Object o) {
fw.println('['); printName(name);
fw.println("[");
int oldChildIndex = childIndex; int oldChildIndex = childIndex;
childIndex = 0; childIndex = 0;
//noinspection unchecked //noinspection unchecked
((List)o).forEach(e -> { writeValue(e); childIndex++; }); ((List)o).forEach(e -> { writeValue(null, e); childIndex++; });
childIndex = oldChildIndex; childIndex = oldChildIndex;
fw.write(']'); fw.write(tabs() + "\t]");
return true;
} }
private void printGenericRecord(Object o) { protected boolean printGenericRecord(String name, Object o) {
fw.println(); printName(name);
this.indent++; this.indent++;
write((GenericRecord) o); write((GenericRecord) o);
this.indent--; this.indent--;
return true;
} }
private void printAnnotatedFlag(Object o) { protected boolean printAnnotatedFlag(String name, Object o) {
printName(name);
AnnotatedFlag af = (AnnotatedFlag) o; AnnotatedFlag af = (AnnotatedFlag) o;
fw.write("0x"); fw.print(af.getValue().get().longValue());
fw.write(Long.toHexString(af.getValue().get().longValue()));
if (withComments) { if (withComments) {
fw.write(" /* "); fw.write(" /* ");
fw.write(af.getDescription()); fw.write(af.getDescription());
fw.write(" */ "); fw.write(" */ ");
} }
return true;
} }
private void printBytes(Object o) { protected boolean printBytes(String name, Object o) {
printName(name);
fw.write('"'); fw.write('"');
fw.write(DatatypeConverter.printBase64Binary((byte[]) o)); fw.write(Base64.getEncoder().encodeToString((byte[]) o));
fw.write('"'); fw.write('"');
return true;
} }
private void printPoint(Object o) { protected boolean printPoint(String name, Object o) {
printName(name);
Point2D p = (Point2D)o; 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; 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; 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 PathIterator iter = ((Path2D)o).getPathIterator(null);
final double[] pnts = new double[6]; final double[] pnts = new double[6];
fw.print("["); fw.write("[");
indent += 2; indent += 2;
String t = tabs(); String t = tabs();
@ -309,19 +364,19 @@ public class GenericRecordJsonWriter implements Closeable {
fw.print(t); fw.print(t);
isNext = true; isNext = true;
final int segType = iter.currentSegment(pnts); final int segType = iter.currentSegment(pnts);
fw.append("{ type: "); fw.append("{ \"type\": ");
switch (segType) { switch (segType) {
case PathIterator.SEG_MOVETO: case PathIterator.SEG_MOVETO:
fw.write("'move', x: "+pnts[0]+", y: "+pnts[1]); fw.write("'move', \"x\": "+pnts[0]+", \"y\": "+pnts[1]);
break; break;
case PathIterator.SEG_LINETO: case PathIterator.SEG_LINETO:
fw.write("'lineto', x: "+pnts[0]+", y: "+pnts[1]); fw.write("'lineto', \"x\": "+pnts[0]+", \"y\": "+pnts[1]);
break; break;
case PathIterator.SEG_QUADTO: 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; break;
case PathIterator.SEG_CUBICTO: 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; break;
case PathIterator.SEG_CLOSE: case PathIterator.SEG_CLOSE:
fw.write("'close'"); fw.write("'close'");
@ -332,9 +387,11 @@ public class GenericRecordJsonWriter implements Closeable {
} }
fw.write("]"); fw.write("]");
return true;
} }
private void printObject(Object o) { protected boolean printObject(String name, Object o) {
printName(name);
fw.write('"'); fw.write('"');
final Matcher m = ESC_CHARS.matcher(o.toString()); final Matcher m = ESC_CHARS.matcher(o.toString());
@ -374,20 +431,25 @@ public class GenericRecordJsonWriter implements Closeable {
fw.write(sb.toString()); fw.write(sb.toString());
fw.write('"'); fw.write('"');
return true;
} }
private void printAffineTransform(Object o) { protected boolean printAffineTransform(String name, Object o) {
printName(name);
AffineTransform xForm = (AffineTransform)o; AffineTransform xForm = (AffineTransform)o;
fw.write( fw.write(
"{ scaleX: "+xForm.getScaleX()+ "{ \"scaleX\": "+xForm.getScaleX()+
", shearX: "+xForm.getShearX()+ ", \"shearX\": "+xForm.getShearX()+
", transX: "+xForm.getTranslateX()+ ", \"transX\": "+xForm.getTranslateX()+
", scaleY: "+xForm.getScaleY()+ ", \"scaleY\": "+xForm.getScaleY()+
", shearY: "+xForm.getShearY()+ ", \"shearY\": "+xForm.getShearY()+
", transY: "+xForm.getTranslateY()+" }"); ", \"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(); final int rgb = ((Color)o).getRGB();
fw.print(rgb); fw.print(rgb);
@ -396,17 +458,20 @@ public class GenericRecordJsonWriter implements Closeable {
fw.write(trimHex(rgb, 8)); fw.write(trimHex(rgb, 8));
fw.write(" */"); fw.write(" */");
} }
return true;
} }
private void printArray(Object o) { protected boolean printArray(String name, Object o) {
fw.println('['); printName(name);
fw.write("[");
int length = Array.getLength(o); int length = Array.getLength(o);
final int oldChildIndex = childIndex; final int oldChildIndex = childIndex;
for (childIndex=0; childIndex<length; childIndex++) { for (childIndex=0; childIndex<length; childIndex++) {
writeValue(Array.get(o, childIndex)); writeValue(null, Array.get(o, childIndex));
} }
childIndex = oldChildIndex; childIndex = oldChildIndex;
fw.write(']'); fw.write(tabs() + "\t]");
return true;
} }
static String trimHex(final long l, final int size) { static String trimHex(final long l, final int size) {
@ -433,30 +498,58 @@ public class GenericRecordJsonWriter implements Closeable {
} }
static class AppendableWriter extends Writer { static class AppendableWriter extends Writer {
private Appendable buffer; private final Appendable appender;
private final Writer writer;
private String holdBack;
AppendableWriter(Appendable buffer) { AppendableWriter(Appendable buffer) {
super(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 @Override
public void write(char[] cbuf, int off, int len) throws IOException { 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 @Override
public void flush() throws IOException { public void flush() throws IOException {
if (buffer instanceof Flushable) { Object o = (appender != null) ? appender : writer;
((Flushable)buffer).flush(); if (o instanceof Flushable) {
((Flushable)o).flush();
} }
} }
@Override @Override
public void close() throws IOException { public void close() throws IOException {
flush(); flush();
if (buffer instanceof Closeable) { Object o = (appender != null) ? appender : writer;
((Closeable)buffer).close(); if (o instanceof Closeable) {
((Closeable)o).close();
} }
} }
} }

View File

@ -39,27 +39,41 @@ import java.nio.charset.StandardCharsets;
import java.util.AbstractMap; import java.util.AbstractMap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Base64;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.xml.bind.DatatypeConverter;
import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.util.GenericRecordJsonWriter.AppendableWriter; import org.apache.poi.util.GenericRecordJsonWriter.AppendableWriter;
import org.apache.poi.util.GenericRecordJsonWriter.NullOutputStream; import org.apache.poi.util.GenericRecordJsonWriter.NullOutputStream;
@SuppressWarnings("WeakerAccess")
public class GenericRecordXmlWriter implements Closeable { public class GenericRecordXmlWriter implements Closeable {
private static final String TABS; private static final String TABS;
private static final String ZEROS = "0000000000000000"; private static final String ZEROS = "0000000000000000";
private static final Pattern ESC_CHARS = Pattern.compile("[<>&'\"\\p{Cntrl}]"); 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 { static {
char[] t = new char[255]; char[] t = new char[255];
@ -83,7 +97,7 @@ public class GenericRecordXmlWriter implements Closeable {
handler(Object.class, GenericRecordXmlWriter::printObject); 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)); handler.add(new AbstractMap.SimpleEntry<>(c, printer));
} }
@ -126,15 +140,15 @@ public class GenericRecordXmlWriter implements Closeable {
fw.close(); fw.close();
} }
private String tabs() { protected String tabs() {
return TABS.substring(0, Math.min(indent, TABS.length())); return TABS.substring(0, Math.min(indent, TABS.length()));
} }
public void write(GenericRecord record) { 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(); final String tabs = tabs();
Enum type = record.getGenericRecordType(); Enum type = record.getGenericRecordType();
String recordName = (type != null) ? type.name() : record.getClass().getSimpleName(); String recordName = (type != null) ? type.name() : record.getClass().getSimpleName();
@ -148,49 +162,16 @@ public class GenericRecordXmlWriter implements Closeable {
fw.append("\""); fw.append("\"");
} }
boolean hasChildren = false;
Map<String, Supplier<?>> prop = record.getGenericProperties(); attributePhase = true;
if (prop != null) {
final int oldChildIndex = childIndex; boolean hasComplex = writeProperties(record);
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 = false; attributePhase = false;
List<? extends GenericRecord> list = record.getGenericChildren(); hasComplex |= writeChildren(record, hasComplex);
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--;
}
if (hasChildren) { if (hasComplex) {
fw.append(tabs); fw.append(tabs);
fw.println("</" + name + ">"); fw.println("</" + name + ">");
} else { } else {
@ -198,13 +179,61 @@ public class GenericRecordXmlWriter implements Closeable {
} }
} }
public void writeError(String errorMsg) { protected boolean writeProperties(GenericRecord record) {
fw.append("<error>"); Map<String, Supplier<?>> prop = record.getGenericProperties();
printObject(errorMsg); if (prop == null || prop.isEmpty()) {
fw.append("</error>"); 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();
} }
private Stream<Map.Entry<String,Supplier<?>>> writeProp(Map.Entry<String,Supplier<?>> me) { 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) {
printObject("error", errorMsg);
}
protected Stream<Map.Entry<String,Supplier<?>>> writeProp(Map.Entry<String,Supplier<?>> me) {
Object obj = me.getValue().get(); Object obj = me.getValue().get();
if (obj == null) { if (obj == null) {
return Stream.empty(); return Stream.empty();
@ -223,7 +252,7 @@ public class GenericRecordXmlWriter implements Closeable {
return Stream.empty(); return Stream.empty();
} }
private static boolean isComplex(Object obj) { protected static boolean isComplex(Object obj) {
return !( return !(
obj instanceof Number || obj instanceof Number ||
obj instanceof Boolean || obj instanceof Boolean ||
@ -233,100 +262,101 @@ public class GenericRecordXmlWriter implements Closeable {
obj instanceof Enum); obj instanceof Enum);
} }
private void writeValue(String key, Object o) { protected void writeValue(String name, Object value) {
assert(key != null); assert(name != null);
if (o instanceof GenericRecord) { if (value instanceof GenericRecord) {
printGenericRecord((GenericRecord)o, key); printGenericRecord(name, value);
} else if (o != null) { } else if (value != null) {
if (key.endsWith(">")) { if (name.endsWith(">")) {
fw.print("\t"); fw.print("\t");
} }
fw.print(attributePhase ? " " + key + "=\"" : tabs()+"<" + key);
if (key.endsWith(">")) {
fw.println();
}
handler.stream(). handler.stream().
filter(h -> matchInstanceOrArray(h.getKey(), o)). filter(h -> matchInstanceOrArray(h.getKey(), value)).
findFirst(). 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()); return key.isInstance(instance) || (Array.class.equals(key) && instance.getClass().isArray());
} }
private void printNumber(Object o) {
protected void openName(String name) {
name = name.replace(">>", ">");
if (attributePhase) {
fw.print(" " + name.replace('>',' ').trim() + "=\"");
} else {
fw.print(tabs() + "<" + name);
if (name.endsWith(">")) {
fw.println();
}
}
}
protected void closeName(String name) {
name = name.replace(">>", ">");
if (attributePhase) {
fw.append("\"");
} else {
if (name.endsWith(">")) {
fw.println(tabs() + "\t</" + name);
} else {
fw.println("/>");
}
}
}
protected boolean printNumber(String name, Object o) {
assert(attributePhase); assert(attributePhase);
openName(name);
Number n = (Number)o; Number n = (Number)o;
fw.print(n.toString()); fw.print(n.toString());
closeName(name);
if (attributePhase) { return true;
return;
}
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;
} else {
size = -1;
}
long l = n.longValue();
if (withComments && size > 0 && (l < 0 || l > 9)) {
fw.write(" /* 0x");
fw.write(trimHex(l, size));
fw.write(" */");
}
} }
private void printBoolean(Object o) { protected boolean printBoolean(String name, Object o) {
assert (attributePhase);
openName(name);
fw.write(((Boolean)o).toString()); fw.write(((Boolean)o).toString());
closeName(name);
return true;
} }
private void printList(Object o) { protected boolean printList(String name, Object o) {
assert (!attributePhase); assert (!attributePhase);
fw.println(">"); openName(name+">");
int oldChildIndex = childIndex; int oldChildIndex = childIndex;
childIndex = 0; childIndex = 0;
//noinspection unchecked //noinspection unchecked
((List)o).forEach(e -> { writeValue("item>", e); childIndex++; }); ((List)o).forEach(e -> { writeValue("item>", e); childIndex++; });
childIndex = oldChildIndex; childIndex = oldChildIndex;
closeName(name+">");
return true;
} }
private void printArray(Object o) { protected boolean printArray(String name, Object o) {
assert (!attributePhase); assert (!attributePhase);
fw.println(">"); openName(name+">");
int length = Array.getLength(o); int length = Array.getLength(o);
final int oldChildIndex = childIndex; final int oldChildIndex = childIndex;
for (childIndex=0; childIndex<length; childIndex++) { for (childIndex=0; childIndex<length; childIndex++) {
writeValue("item>", Array.get(o, childIndex)); writeValue("item>", Array.get(o, childIndex));
} }
childIndex = oldChildIndex; childIndex = oldChildIndex;
closeName(name+">");
return true;
} }
private void printGenericRecord(Object o, String name) { protected void printGenericRecord(String name, Object value) {
write((GenericRecord) o, name); write(name, (GenericRecord) value);
} }
private void printAnnotatedFlag(Object o) { protected boolean printAnnotatedFlag(String name, Object o) {
assert (!attributePhase); assert (!attributePhase);
GenericRecordUtil.AnnotatedFlag af = (GenericRecordUtil.AnnotatedFlag) o; GenericRecordUtil.AnnotatedFlag af = (GenericRecordUtil.AnnotatedFlag) o;
Number n = af.getValue().get(); Number n = af.getValue().get();
@ -341,6 +371,7 @@ public class GenericRecordXmlWriter implements Closeable {
len = 16; len = 16;
} }
openName(name);
fw.print(" flag=\"0x"); fw.print(" flag=\"0x");
fw.print(trimHex(n.longValue(), len)); fw.print(trimHex(n.longValue(), len));
fw.print('"'); fw.print('"');
@ -349,35 +380,50 @@ public class GenericRecordXmlWriter implements Closeable {
fw.print(af.getDescription()); fw.print(af.getDescription());
fw.print("\""); fw.print("\"");
} }
fw.println("/>"); closeName(name);
return true;
} }
private void printBytes(Object o) { protected boolean printBytes(String name, Object o) {
assert (!attributePhase); assert (!attributePhase);
fw.write(">"); openName(name+">");
fw.write(DatatypeConverter.printBase64Binary((byte[]) o)); 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); assert (!attributePhase);
openName(name);
Point2D p = (Point2D)o; Point2D p = (Point2D)o;
fw.println(" x=\""+p.getX()+"\" y=\""+p.getY()+"\"/>"); 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); assert (!attributePhase);
openName(name);
Dimension2D p = (Dimension2D)o; Dimension2D p = (Dimension2D)o;
fw.println(" width=\""+p.getWidth()+"\" height=\""+p.getHeight()+"\"/>"); 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); assert (!attributePhase);
openName(name);
Rectangle2D p = (Rectangle2D)o; Rectangle2D p = (Rectangle2D)o;
fw.println(" x=\""+p.getX()+"\" y=\""+p.getY()+"\" width=\""+p.getWidth()+"\" height=\""+p.getHeight()+"\"/>"); 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); assert (!attributePhase);
openName(name+">");
final PathIterator iter = ((Path2D)o).getPathIterator(null); final PathIterator iter = ((Path2D)o).getPathIterator(null);
final double[] pnts = new double[6]; final double[] pnts = new double[6];
@ -385,10 +431,8 @@ public class GenericRecordXmlWriter implements Closeable {
String t = tabs(); String t = tabs();
indent -= 2; indent -= 2;
boolean isNext = false;
while (!iter.isDone()) { while (!iter.isDone()) {
fw.print(t); fw.print(t);
isNext = true;
final int segType = iter.currentSegment(pnts); final int segType = iter.currentSegment(pnts);
fw.print("<pathelement "); fw.print("<pathelement ");
switch (segType) { switch (segType) {
@ -412,9 +456,12 @@ public class GenericRecordXmlWriter implements Closeable {
iter.next(); 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 Matcher m = ESC_CHARS.matcher(o.toString());
final StringBuffer sb = new StringBuffer(); final StringBuffer sb = new StringBuffer();
while (m.find()) { while (m.find()) {
@ -444,34 +491,44 @@ public class GenericRecordXmlWriter implements Closeable {
} }
m.appendTail(sb); m.appendTail(sb);
fw.write(sb.toString()); fw.write(sb.toString());
closeName(name+">");
return true;
} }
private void printAffineTransform(Object o) { protected boolean printAffineTransform(String name, Object o) {
assert (!attributePhase); assert (!attributePhase);
openName(name);
AffineTransform xForm = (AffineTransform)o; AffineTransform xForm = (AffineTransform)o;
fw.write( fw.write("<"+name+
" scaleX=\""+xForm.getScaleX()+"\" "+ " scaleX=\""+xForm.getScaleX()+"\" "+
"shearX=\""+xForm.getShearX()+"\" "+ "shearX=\""+xForm.getShearX()+"\" "+
"transX=\""+xForm.getTranslateX()+"\" "+ "transX=\""+xForm.getTranslateX()+"\" "+
"scaleY=\""+xForm.getScaleY()+"\" "+ "scaleY=\""+xForm.getScaleY()+"\" "+
"shearY=\""+xForm.getShearY()+"\" "+ "shearY=\""+xForm.getShearY()+"\" "+
"transY=\""+xForm.getTranslateY()+"\"/>"); "transY=\""+xForm.getTranslateY()+"\"/>");
closeName(name);
return true;
} }
private void printColor(Object o) { protected boolean printColor(String name, Object o) {
assert (attributePhase); assert (attributePhase);
openName(name);
final int rgb = ((Color)o).getRGB(); final int rgb = ((Color)o).getRGB();
fw.print("0x"); fw.print("0x"+trimHex(rgb, 8));
fw.print(trimHex(rgb, 8)); closeName(name);
return true;
} }
private void printBufferedImage(Object o) { protected boolean printBufferedImage(String name, Object o) {
assert (!attributePhase); assert (!attributePhase);
openName(name);
BufferedImage bi = (BufferedImage)o; 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); final String b = Long.toHexString(l);
int len = b.length(); int len = b.length();
return ZEROS.substring(0, Math.max(0,size-len)) + b.substring(Math.max(0,len-size), len); return ZEROS.substring(0, Math.max(0,size-len)) + b.substring(Math.max(0,len-size), len);

View File

@ -20,11 +20,13 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; 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.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.sl.usermodel.ObjectData;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; 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. * 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); private static final POILogger LOG = POILogFactory.getLogger(HSLFObjectData.class);
/** /**
@ -91,4 +93,14 @@ public class HSLFObjectData implements ObjectData {
public String getFileName() { public String getFileName() {
return null; return null;
} }
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return null;
}
@Override
public List<? extends GenericRecord> getGenericChildren() {
return Collections.singletonList(getExOleObjStg());
}
} }

View File

@ -21,17 +21,28 @@ import java.awt.Dimension;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.hslf.blip.*; 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.CryptoFunctions;
import org.apache.poi.poifs.crypt.HashAlgorithm; import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.sl.usermodel.PictureData; 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. * 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. * Size of the image checksum calculated using MD5 algorithm.
@ -226,4 +237,19 @@ public abstract class HSLFPictureData implements PictureData {
Units.pointsToPixel(dim.getHeight()) 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);
}
} }

View 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.MasterSheet;
import org.apache.poi.sl.usermodel.PictureData.PictureType; import org.apache.poi.sl.usermodel.PictureData.PictureType;
import org.apache.poi.sl.usermodel.SlideShow; import org.apache.poi.sl.usermodel.SlideShow;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
@ -1168,7 +1169,10 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap
@Override @Override
public Map<String, Supplier<?>> getGenericProperties() { public Map<String, Supplier<?>> getGenericProperties() {
return null; return GenericRecordUtil.getGenericProperties(
"pictures", this::getPictureData,
"embeddedObjects", this::getEmbeddedObjects
);
} }
@Override @Override

View File

@ -86,26 +86,26 @@ public final class TestEscherBSERecord {
EscherBSERecord record = createRecord(); EscherBSERecord record = createRecord();
String expected = String expected =
"{ /* BSE */\n" + "{ /* BSE */\n" +
"\t recordId: -4089 /* 0xf007 */\n" + "\t \"recordId\": -4089 /* 0xf007 */\n" +
"\t, version: 1\n" + "\t, \"version\": 1\n" +
"\t, instance: 0\n" + "\t, \"instance\": 0\n" +
"\t, options: 1\n" + "\t, \"options\": 1\n" +
"\t, recordSize: 44 /* 0x0000002c */\n" + "\t, \"recordSize\": 44 /* 0x0000002c */\n" +
"\t, blipTypeWin32: 5\n" + "\t, \"blipTypeWin32\": 5\n" +
"\t, pictureTypeWin32: \"JPEG\"\n" + "\t, \"pictureTypeWin32\": \"JPEG\"\n" +
"\t, blipTypeMacOS: 5\n" + "\t, \"blipTypeMacOS\": 5\n" +
"\t, pictureTypeMacOS: \"JPEG\"\n" + "\t, \"pictureTypeMacOS\": \"JPEG\"\n" +
"\t, suid: \"AQIDBAUGBwgJCgsMDQ4PAA==\"\n" + "\t, \"suid\": \"AQIDBAUGBwgJCgsMDQ4PAA==\"\n" +
"\t, tag: 1\n" + "\t, \"tag\": 1\n" +
"\t, size: 0\n" + "\t, \"size\": 0\n" +
"\t, ref: 2\n" + "\t, \"ref\": 2\n" +
"\t, offset: 3\n" + "\t, \"offset\": 3\n" +
"\t, usage: 4\n" + "\t, \"usage\": 4\n" +
"\t, name: 5\n" + "\t, \"name\": 5\n" +
"\t, unused2: 6\n" + "\t, \"unused2\": 6\n" +
"\t, unused3: 7\n" + "\t, \"unused3\": 7\n" +
"\t, blipRecord: null\n" + "\t, \"blipRecord\": null\n" +
"\t, remainingData: \"\"\n" + "\t, \"remainingData\": \"\"\n" +
"}"; "}";
expected = expected.replace("\n", System.getProperty("line.separator")); expected = expected.replace("\n", System.getProperty("line.separator"));
String actual = record.toString(); String actual = record.toString();

View File

@ -27,12 +27,12 @@ public final class TestEscherBoolProperty {
EscherBoolProperty p = new EscherBoolProperty(EscherPropertyTypes.GEOMETRY__FILLOK, 1); EscherBoolProperty p = new EscherBoolProperty(EscherPropertyTypes.GEOMETRY__FILLOK, 1);
String expected = String expected =
"{ /* GEOMETRY__FILLOK */\n" + "{ /* GEOMETRY__FILLOK */\n" +
"\t id: 383 /* 0x017f */\n" + "\t \"id\": 383 /* 0x017f */\n" +
"\t, name: \"geometry.fillok\"\n" + "\t, \"name\": \"geometry.fillok\"\n" +
"\t, propertyNumber: 383 /* 0x017f */\n" + "\t, \"propertyNumber\": 383 /* 0x017f */\n" +
"\t, propertySize: 6\n" + "\t, \"propertySize\": 6\n" +
"\t, flags: 0x17f /* */ \n" + "\t, \"flags\": 383 /* */ \n" +
"\t, value: 1\n" + "\t, \"value\": 1\n" +
"}"; "}";
expected = expected.replace("\n", System.getProperty("line.separator")); expected = expected.replace("\n", System.getProperty("line.separator"));
assertEquals(expected, p.toString()); assertEquals(expected, p.toString());

View File

@ -66,15 +66,15 @@ public final class TestEscherChildAnchorRecord {
public void testToString(){ public void testToString(){
String expected = String expected =
"{ /* CHILD_ANCHOR */\n" + "{ /* CHILD_ANCHOR */\n" +
"\t recordId: -4081 /* 0xf00f */\n" + "\t \"recordId\": -4081 /* 0xf00f */\n" +
"\t, version: 1\n" + "\t, \"version\": 1\n" +
"\t, instance: 0\n" + "\t, \"instance\": 0\n" +
"\t, options: 1\n" + "\t, \"options\": 1\n" +
"\t, recordSize: 24 /* 0x00000018 */\n" + "\t, \"recordSize\": 24 /* 0x00000018 */\n" +
"\t, x1: 1\n" + "\t, \"x1\": 1\n" +
"\t, y1: 2\n" + "\t, \"y1\": 2\n" +
"\t, x2: 3\n" + "\t, \"x2\": 3\n" +
"\t, y2: 4\n" + "\t, \"y2\": 4\n" +
"}"; "}";
expected = expected.replace("\n", System.getProperty("line.separator")); expected = expected.replace("\n", System.getProperty("line.separator"));
assertEquals( expected, createRecord().toString() ); assertEquals( expected, createRecord().toString() );

View File

@ -72,21 +72,21 @@ public class TestEscherClientAnchorRecord {
public void testToString() { public void testToString() {
String expected = String expected =
"{ /* CLIENT_ANCHOR */\n" + "{ /* CLIENT_ANCHOR */\n" +
"\t recordId: -4080 /* 0xf010 */\n" + "\t \"recordId\": -4080 /* 0xf010 */\n" +
"\t, version: 1\n" + "\t, \"version\": 1\n" +
"\t, instance: 0\n" + "\t, \"instance\": 0\n" +
"\t, options: 1\n" + "\t, \"options\": 1\n" +
"\t, recordSize: 28 /* 0x0000001c */\n" + "\t, \"recordSize\": 28 /* 0x0000001c */\n" +
"\t, flag: 77 /* 0x004d */\n" + "\t, \"flag\": 77 /* 0x004d */\n" +
"\t, col1: 55 /* 0x0037 */\n" + "\t, \"col1\": 55 /* 0x0037 */\n" +
"\t, dx1: 33 /* 0x0021 */\n" + "\t, \"dx1\": 33 /* 0x0021 */\n" +
"\t, row1: 88 /* 0x0058 */\n" + "\t, \"row1\": 88 /* 0x0058 */\n" +
"\t, dy1: 11 /* 0x000b */\n" + "\t, \"dy1\": 11 /* 0x000b */\n" +
"\t, col2: 44 /* 0x002c */\n" + "\t, \"col2\": 44 /* 0x002c */\n" +
"\t, dx2: 22 /* 0x0016 */\n" + "\t, \"dx2\": 22 /* 0x0016 */\n" +
"\t, row2: 99 /* 0x0063 */\n" + "\t, \"row2\": 99 /* 0x0063 */\n" +
"\t, dy2: 66 /* 0x0042 */\n" + "\t, \"dy2\": 66 /* 0x0042 */\n" +
"\t, remainingData: \"/90=\"\n" + "\t, \"remainingData\": \"/90=\"\n" +
"}"; "}";
expected = expected.replace("\n", System.getProperty("line.separator")); expected = expected.replace("\n", System.getProperty("line.separator"));
assertEquals( expected, createRecord().toString() ); assertEquals( expected, createRecord().toString() );

View File

@ -55,12 +55,12 @@ public class TestEscherClientDataRecord {
public void testToString() { public void testToString() {
String expected = String expected =
"{ /* CLIENT_DATA */\n" + "{ /* CLIENT_DATA */\n" +
"\t recordId: -4079 /* 0xf011 */\n" + "\t \"recordId\": -4079 /* 0xf011 */\n" +
"\t, version: 2\n" + "\t, \"version\": 2\n" +
"\t, instance: 0\n" + "\t, \"instance\": 0\n" +
"\t, options: 2\n" + "\t, \"options\": 2\n" +
"\t, recordSize: 8\n" + "\t, \"recordSize\": 8\n" +
"\t, remainingData: \"\"\n" + "\t, \"remainingData\": \"\"\n" +
"}"; "}";
expected = expected.replace("\n", System.getProperty("line.separator")); expected = expected.replace("\n", System.getProperty("line.separator"));
assertEquals( expected, createRecord().toString() ); assertEquals( expected, createRecord().toString() );

View File

@ -83,12 +83,12 @@ public final class TestEscherContainerRecord {
r.setOptions((short) 0x000F); r.setOptions((short) 0x000F);
String expected = String expected =
"{ /* SP_CONTAINER */\n" + "{ /* SP_CONTAINER */\n" +
"\t recordId: -4092 /* 0xf004 */\n" + "\t \"recordId\": -4092 /* 0xf004 */\n" +
"\t, version: 15 /* 0x000f */\n" + "\t, \"version\": 15 /* 0x000f */\n" +
"\t, instance: 0\n" + "\t, \"instance\": 0\n" +
"\t, options: 15 /* 0x000f */\n" + "\t, \"options\": 15 /* 0x000f */\n" +
"\t, recordSize: 8\n" + "\t, \"recordSize\": 8\n" +
"\t, isContainer: true\n" + "\t, \"isContainer\": true\n" +
"}"; "}";
expected = expected.replace("\n", System.getProperty("line.separator")); expected = expected.replace("\n", System.getProperty("line.separator"));
assertEquals(expected, r.toString()); assertEquals(expected, r.toString());
@ -101,22 +101,22 @@ public final class TestEscherContainerRecord {
r.addChildRecord(r2); r.addChildRecord(r2);
expected = expected =
"{ /* SP_CONTAINER */\n" + "{ /* SP_CONTAINER */\n" +
"\t recordId: -4092 /* 0xf004 */\n" + "\t \"recordId\": -4092 /* 0xf004 */\n" +
"\t, version: 15 /* 0x000f */\n" + "\t, \"version\": 15 /* 0x000f */\n" +
"\t, instance: 0\n" + "\t, \"instance\": 0\n" +
"\t, options: 15 /* 0x000f */\n" + "\t, \"options\": 15 /* 0x000f */\n" +
"\t, recordSize: 16 /* 0x00000010 */\n" + "\t, \"recordSize\": 16 /* 0x00000010 */\n" +
"\t, isContainer: true\n" + "\t, \"isContainer\": true\n" +
"\t, children: [\n" + "\t, \"children\": [\n" +
"\t\t{ /* OPT */\n" + "\t\t{ /* OPT */\n" +
"\t\t\t recordId: -4085 /* 0xf00b */\n" + "\t\t\t \"recordId\": -4085 /* 0xf00b */\n" +
"\t\t\t, version: 3\n" + "\t\t\t, \"version\": 3\n" +
"\t\t\t, instance: 0\n" + "\t\t\t, \"instance\": 0\n" +
"\t\t\t, options: 3\n" + "\t\t\t, \"options\": 3\n" +
"\t\t\t, recordSize: 8\n" + "\t\t\t, \"recordSize\": 8\n" +
"\t\t\t, isContainer: false\n" + "\t\t\t, \"isContainer\": false\n" +
"\t\t\t, properties: [\n" + "\t\t\t, \"properties\": [\n" +
"]\n" + "\t\t\t]\n" +
"\t\t}\n" + "\t\t}\n" +
"\t]\n" + "\t]\n" +
"}"; "}";
@ -126,33 +126,31 @@ public final class TestEscherContainerRecord {
r.addChildRecord(r2); r.addChildRecord(r2);
expected = expected =
"{ /* SP_CONTAINER */\n" + "{ /* SP_CONTAINER */\n" +
"\t recordId: -4092 /* 0xf004 */\n" + "\t \"recordId\": -4092 /* 0xf004 */\n" +
"\t, version: 15 /* 0x000f */\n" + "\t, \"version\": 15 /* 0x000f */\n" +
"\t, instance: 0\n" + "\t, \"instance\": 0\n" +
"\t, options: 15 /* 0x000f */\n" + "\t, \"options\": 15 /* 0x000f */\n" +
"\t, recordSize: 24 /* 0x00000018 */\n" + "\t, \"recordSize\": 24 /* 0x00000018 */\n" +
"\t, isContainer: true\n" + "\t, \"isContainer\": true\n" +
"\t, children: [\n" + "\t, \"children\": [\n" +
"\t\t{ /* OPT */\n" + "\t\t{ /* OPT */\n" +
"\t\t\t recordId: -4085 /* 0xf00b */\n" + "\t\t\t \"recordId\": -4085 /* 0xf00b */\n" +
"\t\t\t, version: 3\n" + "\t\t\t, \"version\": 3\n" +
"\t\t\t, instance: 0\n" + "\t\t\t, \"instance\": 0\n" +
"\t\t\t, options: 3\n" + "\t\t\t, \"options\": 3\n" +
"\t\t\t, recordSize: 8\n" + "\t\t\t, \"recordSize\": 8\n" +
"\t\t\t, isContainer: false\n" + "\t\t\t, \"isContainer\": false\n" +
"\t\t\t, properties: [\n" + "\t\t\t, \"properties\": [\n" +
"]\n" + "\t\t\t]\n" +
"\t\t},\n" + "\t\t},\t\t{ /* OPT - index: 1 */\n" +
"\n" + "\t\t\t \"recordId\": -4085 /* 0xf00b */\n" +
"\t\t{ /* OPT - index: 1 */\n" + "\t\t\t, \"version\": 3\n" +
"\t\t\t recordId: -4085 /* 0xf00b */\n" + "\t\t\t, \"instance\": 0\n" +
"\t\t\t, version: 3\n" + "\t\t\t, \"options\": 3\n" +
"\t\t\t, instance: 0\n" + "\t\t\t, \"recordSize\": 8\n" +
"\t\t\t, options: 3\n" + "\t\t\t, \"isContainer\": false\n" +
"\t\t\t, recordSize: 8\n" + "\t\t\t, \"properties\": [\n" +
"\t\t\t, isContainer: false\n" + "\t\t\t]\n" +
"\t\t\t, properties: [\n" +
"]\n" +
"\t\t}\n" + "\t\t}\n" +
"\t]\n" + "\t]\n" +
"}"; "}";

View File

@ -59,14 +59,14 @@ public final class TestEscherDgRecord {
public void testToString() { public void testToString() {
String expected = String expected =
"{ /* DG */\n" + "{ /* DG */\n" +
"\t recordId: -4088 /* 0xf008 */\n" + "\t \"recordId\": -4088 /* 0xf008 */\n" +
"\t, version: 0\n" + "\t, \"version\": 0\n" +
"\t, instance: 1\n" + "\t, \"instance\": 1\n" +
"\t, options: 16 /* 0x0010 */\n" + "\t, \"options\": 16 /* 0x0010 */\n" +
"\t, recordSize: 16 /* 0x00000010 */\n" + "\t, \"recordSize\": 16 /* 0x00000010 */\n" +
"\t, numShapes: 2\n" + "\t, \"numShapes\": 2\n" +
"\t, lastMSOSPID: 1025 /* 0x00000401 */\n" + "\t, \"lastMSOSPID\": 1025 /* 0x00000401 */\n" +
"\t, drawingGroupId: 1\n" + "\t, \"drawingGroupId\": 1\n" +
"}"; "}";
expected = expected.replace("\n", System.getProperty("line.separator")); expected = expected.replace("\n", System.getProperty("line.separator"));
assertEquals( expected, createRecord().toString() ); assertEquals( expected, createRecord().toString() );

View File

@ -70,21 +70,20 @@ public final class TestEscherDggRecord {
public void testToString() { public void testToString() {
String expected = String expected =
"{ /* DGG */\n" + "{ /* DGG */\n" +
"\t recordId: -4090 /* 0xf006 */\n" + "\t \"recordId\": -4090 /* 0xf006 */\n" +
"\t, version: 0\n" + "\t, \"version\": 0\n" +
"\t, instance: 0\n" + "\t, \"instance\": 0\n" +
"\t, options: 0\n" + "\t, \"options\": 0\n" +
"\t, recordSize: 32 /* 0x00000020 */\n" + "\t, \"recordSize\": 32 /* 0x00000020 */\n" +
"\t, fileIdClusters: [\n" + "\t, \"fileIdClusters\": [\n" +
"\n" +
"\t{ /* FileIdCluster */\n" + "\t{ /* FileIdCluster */\n" +
"\t\t drawingGroupId: 1\n" + "\t\t \"drawingGroupId\": 1\n" +
"\t\t, numShapeIdUsed: 2\n" + "\t\t, \"numShapeIdUsed\": 2\n" +
"\t}]\n" + "\t}\t]\n" +
"\t, shapeIdMax: 1026 /* 0x00000402 */\n" + "\t, \"shapeIdMax\": 1026 /* 0x00000402 */\n" +
"\t, numIdClusters: 2\n" + "\t, \"numIdClusters\": 2\n" +
"\t, numShapesSaved: 2\n" + "\t, \"numShapesSaved\": 2\n" +
"\t, drawingsSaved: 1\n" + "\t, \"drawingsSaved\": 1\n" +
"}"; "}";
expected = expected.replace("\n", System.getProperty("line.separator")); expected = expected.replace("\n", System.getProperty("line.separator"));
assertEquals( expected, createRecord().toString() ); assertEquals( expected, createRecord().toString() );

View File

@ -148,22 +148,21 @@ public final class TestEscherOptRecord {
r.addEscherProperty(prop1); r.addEscherProperty(prop1);
String expected = String expected =
"{ /* OPT */\n" + "{ /* OPT */\n" +
"\t recordId: -4085 /* 0xf00b */\n" + "\t \"recordId\": -4085 /* 0xf00b */\n" +
"\t, version: 3\n" + "\t, \"version\": 3\n" +
"\t, instance: 1\n" + "\t, \"instance\": 1\n" +
"\t, options: 19 /* 0x0013 */\n" + "\t, \"options\": 19 /* 0x0013 */\n" +
"\t, recordSize: 14 /* 0x0000000e */\n" + "\t, \"recordSize\": 14 /* 0x0000000e */\n" +
"\t, isContainer: false\n" + "\t, \"isContainer\": false\n" +
"\t, properties: [\n" + "\t, \"properties\": [\n" +
"\n" +
"\t{ /* GEOMETRY__FILLOK */\n" + "\t{ /* GEOMETRY__FILLOK */\n" +
"\t\t id: 383 /* 0x017f */\n" + "\t\t \"id\": 383 /* 0x017f */\n" +
"\t\t, name: \"geometry.fillok\"\n" + "\t\t, \"name\": \"geometry.fillok\"\n" +
"\t\t, propertyNumber: 383 /* 0x017f */\n" + "\t\t, \"propertyNumber\": 383 /* 0x017f */\n" +
"\t\t, propertySize: 6\n" + "\t\t, \"propertySize\": 6\n" +
"\t\t, flags: 0x17f /* */ \n" + "\t\t, \"flags\": 383 /* */ \n" +
"\t\t, value: 1\n" + "\t\t, \"value\": 1\n" +
"\t}]\n" + "\t}\t]\n" +
"}"; "}";
expected = expected.replace("\n", System.getProperty("line.separator")); expected = expected.replace("\n", System.getProperty("line.separator"));
assertEquals( expected, r.toString()); assertEquals( expected, r.toString());

View File

@ -59,14 +59,14 @@ public class TestEscherSpRecord {
public void testToString() { public void testToString() {
String expected = String expected =
"{ /* SP */\n" + "{ /* SP */\n" +
"\t recordId: -4086 /* 0xf00a */\n" + "\t \"recordId\": -4086 /* 0xf00a */\n" +
"\t, version: 2\n" + "\t, \"version\": 2\n" +
"\t, instance: 0\n" + "\t, \"instance\": 0\n" +
"\t, options: 2\n" + "\t, \"options\": 2\n" +
"\t, recordSize: 16 /* 0x00000010 */\n" + "\t, \"recordSize\": 16 /* 0x00000010 */\n" +
"\t, shapeType: 0\n" + "\t, \"shapeType\": 0\n" +
"\t, shapeId: 1024 /* 0x00000400 */\n" + "\t, \"shapeId\": 1024 /* 0x00000400 */\n" +
"\t, flags: 0x5 /* GROUP | PATRIARCH */ \n" + "\t, \"flags\": 5 /* GROUP | PATRIARCH */ \n" +
"}"; "}";
expected = expected.replace("\n", System.getProperty("line.separator")); expected = expected.replace("\n", System.getProperty("line.separator"));
assertEquals( expected, createRecord().toString() ); assertEquals( expected, createRecord().toString() );

View File

@ -65,15 +65,15 @@ public final class TestEscherSpgrRecord {
public void testToString() { public void testToString() {
String expected = String expected =
"{ /* SPGR */\n" + "{ /* SPGR */\n" +
"\t recordId: -4087 /* 0xf009 */\n" + "\t \"recordId\": -4087 /* 0xf009 */\n" +
"\t, version: 0\n" + "\t, \"version\": 0\n" +
"\t, instance: 1\n" + "\t, \"instance\": 1\n" +
"\t, options: 16 /* 0x0010 */\n" + "\t, \"options\": 16 /* 0x0010 */\n" +
"\t, recordSize: 24 /* 0x00000018 */\n" + "\t, \"recordSize\": 24 /* 0x00000018 */\n" +
"\t, rectX1: 1\n" + "\t, \"rectX1\": 1\n" +
"\t, rectY1: 2\n" + "\t, \"rectY1\": 2\n" +
"\t, rectX2: 3\n" + "\t, \"rectX2\": 3\n" +
"\t, rectY2: 4\n" + "\t, \"rectY2\": 4\n" +
"}"; "}";
expected = expected.replace("\n", System.getProperty("line.separator")); expected = expected.replace("\n", System.getProperty("line.separator"));
assertEquals( expected, createRecord().toString() ); assertEquals( expected, createRecord().toString() );

View File

@ -65,15 +65,15 @@ public final class TestEscherSplitMenuColorsRecord {
public void testToString() { public void testToString() {
String expected = String expected =
"{ /* SPLIT_MENU_COLORS */\n" + "{ /* SPLIT_MENU_COLORS */\n" +
"\t recordId: -3810 /* 0xf11e */\n" + "\t \"recordId\": -3810 /* 0xf11e */\n" +
"\t, version: 0\n" + "\t, \"version\": 0\n" +
"\t, instance: 4\n" + "\t, \"instance\": 4\n" +
"\t, options: 64 /* 0x0040 */\n" + "\t, \"options\": 64 /* 0x0040 */\n" +
"\t, recordSize: 24 /* 0x00000018 */\n" + "\t, \"recordSize\": 24 /* 0x00000018 */\n" +
"\t, color1: 1026 /* 0x00000402 */\n" + "\t, \"color1\": 1026 /* 0x00000402 */\n" +
"\t, color2: 2\n" + "\t, \"color2\": 2\n" +
"\t, color3: 2\n" + "\t, \"color3\": 2\n" +
"\t, color4: 1\n" + "\t, \"color4\": 1\n" +
"}"; "}";
expected = expected.replace("\n", System.getProperty("line.separator")); expected = expected.replace("\n", System.getProperty("line.separator"));
assertEquals( expected, createRecord().toString() ); assertEquals( expected, createRecord().toString() );

View File

@ -152,12 +152,12 @@ public final class TestUnknownEscherRecord {
r.serialize( 0, data, new NullEscherSerializationListener() ); r.serialize( 0, data, new NullEscherSerializationListener() );
String expected = String expected =
"{ /* UNKNOWN */\n" + "{ /* UNKNOWN */\n" +
"\t recordId: -3822 /* 0xf112 */\n" + "\t \"recordId\": -3822 /* 0xf112 */\n" +
"\t, version: 4\n" + "\t, \"version\": 4\n" +
"\t, instance: 291 /* 0x0123 */\n" + "\t, \"instance\": 291 /* 0x0123 */\n" +
"\t, options: 4660 /* 0x1234 */\n" + "\t, \"options\": 4660 /* 0x1234 */\n" +
"\t, recordSize: 8\n" + "\t, \"recordSize\": 8\n" +
"\t, data: \"\"\n" + "\t, \"data\": \"\"\n" +
"}"; "}";
expected = expected.replace("\n", System.getProperty("line.separator")); expected = expected.replace("\n", System.getProperty("line.separator"));
assertEquals(expected, r.toString() ); assertEquals(expected, r.toString() );

View File

@ -92,11 +92,11 @@ public class TestPolygon {
"<flags flag=\"0x8145\" description=\"IS_COMPLEX\"/>" + "<flags flag=\"0x8145\" description=\"IS_COMPLEX\"/>" +
"<data>BQAFAPD/AAAFAFoABQAyACwAWgBYAAAABQA=</data>" + "<data>BQAFAPD/AAAFAFoABQAyACwAWgBYAAAABQA=</data>" +
"<elements>" + "<elements>" +
"<item>>AAAFAA==</item>" + "<item>AAAFAA==</item>" +
"<item>>WgAFAA==</item>" + "<item>WgAFAA==</item>" +
"<item>>MgAsAA==</item>" + "<item>MgAsAA==</item>" +
"<item>>WgBYAA==</item>" + "<item>WgBYAA==</item>" +
"<item>>AAAFAA==</item>" + "<item>AAAFAA==</item>" +
"</elements>" + "</elements>" +
"</record>"; "</record>";
String actual = verticesProp1.toXml("").replaceAll("[\r\n\t]",""); String actual = verticesProp1.toXml("").replaceAll("[\r\n\t]","");
@ -115,10 +115,10 @@ public class TestPolygon {
"<flags flag=\"0x8145\" description=\"IS_COMPLEX\"/>" + "<flags flag=\"0x8145\" description=\"IS_COMPLEX\"/>" +
"<data>BAAEAPD/AQAEAAIABQADAAYAAQAEAA==</data>" + "<data>BAAEAPD/AQAEAAIABQADAAYAAQAEAA==</data>" +
"<elements>" + "<elements>" +
"<item>>AQAEAA==</item>" + "<item>AQAEAA==</item>" +
"<item>>AgAFAA==</item>" + "<item>AgAFAA==</item>" +
"<item>>AwAGAA==</item>" + "<item>AwAGAA==</item>" +
"<item>>AQAEAA==</item>" + "<item>AQAEAA==</item>" +
"</elements></record>"; "</elements></record>";
actual = verticesProp1.toXml("").replaceAll("[\r\n\t]",""); actual = verticesProp1.toXml("").replaceAll("[\r\n\t]","");