[Libreoffice-commits] mso-dumper.git: 6 commits - msodumper/emfrecord.py msodumper/msodraw.py msodumper/wmfrecord.py

Miklos Vajna vmiklos at collabora.co.uk
Fri Apr 25 13:21:58 PDT 2014


 msodumper/emfrecord.py |  150 +++++++++++++++++++++++++++-
 msodumper/msodraw.py   |   64 +++++++++++
 msodumper/wmfrecord.py |  262 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 471 insertions(+), 5 deletions(-)

New commits:
commit 154a8a3c0cc0cb864fbebc55f13ca8b187214609
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Apr 25 22:19:05 2014 +0200

    dump EmrExtcreatepen

diff --git a/msodumper/emfrecord.py b/msodumper/emfrecord.py
index 2f7a290..6df170a 100644
--- a/msodumper/emfrecord.py
+++ b/msodumper/emfrecord.py
@@ -28,6 +28,29 @@ DIBColors = {
     0x02: "DIB_PAL_INDICES"
 }
 
+# The PenStyle enumeration defines the attributes of pens that can be used in graphics operations.
+PenStyle = {
+    0x00000000: "PS_COSMETIC",
+    0x00000000: "PS_ENDCAP_ROUND",
+    0x00000000: "PS_JOIN_ROUND",
+    0x00000000: "PS_SOLID",
+    0x00000001: "PS_DASH",
+    0x00000002: "PS_DOT",
+    0x00000003: "PS_DASHDOT",
+    0x00000004: "PS_DASHDOTDOT",
+    0x00000005: "PS_NULL",
+    0x00000006: "PS_INSIDEFRAME",
+    0x00000007: "PS_USERSTYLE",
+    0x00000008: "PS_ALTERNATE",
+    0x00000100: "PS_ENDCAP_SQUARE",
+    0x00000200: "PS_ENDCAP_FLAT",
+    0x00001000: "PS_JOIN_BEVEL",
+    0x00002000: "PS_JOIN_MITER",
+    0x00010000: "PS_GEOMETRIC",
+    # Additional combinations
+    0x00010200: "PS_GEOMETRIC, PS_ENDCAP_FLAT",
+}
+
 
 class EMFStream(DOCDirStream):
     def __init__(self, bytes):
@@ -530,6 +553,50 @@ class EmrBitblt(EMFRecord):
         assert self.pos - posOrig == self.Size
 
 
+class LogPenEx(EMFRecord):
+    """The LogPenEx object specifies the style, width, and color of an extended logical pen."""
+    def __init__(self, parent, name):
+        EMFRecord.__init__(self, parent)
+        self.name = name
+
+    def dump(self):
+        print '<%s type="LogPenEx">' % self.name
+        self.printAndSet("PenStyle", self.readuInt32(), dict=PenStyle)
+        self.printAndSet("Width", self.readuInt32())
+        self.printAndSet("BrushStyle", self.readuInt32(), dict=wmfrecord.BrushStyle)
+        wmfrecord.ColorRef(self, "ColorRef").dump()
+        if self.BrushStyle == 0x0002:  # "BS_HATCHED"
+            self.printAndSet("BrushHatch", self.readuInt32(), dict=wmfrecord.HatchStyle)
+        else:
+            self.printAndSet("BrushHatch", self.readuInt32())
+        self.printAndSet("NumStyleEntries", self.readuInt32())
+        if self.NumStyleEntries > 0:
+            print '<todo what="LogPenEx::dump(): self.NumStyleEntries != 0"/>'
+        print '</%s>' % self.name
+        self.parent.pos = self.pos
+
+
+class EmrExtcreatepen(EMFRecord):
+    """Defines an extended logical pen."""
+    def __init__(self, parent):
+        EMFRecord.__init__(self, parent)
+
+    def dump(self):
+        posOrig = self.pos
+        self.printAndSet("Type", self.readuInt32())
+        self.printAndSet("Size", self.readuInt32(), hexdump=False)
+        self.printAndSet("ihPen", self.readuInt32(), hexdump=False)
+        self.printAndSet("offBmi", self.readuInt32(), hexdump=False)
+        self.printAndSet("cbBmi", self.readuInt32(), hexdump=False)
+        self.printAndSet("offBits", self.readuInt32(), hexdump=False)
+        self.printAndSet("cbBits", self.readuInt32(), hexdump=False)
+        LogPenEx(self, "elp").dump()
+        if self.cbBmi:
+            print '<todo what="LogPenEx::dump(): self.cbBmi != 0"/>'
+        if self.cbBits:
+            print '<todo what="LogPenEx::dump(): self.cbBits != 0"/>'
+
+
 class EmrEof(EMFRecord):
     """Indicates the end of the metafile and specifies a palette."""
     def __init__(self, parent):
