]> source.dussan.org Git - poi.git/commitdiff
#56004 - Support for WMF rendering (parsing the WMF records)
authorAndreas Beeker <kiwiwings@apache.org>
Mon, 21 Dec 2015 01:26:39 +0000 (01:26 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Mon, 21 Dec 2015 01:26:39 +0000 (01:26 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1721078 13f79535-47bb-0310-9956-ffa450edef68

20 files changed:
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmap16.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBrushStyle.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfColorRef.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfEscape.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHatchStyle.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHeader.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPlaceableHeader.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRecord.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRecordType.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfTernaryRasterOp.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java [new file with mode: 0644]

diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmap16.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmap16.java
new file mode 100644 (file)
index 0000000..52ea1d9
--- /dev/null
@@ -0,0 +1,105 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+import java.awt.image.BufferedImage;\r
+import java.io.ByteArrayInputStream;\r
+import java.io.IOException;\r
+\r
+import javax.imageio.stream.ImageInputStream;\r
+import javax.imageio.stream.MemoryCacheImageInputStream;\r
+\r
+import org.apache.poi.util.LittleEndianConsts;\r
+import org.apache.poi.util.LittleEndianInputStream;\r
+\r
+public class HwmfBitmap16 {\r
+    final boolean isPartial;\r
+    int type;\r
+    int width;\r
+    int height;\r
+    int widthBytes;\r
+    int planes;\r
+    int bitsPixel;\r
+    \r
+    public HwmfBitmap16() {\r
+        this(false);\r
+    }\r
+    \r
+    public HwmfBitmap16(boolean isPartial) {\r
+        this.isPartial = isPartial;\r
+    }\r
+    \r
+    public int init(LittleEndianInputStream leis) throws IOException {\r
+        // A 16-bit signed integer that defines the bitmap type.\r
+        type = leis.readShort();\r
+        \r
+        // A 16-bit signed integer that defines the width of the bitmap in pixels.\r
+        width = leis.readShort();\r
+        \r
+        // A 16-bit signed integer that defines the height of the bitmap in scan lines.\r
+        height = leis.readShort();\r
+        \r
+        // A 16-bit signed integer that defines the number of bytes per scan line.\r
+        widthBytes = leis.readShort();\r
+        \r
+        // An 8-bit unsigned integer that defines the number of color planes in the \r
+        // bitmap. The value of this field MUST be 0x01.\r
+        planes = leis.readUByte();\r
+        \r
+        // An 8-bit unsigned integer that defines the number of adjacent color bits on \r
+        // each plane.\r
+        bitsPixel = leis.readUByte();\r
+\r
+        int size = 2*LittleEndianConsts.BYTE_SIZE+4*LittleEndianConsts.SHORT_SIZE;\r
+        if (isPartial) {\r
+            // Bits (4 bytes): This field MUST be ignored.\r
+            long skipSize = leis.skip(LittleEndianConsts.INT_SIZE);\r
+            assert(skipSize == LittleEndianConsts.INT_SIZE);\r
+            // Reserved (18 bytes): This field MUST be ignored.\r
+            skipSize = leis.skip(18);\r
+            assert(skipSize == 18);\r
+            size += 18+LittleEndianConsts.INT_SIZE;\r
+        }\r
+        \r
+        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);\r
+        \r
+        int size2 = 0;\r
+        byte buf[] = new byte[widthBytes];\r
+        for (int h=0; h<height; h++) {\r
+            leis.read(buf);\r
+            size2 += widthBytes;\r
+\r
+            ImageInputStream iis = new MemoryCacheImageInputStream(new ByteArrayInputStream(buf));\r
+\r
+            for (int w=0; w<width; w++) {\r
+                long bitsAtPixel = iis.readBits(bitsPixel);\r
+                // TODO: is bitsPixel a multiple of 3 (r,g,b)\r
+                // which colortable should be used for the various bit sizes???\r
+                \r
+            }\r
+        }\r
+        \r
+        int bytes = (((width * bitsPixel + 15) >> 4) << 1) * height;\r
+        assert (bytes == size2);\r
+\r
+        size += size2;\r
+        \r
+        \r
+        return size;\r
+    }\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java
new file mode 100644 (file)
index 0000000..c3317d1
--- /dev/null
@@ -0,0 +1,441 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+import java.awt.Color;\r
+import java.awt.image.BufferedImage;\r
+import java.awt.image.IndexColorModel;\r
+import java.awt.image.WritableRaster;\r
+import java.io.IOException;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.apache.poi.util.LittleEndianConsts;\r
+import org.apache.poi.util.LittleEndianInputStream;\r
+\r
+/**\r
+ * The DeviceIndependentBitmap Object defines an image in device-independent bitmap (DIB) format.\r
+ */\r
+public class HwmfBitmapDib {\r
+    public static enum BitCount {\r
+        /**\r
+         * The image SHOULD be in either JPEG or PNG format. <6> Neither of these formats includes\r
+         *  a color table, so this value specifies that no color table is present. See [JFIF] and [RFC2083]\r
+         *  for more information concerning JPEG and PNG compression formats.\r
+         */\r
+        BI_BITCOUNT_0(0x0000),\r
+        /**\r
+         * Each pixel in the bitmap is represented by a single bit. If the bit is clear, the pixel is displayed\r
+         *  with the color of the first entry in the color table; if the bit is set, the pixel has the color of the\r
+         *  second entry in the table.\r
+         */\r
+        BI_BITCOUNT_1(0x0001),\r
+        /**\r
+         * Each pixel in the bitmap is represented by a 4-bit index into the color table, and each byte\r
+         *  contains 2 pixels.\r
+         */\r
+        BI_BITCOUNT_2(0x0004),\r
+        /**\r
+         * Each pixel in the bitmap is represented by an 8-bit index into the color table, and each byte\r
+         *  contains 1 pixel.\r
+         */\r
+        BI_BITCOUNT_3(0x0008),\r
+        /**\r
+         * Each pixel in the bitmap is represented by a 16-bit value.\r
+         * <br/>\r
+         * If the Compression field of the BitmapInfoHeader Object is BI_RGB, the Colors field of DIB\r
+         *  is NULL. Each WORD in the bitmap array represents a single pixel. The relative intensities of \r
+         *  red, green, and blue are represented with 5 bits for each color component. The value for blue \r
+         *  is in the least significant 5 bits, followed by 5 bits each for green and red. The most significant \r
+         *  bit is not used. The color table is used for optimizing colors on palette-based devices, and \r
+         *  contains the number of entries specified by the ColorUsed field of the BitmapInfoHeader \r
+         *  Object.\r
+         * <br/>\r
+         * If the Compression field of the BitmapInfoHeader Object is BI_BITFIELDS, the Colors field \r
+         *  contains three DWORD color masks that specify the red, green, and blue components,\r
+         *  respectively, of each pixel. Each WORD in the bitmap array represents a single pixel.\r
+         * <br/>\r
+         * When the Compression field is set to BI_BITFIELDS, bits set in each DWORD mask MUST be \r
+         *  contiguous and SHOULD NOT overlap the bits of another mask.\r
+         */\r
+        BI_BITCOUNT_4(0x0010),\r
+        /**\r
+         * The bitmap has a maximum of 2^24 colors, and the Colors field of DIB is \r
+         *  NULL. Each 3-byte triplet in the bitmap array represents the relative intensities of blue, green, \r
+         *  and red, respectively, for a pixel. The Colors color table is used for optimizing colors used on \r
+         *  palette-based devices, and MUST contain the number of entries specified by the ColorUsed\r
+         *  field of the BitmapInfoHeader Object.\r
+         */\r
+        BI_BITCOUNT_5(0x0018),\r
+        /**\r
+         * The bitmap has a maximum of 2^24 colors.\r
+         * <br/>\r
+         * If the Compression field of the BitmapInfoHeader Object is set to BI_RGB, the Colors field \r
+         *  of DIB is set to NULL. Each DWORD in the bitmap array represents the relative intensities of \r
+         *  blue, green, and red, respectively, for a pixel. The high byte in each DWORD is not used. The \r
+         *  Colors color table is used for optimizing colors used on palette-based devices, and MUST \r
+         *  contain the number of entries specified by the ColorUsed field of the BitmapInfoHeader \r
+         *  Object.\r
+         * <br/>\r
+         * If the Compression field of the BitmapInfoHeader Object is set to BI_BITFIELDS, the Colors\r
+         *  field contains three DWORD color masks that specify the red, green, and blue components, \r
+         *  respectively, of each pixel. Each DWORD in the bitmap array represents a single pixel.\r
+         * <br/>\r
+         * When the Compression field is set to BI_BITFIELDS, bits set in each DWORD mask must be \r
+         *  contiguous and should not overlap the bits of another mask. All the bits in the pixel do not \r
+         *  need to be used.\r
+         */\r
+        BI_BITCOUNT_6(0x0020);\r
+        \r
+        int flag;\r
+        BitCount(int flag) {\r
+            this.flag = flag;\r
+        }\r
+        static BitCount valueOf(int flag) {\r
+            for (BitCount bc : values()) {\r
+                if (bc.flag == flag) return bc;\r
+            }\r
+            return null;\r
+        }\r
+    }\r
+\r
+    public static enum Compression {\r
+        /**\r
+         * The bitmap is in uncompressed red green blue (RGB) format that is not compressed\r
+         * and does not use color masks.\r
+         */\r
+        BI_RGB(0x0000),\r
+        /**\r
+         * An RGB format that uses run-length encoding (RLE) compression for bitmaps\r
+         * with 8 bits per pixel. The compression uses a 2-byte format consisting of a count byte\r
+         * followed by a byte containing a color index.\r
+         */\r
+        BI_RLE8(0x0001),\r
+        /**\r
+         * An RGB format that uses RLE compression for bitmaps with 4 bits per pixel. The\r
+         * compression uses a 2-byte format consisting of a count byte followed by two word-length\r
+         * color indexes.\r
+         */\r
+        BI_RLE4(0x0002),\r
+        /**\r
+         * The bitmap is not compressed and the color table consists of three DWORD\r
+         * color masks that specify the red, green, and blue components, respectively, of each pixel.\r
+         * This is valid when used with 16 and 32-bits per pixel bitmaps.\r
+         */\r
+        BI_BITFIELDS(0x0003),\r
+        /**\r
+         * The image is a JPEG image, as specified in [JFIF]. This value SHOULD only be used in \r
+         * certain bitmap operations, such as JPEG pass-through. The application MUST query for the \r
+         * pass-through support, since not all devices support JPEG pass-through. Using non-RGB \r
+         * bitmaps MAY limit the portability of the metafile to other devices. For instance, display device \r
+         * contexts generally do not support this pass-through.\r
+         */\r
+        BI_JPEG(0x0004),\r
+        /**\r
+         * The image is a PNG image, as specified in [RFC2083]. This value SHOULD only be \r
+         * used certain bitmap operations, such as JPEG/PNG pass-through. The application MUST query \r
+         * for the pass-through support, because not all devices support JPEG/PNG pass-through. Using \r
+         * non-RGB bitmaps MAY limit the portability of the metafile to other devices. For instance, \r
+         * display device contexts generally do not support this pass-through.\r
+         */\r
+        BI_PNG(0x0005),\r
+        /**\r
+         * The image is an uncompressed CMYK format.\r
+         */\r
+        BI_CMYK(0x000B),\r
+        /**\r
+         * A CMYK format that uses RLE compression for bitmaps with 8 bits per pixel.\r
+         * The compression uses a 2-byte format consisting of a count byte followed by a byte containing\r
+         * a color index.\r
+         */\r
+        BI_CMYKRLE8(0x000C),\r
+        /**\r
+         * A CMYK format that uses RLE compression for bitmaps with 4 bits per pixel.\r
+         * The compression uses a 2-byte format consisting of a count byte followed by two word-length\r
+         * color indexes.\r
+         */\r
+        BI_CMYKRLE4(0x000D);\r
+        \r
+        int flag;\r
+        Compression(int flag) {\r
+            this.flag = flag;\r
+        }\r
+        static Compression valueOf(int flag) {\r
+            for (Compression c : values()) {\r
+                if (c.flag == flag) return c;\r
+            }\r
+            return null;\r
+        }        \r
+    }\r
+    \r
+    \r
+    int headerSize;\r
+    int headerWidth;\r
+    int headerHeight;\r
+    int headerPlanes;\r
+    BitCount headerBitCount;\r
+    Compression headerCompression;\r
+    long headerImageSize = -1;\r
+    int headerXPelsPerMeter = -1;\r
+    int headerYPelsPerMeter = -1;\r
+    long headerColorUsed = -1;\r
+    long headerColorImportant = -1;\r
+    \r
+    Color colorTable[];\r
+    int colorMaskRed=0,colorMaskGreen=0,colorMaskBlue=0;\r
+    \r
+    public int init(LittleEndianInputStream leis) throws IOException {\r
+        int size = 0;\r
+        size += readHeader(leis);\r
+        size += readColors(leis);\r
+        int size2;\r
+        switch (headerBitCount) {\r
+            default:\r
+            case BI_BITCOUNT_0:\r
+                throw new RuntimeException("JPG and PNG formats aren't supported yet.");\r
+            case BI_BITCOUNT_1:\r
+            case BI_BITCOUNT_2:\r
+            case BI_BITCOUNT_3:\r
+                size2 = readBitmapIndexed(leis);\r
+                break;\r
+            case BI_BITCOUNT_4:\r
+            case BI_BITCOUNT_5:\r
+            case BI_BITCOUNT_6:\r
+                size2 = readBitmapDirect(leis);\r
+                break;\r
+        }\r
+        \r
+        assert( headerSize != 0x0C || ((((headerWidth * headerPlanes * headerBitCount.flag + 31) & ~31) / 8) * Math.abs(headerHeight)) == size2);\r
+        assert ( headerSize == 0x0C || headerImageSize == size2 );\r
+        \r
+        size += size2;\r
+        \r
+        return size;\r
+    }\r
+\r
+    protected int readHeader(LittleEndianInputStream leis) throws IOException {\r
+        int size = 0;\r
+        \r
+        /**\r
+         * DIBHeaderInfo (variable): Either a BitmapCoreHeader Object or a\r
+         * BitmapInfoHeader Object that specifies information about the image.\r
+         * \r
+         * The first 32 bits of this field is the HeaderSize value.\r
+         * If it is 0x0000000C, then this is a BitmapCoreHeader; otherwise, this is a BitmapInfoHeader.\r
+         */\r
+        headerSize = leis.readInt();\r
+        size += LittleEndianConsts.INT_SIZE;\r
+        \r
+        // BitmapCoreHeader\r
+        // A 16-bit unsigned integer that defines the width of the DIB, in pixels.\r
+        headerWidth = leis.readUShort();\r
+        // A 16-bit unsigned integer that defines the height of the DIB, in pixels.\r
+        headerHeight = leis.readUShort();\r
+        // A 16-bit unsigned integer that defines the number of planes for the target\r
+        // device. This value MUST be 0x0001.\r
+        headerPlanes = leis.readUShort();\r
+        // A 16-bit unsigned integer that defines the format of each pixel, and the\r
+        // maximum number of colors in the DIB.\r
+        headerBitCount = BitCount.valueOf(leis.readUShort());\r
+        size += 4*LittleEndianConsts.SHORT_SIZE;\r
+\r
+        if (headerSize > 0x0C) {\r
+            // BitmapInfoHeader\r
+            // A 32-bit unsigned integer that defines the compression mode of the \r
+            // DIB. \r
+            // This value MUST NOT specify a compressed format if the DIB is a top-down bitmap,\r
+            // as indicated by the Height value.\r
+            headerCompression = Compression.valueOf((int)leis.readUInt());\r
+            // A 32-bit unsigned integer that defines the size, in bytes, of the image.\r
+            // If the Compression value is BI_RGB, this value SHOULD be zero and MUST be ignored.\r
+            // If the Compression value is BI_JPEG or BI_PNG, this value MUST specify the size of the JPEG \r
+            // or PNG image buffer, respectively.\r
+            headerImageSize = leis.readUInt();\r
+            // A 32-bit signed integer that defines the horizontal resolution, \r
+            // in pixels-per-meter, of the target device for the DIB.\r
+            headerXPelsPerMeter = leis.readInt();\r
+            // A 32-bit signed integer that defines the vertical resolution,\r
+            headerYPelsPerMeter = leis.readInt();\r
+            // A 32-bit unsigned integer that specifies the number of indexes in the\r
+            // color table used by the DIB\r
+            // in pixelsper-meter, of the target device for the DIB.\r
+            headerColorUsed = leis.readUInt();\r
+            // A 32-bit unsigned integer that defines the number of color indexes that are\r
+            // required for displaying the DIB. If this value is zero, all color indexes are required.\r
+            headerColorImportant = leis.readUInt();\r
+            size += 6*LittleEndianConsts.INT_SIZE;\r
+        }\r
+        return size;\r
+    }\r
+\r
+    protected int readColors(LittleEndianInputStream leis) throws IOException {\r
+        switch (headerBitCount) {\r
+        default:\r
+        case BI_BITCOUNT_0:\r
+            // no table\r
+            return 0;\r
+        case BI_BITCOUNT_1:\r
+            // 2 colors\r
+            return readRGBQuad(leis, 2);\r
+        case BI_BITCOUNT_2:\r
+            // 16 colors\r
+            return readRGBQuad(leis, 16);\r
+        case BI_BITCOUNT_3:\r
+            // 256 colors\r
+            return readRGBQuad(leis, 256);\r
+        case BI_BITCOUNT_5:\r
+            colorMaskRed=0xFF;\r
+            colorMaskGreen=0xFF;\r
+            colorMaskBlue=0xFF;\r
+            return 0;\r
+        case BI_BITCOUNT_4:\r
+            if (headerCompression == Compression.BI_RGB) {\r
+                colorMaskBlue = 0x1F;\r
+                colorMaskGreen = 0x1F<<5;\r
+                colorMaskRed = 0x1F<<10;\r
+                return 0;\r
+            } else {\r
+                assert(headerCompression == Compression.BI_BITFIELDS);\r
+                colorMaskBlue = leis.readInt();\r
+                colorMaskGreen = leis.readInt();\r
+                colorMaskRed = leis.readInt();\r
+                return 3*LittleEndianConsts.INT_SIZE;\r
+            }\r
+        case BI_BITCOUNT_6:    \r
+            if (headerCompression == Compression.BI_RGB) {\r
+                colorMaskBlue = colorMaskGreen = colorMaskRed = 0xFF;\r
+                return 0;\r
+            } else {\r
+                assert(headerCompression == Compression.BI_BITFIELDS);\r
+                colorMaskBlue = leis.readInt();\r
+                colorMaskGreen = leis.readInt();\r
+                colorMaskRed = leis.readInt();\r
+                return 3*LittleEndianConsts.INT_SIZE;\r
+            }\r
+        }\r
+    }\r
+    \r
+    protected int readRGBQuad(LittleEndianInputStream leis, int count) throws IOException {\r
+        int size = 0;\r
+        List<Color> colorList = new ArrayList<Color>();\r
+        for (int i=0; i<count; i++) {\r
+            int blue = leis.readUByte();\r
+            int green = leis.readUByte();\r
+            int red = leis.readUByte();\r
+            @SuppressWarnings("unused")\r
+            int reserved = leis.readUByte();\r
+            Color c = new Color(red, green, blue);\r
+            colorList.add(c);\r
+            size += 4 * LittleEndianConsts.BYTE_SIZE;\r
+        }\r
+        colorTable = colorList.toArray(new Color[colorList.size()]);\r
+        return size;\r
+    }\r
+    \r
+    protected int readBitmapIndexed(LittleEndianInputStream leis) throws IOException {\r
+        assert(colorTable != null);\r
+        byte r[] = new byte[colorTable.length];\r
+        byte g[] = new byte[colorTable.length];\r
+        byte b[] = new byte[colorTable.length];\r
+        for (int i=0; i<colorTable.length; i++) {\r
+            r[i] = (byte)colorTable[i].getRed();\r
+            g[i] = (byte)colorTable[i].getGreen();\r
+            b[i] = (byte)colorTable[i].getBlue();\r
+        }\r
+        int bits = 32-Integer.numberOfLeadingZeros(colorTable.length);\r
+        IndexColorModel cm = new IndexColorModel(bits,colorTable.length,r,g,b);\r
+        \r
+        BufferedImage bi = new BufferedImage(headerWidth, headerHeight, BufferedImage.TYPE_BYTE_INDEXED, cm);\r
+        WritableRaster wr = bi.getRaster();\r
+        \r
+        int pixelCount = headerWidth*headerHeight;\r
+        int size = 0;\r
+        for (int pixel=0; pixel<pixelCount; size++) {\r
+            int v = leis.readUByte();\r
+            switch (headerBitCount) {\r
+            default:\r
+                throw new RuntimeException("invalid bitcount for indexed image");\r
+            case BI_BITCOUNT_1:\r
+                for (int j=0; j<8 && pixel<pixelCount; j++,pixel++) {\r
+                    wr.setSample(pixel/headerWidth,pixel%headerWidth,0,(v>>(7-j))&1);\r
+                }\r
+                break;\r
+            case BI_BITCOUNT_2:\r
+                wr.setSample(pixel/headerWidth, pixel%headerWidth, 0, (v>>4)&15);\r
+                pixel++;\r
+                if (pixel<pixelCount) {\r
+                    wr.setSample(pixel/headerWidth, pixel%headerWidth, 0, v&15);\r
+                    pixel++;\r
+                }\r
+                break;\r
+            case BI_BITCOUNT_3:\r
+                wr.setSample(pixel/headerWidth, pixel%headerWidth, 0, v);\r
+                pixel++;\r
+                break;\r
+            }\r
+        }\r
+        return size;\r
+    }\r
+    \r
+    protected int readBitmapDirect(LittleEndianInputStream leis) throws IOException {\r
+        assert(colorTable == null);\r
+        \r
+        BufferedImage bi = new BufferedImage(headerWidth, headerHeight, BufferedImage.TYPE_INT_RGB);\r
+        WritableRaster wr = bi.getRaster();\r
+        \r
+        int bitShiftRed=0,bitShiftGreen=0,bitShiftBlue=0;\r
+        if (headerCompression == Compression.BI_BITFIELDS) {\r
+            bitShiftGreen = 32-Integer.numberOfLeadingZeros(this.colorMaskBlue);\r
+            bitShiftRed = 32-Integer.numberOfLeadingZeros(this.colorMaskGreen);\r
+        }\r
+        \r
+        int pixelCount = headerWidth*headerHeight;\r
+        int size = 0;\r
+        int rgb[] = new int[3];\r
+        for (int pixel=0; pixel<pixelCount; pixel++) {\r
+            int v;\r
+            switch (headerBitCount) {\r
+            default:\r
+                throw new RuntimeException("invalid bitcount for indexed image");\r
+            case BI_BITCOUNT_4:\r
+                v = leis.readUShort();\r
+                rgb[0] = (v & colorMaskRed) >> bitShiftRed;\r
+                rgb[1] = (v & colorMaskGreen) >> bitShiftGreen;\r
+                rgb[2] = (v & colorMaskBlue) >> bitShiftBlue;\r
+                size += LittleEndianConsts.SHORT_SIZE;\r
+                break;\r
+            case BI_BITCOUNT_5:\r
+                rgb[2] = leis.readUByte();\r
+                rgb[1] = leis.readUByte();\r
+                rgb[0] = leis.readUByte();\r
+                size += 3*LittleEndianConsts.BYTE_SIZE;\r
+                break;\r
+            case BI_BITCOUNT_6:\r
+                v = leis.readInt();\r
+                rgb[0] = (v & colorMaskRed) >> bitShiftRed;\r
+                rgb[1] = (v & colorMaskGreen) >> bitShiftGreen;\r
+                rgb[2] = (v & colorMaskBlue) >> bitShiftBlue;\r
+                size += LittleEndianConsts.INT_SIZE;\r
+                break;\r
+            }\r
+            wr.setPixel(pixel/headerWidth,pixel%headerWidth,rgb);\r
+        }\r
+        \r
+        return size;\r
+    }\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBrushStyle.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBrushStyle.java
new file mode 100644 (file)
index 0000000..5568e2b
--- /dev/null
@@ -0,0 +1,80 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+/**\r
+ * A 16-bit unsigned integer that defines the brush style. The legal values for this\r
+ * field are defined as follows: if the value is not BS_PATTERN, BS_DIBPATTERNPT MUST be\r
+ * assumed.\r
+ */\r
+public enum HwmfBrushStyle {\r
+    /**\r
+     * A brush that paints a single, constant color, either solid or dithered.\r
+     */\r
+    BS_SOLID(0x0000),\r
+    /**\r
+     * A brush that does nothing. Using a BS_NULL brush in a graphics operation\r
+     * MUST have the same effect as using no brush at all.\r
+     */\r
+    BS_NULL(0x0001),\r
+    /**\r
+     * A brush that paints a predefined simple pattern, or "hatch", onto a solid background.\r
+     */\r
+    BS_HATCHED(0x0002),\r
+    /**\r
+     * A brush that paints a pattern defined by a bitmap, which MAY be a Bitmap16\r
+     * Object or a DeviceIndependentBitmap (DIB) Object.\r
+     */\r
+    BS_PATTERN(0x0003),\r
+    /**\r
+     * Not supported\r
+     */\r
+    BS_INDEXED(0x0004),\r
+    /**\r
+     * A pattern brush specified by a DIB.\r
+     */\r
+    BS_DIBPATTERN(0x0005),\r
+    /**\r
+     * A pattern brush specified by a DIB.\r
+     */\r
+    BS_DIBPATTERNPT(0x0006),\r
+    /**\r
+     * Not supported\r
+     */\r
+    BS_PATTERN8X8(0x0007),\r
+    /**\r
+     * Not supported\r
+     */\r
+    BS_DIBPATTERN8X8(0x0008),\r
+    /**\r
+     * Not supported\r
+     */\r
+    BS_MONOPATTERN(0x0009);\r
+\r
+    int flag;\r
+    HwmfBrushStyle(int flag) {\r
+        this.flag = flag;\r
+    }\r
+\r
+    static HwmfBrushStyle valueOf(int flag) {\r
+        for (HwmfBrushStyle bs : values()) {\r
+            if (bs.flag == flag) return bs;\r
+        }\r
+        return null;\r
+    }\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfColorRef.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfColorRef.java
new file mode 100644 (file)
index 0000000..9a5288f
--- /dev/null
@@ -0,0 +1,47 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+import java.awt.Color;\r
+import java.io.IOException;\r
+\r
+import org.apache.poi.util.LittleEndianConsts;\r
+import org.apache.poi.util.LittleEndianInputStream;\r
+\r
+public class HwmfColorRef {\r
+    /**\r
+     * A 32-bit ColorRef Object that defines the color value.\r
+     * Red (1 byte):  An 8-bit unsigned integer that defines the relative intensity of red.\r
+     * Green (1 byte):  An 8-bit unsigned integer that defines the relative intensity of green.\r
+     * Blue (1 byte):  An 8-bit unsigned integer that defines the relative intensity of blue.\r
+     * Reserved (1 byte):  An 8-bit unsigned integer that MUST be 0x00.\r
+     */\r
+    Color colorRef;\r
+    \r
+    public int init(LittleEndianInputStream leis) throws IOException {\r
+        int red = leis.readUByte();\r
+        int green = leis.readUByte();\r
+        int blue = leis.readUByte();\r
+        @SuppressWarnings("unused")\r
+        int reserved = leis.readUByte();\r
+\r
+        colorRef = new Color(red, green, blue);\r
+        return 4*LittleEndianConsts.BYTE_SIZE;\r
+    }\r
+\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java
new file mode 100644 (file)
index 0000000..81526dd
--- /dev/null
@@ -0,0 +1,619 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+import java.io.IOException;\r
+\r
+import org.apache.poi.util.LittleEndianConsts;\r
+import org.apache.poi.util.LittleEndianInputStream;\r
+\r
+public class HwmfDraw {\r
+    /**\r
+     * The META_MOVETO record sets the output position in the playback device context to a specified\r
+     * point.\r
+     */\r
+    public static class WmfMoveTo implements HwmfRecord {\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units.\r
+         */\r
+        int y;\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units.\r
+         */\r
+        int x;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.moveTo;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            y = leis.readShort();\r
+            x = leis.readShort();\r
+            return 2*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * The META_LINETO record draws a line from the drawing position that is defined in the playback\r
+     * device context up to, but not including, the specified point.\r
+     */\r
+    public static class WmfLineTo implements HwmfRecord {\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the vertical component of the drawing\r
+         * destination position, in logical units.\r
+         */\r
+        int y;\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the horizontal component of the drawing\r
+         * destination position, in logical units.\r
+         */\r
+        int x;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.lineTo;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            y = leis.readShort();\r
+            x = leis.readShort();\r
+            return 2*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * The META_POLYGON record paints a polygon consisting of two or more vertices connected by\r
+     * straight lines. The polygon is outlined by using the pen and filled by using the brush and polygon fill\r
+     * mode that are defined in the playback device context.\r
+     */\r
+    public static class WmfPolygon implements HwmfRecord {\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the number of points in the array.\r
+         */\r
+        int numberofPoints;\r
+        \r
+        short xPoints[], yPoints[];\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.polygon;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            numberofPoints = leis.readShort();\r
+            xPoints = new short[numberofPoints];\r
+            yPoints = new short[numberofPoints];\r
+            \r
+            for (int i=0; i<numberofPoints; i++) {\r
+                // A 16-bit signed integer that defines the horizontal (x) coordinate of the point.\r
+                xPoints[i] = leis.readShort();\r
+                // A 16-bit signed integer that defines the vertical (y) coordinate of the point.\r
+                yPoints[i] = leis.readShort();\r
+            }\r
+            \r
+            return LittleEndianConsts.SHORT_SIZE+numberofPoints*LittleEndianConsts.INT_SIZE;\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * The META_POLYLINE record draws a series of line segments by connecting the points in the\r
+     * specified array.\r
+     */\r
+    public static class WmfPolyline extends WmfPolygon {\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.polyline;\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * The META_ELLIPSE record draws an ellipse. The center of the ellipse is the center of the specified\r
+     * bounding rectangle. The ellipse is outlined by using the pen and is filled by using the brush; these\r
+     * are defined in the playback device context.\r
+     */\r
+    public static class WmfEllipse implements HwmfRecord {\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
+         * the lower-right corner of the bounding rectangle.\r
+         */\r
+        int bottomRect;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
+         * the lower-right corner of the bounding rectangle.\r
+         */\r
+        int rightRect;\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
+         * upper-left corner of the bounding rectangle.\r
+         */\r
+        int topRect;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
+         * the upper-left corner of the bounding rectangle.\r
+         */\r
+        int leftRect;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.ellipse;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            bottomRect = leis.readShort();\r
+            rightRect = leis.readShort();\r
+            topRect = leis.readShort();\r
+            leftRect = leis.readShort();\r
+            return 4*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+\r
+    /**\r
+     * The META_FRAMEREGION record draws a border around a specified region using a specified brush.\r
+     */\r
+    public static class WmfFrameRegion implements HwmfRecord {\r
+        /**\r
+         * A 16-bit unsigned integer used to index into the WMF Object Table to get\r
+         * the region to be framed.\r
+         */\r
+        int region;  \r
+        /**\r
+         * A 16-bit unsigned integer used to index into the WMF Object Table to get the\r
+         * Brush to use for filling the region.\r
+         */\r
+        int brush;\r
+        /**\r
+         * A 16-bit signed integer that defines the height, in logical units, of the\r
+         * region frame.\r
+         */\r
+        int height;\r
+        /**\r
+         * A 16-bit signed integer that defines the width, in logical units, of the\r
+         * region frame.\r
+         */\r
+        int width;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.frameRegion;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            region = leis.readUShort();\r
+            brush = leis.readUShort();\r
+            height = leis.readShort();\r
+            width = leis.readShort();\r
+            return 4*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_POLYPOLYGON record paints a series of closed polygons. Each polygon is outlined by\r
+     * using the pen and filled by using the brush and polygon fill mode; these are defined in the playback\r
+     * device context. The polygons drawn by this function can overlap.\r
+     */\r
+    public static class WmfPolyPolygon implements HwmfRecord {\r
+        \r
+        /**\r
+         * A 16-bit unsigned integer that defines the number of polygons in the object.\r
+         */\r
+        int numberOfPolygons;\r
+        \r
+        /**\r
+         * A NumberOfPolygons array of 16-bit unsigned integers that define the number of\r
+         * points for each polygon in the object.\r
+         */\r
+        int pointsPerPolygon[];\r
+        \r
+        /**\r
+         * An array of 16-bit unsigned integers that define the coordinates of the polygons.\r
+         */\r
+        int xPoints[][];\r
+\r
+        /**\r
+         * An array of 16-bit unsigned integers that define the coordinates of the polygons.\r
+         */\r
+        int yPoints[][];\r
+        \r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.polyPolygon;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            // see http://secunia.com/gfx/pdf/SA31675_BA.pdf ;)\r
+            numberOfPolygons = leis.readUShort();\r
+            pointsPerPolygon = new int[numberOfPolygons];\r
+            xPoints = new int[numberOfPolygons][];\r
+            yPoints = new int[numberOfPolygons][];\r
+\r
+            int size = LittleEndianConsts.SHORT_SIZE;\r
+            \r
+            for (int i=0; i<numberOfPolygons; i++) {\r
+                pointsPerPolygon[i] = leis.readUShort();\r
+                size += LittleEndianConsts.SHORT_SIZE;\r
+            }\r
+            \r
+            for (int i=0; i<numberOfPolygons; i++) {\r
+                \r
+                xPoints[i] = new int[pointsPerPolygon[i]];\r
+                yPoints[i] = new int[pointsPerPolygon[i]];\r
+                \r
+                for (int j=0; j<pointsPerPolygon[i]; j++) {\r
+                    xPoints[i][j] = leis.readUShort();\r
+                    yPoints[i][j] = leis.readUShort();\r
+                    size += 2*LittleEndianConsts.SHORT_SIZE;\r
+                }\r
+            }\r
+            \r
+            return size;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_RECTANGLE record paints a rectangle. The rectangle is outlined by using the pen and\r
+     * filled by using the brush that are defined in the playback device context.\r
+     */\r
+    public static class WmfRectangle implements HwmfRecord {\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
+         * the lower-right corner of the rectangle.\r
+         */\r
+        int bottomRect;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
+         * the lower-right corner of the rectangle.\r
+         */\r
+        int rightRect;\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
+         * upper-left corner of the rectangle.\r
+         */\r
+        int topRect;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
+         * the upper-left corner of the rectangle.\r
+         */\r
+        int leftRect;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.frameRegion;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            bottomRect = leis.readShort();\r
+            rightRect = leis.readShort();\r
+            topRect = leis.readShort();\r
+            leftRect = leis.readShort();\r
+            return 4*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_RECTANGLE record paints a rectangle. The rectangle is outlined by using the pen and\r
+     * filled by using the brush that are defined in the playback device context.\r
+     */\r
+    public static class WmfSetPixel implements HwmfRecord {\r
+        /**\r
+         * A ColorRef Object that defines the color value.\r
+         */\r
+        HwmfColorRef colorRef; \r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the point\r
+         * to be set.\r
+         */\r
+        int y;\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the point\r
+         * to be set.\r
+         */\r
+        int x;\r
+        \r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setPixel;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            colorRef = new HwmfColorRef();\r
+            int size = colorRef.init(leis);\r
+            y = leis.readShort();\r
+            x = leis.readShort();\r
+            return 2*LittleEndianConsts.SHORT_SIZE+size;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_ROUNDRECT record paints a rectangle with rounded corners. The rectangle is outlined\r
+     * using the pen and filled using the brush, as defined in the playback device context.\r
+     */\r
+    public static class WmfRoundRect implements HwmfRecord {\r
+        /**\r
+         * A 16-bit signed integer that defines the height, in logical coordinates, of the\r
+         * ellipse used to draw the rounded corners.\r
+         */\r
+        int height;\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the width, in logical coordinates, of the\r
+         * ellipse used to draw the rounded corners.\r
+         */\r
+        int width;\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
+         * the lower-right corner of the rectangle.\r
+         */\r
+        int bottomRect;\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
+         * the lower-right corner of the rectangle.\r
+         */\r
+        int rightRect;\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
+         * upper-left corner of the rectangle.\r
+         */\r
+        int topRect;\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
+         * the upper-left corner of the rectangle.\r
+         */\r
+        int leftRect;\r
+        \r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.roundRect;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            height = leis.readShort();\r
+            width = leis.readShort();\r
+            bottomRect = leis.readShort();\r
+            rightRect = leis.readShort();\r
+            topRect = leis.readShort();\r
+            leftRect = leis.readShort();\r
+            return 6*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+    \r
+\r
+\r
+    /**\r
+     * The META_PIE record draws a pie-shaped wedge bounded by the intersection of an ellipse and two\r
+     * radials. The pie is outlined by using the pen and filled by using the brush that are defined in the\r
+     * playback device context.\r
+     */\r
+    public static class WmfPie implements HwmfRecord {\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical\r
+         * coordinates, of the endpoint of the second radial.\r
+         */\r
+        int yRadial2;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical\r
+         * coordinates, of the endpoint of the second radial.\r
+         */\r
+        int xRadial2;\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical \r
+         * coordinates, of the endpoint of the first radial.\r
+         */\r
+        int yRadial1;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical \r
+         * coordinates, of the endpoint of the first radial.\r
+         */\r
+        int xRadial1;  \r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of \r
+         * the lower-right corner of the bounding rectangle.\r
+         */\r
+        int bottomRect;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+         * the lower-right corner of the bounding rectangle.\r
+         */\r
+        int rightRect;\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the \r
+         * upper-left corner of the bounding rectangle.\r
+         */\r
+        int topRect;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+         * the upper-left corner of the bounding rectangle.\r
+         */\r
+        int leftRect;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.pie;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            yRadial2 = leis.readShort();\r
+            xRadial2 = leis.readShort();\r
+            yRadial1 = leis.readShort();\r
+            xRadial1 = leis.readShort();\r
+            bottomRect = leis.readShort();\r
+            rightRect = leis.readShort();\r
+            topRect = leis.readShort();\r
+            leftRect = leis.readShort();\r
+            return 8*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_ARC record draws an elliptical arc.\r
+     */\r
+    public static class WmfArc implements HwmfRecord {\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
+         * the ending point of the radial line defining the ending point of the arc.\r
+         */\r
+        int yEndArc; \r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+         * the ending point of the radial line defining the ending point of the arc.\r
+         */\r
+        int xEndArc; \r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of \r
+         * the ending point of the radial line defining the starting point of the arc.\r
+         */\r
+        int yStartArc;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+         * the ending point of the radial line defining the starting point of the arc.\r
+         */\r
+        int xStartArc;\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of \r
+         * the lower-right corner of the bounding rectangle.\r
+         */\r
+        int bottomRect;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+         * the lower-right corner of the bounding rectangle.\r
+         */\r
+        int rightRect;\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the \r
+         * upper-left corner of the bounding rectangle.\r
+         */\r
+        int topRect;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+         * the upper-left corner of the bounding rectangle.\r
+         */\r
+        int leftRect;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.arc;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            yEndArc = leis.readShort();\r
+            xEndArc = leis.readShort();\r
+            yStartArc = leis.readShort();\r
+            xStartArc = leis.readShort();\r
+            bottomRect = leis.readShort();\r
+            rightRect = leis.readShort();\r
+            topRect = leis.readShort();\r
+            leftRect = leis.readShort();\r
+            return 8*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_CHORD record draws a chord, which is defined by a region bounded by the intersection of\r
+     * an ellipse with a line segment. The chord is outlined using the pen and filled using the brush\r
+     * that are defined in the playback device context.\r
+     */\r
+    public static class WmfChord implements HwmfRecord {\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical \r
+         * coordinates, of the endpoint of the second radial.\r
+         */\r
+        int yRadial2;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical \r
+         * coordinates, of the endpoint of the second radial.\r
+         */\r
+        int xRadial2;\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical \r
+         * coordinates, of the endpoint of the first radial.\r
+         */\r
+        int yRadial1;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical \r
+         * coordinates, of the endpoint of the first radial.\r
+         */\r
+        int xRadial1;\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of \r
+         * the lower-right corner of the bounding rectangle.\r
+         */\r
+        int bottomRect;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+         * the lower-right corner of the bounding rectangle.\r
+         */\r
+        int rightRect;\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the \r
+         * upper-left corner of the bounding rectangle.\r
+         */\r
+        int topRect;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+         * the upper-left corner of the bounding rectangle.\r
+         */\r
+        int leftRect;\r
+        \r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.chord;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            yRadial2 = leis.readShort();\r
+            xRadial2 = leis.readShort();\r
+            yRadial1 = leis.readShort();\r
+            xRadial1 = leis.readShort();\r
+            bottomRect = leis.readShort();\r
+            rightRect = leis.readShort();\r
+            topRect = leis.readShort();\r
+            leftRect = leis.readShort();\r
+            return 8*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+\r
+    /**\r
+     * The META_SELECTOBJECT record specifies a graphics object for the playback device context. The \r
+     * new object replaces the previous object of the same type, unless if the previous object is a palette \r
+     * object. If the previous object is a palette object, then the META_SELECTPALETTE record must be \r
+     * used instead of the META_SELECTOBJECT record, as the META_SELECTOBJECT record does not \r
+     * support replacing the palette object type.\r
+     */\r
+    public static class WmfSelectObject implements HwmfRecord {\r
+        \r
+        /**\r
+         * A 16-bit unsigned integer used to index into the WMF Object Table to\r
+         * get the object to be selected.\r
+         */\r
+        int objectIndex;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.selectObject;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            objectIndex = leis.readUShort();\r
+            return LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+ }\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfEscape.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfEscape.java
new file mode 100644 (file)
index 0000000..d9cddc9
--- /dev/null
@@ -0,0 +1,53 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+import java.io.IOException;\r
+\r
+import org.apache.poi.util.LittleEndianConsts;\r
+import org.apache.poi.util.LittleEndianInputStream;\r
+\r
+public class HwmfEscape implements HwmfRecord {\r
+    \r
+    /**\r
+     * A 16-bit unsigned integer that defines the escape function. The \r
+     * value MUST be from the MetafileEscapes enumeration.\r
+     */\r
+    int escapeFunction;\r
+    /**\r
+     * A 16-bit unsigned integer that specifies the size, in bytes, of the \r
+     * EscapeData field.\r
+     */\r
+    int byteCount;\r
+    /**\r
+     * An array of bytes of size ByteCount.\r
+     */\r
+    byte escapeData[];\r
+    \r
+    public HwmfRecordType getRecordType() {\r
+        return HwmfRecordType.escape;\r
+    }\r
+    \r
+    public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+        escapeFunction = leis.readUShort();\r
+        byteCount = leis.readUShort();\r
+        escapeData = new byte[byteCount];\r
+        leis.read(escapeData);\r
+        return 2*LittleEndianConsts.SHORT_SIZE+byteCount;\r
+    }\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java
new file mode 100644 (file)
index 0000000..316d3fc
--- /dev/null
@@ -0,0 +1,794 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+import java.io.IOException;\r
+\r
+import org.apache.poi.util.LittleEndianConsts;\r
+import org.apache.poi.util.LittleEndianInputStream;\r
+\r
+public class HwmfFill {\r
+    /**\r
+     * The META_FILLREGION record fills a region using a specified brush.\r
+     */\r
+    public static class WmfFillRegion implements HwmfRecord {\r
+        \r
+        /**\r
+         * A 16-bit unsigned integer used to index into the WMF Object Table to get\r
+         * the region to be filled.\r
+         */\r
+        int region;\r
+\r
+        /**\r
+         * A 16-bit unsigned integer used to index into the WMF Object Table to get the\r
+         * brush to use for filling the region.\r
+         */\r
+        int brush;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.fillRegion;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            region = leis.readUShort();\r
+            brush = leis.readUShort();\r
+            return 2*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_PAINTREGION record paints the specified region by using the brush that is\r
+     * defined in the playback device context.\r
+     */\r
+    public static class WmfPaintRegion implements HwmfRecord {\r
+        \r
+        /**\r
+         * A 16-bit unsigned integer used to index into the WMF Object Table to get\r
+         * the region to be painted.\r
+         */\r
+        int region;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.paintRegion;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            region = leis.readUShort();\r
+            return LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+    \r
+    \r
+    /**\r
+     * The META_FLOODFILL record fills an area of the output surface with the brush that\r
+     * is defined in the playback device context.\r
+     */\r
+    public static class WmfFloodFill implements HwmfRecord {\r
+        \r
+        /**\r
+         * A 32-bit ColorRef Object that defines the color value.\r
+         */\r
+        HwmfColorRef colorRef;\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
+         * point where filling is to start.\r
+         */\r
+        int yStart;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
+         * point where filling is to start.\r
+         */\r
+        int xStart;\r
+        \r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.floodFill;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            colorRef = new HwmfColorRef();\r
+            int size = colorRef.init(leis);\r
+            yStart = leis.readShort();\r
+            xStart = leis.readShort();\r
+            return size+2*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_SETPOLYFILLMODE record sets polygon fill mode in the playback device context for\r
+     * graphics operations that fill polygons.\r
+     */\r
+    public static class WmfSetPolyfillMode implements HwmfRecord {\r
+        \r
+        /**\r
+         * A 16-bit unsigned integer that defines polygon fill mode.\r
+         * This MUST be one of the values: ALTERNATE = 0x0001, WINDING = 0x0002\r
+         */\r
+        int polyFillMode;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setPolyFillMode;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            polyFillMode = leis.readUShort();\r
+            return LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+\r
+    /**\r
+     * The META_EXTFLOODFILL record fills an area with the brush that is defined in\r
+     * the playback device context.\r
+     */\r
+    public static class WmfExtFloodFill implements HwmfRecord {\r
+        \r
+        /**\r
+         * A 16-bit unsigned integer that defines the fill operation to be performed. This\r
+         * member MUST be one of the values in the FloodFill Enumeration table:\r
+         * \r
+         * FLOODFILLBORDER = 0x0000:\r
+         * The fill area is bounded by the color specified by the Color member.\r
+         * This style is identical to the filling performed by the META_FLOODFILL record.\r
+         * \r
+         * FLOODFILLSURFACE = 0x0001:\r
+         * The fill area is bounded by the color that is specified by the Color member.\r
+         * Filling continues outward in all directions as long as the color is encountered.\r
+         * This style is useful for filling areas with multicolored boundaries.\r
+         */\r
+        int mode;\r
+        \r
+        /**\r
+         * A 32-bit ColorRef Object that defines the color value.\r
+         */\r
+        HwmfColorRef colorRef;\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the point\r
+         * to be set.\r
+         */\r
+        int y;\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the point\r
+         * to be set.\r
+         */\r
+        int x;  \r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.extFloodFill;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            mode = leis.readUShort();\r
+            colorRef = new HwmfColorRef();\r
+            int size = colorRef.init(leis);\r
+            y = leis.readShort();\r
+            x = leis.readShort();\r
+            return size+3*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_INVERTREGION record draws a region in which the colors are inverted.\r
+     */\r
+    public static class WmfInvertRegion implements HwmfRecord {\r
+        \r
+        /**\r
+         * A 16-bit unsigned integer used to index into the WMF Object Table to get\r
+         * the region to be inverted.\r
+         */\r
+        int region;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.invertRegion;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            region = leis.readUShort();\r
+            return LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+    \r
+\r
+    /**\r
+     * The META_PATBLT record paints a specified rectangle using the brush that is defined in the playback\r
+     * device context. The brush color and the surface color or colors are combined using the specified\r
+     * raster operation.\r
+     */\r
+    public static class WmfPatBlt implements HwmfRecord {\r
+        \r
+        /**\r
+         * A 32-bit unsigned integer that defines the raster operation code.\r
+         * This code MUST be one of the values in the Ternary Raster Operation enumeration table.\r
+         */\r
+        HwmfTernaryRasterOp rasterOperation;\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the height, in logical units, of the rectangle.\r
+         */\r
+        int height;\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the width, in logical units, of the rectangle.\r
+         */\r
+        int width;\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
+         * upper-left corner of the rectangle to be filled.\r
+         */\r
+        int yLeft;\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
+         * upper-left corner of the rectangle to be filled.\r
+         */\r
+        int xLeft;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.patBlt;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            int rasterOpIndex = leis.readUShort();\r
+            int rasterOpCode = leis.readUShort();\r
+\r
+            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+            assert(rasterOpCode == rasterOperation.opCode);\r
+            \r
+            height = leis.readShort();\r
+            width = leis.readShort();\r
+            yLeft = leis.readShort();\r
+            xLeft = leis.readShort();\r
+\r
+            return 6*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     */\r
+    public static class WmfStretchBlt implements HwmfRecord {\r
+        /**\r
+         * A 32-bit unsigned integer that defines how the source pixels, the current brush\r
+         * in the playback device context, and the destination pixels are to be combined to form the new \r
+         * image. This code MUST be one of the values in the Ternary Raster Operation Enumeration\r
+         */\r
+        HwmfTernaryRasterOp rasterOperation;\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the height, in logical units, of the source rectangle.\r
+         */\r
+        int srcHeight; \r
+        /**\r
+         * A 16-bit signed integer that defines the width, in logical units, of the source rectangle.\r
+         */\r
+        int srcWidth; \r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left corner \r
+         * of the source rectangle.\r
+         */\r
+        int ySrc;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left corner \r
+         * of the source rectangle.\r
+         */\r
+        int xSrc;\r
+        /**\r
+         * A 16-bit signed integer that defines the height, in logical units, of the destination rectangle.\r
+         */\r
+        int destHeight;\r
+        /**\r
+         * A 16-bit signed integer that defines the width, in logical units, of the destination rectangle.\r
+         */\r
+        int destWidth;\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left \r
+         * corner of the destination rectangle.\r
+         */\r
+        int yDest;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left \r
+         * corner of the destination rectangle.\r
+         */\r
+        int xDest;\r
+        \r
+        /**\r
+         * A variable-sized Bitmap16 Object that defines source image content.\r
+         * This object MUST be specified, even if the raster operation does not require a source.\r
+         */\r
+        HwmfBitmap16 target;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.stretchBlt;\r
+        }\r
+        \r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));\r
+\r
+            int size = 0;\r
+            int rasterOpIndex = leis.readUShort();\r
+            int rasterOpCode = leis.readUShort();\r
+            \r
+            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+            assert(rasterOpCode == rasterOperation.opCode);\r
+\r
+            srcHeight = leis.readShort();\r
+            srcWidth = leis.readShort();\r
+            ySrc = leis.readShort();\r
+            xSrc = leis.readShort();\r
+            size = 6*LittleEndianConsts.SHORT_SIZE;\r
+            if (!hasBitmap) {\r
+                @SuppressWarnings("unused")\r
+                int reserved = leis.readShort();\r
+                size += LittleEndianConsts.SHORT_SIZE;\r
+            }\r
+            destHeight = leis.readShort();\r
+            destWidth = leis.readShort();\r
+            yDest = leis.readShort();\r
+            xDest = leis.readShort();\r
+            size += 4*LittleEndianConsts.SHORT_SIZE;\r
+            if (hasBitmap) {\r
+                target = new HwmfBitmap16();\r
+                size += target.init(leis);\r
+            }\r
+            \r
+            return size;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_STRETCHDIB record specifies the transfer of color data from a\r
+     * block of pixels in deviceindependent format according to a raster operation,\r
+     * with possible expansion or contraction.\r
+     * The source of the color data is a DIB, and the destination of the transfer is\r
+     * the current output region in the playback device context.\r
+     */\r
+    public static class WmfStretchDib implements HwmfRecord {\r
+        /**\r
+         * A 32-bit unsigned integer that defines how the source pixels, the current brush in\r
+         * the playback device context, and the destination pixels are to be combined to\r
+         * form the new image.\r
+         */\r
+        HwmfTernaryRasterOp rasterOperation;\r
+\r
+        /**\r
+         * A 16-bit unsigned integer that defines whether the Colors field of the\r
+         * DIB contains explicit RGB values or indexes into a palette.\r
+         * This value MUST be in the ColorUsage Enumeration:\r
+         * DIB_RGB_COLORS = 0x0000,\r
+         * DIB_PAL_COLORS = 0x0001,\r
+         * DIB_PAL_INDICES = 0x0002\r
+         */\r
+        int colorUsage;\r
+        /**\r
+         * A 16-bit signed integer that defines the height, in logical units, of the\r
+         * source rectangle.\r
+         */\r
+        int srcHeight;\r
+        /**\r
+         * A 16-bit signed integer that defines the width, in logical units, of the\r
+         * source rectangle.\r
+         */\r
+        int srcWidth; \r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
+         * source rectangle.\r
+         */\r
+        int ySrc;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the \r
+         * source rectangle.\r
+         */\r
+        int xSrc;\r
+        /**\r
+         * A 16-bit signed integer that defines the height, in logical units, of the \r
+         * destination rectangle.\r
+         */\r
+        int destHeight;\r
+        /**\r
+         * A 16-bit signed integer that defines the width, in logical units, of the \r
+         * destination rectangle.\r
+         */\r
+        int destWidth;\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the \r
+         * upper-left corner of the destination rectangle.\r
+         */\r
+        int yDst;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the \r
+         * upper-left corner of the destination rectangle.\r
+         */\r
+        int xDst;\r
+        /**\r
+         * A variable-sized DeviceIndependentBitmap Object (section 2.2.2.9) that is the \r
+         * source of the color data.\r
+         */\r
+        HwmfBitmapDib dib;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.stretchDib;\r
+        }\r
+        \r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            int rasterOpIndex = leis.readUShort();\r
+            int rasterOpCode = leis.readUShort();\r
+            \r
+            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+            assert(rasterOpCode == rasterOperation.opCode);\r
+\r
+            colorUsage = leis.readUShort();\r
+            srcHeight = leis.readShort();\r
+            srcWidth = leis.readShort();\r
+            ySrc = leis.readShort();\r
+            xSrc = leis.readShort();\r
+            destHeight = leis.readShort();\r
+            destWidth = leis.readShort();\r
+            yDst = leis.readShort();\r
+            xDst = leis.readShort();\r
+            \r
+            int size = 11*LittleEndianConsts.SHORT_SIZE;\r
+            dib = new HwmfBitmapDib();\r
+            size += dib.init(leis);\r
+            return size;\r
+        }        \r
+    }\r
+    \r
+    public static class WmfBitBlt implements HwmfRecord {\r
+\r
+        /**\r
+         * A 32-bit unsigned integer that defines how the source pixels, the current brush in the playback \r
+         * device context, and the destination pixels are to be combined to form the new image.\r
+         */\r
+        HwmfTernaryRasterOp rasterOperation;\r
+        \r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left corner \r
+        of the source rectangle.\r
+         */\r
+        int ySrc; \r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left corner \r
+        of the source rectangle.\r
+         */\r
+        int xSrc; \r
+        /**\r
+         * A 16-bit signed integer that defines the height, in logical units, of the source and \r
+        destination rectangles.\r
+         */\r
+        int height;\r
+        /**\r
+         * A 16-bit signed integer that defines the width, in logical units, of the source and destination \r
+        rectangles.\r
+         */\r
+        int width;\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left \r
+        corner of the destination rectangle.\r
+         */\r
+        int yDest;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left \r
+        corner of the destination rectangle.\r
+         */\r
+        int xDest;\r
+        \r
+        /**\r
+         * A variable-sized Bitmap16 Object that defines source image content.\r
+         * This object MUST be specified, even if the raster operation does not require a source.\r
+         */\r
+        HwmfBitmap16 target;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.bitBlt;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));\r
+\r
+            int size = 0;\r
+            int rasterOpIndex = leis.readUShort();\r
+            int rasterOpCode = leis.readUShort();\r
+            \r
+            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+            assert(rasterOpCode == rasterOperation.opCode);\r
+\r
+            ySrc = leis.readShort();\r
+            xSrc = leis.readShort();\r
+\r
+            size = 4*LittleEndianConsts.SHORT_SIZE;\r
+            \r
+            if (!hasBitmap) {\r
+                @SuppressWarnings("unused")\r
+                int reserved = leis.readShort();\r
+                size += LittleEndianConsts.SHORT_SIZE;\r
+            }\r
+            \r
+            height = leis.readShort();\r
+            width = leis.readShort();\r
+            yDest = leis.readShort();\r
+            xDest = leis.readShort();\r
+\r
+            size += 4*LittleEndianConsts.SHORT_SIZE;\r
+            if (hasBitmap) {\r
+                target = new HwmfBitmap16();\r
+                size += target.init(leis);\r
+            }\r
+            \r
+            return size;\r
+        }\r
+    }\r
+\r
+\r
+    /**\r
+     * The META_SETDIBTODEV record sets a block of pixels in the playback device context\r
+     * using deviceindependent color data.\r
+     * The source of the color data is a DIB\r
+     */\r
+    public static class WmfSetDibToDev implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit unsigned integer that defines whether the Colors field of the\r
+         * DIB contains explicit RGB values or indexes into a palette.\r
+         * This MUST be one of the values in the ColorUsage Enumeration:\r
+         * DIB_RGB_COLORS = 0x0000,\r
+         * DIB_PAL_COLORS = 0x0001,\r
+         * DIB_PAL_INDICES = 0x0002\r
+         */\r
+        int colorUsage;  \r
+        /**\r
+         * A 16-bit unsigned integer that defines the number of scan lines in the source.\r
+         */\r
+        int scanCount;\r
+        /**\r
+         * A 16-bit unsigned integer that defines the starting scan line in the source.\r
+         */\r
+        int startScan;  \r
+        /**\r
+         * A 16-bit unsigned integer that defines the y-coordinate, in logical units, of the\r
+         * source rectangle.\r
+         */\r
+        int yDib;  \r
+        /**\r
+         * A 16-bit unsigned integer that defines the x-coordinate, in logical units, of the\r
+         * source rectangle.\r
+         */\r
+        int xDib;  \r
+        /**\r
+         * A 16-bit unsigned integer that defines the height, in logical units, of the\r
+         * source and destination rectangles.\r
+         */\r
+        int height;\r
+        /**\r
+         * A 16-bit unsigned integer that defines the width, in logical units, of the\r
+         * source and destination rectangles.\r
+         */\r
+        int width;\r
+        /**\r
+         * A 16-bit unsigned integer that defines the y-coordinate, in logical units, of the\r
+         * upper-left corner of the destination rectangle.\r
+         */\r
+        int yDest;\r
+        /**\r
+         * A 16-bit unsigned integer that defines the x-coordinate, in logical units, of the\r
+         * upper-left corner of the destination rectangle.\r
+         */\r
+        int xDest;\r
+        /**\r
+         * A variable-sized DeviceIndependentBitmap Object that is the source of the color data.\r
+         */\r
+        HwmfBitmapDib dib;        \r
+        \r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setDibToDev;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            colorUsage = leis.readUShort();\r
+            scanCount = leis.readUShort();\r
+            startScan = leis.readUShort();\r
+            yDib = leis.readUShort();\r
+            xDib = leis.readUShort();\r
+            height = leis.readUShort();\r
+            width = leis.readUShort();\r
+            yDest = leis.readUShort();\r
+            xDest = leis.readUShort();\r
+            \r
+            int size = 9*LittleEndianConsts.SHORT_SIZE;\r
+            dib = new HwmfBitmapDib();\r
+            size += dib.init(leis);\r
+            \r
+            return size;\r
+        }        \r
+    }\r
+\r
+\r
+    public static class WmfDibBitBlt implements HwmfRecord {\r
+\r
+        /**\r
+         * A 32-bit unsigned integer that defines how the source pixels, the current brush\r
+         * in the playback device context, and the destination pixels are to be combined to form the\r
+         * new image. This code MUST be one of the values in the Ternary Raster Operation Enumeration.\r
+         */\r
+        HwmfTernaryRasterOp rasterOperation;  \r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the source rectangle.\r
+         */\r
+        int ySrc;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the source rectangle.\r
+         */\r
+        int xSrc;\r
+        /**\r
+         * A 16-bit signed integer that defines the height, in logical units, of the source and \r
+         * destination rectangles.\r
+         */\r
+        int height;\r
+        /**\r
+         * A 16-bit signed integer that defines the width, in logical units, of the source and destination\r
+         * rectangles.\r
+         */\r
+        int width;\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left\r
+         * corner of the destination rectangle.\r
+         */\r
+        int yDest;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left \r
+         * corner of the destination rectangle.\r
+         */\r
+        int xDest;\r
+        \r
+        /**\r
+         * A variable-sized DeviceIndependentBitmap Object that defines image content.\r
+         * This object MUST be specified, even if the raster operation does not require a source.\r
+         */\r
+        HwmfBitmapDib target;\r
+        \r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.dibBitBlt;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));\r
+\r
+            int size = 0;\r
+            int rasterOpIndex = leis.readUShort();\r
+            int rasterOpCode = leis.readUShort();\r
+            \r
+            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+            assert(rasterOpCode == rasterOperation.opCode);\r
+\r
+            ySrc = leis.readShort();\r
+            xSrc = leis.readShort();\r
+            size = 4*LittleEndianConsts.SHORT_SIZE;\r
+            if (!hasBitmap) {\r
+                @SuppressWarnings("unused")\r
+                int reserved = leis.readShort();\r
+                size += LittleEndianConsts.SHORT_SIZE;\r
+            }\r
+            height = leis.readShort();\r
+            width = leis.readShort();\r
+            yDest = leis.readShort();\r
+            xDest = leis.readShort();\r
+            \r
+            size += 4*LittleEndianConsts.SHORT_SIZE;\r
+            if (hasBitmap) {\r
+                target = new HwmfBitmapDib();\r
+                size += target.init(leis);\r
+            }\r
+            \r
+            return size;\r
+        }\r
+    }\r
+\r
+    public static class WmfDibStretchBlt implements HwmfRecord {\r
+        /**\r
+         * A 32-bit unsigned integer that defines how the source pixels, the current brush\r
+         * in the playback device context, and the destination pixels are to be combined to form the\r
+         * new image. This code MUST be one of the values in the Ternary Raster Operation Enumeration.\r
+         */\r
+        HwmfTernaryRasterOp rasterOperation;\r
+        /**\r
+         * A 16-bit signed integer that defines the height, in logical units, of the source rectangle.\r
+         */\r
+        int srcHeight;\r
+        /**\r
+         * A 16-bit signed integer that defines the width, in logical units, of the source rectangle.\r
+         */\r
+        int srcWidth;\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
+         * upper-left corner of the source rectangle.\r
+         */\r
+        int ySrc;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
+         * upper-left corner of the source rectangle.\r
+         */\r
+        int xSrc;\r
+        /**\r
+         * A 16-bit signed integer that defines the height, in logical units, of the\r
+         * destination rectangle.\r
+         */\r
+        int destHeight;\r
+        /**\r
+         * A 16-bit signed integer that defines the width, in logical units, of the\r
+         * destination rectangle.\r
+         */\r
+        int destWidth;\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units,\r
+         * of the upper-left corner of the destination rectangle.\r
+         */\r
+        int yDest;\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units,\r
+         * of the upper-left corner of the destination rectangle.\r
+         */\r
+        int xDest;\r
+        /**\r
+         * A variable-sized DeviceIndependentBitmap Object that defines image content.\r
+         * This object MUST be specified, even if the raster operation does not require a source.\r
+         */\r
+        HwmfBitmapDib target;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.dibStretchBlt;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));\r
+\r
+            int size = 0;\r
+            int rasterOpIndex = leis.readUShort();\r
+            int rasterOpCode = leis.readUShort();\r
+            \r
+            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+            assert(rasterOpCode == rasterOperation.opCode);\r
+\r
+            srcHeight = leis.readShort();\r
+            srcWidth = leis.readShort();\r
+            ySrc = leis.readShort();\r
+            xSrc = leis.readShort();\r
+            size = 6*LittleEndianConsts.SHORT_SIZE;\r
+            if (!hasBitmap) {\r
+                @SuppressWarnings("unused")\r
+                int reserved = leis.readShort();\r
+                size += LittleEndianConsts.SHORT_SIZE;\r
+            }\r
+            destHeight = leis.readShort();\r
+            destWidth = leis.readShort();\r
+            yDest = leis.readShort();\r
+            xDest = leis.readShort();\r
+            size += 4*LittleEndianConsts.SHORT_SIZE;\r
+            if (hasBitmap) {\r
+                target = new HwmfBitmapDib();\r
+                size += target.init(leis);\r
+            }\r
+            \r
+            return size;\r
+        }\r
+    }\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java
new file mode 100644 (file)
index 0000000..af6703e
--- /dev/null
@@ -0,0 +1,498 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+import java.io.IOException;\r
+import java.nio.charset.Charset;\r
+\r
+import org.apache.poi.util.LittleEndianInputStream;\r
+\r
+/**\r
+ * The Font object specifies the attributes of a logical font\r
+ */\r
+public class HwmfFont {\r
+    public enum WmfCharset {\r
+        /** Specifies the English character set. */\r
+        ANSI_CHARSET(0x00000000),\r
+        /**\r
+         * Specifies a character set based on the current system locale;\r
+         * for example, when the system locale is United States English,\r
+         * the default character set is ANSI_CHARSET.\r
+         */\r
+        DEFAULT_CHARSET(0x00000001),\r
+        /** Specifies a character set of symbols. */\r
+        SYMBOL_CHARSET(0x00000002),\r
+        /** Specifies the Apple Macintosh character set. */\r
+        MAC_CHARSET(0x0000004D),\r
+        /** Specifies the Japanese character set. */\r
+        SHIFTJIS_CHARSET(0x00000080),\r
+        /** Also spelled "Hangeul". Specifies the Hangul Korean character set. */\r
+        HANGUL_CHARSET(0x00000081),\r
+        /** Also spelled "Johap". Specifies the Johab Korean character set. */\r
+        JOHAB_CHARSET(0x00000082),\r
+        /** Specifies the "simplified" Chinese character set for People's Republic of China. */\r
+        GB2312_CHARSET(0x00000086),\r
+        /**\r
+         * Specifies the "traditional" Chinese character set, used mostly in\r
+         * Taiwan and in the Hong Kong and Macao Special Administrative Regions.\r
+         */\r
+        CHINESEBIG5_CHARSET(0x00000088),\r
+        /** Specifies the Greek character set. */\r
+        GREEK_CHARSET(0x000000A1),\r
+        /** Specifies the Turkish character set. */\r
+        TURKISH_CHARSET(0x000000A2),\r
+        /** Specifies the Vietnamese character set. */\r
+        VIETNAMESE_CHARSET(0x000000A3),\r
+        /** Specifies the Hebrew character set. */\r
+        HEBREW_CHARSET(0x000000B1),\r
+        /** Specifies the Arabic character set. */\r
+        ARABIC_CHARSET(0x000000B2),\r
+        /** Specifies the Baltic (Northeastern European) character set. */\r
+        BALTIC_CHARSET(0x000000BA),\r
+        /** Specifies the Russian Cyrillic character set. */\r
+        RUSSIAN_CHARSET(0x000000CC),\r
+        /** Specifies the Thai character set. */\r
+        THAI_CHARSET(0x000000DE),\r
+        /** Specifies a Eastern European character set. */\r
+        EASTEUROPE_CHARSET(0x000000EE),\r
+        /**\r
+         * Specifies a mapping to one of the OEM code pages,\r
+         * according to the current system locale setting.\r
+         */\r
+        OEM_CHARSET(0x000000FF);\r
+\r
+        int flag;\r
+        WmfCharset(int flag) {\r
+            this.flag = flag;\r
+        }\r
+\r
+        static WmfCharset valueOf(int flag) {\r
+            for (WmfCharset cs : values()) {\r
+                if (cs.flag == flag) return cs;\r
+            }\r
+            return null;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The output precision defines how closely the output must match the requested font's height,\r
+     * width, character orientation, escapement, pitch, and font type.\r
+     */\r
+    public enum WmfOutPrecision {\r
+        /**\r
+         * A value that specifies default behavior.\r
+         */\r
+        OUT_DEFAULT_PRECIS(0x00000000),\r
+        /**\r
+         * A value that is returned when rasterized fonts are enumerated.\r
+         */\r
+        OUT_STRING_PRECIS(0x00000001),\r
+        /**\r
+         * A value that is returned when TrueType and other outline fonts, and\r
+         * vector fonts are enumerated.\r
+         */\r
+        OUT_STROKE_PRECIS(0x00000003),\r
+        /**\r
+         * A value that specifies the choice of a TrueType font when the system\r
+         * contains multiple fonts with the same name.\r
+         */\r
+        OUT_TT_PRECIS(0x00000004),\r
+        /**\r
+         * A value that specifies the choice of a device font when the system\r
+         * contains multiple fonts with the same name.\r
+         */\r
+        OUT_DEVICE_PRECIS(0x00000005),\r
+        /**\r
+         * A value that specifies the choice of a rasterized font when the system\r
+         * contains multiple fonts with the same name.\r
+         */\r
+        OUT_RASTER_PRECIS(0x00000006),\r
+        /**\r
+         * A value that specifies the requirement for only TrueType fonts. If\r
+         * there are no TrueType fonts installed in the system, default behavior is specified.\r
+         */\r
+        OUT_TT_ONLY_PRECIS(0x00000007),\r
+        /**\r
+         * A value that specifies the requirement for TrueType and other outline fonts.\r
+         */\r
+        OUT_OUTLINE_PRECIS (0x00000008),\r
+        /**\r
+         * A value that specifies a preference for TrueType and other outline fonts.\r
+         */\r
+        OUT_SCREEN_OUTLINE_PRECIS (0x00000009),\r
+        /**\r
+         * A value that specifies a requirement for only PostScript fonts. If there\r
+         * are no PostScript fonts installed in the system, default behavior is specified.\r
+         */\r
+        OUT_PS_ONLY_PRECIS (0x0000000A);\r
+\r
+\r
+        int flag;\r
+        WmfOutPrecision(int flag) {\r
+            this.flag = flag;\r
+        }\r
+\r
+        static WmfOutPrecision valueOf(int flag) {\r
+            for (WmfOutPrecision op : values()) {\r
+                if (op.flag == flag) return op;\r
+            }\r
+            return null;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * ClipPrecision Flags specify clipping precision, which defines how to clip characters that are\r
+     * partially outside a clipping region. These flags can be combined to specify multiple options.\r
+     */\r
+    public enum WmfClipPrecision {\r
+\r
+        /**\r
+         * Specifies that default clipping MUST be used.\r
+         */\r
+        CLIP_DEFAULT_PRECIS (0x00000000),\r
+\r
+        /**\r
+         * This value SHOULD NOT be used.\r
+         */\r
+        CLIP_CHARACTER_PRECIS (0x00000001),\r
+\r
+        /**\r
+         * This value MAY be returned when enumerating rasterized, TrueType and vector fonts.\r
+         */\r
+        CLIP_STROKE_PRECIS (0x00000002),\r
+\r
+        /**\r
+         * This value is used to control font rotation, as follows:\r
+         * If set, the rotation for all fonts SHOULD be determined by the orientation of the coordinate system;\r
+         * that is, whether the orientation is left-handed or right-handed.\r
+         *\r
+         * If clear, device fonts SHOULD rotate counterclockwise, but the rotation of other fonts\r
+         * SHOULD be determined by the orientation of the coordinate system.\r
+         */\r
+        CLIP_LH_ANGLES (0x00000010),\r
+\r
+        /**\r
+         * This value SHOULD NOT be used.\r
+         */\r
+        CLIP_TT_ALWAYS (0x00000020),\r
+\r
+        /**\r
+         * This value specifies that font association SHOULD< be turned off.\r
+         */\r
+        CLIP_DFA_DISABLE (0x00000040),\r
+\r
+        /**\r
+         * This value specifies that font embedding MUST be used to render document content;\r
+         * embedded fonts are read-only.\r
+         */\r
+        CLIP_EMBEDDED (0x00000080);\r
+\r
+\r
+        int flag;\r
+        WmfClipPrecision(int flag) {\r
+            this.flag = flag;\r
+        }\r
+\r
+        static WmfClipPrecision valueOf(int flag) {\r
+            for (WmfClipPrecision cp : values()) {\r
+                if (cp.flag == flag) return cp;\r
+            }\r
+            return null;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The output quality defines how carefully to attempt to match the logical font attributes to those of an actual\r
+     * physical font.\r
+     */\r
+    public enum WmfFontQuality {\r
+        /**\r
+         * Specifies that the character quality of the font does not matter, so DRAFT_QUALITY can be used.\r
+         */\r
+        DEFAULT_QUALITY (0x00),\r
+        \r
+        /**\r
+         * Specifies that the character quality of the font is less important than the\r
+         * matching of logical attribuetes. For rasterized fonts, scaling SHOULD be enabled, which\r
+         * means that more font sizes are available.\r
+         */\r
+        DRAFT_QUALITY (0x01),\r
+        \r
+        /**\r
+         * Specifies that the character quality of the font is more important than the\r
+         * matching of logical attributes. For rasterized fonts, scaling SHOULD be disabled, and the font\r
+         * closest in size SHOULD be chosen.\r
+         */\r
+        PROOF_QUALITY (0x02),\r
+        \r
+        /**\r
+         * Specifies that anti-aliasing SHOULD NOT be used when rendering text.\r
+         */\r
+        NONANTIALIASED_QUALITY (0x03),\r
+        \r
+        /**\r
+         * Specifies that anti-aliasing SHOULD be used when rendering text, if the font supports it.\r
+         */\r
+        ANTIALIASED_QUALITY (0x04),\r
+        \r
+        /**\r
+         * Specifies that ClearType anti-aliasing SHOULD be used when rendering text, if the font supports it.\r
+         * \r
+         * Fonts that do not support ClearType anti-aliasing include type 1 fonts, PostScript fonts,\r
+         * OpenType fonts without TrueType outlines, rasterized fonts, vector fonts, and device fonts.\r
+         */\r
+        CLEARTYPE_QUALITY (0x05);\r
+        \r
+        int flag;\r
+        WmfFontQuality(int flag) {\r
+            this.flag = flag;\r
+        }\r
+\r
+        static WmfFontQuality valueOf(int flag) {\r
+            for (WmfFontQuality fq : values()) {\r
+                if (fq.flag == flag) return fq;\r
+            }\r
+            return null;\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * A property of a font that describes its general appearance.\r
+     */\r
+    public enum WmfFontFamilyClass {\r
+        /**\r
+         * The default font is specified, which is implementation-dependent.\r
+         */\r
+        FF_DONTCARE (0x00),\r
+        /**\r
+         * Fonts with variable stroke widths, which are proportional to the actual widths of\r
+         * the glyphs, and which have serifs. "MS Serif" is an example.\r
+         */\r
+        FF_ROMAN (0x01),\r
+        /**\r
+         * Fonts with variable stroke widths, which are proportional to the actual widths of the\r
+         * glyphs, and which do not have serifs. "MS Sans Serif" is an example.\r
+         */\r
+        FF_SWISS (0x02),\r
+        /**\r
+         * Fonts with constant stroke width, with or without serifs. Fixed-width fonts are\r
+         * usually modern. "Pica", "Elite", and "Courier New" are examples.\r
+         */\r
+        FF_MODERN (0x03),\r
+        /**\r
+         * Fonts designed to look like handwriting. "Script" and "Cursive" are examples.\r
+         */\r
+        FF_SCRIPT (0x04),\r
+        /**\r
+         * Novelty fonts. "Old English" is an example.\r
+         */\r
+        FF_DECORATIVE (0x05);\r
+        \r
+        int flag;\r
+        WmfFontFamilyClass(int flag) {\r
+            this.flag = flag;\r
+        }\r
+\r
+        static WmfFontFamilyClass valueOf(int flag) {\r
+            for (WmfFontFamilyClass ff : values()) {\r
+                if (ff.flag == flag) return ff;\r
+            }\r
+            return null;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * A property of a font that describes the pitch, of the characters.\r
+     */\r
+    public enum WmfFontPitch {\r
+        /**\r
+         * The default pitch, which is implementation-dependent.\r
+         */\r
+        DEFAULT_PITCH (0x00),\r
+        /**\r
+         * A fixed pitch, which means that all the characters in the font occupy the same\r
+         * width when output in a string.\r
+         */\r
+        FIXED_PITCH (0x01),\r
+        /**\r
+         * A variable pitch, which means that the characters in the font occupy widths\r
+         * that are proportional to the actual widths of the glyphs when output in a string. For example,\r
+         * the "i" and space characters usually have much smaller widths than a "W" or "O" character.\r
+         */\r
+        VARIABLE_PITCH (0x02);\r
+        \r
+        int flag;\r
+        WmfFontPitch(int flag) {\r
+            this.flag = flag;\r
+        }\r
+\r
+        static WmfFontPitch valueOf(int flag) {\r
+            for (WmfFontPitch fp : values()) {\r
+                if (fp.flag == flag) return fp;\r
+            }\r
+            return null;\r
+        }        \r
+    }\r
+    \r
+    /**\r
+     * A 16-bit signed integer that specifies the height, in logical units, of the font's\r
+     * character cell. The character height is computed as the character cell height minus the\r
+     * internal leading. The font mapper SHOULD interpret the height as follows.\r
+     *\r
+     * negative value:\r
+     * The font mapper SHOULD transform this value into device units and match its\r
+     * absolute value against the character height of available fonts.\r
+     *\r
+     * zero value:\r
+     * A default height value MUST be used when creating a physical font.\r
+     *\r
+     * positive value:\r
+     * The font mapper SHOULD transform this value into device units and match it\r
+     * against the cell height of available fonts.\r
+     *\r
+     * For all height comparisons, the font mapper SHOULD find the largest physical\r
+     * font that does not exceed the requested size.\r
+     */\r
+    int height;\r
+\r
+    /**\r
+     * A 16-bit signed integer that defines the average width, in logical units, of\r
+     * characters in the font. If Width is 0x0000, the aspect ratio of the device SHOULD be matched\r
+     * against the digitization aspect ratio of the available fonts to find the closest match,\r
+     * determined by the absolute value of the difference.\r
+     */\r
+    int width;\r
+\r
+    /**\r
+     * A 16-bit signed integer that defines the angle, in tenths of degrees, between the\r
+     * escapement vector and the x-axis of the device. The escapement vector is parallel\r
+     * to the base line of a row of text.\r
+     */\r
+    int escapement;\r
+\r
+    /**\r
+     * A 16-bit signed integer that defines the angle, in tenths of degrees,\r
+     * between each character's base line and the x-axis of the device.\r
+     */\r
+    int orientation;\r
+\r
+    /**\r
+     * A 16-bit signed integer that defines the weight of the font in the range 0\r
+     * through 1000. For example, 400 is normal and 700 is bold. If this value is 0x0000,\r
+     * a default weight SHOULD be used.\r
+     */\r
+    int weight;\r
+\r
+    /**\r
+     * A 8-bit Boolean value that specifies the italic attribute of the font.\r
+     * 0 = not italic / 1 = italic.\r
+     */\r
+    boolean italic;\r
+\r
+    /**\r
+     * An 8-bit Boolean value that specifies the underline attribute of the font.\r
+     * 0 = not underlined / 1 = underlined\r
+     */\r
+    boolean underline;\r
+\r
+    /**\r
+     * An 8-bit Boolean value that specifies the strike out attribute of the font.\r
+     * 0 = not striked out / 1 = striked out\r
+     */\r
+    boolean strikeOut;\r
+\r
+    /**\r
+     * An 8-bit unsigned integer that defines the character set.\r
+     * It SHOULD be set to a value in the {@link WmfCharset} Enumeration.\r
+     *\r
+     * The DEFAULT_CHARSET value MAY be used to allow the name and size of a font to fully\r
+     * describe the logical font. If the specified font name does not exist, a font in another character\r
+     * set MAY be substituted. The DEFAULT_CHARSET value is set to a value based on the current\r
+     * system locale. For example, when the system locale is United States, it is set to ANSI_CHARSET.\r
+     * If a typeface name in the FaceName field is specified, the CharSet value MUST match the\r
+     * character set of that typeface.\r
+     */\r
+    WmfCharset charSet;\r
+\r
+    /**\r
+     * An 8-bit unsigned integer that defines the output precision.\r
+     */\r
+    WmfOutPrecision outPrecision;\r
+\r
+    /**\r
+     * An 8-bit unsigned integer that defines the clipping precision.\r
+     * These flags can be combined to specify multiple options.\r
+     *\r
+     * @see WmfClipPrecision\r
+     */\r
+    int clipPrecision;\r
+\r
+    /**\r
+     * An 8-bit unsigned integer that defines the output quality.\r
+     */\r
+    WmfFontQuality quality;\r
+\r
+    /**\r
+     * Font families specify the look of fonts in a general way and are\r
+     * intended for specifying fonts when the exact typeface wanted is not available.\r
+     * (LSB 4 bits)\r
+     */\r
+    WmfFontFamilyClass family;\r
+    \r
+    /**\r
+     * A property of a font that describes the pitch (MSB 2 bits)\r
+     */\r
+    WmfFontPitch pitch;\r
+\r
+    /**\r
+     * A null-terminated string of 8-bit Latin-1 [ISO/IEC-8859-1] ANSI\r
+     * characters that specifies the typeface name of the font. The length of this string MUST NOT\r
+     * exceed 32 8-bit characters, including the terminating null.\r
+     */\r
+    String facename;\r
+\r
+    public int init(LittleEndianInputStream leis) throws IOException {\r
+        height = leis.readShort();\r
+        width = leis.readShort();\r
+        escapement = leis.readShort();\r
+        orientation = leis.readShort();\r
+        weight = leis.readShort();\r
+        italic = leis.readByte() != 0;\r
+        underline = leis.readByte() != 0;\r
+        strikeOut = leis.readByte() != 0;\r
+        charSet = WmfCharset.valueOf(leis.readUByte());\r
+        outPrecision = WmfOutPrecision.valueOf(leis.readUByte());\r
+        quality = WmfFontQuality.valueOf(leis.readUByte());\r
+        int pitchAndFamily = leis.readUByte();\r
+        family = WmfFontFamilyClass.valueOf(pitchAndFamily & 0xF);\r
+        pitch = WmfFontPitch.valueOf((pitchAndFamily >>> 6) & 3);\r
+        \r
+        byte buf[] = new byte[32], readBytes;\r
+        for (readBytes = 0; readBytes < 32; readBytes++) {\r
+            if ((buf[readBytes] = leis.readByte()) == 0) {\r
+                break;\r
+            }\r
+        }\r
+        if (readBytes == 1 || readBytes == 32) {\r
+            throw new IOException("Font facename can't be determined.");\r
+        }\r
+        facename = new String(buf, 0, readBytes-1, Charset.forName("ISO-8859-1"));\r
+        \r
+        return 17+readBytes;\r
+    }\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHatchStyle.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHatchStyle.java
new file mode 100644 (file)
index 0000000..18922bf
--- /dev/null
@@ -0,0 +1,48 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+/**\r
+ * The HatchStyle Enumeration specifies the hatch pattern.\r
+ */\r
+public enum HwmfHatchStyle {\r
+    /** A horizontal hatch */\r
+    HS_HORIZONTAL(0x0000),\r
+    /** A vertical hatch */\r
+    HS_VERTICAL(0x0001),\r
+    /** A 45-degree downward, left-to-right hatch. */\r
+    HS_FDIAGONAL(0x0002),\r
+    /** A 45-degree upward, left-to-right hatch. */\r
+    HS_BDIAGONAL(0x0003),\r
+    /** A horizontal and vertical cross-hatch. */\r
+    HS_CROSS(0x0004),\r
+    /** A 45-degree crosshatch. */\r
+    HS_DIAGCROSS(0x0005);\r
+\r
+    int flag;\r
+    HwmfHatchStyle(int flag) {\r
+        this.flag = flag;\r
+    }\r
+\r
+    static HwmfHatchStyle valueOf(int flag) {\r
+        for (HwmfHatchStyle hs : values()) {\r
+            if (hs.flag == flag) return hs;\r
+        }\r
+        return null;\r
+    }\r
+}
\ No newline at end of file
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHeader.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHeader.java
new file mode 100644 (file)
index 0000000..a36cfd4
--- /dev/null
@@ -0,0 +1,76 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+import java.io.IOException;\r
+\r
+import org.apache.poi.util.LittleEndianConsts;\r
+import org.apache.poi.util.LittleEndianInputStream;\r
+\r
+public class HwmfHeader {\r
+    private int type;\r
+    private int recordSize;\r
+    private int version;\r
+    private int filesize;\r
+    private int numberOfObjects;\r
+    private long maxRecord;\r
+    private int numberOfMembers;\r
+    \r
+    public HwmfHeader(LittleEndianInputStream leis) throws IOException {\r
+        // Type (2 bytes):  A 16-bit unsigned integer that defines the type of metafile\r
+        // MEMORYMETAFILE = 0x0001, DISKMETAFILE = 0x0002 \r
+        type = leis.readUShort();\r
+\r
+        // HeaderSize (2 bytes):  A 16-bit unsigned integer that defines the number\r
+        // of 16-bit words in the header.\r
+        recordSize = leis.readUShort();\r
+        int bytesLeft = recordSize*LittleEndianConsts.SHORT_SIZE-4;\r
+        \r
+        // Version (2 bytes):  A 16-bit unsigned integer that defines the metafile version.\r
+        // METAVERSION100 = 0x0100, METAVERSION300 = 0x0300\r
+        version = leis.readUShort();\r
+        bytesLeft -= LittleEndianConsts.SHORT_SIZE;\r
+        \r
+        // SizeLow (2 bytes):  A 16-bit unsigned integer that defines the low-order word\r
+        // of the number of 16-bit words in the entire metafile.\r
+        // SizeHigh (2 bytes):  A 16-bit unsigned integer that defines the high-order word\r
+        // of the number of 16-bit words in the entire metafile.\r
+        filesize = leis.readInt();\r
+        bytesLeft -= LittleEndianConsts.INT_SIZE;\r
+        \r
+        // NumberOfObjects (2 bytes):  A 16-bit unsigned integer that specifies the number\r
+        // of graphics objects that are defined in the entire metafile. These objects include\r
+        // brushes, pens, and the other objects\r
+        numberOfObjects = leis.readUShort();\r
+        bytesLeft -= LittleEndianConsts.SHORT_SIZE;\r
+        \r
+        // MaxRecord (4 bytes):  A 32-bit unsigned integer that specifies the size of the\r
+        // largest record used in the metafile (in 16-bit elements).\r
+        maxRecord = leis.readUInt();\r
+        bytesLeft -= LittleEndianConsts.INT_SIZE;\r
+        \r
+        // NumberOfMembers (2 bytes):  A 16-bit unsigned integer that is not used.\r
+        // It SHOULD be 0x0000.\r
+        numberOfMembers = leis.readUShort();\r
+        bytesLeft -= LittleEndianConsts.SHORT_SIZE;\r
+        \r
+        if (bytesLeft > 0) {\r
+            leis.skip(bytesLeft);\r
+        }\r
+    }\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java
new file mode 100644 (file)
index 0000000..ef539fb
--- /dev/null
@@ -0,0 +1,506 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+import java.io.IOException;\r
+\r
+import org.apache.poi.util.LittleEndianConsts;\r
+import org.apache.poi.util.LittleEndianInputStream;\r
+\r
+public class HwmfMisc {\r
+\r
+    /**\r
+     * The META_SAVEDC record saves the playback device context for later retrieval.\r
+     */\r
+    public static class WmfSaveDc implements HwmfRecord {\r
+        public HwmfRecordType getRecordType() { return HwmfRecordType.saveDc; }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            return 0;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_SETRELABS record is reserved and not supported.\r
+     */\r
+    public static class WmfSetRelabs implements HwmfRecord {\r
+        public HwmfRecordType getRecordType() { return HwmfRecordType.setRelabs; }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            return 0;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_RESTOREDC record restores the playback device context from a previously saved device\r
+     * context.\r
+     */\r
+    public static class WmfRestoreDc implements HwmfRecord {\r
+\r
+        /**\r
+         * nSavedDC (2 bytes):  A 16-bit signed integer that defines the saved state to be restored. If this\r
+         * member is positive, nSavedDC represents a specific instance of the state to be restored. If\r
+         * this member is negative, nSavedDC represents an instance relative to the current state.\r
+         */\r
+        int nSavedDC;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.restoreDc;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            nSavedDC = leis.readShort();\r
+            return LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_SETBKCOLOR record sets the background color in the playback device context to a\r
+     * specified color, or to the nearest physical color if the device cannot represent the specified color.\r
+     */\r
+    public static class WmfSetBkColor implements HwmfRecord {\r
+\r
+        HwmfColorRef colorRef;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setBkColor;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            colorRef = new HwmfColorRef();\r
+            return colorRef.init(leis);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_SETBKMODE record defines the background raster operation mix mode in the playback\r
+     * device context. The background mix mode is the mode for combining pens, text, hatched brushes,\r
+     * and interiors of filled objects with background colors on the output surface.\r
+     */\r
+    public static class WmfSetBkMode implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit unsigned integer that defines background mix mode.\r
+         * This MUST be either TRANSPARENT = 0x0001 or OPAQUE = 0x0002\r
+         */\r
+        int bkMode;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setBkMode;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            bkMode = leis.readUShort();\r
+            return LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_SETLAYOUT record defines the layout orientation in the playback device context.\r
+     * The layout orientation determines the direction in which text and graphics are drawn\r
+     */\r
+    public static class WmfSetLayout implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit unsigned integer that defines the layout of text and graphics.\r
+         * LAYOUT_LTR = 0x0000\r
+         * LAYOUT_RTL = 0x0001\r
+         * LAYOUT_BITMAPORIENTATIONPRESERVED = 0x0008\r
+         */\r
+        int layout;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setLayout;\r
+        }\r
+\r
+        @SuppressWarnings("unused")\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            layout = leis.readUShort();\r
+            // A 16-bit field that MUST be ignored.\r
+            int reserved = leis.readShort();\r
+            return 2*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_SETMAPMODE record defines the mapping mode in the playback device context.\r
+     * The mapping mode defines the unit of measure used to transform page-space units into\r
+     * device-space units, and also defines the orientation of the device's x and y axes.\r
+     */\r
+    public static class WmfSetMapMode implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit unsigned integer that defines the mapping mode.\r
+         *\r
+         * The MapMode defines how logical units are mapped to physical units;\r
+         * that is, assuming that the origins in both the logical and physical coordinate systems\r
+         * are at the same point on the drawing surface, what is the physical coordinate (x',y')\r
+         * that corresponds to logical coordinate (x,y).\r
+         *\r
+         * For example, suppose the mapping mode is MM_TEXT. Given the following definition of that\r
+         * mapping mode, and an origin (0,0) at the top left corner of the drawing surface, logical\r
+         * coordinate (4,5) would map to physical coordinate (4,5) in pixels.\r
+         *\r
+         * Now suppose the mapping mode is MM_LOENGLISH, with the same origin as the previous\r
+         * example. Given the following definition of that mapping mode, logical coordinate (4,-5)\r
+         * would map to physical coordinate (0.04,0.05) in inches.\r
+         *\r
+         * This MUST be one of the following:\r
+         *\r
+         * MM_TEXT (= 0x0001):\r
+         *  Each logical unit is mapped to one device pixel.\r
+         *  Positive x is to the right; positive y is down.\r
+         *\r
+         * MM_LOMETRIC (= 0x0002):\r
+         *  Each logical unit is mapped to 0.1 millimeter.\r
+         *  Positive x is to the right; positive y is up.\r
+         *\r
+         * MM_HIMETRIC (= 0x0003):\r
+         *  Each logical unit is mapped to 0.01 millimeter.\r
+         *  Positive x is to the right; positive y is up.\r
+         *\r
+         * MM_LOENGLISH (= 0x0004):\r
+         *  Each logical unit is mapped to 0.01 inch.\r
+         *  Positive x is to the right; positive y is up.\r
+         *\r
+         * MM_HIENGLISH (= 0x0005):\r
+         *  Each logical unit is mapped to 0.001 inch.\r
+         *  Positive x is to the right; positive y is up.\r
+         *\r
+         * MM_TWIPS (= 0x0006):\r
+         *  Each logical unit is mapped to one twentieth (1/20) of a point.\r
+         *  In printing, a point is 1/72 of an inch; therefore, 1/20 of a point is 1/1440 of an inch.\r
+         *  This unit is also known as a "twip".\r
+         *  Positive x is to the right; positive y is up.\r
+         *\r
+         * MM_ISOTROPIC (= 0x0007):\r
+         *  Logical units are mapped to arbitrary device units with equally scaled axes;\r
+         *  that is, one unit along the x-axis is equal to one unit along the y-axis.\r
+         *  The META_SETWINDOWEXT and META_SETVIEWPORTEXT records specify the units and the\r
+         *  orientation of the axes.\r
+         *  The processing application SHOULD make adjustments as necessary to ensure the x and y\r
+         *  units remain the same size. For example, when the window extent is set, the viewport\r
+         *  SHOULD be adjusted to keep the units isotropic.\r
+         *\r
+         * MM_ANISOTROPIC (= 0x0008):\r
+         *  Logical units are mapped to arbitrary units with arbitrarily scaled axes.\r
+         */\r
+        int mapMode;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setMapMode;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            mapMode = leis.readUShort();\r
+            return LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_SETMAPPERFLAGS record defines the algorithm that the font mapper uses when it maps\r
+     * logical fonts to physical fonts.\r
+     */\r
+    public static class WmfSetMapperFlags implements HwmfRecord {\r
+\r
+        /**\r
+         * A 32-bit unsigned integer that defines whether the font mapper should attempt to\r
+         * match a font's aspect ratio to the current device's aspect ratio. If bit 0 is\r
+         * set, the mapper selects only matching fonts.\r
+         */\r
+        long mapperValues;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setMapperFlags;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            mapperValues = leis.readUInt();\r
+            return LittleEndianConsts.INT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_SETROP2 record defines the foreground raster operation mix mode in the playback device\r
+     * context. The foreground mix mode is the mode for combining pens and interiors of filled objects with\r
+     * foreground colors on the output surface.\r
+     */\r
+    public static class WmfSetRop2 implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit unsigned integer that defines the foreground binary raster\r
+         * operation mixing mode. This MUST be one of the values:\r
+         * R2_BLACK = 0x0001,\r
+         * R2_NOTMERGEPEN = 0x0002,\r
+         * R2_MASKNOTPEN = 0x0003,\r
+         * R2_NOTCOPYPEN = 0x0004,\r
+         * R2_MASKPENNOT = 0x0005,\r
+         * R2_NOT = 0x0006,\r
+         * R2_XORPEN = 0x0007,\r
+         * R2_NOTMASKPEN = 0x0008,\r
+         * R2_MASKPEN = 0x0009,\r
+         * R2_NOTXORPEN = 0x000A,\r
+         * R2_NOP = 0x000B,\r
+         * R2_MERGENOTPEN = 0x000C,\r
+         * R2_COPYPEN = 0x000D,\r
+         * R2_MERGEPENNOT = 0x000E,\r
+         * R2_MERGEPEN = 0x000F,\r
+         * R2_WHITE = 0x0010\r
+         */\r
+        int drawMode;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setRop2;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            drawMode = leis.readUShort();\r
+            return LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_SETSTRETCHBLTMODE record defines the bitmap stretching mode in the playback device\r
+     * context.\r
+     */\r
+    public static class WmfSetStretchBltMode implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit unsigned integer that defines bitmap stretching mode.\r
+         * This MUST be one of the values:\r
+         * BLACKONWHITE = 0x0001,\r
+         * WHITEONBLACK = 0x0002,\r
+         * COLORONCOLOR = 0x0003,\r
+         * HALFTONE = 0x0004\r
+         */\r
+        int setStretchBltMode;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setStretchBltMode;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            setStretchBltMode = leis.readUShort();\r
+            return LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_DIBCREATEPATTERNBRUSH record creates a Brush Object with a\r
+     * pattern specified by a DeviceIndependentBitmap (DIB) Object\r
+     */\r
+    public static class WmfDibCreatePatternBrush implements HwmfRecord {\r
+\r
+        HwmfBrushStyle style;\r
+\r
+        /**\r
+         * A 16-bit unsigned integer that defines whether the Colors field of a DIB\r
+         * Object contains explicit RGB values, or indexes into a palette.\r
+         *\r
+         * If the Style field specifies BS_PATTERN, a ColorUsage value of DIB_RGB_COLORS MUST be\r
+         * used regardless of the contents of this field.\r
+         *\r
+         * If the Style field specified anything but BS_PATTERN, this field MUST be one of the values:\r
+         * DIB_RGB_COLORS = 0x0000,\r
+         * DIB_PAL_COLORS = 0x0001,\r
+         * DIB_PAL_INDICES = 0x0002\r
+         */\r
+        int colorUsage;\r
+\r
+        HwmfBitmapDib patternDib;\r
+        HwmfBitmap16 pattern16;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.dibCreatePatternBrush;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            style = HwmfBrushStyle.valueOf(leis.readUShort());\r
+            colorUsage = leis.readUShort();\r
+            int size = 2*LittleEndianConsts.SHORT_SIZE;\r
+            switch (style) {\r
+            case BS_SOLID:\r
+            case BS_NULL:\r
+            case BS_DIBPATTERN:\r
+            case BS_DIBPATTERNPT:\r
+            case BS_HATCHED:\r
+                patternDib = new HwmfBitmapDib();\r
+                size += patternDib.init(leis);\r
+                break;\r
+            case BS_PATTERN:\r
+                pattern16 = new HwmfBitmap16();\r
+                size += pattern16.init(leis);\r
+                break;\r
+            case BS_INDEXED:\r
+            case BS_DIBPATTERN8X8:\r
+            case BS_MONOPATTERN:\r
+            case BS_PATTERN8X8:\r
+                throw new RuntimeException("pattern not supported");\r
+            }\r
+            return size;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_DELETEOBJECT record deletes an object, including Bitmap16, Brush,\r
+     * DeviceIndependentBitmap, Font, Palette, Pen, and Region. After the object is deleted,\r
+     * its index in the WMF Object Table is no longer valid but is available to be reused.\r
+     */\r
+    public static class WmfDeleteObject implements HwmfRecord {\r
+        /**\r
+         * A 16-bit unsigned integer used to index into the WMF Object Table to\r
+        get the object to be deleted.\r
+         */\r
+        int objectIndex;\r
+\r
+        public HwmfRecordType getRecordType() { return HwmfRecordType.deleteObject; }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            objectIndex = leis.readUShort();\r
+            return LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    public static class WmfCreatePatternBrush implements HwmfRecord {\r
+\r
+        HwmfBitmap16 pattern;\r
+\r
+        public HwmfRecordType getRecordType() { return HwmfRecordType.createPatternBrush; }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            pattern = new HwmfBitmap16(true);\r
+            return pattern.init(leis);\r
+        }\r
+    }\r
+\r
+    public static class WmfCreatePenIndirect implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit unsigned integer that specifies the pen style.\r
+         * The value MUST be defined from the PenStyle Enumeration table.\r
+         *\r
+         * PS_COSMETIC = 0x0000,\r
+         * PS_ENDCAP_ROUND = 0x0000,\r
+         * PS_JOIN_ROUND = 0x0000,\r
+         * PS_SOLID = 0x0000,\r
+         * PS_DASH = 0x0001,\r
+         * PS_DOT = 0x0002,\r
+         * PS_DASHDOT = 0x0003,\r
+         * PS_DASHDOTDOT = 0x0004,\r
+         * PS_NULL = 0x0005,\r
+         * PS_INSIDEFRAME = 0x0006,\r
+         * PS_USERSTYLE = 0x0007,\r
+         * PS_ALTERNATE = 0x0008,\r
+         * PS_ENDCAP_SQUARE = 0x0100,\r
+         * PS_ENDCAP_FLAT = 0x0200,\r
+         * PS_JOIN_BEVEL = 0x1000,\r
+         * PS_JOIN_MITER = 0x2000\r
+         */\r
+        int penStyle;\r
+        /**\r
+         * A 32-bit PointS Object that specifies a point for the object dimensions.\r
+         * The xcoordinate is the pen width. The y-coordinate is ignored.\r
+         */\r
+        int xWidth, yWidth;\r
+        /**\r
+         * A 32-bit ColorRef Object that specifies the pen color value.\r
+         */\r
+        HwmfColorRef colorRef;\r
+\r
+        public HwmfRecordType getRecordType() { return HwmfRecordType.createPenIndirect; }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            penStyle = leis.readUShort();\r
+            xWidth = leis.readShort();\r
+            yWidth = leis.readShort();\r
+            colorRef = new HwmfColorRef();\r
+            int size = 3*LittleEndianConsts.SHORT_SIZE;\r
+            size += colorRef.init(leis);\r
+            return size;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_CREATEBRUSHINDIRECT record creates a Brush Object\r
+     * from a LogBrush Object.\r
+     * \r
+     * The following table shows the relationship between values in the BrushStyle,\r
+     * ColorRef and BrushHatch fields in a LogBrush Object. Only supported brush styles are listed.\r
+     * \r
+     * <table>\r
+     * <tr>\r
+     *   <th>BrushStyle</th>\r
+     *   <th>ColorRef</th>\r
+     *   <th>BrushHatch</th>\r
+     * </tr>\r
+     * <tr>\r
+     *   <td>BS_SOLID</td>\r
+     *   <td>SHOULD be a ColorRef Object, which determines the color of the brush.</td>\r
+     *   <td>Not used, and SHOULD be ignored.</td>\r
+     * </tr>\r
+     * <tr>\r
+     *   <td>BS_NULL</td>\r
+     *   <td>Not used, and SHOULD be ignored.</td>\r
+     *   <td>Not used, and SHOULD be ignored.</td>\r
+     * </tr>\r
+     * <tr>\r
+     *   <td>BS_PATTERN</td>\r
+     *   <td>Not used, and SHOULD be ignored.</td>\r
+     *   <td>Not used. A default object, such as a solidcolor black Brush Object, MAY be created.</td>\r
+     * </tr>\r
+     * <tr>\r
+     *   <td>BS_DIBPATTERN</td>\r
+     *   <td>Not used, and SHOULD be ignored.</td>\r
+     *   <td>Not used. A default object, such as a solidcolor black Brush Object, MAY be created</td>\r
+     * </tr>\r
+     * <tr>\r
+     *   <td>BS_DIBPATTERNPT</td>\r
+     *   <td>Not used, and SHOULD be ignored.</td>\r
+     *   <td>Not used. A default object, such as a solidcolor black Brush Object, MAY be created.</td>\r
+     * </tr>\r
+     * <tr>\r
+     *   <td>BS_HATCHED</td>\r
+     *   <td>SHOULD be a ColorRef Object, which determines the foreground color of the hatch pattern.</td>\r
+     *   <td>A value from the {@link HwmfHatchStyle} Enumeration that specifies the orientation of lines used to create the hatch.</td>\r
+     * </tr>\r
+     * </table>\r
+     */\r
+    public static class WmfCreateBrushIndirect implements HwmfRecord {\r
+        HwmfBrushStyle brushStyle;\r
+\r
+        HwmfColorRef colorRef;\r
+\r
+        /**\r
+         * A 16-bit field that specifies the brush hatch type.\r
+         * Its interpretation depends on the value of BrushStyle.\r
+         * \r
+         */\r
+        HwmfHatchStyle brushHatch;\r
+\r
+        public HwmfRecordType getRecordType() { return HwmfRecordType.createBrushIndirect; }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            brushStyle = HwmfBrushStyle.valueOf(leis.readUShort());\r
+            colorRef = new HwmfColorRef();\r
+            int size = colorRef.init(leis);\r
+            brushHatch = HwmfHatchStyle.valueOf(leis.readUShort());\r
+            size += 4;\r
+            return size;\r
+        }\r
+    }\r
+}
\ No newline at end of file
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java
new file mode 100644 (file)
index 0000000..cbd0a60
--- /dev/null
@@ -0,0 +1,163 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+import java.io.IOException;\r
+\r
+import org.apache.poi.util.LittleEndianConsts;\r
+import org.apache.poi.util.LittleEndianInputStream;\r
+\r
+public class HwmfPalette {\r
+    \r
+    public static class PaletteEntry {\r
+        // Values (1 byte):  An 8-bit unsigned integer that defines how the palette entry is to be used. \r
+        // The Values field MUST be 0x00 or one of the values in the PaletteEntryFlag Enumeration table.\r
+        // Blue (1 byte): An 8-bit unsigned integer that defines the blue intensity value for the palette entry.\r
+        // Green (1 byte): An 8-bit unsigned integer that defines the green intensity value for the palette entry.\r
+        // Red (1 byte): An 8-bit unsigned integer that defines the red intensity value for the palette entry.\r
+        int values, blue, green, red;\r
+        \r
+        public int init(LittleEndianInputStream leis) throws IOException {\r
+            values = leis.readUByte();\r
+            blue = leis.readUByte();\r
+            green = leis.readUByte();\r
+            red = leis.readUByte();\r
+            return 4*LittleEndianConsts.BYTE_SIZE;\r
+        }\r
+    }\r
+    \r
+    public static abstract class WmfPaletteParent implements HwmfRecord  {\r
+    \r
+        /**\r
+         * Start (2 bytes):  A 16-bit unsigned integer that defines the offset into the Palette Object when\r
+         * used with the META_SETPALENTRIES and META_ANIMATEPALETTE record types.\r
+         * When used with META_CREATEPALETTE, it MUST be 0x0300\r
+         */\r
+        int start;\r
+        \r
+        /**\r
+         * NumberOfEntries (2 bytes):  A 16-bit unsigned integer that defines the number of objects in\r
+         * aPaletteEntries.  \r
+         */\r
+        int numberOfEntries;\r
+        \r
+        PaletteEntry entries[];\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            start = leis.readUShort();\r
+            numberOfEntries = leis.readUShort();\r
+            int size = 2*LittleEndianConsts.SHORT_SIZE;\r
+            entries = new PaletteEntry[numberOfEntries];\r
+            for (int i=0; i<numberOfEntries; i++) {\r
+                entries[i] = new PaletteEntry();\r
+                size += entries[i].init(leis);\r
+            }\r
+            return size;\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * The META_CREATEPALETTE record creates a Palette Object\r
+     */\r
+    public static class WmfCreatePalette extends WmfPaletteParent {\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.createPalette;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_SETPALENTRIES record defines RGB color values in a range of entries in the logical\r
+     * palette that is defined in the playback device context.\r
+     */\r
+    public static class WmfSetPaletteEntries extends WmfPaletteParent {\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setPalEntries;\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * The META_RESIZEPALETTE record redefines the size of the logical palette that is defined in the\r
+     * playback device context.\r
+     */\r
+    public static class WmfResizePalette implements HwmfRecord {\r
+        /**\r
+         * A 16-bit unsigned integer that defines the number of entries in \r
+         * the logical palette.\r
+         */\r
+        int numberOfEntries;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.resizePalette;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            numberOfEntries = leis.readUShort();\r
+            return LittleEndianConsts.SHORT_SIZE;\r
+        }        \r
+    }\r
+\r
+    /**\r
+     * The META_SELECTPALETTE record defines the current logical palette with a specified Palette Object.\r
+     */\r
+    public static class WmfSelectPalette implements HwmfRecord {\r
+        /**\r
+         * A 16-bit unsigned integer used to index into the WMF Object Table to get\r
+         * the Palette Object to be selected.\r
+         */\r
+        int palette;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.selectPalette;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            palette = leis.readUShort();\r
+            return LittleEndianConsts.SHORT_SIZE;\r
+        }        \r
+    }\r
+\r
+    /**\r
+     * The META_REALIZEPALETTE record maps entries from the logical palette that\r
+     * is defined in the playback device context to the system palette.\r
+     */\r
+    public static class WmfRealizePalette implements HwmfRecord {\r
+        public HwmfRecordType getRecordType() { return HwmfRecordType.realizePalette; }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            return 0;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_ANIMATEPALETTE record redefines entries in the logical palette that\r
+     * is defined in the playback device context with the specified Palette object\r
+     * \r
+     * The logical palette that is specified by the Palette object in this record is the\r
+     * source of the palette changes, and the logical palette that is currently selected\r
+     * into the playback device context is the destination. Entries in the destination\r
+     * palette with the PC_RESERVED PaletteEntryFlag set SHOULD be modified by this record,\r
+     * and entries with that flag clear SHOULD NOT be modified.\r
+     * If none of the entries in the destination palette have the PC_RESERVED flag set, then\r
+     * this record SHOULD have no effect.\r
+     */\r
+    public static class WmfAnimatePalette extends WmfPaletteParent {\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.animatePalette;\r
+        }\r
+    }\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPlaceableHeader.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPlaceableHeader.java
new file mode 100644 (file)
index 0000000..edff44d
--- /dev/null
@@ -0,0 +1,77 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+import java.io.IOException;\r
+\r
+import org.apache.poi.util.LittleEndianConsts;\r
+import org.apache.poi.util.LittleEndianInputStream;\r
+\r
+public class HwmfPlaceableHeader {\r
+    public static int WMF_HEADER_MAGIC = 0x9AC6CDD7;\r
+    \r
+    protected HwmfPlaceableHeader(LittleEndianInputStream leis) throws IOException {\r
+        /*\r
+         * HWmf (2 bytes):  The resource handle to the metafile, when the metafile is in memory. When\r
+         * the metafile is on disk, this field MUST contain 0x0000. This attribute of the metafile is\r
+         * specified in the Type field of the META_HEADER record.\r
+         */\r
+        leis.readShort(); // ignore\r
+        \r
+        /*\r
+         * BoundingBox (8 bytes):  The destination rectangle, measured in logical units, for displaying\r
+         * the metafile. The size of a logical unit is specified by the Inch field.\r
+         */\r
+        int x1 = leis.readShort();\r
+        int y1 = leis.readShort();\r
+        int x2 = leis.readShort();\r
+        int y2 = leis.readShort();\r
+        \r
+        /*\r
+         * Inch (2 bytes):  The number of logical units per inch used to represent the image.\r
+         * This value can be used to scale an image.\r
+         * By convention, an image is considered to be recorded at 1440 logical units (twips) per inch.\r
+         * Thus, a value of 720 specifies that the image SHOULD be rendered at twice its normal size,\r
+         * and a value of 2880 specifies that the image SHOULD be rendered at half its normal size.\r
+         */\r
+        int inch = leis.readShort();\r
+        \r
+        /*\r
+         * Reserved (4 bytes):  A field that is not used and MUST be set to 0x00000000.\r
+         */\r
+        leis.readInt();\r
+        \r
+        /*\r
+         * Checksum (2 bytes):  A checksum for the previous 10 16-bit values in the header.\r
+         * This value can be used to determine whether the metafile has become corrupted.\r
+         */\r
+        leis.readShort();\r
+        \r
+    }\r
+    \r
+    public static HwmfPlaceableHeader readHeader(LittleEndianInputStream leis) throws IOException {\r
+        leis.mark(LittleEndianConsts.INT_SIZE);\r
+        int magic = leis.readInt();\r
+        if (magic == WMF_HEADER_MAGIC) {\r
+            return new HwmfPlaceableHeader(leis);\r
+        } else {\r
+            leis.reset();\r
+            return null;\r
+        }\r
+    }\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRecord.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRecord.java
new file mode 100644 (file)
index 0000000..d600b09
--- /dev/null
@@ -0,0 +1,35 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+import java.io.IOException;\r
+\r
+import org.apache.poi.util.LittleEndianInputStream;\r
+\r
+public interface HwmfRecord {\r
+    HwmfRecordType getRecordType();\r
+\r
+    /**\r
+     * Init record from stream\r
+     *\r
+     * @param leis the little endian input stream\r
+     * @return count of processed bytes\r
+     * @throws IOException\r
+     */\r
+    int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException;\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRecordType.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRecordType.java
new file mode 100644 (file)
index 0000000..b5b9309
--- /dev/null
@@ -0,0 +1,111 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+/**\r
+ * Available record types for WMF\r
+ * \r
+ * @see <a href="http://www.symantec.com/avcenter/reference/inside.the.windows.meta.file.format.pdf">Inside the Windows Meta File Format</a>\r
+ */\r
+public enum HwmfRecordType {\r
+    eof(0x0000, null),\r
+    realizePalette(0x0035, HwmfPalette.WmfRealizePalette.class),\r
+    setPalEntries(0x0037, HwmfPalette.WmfSetPaletteEntries.class),\r
+    setBkMode(0x0102, HwmfMisc.WmfSetBkMode.class),\r
+    setMapMode(0x0103, HwmfMisc.WmfSetMapMode.class),\r
+    setRop2(0x0104, HwmfMisc.WmfSetRop2.class),\r
+    setRelabs(0x0105, HwmfMisc.WmfSetRelabs.class),\r
+    setPolyFillMode(0x0106, HwmfFill.WmfSetPolyfillMode.class),\r
+    setStretchBltMode(0x0107, HwmfMisc.WmfSetStretchBltMode.class),\r
+    setTextCharExtra(0x0108, HwmfText.WmfSetTextCharExtra.class),\r
+    restoreDc(0x0127, HwmfMisc.WmfRestoreDc.class),\r
+    resizePalette(0x0139, HwmfPalette.WmfResizePalette.class),\r
+    dibCreatePatternBrush(0x0142, HwmfMisc.WmfDibCreatePatternBrush.class),\r
+    setLayout(0x0149, HwmfMisc.WmfSetLayout.class),\r
+    setBkColor(0x0201, HwmfMisc.WmfSetBkColor.class),\r
+    setTextColor(0x0209, HwmfText.WmfSetTextColor.class),\r
+    offsetViewportOrg(0x0211, HwmfWindowing.WmfOffsetViewportOrg.class),\r
+    lineTo(0x0213, HwmfDraw.WmfLineTo.class),\r
+    moveTo(0x0214, HwmfDraw.WmfMoveTo.class),\r
+    offsetClipRgn(0x0220, HwmfWindowing.WmfOffsetClipRgn.class),\r
+    fillRegion(0x0228, HwmfFill.WmfFillRegion.class),\r
+    setMapperFlags(0x0231, HwmfMisc.WmfSetMapperFlags.class),\r
+    selectPalette(0x0234, HwmfPalette.WmfSelectPalette.class),\r
+    polygon(0x0324, HwmfDraw.WmfPolygon.class),\r
+    polyline(0x0325, HwmfDraw.WmfPolyline.class),\r
+    setTextJustification(0x020a, HwmfText.WmfSetTextJustification.class),\r
+    setWindowOrg(0x020b, HwmfWindowing.WmfSetWindowOrg.class),\r
+    setWindowExt(0x020c, HwmfWindowing.WmfSetWindowExt.class),\r
+    setViewportOrg(0x020d, HwmfWindowing.WmfSetViewportOrg.class),\r
+    setViewportExt(0x020e, HwmfWindowing.WmfSetViewportExt.class),\r
+    offsetWindowOrg(0x020f, HwmfWindowing.WmfOffsetWindowOrg.class),\r
+    scaleWindowExt(0x0410, HwmfWindowing.WmfScaleWindowExt.class),\r
+    scaleViewportExt(0x0412, HwmfWindowing.WmfScaleViewportExt.class), \r
+    excludeClipRect(0x0415, HwmfWindowing.WmfExcludeClipRect.class),\r
+    intersectClipRect(0x0416, HwmfWindowing.WmfIntersectClipRect.class),\r
+    ellipse(0x0418, HwmfDraw.WmfEllipse.class),\r
+    floodFill(0x0419, HwmfFill.WmfFloodFill.class),\r
+    frameRegion(0x0429, HwmfDraw.WmfFrameRegion.class),\r
+    animatePalette(0x0436, HwmfPalette.WmfAnimatePalette.class),\r
+    textOut(0x0521, HwmfText.WmfTextOut.class),\r
+    polyPolygon(0x0538, HwmfDraw.WmfPolyPolygon.class),\r
+    extFloodFill(0x0548, HwmfFill.WmfExtFloodFill.class),\r
+    rectangle(0x041b, HwmfDraw.WmfRectangle.class),\r
+    setPixel(0x041f, HwmfDraw.WmfSetPixel.class),\r
+    roundRect(0x061c, HwmfDraw.WmfRoundRect.class),\r
+    patBlt(0x061d, HwmfFill.WmfPatBlt.class),\r
+    saveDc(0x001e, HwmfMisc.WmfSaveDc.class),\r
+    pie(0x081a, HwmfDraw.WmfPie.class),\r
+    stretchBlt(0x0b23, HwmfFill.WmfStretchBlt.class),\r
+    escape(0x0626, HwmfEscape.class),\r
+    invertRegion(0x012a, HwmfFill.WmfInvertRegion.class),\r
+    paintRegion(0x012b, HwmfFill.WmfPaintRegion.class),\r
+    selectClipRegion(0x012c, HwmfWindowing.WmfSelectClipRegion.class),\r
+    selectObject(0x012d, HwmfDraw.WmfSelectObject.class),\r
+    setTextAlign(0x012e, HwmfText.WmfSetTextAlign.class),\r
+    arc(0x0817, HwmfDraw.WmfArc.class),\r
+    chord(0x0830, HwmfDraw.WmfChord.class),\r
+    bitBlt(0x0922, HwmfFill.WmfBitBlt.class),\r
+    extTextOut(0x0a32, HwmfText.WmfExtTextOut.class),\r
+    setDibToDev(0x0d33, HwmfFill.WmfSetDibToDev.class),\r
+    dibBitBlt(0x0940, HwmfFill.WmfDibBitBlt.class),\r
+    dibStretchBlt(0x0b41, HwmfFill.WmfDibStretchBlt.class),\r
+    stretchDib(0x0f43, HwmfFill.WmfStretchDib.class),\r
+    deleteObject(0x01f0, HwmfMisc.WmfDeleteObject.class),\r
+    createPalette(0x00f7, HwmfPalette.WmfCreatePalette.class),\r
+    createPatternBrush(0x01f9, HwmfMisc.WmfCreatePatternBrush.class),\r
+    createPenIndirect(0x02fa, HwmfMisc.WmfCreatePenIndirect.class),\r
+    createFontIndirect(0x02fb, HwmfText.WmfCreateFontIndirect.class),\r
+    createBrushIndirect(0x02fc, HwmfMisc.WmfCreateBrushIndirect.class),\r
+    createRegion(0x06ff, HwmfWindowing.WmfCreateRegion.class);\r
+    \r
+    public int id;\r
+    public Class<? extends HwmfRecord> clazz;\r
+    \r
+    HwmfRecordType(int id, Class<? extends HwmfRecord> clazz) {\r
+        this.id = id;\r
+        this.clazz = clazz;\r
+    }\r
+    \r
+    public static HwmfRecordType getById(int id) {\r
+        for (HwmfRecordType wrt : values()) {\r
+            if (wrt.id == id) return wrt;\r
+        }\r
+        return null;\r
+    }\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfTernaryRasterOp.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfTernaryRasterOp.java
new file mode 100644 (file)
index 0000000..315eb11
--- /dev/null
@@ -0,0 +1,336 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+public enum HwmfTernaryRasterOp {\r
+    BLACKNESS(0x0000,0x0042,"0"),\r
+    DPSOON(0x0001,0x0289,"DPSoon"),\r
+    DPSONA(0x0002,0x0C89,"DPSona"),\r
+    PSON(0x0003,0x00AA,"PSon"),\r
+    SDPONA(0x0004,0x0C88,"SDPona"),\r
+    DPON(0x0005,0x00A9,"DPon"),\r
+    PDSXNON(0x0006,0x0865,"PDSxnon"),\r
+    PDSAON(0x0007,0x02C5,"PDSaon"),\r
+    SDPNAA(0x0008,0x0F08,"SDPnaa"),\r
+    PDSXON(0x0009,0x0245,"PDSxon"),\r
+    DPNA(0x000A,0x0329,"DPna"),\r
+    PSDNAON(0x000B,0x0B2A,"PSDnaon"),\r
+    SPNA(0x000C,0x0324,"SPna"),\r
+    PDSNAON(0x000D,0x0B25,"PDSnaon"),\r
+    PDSONON(0x000E,0x08A5,"PDSonon"),\r
+    PN(0x000F,0x0001,"Pn"),\r
+    PDSONA(0x0010,0x0C85,"PDSona"),\r
+    NOTSRCERASE(0x0011,0x00A6,"DSon"),\r
+    SDPXNON(0x0012,0x0868,"SDPxnon"),\r
+    SDPAON(0x0013,0x02C8,"SDPaon"),\r
+    DPSXNON(0x0014,0x0869,"DPSxnon"),\r
+    DPSAON(0x0015,0x02C9,"DPSaon"),\r
+    PSDPSANAXX(0x0016,0x5CCA,"PSDPSanaxx"),\r
+    SSPXDSXAXN(0x0017,0x1D54,"SSPxDSxaxn"),\r
+    SPXPDXA(0x0018,0x0D59,"SPxPDxa"),\r
+    SDPSANAXN(0x0019,0x1CC8,"SDPSanaxn"),\r
+    PDSPAOX(0x001A,0x06C5,"PDSPaox"),\r
+    SDPSXAXN(0x001B,0x0768,"SDPSxaxn"),\r
+    PSDPAOX(0x001C,0x06CA,"PSDPaox"),\r
+    DSPDXAXN(0x001D,0x0766,"DSPDxaxn"),\r
+    PDSOX(0x001E,0x01A5,"PDSox"),\r
+    PDSOAN(0x001F,0x0385,"PDSoan"),\r
+    DPSNAA(0x0020,0x0F09,"DPSnaa"),\r
+    SDPXON(0x0021,0x0248,"SDPxon"),\r
+    DSNA(0x0022,0x0326,"DSna"),\r
+    SPDNAON(0x0023,0x0B24,"SPDnaon"),\r
+    SPXDSXA(0x0024,0x0D55,"SPxDSxa"),\r
+    PDSPANAXN(0x0025,0x1CC5,"PDSPanaxn"),\r
+    SDPSAOX(0x0026,0x06C8,"SDPSaox"),\r
+    SDPSXNOX(0x0027,0x1868,"SDPSxnox"),\r
+    DPSXA(0x0028,0x0369,"DPSxa"),\r
+    PSDPSAOXXN(0x0029,0x16CA,"PSDPSaoxxn"),\r
+    DPSANA(0x002A,0x0CC9,"DPSana"),\r
+    SSPXPDXAXN(0x002B,0x1D58,"SSPxPDxaxn"),\r
+    SPDSOAX(0x002C,0x0784,"SPDSoax"),\r
+    PSDNOX(0x002D,0x060A,"PSDnox"),\r
+    PSDPXOX(0x002E,0x064A,"PSDPxox"),\r
+    PSDNOAN(0x002F,0x0E2A,"PSDnoan"),\r
+    PSNA(0x0030,0x032A,"PSna"),\r
+    SDPNAON(0x0031,0x0B28,"SDPnaon"),\r
+    SDPSOOX(0x0032,0x0688,"SDPSoox"),\r
+    NOTSRCCOPY(0x0033,0x0008,"Sn"),\r
+    SPDSAOX(0x0034,0x06C4,"SPDSaox"),\r
+    SPDSXNOX(0x0035,0x1864,"SPDSxnox"),\r
+    SDPOX(0x0036,0x01A8,"SDPox"),\r
+    SDPOAN(0x0037,0x0388,"SDPoan"),\r
+    PSDPOAX(0x0038,0x078A,"PSDPoax"),\r
+    SPDNOX(0x0390,0x604,"SPDnox"),\r
+    SPDSXOX(0x003A,0x0644,"SPDSxox"),\r
+    SPDNOAN(0x003B,0x0E24,"SPDnoan"),\r
+    PSX(0x003C,0x004A,"PSx"),\r
+    SPDSONOX(0x003D,0x18A4,"SPDSonox"),\r
+    SPDSNAOX(0x003E,0x1B24,"SPDSnaox"),\r
+    PSAN(0x003F,0x00EA,"PSan"),\r
+    PSDNAA(0x0040,0x0F0A,"PSDnaa"),\r
+    DPSXON(0x0041,0x0249,"DPSxon"),\r
+    SDXPDXA(0x0042,0x0D5D,"SDxPDxa"),\r
+    SPDSANAXN(0x0043,0x1CC4,"SPDSanaxn"),\r
+    SRCERASE(0x0044,0x0328,"SDna"),\r
+    DPSNAON(0x0045,0x0B29,"DPSnaon"),\r
+    DSPDAOX(0x0046,0x06C6,"DSPDaox"),\r
+    PSDPXAXN(0x0047,0x076A,"PSDPxaxn"),\r
+    SDPXA(0x0048,0x0368,"SDPxa"),\r
+    PDSPDAOXXN(0x0049,0x16C5,"PDSPDaoxxn"),\r
+    DPSDOAX(0x004A,0x0789,"DPSDoax"),\r
+    PDSNOX(0x004B,0x0605,"PDSnox"),\r
+    SDPANA(0x004C,0x0CC8,"SDPana"),\r
+    SSPXDSXOXN(0x004D,0x1954,"SSPxDSxoxn"),\r
+    PDSPXOX(0x004E,0x0645,"PDSPxox"),\r
+    PDSNOAN(0x004F,0x0E25,"PDSnoan"),\r
+    PDNA(0x0050,0x0325,"PDna"),\r
+    DSPNAON(0x0051,0x0B26,"DSPnaon"),\r
+    DPSDAOX(0x0052,0x06C9,"DPSDaox"),\r
+    SPDSXAXN(0x0053,0x0764,"SPDSxaxn"),\r
+    DPSONON(0x0054,0x08A9,"DPSonon"),\r
+    DSTINVERT(0x0055,0x0009,"Dn"),\r
+    DPSOX(0x0056,0x01A9,"DPSox"),\r
+    DPSOAN(0x0005,0x70389,"DPSoan"),\r
+    PDSPOAX(0x0058,0x0785,"PDSPoax"),\r
+    DPSNOX(0x0059,0x0609,"DPSnox"),\r
+    PATINVERT(0x005A,0x0049,"DPx"),\r
+    DPSDONOX(0x005B,0x18A9,"DPSDonox"),\r
+    DPSDXOX(0x005C,0x0649,"DPSDxox"),\r
+    DPSNOAN(0x005D,0x0E29,"DPSnoan"),\r
+    DPSDNAOX(0x005E,0x1B29,"DPSDnaox"),\r
+    DPAN(0x005F,0x00E9,"DPan"),\r
+    PDSXA(0x0060,0x0365,"PDSxa"),\r
+    DSPDSAOXXN(0x0061,0x16C6,"DSPDSaoxxn"),\r
+    DSPDOAX(0x0062,0x0786,"DSPDoax"),\r
+    SDPNOX(0x0063,0x0608,"SDPnox"),\r
+    SDPSOAX(0x0064,0x0788,"SDPSoax"),\r
+    DSPNOX(0x0065,0x0606,"DSPnox"),\r
+    SRCINVERT(0x0066,0x0046,"DSx"),\r
+    SDPSONOX(0x0067,0x18A8,"SDPSonox"),\r
+    DSPDSONOXXN(0x0068,0x58A6,"DSPDSonoxxn"),\r
+    PDSXXN(0x0069,0x0145,"PDSxxn"),\r
+    DPSAX(0x006A,0x01E9,"DPSax"),\r
+    PSDPSOAXXN(0x006B,0x178A,"PSDPSoaxxn"),\r
+    SDPAX(0x006C,0x01E8,"SDPax"),\r
+    PDSPDOAXXN(0x006D,0x1785,"PDSPDoaxxn"),\r
+    SDPSNOAX(0x006E,0x1E28,"SDPSnoax"),\r
+    // PDXNAN(0x006F,0x0C65,"PDXnan"), // invalid combo\r
+    PDSANA(0x0070,0x0CC5,"PDSana"),\r
+    SSDXPDXAXN(0x0071,0x1D5C,"SSDxPDxaxn"),\r
+    SDPSXOX(0x0072,0x0648,"SDPSxox"),\r
+    SDPNOAN(0x0073,0x0E28,"SDPnoan"),\r
+    DSPDXOX(0x0074,0x0646,"DSPDxox"),\r
+    DSPNOAN(0x0075,0x0E26,"DSPnoan"),\r
+    SDPSNAOX(0x0076,0x1B28,"SDPSnaox"),\r
+    DSAN(0x0077,0x00E6,"DSan"),\r
+    PDSAX(0x0078,0x01E5,"PDSax"),\r
+    DSPDSOAXXN(0x0079,0x1786,"DSPDSoaxxn"),\r
+    DPSDNOAX(0x007A,0x1E29,"DPSDnoax"),\r
+    SDPXNAN(0x007B,0x0C68,"SDPxnan"),\r
+    SPDSNOAX(0x007C,0x1E24,"SPDSnoax"),\r
+    DPSXNAN(0x007D,0x0C69,"DPSxnan"),\r
+    SPXDSXO(0x007E,0x0955,"SPxDSxo"),\r
+    DPSAAN(0x007F,0x03C9,"DPSaan"),\r
+    DPSAA(0x0080,0x03E9,"DPSaa"),\r
+    SPXDSXON(0x0081,0x0975,"SPxDSxon"),\r
+    DPSXNA(0x0082,0x0C49,"DPSxna"),\r
+    SPDSNOAXN(0x0083,0x1E04,"SPDSnoaxn"),\r
+    SDPXNA(0x0084,0x0C48,"SDPxna"),\r
+    PDSPNOAXN(0x0085,0x1E05,"PDSPnoaxn"),\r
+    DSPDSOAXX(0x0086,0x17A6,"DSPDSoaxx"),\r
+    PDSAXN(0x0087,0x01C5,"PDSaxn"),\r
+    SRCAND(0x0088,0x00C6,"DSa"),\r
+    SDPSNAOXN(0x0089,0x1B08,"SDPSnaoxn"),\r
+    DSPNOA(0x008A,0x0E06,"DSPnoa"),\r
+    DSPDXOXN(0x008B,0x0666,"DSPDxoxn"),\r
+    SDPNOA(0x008C,0x0E08,"SDPnoa"),\r
+    SDPSXOXN(0x008D,0x0668,"SDPSxoxn"),\r
+    SSDXPDXAX(0x008E,0x1D7C,"SSDxPDxax"),\r
+    PDSANAN(0x008F,0x0CE5,"PDSanan"),\r
+    PDSXNA(0x0090,0x0C45,"PDSxna"),\r
+    SDPSNOAXN(0x0091,0x1E08,"SDPSnoaxn"),\r
+    DPSDPOAXX(0x0092,0x17A9,"DPSDPoaxx"),\r
+    SPDAXN(0x0093,0x01C4,"SPDaxn"),\r
+    PSDPSOAXX(0x0094,0x17AA,"PSDPSoaxx"),\r
+    DPSAXN(0x0095,0x01C9,"DPSaxn"),\r
+    DPSXX(0x0096,0x0169,"DPSxx"),\r
+    PSDPSONOXX(0x0097,0x588A,"PSDPSonoxx"),\r
+    SDPSONOXN(0x0098,0x1888,"SDPSonoxn"),\r
+    DSXN(0x0099,0x0066,"DSxn"),\r
+    DPSNAX(0x009A,0x0709,"DPSnax"),\r
+    SDPSOAXN(0x009B,0x07A8,"SDPSoaxn"),\r
+    SPDNAX(0x009C,0x0704,"SPDnax"),\r
+    DSPDOAXN(0x009D,0x07A6,"DSPDoaxn"),\r
+    DSPDSAOXX(0x009E,0x16E6,"DSPDSaoxx"),\r
+    PDSXAN(0x009F,0x0345,"PDSxan"),\r
+    DPA(0x00A0,0x00C9,"DPa"),\r
+    PDSPNAOXN(0x00A1,0x1B05,"PDSPnaoxn"),\r
+    DPSNOA(0x00A2,0x0E09,"DPSnoa"),\r
+    DPSDXOXN(0x00A3,0x0669,"DPSDxoxn"),\r
+    PDSPONOXN(0x00A4,0x1885,"PDSPonoxn"),\r
+    PDXN(0x00A5,0x0065,"PDxn"),\r
+    DSPNAX(0x00A6,0x0706,"DSPnax"),\r
+    PDSPOAXN(0x00A7,0x07A5,"PDSPoaxn"),\r
+    DPSOA(0x00A8,0x03A9,"DPSoa"),\r
+    DPSOXN(0x00A9,0x0189,"DPSoxn"),\r
+    D(0x00AA,0x0029,"D"),\r
+    DPSONO(0x00AB,0x0889,"DPSono"),\r
+    SPDSXAX(0x00AC,0x0744,"SPDSxax"),\r
+    DPSDAOXN(0x00AD,0x06E9,"DPSDaoxn"),\r
+    DSPNAO(0x00AE,0x0B06,"DSPnao"),\r
+    DPNO(0x00AF,0x0229,"DPno"),\r
+    PDSNOA(0x00B0,0x0E05,"PDSnoa"),\r
+    PDSPXOXN(0x00B1,0x0665,"PDSPxoxn"),\r
+    SSPXDSXOX(0x00B2,0x1974,"SSPxDSxox"),\r
+    SDPANAN(0x00B3,0x0CE8,"SDPanan"),\r
+    PSDNAX(0x00B4,0x070A,"PSDnax"),\r
+    DPSDOAXN(0x00B5,0x07A9,"DPSDoaxn"),\r
+    DPSDPAOXX(0x00B6,0x16E9,"DPSDPaoxx"),\r
+    SDPXAN(0x00B7,0x0348,"SDPxan"),\r
+    PSDPXAX(0x00B8,0x074A,"PSDPxax"),\r
+    DSPDAOXN(0x00B9,0x06E6,"DSPDaoxn"),\r
+    DPSNAO(0x00BA,0x0B09,"DPSnao"),\r
+    MERGEPAINT(0x00BB,0x0226,"DSno"),\r
+    SPDSANAX(0x00BC,0x1CE4,"SPDSanax"),\r
+    SDXPDXAN(0x00BD,0x0D7D,"SDxPDxan"),\r
+    DPSXO(0x00BE,0x0269,"DPSxo"),\r
+    DPSANO(0x00BF,0x08C9,"DPSano"),\r
+    MERGECOPY(0x00C0,0x00CA,"PSa"),\r
+    SPDSNAOXN(0x00C1,0x1B04,"SPDSnaoxn"),\r
+    SPDSONOXN(0x00C2,0x1884,"SPDSonoxn"),\r
+    PSXN(0x00C3,0x006A,"PSxn"),\r
+    SPDNOA(0x00C4,0x0E04,"SPDnoa"),\r
+    SPDSXOXN(0x00C5,0x0664,"SPDSxoxn"),\r
+    SDPNAX(0x00C6,0x0708,"SDPnax"),\r
+    PSDPOAXN(0x00C7,0x07AA,"PSDPoaxn"),\r
+    SDPOA(0x00C8,0x03A8,"SDPoa"),\r
+    SPDOXN(0x00C9,0x0184,"SPDoxn"),\r
+    DPSDXAX(0x00CA,0x0749,"DPSDxax"),\r
+    SPDSAOXN(0x00CB,0x06E4,"SPDSaoxn"),\r
+    SRCCOPY(0x00CC,0x0020,"S"),\r
+    SDPONO(0x00CD,0x0888,"SDPono"),\r
+    SDPNAO(0x00CE,0x0B08,"SDPnao"),\r
+    SPNO(0x00CF,0x0224,"SPno"),\r
+    PSDNOA(0x00D0,0x0E0A,"PSDnoa"),\r
+    PSDPXOXN(0x00D1,0x066A,"PSDPxoxn"),\r
+    PDSNAX(0x00D2,0x0705,"PDSnax"),\r
+    SPDSOAXN(0x00D3,0x07A4,"SPDSoaxn"),\r
+    SSPXPDXAX(0x00D4,0x1D78,"SSPxPDxax"),\r
+    DPSANAN(0x00D5,0x0CE9,"DPSanan"),\r
+    PSDPSAOXX(0x00D6,0x16EA,"PSDPSaoxx"),\r
+    DPSXAN(0x00D7,0x0349,"DPSxan"),\r
+    PDSPXAX(0x00D8,0x0745,"PDSPxax"),\r
+    SDPSAOXN(0x00D9,0x06E8,"SDPSaoxn"),\r
+    DPSDANAX(0x00DA,0x1CE9,"DPSDanax"),\r
+    SPXDSXAN(0x00DB,0x0D75,"SPxDSxan"),\r
+    SPDNAO(0x00DC,0x0B04,"SPDnao"),\r
+    SDNO(0x00DD,0x0228,"SDno"),\r
+    SDPXO(0x00DE,0x0268,"SDPxo"),\r
+    SDPANO(0x00DF,0x08C8,"SDPano"),\r
+    PDSOA(0x00E0,0x03A5,"PDSoa"),\r
+    PDSOXN(0x00E1,0x0185,"PDSoxn"),\r
+    DSPDXAX(0x00E2,0x0746,"DSPDxax"),\r
+    PSDPAOXN(0x00E3,0x06EA,"PSDPaoxn"),\r
+    SDPSXAX(0x00E4,0x0748,"SDPSxax"),\r
+    PDSPAOXN(0x00E5,0x06E5,"PDSPaoxn"),\r
+    SDPSANAX(0x00E6,0x1CE8,"SDPSanax"),\r
+    SPXPDXAN(0x00E7,0x0D79,"SPxPDxan"),\r
+    SSPXDSXAX(0x00E8,0x1D74,"SSPxDSxax"),\r
+    DSPDSANAXXN(0x00E9,0x5CE6,"DSPDSanaxxn"),\r
+    DPSAO(0x00EA,0x02E9,"DPSao"),\r
+    DPSXNO(0x00EB,0x0849,"DPSxno"),\r
+    SDPAO(0x00EC,0x02E8,"SDPao"),\r
+    SDPXNO(0x00ED,0x0848,"SDPxno"),\r
+    SRCPAINT(0x00EE,0x0086,"DSo"),\r
+    SDPNOO(0x00EF,0x0A08,"SDPnoo"),\r
+    PATCOPY(0x00F0,0x0021,"P"),\r
+    PDSONO(0x00F1,0x0885,"PDSono"),\r
+    PDSNAO(0x00F2,0x0B05,"PDSnao"),\r
+    PSNO(0x00F3,0x022A,"PSno"),\r
+    PSDNAO(0x00F4,0x0B0A,"PSDnao"),\r
+    PDNO(0x00F5,0x0225,"PDno"),\r
+    PDSXO(0x00F6,0x0265,"PDSxo"),\r
+    PDSANO(0x00F7,0x08C5,"PDSano"),\r
+    PDSAO(0x00F8,0x02E5,"PDSao"),\r
+    PDSXNO(0x00F9,0x0845,"PDSxno"),\r
+    DPO(0x00FA,0x0089,"DPo"),\r
+    PATPAINT(0x00FB,0x0A09,"DPSnoo"),\r
+    PSO(0x00FC,0x008A,"PSo"),\r
+    PSDNOO(0x00FD,0x0A0A,"PSDnoo"),\r
+    DPSOO(0x00FE,0x02A9,"DPSoo"),\r
+    WHITENESS(0x00FF,0x0062,"1");\r
+    \r
+    int opIndex;\r
+    int opCode;\r
+    String opCmd;\r
+    \r
+    HwmfTernaryRasterOp(int opIndex, int opCode, String opCmd) {\r
+        this.opIndex=opIndex;\r
+        this.opCode=opCode;\r
+        this.opCmd=opCmd;\r
+    }\r
+    \r
+    public static HwmfTernaryRasterOp fromOpIndex(int opIndex) {\r
+        for (HwmfTernaryRasterOp bb : HwmfTernaryRasterOp.values()) {\r
+            if (bb.opIndex == opIndex) {\r
+                return bb;\r
+            }\r
+        }\r
+        return null;\r
+    }\r
+    \r
+    public String describeCmd() {\r
+        String stack[] = new String[10];\r
+        int stackPnt = 0;\r
+        \r
+        for (char c : opCmd.toCharArray()) {\r
+            switch (c) {\r
+                case 'S':\r
+                case 'D':\r
+                case 'P':\r
+                    stack[stackPnt++] = ""+c;\r
+                    break;\r
+                case 'n':\r
+                    stack[stackPnt-1] = "not("+stack[stackPnt-1]+")";\r
+                    break;\r
+                case 'a':\r
+                    stack[stackPnt-2] = "("+stack[stackPnt-1]+" and "+stack[stackPnt-2]+")";\r
+                    stackPnt--;\r
+                    break;\r
+                case 'o':\r
+                    stack[stackPnt-2] = "("+stack[stackPnt-1]+" or "+stack[stackPnt-2]+")";\r
+                    stackPnt--;\r
+                    break;\r
+                case 'x':\r
+                    stack[stackPnt-2] = "("+stack[stackPnt-1]+" xor "+stack[stackPnt-2]+")";\r
+                    stackPnt--;\r
+                    break;\r
+                case '1':\r
+                    stack[stackPnt++] = "all white";\r
+                    break;\r
+                case '0':\r
+                    stack[stackPnt++] = "all black";\r
+                    break;\r
+                default:\r
+                    throw new RuntimeException("unknown cmd '"+c+"'.");\r
+            }\r
+        }\r
+\r
+        return stack[--stackPnt];\r
+    }\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java
new file mode 100644 (file)
index 0000000..84dc4b1
--- /dev/null
@@ -0,0 +1,347 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+import java.io.IOException;\r
+\r
+import org.apache.poi.hwmf.record.HwmfMisc.WmfSetMapMode;\r
+import org.apache.poi.util.LittleEndianConsts;\r
+import org.apache.poi.util.LittleEndianInputStream;\r
+\r
+public class HwmfText {\r
+\r
+    /**\r
+     * The META_SETTEXTCHAREXTRA record defines inter-character spacing for text justification in the \r
+     * playback device context. Spacing is added to the white space between each character, including\r
+     * break characters, when a line of justified text is output.\r
+     */\r
+    public static class WmfSetTextCharExtra implements HwmfRecord {\r
+        \r
+        /**\r
+         * A 16-bit unsigned integer that defines the amount of extra space, in\r
+         * logical units, to be added to each character. If the current mapping mode is not MM_TEXT,\r
+         * this value is transformed and rounded to the nearest pixel. For details about setting the\r
+         * mapping mode, see META_SETMAPMODE\r
+         */\r
+        int charExtra;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setTextCharExtra;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            charExtra = leis.readUShort();\r
+            return LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * The META_SETTEXTCOLOR record defines the text foreground color in the playback device context.\r
+     */\r
+    public static class WmfSetTextColor implements HwmfRecord {\r
+        \r
+        HwmfColorRef colorRef;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setTextColor;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            colorRef = new HwmfColorRef();\r
+            return colorRef.init(leis);\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * The META_SETTEXTJUSTIFICATION record defines the amount of space to add to break characters\r
+     * in a string of justified text.\r
+     */\r
+    public static class WmfSetTextJustification implements HwmfRecord {\r
+        \r
+        /**\r
+         * A 16-bit unsigned integer that specifies the number of space characters in the line.\r
+         */\r
+        int breakCount;\r
+        \r
+        /**\r
+         * A 16-bit unsigned integer that specifies the total extra space, in logical\r
+         * units, to be added to the line of text. If the current mapping mode is not MM_TEXT, the value\r
+         * identified by the BreakExtra member is transformed and rounded to the nearest pixel. For\r
+         * details about setting the mapping mode, see {@link WmfSetMapMode}.\r
+         */\r
+        int breakExtra;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setBkColor;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            breakCount = leis.readUShort();\r
+            breakExtra = leis.readUShort();\r
+            return 2*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * The META_TEXTOUT record outputs a character string at the specified location by using the font,\r
+     * background color, and text color that are defined in the playback device context.\r
+     */\r
+    public static class WmfTextOut implements HwmfRecord {\r
+        /**\r
+         * A 16-bit signed integer that defines the length of the string, in bytes, pointed to by String.\r
+         */\r
+        int stringLength;\r
+        /**\r
+         * The size of this field MUST be a multiple of two. If StringLength is an odd\r
+         * number, then this field MUST be of a size greater than or equal to StringLength + 1.\r
+         * A variable-length string that specifies the text to be drawn.\r
+         * The string does not need to be null-terminated, because StringLength specifies the\r
+         * length of the string.\r
+         * The string is written at the location specified by the XStart and YStart fields.\r
+         */\r
+        String text;\r
+        /**\r
+         * A 16-bit signed integer that defines the vertical (y-axis) coordinate, in logical\r
+         * units, of the point where drawing is to start.\r
+         */\r
+        int yStart;\r
+        /**\r
+         * A 16-bit signed integer that defines the horizontal (x-axis) coordinate, in\r
+         * logical units, of the point where drawing is to start.\r
+         */\r
+        int xStart;  \r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.textOut;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            stringLength = leis.readShort();\r
+            byte buf[] = new byte[stringLength+(stringLength%2)];\r
+            leis.readFully(buf);\r
+            text = new String(buf, "UTF16-LE").trim();\r
+            yStart = leis.readShort();\r
+            xStart = leis.readShort();\r
+            return 3*LittleEndianConsts.SHORT_SIZE+buf.length;\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * The META_EXTTEXTOUT record outputs text by using the font, background color, and text color that\r
+     * are defined in the playback device context. Optionally, dimensions can be provided for clipping,\r
+     * opaquing, or both.\r
+     */\r
+    public static class WmfExtTextOut implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, where the \r
+        text string is to be located.\r
+         */\r
+        int y;  \r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, where the \r
+        text string is to be located.\r
+         */\r
+        int x;  \r
+        /**\r
+         * A 16-bit signed integer that defines the length of the string.\r
+         */\r
+        int stringLength;\r
+        /**\r
+         * A 16-bit unsigned integer that defines the use of the application-defined \r
+         * rectangle. This member can be a combination of one or more values in the \r
+         * ExtTextOutOptions Flags:\r
+         * \r
+         * ETO_OPAQUE (0x0002):\r
+         * Indicates that the background color that is defined in the playback device context \r
+         * SHOULD be used to fill the rectangle.\r
+         * \r
+         * ETO_CLIPPED (0x0004):\r
+         * Indicates that the text SHOULD be clipped to the rectangle.\r
+         * \r
+         * ETO_GLYPH_INDEX (0x0010):\r
+         * Indicates that the string to be output SHOULD NOT require further processing \r
+         * with respect to the placement of the characters, and an array of character \r
+         * placement values SHOULD be provided. This character placement process is \r
+         * useful for fonts in which diacritical characters affect character spacing.\r
+         * \r
+         * ETO_RTLREADING (0x0080):\r
+         * Indicates that the text MUST be laid out in right-to-left reading order, instead of \r
+         * the default left-to-right order. This SHOULD be applied only when the font that is \r
+         * defined in the playback device context is either Hebrew or Arabic. <37>\r
+         * \r
+         * ETO_NUMERICSLOCAL (0x0400):\r
+         * Indicates that to display numbers, digits appropriate to the locale SHOULD be \r
+         * used.\r
+         * \r
+         * ETO_NUMERICSLATIN (0x0800):\r
+         * Indicates that to display numbers, European digits SHOULD be used. <39>\r
+         * \r
+         * ETO_PDY (0x2000):\r
+         * Indicates that both horizontal and vertical character displacement values \r
+         * SHOULD be provided.\r
+         */\r
+        int fwOpts;\r
+        /**\r
+         * An optional 8-byte Rect Object (section 2.2.2.18) that defines the \r
+         * dimensions, in logical coordinates, of a rectangle that is used for clipping, opaquing, or both.\r
+         * \r
+         * The corners are given in the order left, top, right, bottom.\r
+         * Each value is a 16-bit signed integer that defines the coordinate, in logical coordinates, of \r
+         * the upper-left corner of the rectangle\r
+         */\r
+        int left,top,right,bottom;\r
+        /**\r
+         * A variable-length string that specifies the text to be drawn. The string does \r
+         * not need to be null-terminated, because StringLength specifies the length of the string. If \r
+         * the length is odd, an extra byte is placed after it so that the following member (optional Dx) is \r
+         * aligned on a 16-bit boundary.\r
+         */\r
+        String text;\r
+        /**\r
+         * An optional array of 16-bit signed integers that indicate the distance between \r
+         * origins of adjacent character cells. For example, Dx[i] logical units separate the origins of \r
+         * character cell i and character cell i + 1. If this field is present, there MUST be the same \r
+         * number of values as there are characters in the string.\r
+         */\r
+        int dx[];\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.extTextOut;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            y = leis.readShort();\r
+            x = leis.readShort();\r
+            stringLength = leis.readShort();\r
+            fwOpts = leis.readUShort();\r
+            left = leis.readShort();\r
+            top = leis.readShort();\r
+            right = leis.readShort();\r
+            bottom = leis.readShort();\r
+            \r
+            byte buf[] = new byte[stringLength+(stringLength%2)];\r
+            leis.readFully(buf);\r
+            text = new String(buf, "UTF16-LE");\r
+            \r
+            int size = 8*LittleEndianConsts.SHORT_SIZE+buf.length;\r
+            if (size < recordSize) {\r
+                dx = new int[text.length()];\r
+                for (int i=0; i<dx.length; i++) {\r
+                    dx[i] = leis.readShort();\r
+                }\r
+                size += dx.length*LittleEndianConsts.SHORT_SIZE;\r
+            }\r
+            \r
+            return size;\r
+        }\r
+    }\r
+    \r
+\r
+    \r
+    \r
+    /**\r
+     * The META_SETTEXTALIGN record defines text-alignment values in the playback device context.\r
+     */\r
+    public static class WmfSetTextAlign implements HwmfRecord {\r
+        \r
+        /**\r
+         * A 16-bit unsigned integer that defines text alignment.\r
+         * This value MUST be a combination of one or more TextAlignmentMode Flags\r
+         * for text with a horizontal baseline, and VerticalTextAlignmentMode Flags\r
+         * for text with a vertical baseline.\r
+         * \r
+         * TextAlignmentMode Flags:\r
+         * TA_NOUPDATECP (0x0000):\r
+         * The drawing position in the playback device context MUST NOT be updated after each\r
+         * text output call. The reference point MUST be passed to the text output function.\r
+         * \r
+         * TA_LEFT (0x0000):\r
+         * The reference point MUST be on the left edge of the bounding rectangle.\r
+         * \r
+         * TA_TOP (0x0000):\r
+         * The reference point MUST be on the top edge of the bounding rectangle.\r
+         * \r
+         * TA_UPDATECP (0x0001):\r
+         * The drawing position in the playback device context MUST be updated after each text\r
+         * output call. It MUST be used as the reference point.\r
+         * \r
+         * TA_RIGHT (0x0002):\r
+         * The reference point MUST be on the right edge of the bounding rectangle.\r
+         * \r
+         * TA_CENTER (0x0006):\r
+         * The reference point MUST be aligned horizontally with the center of the bounding\r
+         * rectangle.\r
+         * \r
+         * TA_BOTTOM (0x0008):\r
+         * The reference point MUST be on the bottom edge of the bounding rectangle.\r
+         * \r
+         * TA_BASELINE (0x0018):\r
+         * The reference point MUST be on the baseline of the text.\r
+         * \r
+         * TA_RTLREADING (0x0100):\r
+         * The text MUST be laid out in right-to-left reading order, instead of the default\r
+         * left-toright order. This SHOULD be applied only when the font that is defined in the\r
+         * playback device context is either Hebrew or Arabic.\r
+         * \r
+         * \r
+         * VerticalTextAlignmentMode Flags (e.g. for Kanji fonts)\r
+         * VTA_TOP (0x0000):\r
+         * The reference point MUST be on the top edge of the bounding rectangle.\r
+         * \r
+         * VTA_RIGHT (0x0000):\r
+         * The reference point MUST be on the right edge of the bounding rectangle.\r
+         * \r
+         * VTA_BOTTOM (0x0002):\r
+         * The reference point MUST be on the bottom edge of the bounding rectangle.\r
+         * \r
+         * VTA_CENTER (0x0006):\r
+         * The reference point MUST be aligned vertically with the center of the bounding\r
+         * rectangle.\r
+         * \r
+         * VTA_LEFT (0x0008):\r
+         * The reference point MUST be on the left edge of the bounding rectangle.\r
+         * \r
+         * VTA_BASELINE (0x0018):\r
+         * The reference point MUST be on the baseline of the text.\r
+         */\r
+        int textAlignmentMode;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setTextAlign;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            textAlignmentMode = leis.readUShort();\r
+            return LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+    \r
+    public static class WmfCreateFontIndirect implements HwmfRecord {\r
+        HwmfFont font;\r
+        \r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.createFontIndirect;\r
+        }\r
+        \r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            font = new HwmfFont();\r
+            return font.init(leis);\r
+        }\r
+    }\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java
new file mode 100644 (file)
index 0000000..ee8943b
--- /dev/null
@@ -0,0 +1,549 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+import java.io.IOException;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.apache.poi.util.LittleEndianConsts;\r
+import org.apache.poi.util.LittleEndianInputStream;\r
+\r
+public class HwmfWindowing {\r
+\r
+    /**\r
+     * The META_OFFSETCLIPRGN record moves the clipping region in the playback device context by the\r
+     * specified offsets.\r
+     */\r
+    public static class WmfOffsetClipRgn implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the number of logical units to move up or down.\r
+         */\r
+        int yOffset;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the number of logical units to move left or right.\r
+         */\r
+        int xOffset;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.offsetClipRgn;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            yOffset = leis.readShort();\r
+            xOffset = leis.readShort();\r
+            return 2*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+\r
+    /**\r
+     * The META_SETVIEWPORTORG record defines the viewport origin in the playback device context.\r
+     */\r
+    public static class WmfSetViewportOrg implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the vertical offset, in device units.\r
+         */\r
+        int y;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the horizontal offset, in device units.\r
+         */\r
+        int x;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setViewportOrg;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            y = leis.readShort();\r
+            x = leis.readShort();\r
+            return 2*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_SETVIEWPORTEXT record sets the horizontal and vertical extents\r
+     * of the viewport in the playback device context.\r
+     */\r
+    public static class WmfSetViewportExt implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the vertical extent\r
+         * of the viewport in device units.\r
+         */\r
+        int y;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the horizontal extent\r
+         * of the viewport in device units.\r
+         */\r
+        int x;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setViewportExt;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            y = leis.readShort();\r
+            x = leis.readShort();\r
+            return 2*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_OFFSETVIEWPORTORG record moves the viewport origin in the playback device context\r
+     * by specified horizontal and vertical offsets.\r
+     */\r
+    public static class WmfOffsetViewportOrg implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the vertical offset, in device units.\r
+         */\r
+        int yOffset;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the horizontal offset, in device units.\r
+         */\r
+        int xOffset;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.offsetViewportOrg;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            yOffset = leis.readShort();\r
+            xOffset = leis.readShort();\r
+            return 2*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_SETWINDOWORG record defines the output window origin in the playback device context.\r
+     */\r
+    public static class WmfSetWindowOrg implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units.\r
+         */\r
+        int y;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units.\r
+         */\r
+        int x;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setWindowOrg;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            y = leis.readShort();\r
+            x = leis.readShort();\r
+            return 2*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_SETWINDOWEXT record defines the horizontal and vertical extents\r
+     * of the output window in the playback device context.\r
+     */\r
+    public static class WmfSetWindowExt implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the vertical extent of\r
+         * the window in logical units.\r
+         */\r
+        int y;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the horizontal extent of\r
+         * the window in logical units.\r
+         */\r
+        int x;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setWindowExt;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            y = leis.readShort();\r
+            x = leis.readShort();\r
+            return 2*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_OFFSETWINDOWORG record moves the output window origin in the\r
+     * playback device context by specified horizontal and vertical offsets.\r
+     */\r
+    public static class WmfOffsetWindowOrg implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the vertical offset, in device units.\r
+         */\r
+        int yOffset;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the horizontal offset, in device units.\r
+         */\r
+        int xOffset;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.offsetWindowOrg;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            yOffset = leis.readShort();\r
+            xOffset = leis.readShort();\r
+            return 2*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_OFFSETWINDOWORG record moves the output window origin in the\r
+     * playback device context by specified horizontal and vertical offsets.\r
+     */\r
+    public static class WmfScaleWindowExt implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the amount by which to divide the\r
+         * result of multiplying the current y-extent by the value of the yNum member.\r
+         */\r
+        int yDenom;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the amount by which to multiply the\r
+         * current y-extent.\r
+         */\r
+        int yNum;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the amount by which to divide the\r
+         * result of multiplying the current x-extent by the value of the xNum member.\r
+         */\r
+        int xDenom;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the amount by which to multiply the\r
+         * current x-extent.\r
+         */\r
+        int xNum;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.scaleWindowExt;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            yDenom = leis.readShort();\r
+            yNum = leis.readShort();\r
+            xDenom = leis.readShort();\r
+            xNum = leis.readShort();\r
+            return 4*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+\r
+    /**\r
+     * The META_SCALEVIEWPORTEXT record scales the horizontal and vertical extents of the viewport\r
+     * that is defined in the playback device context by using the ratios formed by the specified\r
+     * multiplicands and divisors.\r
+     */\r
+    public static class WmfScaleViewportExt implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the amount by which to divide the\r
+         * result of multiplying the current y-extent by the value of the yNum member.\r
+         */\r
+        int yDenom;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the amount by which to multiply the\r
+         * current y-extent.\r
+         */\r
+        int yNum;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the amount by which to divide the\r
+         * result of multiplying the current x-extent by the value of the xNum member.\r
+         */\r
+        int xDenom;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the amount by which to multiply the\r
+         * current x-extent.\r
+         */\r
+        int xNum;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.scaleViewportExt;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            yDenom = leis.readShort();\r
+            yNum = leis.readShort();\r
+            xDenom = leis.readShort();\r
+            xNum = leis.readShort();\r
+            return 4*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_EXCLUDECLIPRECT record sets the clipping region in the playback device context to the\r
+     * existing clipping region minus the specified rectangle.\r
+     */\r
+    public static class WmfExcludeClipRect implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
+         * lower-right corner of the rectangle.\r
+         */\r
+        int bottom;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
+         * lower-right corner of the rectangle.\r
+         */\r
+        int right;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
+         * upper-left corner of the rectangle.\r
+         */\r
+        int top;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
+         * upper-left corner of the rectangle.\r
+         */\r
+        int left;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.excludeClipRect;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            bottom = leis.readShort();\r
+            right = leis.readShort();\r
+            top = leis.readShort();\r
+            left = leis.readShort();\r
+            return 4*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+\r
+    /**\r
+     * The META_INTERSECTCLIPRECT record sets the clipping region in the playback device context to the\r
+     * intersection of the existing clipping region and the specified rectangle.\r
+     */\r
+    public static class WmfIntersectClipRect implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
+         * lower-right corner of the rectangle.\r
+         */\r
+        int bottom;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
+         * lower-right corner of the rectangle.\r
+         */\r
+        int right;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
+         * upper-left corner of the rectangle.\r
+         */\r
+        int top;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
+         * upper-left corner of the rectangle.\r
+         */\r
+        int left;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.intersectClipRect;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            bottom = leis.readShort();\r
+            right = leis.readShort();\r
+            top = leis.readShort();\r
+            left = leis.readShort();\r
+            return 4*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_INTERSECTCLIPRECT record sets the clipping region in the playback device context to the\r
+     * intersection of the existing clipping region and the specified rectangle.\r
+     */\r
+    public static class WmfSelectClipRegion implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit unsigned integer used to index into the WMF Object Table to get\r
+         * the region to be clipped.\r
+         */\r
+        int region;\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.selectClipRegion;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            region = leis.readShort();\r
+            return LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+    }\r
+\r
+    public static class WmfScanObject {\r
+        /**\r
+         * A 16-bit unsigned integer that specifies the number of horizontal (x-axis)\r
+         * coordinates in the ScanLines array. This value MUST be a multiple of 2, since left and right\r
+         * endpoints are required to specify each scanline.\r
+         */\r
+        int count;\r
+        /**\r
+         * A 16-bit unsigned integer that defines the vertical (y-axis) coordinate, in logical units, of the top scanline.\r
+         */\r
+        int top;\r
+        /**\r
+         * A 16-bit unsigned integer that defines the vertical (y-axis) coordinate, in logical units, of the bottom scanline.\r
+         */\r
+        int bottom;\r
+        /**\r
+         * A 16-bit unsigned integer that defines the horizontal (x-axis) coordinate,\r
+         * in logical units, of the left endpoint of the scanline.\r
+         */\r
+        int left_scanline[];\r
+        /**\r
+         * A 16-bit unsigned integer that defines the horizontal (x-axis) coordinate,\r
+         * in logical units, of the right endpoint of the scanline.\r
+         */\r
+        int right_scanline[];\r
+        /**\r
+         * A 16-bit unsigned integer that MUST be the same as the value of the Count\r
+         * field; it is present to allow upward travel in the structure.\r
+         */\r
+        int count2;\r
+\r
+        public int init(LittleEndianInputStream leis) {\r
+            count = leis.readUShort();\r
+            top = leis.readUShort();\r
+            bottom = leis.readUShort();\r
+            left_scanline = new int[count];\r
+            right_scanline = new int[count];\r
+            for (int i=0; i*2<count; i++) {\r
+                left_scanline[i] = leis.readUShort();\r
+                right_scanline[i] = leis.readUShort();\r
+            }\r
+            count2 = leis.readUShort();\r
+            return 8 + count*4;\r
+        }\r
+    }\r
+\r
+    public static class WmfCreateRegion implements HwmfRecord {\r
+        /**\r
+         * A 16-bit signed integer. A value that MUST be ignored.\r
+         */\r
+        int nextInChain;\r
+        /**\r
+         * A 16-bit signed integer that specifies the region identifier. It MUST be 0x0006.\r
+         */\r
+        int objectType;\r
+        /**\r
+         * A 32-bit unsigned integer. A value that MUST be ignored.\r
+         */\r
+        int objectCount;\r
+        /**\r
+         * A 16-bit signed integer that defines the size of the region in bytes plus the size of aScans in bytes.\r
+         */\r
+        int regionSize;\r
+        /**\r
+         * A 16-bit signed integer that defines the number of scanlines composing the region.\r
+         */\r
+        int scanCount;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the maximum number of points in any one scan in this region.\r
+         */\r
+        int maxScan;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
+         * lower-right corner of the rectangle.\r
+         */\r
+        int bottom;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
+         * lower-right corner of the rectangle.\r
+         */\r
+        int right;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
+         * upper-left corner of the rectangle.\r
+         */\r
+        int top;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
+         * upper-left corner of the rectangle.\r
+         */\r
+        int left;\r
+\r
+        /**\r
+         * An array of Scan objects that define the scanlines in the region.\r
+         */\r
+        WmfScanObject scanObjects[];\r
+\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.createRegion;\r
+        }\r
+\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            nextInChain = leis.readShort();\r
+            objectType = leis.readShort();\r
+            objectCount = leis.readUShort();\r
+            regionSize = leis.readShort();\r
+            scanCount = leis.readShort();\r
+            maxScan = leis.readShort();\r
+            bottom = leis.readShort();\r
+            right = leis.readShort();\r
+            top = leis.readShort();\r
+            left = leis.readShort();\r
+\r
+            List<WmfScanObject> soList = new ArrayList<WmfScanObject>();\r
+            int scanCountI = 0, size = 0;\r
+            do {\r
+                WmfScanObject so = new WmfScanObject();\r
+                size += so.init(leis);\r
+                scanCountI += so.count;\r
+                soList.add(so);\r
+            } while  (scanCountI < scanCount);\r
+            scanObjects = soList.toArray(new WmfScanObject[soList.size()]);\r
+\r
+            return 20 + size;\r
+        }\r
+    }\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java b/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java
new file mode 100644 (file)
index 0000000..b99b6b0
--- /dev/null
@@ -0,0 +1,75 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.usermodel;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.util.ArrayList;\r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
+import org.apache.poi.hwmf.record.HwmfHeader;\r
+import org.apache.poi.hwmf.record.HwmfPlaceableHeader;\r
+import org.apache.poi.hwmf.record.HwmfRecord;\r
+import org.apache.poi.hwmf.record.HwmfRecordType;\r
+import org.apache.poi.util.LittleEndianInputStream;\r
+\r
+public class HwmfPicture {\r
+    List<HwmfRecord> records = new ArrayList<HwmfRecord>();\r
+    \r
+    public List<HwmfRecord> getRecords() {\r
+        return Collections.unmodifiableList(records);\r
+    }\r
+    \r
+    public HwmfPicture(InputStream inputStream) throws IOException {\r
+        LittleEndianInputStream leis = new LittleEndianInputStream(inputStream);\r
+        HwmfPlaceableHeader placeableHeader = HwmfPlaceableHeader.readHeader(leis);\r
+        HwmfHeader header = new HwmfHeader(leis);\r
+        \r
+        for (;;) {\r
+            // recordSize in DWORDs\r
+            long recordSize = leis.readUInt()*2;\r
+            int recordFunction = leis.readShort();\r
+            // 4 bytes (recordSize) + 2 bytes (recordFunction)\r
+            int consumedSize = 6;\r
+            HwmfRecordType wrt = HwmfRecordType.getById(recordFunction);\r
+            if (wrt == null) {\r
+                throw new IOException("unexpected record type: "+recordFunction);\r
+            }\r
+            if (wrt == HwmfRecordType.eof) break;\r
+            if (wrt.clazz == null) {\r
+                throw new IOException("unsupported record type: "+recordFunction);\r
+            }\r
+            \r
+            HwmfRecord wr;\r
+            try {\r
+                wr = wrt.clazz.newInstance();\r
+                records.add(wr);\r
+            } catch (Exception e) {\r
+                throw (IOException)new IOException("can't create wmf record").initCause(e);\r
+            }\r
+            \r
+            consumedSize += wr.init(leis, recordSize, recordFunction);\r
+            if (consumedSize < recordSize) {\r
+                leis.skip(recordSize - consumedSize);\r
+            }\r
+        }\r
+    }\r
+\r
+\r
+}\r
diff --git a/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java b/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java
new file mode 100644 (file)
index 0000000..ac5d6c0
--- /dev/null
@@ -0,0 +1,42 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf;\r
+\r
+import static org.junit.Assert.assertEquals;\r
+\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.IOException;\r
+import java.util.List;\r
+\r
+import org.apache.poi.POIDataSamples;\r
+import org.apache.poi.hwmf.record.HwmfRecord;\r
+import org.apache.poi.hwmf.usermodel.HwmfPicture;\r
+import org.junit.Test;\r
+\r
+public class TestHwmfParsing {\r
+    @Test\r
+    public void parse() throws IOException {\r
+        File f = POIDataSamples.getSlideShowInstance().getFile("santa.wmf");\r
+        FileInputStream fis = new FileInputStream(f);\r
+        HwmfPicture wmf = new HwmfPicture(fis);\r
+        fis.close();\r
+        List<HwmfRecord> records = wmf.getRecords();\r
+        assertEquals(581, records.size());\r
+    }\r
+}\r