Modified: 
poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmap16.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmap16.java?rev=1866808&r1=1866807&r2=1866808&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmap16.java 
(original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmap16.java 
Wed Sep 11 21:24:06 2019
@@ -19,20 +19,26 @@ package org.apache.poi.hwmf.record;
 
 import java.awt.image.BufferedImage;
 import java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.function.Supplier;
 
+import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 
-public class HwmfBitmap16 {
-    final boolean isPartial;
-    int type;
-    int width;
-    int height;
-    int widthBytes;
-    int planes;
-    int bitsPixel;
-    
+public class HwmfBitmap16 implements GenericRecord {
+    private final boolean isPartial;
+    private int type;
+    private int width;
+    private int height;
+    private int widthBytes;
+    private int planes;
+    private int bitsPixel;
+    private byte[] bitmap;
+
     public HwmfBitmap16() {
         this(false);
     }
@@ -74,7 +80,7 @@ public class HwmfBitmap16 {
         }
 
         int length = (((width * bitsPixel + 15) >> 4) << 1) * height;
-        /*byte buf[] =*/ IOUtils.toByteArray(leis, length);
+        bitmap = IOUtils.toByteArray(leis, length);
         
         // TODO: this is not implemented ... please provide a sample, if it
         // ever happens to you, to come here ...
@@ -85,4 +91,18 @@ public class HwmfBitmap16 {
     public BufferedImage getImage() {
         return new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
     }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        final Map<String,Supplier<?>> m = new LinkedHashMap<>();
+        m.put("isPartial", () -> isPartial);
+        m.put("type", () -> type);
+        m.put("width", () -> width);
+        m.put("height", () -> height);
+        m.put("widthBytes", () -> widthBytes);
+        m.put("planes", () -> planes);
+        m.put("bitsPixel", () -> bitsPixel);
+        m.put("bitmap", () -> bitmap);
+        return Collections.unmodifiableMap(m);
+    }
 }

Modified: 
poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java?rev=1866808&r1=1866807&r2=1866808&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java 
(original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java 
Wed Sep 11 21:24:06 2019
@@ -29,10 +29,16 @@ import java.awt.image.IndexColorModel;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.function.Supplier;
 
 import javax.imageio.ImageIO;
 
+import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hwmf.usermodel.HwmfPicture;
+import org.apache.poi.util.GenericRecordJsonWriter;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianConsts;
@@ -44,7 +50,7 @@ import org.apache.poi.util.RecordFormatE
 /**
  * The DeviceIndependentBitmap Object defines an image in device-independent 
bitmap (DIB) format.
  */
-public class HwmfBitmapDib {
+public class HwmfBitmapDib implements GenericRecord {
 
     private static final POILogger logger = 
POILogFactory.getLogger(HwmfBitmapDib.class);
     private static final int BMP_HEADER_SIZE = 14;
@@ -435,8 +441,12 @@ public class HwmfBitmapDib {
     }
 
     public byte[] getBMPData() {
+        if (headerWidth <= 0 || headerHeight <= 0) {
+            return null;
+        }
+
         if (imageData == null) {
-            throw new RecordFormatException("bitmap not initialized ... need 
to call init() before");
+            throw new RecordFormatException("used to throw exception: bitmap 
not initialized ... need to call init() before");
         }
 
         // sometimes there are missing bytes after the imageData which will be 
0-filled
@@ -488,23 +498,33 @@ public class HwmfBitmapDib {
 
     @Override
     public String toString() {
-        return
-            "{ headerSize: " + headerSize +
-            ", width: " + headerWidth +
-            ", height: " + headerHeight +
-            ", planes: " + headerPlanes +
-            ", bitCount: '" + headerBitCount + "'" +
-            ", compression: '" + headerCompression + "'" +
-            ", imageSize: " + headerImageSize +
-            ", xPelsPerMeter: " + headerXPelsPerMeter +
-            ", yPelsPerMeter: " + headerYPelsPerMeter +
-            ", colorUsed: " + headerColorUsed +
-            ", colorImportant: " + headerColorImportant +
-            ", imageSize: " + (imageData == null ? 0 : imageData.length) +
-            "}";
+        return GenericRecordJsonWriter.marshal(this);
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        final Map<String,Supplier<?>> m = new LinkedHashMap<>();
+        m.put("headerSize", () -> headerSize);
+        m.put("width", () -> headerWidth);
+        m.put("height", () -> headerHeight);
+        m.put("planes", () -> headerPlanes);
+        m.put("bitCount", () -> headerBitCount);
+        m.put("compression", () -> headerCompression);
+        m.put("imageSize", () -> headerImageSize);
+        m.put("xPelsPerMeter", () -> headerXPelsPerMeter);
+        m.put("yPelsPerMeter", () -> headerYPelsPerMeter);
+        m.put("colorUsed", () -> headerColorUsed);
+        m.put("colorImportant", () -> headerColorImportant);
+        m.put("image", this::getImage);
+        m.put("bmpData", this::getBMPData);
+        return Collections.unmodifiableMap(m);
     }
 
     protected BufferedImage getPlaceholder() {
+        if (headerHeight <= 0 || headerWidth <= 0) {
+            return new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
+        }
+
         BufferedImage bi = new BufferedImage(headerWidth, headerHeight, 
BufferedImage.TYPE_INT_ARGB);
         Graphics2D g = bi.createGraphics();
         g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
RenderingHints.VALUE_ANTIALIAS_ON);

Modified: 
poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfColorRef.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfColorRef.java?rev=1866808&r1=1866807&r2=1866808&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfColorRef.java 
(original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfColorRef.java 
Wed Sep 11 21:24:06 2019
@@ -19,8 +19,12 @@ package org.apache.poi.hwmf.record;
 
 import java.awt.Color;
 import java.io.IOException;
-import java.util.Locale;
+import java.util.Map;
+import java.util.function.Supplier;
 
+import org.apache.poi.common.usermodel.GenericRecord;
+import org.apache.poi.util.GenericRecordJsonWriter;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 
@@ -31,7 +35,7 @@ import org.apache.poi.util.LittleEndianI
  * Blue (1 byte):  An 8-bit unsigned integer that defines the relative 
intensity of blue.
  * Reserved (1 byte):  An 8-bit unsigned integer that MUST be 0x00.
  */
-public class HwmfColorRef implements Cloneable {
+public class HwmfColorRef implements Cloneable, GenericRecord {
     private Color colorRef = Color.BLACK;
     
     public HwmfColorRef() {}
@@ -77,6 +81,11 @@ public class HwmfColorRef implements Clo
 
     @Override
     public String toString() {
-        return String.format(Locale.ROOT, "%#08X", colorRef.getRGB()&0xFFFFFF);
+        return GenericRecordJsonWriter.marshal(this);
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties("color", 
colorRef::getRGB);
     }
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java?rev=1866808&r1=1866807&r2=1866808&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java 
(original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java Wed 
Sep 11 21:24:06 2019
@@ -18,28 +18,35 @@
 package org.apache.poi.hwmf.record;
 
 import java.awt.Shape;
-import java.awt.geom.AffineTransform;
 import java.awt.geom.Arc2D;
 import java.awt.geom.Area;
 import java.awt.geom.Dimension2D;
 import java.awt.geom.Ellipse2D;
 import java.awt.geom.Line2D;
 import java.awt.geom.Path2D;
-import java.awt.geom.PathIterator;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.geom.RoundRectangle2D;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
 
 import org.apache.poi.hwmf.draw.HwmfGraphics;
 import org.apache.poi.hwmf.draw.HwmfGraphics.FillDrawStyle;
+import org.apache.poi.util.Dimension2DDouble;
+import org.apache.poi.util.GenericRecordJsonWriter;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 
-public class HwmfDraw {
+@SuppressWarnings("WeakerAccess")
+public final class HwmfDraw {
+
+    private HwmfDraw() {}
+
     /**
      * The META_MOVETO record sets the output position in the playback device 
context to a specified
      * point.
@@ -65,7 +72,16 @@ public class HwmfDraw {
 
         @Override
         public String toString() {
-            return pointToString(point);
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public Point2D getPoint() {
+            return point;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("point", 
this::getPoint);
         }
     }
 
@@ -97,7 +113,16 @@ public class HwmfDraw {
 
         @Override
         public String toString() {
-            return pointToString(point);
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public Point2D getPoint() {
+            return point;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("point", 
this::getPoint);
         }
     }
 
@@ -117,9 +142,7 @@ public class HwmfDraw {
 
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int 
recordFunction) throws IOException {
-            /**
-             * A 16-bit signed integer that defines the number of points in 
the array.
-             */
+            //A 16-bit signed integer that defines the number of points in the 
array.
             int numberofPoints = leis.readShort();
 
             poly = new Path2D.Double(Path2D.WIND_EVEN_ODD, numberofPoints);
@@ -143,23 +166,12 @@ public class HwmfDraw {
             Path2D p = (Path2D)poly.clone();
             // don't close the path
             p.setWindingRule(ctx.getProperties().getWindingRule());
-            switch (getFillDrawStyle()) {
-                case FILL:
-                    ctx.fill(p);
-                    break;
-                case DRAW:
-                    ctx.draw(p);
-                    break;
-                case FILL_DRAW:
-                    ctx.fill(p);
-                    ctx.draw(p);
-                    break;
-            }
+            getFillDrawStyle().handler.accept(ctx, p);
         }
 
         @Override
         public String toString() {
-            return "{ poly: "+polyToString(poly)+" }";
+            return GenericRecordJsonWriter.marshal(this);
         }
 
         /**
@@ -168,6 +180,15 @@ public class HwmfDraw {
         protected FillDrawStyle getFillDrawStyle() {
             return FillDrawStyle.FILL;
         }
+
+        public Path2D getPoly() {
+            return poly;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("poly", 
this::getPoly);
+        }
     }
 
     /**
@@ -216,7 +237,16 @@ public class HwmfDraw {
 
         @Override
         public String toString() {
-            return boundsToString(bounds);
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public Rectangle2D getBounds() {
+            return bounds;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("bounds", 
this::getBounds);
         }
     }
 
@@ -235,16 +265,11 @@ public class HwmfDraw {
          * Brush to use for filling the region.
          */
         protected int brushIndex;
+
         /**
-         * A 16-bit signed integer that defines the height, in logical units, 
of the
-         * region frame.
-         */
-        protected int height;
-        /**
-         * A 16-bit signed integer that defines the width, in logical units, 
of the
-         * region frame.
+         * The region frame, in logical units
          */
-        protected int width;
+        protected final Dimension2D frame = new Dimension2DDouble();
 
         @Override
         public HwmfRecordType getWmfRecordType() {
@@ -255,8 +280,10 @@ public class HwmfDraw {
         public int init(LittleEndianInputStream leis, long recordSize, int 
recordFunction) throws IOException {
             regionIndex = leis.readUShort();
             brushIndex = leis.readUShort();
-            height = leis.readShort();
-            width = leis.readShort();
+            // A 16-bit signed integer that defines the height/width, in 
logical units, of the region frame.
+            int height = leis.readShort();
+            int width = leis.readShort();
+            frame.setSize(width, height);
             return 4*LittleEndianConsts.SHORT_SIZE;
         }
 
@@ -265,15 +292,35 @@ public class HwmfDraw {
             ctx.applyObjectTableEntry(brushIndex);
             ctx.applyObjectTableEntry(regionIndex);
             Rectangle2D inner = ctx.getProperties().getRegion().getBounds();
-            double x = inner.getX()-width;
-            double y = inner.getY()-height;
-            double w = inner.getWidth()+2.0*width;
-            double h = inner.getHeight()+2.0*height;
+            double x = inner.getX()-frame.getWidth();
+            double y = inner.getY()-frame.getHeight();
+            double w = inner.getWidth()+2.0*frame.getWidth();
+            double h = inner.getHeight()+2.0*frame.getHeight();
             Rectangle2D outer = new Rectangle2D.Double(x,y,w,h);
             Area frame = new Area(outer);
             frame.subtract(new Area(inner));
             ctx.fill(frame);
         }
+
+        public int getRegionIndex() {
+            return regionIndex;
+        }
+
+        public int getBrushIndex() {
+            return brushIndex;
+        }
+
+        public Dimension2D getFrame() {
+            return frame;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "regionIndex", this::getRegionIndex,
+                "brushIndex", this::getBrushIndex,
+                "frame", this::getFrame);
+        }
     }
 
     /**
@@ -292,15 +339,11 @@ public class HwmfDraw {
 
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int 
recordFunction) throws IOException {
-            // see http://secunia.com/gfx/pdf/SA31675_BA.pdf ;)
-            /**
-             * A 16-bit unsigned integer that defines the number of polygons 
in the object.
-             */
+            // see also CVE-2008-3014 - 
https://dl.packetstormsecurity.net/papers/attack/CVE-2008-3014.pdf ;)
+            // A 16-bit unsigned integer that defines the number of polygons 
in the object.
             int numberOfPolygons = leis.readUShort();
-            /**
-             * A NumberOfPolygons array of 16-bit unsigned integers that 
define the number of
-             * points for each polygon in the object.
-             */
+            // A NumberOfPolygons array of 16-bit unsigned integers that 
define the number of points for
+            // each polygon in the object.
             int[] pointsPerPolygon = new int[numberOfPolygons];
 
             int size = LittleEndianConsts.SHORT_SIZE;
@@ -311,10 +354,8 @@ public class HwmfDraw {
             }
 
             for (int nPoints : pointsPerPolygon) {
-                /**
-                 * An array of 16-bit signed integers that define the 
coordinates of the polygons.
-                 * (Note: MS-WMF wrongly says unsigned integers ...)
-                 */
+                // An array of 16-bit signed integers that define the 
coordinates of the polygons.
+                // (Note: MS-WMF wrongly says unsigned integers ...)
                 Path2D poly = new Path2D.Double(Path2D.WIND_EVEN_ODD, nPoints);
                 for (int i=0; i<nPoints; i++) {
                     int x = leis.readShort();
@@ -396,20 +437,16 @@ public class HwmfDraw {
 
         @Override
         public String toString() {
-            final StringBuilder sb = new StringBuilder();
-            sb.append("{ polyList: [");
-            boolean isFirst = true;
-            for (Path2D p : polyList) {
-                if (!isFirst) {
-                    sb.append(",");
-                }
-                isFirst = false;
-                sb.append("{ points: ");
-                sb.append(polyToString(p));
-                sb.append(" }");
-            }
-            sb.append(" }");
-            return sb.toString();
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public List<Path2D> getPolyList() {
+            return polyList;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("polyList", 
this::getPolyList);
         }
     }
 
@@ -437,7 +474,16 @@ public class HwmfDraw {
 
         @Override
         public String toString() {
-            return boundsToString(bounds);
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public Rectangle2D getBounds() {
+            return bounds;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("bounds", 
this::getBounds);
         }
     }
 
@@ -469,6 +515,22 @@ public class HwmfDraw {
             Shape s = new Rectangle2D.Double(point.getX(), point.getY(), 1, 1);
             ctx.fill(s);
         }
+
+        public HwmfColorRef getColorRef() {
+            return colorRef;
+        }
+
+        public Point2D getPoint() {
+            return point;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "colorRef", this::getColorRef,
+                "point", this::getPoint
+            );
+        }
     }
 
     /**
@@ -476,17 +538,7 @@ public class HwmfDraw {
      * using the pen and filled using the brush, as defined in the playback 
device context.
      */
     public static class WmfRoundRect implements HwmfRecord {
-        /**
-         * A 16-bit signed integer that defines the height, in logical 
coordinates, of the
-         * ellipse used to draw the rounded corners.
-         */
-        protected int height;
-
-        /**
-         * A 16-bit signed integer that defines the width, in logical 
coordinates, of the
-         * ellipse used to draw the rounded corners.
-         */
-        protected int width;
+        protected final Dimension2D corners = new Dimension2DDouble();
 
         protected final Rectangle2D bounds = new Rectangle2D.Double();
 
@@ -498,8 +550,11 @@ public class HwmfDraw {
 
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int 
recordFunction) throws IOException {
-            height = leis.readShort();
-            width = leis.readShort();
+            // A 16-bit signed integer that defines the height/width, in 
logical coordinates,
+            // of the ellipse used to draw the rounded corners.
+            int height = leis.readShort();
+            int width = leis.readShort();
+            corners.setSize(width, height);
             return 2*LittleEndianConsts.SHORT_SIZE+readBounds(leis, bounds);
         }
 
@@ -509,8 +564,28 @@ public class HwmfDraw {
         }
 
         protected RoundRectangle2D getShape() {
-            return new RoundRectangle2D.Double(bounds.getX(), bounds.getY(), 
bounds.getWidth(), bounds.getHeight(), width, height);
+            return new RoundRectangle2D.Double(
+                bounds.getX(), bounds.getY(), bounds.getWidth(), 
bounds.getHeight(),
+                corners.getWidth(), corners.getHeight()
+            );
+        }
+
+        public Dimension2D getCorners() {
+            return corners;
         }
+
+        public Rectangle2D getBounds() {
+            return bounds;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "bounds", this::getBounds,
+                "corners", this::getCorners
+            );
+        }
+
     }
 
 
@@ -518,6 +593,22 @@ public class HwmfDraw {
      * The META_ARC record draws an elliptical arc.
      */
     public static class WmfArc implements HwmfRecord {
+        public enum WmfArcClosure {
+            ARC(HwmfRecordType.arc, Arc2D.OPEN, FillDrawStyle.DRAW),
+            CHORD(HwmfRecordType.chord, Arc2D.CHORD, FillDrawStyle.FILL_DRAW),
+            PIE(HwmfRecordType.pie, Arc2D.PIE, FillDrawStyle.FILL_DRAW);
+
+            public final HwmfRecordType recordType;
+            public final int awtType;
+            public final FillDrawStyle drawStyle;
+
+            WmfArcClosure(HwmfRecordType recordType, int awtType, 
FillDrawStyle drawStyle) {
+                this.recordType = recordType;
+                this.awtType = awtType;
+                this.drawStyle = drawStyle;
+            }
+        }
+
         /** starting point of the arc */
         protected final Point2D startPoint = new Point2D.Double();
 
@@ -544,32 +635,25 @@ public class HwmfDraw {
 
         @Override
         public void draw(HwmfGraphics ctx) {
-            Shape s = getShape();
-            switch (getFillDrawStyle()) {
-                case FILL:
-                    ctx.fill(s);
-                    break;
-                case DRAW:
-                    ctx.draw(s);
-                    break;
-                case FILL_DRAW:
-                    ctx.fill(s);
-                    ctx.draw(s);
-                    break;
-            }
+            getFillDrawStyle().handler.accept(ctx, getShape());
         }
 
-        protected FillDrawStyle getFillDrawStyle() {
+        public WmfArcClosure getArcClosure() {
             switch (getWmfRecordType()) {
                 default:
                 case arc:
-                    return FillDrawStyle.DRAW;
+                    return WmfArcClosure.ARC;
                 case chord:
+                    return WmfArcClosure.CHORD;
                 case pie:
-                    return FillDrawStyle.FILL_DRAW;
+                    return WmfArcClosure.PIE;
             }
         }
 
+        protected FillDrawStyle getFillDrawStyle() {
+            return getArcClosure().drawStyle;
+        }
+
         protected Arc2D getShape() {
             double startAngle = Math.toDegrees(Math.atan2(-(startPoint.getY() 
- bounds.getCenterY()), startPoint.getX() - bounds.getCenterX()));
             double endAngle =   Math.toDegrees(Math.atan2(-(endPoint.getY() - 
bounds.getCenterY()), endPoint.getX() - bounds.getCenterX()));
@@ -578,33 +662,37 @@ public class HwmfDraw {
                 startAngle += 360;
             }
 
-            int arcClosure;
-            switch (getWmfRecordType()) {
-                default:
-                case arc:
-                    arcClosure = Arc2D.OPEN;
-                    break;
-                case chord:
-                    arcClosure = Arc2D.CHORD;
-                    break;
-                case pie:
-                    arcClosure = Arc2D.PIE;
-                    break;
-            }
-
-            return new Arc2D.Double(bounds.getX(), bounds.getY(), 
bounds.getWidth(), bounds.getHeight(), startAngle, arcAngle, arcClosure);
+            return new Arc2D.Double(bounds.getX(), bounds.getY(), 
bounds.getWidth(), bounds.getHeight(),
+                startAngle, arcAngle, getArcClosure().awtType);
         }
 
         @Override
         public String toString() {
-            Arc2D arc = getShape();
-            return
-                "{ startPoint: "+pointToString(startPoint)+
-                ", endPoint: "+pointToString(endPoint)+
-                ", startAngle: "+arc.getAngleStart()+
-                ", extentAngle: "+arc.getAngleExtent()+
-                ", bounds: "+boundsToString(bounds)+
-                " }";
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public Point2D getStartPoint() {
+            return startPoint;
+        }
+
+        public Point2D getEndPoint() {
+            return endPoint;
+        }
+
+        public Rectangle2D getBounds() {
+            return bounds;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            final Arc2D arc = getShape();
+            return GenericRecordUtil.getGenericProperties(
+                "startPoint", this::getStartPoint,
+                "endPoint", this::getEndPoint,
+                "startAngle", arc::getAngleStart,
+                "extentAngle", arc::getAngleExtent,
+                "bounds", this::getBounds
+            );
         }
     }
 
@@ -668,14 +756,22 @@ public class HwmfDraw {
 
         @Override
         public String toString() {
-            return "{ index: "+objectIndex +" }";
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public int getObjectIndex() {
+            return objectIndex;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("objectIndex", 
this::getObjectIndex);
         }
     }
 
+    @SuppressWarnings("DuplicatedCode")
     static int readBounds(LittleEndianInputStream leis, Rectangle2D bounds) {
-        /**
-         * The 16-bit signed integers that defines the corners of the bounding 
rectangle.
-         */
+        // The 16-bit signed integers that defines the corners of the bounding 
rectangle.
         int bottom = leis.readShort();
         int right = leis.readShort();
         int top = leis.readShort();
@@ -691,10 +787,9 @@ public class HwmfDraw {
         return 4 * LittleEndianConsts.SHORT_SIZE;
     }
 
+    @SuppressWarnings("DuplicatedCode")
     static int readRectS(LittleEndianInputStream leis, Rectangle2D bounds) {
-        /**
-         * The 16-bit signed integers that defines the corners of the bounding 
rectangle.
-         */
+        // The 16-bit signed integers that defines the corners of the bounding 
rectangle.
         int left = leis.readShort();
         int top = leis.readShort();
         int right = leis.readShort();
@@ -711,58 +806,13 @@ public class HwmfDraw {
     }
 
     static int readPointS(LittleEndianInputStream leis, Point2D point) {
-        /** a signed integer that defines the x/y-coordinate, in logical 
units. */
+        // a signed integer that defines the x/y-coordinate, in logical units.
         int y = leis.readShort();
         int x = leis.readShort();
         point.setLocation(x, y);
         return 2*LittleEndianConsts.SHORT_SIZE;
     }
 
-    static String polyToString(Path2D poly) {
-        StringBuilder sb = new StringBuilder();
-        sb.append("[");
-        final PathIterator iter = poly.getPathIterator(null);
-        double[] pnts = new double[6];
-        while (!iter.isDone()) {
-            int segType = iter.currentSegment(pnts);
-            switch (segType) {
-                case PathIterator.SEG_MOVETO:
-                    sb.append("{ type: 'move', x: "+pnts[0]+", y: "+pnts[1]+" 
}, ");
-                    break;
-                case PathIterator.SEG_LINETO:
-                    sb.append("{ type: 'lineto', x: "+pnts[0]+", y: 
"+pnts[1]+" }, ");
-                    break;
-                case PathIterator.SEG_QUADTO:
-                    sb.append("{ type: 'quad', x1: "+pnts[0]+", y1: 
"+pnts[1]+", x2: "+pnts[2]+", y2: "+pnts[3]+" }, ");
-                    break;
-                case PathIterator.SEG_CUBICTO:
-                    sb.append("{ type: 'cubic', x1: "+pnts[0]+", y1: 
"+pnts[1]+", x2: "+pnts[2]+", y2: "+pnts[3]+", x3: "+pnts[4]+", y3: "+pnts[5]+" 
}, ");
-                    break;
-                case PathIterator.SEG_CLOSE:
-                    sb.append("{ type: 'close' }, ");
-                    break;
-            }
-            iter.next();
-        }
-        sb.append("]");
-        return sb.toString();
-    }
-
-    @Internal
-    public static String pointToString(Point2D point) {
-        return (point == null) ? "null" : "{ x: "+point.getX()+", y: 
"+point.getY()+" }";
-    }
-
-    @Internal
-    public static String boundsToString(Rectangle2D bounds) {
-        return (bounds == null) ? "null" : "{ x: "+bounds.getX()+", y: 
"+bounds.getY()+", w: "+bounds.getWidth()+", h: "+bounds.getHeight()+" }";
-    }
-
-    @Internal
-    public static String dimToString(Dimension2D dim) {
-        return (dim == null) ? "null" : "{ w: "+dim.getWidth()+", h: 
"+dim.getHeight()+" }";
-    }
-
     @Internal
     public static Rectangle2D normalizeBounds(Rectangle2D bounds) {
         return (bounds.getWidth() >= 0 && bounds.getHeight() >= 0) ? bounds

Modified: 
poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfEscape.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfEscape.java?rev=1866808&r1=1866807&r2=1866808&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfEscape.java 
(original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfEscape.java Wed 
Sep 11 21:24:06 2019
@@ -18,13 +18,16 @@
 package org.apache.poi.hwmf.record;
 
 import java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
 import java.util.function.Supplier;
 
+import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hwmf.draw.HwmfGraphics;
-import org.apache.poi.util.HexDump;
+import org.apache.poi.util.GenericRecordJsonWriter;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.LittleEndianCP950Reader;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 
@@ -32,6 +35,7 @@ import org.apache.poi.util.LittleEndianI
  * The MetafileEscapes specifies printer driver functionality that
  * might not be directly accessible through WMF records
  */
+@SuppressWarnings("WeakerAccess")
 public class HwmfEscape implements HwmfRecord {
     private static final int MAX_OBJECT_SIZE = 0xFFFF;
 
@@ -221,13 +225,18 @@ public class HwmfEscape implements HwmfR
     }
     
     public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("escape - function: "+escapeFunction+"\n");
-        sb.append(escapeData.toString());
-        return sb.toString();
+        return GenericRecordJsonWriter.marshal(this);
     }
 
-    public static class WmfEscapeUnknownData implements HwmfEscapeData {
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties(
+            "escapeFunction", this::getEscapeFunction,
+            "escapeData", this::getEscapeData
+        );
+    }
+
+    public static class WmfEscapeUnknownData implements HwmfEscapeData, 
GenericRecord {
         EscapeFunction escapeFunction;
         private byte[] escapeDataBytes;
 
@@ -239,16 +248,21 @@ public class HwmfEscape implements HwmfR
         public int init(LittleEndianInputStream leis, long recordSize, 
EscapeFunction escapeFunction) throws IOException {
             this.escapeFunction = escapeFunction;
             escapeDataBytes = 
IOUtils.toByteArray(leis,recordSize,MAX_OBJECT_SIZE);
-            return 0;
+            return (int)recordSize;
         }
 
         @Override
         public String toString() {
-            return HexDump.dump(escapeDataBytes, 0, 0);
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("escapeDataBytes", 
this::getEscapeDataBytes);
         }
     }
 
-    public static class WmfEscapeEMF implements HwmfEscapeData {
+    public static class WmfEscapeEMF implements HwmfEscapeData, GenericRecord {
         // The magic for EMF parts, i.e. the byte sequence for "WMFC"
         private static final int EMF_COMMENT_IDENTIFIER = 0x43464D57;
 
@@ -276,7 +290,9 @@ public class HwmfEscape implements HwmfR
             if (commentIdentifier != EMF_COMMENT_IDENTIFIER) {
                 // there are some WMF implementation using this record as a 
MFCOMMENT or similar
                 // if the commentIdentifier doesn't match, then return 
immediately
-                return LittleEndianConsts.INT_SIZE;
+                emfData = IOUtils.toByteArray(leis, 
recordSize-LittleEndianConsts.INT_SIZE, MAX_OBJECT_SIZE);
+                remainingBytes = emfData.length;
+                return (int)recordSize;
             }
 
             // A 32-bit unsigned integer that identifies the type of comment 
in this record.
@@ -344,5 +360,21 @@ public class HwmfEscape implements HwmfR
         public byte[] getEmfData() {
             return emfData;
         }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            final Map<String,Supplier<?>> m = new LinkedHashMap<>();
+            m.put("commentIdentifier", () -> commentIdentifier);
+            m.put("commentType", () -> commentType);
+            m.put("version", () -> version);
+            m.put("checksum", () -> checksum);
+            m.put("flags", () -> flags);
+            m.put("commentRecordCount", this::getCommentRecordCount);
+            m.put("currentRecordSize", this::getCurrentRecordSize);
+            m.put("remainingBytes", this::getRemainingBytes);
+            m.put("emfRecordSize", this::getEmfRecordSize);
+            m.put("emfData", this::getEmfData);
+            return Collections.unmodifiableMap(m);
+        }
     }
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java?rev=1866808&r1=1866807&r2=1866808&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java 
(original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java Wed 
Sep 11 21:24:06 2019
@@ -17,7 +17,6 @@
 
 package org.apache.poi.hwmf.record;
 
-import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
 import static org.apache.poi.hwmf.record.HwmfDraw.readPointS;
 
 import java.awt.Color;
@@ -27,17 +26,20 @@ import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 import java.io.IOException;
+import java.util.Map;
+import java.util.function.Supplier;
 
 import org.apache.poi.hwmf.draw.HwmfDrawProperties;
 import org.apache.poi.hwmf.draw.HwmfGraphics;
 import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;
+import org.apache.poi.util.GenericRecordJsonWriter;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 
+@SuppressWarnings("WeakerAccess")
 public class HwmfFill {
-    /**
-     * A record which contains an image (to be extracted)
-     */
+    /** A record which contains an image (to be extracted) */
     public interface HwmfImageRecord {
 
         default BufferedImage getImage() {
@@ -70,9 +72,7 @@ public class HwmfFill {
      * i.e. if contains explicit RGB values or indexes into a palette.
      */
     public enum ColorUsage {
-        /**
-         * The color table contains RGB values
-         */
+        /** The color table contains RGB values */
         DIB_RGB_COLORS(0x0000),
         /**
          * The color table contains 16-bit indices into the current logical 
palette in
@@ -139,7 +139,22 @@ public class HwmfFill {
             if (region != null) {
                 ctx.fill(region);
             }
-            
+        }
+
+        public int getRegionIndex() {
+            return regionIndex;
+        }
+
+        public int getBrushIndex() {
+            return brushIndex;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "regionIndex", this::getRegionIndex,
+                "brushIndex", this::getBrushIndex
+            );
         }
     }
 
@@ -173,6 +188,15 @@ public class HwmfFill {
                 ctx.fill(region);
             }        
         }
+
+        public int getRegionIndex() {
+            return regionIndex;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("regionIndex", 
this::getRegionIndex);
+        }
     }
     
     
@@ -182,9 +206,7 @@ public class HwmfFill {
      */
     public static class WmfFloodFill implements HwmfRecord {
         
-        /**
-         * A 32-bit ColorRef Object that defines the color value.
-         */
+        /** A 32-bit ColorRef Object that defines the color value. */
         protected final HwmfColorRef colorRef = new HwmfColorRef();
 
         /** the point where filling is to start. */
@@ -206,6 +228,22 @@ public class HwmfFill {
         public void draw(HwmfGraphics ctx) {
             
         }
+
+        public HwmfColorRef getColorRef() {
+            return colorRef;
+        }
+
+        public Point2D getStart() {
+            return start;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "colorRef", this::getColorRef,
+                "start", this::getStart
+            );
+        }
     }
 
     /**
@@ -267,7 +305,16 @@ public class HwmfFill {
 
         @Override
         public String toString() {
-            return "{ polyFillMode: '"+ polyFillMode +"' }";
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public HwmfPolyfillMode getPolyFillMode() {
+            return polyFillMode;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("polyFillMode", 
this::getPolyFillMode);
         }
     }
 
@@ -277,21 +324,22 @@ public class HwmfFill {
      * the playback device context.
      */
     public static class WmfExtFloodFill extends WmfFloodFill {
-        
-        /**
-         * A 16-bit unsigned integer that defines the fill operation to be 
performed. This
-         * member MUST be one of the values in the FloodFill Enumeration table:
-         * 
-         * FLOODFILLBORDER = 0x0000:
-         * The fill area is bounded by the color specified by the Color member.
-         * This style is identical to the filling performed by the 
META_FLOODFILL record.
-         * 
-         * FLOODFILLSURFACE = 0x0001:
-         * The fill area is bounded by the color that is specified by the 
Color member.
-         * Filling continues outward in all directions as long as the color is 
encountered.
-         * This style is useful for filling areas with multicolored boundaries.
-         */
-        protected int mode;
+
+        public enum HwmfFloodFillMode {
+            /**
+             * The fill area is bounded by the color specified by the Color 
member.
+             * This style is identical to the filling performed by the 
META_FLOODFILL record.
+             */
+            FLOOD_FILL_BORDER,
+            /**
+             * The fill area is bounded by the color that is specified by the 
Color member.
+             * Filling continues outward in all directions as long as the 
color is encountered.
+             * This style is useful for filling areas with multicolored 
boundaries.
+             */
+            FLOOD_FILL_SURFACE
+        }
+
+        protected HwmfFloodFillMode mode;
         
         @Override
         public HwmfRecordType getWmfRecordType() {
@@ -300,7 +348,9 @@ public class HwmfFill {
         
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int 
recordFunction) throws IOException {
-            mode = leis.readUShort();
+            // A 16-bit unsigned integer that defines the fill operation to be 
performed. This
+            // member MUST be one of the values in the FloodFill Enumeration 
table:
+            mode = HwmfFloodFillMode.values()[leis.readUShort()];
             return super.init(leis, recordSize, 
recordFunction)+LittleEndianConsts.SHORT_SIZE;
         }
 
@@ -308,6 +358,15 @@ public class HwmfFill {
         public void draw(HwmfGraphics ctx) {
             
         }
+
+        public HwmfFloodFillMode getMode() {
+            return mode;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("mode", 
this::getMode);
+        }
     }
 
     /**
@@ -319,7 +378,7 @@ public class HwmfFill {
          * A 16-bit unsigned integer used to index into the WMF Object Table 
to get
          * the region to be inverted.
          */
-        private int region;
+        private int regionIndex;
         
         @Override
         public HwmfRecordType getWmfRecordType() {
@@ -328,7 +387,7 @@ public class HwmfFill {
         
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int 
recordFunction) throws IOException {
-            region = leis.readUShort();
+            regionIndex = leis.readUShort();
             return LittleEndianConsts.SHORT_SIZE;
         }
 
@@ -336,6 +395,15 @@ public class HwmfFill {
         public void draw(HwmfGraphics ctx) {
             
         }
+
+        public int getRegionIndex() {
+            return regionIndex;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("regionIndex", 
this::getRegionIndex);
+        }
     }
     
 
@@ -361,12 +429,7 @@ public class HwmfFill {
         
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int 
recordFunction) throws IOException {
-            int rasterOpCode = leis.readUShort();
-            int rasterOpIndex = leis.readUShort();
-
-            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
-            assert(rasterOpCode == rasterOperation.opCode);
-            
+            rasterOperation = readRasterOperation(leis);
             return readBounds2(leis, bounds)+2*LittleEndianConsts.SHORT_SIZE;
         }
 
@@ -374,6 +437,21 @@ public class HwmfFill {
         public void draw(HwmfGraphics ctx) {
             
         }
+
+        public HwmfTernaryRasterOp getRasterOperation() {
+            return rasterOperation;
+        }
+
+        public Rectangle2D getBounds() {
+            return bounds;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "rasterOperation", this::getRasterOperation,
+                "bounds", this::getBounds);
+        }
     }
 
     /**
@@ -415,13 +493,9 @@ public class HwmfFill {
         
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int 
recordFunction) throws IOException {
-            boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));
+            final boolean hasBitmap = hasBitmap(recordSize, recordFunction);
 
-            int rasterOpCode = leis.readUShort();
-            int rasterOpIndex = leis.readUShort();
-            
-            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
-            assert(rasterOpCode == rasterOperation.opCode);
+            rasterOperation = readRasterOperation(leis);
 
             int size = 2*LittleEndianConsts.SHORT_SIZE;
 
@@ -449,11 +523,33 @@ public class HwmfFill {
 
         @Override
         public String toString() {
-            return
-                "{ rasterOperation: '"+rasterOperation+"'"+
-                ", srcBounds: "+boundsToString(srcBounds)+
-                ", dstBounds: "+boundsToString(dstBounds)+
-                "}";
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public HwmfTernaryRasterOp getRasterOperation() {
+            return rasterOperation;
+        }
+
+        public Rectangle2D getSrcBounds() {
+            return srcBounds;
+        }
+
+        public Rectangle2D getDstBounds() {
+            return dstBounds;
+        }
+
+        public HwmfBitmap16 getTarget() {
+            return target;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "rasterOperation", this::getRasterOperation,
+                "srcBounds", this::getSrcBounds,
+                "dstBounds", this::getDstBounds,
+                "target", this::getTarget
+            );
         }
     }
 
@@ -498,12 +594,7 @@ public class HwmfFill {
         
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int 
recordFunction) throws IOException {
-            int rasterOpCode = leis.readUShort();
-            int rasterOpIndex = leis.readUShort();
-            
-            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
-            assert(rasterOpCode == rasterOperation.opCode);
-
+            rasterOperation = readRasterOperation(leis);
             colorUsage = ColorUsage.valueOf(leis.readUShort());
 
             int size = 3*LittleEndianConsts.SHORT_SIZE;
@@ -546,12 +637,33 @@ public class HwmfFill {
 
         @Override
         public String toString() {
-            return
-                "{ rasterOperation: '"+rasterOperation+"'"+
-                ", colorUsage: '"+colorUsage+"'"+
-                ", srcBounds: "+boundsToString(srcBounds)+
-                ", dstBounds: "+boundsToString(dstBounds)+
-                "}";
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public HwmfTernaryRasterOp getRasterOperation() {
+            return rasterOperation;
+        }
+
+        public ColorUsage getColorUsage() {
+            return colorUsage;
+        }
+
+        public Rectangle2D getSrcBounds() {
+            return srcBounds;
+        }
+
+        public Rectangle2D getDstBounds() {
+            return dstBounds;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "rasterOperation", this::getRasterOperation,
+                "colorUsage", this::getColorUsage,
+                "srcBounds", this::getSrcBounds,
+                "dstBounds", this::getDstBounds
+            );
         }
     }
     
@@ -564,13 +676,9 @@ public class HwmfFill {
         
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int 
recordFunction) throws IOException {
-            boolean hasBitmap = (recordSize/2 != ((recordFunction >> 8) + 3));
+            final boolean hasBitmap = hasBitmap(recordSize/2, recordFunction);
 
-            int rasterOpCode = leis.readUShort();
-            int rasterOpIndex = leis.readUShort();
-            
-            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
-            assert(rasterOpCode == rasterOperation.opCode);
+            rasterOperation = readRasterOperation(leis);
 
             int size = 2*LittleEndianConsts.SHORT_SIZE;
 
@@ -674,6 +782,38 @@ public class HwmfFill {
         public byte[] getBMPData() {
             return dib.getBMPData();
         }
+
+        public ColorUsage getColorUsage() {
+            return colorUsage;
+        }
+
+        public int getScanCount() {
+            return scanCount;
+        }
+
+        public int getStartScan() {
+            return startScan;
+        }
+
+        public Rectangle2D getSrcBounds() {
+            return srcBounds;
+        }
+
+        public Rectangle2D getDstBounds() {
+            return dstBounds;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "colorUsage", this::getColorUsage,
+                "scanCount", this::getScanCount,
+                "startScan", this::getStartScan,
+                "srcBounds", this::getSrcBounds,
+                "dstBounds", this::getDstBounds,
+                "dib", () -> dib
+            );
+        }
     }
 
 
@@ -685,13 +825,9 @@ public class HwmfFill {
         
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int 
recordFunction) throws IOException {
-            boolean hasBitmap = (recordSize/2 != ((recordFunction >> 8) + 3));
+            final boolean hasBitmap = hasBitmap(recordSize/2, recordFunction);
 
-            int rasterOpCode = leis.readUShort();
-            int rasterOpIndex = leis.readUShort();
-            
-            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
-            assert(rasterOpCode == rasterOperation.opCode);
+            rasterOperation = readRasterOperation(leis);
 
             int size = 2*LittleEndianConsts.SHORT_SIZE;
 
@@ -752,13 +888,9 @@ public class HwmfFill {
         
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int 
recordFunction) throws IOException {
-            boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));
+            final boolean hasBitmap = hasBitmap(recordSize, recordFunction);
 
-            int rasterOpCode = leis.readUShort();
-            int rasterOpIndex = leis.readUShort();
-            
-            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
-            assert(rasterOperation != null && rasterOpCode == 
rasterOperation.opCode);
+            rasterOperation = readRasterOperation(leis);
 
             int size = 2*LittleEndianConsts.SHORT_SIZE;
 
@@ -802,12 +934,36 @@ public class HwmfFill {
         public byte[] getBMPData() {
             return (target != null && target.isValid()) ? target.getBMPData() 
: null;
         }
+
+        public HwmfTernaryRasterOp getRasterOperation() {
+            return rasterOperation;
+        }
+
+        public Rectangle2D getSrcBounds() {
+            return srcBounds;
+        }
+
+        public Rectangle2D getDstBounds() {
+            return dstBounds;
+        }
+
+        public HwmfBitmapDib getTarget() {
+            return target;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "rasterOperation", this::getRasterOperation,
+                "srcBounds", this::getSrcBounds,
+                "dstBounds", this::getDstBounds,
+                "target", this::getTarget
+            );
+        }
     }
 
     static int readBounds2(LittleEndianInputStream leis, Rectangle2D bounds) {
-        /**
-         * The 16-bit signed integers that defines the corners of the bounding 
rectangle.
-         */
+        // The 16-bit signed integers that defines the corners of the bounding 
rectangle.
         int h = leis.readShort();
         int w = leis.readShort();
         int y = leis.readShort();
@@ -818,4 +974,16 @@ public class HwmfFill {
         return 4 * LittleEndianConsts.SHORT_SIZE;
     }
 
+    private static boolean hasBitmap(long recordSize, int recordFunction) {
+        return (recordSize > ((recordFunction >> 8) + 3));
+    }
+
+    private static HwmfTernaryRasterOp 
readRasterOperation(LittleEndianInputStream leis) {
+        int rasterOpCode = leis.readUShort();
+        int rasterOpIndex = leis.readUShort();
+
+        HwmfTernaryRasterOp rasterOperation = 
HwmfTernaryRasterOp.valueOf(rasterOpIndex);
+        assert(rasterOperation != null && rasterOpCode == 
rasterOperation.opCode);
+        return rasterOperation;
+    }
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java?rev=1866808&r1=1866807&r2=1866808&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java 
(original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java Wed 
Sep 11 21:24:06 2019
@@ -19,7 +19,12 @@ package org.apache.poi.hwmf.record;
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.function.Supplier;
 
+import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.common.usermodel.fonts.FontCharset;
 import org.apache.poi.common.usermodel.fonts.FontFamily;
 import org.apache.poi.common.usermodel.fonts.FontHeader;
@@ -27,6 +32,8 @@ import org.apache.poi.common.usermodel.f
 import org.apache.poi.common.usermodel.fonts.FontPitch;
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.util.GenericRecordJsonWriter;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 
@@ -34,7 +41,7 @@ import org.apache.poi.util.LittleEndianI
  * The Font object specifies the attributes of a logical font
  */
 @SuppressWarnings({"unused", "Duplicates"})
-public class HwmfFont implements FontInfo {
+public class HwmfFont implements FontInfo, GenericRecord {
 
     /**
      * The output precision defines how closely the output must match the 
requested font's height,
@@ -108,17 +115,17 @@ public class HwmfFont implements FontInf
      * ClipPrecision Flags specify clipping precision, which defines how to 
clip characters that are
      * partially outside a clipping region. These flags can be combined to 
specify multiple options.
      */
-    public static class WmfClipPrecision {
+    public static class WmfClipPrecision implements GenericRecord {
 
         /** Specifies that default clipping MUST be used. */
-        private static final BitField CLIP_DEFAULT_PRECIS = 
BitFieldFactory.getInstance(0x0000);
+        private static final BitField DEFAULT_PRECIS = 
BitFieldFactory.getInstance(0x0003);
 
 
         /** This value SHOULD NOT be used. */
-        private static final BitField CLIP_CHARACTER_PRECIS = 
BitFieldFactory.getInstance(0x0001);
+        private static final BitField CHARACTER_PRECIS = 
BitFieldFactory.getInstance(0x0001);
 
         /** This value MAY be returned when enumerating rasterized, TrueType 
and vector fonts. */
-        private static final BitField CLIP_STROKE_PRECIS = 
BitFieldFactory.getInstance(0x0002);
+        private static final BitField STROKE_PRECIS = 
BitFieldFactory.getInstance(0x0002);
 
         /**
          * This value is used to control font rotation, as follows:
@@ -128,39 +135,79 @@ public class HwmfFont implements FontInf
          * If clear, device fonts SHOULD rotate counterclockwise, but the 
rotation of other fonts
          * SHOULD be determined by the orientation of the coordinate system.
          */
-        private static final BitField CLIP_LH_ANGLES = 
BitFieldFactory.getInstance(0x0010);
+        private static final BitField LH_ANGLES = 
BitFieldFactory.getInstance(0x0010);
 
         /** This value SHOULD NOT be used. */
-        private static final BitField CLIP_TT_ALWAYS = 
BitFieldFactory.getInstance(0x0020);
+        private static final BitField TT_ALWAYS = 
BitFieldFactory.getInstance(0x0020);
 
-        /** This value specifies that font association SHOULD< be turned off. 
*/
-        private static final BitField CLIP_DFA_DISABLE = 
BitFieldFactory.getInstance(0x0040);
+        /** This value specifies that font association SHOULD be turned off. */
+        private static final BitField DFA_DISABLE = 
BitFieldFactory.getInstance(0x0040);
 
         /**
          * This value specifies that font embedding MUST be used to render 
document content;
          * embedded fonts are read-only.
          */
-        private static final BitField CLIP_EMBEDDED = 
BitFieldFactory.getInstance(0x0080);
+        private static final BitField EMBEDDED = 
BitFieldFactory.getInstance(0x0080);
 
-        int flag;
+        private static final int[] FLAG_MASKS = {
+            0x0001, 0x0002, 0x0010, 0x0020, 0x0040, 0x0080
+        };
+
+        private static final String[] FLAG_NAMES = {
+            "CHARACTER_PRECIS",
+            "STROKE_PRECIS",
+            "LH_ANGLES",
+            "TT_ALWAYS",
+            "DFA_DISABLE",
+            "EMBEDDED"
+        };
+
+        private int flag;
 
         public int init(LittleEndianInputStream leis) {
             flag = leis.readUByte();
             return LittleEndianConsts.BYTE_SIZE;
         }
 
+        public boolean isDefaultPrecision() {
+            return !DEFAULT_PRECIS.isSet(flag);
+        }
+
+        public boolean isCharacterPrecision() {
+            return CHARACTER_PRECIS.isSet(flag);
+        }
+
+        public boolean isStrokePrecision() {
+            return STROKE_PRECIS.isSet(flag);
+        }
+
+        public boolean isLeftHandAngles() {
+            return LH_ANGLES.isSet(flag);
+        }
+
+        public boolean isTrueTypeAlways() {
+            return TT_ALWAYS.isSet(flag);
+        }
+
+        public boolean isFontAssociated() {
+            return !DFA_DISABLE.isSet(flag);
+        }
+
+        public boolean useEmbeddedFont() {
+            return EMBEDDED.isSet(flag);
+        }
+
         @Override
         public String toString() {
-            return
-                (((flag&0x3) == 0 ? "default " : " ")+
-                (CLIP_CHARACTER_PRECIS.isSet(flag) ? "char " : " ")+
-                (CLIP_STROKE_PRECIS.isSet(flag) ? "stroke " : " ")+
-                (CLIP_LH_ANGLES.isSet(flag) ? "angles " : " ")+
-                (CLIP_TT_ALWAYS.isSet(flag) ? "tt_always " : " ")+
-                (CLIP_DFA_DISABLE.isSet(flag) ? "dfa " : " ")+
-                (CLIP_EMBEDDED.isSet(flag) ? "embedded " : " ")
-                ).trim()
-            ;
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "isDefaultPrecision", this::isDefaultPrecision,
+                "flag", GenericRecordUtil.getBitsAsString(() -> flag, 
FLAG_MASKS, FLAG_NAMES)
+            );
         }
     }
 
@@ -456,21 +503,7 @@ public class HwmfFont implements FontInf
 
     @Override
     public String toString() {
-        return "{ height: "+height+
-                ", width: "+width+
-                ", escapment: "+escapement+
-                ", weight: "+weight+
-                ", italic: "+italic+
-                ", underline: "+underline+
-                ", strikeOut: "+strikeOut+
-                ", charset: '"+charSet+"'"+
-                ", outPrecision: '"+outPrecision+"'"+
-                ", clipPrecision: '"+clipPrecision+"'"+
-                ", quality: '"+quality+"'"+
-                ", pitch: '"+getPitch()+"'"+
-                ", family: '"+getFamily()+"'"+
-                ", facename: '"+facename+"'"+
-                "}";
+        return GenericRecordJsonWriter.marshal(this);
     }
 
     protected int readString(LittleEndianInputStream leis, StringBuilder sb, 
int limit) throws IOException {
@@ -489,4 +522,24 @@ public class HwmfFont implements FontInf
 
         return readBytes;
     }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        final Map<String,Supplier<?>> m = new LinkedHashMap<>();
+        m.put("height", this::getHeight);
+        m.put("width", this::getWidth);
+        m.put("escapment", this::getEscapement);
+        m.put("weight", this::getWeight);
+        m.put("italic", this::isItalic);
+        m.put("underline", this::isUnderline);
+        m.put("strikeOut", this::isStrikeOut);
+        m.put("charset", this::getCharset);
+        m.put("outPrecision", this::getOutPrecision);
+        m.put("clipPrecision", this::getClipPrecision);
+        m.put("quality", this::getQuality);
+        m.put("pitch", this::getPitch);
+        m.put("family", this::getFamily);
+        m.put("typeface", this::getTypeface);
+        return Collections.unmodifiableMap(m);
+    }
 }

Modified: 
poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHeader.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHeader.java?rev=1866808&r1=1866807&r2=1866808&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHeader.java 
(original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHeader.java Wed 
Sep 11 21:24:06 2019
@@ -18,12 +18,21 @@
 package org.apache.poi.hwmf.record;
 
 import java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.function.Supplier;
 
+import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 
-public class HwmfHeader {
-    private int type;
+public class HwmfHeader implements GenericRecord {
+    public enum HwmfHeaderMetaType {
+        MEMORY_METAFILE, DISK_METAFILE
+    }
+
+    private HwmfHeaderMetaType type;
     private int recordSize;
     private int version;
     private int filesize;
@@ -34,7 +43,7 @@ public class HwmfHeader {
     public HwmfHeader(LittleEndianInputStream leis) throws IOException {
         // Type (2 bytes):  A 16-bit unsigned integer that defines the type of 
metafile
         // MEMORYMETAFILE = 0x0001, DISKMETAFILE = 0x0002 
-        type = leis.readUShort();
+        type = HwmfHeaderMetaType.values()[leis.readUShort()-1];
 
         // HeaderSize (2 bytes):  A 16-bit unsigned integer that defines the 
number
         // of 16-bit words in the header.
@@ -74,4 +83,17 @@ public class HwmfHeader {
             assert(len == bytesLeft);
         }
     }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        final Map<String,Supplier<?>> m = new LinkedHashMap<>();
+        m.put("type", () -> type);
+        m.put("recordSize", () -> recordSize);
+        m.put("version", () -> version);
+        m.put("filesize", () -> filesize);
+        m.put("numberOfObjects", () -> numberOfObjects);
+        m.put("maxRecord", () -> maxRecord);
+        m.put("numberOfMembers", () -> numberOfMembers);
+        return Collections.unmodifiableMap(m);
+    }
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java?rev=1866808&r1=1866807&r2=1866808&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java 
(original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java Wed 
Sep 11 21:24:06 2019
@@ -21,6 +21,8 @@ import java.awt.Color;
 import java.awt.geom.Dimension2D;
 import java.awt.image.BufferedImage;
 import java.io.IOException;
+import java.util.Map;
+import java.util.function.Supplier;
 
 import org.apache.poi.hwmf.draw.HwmfDrawProperties;
 import org.apache.poi.hwmf.draw.HwmfGraphics;
@@ -28,9 +30,12 @@ import org.apache.poi.hwmf.record.HwmfFi
 import org.apache.poi.hwmf.record.HwmfFill.HwmfImageRecord;
 import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;
 import org.apache.poi.util.Dimension2DDouble;
+import org.apache.poi.util.GenericRecordJsonWriter;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 
+@SuppressWarnings("WeakerAccess")
 public class HwmfMisc {
 
     /**
@@ -56,6 +61,11 @@ public class HwmfMisc {
         public String toString() {
             return "{}";
         }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return null;
+        }
     }
 
     /**
@@ -74,6 +84,11 @@ public class HwmfMisc {
         public void draw(HwmfGraphics ctx) {
 
         }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return null;
+        }
     }
 
     /**
@@ -107,7 +122,16 @@ public class HwmfMisc {
 
         @Override
         public String toString() {
-            return "{ nSavedDC: "+nSavedDC+" }";
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public int getNSavedDC() {
+            return nSavedDC;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("nSavedDC", 
this::getNSavedDC);
         }
     }
 
@@ -136,7 +160,16 @@ public class HwmfMisc {
 
         @Override
         public String toString() {
-            return "{ colorRef: "+colorRef+" }";
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public HwmfColorRef getColorRef() {
+            return colorRef;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("colorRef", 
this::getColorRef);
         }
     }
 
@@ -184,7 +217,16 @@ public class HwmfMisc {
 
         @Override
         public String toString() {
-            return "{ bkMode: '"+bkMode+"' }";
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public HwmfBkMode getBkMode() {
+            return bkMode;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("bkMode", 
this::getBkMode);
         }
     }
 
@@ -219,6 +261,11 @@ public class HwmfMisc {
         public void draw(HwmfGraphics ctx) {
 
         }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("layout", () -> 
layout);
+        }
     }
 
     /**
@@ -249,7 +296,16 @@ public class HwmfMisc {
 
         @Override
         public String toString() {
-            return "{ mapMode: '"+mapMode+"' }";
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public HwmfMapMode getMapMode() {
+            return mapMode;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("mapMode", 
this::getMapMode);
         }
     }
 
@@ -285,7 +341,12 @@ public class HwmfMisc {
 
         @Override
         public String toString() {
-            return "{ mapperValues: "+mapperValues+" }";
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("mapperValues", () 
-> mapperValues);
         }
     }
 
@@ -317,7 +378,16 @@ public class HwmfMisc {
 
         @Override
         public String toString() {
-            return "{ drawMode: '"+drawMode+"' }";
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public HwmfBinaryRasterOp getDrawMode() {
+            return drawMode;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("drawMode", 
this::getDrawMode);
         }
     }
 
@@ -394,7 +464,16 @@ public class HwmfMisc {
 
         @Override
         public String toString() {
-            return "{ stretchBltMode: '"+stretchBltMode+"' }";
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public StretchBltMode getStretchBltMode() {
+            return stretchBltMode;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("stretchBltMode", 
this::getStretchBltMode);
         }
     }
 
@@ -486,6 +565,24 @@ public class HwmfMisc {
                 return null;
             }
         }
+
+        public HwmfBrushStyle getStyle() {
+            return style;
+        }
+
+        public ColorUsage getColorUsage() {
+            return colorUsage;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "style", this::getStyle,
+                "colorUsage", this::getColorUsage,
+                "pattern", () -> (patternDib != null && patternDib.isValid()) 
? patternDib : pattern16,
+                "bmpData", this::getBMPData
+            );
+        }
     }
 
     /**
@@ -524,7 +621,16 @@ public class HwmfMisc {
 
         @Override
         public String toString() {
-            return "{ index: "+objectIndex+" }";
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public int getObjectIndex() {
+            return objectIndex;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("objectIndex", 
this::getObjectIndex);
         }
     }
 
@@ -554,6 +660,15 @@ public class HwmfMisc {
             dp.setBrushBitmap(pattern.getImage());
             dp.setBrushStyle(HwmfBrushStyle.BS_PATTERN);
         }
+
+        public HwmfBitmap16 getPattern() {
+            return pattern;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("pattern", 
this::getPattern);
+        }
     }
 
     public static class WmfCreatePenIndirect implements HwmfRecord, 
HwmfObjectTableEntry {
@@ -599,10 +714,28 @@ public class HwmfMisc {
 
         @Override
         public String toString() {
-            return
-                "{ penStyle: "+penStyle+
-                ", dimension: { width: "+dimension.getWidth()+", height: 
"+dimension.getHeight()+" }"+
-                ", colorRef: "+colorRef+"}";
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public HwmfPenStyle getPenStyle() {
+            return penStyle;
+        }
+
+        public Dimension2D getDimension() {
+            return dimension;
+        }
+
+        public HwmfColorRef getColorRef() {
+            return colorRef;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "penStyle", this::getPenStyle,
+                "dimension", this::getDimension,
+                "colorRef", this::getColorRef
+            );
         }
     }
 
@@ -687,10 +820,28 @@ public class HwmfMisc {
 
         @Override
         public String toString() {
-            return
-                "{ brushStyle: '"+brushStyle+"'"+
-                ", colorRef: "+colorRef+
-                ", brushHatch: '"+brushHatch+"' }";
+            return GenericRecordJsonWriter.marshal(this);
+        }
+
+        public HwmfBrushStyle getBrushStyle() {
+            return brushStyle;
+        }
+
+        public HwmfColorRef getColorRef() {
+            return colorRef;
+        }
+
+        public HwmfHatchStyle getBrushHatch() {
+            return brushHatch;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "brushStyle", this::getBrushStyle,
+                "colorRef", this::getColorRef,
+                "brushHatch", this::getBrushHatch
+            );
         }
     }
 }
\ No newline at end of file

Modified: 
poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java?rev=1866808&r1=1866807&r2=1866808&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java 
(original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java 
Wed Sep 11 21:24:06 2019
@@ -17,25 +17,35 @@
 
 package org.apache.poi.hwmf.record;
 
+import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
+
 import java.awt.Color;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
 
+import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hwmf.draw.HwmfDrawProperties;
 import org.apache.poi.hwmf.draw.HwmfGraphics;
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.util.GenericRecordUtil;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 
 public class HwmfPalette {
 
-    public static class PaletteEntry {
+    public static class PaletteEntry implements GenericRecord {
         private static final BitField PC_RESERVED   = 
BitFieldFactory.getInstance(0x01);
         private static final BitField PC_EXPLICIT   = 
BitFieldFactory.getInstance(0x02);
         private static final BitField PC_NOCOLLAPSE = 
BitFieldFactory.getInstance(0x04);
 
+        private static final int[] FLAGS_MASKS = { 1,2,4 };
+
+        private static final String[] FLAGS_NAMES = { "RESERVED", "EXPLICIT", 
"NOCOLLAPSE" };
+
         private int values;
         private Color colorRef;
 
@@ -91,6 +101,18 @@ public class HwmfPalette {
         public boolean isNoCollapse() {
             return PC_NOCOLLAPSE.isSet(values);
         }
+
+        public Color getColorRef() {
+            return colorRef;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "flags", getBitsAsString(() -> values, FLAGS_MASKS, 
FLAGS_NAMES),
+                "color", this::getColorRef
+            );
+        }
     }
 
     public static abstract class WmfPaletteParent implements HwmfRecord, 
HwmfObjectTableEntry  {
@@ -112,10 +134,8 @@ public class HwmfPalette {
         }
 
         protected int readPaletteEntries(LittleEndianInputStream leis, int 
nbrOfEntries) throws IOException {
-            /**
-             * NumberOfEntries (2 bytes):  A 16-bit unsigned integer that 
defines the number of objects in
-             * aPaletteEntries.
-             */
+            // NumberOfEntries (2 bytes):  A 16-bit unsigned integer that 
defines the number of objects in
+            // aPaletteEntries.
             final int numberOfEntries = (nbrOfEntries > -1) ? nbrOfEntries : 
leis.readUShort();
             int size = (nbrOfEntries > -1) ? 0 : LittleEndianConsts.SHORT_SIZE;
             for (int i=0; i<numberOfEntries; i++) {
@@ -131,7 +151,7 @@ public class HwmfPalette {
             ctx.addObjectTableEntry(this);
         }
         
-        protected List<PaletteEntry> getPaletteCopy() {
+        List<PaletteEntry> getPaletteCopy() {
             List<PaletteEntry> newPalette = new ArrayList<>();
             for (PaletteEntry et : palette) {
                 newPalette.add(new PaletteEntry(et));
@@ -139,9 +159,17 @@ public class HwmfPalette {
             return newPalette;
         }
 
-        protected int getPaletteStart() {
+        int getPaletteStart() {
             return start;
         }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties(
+                "paletteStart", this::getPaletteStart,
+                "pallete", this::getPaletteCopy
+            );
+        }
     }
 
     /**
@@ -233,6 +261,15 @@ public class HwmfPalette {
             palette = palette.subList(0, numberOfEntries);
             props.setPalette(palette);
         }
+
+        public int getNumberOfEntries() {
+            return numberOfEntries;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("numberOfEntries", 
this::getNumberOfEntries);
+        }
     }
 
     /**
@@ -260,6 +297,15 @@ public class HwmfPalette {
         public void draw(HwmfGraphics ctx) {
             ctx.applyObjectTableEntry(paletteIndex);
         }
+
+        public int getPaletteIndex() {
+            return paletteIndex;
+        }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return GenericRecordUtil.getGenericProperties("paletteIndex", 
this::getPaletteIndex);
+        }
     }
 
     /**
@@ -281,6 +327,11 @@ public class HwmfPalette {
         public void draw(HwmfGraphics ctx) {
 
         }
+
+        @Override
+        public Map<String, Supplier<?>> getGenericProperties() {
+            return null;
+        }
     }
 
     /**
@@ -306,7 +357,7 @@ public class HwmfPalette {
             HwmfDrawProperties props = ctx.getProperties();
             List<PaletteEntry> dest = props.getPalette();
             List<PaletteEntry> src = getPaletteCopy();
-            int start = getPaletteStart();
+            final int start = getPaletteStart();
             if (dest == null) {
                 dest = new ArrayList<>();
             }

Modified: 
poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java?rev=1866808&r1=1866807&r2=1866808&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java 
(original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java 
Wed Sep 11 21:24:06 2019
@@ -18,9 +18,14 @@
 package org.apache.poi.hwmf.record;
 
 import java.awt.BasicStroke;
+import java.util.Map;
+import java.util.function.Supplier;
 
+import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.util.GenericRecordJsonWriter;
+import org.apache.poi.util.GenericRecordUtil;
 
 /**
  * The 16-bit PenStyle Enumeration is used to specify different types of pens
@@ -32,7 +37,7 @@ import org.apache.poi.util.BitFieldFacto
  * The defaults in case the other values of the subsection aren't set are
  * solid, round end caps, round joins and cosmetic type.
  */
-public class HwmfPenStyle implements Cloneable {
+public class HwmfPenStyle implements Cloneable, GenericRecord {
     public enum HwmfLineCap {
         /** Rounded ends */
         ROUND(0, BasicStroke.CAP_ROUND),
@@ -207,12 +212,18 @@ public class HwmfPenStyle implements Clo
 
     @Override
     public String toString() {
-        return
-            "{ lineCap: '"+getLineCap()+"'"+
-            ", lineDash: '"+getLineDash()+"'"+
-            ", lineJoin: '"+getLineJoin()+"'"+
-            (isAlternateDash()?", alternateDash: true ":"")+
-            (isGeometric()?", geometric: true ":"")+
-            "}";
+        return GenericRecordJsonWriter.marshal(this);
+    }
+
+    @Override
+    public Map<String, Supplier<?>> getGenericProperties() {
+        return GenericRecordUtil.getGenericProperties(
+            "lineCap", this::getLineCap,
+            "lineJoin", this::getLineJoin,
+            "lineDash", this::getLineDash,
+            "lineDashes", this::getLineDashes,
+            "alternateDash", this::isAlternateDash,
+            "geometric", this::isGeometric
+        );
     }
 }

Modified: 
poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRecord.java?rev=1866808&r1=1866807&r2=1866808&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRecord.java 
(original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRecord.java Wed 
Sep 11 21:24:06 2019
@@ -19,10 +19,11 @@ package org.apache.poi.hwmf.record;
 
 import java.io.IOException;
 
+import org.apache.poi.common.usermodel.GenericRecord;
 import org.apache.poi.hwmf.draw.HwmfGraphics;
 import org.apache.poi.util.LittleEndianInputStream;
 
-public interface HwmfRecord {
+public interface HwmfRecord extends GenericRecord {
     HwmfRecordType getWmfRecordType();
 
     /**
@@ -40,4 +41,9 @@ public interface HwmfRecord {
      * @param ctx the graphics context to modify
      */
     void draw(HwmfGraphics ctx);
+
+    @Override
+    default Enum getGenericRecordType() {
+        return getWmfRecordType();
+    }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@poi.apache.org
For additional commands, e-mail: commits-h...@poi.apache.org

Reply via email to