@@ -747,7 +814,7 @@ RecordType = {
     0x0000005C: ['EMR_POLYDRAW16'],
     0x0000005D: ['EMR_CREATEMONOBRUSH'],
     0x0000005E: ['EMR_CREATEDIBPATTERNBRUSHPT'],
-    0x0000005F: ['EMR_EXTCREATEPEN'],
+    0x0000005F: ['EMR_EXTCREATEPEN', EmrExtcreatepen],
     0x00000060: ['EMR_POLYTEXTOUTA'],
     0x00000061: ['EMR_POLYTEXTOUTW'],
     0x00000062: ['EMR_SETICMMODE', EmrSeticmmode],
commit 98ba933a00f93421dc705c144a846c704c2722ad
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Apr 25 21:48:57 2014 +0200

    dump EmrBitblt

diff --git a/msodumper/emfrecord.py b/msodumper/emfrecord.py
index 55eb34c..2f7a290 100644
--- a/msodumper/emfrecord.py
+++ b/msodumper/emfrecord.py
@@ -22,6 +22,12 @@ RegionMode = {
     0x05: "RGN_COPY"
 }
 
+DIBColors = {
+    0x00: "DIB_RGB_COLORS",
+    0x01: "DIB_PAL_COLORS",
+    0x02: "DIB_PAL_INDICES"
+}
+
 
 class EMFStream(DOCDirStream):
     def __init__(self, bytes):
@@ -497,6 +503,33 @@ class EmrStrokeandfillpath(EMFRecord):
         assert self.pos - posOrig == self.Size
 
 
+class EmrBitblt(EMFRecord):
+    """Specifies a block transfer of pixels from a source bitmap to a destination rectangle."""
+    def __init__(self, parent):
+        EMFRecord.__init__(self, parent)
+
+    def dump(self):
+        posOrig = self.pos
+        self.printAndSet("Type", self.readuInt32())
+        self.printAndSet("Size", self.readuInt32(), hexdump=False)
+        wmfrecord.RectL(self, "Bounds").dump()
+        self.printAndSet("xDest", self.readInt32(), hexdump=False)
+        self.printAndSet("yDest", self.readInt32(), hexdump=False)
+        self.printAndSet("cxDest", self.readInt32(), hexdump=False)
+        self.printAndSet("cyDest", self.readInt32(), hexdump=False)
+        self.printAndSet("BitBltRasterOperation", self.readuInt32(), dict=wmfrecord.RasterPolishMap)
+        self.printAndSet("xSrc", self.readInt32(), hexdump=False)
+        self.printAndSet("ySrc", self.readInt32(), hexdump=False)
+        XForm(self, "XformSrc").dump()
+        wmfrecord.ColorRef(self, "BkColorSrc").dump()
+        self.printAndSet("UsageSrc", self.readInt32(), dict=DIBColors)
+        self.printAndSet("offBmiSrc", self.readuInt32())
+        self.printAndSet("cbBmiSrc", self.readuInt32())
+        self.printAndSet("offBitsSrc", self.readuInt32())
+        self.printAndSet("cbBitsSrc", self.readuInt32())
+        assert self.pos - posOrig == self.Size
+
+
 class EmrEof(EMFRecord):
     """Indicates the end of the metafile and specifies a palette."""
     def __init__(self, parent):
@@ -695,7 +728,7 @@ RecordType = {
     0x00000049: ['EMR_INVERTRGN'],
     0x0000004A: ['EMR_PAINTRGN'],
     0x0000004B: ['EMR_EXTSELECTCLIPRGN', EmrExtselectcliprgn],
-    0x0000004C: ['EMR_BITBLT'],
+    0x0000004C: ['EMR_BITBLT', EmrBitblt],
     0x0000004D: ['EMR_STRETCHBLT'],
     0x0000004E: ['EMR_MASKBLT'],
     0x0000004F: ['EMR_PLGBLT'],
diff --git a/msodumper/wmfrecord.py b/msodumper/wmfrecord.py
index dd4e8ea..5b23e35 100644
--- a/msodumper/wmfrecord.py
+++ b/msodumper/wmfrecord.py
@@ -34,6 +34,268 @@ HatchStyle = {
 }
 
 
+# No idea what's the proper name of this thing, see
+# http://msdn.microsoft.com/en-us/library/dd145130%28VS.85%29.aspx
+RasterPolishMap = {
+    0x00000042: "0",
+    0x00010289: "DPSoon",
+    0x00020C89: "DPSona",
+    0x000300AA: "PSon",
+    0x00040C88: "SDPona",
+    0x000500A9: "DPon",
+    0x00060865: "PDSxnon",
+    0x000702C5: "PDSaon",
+    0x00080F08: "SDPnaa",
+    0x00090245: "PDSxon",
+    0x000A0329: "DPna",
+    0x000B0B2A: "PSDnaon",
+    0x000C0324: "SPna",
+    0x000D0B25: "PDSnaon",
+    0x000E08A5: "PDSonon",
+    0x000F0001: "Pn",
+    0x00100C85: "PDSona",
+    0x001100A6: "DSon",
+    0x00120868: "SDPxnon",
+    0x001302C8: "SDPaon",
+    0x00140869: "DPSxnon",
+    0x001502C9: "DPSaon",
+    0x00165CCA: "PSDPSanaxx",
+    0x00171D54: "SSPxDSxaxn",
+    0x00180D59: "SPxPDxa",
+    0x00191CC8: "SDPSanaxn",
+    0x001A06C5: "PDSPaox",
+    0x001B0768: "SDPSxaxn",
+    0x001C06CA: "PSDPaox",
+    0x001D0766: "DSPDxaxn",
+    0x001E01A5: "PDSox",
+    0x001F0385: "PDSoan",
+    0x00200F09: "DPSnaa",
+    0x00210248: "SDPxon",
+    0x00220326: "DSna",
+    0x00230B24: "SPDnaon",
+    0x00240D55: "SPxDSxa",
+    0x00251CC5: "PDSPanaxn",
+    0x002606C8: "SDPSaox",
+    0x00271868: "SDPSxnox",
+    0x00280369: "DPSxa",
+    0x002916CA: "PSDPSaoxxn",
+    0x002A0CC9: "DPSana",
+    0x002B1D58: "SSPxPDxaxn",
+    0x002C0784: "SPDSoax",
+    0x002D060A: "PSDnox",
+    0x002E064A: "PSDPxox",
+    0x002F0E2A: "PSDnoan",
+    0x0030032A: "PSna",
+    0x00310B28: "SDPnaon",
+    0x00320688: "SDPSoox",
+    0x00330008: "Sn",
+    0x003406C4: "SPDSaox",
+    0x00351864: "SPDSxnox",
+    0x003601A8: "SDPox",
+    0x00370388: "SDPoan",
+    0x0038078A: "PSDPoax",
+    0x00390604: "SPDnox",
+    0x003A0644: "SPDSxox",
+    0x003B0E24: "SPDnoan",
+    0x003C004A: "PSx",
+    0x003D18A4: "SPDSonox",
+    0x003E1B24: "SPDSnaox",
+    0x003F00EA: "PSan",
+    0x00400F0A: "PSDnaa",
+    0x00410249: "DPSxon",
+    0x00420D5D: "SDxPDxa",
+    0x00431CC4: "SPDSanaxn",
+    0x00440328: "SDna",
+    0x00450B29: "DPSnaon",
+    0x004606C6: "DSPDaox",
+    0x0047076A: "PSDPxaxn",
+    0x00480368: "SDPxa",
+    0x004916C5: "PDSPDaoxxn",
+    0x004A0789: "DPSDoax",
+    0x004B0605: "PDSnox",
+    0x004C0CC8: "SDPana",
+    0x004D1954: "SSPxDSxoxn",
+    0x004E0645: "PDSPxox",
+    0x004F0E25: "PDSnoan",
+    0x00500325: "PDna",
+    0x00510B26: "DSPnaon",
+    0x005206C9: "DPSDaox",
+    0x00530764: "SPDSxaxn",
+    0x005408A9: "DPSonon",
+    0x00550009: "Dn",
+    0x005601A9: "DPSox",
+    0x00570389: "DPSoan",
+    0x00580785: "PDSPoax",
+    0x00590609: "DPSnox",
+    0x005A0049: "DPx",
+    0x005B18A9: "DPSDonox",
+    0x005C0649: "DPSDxox",
+    0x005D0E29: "DPSnoan",
+    0x005E1B29: "DPSDnaox",
+    0x005F00E9: "DPan",
+    0x00600365: "PDSxa",
+    0x006116C6: "DSPDSaoxxn",
+    0x00620786: "DSPDoax",
+    0x00630608: "SDPnox",
+    0x00640788: "SDPSoax",
+    0x00650606: "DSPnox",
+    0x00660046: "DSx",
+    0x006718A8: "SDPSonox",
+    0x006858A6: "DSPDSonoxxn",
+    0x00690145: "PDSxxn",
+    0x006A01E9: "DPSax",
+    0x006B178A: "PSDPSoaxxn",
+    0x006C01E8: "SDPax",
+    0x006D1785: "PDSPDoaxxn",
+    0x006E1E28: "SDPSnoax",
+    0x006F0C65: "PDSxnan",
+    0x00700CC5: "PDSana",
+    0x00711D5C: "SSDxPDxaxn",
+    0x00720648: "SDPSxox",
+    0x00730E28: "SDPnoan",
+    0x00740646: "DSPDxox",
+    0x00750E26: "DSPnoan",
+    0x00761B28: "SDPSnaox",
+    0x007700E6: "DSan",
+    0x007801E5: "PDSax",
+    0x00791786: "DSPDSoaxxn",
+    0x007A1E29: "DPSDnoax",
+    0x007B0C68: "SDPxnan",
+    0x007C1E24: "SPDSnoax",
+    0x007D0C69: "DPSxnan",
+    0x007E0955: "SPxDSxo",
+    0x007F03C9: "DPSaan",
+    0x008003E9: "DPSaa",
+    0x00810975: "SPxDSxon",
+    0x00820C49: "DPSxna",
+    0x00831E04: "SPDSnoaxn",
+    0x00840C48: "SDPxna",
+    0x00851E05: "PDSPnoaxn",
+    0x008617A6: "DSPDSoaxx",
+    0x008701C5: "PDSaxn",
+    0x008800C6: "DSa",
+    0x00891B08: "SDPSnaoxn",
+    0x008A0E06: "DSPnoa",
+    0x008B0666: "DSPDxoxn",
+    0x008C0E08: "SDPnoa",
+    0x008D0668: "SDPSxoxn",
+    0x008E1D7C: "SSDxPDxax",
+    0x008F0CE5: "PDSanan",
+    0x00900C45: "PDSxna",
+    0x00911E08: "SDPSnoaxn",
+    0x009217A9: "DPSDPoaxx",
+    0x009301C4: "SPDaxn",
+    0x009417AA: "PSDPSoaxx",
+    0x009501C9: "DPSaxn",
+    0x00960169: "DPSxx",
+    0x0097588A: "PSDPSonoxx",
+    0x00981888: "SDPSonoxn",
+    0x00990066: "DSxn",
+    0x009A0709: "DPSnax",
+    0x009B07A8: "SDPSoaxn",
+    0x009C0704: "SPDnax",
+    0x009D07A6: "DSPDoaxn",
+    0x009E16E6: "DSPDSaoxx",
+    0x009F0345: "PDSxan",
+    0x00A000C9: "DPa",
+    0x00A11B05: "PDSPnaoxn",
+    0x00A20E09: "DPSnoa",
+    0x00A30669: "DPSDxoxn",
+    0x00A41885: "PDSPonoxn",
+    0x00A50065: "PDxn",
+    0x00A60706: "DSPnax",
+    0x00A707A5: "PDSPoaxn",
+    0x00A803A9: "DPSoa",
+    0x00A90189: "DPSoxn",
+    0x00AA0029: "D",
+    0x00AB0889: "DPSono",
+    0x00AC0744: "SPDSxax",
+    0x00AD06E9: "DPSDaoxn",
+    0x00AE0B06: "DSPnao",
+    0x00AF0229: "DPno",
+    0x00B00E05: "PDSnoa",
+    0x00B10665: "PDSPxoxn",
+    0x00B21974: "SSPxDSxox",
+    0x00B30CE8: "SDPanan",
+    0x00B4070A: "PSDnax",
+    0x00B507A9: "DPSDoaxn",
+    0x00B616E9: "DPSDPaoxx",
+    0x00B70348: "SDPxan",
+    0x00B8074A: "PSDPxax",
+    0x00B906E6: "DSPDaoxn",
+    0x00BA0B09: "DPSnao",
+    0x00BB0226: "DSno",
+    0x00BC1CE4: "SPDSanax",
+    0x00BD0D7D: "SDxPDxan",
+    0x00BE0269: "DPSxo",
+    0x00BF08C9: "DPSano",
+    0x00C000CA: "PSa",
+    0x00C11B04: "SPDSnaoxn",
+    0x00C21884: "SPDSonoxn",
+    0x00C3006A: "PSxn",
+    0x00C40E04: "SPDnoa",
+    0x00C50664: "SPDSxoxn",
+    0x00C60708: "SDPnax",
+    0x00C707AA: "PSDPoaxn",
+    0x00C803A8: "SDPoa",
+    0x00C90184: "SPDoxn",
+    0x00CA0749: "DPSDxax",
+    0x00CB06E4: "SPDSaoxn",
+    0x00CC0020: "S",
+    0x00CD0888: "SDPono",
+    0x00CE0B08: "SDPnao",
+    0x00CF0224: "SPno",
+    0x00D00E0A: "PSDnoa",
+    0x00D1066A: "PSDPxoxn",
+    0x00D20705: "PDSnax",
+    0x00D307A4: "SPDSoaxn",
+    0x00D41D78: "SSPxPDxax",
+    0x00D50CE9: "DPSanan",
+    0x00D616EA: "PSDPSaoxx",
+    0x00D70349: "DPSxan",
+    0x00D80745: "PDSPxax",
+    0x00D906E8: "SDPSaoxn",
+    0x00DA1CE9: "DPSDanax",
+    0x00DB0D75: "SPxDSxan",
+    0x00DC0B04: "SPDnao",
+    0x00DD0228: "SDno",
+    0x00DE0268: "SDPxo",
+    0x00DF08C8: "SDPano",
+    0x00E003A5: "PDSoa",
+    0x00E10185: "PDSoxn",
+    0x00E20746: "DSPDxax",
+    0x00E306EA: "PSDPaoxn",
+    0x00E40748: "SDPSxax",
+    0x00E506E5: "PDSPaoxn",
+    0x00E61CE8: "SDPSanax",
+    0x00E70D79: "SPxPDxan",
+    0x00E81D74: "SSPxDSxax",
+    0x00E95CE6: "DSPDSanaxxn",
+    0x00EA02E9: "DPSao",
+    0x00EB0849: "DPSxno",
+    0x00EC02E8: "SDPao",
+    0x00ED0848: "SDPxno",
+    0x00EE0086: "DSo",
+    0x00EF0A08: "SDPnoo",
+    0x00F00021: "P",
+    0x00F10885: "PDSono",
+    0x00F20B05: "PDSnao",
+    0x00F3022A: "PSno",
+    0x00F40B0A: "PSDnao",
+    0x00F50225: "PDno",
+    0x00F60265: "PDSxo",
+    0x00F708C5: "PDSano",
+    0x00F802E5: "PDSao",
+    0x00F90845: "PDSxno",
+    0x00FA0089: "DPo",
+    0x00FB0A09: "DPSnoo",
+    0x00FC008A: "PSo",
+    0x00FD0A0A: "PSDnoo",
+    0x00FE02A9: "DPSoo",
+    0x00FF0062: "1"
+}
+
+
 class WMFRecord(DOCDirStream):
     def __init__(self, parent):
         DOCDirStream.__init__(self, parent.bytes)
commit 20ca1d9b734f333d00066724fb5488dfa8b06d40
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Apr 25 16:04:15 2014 +0200

    dump EmrStrokeandfillpath

diff --git a/msodumper/emfrecord.py b/msodumper/emfrecord.py
index 56455e9..55eb34c 100644
--- a/msodumper/emfrecord.py
+++ b/msodumper/emfrecord.py
@@ -483,6 +483,20 @@ class EmrFillpath(EMFRecord):
         assert self.pos - posOrig == self.Size
 
 
+class EmrStrokeandfillpath(EMFRecord):
+    """The EMR_STROKEANDFILLPATH record closes any open figures in a path, strokes the outline of the
+    path by using the current pen, and fills its interior by using the current brush."""
+    def __init__(self, parent):
+        EMFRecord.__init__(self, parent)
+
+    def dump(self):
+        posOrig = self.pos
+        self.printAndSet("Type", self.readuInt32())
+        self.printAndSet("Size", self.readuInt32(), hexdump=False)
+        wmfrecord.RectL(self, "Bounds").dump()
+        assert self.pos - posOrig == self.Size
+
+
 class EmrEof(EMFRecord):
     """Indicates the end of the metafile and specifies a palette."""
     def __init__(self, parent):
@@ -669,7 +683,7 @@ RecordType = {
     0x0000003C: ['EMR_ENDPATH', EmrEndpath],
     0x0000003D: ['EMR_CLOSEFIGURE', EmrClosefigure],
     0x0000003E: ['EMR_FILLPATH', EmrFillpath],
-    0x0000003F: ['EMR_STROKEANDFILLPATH'],
+    0x0000003F: ['EMR_STROKEANDFILLPATH', EmrStrokeandfillpath],
     0x00000040: ['EMR_STROKEPATH'],
     0x00000041: ['EMR_FLATTENPATH'],
     0x00000042: ['EMR_WIDENPATH'],
commit 608069a6b41ca7608bc026aa8647b04c8f5dc078
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Apr 25 16:01:30 2014 +0200

    dump EmrFillpath

diff --git a/msodumper/emfrecord.py b/msodumper/emfrecord.py
index 36c9f52..56455e9 100644
--- a/msodumper/emfrecord.py
+++ b/msodumper/emfrecord.py
@@ -469,6 +469,20 @@ class EmrClosefigure(EMFRecord):
         assert self.pos - posOrig == self.Size
 
 
+class EmrFillpath(EMFRecord):
+    """Closes any open figures in the current path and fills the path's
+    interior with the current brush and polygon-filling mode."""
+    def __init__(self, parent):
+        EMFRecord.__init__(self, parent)
+
+    def dump(self):
+        posOrig = self.pos
+        self.printAndSet("Type", self.readuInt32())
+        self.printAndSet("Size", self.readuInt32(), hexdump=False)
+        wmfrecord.RectL(self, "Bounds").dump()
+        assert self.pos - posOrig == self.Size
+
+
 class EmrEof(EMFRecord):
     """Indicates the end of the metafile and specifies a palette."""
     def __init__(self, parent):
@@ -654,7 +668,7 @@ RecordType = {
     0x0000003B: ['EMR_BEGINPATH', EmrBeginpath],
     0x0000003C: ['EMR_ENDPATH', EmrEndpath],
     0x0000003D: ['EMR_CLOSEFIGURE', EmrClosefigure],
-    0x0000003E: ['EMR_FILLPATH'],
+    0x0000003E: ['EMR_FILLPATH', EmrFillpath],
     0x0000003F: ['EMR_STROKEANDFILLPATH'],
     0x00000040: ['EMR_STROKEPATH'],
     0x00000041: ['EMR_FLATTENPATH'],
commit c690ade6318e568fc051771d29870286888408e7
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Apr 25 15:59:12 2014 +0200

    dump EmrClosefigure

diff --git a/msodumper/emfrecord.py b/msodumper/emfrecord.py
index 68ad15b..36c9f52 100644
--- a/msodumper/emfrecord.py
+++ b/msodumper/emfrecord.py
@@ -457,6 +457,18 @@ class EmrEndpath(EMFRecord):
         assert self.pos - posOrig == self.Size
 
 
+class EmrClosefigure(EMFRecord):
+    """This record closes an open figure in a path."""
+    def __init__(self, parent):
+        EMFRecord.__init__(self, parent)
+
+    def dump(self):
+        posOrig = self.pos
+        self.printAndSet("Type", self.readuInt32())
+        self.printAndSet("Size", self.readuInt32(), hexdump=False)
+        assert self.pos - posOrig == self.Size
+
+
 class EmrEof(EMFRecord):
     """Indicates the end of the metafile and specifies a palette."""
     def __init__(self, parent):
@@ -641,7 +653,7 @@ RecordType = {
     0x0000003A: ['EMR_SETMITERLIMIT'],
     0x0000003B: ['EMR_BEGINPATH', EmrBeginpath],
     0x0000003C: ['EMR_ENDPATH', EmrEndpath],
-    0x0000003D: ['EMR_CLOSEFIGURE'],
+    0x0000003D: ['EMR_CLOSEFIGURE', EmrClosefigure],
     0x0000003E: ['EMR_FILLPATH'],
     0x0000003F: ['EMR_STROKEANDFILLPATH'],
     0x00000040: ['EMR_STROKEPATH'],
commit dcf267f84f3cd325fddd0f143a751d415c79b265
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Apr 25 15:44:21 2014 +0200

    msodraw: dump BlipEMF
    
    Not connected to the EMF dumper yet, just provide the raw data as a
    base64 dump.

diff --git a/msodumper/msodraw.py b/msodumper/msodraw.py
index 0b4f99a..cfaf245 100644
--- a/msodumper/msodraw.py
+++ b/msodumper/msodraw.py
@@ -7,6 +7,9 @@
 
 import globals, xlsmodel
 import sys
+import textwrap
+import zlib
+import base64
 from pptrecord import shapeTypes
 
 def indent (level):
@@ -33,6 +36,9 @@ def hexdump(value):
         ret.append("%02x" % ord(i))
     return "".join(ret)
 
+def inflate(bytes):
+    return textwrap.fill(base64.b64encode(zlib.decompress(bytes)), width=160)
+
 class RecordHeader:
 
     size = 8
@@ -54,6 +60,7 @@ class RecordHeader:
         FClientAnchor           = 0xF010
         FClientData             = 0xF011
         FConnectorRule          = 0xF012
+        BlipEMF                 = 0xF01A
         BlipPNG                 = 0xF01E
         FDGSL                   = 0xF119
         SplitMenuColorContainer = 0xF11E
@@ -291,6 +298,62 @@ class FDGSL:
         for shape in self.shapesSelected:
             recHdl.appendLine("  ID of shape selected: %d"%shape)
 
+class MetafileHeader:
+    """[MS-ODRAW] 2.2.31 The OfficeArtMetafileHeader record specifies how to process a metafile."""
+    def __init__(self, strm):
+        self.strm = strm
+
+    def parseBytes(self, rh):
+        self.cbSize = self.strm.readUnsignedInt(4)
+        self.strm.readBytes(16) # TODO rcBounds
+        self.strm.readBytes(8) # TODO ptSize
+        self.cbSave = self.strm.readUnsignedInt(4)
+        self.compression = self.strm.readUnsignedInt(1)
+        self.filter = self.strm.readUnsignedInt(1)
+
+    def appendLines(self, recHdl, rh):
+        pass
+
+    def dumpXml(self, recHdl, model, rh):
+        recHdl.appendLine('<metafileHeader type="OfficeArtMetafileHeader">')
+        recHdl.appendLine('<cbSize value="%s"/>' % self.cbSize)
+        recHdl.appendLine('<cbSave value="%s"/>' % self.cbSave)
+        recHdl.appendLine('<compression value="%s"/>' % hex(self.compression))
+        recHdl.appendLine('<filter value="%s"/>' % hex(self.filter))
+        recHdl.appendLine('</metafileHeader>')
+
+class BlipEMF:
+    """[MS-ODRAW] 2.2.24 The OfficeArtBlipEMF record specifies BLIP file data for the enhanced metafile format (EMF)."""
+    def __init__(self, strm):
+        self.strm = strm
+
+    def __parseBytes(self, rh):
+        pos = self.strm.pos
+        self.rgbUid1 = self.strm.readBytes(16)
+        if rh.recInstance == 0x3D5:
+            self.rgbUid2 = self.strm.readBytes(16)
+        else:
+            self.rgbUid2 = None
+        self.metafileHeader = MetafileHeader(self.strm)
+        self.metafileHeader.parseBytes(rh)
+        self.BLIPFileData = self.strm.readBytes(self.metafileHeader.cbSave)
+
+    def appendLines(self, recHdl, rh):
+        pass
+
+    def dumpXml(self, recHdl, model, rh):
+        recHdl.appendLine('<blipEmf type="OfficeArtBlipEMF">')
+        self.__parseBytes(rh)
+        recHdl.appendLine('<rgbUid1 value="%s"/>' % hexdump(self.rgbUid1))
+        if self.rgbUid2:
+            recHdl.appendLine('<rgbUid2 value="%s"/>' % hexdump(self.rgbUid2))
+        self.metafileHeader.dumpXml(recHdl, model, rh)
+        if self.metafileHeader.compression == 0x00:
+            recHdl.appendLine('<BLIPFileData value="%s"/>' % inflate(self.BLIPFileData))
+        else:
+            recHdl.appendLine('<todo what="BlipEMF::dumpXml(): unexpected metafileHeader.compression == %s"/>' % hex(self.metafileHeader.compression))
+        recHdl.appendLine('</blipEmf>')
+
 class BlipPNG:
     def __init__(self, strm):
         self.strm = strm
@@ -1286,6 +1349,7 @@ recData = {
     RecordHeader.Type.FConnectorRule: FConnectorRule,
     RecordHeader.Type.FDGSL: FDGSL,
     RecordHeader.Type.BlipPNG: BlipPNG,
+    RecordHeader.Type.BlipEMF: BlipEMF,
     RecordHeader.Type.FClientAnchor: FClientAnchorSheet,
     RecordHeader.Type.FClientData: FClientData,
     RecordHeader.Type.FClientTextbox: FClientTextbox,


More information about the Libreoffice-commits mailing list