mirror of https://github.com/apache/poi.git
#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:
parent
468346fca8
commit
6e32d853be
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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() );
|
||||||
|
|
|
@ -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() );
|
||||||
|
|
|
@ -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() );
|
||||||
|
|
|
@ -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" +
|
||||||
"}";
|
"}";
|
||||||
|
|
|
@ -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() );
|
||||||
|
|
|
@ -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() );
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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() );
|
||||||
|
|
|
@ -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() );
|
||||||
|
|
|
@ -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() );
|
||||||
|
|
|
@ -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() );
|
||||||
|
|
|
@ -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]","");
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue