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 <vmik...@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 <vmik...@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 <vmik...@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 <vmik...@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 <vmik...@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 <vmik...@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, _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits