extract-msg 0.48.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. extract_msg/__init__.py +71 -0
  2. extract_msg/__main__.py +115 -0
  3. extract_msg/_rtf/__init__.py +21 -0
  4. extract_msg/_rtf/create_doc.py +29 -0
  5. extract_msg/_rtf/inject_rtf.py +174 -0
  6. extract_msg/_rtf/token.py +35 -0
  7. extract_msg/_rtf/tokenize_rtf.py +253 -0
  8. extract_msg/attachments/__init__.py +144 -0
  9. extract_msg/attachments/attachment.py +188 -0
  10. extract_msg/attachments/attachment_base.py +730 -0
  11. extract_msg/attachments/broken_att.py +42 -0
  12. extract_msg/attachments/custom_att.py +173 -0
  13. extract_msg/attachments/custom_att_handler/__init__.py +80 -0
  14. extract_msg/attachments/custom_att_handler/custom_handler.py +134 -0
  15. extract_msg/attachments/custom_att_handler/lnk_obj_att.py +109 -0
  16. extract_msg/attachments/custom_att_handler/outlook_image_dib.py +141 -0
  17. extract_msg/attachments/emb_msg_att.py +134 -0
  18. extract_msg/attachments/signed_att.py +234 -0
  19. extract_msg/attachments/unsupported_att.py +40 -0
  20. extract_msg/attachments/web_att.py +74 -0
  21. extract_msg/constants/__init__.py +294 -0
  22. extract_msg/constants/ps.py +46 -0
  23. extract_msg/constants/re.py +42 -0
  24. extract_msg/constants/st.py +110 -0
  25. extract_msg/data/logging-config/logging-nt.json +64 -0
  26. extract_msg/data/logging-config/logging-posix.json +64 -0
  27. extract_msg/encoding/__init__.py +277 -0
  28. extract_msg/encoding/_dt/__init__.py +4 -0
  29. extract_msg/encoding/_dt/_mac_ce.py +8 -0
  30. extract_msg/encoding/_dt/_mac_cyrillic.py +8 -0
  31. extract_msg/encoding/_dt/_mac_greek.py +8 -0
  32. extract_msg/encoding/_dt/_mac_iceland.py +8 -0
  33. extract_msg/encoding/_dt/_mac_turkish.py +8 -0
  34. extract_msg/encoding/_dt/_win874_dec.py +8 -0
  35. extract_msg/encoding/_dt/_win950_dec.py +6 -0
  36. extract_msg/encoding/utils.py +329 -0
  37. extract_msg/enums.py +2067 -0
  38. extract_msg/exceptions.py +170 -0
  39. extract_msg/msg_classes/__init__.py +49 -0
  40. extract_msg/msg_classes/appointment.py +195 -0
  41. extract_msg/msg_classes/calendar.py +92 -0
  42. extract_msg/msg_classes/calendar_base.py +496 -0
  43. extract_msg/msg_classes/contact.py +1335 -0
  44. extract_msg/msg_classes/journal.py +131 -0
  45. extract_msg/msg_classes/meeting_cancellation.py +108 -0
  46. extract_msg/msg_classes/meeting_exception.py +55 -0
  47. extract_msg/msg_classes/meeting_forward.py +115 -0
  48. extract_msg/msg_classes/meeting_related.py +65 -0
  49. extract_msg/msg_classes/meeting_request.py +189 -0
  50. extract_msg/msg_classes/meeting_response.py +74 -0
  51. extract_msg/msg_classes/message.py +12 -0
  52. extract_msg/msg_classes/message_base.py +1382 -0
  53. extract_msg/msg_classes/message_signed.py +17 -0
  54. extract_msg/msg_classes/message_signed_base.py +168 -0
  55. extract_msg/msg_classes/msg.py +1172 -0
  56. extract_msg/msg_classes/post.py +53 -0
  57. extract_msg/msg_classes/sticky_note.py +67 -0
  58. extract_msg/msg_classes/task.py +363 -0
  59. extract_msg/msg_classes/task_request.py +86 -0
  60. extract_msg/null_date.py +34 -0
  61. extract_msg/ole_writer.py +1086 -0
  62. extract_msg/open_msg.py +204 -0
  63. extract_msg/properties/__init__.py +23 -0
  64. extract_msg/properties/named.py +481 -0
  65. extract_msg/properties/prop.py +506 -0
  66. extract_msg/properties/properties_store.py +476 -0
  67. extract_msg/py.typed +0 -0
  68. extract_msg/recipient.py +362 -0
  69. extract_msg/structures/__init__.py +34 -0
  70. extract_msg/structures/_helpers.py +345 -0
  71. extract_msg/structures/business_card.py +422 -0
  72. extract_msg/structures/cfoas.py +108 -0
  73. extract_msg/structures/contact_link_entry.py +51 -0
  74. extract_msg/structures/dev_mode_a.py +621 -0
  75. extract_msg/structures/dv_target_device.py +168 -0
  76. extract_msg/structures/entry_id.py +697 -0
  77. extract_msg/structures/misc_id.py +222 -0
  78. extract_msg/structures/mon_stream.py +55 -0
  79. extract_msg/structures/odt.py +74 -0
  80. extract_msg/structures/ole_pres.py +302 -0
  81. extract_msg/structures/ole_stream_struct.py +117 -0
  82. extract_msg/structures/recurrence_pattern.py +199 -0
  83. extract_msg/structures/report_tag.py +127 -0
  84. extract_msg/structures/system_time.py +158 -0
  85. extract_msg/structures/time_zone_definition.py +111 -0
  86. extract_msg/structures/time_zone_struct.py +102 -0
  87. extract_msg/structures/toc_entry.py +137 -0
  88. extract_msg/structures/tz_rule.py +148 -0
  89. extract_msg/utils.py +1270 -0
  90. extract_msg-0.48.2.dist-info/LICENSE.txt +674 -0
  91. extract_msg-0.48.2.dist-info/METADATA +321 -0
  92. extract_msg-0.48.2.dist-info/RECORD +95 -0
  93. extract_msg-0.48.2.dist-info/WHEEL +5 -0
  94. extract_msg-0.48.2.dist-info/entry_points.txt +2 -0
  95. extract_msg-0.48.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,222 @@
1
+ """
2
+ Miscellaneous ID structures used in MSG files that don't fit into any of the
3
+ other ID structure classifications.
4
+ """
5
+
6
+
7
+ __all__ = [
8
+ 'FolderID',
9
+ 'GlobalObjectID',
10
+ 'MessageID',
11
+ 'ServerID',
12
+ ]
13
+
14
+
15
+ import datetime
16
+
17
+ from .. import constants
18
+ from ._helpers import BytesReader
19
+ from ..utils import filetimeToDatetime
20
+
21
+
22
+ class FolderID:
23
+ """
24
+ A Folder ID structure specified in [MS-OXCDATA].
25
+ """
26
+
27
+ __SIZE__: int = 16
28
+
29
+ def __init__(self, data: bytes):
30
+ self.__rawData = data
31
+ self.__replicaID = constants.st.ST_LE_UI16.unpack(data[:2])[0]
32
+ # This entry is 6 bytes, so we pull some shenanigans to unpack it.
33
+ self.__globalCounter = constants.st.ST_LE_UI64.unpack(data[2:8] + b'\x00\x00')[0]
34
+
35
+ def __bytes__(self) -> bytes:
36
+ return self.toBytes()
37
+
38
+ def toBytes(self) -> bytes:
39
+ return self.__rawData
40
+
41
+ @property
42
+ def globalCounter(self) -> int:
43
+ """
44
+ An unsigned integer identifying the folder within its Store object.
45
+ """
46
+ return self.__globalCounter
47
+
48
+ @property
49
+ def replicaID(self) -> int:
50
+ """
51
+ An unsigned integer identifying a Store object.
52
+ """
53
+ return self.__replicaID
54
+
55
+
56
+
57
+ class GlobalObjectID:
58
+ """
59
+ A GlobalObjectID structure, as specified in [MS-OXOCAL].
60
+ """
61
+
62
+ def __init__(self, data: bytes):
63
+ self.__rawData = data
64
+ reader = BytesReader(data)
65
+ expectedBytes = b'\x04\x00\x00\x00\x82\x00\xE0\x00\x74\xC5\xB7\x10\x1A\x82\xE0\x08'
66
+ errorMsg = 'Byte Array ID did not match for GlobalObjectID (got {actual}).'
67
+ self.__byteArrayID = reader.assertRead(expectedBytes, errorMsg)
68
+ self.__yh = reader.read(1)
69
+ self.__yl = reader.read(1)
70
+ self.__year = constants.st.ST_BE_UI16.unpack(self.__yh + self.__yl)[0]
71
+ self.__month = reader.readUnsignedByte()
72
+ self.__day = reader.readUnsignedByte()
73
+ self.__creationTime = filetimeToDatetime(reader.readUnsignedLong())
74
+ reader.assertNull(8, 'Reserved was not set to null.')
75
+ size = reader.readUnsignedInt()
76
+ self.__data = reader.read(size)
77
+
78
+ def __bytes__(self) -> bytes:
79
+ return self.toBytes()
80
+
81
+ def toBytes(self) -> bytes:
82
+ return self.__rawData
83
+
84
+ @property
85
+ def byteArrayID(self) -> bytes:
86
+ """
87
+ An array of 16 bytes identifying the bytes this BLOB as a Global Object
88
+ ID.
89
+ """
90
+ return self.__byteArrayID
91
+
92
+ @property
93
+ def creationTime(self) -> datetime.datetime:
94
+ """
95
+ The date and time when this Global Object ID was generated.
96
+ """
97
+ return self.__creationTime
98
+
99
+ @property
100
+ def data(self) -> bytes:
101
+ """
102
+ An array of bytes that ensures the uniqueness of the Global Object ID
103
+ amoung all Calendar objects in all mailboxes.
104
+ """
105
+ return self.__data
106
+
107
+ @property
108
+ def day(self) -> int:
109
+ """
110
+ The day from the PidLidExceptionReplaceTime property if the object
111
+ represents an exception. Otherwise, this is 0.
112
+ """
113
+ return self.__day
114
+
115
+ @property
116
+ def month(self) -> int:
117
+ """
118
+ The month from the PidLidExceptionReplaceTime property if the object
119
+ represents an exception. Otherwise, this is 0.
120
+ """
121
+ return self.__month
122
+
123
+ @property
124
+ def year(self) -> int:
125
+ """
126
+ The year from the PidLidExceptionReplaceTime property if the object
127
+ represents an exception. Otherwise, this is 0.
128
+ """
129
+ return self.__year
130
+
131
+
132
+
133
+ class MessageID:
134
+ """
135
+ A Message ID structure, as defined in [MS-OXCDATA].
136
+ """
137
+
138
+ __SIZE__: int = 8
139
+
140
+ def __init__(self, data: bytes):
141
+ self.__rawData = data
142
+ self.__replicaID = constants.st.ST_LE_UI16.unpack(data[:2])[0]
143
+ # This entry is 6 bytes, so we pull some shenanigans to unpack it.
144
+ self.__globalCounter = constants.st.ST_LE_UI64.unpack(data[2:8] + b'\x00\x00')[0]
145
+
146
+ def __bytes__(self) -> bytes:
147
+ return self.toBytes()
148
+
149
+ def toBytes(self) -> bytes:
150
+ return self.__rawData
151
+
152
+ @property
153
+ def globalCounter(self) -> int:
154
+ """
155
+ An unsigned integer identifying the folder within its Store object.
156
+ """
157
+ return self.__globalCounter
158
+
159
+ @property
160
+ def isFolder(self) -> bool:
161
+ """
162
+ Tells if the object pointed to is actually a folder.
163
+ """
164
+ return self.__globalCounter == 0 and self.__replicaID == 0
165
+
166
+ @property
167
+ def replicaID(self) -> int:
168
+ """
169
+ An unsigned integer identifying a Store object.
170
+ """
171
+ return self.__replicaID
172
+
173
+
174
+
175
+ class ServerID:
176
+ """
177
+ Class representing a PtypServerId.
178
+ """
179
+ def __init__(self, data: bytes):
180
+ """
181
+ :param data: The data to use to create the ServerID.
182
+
183
+ :raises TypeError: The data is not a ServerID.
184
+ """
185
+ # According to the docs, the first byte being a 1 means it follows this
186
+ # structure. A value of 0 means it does not.
187
+ if data[0] != 1:
188
+ raise TypeError('Not a standard ServerID.')
189
+ self.__rawData = data
190
+ self.__folderID = FolderID(data[1:9])
191
+ self.__messageID = MessageID(data[9:17])
192
+ self.__instance = constants.st.ST_LE_UI32.unpack(data[17:21])[0]
193
+
194
+ def __bytes__(self) -> bytes:
195
+ return self.toBytes()
196
+
197
+ def toBytes(self) -> bytes:
198
+ return self.__rawData
199
+
200
+ @property
201
+ def folderID(self) -> FolderID:
202
+ """
203
+ The folder the message will be in.
204
+ """
205
+ return self.__folderID
206
+
207
+ @property
208
+ def instance(self) -> int:
209
+ """
210
+ Instance number that is only used in multivalue properties for searching
211
+ for a specific ServerID. Will otherwise be 0.
212
+ """
213
+ return self.__instance
214
+
215
+ @property
216
+ def messageID(self) -> MessageID:
217
+ """
218
+ A MessageID identifying a message in a folder identified by the folderID
219
+ instance of this object. If the object pointed to is a folder, both
220
+ properties will be 0.
221
+ """
222
+ return self.__messageID
@@ -0,0 +1,55 @@
1
+ __all__ = [
2
+ 'MonikerStream',
3
+ ]
4
+
5
+
6
+ from typing import final, Optional
7
+
8
+
9
+ @final
10
+ class MonikerStream:
11
+ def __init__(self, data: Optional[bytes] = None):
12
+ if data:
13
+ self.__clsid = data[:16]
14
+ self.__streamData = data[16:]
15
+ else:
16
+ self.__clsid = b'\x00' * 16
17
+ self.__streamData = b''
18
+
19
+ def __bytes__(self) -> bytes:
20
+ return self.toBytes()
21
+
22
+ def toBytes(self) -> bytes:
23
+ return self.__clsid + self.__streamData
24
+
25
+ @property
26
+ def clsid(self) -> bytes:
27
+ """
28
+ The CLSID, as a stream of 16 bytes, of an implementation specific object
29
+ capable of processing the stream data.
30
+ """
31
+ return self.__clsid
32
+
33
+ @clsid.setter
34
+ def clsid(self, data: bytes) -> None:
35
+ if not isinstance(data, bytes):
36
+ raise TypeError('CLSID MUST be bytes.')
37
+ if len(data) != 16:
38
+ raise ValueError('CLSID MUST be 16 bytes.')
39
+
40
+ self.__clsid = data
41
+
42
+ @property
43
+ def streamData(self) -> bytes:
44
+ """
45
+ An array of bytes that specifies the reference to the linked object.
46
+ """
47
+ return self.__streamData
48
+
49
+ @streamData.setter
50
+ def streamData(self, data: bytes) -> None:
51
+ if not isinstance(data, bytes):
52
+ raise TypeError('Stream data MUST be bytes.')
53
+
54
+ self.__streamData = data
55
+
@@ -0,0 +1,74 @@
1
+ __all__ = [
2
+ 'ODTStruct',
3
+ ]
4
+
5
+ import struct
6
+ from typing import final, Optional
7
+
8
+ from ..enums import ODTCf, ODTPersist1, ODTPersist2
9
+
10
+
11
+ @final
12
+ class ODTStruct:
13
+ def __init__(self, data: Optional[bytes] = None):
14
+ if data:
15
+ values = struct.unpack('<HH', data[:8])
16
+ self.__cf = ODTCf(values[0])
17
+ self.__persist1 = ODTPersist1(values[1])
18
+ if len(data) >= 6:
19
+ self.__persist2 = ODTPersist2(struct.unpack('<H', data[4:6])[0])
20
+ else:
21
+ self.__persist2 = ODTPersist2.NONE
22
+ else:
23
+ self.__cf = ODTCf.UNSPECIFIED
24
+ self.__persist1 = ODTPersist1.NONE
25
+ self.__persist2 = ODTPersist2.NONE
26
+
27
+ def __bytes__(self) -> bytes:
28
+ return self.toBytes()
29
+
30
+ def toBytes(self) -> bytes:
31
+ return struct.pack('<HHH', self.__cf, self.__persist1, self.__persist2)
32
+
33
+ @property
34
+ def cf(self) -> ODTCf:
35
+ """
36
+ An enum value that specifies the format this OLE object uses to
37
+ transmit data to the host application.
38
+ """
39
+ return self.__cf
40
+
41
+ @cf.setter
42
+ def cf(self, value: ODTCf) -> None:
43
+ if not isinstance(value, ODTCf):
44
+ raise TypeError(':property cf: MUST be of type ODTCf.')
45
+
46
+ self.__cf = value
47
+
48
+ @property
49
+ def odtPersist1(self) -> ODTPersist1:
50
+ """
51
+ Flags that specify information about the OLE object.
52
+ """
53
+ return self.__persist1
54
+
55
+ @odtPersist1.setter
56
+ def odtPersist1(self, value: ODTPersist1) -> None:
57
+ if not isinstance(value, ODTPersist1):
58
+ raise TypeError(':property odtPersist1: MUST be of type ODTPersist1.')
59
+
60
+ self.__persist1 = value
61
+
62
+ @property
63
+ def odtPersist2(self) -> ODTPersist2:
64
+ """
65
+ Flags that specify additional information about the OLE object.
66
+ """
67
+ return self.__persist2
68
+
69
+ @odtPersist2.setter
70
+ def odtPersist2(self, value: ODTPersist2) -> None:
71
+ if not isinstance(value, ODTPersist2):
72
+ raise TypeError(':property odtPersist2: MUST be of type ODTPersist2.')
73
+
74
+ self.__persist2 = value
@@ -0,0 +1,302 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ __all__ = [
5
+ 'OLEPresentationStream',
6
+ ]
7
+
8
+
9
+ from typing import List, Optional, Union
10
+
11
+ from ._helpers import BytesReader
12
+ from .cfoas import ClipboardFormatOrAnsiString
13
+ from ..constants import st
14
+ from .dv_target_device import DVTargetDevice
15
+ from ..enums import ADVF, ClipboardFormat, DVAspect
16
+ from .toc_entry import TOCEntry
17
+
18
+
19
+ class OLEPresentationStream:
20
+ """
21
+ [MS-OLEDS] OLEPresentationStream.
22
+ """
23
+
24
+ def __init__(self, data: bytes):
25
+ reader = BytesReader(data)
26
+ acf = self.__ansiClipboardFormat = ClipboardFormatOrAnsiString(reader)
27
+
28
+ # Validate the structure based on the documentation.
29
+ if acf.markerOrLength == 0:
30
+ raise ValueError('Invalid OLEPresentationStream (MarkerOrLength is 0).')
31
+ if acf.clipboardFormat is ClipboardFormat.CF_BITMAP:
32
+ raise ValueError('Invalid OLEPresentationStream (Format is CF_BITMAP).')
33
+ if 0x201 < acf.markerOrLength < 0xFFFFFFFE:
34
+ raise ValueError('Invalid OLEPresentationStream (ANSI length was more than 0x201).')
35
+
36
+ targetDeviceSize = reader.readUnsignedInt()
37
+ if targetDeviceSize < 0x4:
38
+ raise ValueError('Invalid OLEPresentationStream (TargetDeviceSize was less than 4).')
39
+ if targetDeviceSize > 0x4:
40
+ # Read the TargetDevice field.
41
+ self.__targetDevice = DVTargetDevice(reader.read(targetDeviceSize))
42
+ else:
43
+ self.__targetDevice = None
44
+
45
+ self.__aspect = reader.readUnsignedInt()
46
+ self.__lindex = reader.readUnsignedInt()
47
+ self.__advf = reader.readUnsignedInt()
48
+
49
+ # Reserved1.
50
+ self.__reserved1 = reader.read(4)
51
+
52
+ self.__width = reader.readUnsignedInt()
53
+ self.__height = reader.readUnsignedInt()
54
+ size = reader.readUnsignedInt()
55
+ self.__data = reader.read(size)
56
+
57
+ if acf.clipboardFormat is ClipboardFormat.CF_METAFILEPICT:
58
+ self.__reserved2 = reader.read(18)
59
+ else:
60
+ self.__reserved2 = b'\x00' * 18.
61
+
62
+ self.__tocSignature = reader.readUnsignedInt()
63
+ self.__tocEntries = []
64
+ if self.__tocSignature == 0x494E414E: # b'NANI' in little endian.
65
+ for _ in range(reader.readUnsignedInt()):
66
+ self.__tocEntries.append(TOCEntry(reader))
67
+
68
+ def __bytes__(self) -> bytes:
69
+ return self.toBytes()
70
+
71
+ def toBytes(self) -> bytes:
72
+ ret = bytes(self.__ansiClipboardFormat)
73
+
74
+ if self.__targetDevice is None:
75
+ ret += b'\x04\x00\x00\x00'
76
+ else:
77
+ dvData = bytes(self.__targetDevice)
78
+ ret += st.ST_LE_UI32.pack(len(dvData))
79
+ ret += dvData
80
+
81
+ ret += st.ST_LE_UI32.pack(self.__aspect)
82
+ ret += st.ST_LE_UI32.pack(self.__lindex)
83
+ ret += st.ST_LE_UI32.pack(self.__advf)
84
+ ret += self.__reserved1
85
+ ret += st.ST_LE_UI32.pack(self.__width)
86
+ ret += st.ST_LE_UI32.pack(self.__height)
87
+ ret += st.ST_LE_UI32.pack(len(self.__data)) + self.__data
88
+ if self.reserved2: # Shortcut since this property has protection.
89
+ ret += self.__reserved2
90
+
91
+ if self.__tocSignature == 0x494E414E:
92
+ ret += st.ST_LE_UI32.pack(len(self.__tocEntries))
93
+ for entry in self.__tocEntries:
94
+ ret += bytes(entry)
95
+ else:
96
+ ret += b'\x00\x00\x00\x00'
97
+
98
+ return ret
99
+
100
+ @property
101
+ def advf(self) -> Union[int, ADVF]:
102
+ """
103
+ An implementation specific hint on how to render the presentation data
104
+ on screen. May be ignored on processing.
105
+ """
106
+ return self.__advf
107
+
108
+ @advf.setter
109
+ def advf(self, val: Union[int, ADVF]) -> None:
110
+ if not isinstance(val, int):
111
+ raise TypeError(':property advf: must be an int.')
112
+ if val < 0:
113
+ raise ValueError(':property advf: must be positive.')
114
+ if val > 0xFFFFFFFF:
115
+ raise ValueError(':property advf: cannot be greater than 0xFFFFFFFF.')
116
+
117
+ self.__advf = val
118
+
119
+ @property
120
+ def ansiClipboardFormat(self) -> ClipboardFormatOrAnsiString:
121
+ return self.__ansiClipboardFormat
122
+
123
+ @property
124
+ def aspect(self) -> Union[int, DVAspect]:
125
+ """
126
+ An implementation specific hint on how to render the presentation data
127
+ on screen. May be ignored on processing.
128
+ """
129
+ return self.__aspect
130
+
131
+ @aspect.setter
132
+ def aspect(self, val: Union[int, DVAspect]) -> None:
133
+ if not isinstance(val, int):
134
+ raise TypeError(':property aspect: must be an int.')
135
+ if val < 0:
136
+ raise ValueError(':property aspect: must be positive.')
137
+ if val > 0xFFFFFFFF:
138
+ raise ValueError(':property aspect: cannot be greater than 0xFFFFFFFF.')
139
+
140
+ self.__aspect = val
141
+
142
+ @property
143
+ def data(self) -> bytes:
144
+ """
145
+ The presentation data. The form of this data depends on :property clipboardFormat: of :property ansiClipboardFormat:.
146
+ """
147
+ return self.__data
148
+
149
+ @data.setter
150
+ def data(self, val: bytes) -> None:
151
+ if not isinstance(val, bytes):
152
+ raise TypeError(':property data: must be bytes.')
153
+ self.__data = val
154
+
155
+ @property
156
+ def height(self) -> int:
157
+ """
158
+ The height, in pixels, of the presentation data.
159
+ """
160
+ return self.__height
161
+
162
+ @height.setter
163
+ def height(self, val: int) -> None:
164
+ if not isinstance(val, int):
165
+ raise TypeError(':property height: must be an int.')
166
+ if val < 0:
167
+ raise ValueError(':property height: must be positive.')
168
+ if val > 0xFFFFFFFF:
169
+ raise ValueError(':property height: cannot be greater than 0xFFFFFFFF.')
170
+
171
+ self.__height = val
172
+
173
+ @property
174
+ def lindex(self) -> int:
175
+ """
176
+ An implementation specific hint on how to render the presentation data on screen. May be ignored on processing.
177
+ """
178
+ return self.__lindex
179
+
180
+ @lindex.setter
181
+ def lindex(self, val: int) -> None:
182
+ if not isinstance(val, int):
183
+ raise TypeError(':property lindex: must be an int.')
184
+ if val < 0:
185
+ raise ValueError(':property lindex: must be positive.')
186
+ if val > 0xFFFFFFFF:
187
+ raise ValueError(':property lindex: cannot be greater than 0xFFFFFFFF.')
188
+
189
+ self.__lindex = val
190
+
191
+ @property
192
+ def reserved1(self) -> bytes:
193
+ """
194
+ 4 bytes that can contain any arbitrary data. Must be *exactly* 4 bytes
195
+ when setting.
196
+ """
197
+ return self.__reserved1
198
+
199
+ @reserved1.setter
200
+ def reserved1(self, val: bytes) -> None:
201
+ if not isinstance(val, bytes):
202
+ raise TypeError(':property reserved1: must by bytes.')
203
+ if len(val) != 4:
204
+ raise ValueError(':property reserved1: must be exactly 4 bytes.')
205
+
206
+ self.__reserved1 = val
207
+
208
+ @property
209
+ def reserved2(self) -> Optional[bytes]:
210
+ """
211
+ Optional additional data that is only set if the clipboard format of
212
+ :property ansiClipboardFormat: is ``CF_METAFILEPICT``.
213
+
214
+ Getting this will automatically correct the value retrieved based on
215
+ the clipboard format, but will *not* modify the underlying data.
216
+
217
+ Must be *exactly* 18 bytes when setting.
218
+ """
219
+ if self.__ansiClipboardFormat.clipboardFormat is not ClipboardFormat.CF_METAFILEPICT:
220
+ return None
221
+ return self.__reserved2
222
+
223
+ @reserved2.setter
224
+ def reserved2(self, val: bytes) -> None:
225
+ if self.__ansiClipboardFormat.clipboardFormat is not ClipboardFormat.CF_METAFILEPICT:
226
+ raise ValueError(':property reserved2: cannot be set if the clipboard format (from :property ansiClipboardFormat:) is not CF_METAFILEPICT.')
227
+ if not isinstance(val, bytes):
228
+ raise TypeError(':property reserved2: must by bytes.')
229
+ if len(val) != 18:
230
+ raise ValueError(':property reserved2: must be exactly 18 bytes.')
231
+
232
+ self.__reserved2 = val
233
+
234
+ @property
235
+ def targetDevice(self) -> Optional[DVTargetDevice]:
236
+ return self.__targetDevice
237
+
238
+ @targetDevice.setter
239
+ def targetDevice(self, val: Optional[DVTargetDevice]) -> None:
240
+ if val is not None and not isinstance(val, DVTargetDevice):
241
+ raise TypeError(':property targetDevice: must be None or a DVTargetDevice.')
242
+
243
+ self.__targetDevice = val
244
+
245
+ @property
246
+ def tocEntries(self) -> List[TOCEntry]:
247
+ """
248
+ A list of TOCEntry structures. If :property tocSignature: is not set to
249
+ ``0x494E414E``, accessing this value will clear the list.
250
+
251
+ :returns: A direct reference to the list, allowing for modification.
252
+ This class WILL NOT change this reference over the lifetime of the
253
+ object.
254
+ """
255
+ if self.__tocSignature != 0x494E414E:
256
+ self.__tocEntries.clear()
257
+ return self.__tocEntries
258
+
259
+ @property
260
+ def tocSignature(self) -> int:
261
+ """
262
+ If this field does not contain ``0x494E414E``, then
263
+ :property tocEntries: MUST be empty. Modifications to the list will be lost when it is next retrieved, meaning changes while this property is not ``0x494E414E`` WILL be lost.
264
+
265
+ Setting this to a value other than ``0x494E414E`` will clear the list
266
+ immediately.
267
+ """
268
+ return self.__tocSignature
269
+
270
+ @tocSignature.setter
271
+ def tocSignature(self, val: int) -> None:
272
+ if not isinstance(val, int):
273
+ raise TypeError(':property tocSignature: must be an int.')
274
+ if val < 0:
275
+ raise ValueError(':property tocSignature: must be positive.')
276
+ if val > 0xFFFFFFFF:
277
+ raise ValueError(':property tocSignature: cannot be greater than 0xFFFFFFFF.')
278
+
279
+ if val != 0x494E414E:
280
+ self.__tocEntries.clear()
281
+
282
+ self.__tocSignature = val
283
+
284
+ @property
285
+ def width(self) -> int:
286
+ """
287
+ The width, in pixels, of the presentation data.
288
+ """
289
+ return self.__width
290
+
291
+ @width.setter
292
+ def width(self, val: int) -> None:
293
+ if not isinstance(val, int):
294
+ raise TypeError(':property width: must be an int.')
295
+ if val < 0:
296
+ raise ValueError(':property width: must be positive.')
297
+ if val > 0xFFFFFFFF:
298
+ raise ValueError(':property width: cannot be greater than 0xFFFFFFFF.')
299
+
300
+ self.__width = val
301
+
302
+