summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHossein <hossein@libreoffice.org>2021-09-20 01:18:20 +0200
committerHossein <hossein@libreoffice.org>2021-09-20 01:26:04 +0200
commitb88b38cef5e42137edf8441325765a8ac35aa8c3 (patch)
tree1282a81bea0c6feadec3dfbf4ce1bb2b0d904b1b
parentdb25622001241fda6f2a1c3a1cdff4bc79c6b65e (diff)
Added dump() for 17 wmf records in wmf-dump.py
Added dump() for 17 wmf records to complete the support for test/wmf/pass/tdf88163.wmf file in wmf-dump.py. 58 records of wmf still need dump(). List of records: 1. SetMapMode 2. SetPolyFillMode 3. SetTextColor 4. SetBkColor 5. MoveTo 6. Polygon 7. SetWindowOrg 8. SetWindowExt 9. TextOut 10. PolyPolygon 11. SelectObject 12. DeleteObject 13. PenRecord 14. CreatePenIndirect 15. LogBrush 16. CreateBrushIndirect 17. EndOfFile Change-Id: I1a3d2c30aa6bba01891662b8641a1213d3f5d16f Reviewed-on: https://gerrit.libreoffice.org/c/mso-dumper/+/122333 Tested-by: Hossein <hossein@libreoffice.org> Reviewed-by: Hossein <hossein@libreoffice.org>
-rw-r--r--msodumper/wmfrecord.py345
1 files changed, 291 insertions, 54 deletions
diff --git a/msodumper/wmfrecord.py b/msodumper/wmfrecord.py
index cdc0581..272ba79 100644
--- a/msodumper/wmfrecord.py
+++ b/msodumper/wmfrecord.py
@@ -265,6 +265,17 @@ PaletteEntryFlag = {
0x04: "PC_NOCOLLAPSE",
}
+PitchFont = {
+ 0: "DEFAULT_PITCH",
+ 1: "FIXED_PITCH",
+ 2: "VARIABLE_PITCH",
+}
+
+PolyFillMode = {
+ 0x0001: "ALTERNATE",
+ 0x0002: "WINDING",
+}
+
PostScriptCap = {
-2: "PostScriptNotSet",
0: "PostScriptFlatCap",
@@ -567,6 +578,26 @@ RasterPolishMap = {
}
+PenStyle = {
+ 0x0000: "PS_COSMETIC",
+ 0x0000: "PS_ENDCAP_ROUND",
+ 0x0000: "PS_JOIN_ROUND",
+ 0x0000: "PS_SOLID",
+ 0x0001: "PS_DASH",
+ 0x0002: "PS_DOT",
+ 0x0003: "PS_DASHDOT",
+ 0x0004: "PS_DASHDOTDOT",
+ 0x0005: "PS_NULL",
+ 0x0006: "PS_INSIDEFRAME",
+ 0x0007: "PS_USERSTYLE",
+ 0x0008: "PS_ALTERNATE",
+ 0x0100: "PS_ENDCAP_SQUARE",
+ 0x0200: "PS_ENDCAP_FLAT",
+ 0x1000: "PS_JOIN_BEVEL",
+ 0x2000: "PS_JOIN_MITER",
+}
+
+
class WMFStream(BinaryStream):
def __init__(self, bytes):
BinaryStream.__init__(self, bytes)
@@ -776,7 +807,7 @@ class PlaceableHeader(WMFRecord):
self.printAndSet("HWmf", self.readuInt16())
Rect(self, "BoundingBox").dump()
self.printAndSet("Inch", self.readuInt16(), hexdump=False)
- self.printAndSet("Reserved", self.readuInt32())
+ self.printAndSet("Reserved", self.readuInt32(), hexdump=False)
self.printAndSet("Checksum", self.readuInt16())
assert self.pos == dataPos + self.Size
self.parent.pos = self.pos
@@ -834,7 +865,6 @@ class SetBkMode(WMFRecord):
self.name = "setbkmode"
def dump(self):
- pass
dataPos = self.pos
print('<%s type="SetBkMode">' % self.name)
self.printAndSet("RecordSize", self.readuInt32(), hexdump=False)
@@ -848,12 +878,22 @@ class SetBkMode(WMFRecord):
class SetMapMode(WMFRecord):
- def __init__(self, parent):
+ """The META_SETMAPMODE record is used to define the mapping mode in the playback device context."""
+ def __init__(self, parent, name=None):
WMFRecord.__init__(self, parent)
+ if name:
+ self.name = name
+ else:
+ self.name = "selectobject"
def dump(self):
- print("<todo/>")
- pass
+ dataPos = self.pos
+ print('<%s type="SetTextAlign">' % self.name)
+ self.printAndSet("RecordSize", self.readuInt32(), hexdump=False)
+ self.printAndSet("RecordFunction", self.readuInt16(), hexdump=True)
+ self.printAndSet("MapMode", self.readuInt16(), hexdump=False)
+ print('</%s>' % self.name)
+ assert self.pos == dataPos + self.RecordSize * 2
class SetROP2(WMFRecord):
@@ -875,12 +915,24 @@ class SetRelAbs(WMFRecord):
class SetPolyFillMode(WMFRecord):
- def __init__(self, parent):
+ def __init__(self, parent, name=None):
WMFRecord.__init__(self, parent)
+ if name:
+ self.name = name
+ else:
+ self.name = "setpolyfillmode"
def dump(self):
- print("<todo/>")
- pass
+ dataPos = self.pos
+ print('<%s type="SetPolyFillMode">' % self.name)
+ self.printAndSet("RecordSize", self.readuInt32(), hexdump=False)
+ self.printAndSet("RecordFunction", self.readuInt16(), hexdump=True)
+ self.printAndSet("PolyFillMode", self.readuInt16(), dict=PolyFillMode)
+ # Check optional reserved value if the size shows that it exists
+ if self.RecordSize == 5:
+ self.printAndSet("Reserved", self.readuInt16(), hexdump=False)
+ print('</%s>' % self.name)
+ assert self.pos == dataPos + self.RecordSize * 2
class SetStretchBltMode(WMFRecord):
@@ -937,40 +989,62 @@ class SetLayout(WMFRecord):
pass
-class SetTextColor(WMFRecord):
- def __init__(self, parent):
- WMFRecord.__init__(self, parent)
-
- def dump(self):
- print("<todo/>")
- pass
-
-
class SetBkColor(WMFRecord):
- def __init__(self, parent):
+ """The META_SETBKCOLOR record is used to set the background color. If the specified color
+ is not possible in the device, the nearest physical color is used."""
+ def __init__(self, parent, name=None):
WMFRecord.__init__(self, parent)
+ if name:
+ self.name = name
+ else:
+ self.name = "setbkcolor"
def dump(self):
- print("<todo/>")
pass
+ dataPos = self.pos
+ print('<%s type="SetBkColor">' % self.name)
+ self.printAndSet("RecordSize", self.readuInt32(), hexdump=False)
+ self.printAndSet("RecordFunction", self.readuInt16(), hexdump=True)
+ ColorRef(self, "ColorRef").dump()
+ print('</%s>' % self.name)
+ assert self.pos == dataPos + self.RecordSize * 2
class SetTextColor(WMFRecord):
- def __init__(self, parent):
+ def __init__(self, parent, name=None):
WMFRecord.__init__(self, parent)
+ if name:
+ self.name = name
+ else:
+ self.name = "settextcolor"
def dump(self):
- print("<todo/>")
- pass
+ dataPos = self.pos
+ print('<%s type="SetTextColor">' % self.name)
+ self.printAndSet("RecordSize", self.readuInt32(), hexdump=False)
+ self.printAndSet("RecordFunction", self.readuInt16(), hexdump=True)
+ ColorRef(self, "ColorRef").dump()
+ print('</%s>' % self.name)
+ assert self.pos == dataPos + self.RecordSize * 2
class MoveTo(WMFRecord):
- def __init__(self, parent):
+ def __init__(self, parent, name=None):
WMFRecord.__init__(self, parent)
+ if name:
+ self.name = name
+ else:
+ self.name = "moveto"
def dump(self):
- print("<todo/>")
- pass
+ dataPos = self.pos
+ print('<%s type="MoveTo">' % self.name)
+ self.printAndSet("RecordSize", self.readuInt32(), hexdump=False)
+ self.printAndSet("RecordFunction", self.readuInt16(), hexdump=True)
+ self.printAndSet("Y", self.readInt16(), hexdump=False)
+ self.printAndSet("X", self.readInt16(), hexdump=False)
+ print('</%s>' % self.name)
+ assert self.pos == dataPos + self.RecordSize * 2
class OffsetClipRgn(WMFRecord):
@@ -1010,12 +1084,23 @@ class SelectPalette(WMFRecord):
class Polygon(WMFRecord):
- def __init__(self, parent):
+ def __init__(self, parent, name=None):
WMFRecord.__init__(self, parent)
+ if name:
+ self.name = name
+ else:
+ self.name = "polygon"
def dump(self):
- print("<todo/>")
- pass
+ dataPos = self.pos
+ print('<%s type="Polygon">' % self.name)
+ self.printAndSet("RecordSize", self.readuInt32(), hexdump=False)
+ self.printAndSet("RecordFunction", self.readuInt16(), hexdump=True)
+ self.printAndSet("NumberOfPoints", self.readInt16(), hexdump=False)
+ for i in range(self.NumberOfPoints):
+ PointS(self, "aPoint%d" % i).dump()
+ print('</%s>' % self.name)
+ assert self.pos == dataPos + self.RecordSize * 2
class Polyline(WMFRecord):
@@ -1037,21 +1122,44 @@ class SetTextJustification(WMFRecord):
class SetWindowOrg(WMFRecord):
- def __init__(self, parent):
+ """The META_SETWINDOWORG record is used to define the output window origin."""
+ def __init__(self, parent, name=None):
WMFRecord.__init__(self, parent)
+ if name:
+ self.name = name
+ else:
+ self.name = "setwindoworg"
def dump(self):
- print("<todo/>")
- pass
+ dataPos = self.pos
+ print('<%s type="SetWindowOrg">' % self.name)
+ self.printAndSet("RecordSize", self.readuInt32(), hexdump=False)
+ self.printAndSet("RecordFunction", self.readuInt16(), hexdump=True)
+ self.printAndSet("Y", self.readInt16(), hexdump=False)
+ self.printAndSet("X", self.readInt16(), hexdump=False)
+ print('</%s>' % self.name)
+ assert self.pos == dataPos + self.RecordSize * 2
-class SetWindowExt:
- def __init__(self, parent):
+class SetWindowExt(WMFRecord):
+ """The META_SETWINDOWEXT Record is used to define the extents of the output
+ window, both for the horizontal and vertical dimensions."""
+ def __init__(self, parent, name=None):
WMFRecord.__init__(self, parent)
+ if name:
+ self.name = name
+ else:
+ self.name = "setwindoworg"
def dump(self):
- print("<todo/>")
- pass
+ dataPos = self.pos
+ print('<%s type="SetWindowExt">' % self.name)
+ self.printAndSet("RecordSize", self.readuInt32(), hexdump=False)
+ self.printAndSet("RecordFunction", self.readuInt16(), hexdump=True)
+ self.printAndSet("Y", self.readInt16(), hexdump=False)
+ self.printAndSet("X", self.readInt16(), hexdump=False)
+ print('</%s>' % self.name)
+ assert self.pos == dataPos + self.RecordSize * 2
class SetViewportOrg(WMFRecord):
@@ -1145,21 +1253,63 @@ class AnimatePalette(WMFRecord):
class TextOut(WMFRecord):
- def __init__(self, parent):
+ def __init__(self, parent, name=None):
WMFRecord.__init__(self, parent)
+ if name:
+ self.name = name
+ else:
+ self.name = "textout"
def dump(self):
- print("<todo/>")
- pass
+ dataPos = self.pos
+ print('<%s type="TextOut">' % self.name)
+ self.printAndSet("RecordSize", self.readuInt32(), hexdump=False)
+ self.printAndSet("RecordFunction", self.readuInt16(), hexdump=True)
+ self.printAndSet("StringLength", self.readInt16(), hexdump=False)
+ size = self.StringLength + self.StringLength % 2
+ StringByte = self.readBytes(size)
+ # Use bytes until chr(0) (null byte)
+ self.String = ""
+ for i in range(self.StringLength):
+ if StringByte[i] == 0:
+ break
+ self.String += chr(StringByte[i])
+
+ print('<String value="%s"/>' % (self.String))
+ self.printAndSet("YStart", self.readInt16(), hexdump=False)
+ self.printAndSet("XStart", self.readInt16(), hexdump=False)
+ print('</%s>' % self.name)
+ assert self.pos == dataPos + self.RecordSize * 2
class PolyPolygon(WMFRecord):
- def __init__(self, parent):
+ def __init__(self, parent, name=None):
WMFRecord.__init__(self, parent)
+ if name:
+ self.name = name
+ else:
+ self.name = "polypolygon"
def dump(self):
- print("<todo/>")
pass
+ dataPos = self.pos
+ print('<%s type="PolyPolygon">' % self.name)
+ self.printAndSet("RecordSize", self.readuInt32(), hexdump=False)
+ self.printAndSet("RecordFunction", self.readuInt16(), hexdump=True)
+ self.printAndSet("NumberOfPolygons", self.readuInt16(), hexdump=False)
+ print('<PolygonPointCounts>')
+ self.allPoints = 0
+ for i in range(self.NumberOfPolygons):
+ self.printAndSet("aPointsPerPolygon%d" % i, self.readuInt16(), hexdump=False)
+ print('</PolygonPointCounts>')
+ for i in range(self.NumberOfPolygons):
+ points = getattr(self, "aPointsPerPolygon%d" % i)
+ print('<Polygon%d>' % i)
+ for j in range(points):
+ PointS(self, "aPoint%d" % j).dump()
+ print('</Polygon%d>' % i)
+ print('</%s>' % self.name)
+ assert self.pos == dataPos + self.RecordSize * 2
class ExtFloodFill(WMFRecord):
@@ -1343,16 +1493,26 @@ class SelectClipRgn(WMFRecord):
class SelectObject(WMFRecord):
- def __init__(self, parent):
+ """The META_SELECTOBJECT record is used to specify a graphics object for the playback device context."""
+ def __init__(self, parent, name=None):
WMFRecord.__init__(self, parent)
+ if name:
+ self.name = name
+ else:
+ self.name = "selectobject"
def dump(self):
- print("<todo/>")
- pass
+ dataPos = self.pos
+ print('<%s type="SelectObject">' % self.name)
+ self.printAndSet("RecordSize", self.readuInt32(), hexdump=False)
+ self.printAndSet("RecordFunction", self.readuInt16(), hexdump=True)
+ self.printAndSet("ObjectIndex", self.readuInt16(), hexdump=False)
+ print('</%s>' % self.name)
+ assert self.pos == dataPos + self.RecordSize * 2
class SetTextAlign(WMFRecord):
- """The SetTextAlign record is used to define the text alignment"""
+ """The META_SETTEXTALIGN record is used to define the text alignment"""
def __init__(self, parent, name=None):
WMFRecord.__init__(self, parent)
if name:
@@ -1446,12 +1606,21 @@ class StretchDIBits(WMFRecord):
class DeleteObject(WMFRecord):
- def __init__(self, parent):
+ def __init__(self, parent, name=None):
WMFRecord.__init__(self, parent)
+ if name:
+ self.name = name
+ else:
+ self.name = "deleteobject"
def dump(self):
- print("<todo/>")
- pass
+ dataPos = self.pos
+ print('<%s type="SelectObject">' % self.name)
+ self.printAndSet("RecordSize", self.readuInt32(), hexdump=False)
+ self.printAndSet("RecordFunction", self.readuInt16(), hexdump=True)
+ self.printAndSet("ObjectIndex", self.readuInt16(), hexdump=False)
+ print('</%s>' % self.name)
+ assert self.pos == dataPos + self.RecordSize * 2
class CreatePalette(WMFRecord):
@@ -1472,13 +1641,40 @@ class CreatePatternBrush(WMFRecord):
pass
+class PenRecord(WMFRecord):
+ """The Pen object specifies the style, width, and color of an logical pen."""
+ def __init__(self, parent, name):
+ WMFRecord.__init__(self, parent)
+ self.name = name
+
+ def dump(self):
+ print('<%s type="Pen">' % self.name)
+ self.printAndSet("PenStyle", self.readuInt16(), dict=PenStyle)
+ self.printAndSet("Width", self.readuInt32())
+ ColorRef(self, "ColorRef").dump()
+ print('</%s>' % self.name)
+ self.parent.pos = self.pos
+
+
class CreatePenIndirect(WMFRecord):
- def __init__(self, parent):
+ """The META_CREATEPENINDIRECT record is used to create a Pen object"""
+ def __init__(self, parent, name=None):
WMFRecord.__init__(self, parent)
+ if name:
+ self.name = name
+ else:
+ self.name = "createpenindirect"
def dump(self):
- print("<todo/>")
- pass
+ dataPos = self.pos
+ print('<%s type="CreatePenIndirect">' % self.name)
+ self.printAndSet("RecordSize", self.readuInt32(), hexdump=False)
+ self.printAndSet("RecordFunction", self.readuInt16(), hexdump=True)
+ # Check optional reserved value if the size shows that it exists
+ PenRecord(self, "Pen").dump()
+ print('</%s>' % self.name)
+ # RecordSize is described in words, so we should double for bytes
+ assert self.pos == dataPos + self.RecordSize * 2
class CreateFontIndirect(WMFRecord):
@@ -1541,13 +1737,37 @@ class Font(WMFRecord):
self.parent.pos = self.pos
+class LogBrush(WMFRecord):
+ """The Brush object defines the style, color, and pattern of a device-independent brush."""
+ def __init__(self, parent, name):
+ WMFRecord.__init__(self, parent)
+ self.name = name
+
+ def dump(self):
+ print('<%s>' % self.name)
+ self.printAndSet("BrushStyle", self.readuInt16(), dict=BrushStyle)
+ ColorRef(self, "ColorRef").dump()
+ self.printAndSet("BrushHatch", self.readuInt16(), dict=HatchStyle)
+ print('</%s>' % self.name)
+ self.parent.pos = self.pos
+
+
class CreateBrushIndirect(WMFRecord):
- def __init__(self, parent):
+ def __init__(self, parent, name=None):
WMFRecord.__init__(self, parent)
+ if name:
+ self.name = name
+ else:
+ self.name = "createbrushindirect"
def dump(self):
- print("<todo/>")
- pass
+ dataPos = self.pos
+ print('<%s type="CreateBrushIndirect">' % self.name)
+ self.printAndSet("RecordSize", self.readuInt32(), hexdump=False)
+ self.printAndSet("RecordFunction", self.readuInt16(), hexdump=True)
+ LogBrush(self, "LogBrush").dump()
+ print('</%s>' % self.name)
+ assert self.pos == dataPos + self.RecordSize * 2
class CreateRectRgn(WMFRecord):
@@ -1559,11 +1779,28 @@ class CreateRectRgn(WMFRecord):
pass
+class EndOfFile(WMFRecord):
+ def __init__(self, parent, name=None):
+ WMFRecord.__init__(self, parent)
+ if name:
+ self.name = name
+ else:
+ self.name = "eof"
+
+ def dump(self):
+ dataPos = self.pos
+ print('<%s type="EndOfFile">' % self.name)
+ self.printAndSet("RecordSize", self.readuInt32(), hexdump=False)
+ self.printAndSet("RecordFunction", self.readuInt16(), hexdump=True)
+ print('</%s>' % self.name)
+ assert self.pos == dataPos + self.RecordSize * 2
+
+
# GDI Functions: https://docs.microsoft.com/en-us/windows/win32/api/_gdi/
# Wine API / GDI: https://source.winehq.org/WineAPI/gdi.html
"""The RecordType enumeration defines values that uniquely identify WMF records."""
RecordType = {
- 0x0000: ['META_EOF'],
+ 0x0000: ['META_EOF', EndOfFile],
0x0035: ['META_REALIZEPALETTE', RealizePalette],
0x0037: ['META_SETPALENTRIES', SetPaletteEntries],
0x0102: ['META_SETBKMODE', SetBkMode],