Helpviewer/FlashCookieManager/FlashCookieReader.py

changeset 4360
b8bdb7cd4a92
child 4361
9eec3a532d59
equal deleted inserted replaced
4359:ac1dda9f3f19 4360:b8bdb7cd4a92
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2015 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a class to read flash cookies.
8 """
9
10 #
11 # Note: The code is based on s2x.py
12 #
13
14 from __future__ import unicode_literals
15
16 import struct
17 import io
18
19 from PyQt5.QtCore import QDateTime
20
21
22 class FlashCookieReaderError(Exception):
23 """
24 Class containing data of a reader error.
25 """
26 def __init__(self, msg):
27 """
28 Constructor
29
30 @param msg error message
31 @type str
32 """
33 self.msg = msg
34
35
36 class FlashCookieReader(object):
37 """
38 Class implementing a reader for flash cookies (*.sol files).
39 """
40 Number = b'\x00'
41 Boolean = b'\x01'
42 String = b'\x02'
43 ObjObj = b'\x03'
44 Null = b'\x05'
45 Undef = b'\x06'
46 ObjArr = b'\x08'
47 ObjDate = b'\x0B'
48 ObjM = b'\x0D'
49 ObjXml = b'\x0F'
50 ObjCc = b'\x10'
51
52 EpochCorrectionMsecs = 31 * 24 * 60 * 60 * 1000
53 # Flash Epoch starts at 1969-12-01
54
55 def __init__(self):
56 """
57 Constructor
58 """
59 self.__result = {}
60 # dictionary with element name as key and tuple of
61 # type and value as value
62 self.__data = None
63 self.__parsed = False
64
65 def setBytes(self, solData):
66 """
67 Public method to set the contents of a sol file to be parsed.
68
69 @param solData contents of the file
70 @type bytes
71 """
72 self.__data = io.BytesIO(solData)
73
74 def setFileName(self, solFilename):
75 """
76 Public method to set the name of a sol file to be parsed.
77
78 @param solFilename name of the sol file
79 @type str
80 """
81 self.__data = open(solFilename, "rb")
82
83 def setFile(self, solFile):
84 """
85 Public method to set an open sol file to be parsed.
86
87 @param solFile sol file to be parsed
88 @type io.FileIO
89 """
90 self.__data = solFile
91
92 def parse(self):
93 """
94 Public method to parse the sol file.
95
96 @exception FlashCookieReaderError raised when encountering a parse
97 issue
98 """
99 if self.__data is None:
100 return
101
102 self.__data.seek(0, 2)
103 lenSolData = self.__data.tell()
104 self.__data.seek(0)
105 self.__data.read(2)
106 sLenData = self.__data.read(4)
107 lenData, = struct.unpack(">L", sLenData) # unsigned long, big-endian
108 if lenSolData != lenData + 6:
109 print("Warning: data length doesn't match.")
110 sDataType = self.__data.read(4).decode("utf-8") # 'TCSO'
111 if sDataType != "TCSO":
112 raise FlashCookieReaderError(
113 "Flash cookie type is not 'TCSO'; found '{0}'."
114 .format(sDataType))
115 self.__data.read(6)
116 lenSolName, = struct.unpack(">H", self.__data.read(2))
117 # unsigned short, big-endian
118 solName = self.__data.read(lenSolName)
119 solName = solName.decode("utf-8")
120 self.__result["SolName"] = ("string", solName)
121 self.__data.read(4)
122 while self.__data.tell() < lenSolData:
123 lenVariableName, = struct.unpack(">H", self.__data.read(2))
124 # unsigned short, big-endian
125 variableName = self.__data.read(lenVariableName)
126 variableName = variableName.decode("utf-8")
127 variableType = self.__data.read(1)
128 if variableType == self.Number:
129 self.__parseNumber(variableName, self.__result)
130 elif variableType == self.Boolean:
131 self.__parseBoolean(variableName, self.__result)
132 elif variableType == self.String:
133 self.__parseString(variableName, self.__result)
134 elif variableType == self.ObjObj:
135 self.__parseObject(variableName, self.__result)
136 elif variableType == self.ObjArr:
137 self.__parseArray(variableName, self.__result)
138 elif variableType == self.ObjDate:
139 self.__parseDate(variableName, self.__result)
140 elif variableType == self.ObjXml:
141 self.__parseXml(variableName, self.__result)
142 elif variableType == self.ObjCc:
143 self.__parseOcc(variableName, self.__result)
144 elif variableType == self.ObjM:
145 self.__parseOjm(variableName, self.__result)
146 elif variableType == self.Null:
147 self.__parseNull(variableName, self.__result)
148 elif variableType == self.Undef:
149 self.__parseUndefined(variableName, self.__result)
150 else:
151 raise FlashCookieReaderError(
152 "Unexpected Data Type: " + hex(ord(variableType)))
153 self.__data.read(1) # '\x00'
154 self.__data.close()
155 self.__parsed = True
156
157 def __parseNumber(self, variableName, parent):
158 """
159 Private method to parse a number.
160
161 @param variableName name of the variable to be parsed
162 @type str
163 @param parent reference to the dictionary to insert the result into
164 @type dict
165 """
166 b = self.__data.read(8)
167 if b == b"\x7F\xF0\x00\x00\x00\x00\x00\x00":
168 value = "Infinity"
169 elif b == b"\xFF\xF0\x00\x00\x00\x00\x00\x00":
170 value = "-Infinity"
171 elif value == b"\x7F\xF8\x00\x00\x00\x00\x00\x00":
172 value = "NaN"
173 else:
174 value, = struct.unpack(">d", b) # double, big-endian
175 value = str(value)
176 parent[variableName] = ("number", value)
177
178 def __parseBoolean(self, variableName, parent):
179 """
180 Private method to parse a boolean.
181
182 @param variableName name of the variable to be parsed
183 @type str
184 @param parent reference to the dictionary to insert the result into
185 @type dict
186 """
187 b = self.__data.read(1)
188 if b == b"\x00":
189 value = "False"
190 elif b == b"\x01":
191 value = "True"
192 else:
193 # boolean value error; default to True
194 value = "True"
195 parent[variableName] = ("boolean", value)
196
197 def __parseString(self, variableName, parent):
198 """
199 Private method to parse a string.
200
201 @param variableName name of the variable to be parsed
202 @type str
203 @param parent reference to the dictionary to insert the result into
204 @type dict
205 """
206 lenStr, = struct.unpack(">H", self.__data.read(2))
207 # unsigned short, big-endian
208 b = self.__data.read(lenStr)
209 value = b.decode("utf-8")
210 parent[variableName] = ("string", value)
211
212 def __parseDate(self, variableName, parent):
213 """
214 Private method to parse a date.
215
216 @param variableName name of the variable to be parsed
217 @type str
218 @param parent reference to the dictionary to insert the result into
219 @type dict
220 """
221 msec, = struct.unpack(">d", self.__data.read(8))
222 # double, big-endian
223 # DateObject: Milliseconds Count From Dec. 1, 1969
224 msec -= self.EpochCorrectionMsecs # correct for Unix epoch
225 minOffset, = struct.unpack(">h", self.__data.read(2))
226 # short, big-endian
227 offset = minOffset // 60 # offset in hours
228 # Timezone: UTC + Offset
229 value = QDateTime()
230 value.setMSecsSinceEpoch(msec)
231 value.setOffsetFromUtc(offset * 3600)
232 parent[variableName] = ("date",
233 value.toString("yyyy-MM-dd HH:mm:ss t"))
234
235 def __parseXml(self, variableName, parent):
236 """
237 Private method to parse XML.
238
239 @param variableName name of the variable to be parsed
240 @type str
241 @param parent reference to the dictionary to insert the result into
242 @type dict
243 """
244 lenCData, = struct.unpack(">L", self.__data.read(4))
245 # unsigned long, big-endian
246 cData = self.__data.read(lenCData)
247 value = cData.decode("utf-8")
248 parent[variableName] = ("xml", value)
249
250 def __parseOjm(self, variableName, parent):
251 """
252 Private method to parse an m_object.
253
254 @param variableName name of the variable to be parsed
255 @type str
256 @param parent reference to the dictionary to insert the result into
257 @type dict
258 """
259 parent[variableName] = ("m_object", "")
260
261 def __parseNull(self, variableName, parent):
262 """
263 Private method to parse a null object.
264
265 @param variableName name of the variable to be parsed
266 @type str
267 @param parent reference to the dictionary to insert the result into
268 @type dict
269 """
270 parent[variableName] = ("null", "")
271
272 def __parseUndefined(self, variableName, parent):
273 """
274 Private method to parse an undefined object.
275
276 @param variableName name of the variable to be parsed
277 @type str
278 @param parent reference to the dictionary to insert the result into
279 @type dict
280 """
281 parent[variableName] = ("undefined", "")
282
283 def __parseObject(self, variableName, parent):
284 """
285 Private method to parse an object.
286
287 @param variableName name of the variable to be parsed
288 @type str
289 @param parent reference to the dictionary to insert the result into
290 @type dict
291 """
292 value = {}
293 parent[variableName] = ("object", value)
294
295 lenVariableName, = struct.unpack(">H", self.__data.read(2))
296 # unsigned short, big-endian
297 while lenVariableName != 0:
298 variableName = self.__data.read(lenVariableName)
299 variableName = variableName.decode("utf-8")
300 variableType = self.__data.read(1)
301 if variableType == self.Number:
302 self.__parseNumber(variableName, value)
303 elif variableType == self.Boolean:
304 self.__parseBoolean(variableName, value)
305 elif variableType == self.String:
306 self.__parseString(variableName, value)
307 elif variableType == self.ObjObj:
308 self.__parseObject(variableName, value)
309 elif variableType == self.ObjArr:
310 self.__parseArray(variableName, value)
311 elif variableType == self.ObjDate:
312 self.__parseDate(variableName, value)
313 elif variableType == self.ObjXml:
314 self.__parseXml(variableName, value)
315 elif variableType == self.ObjCc:
316 self.__parseOcc(variableName, value)
317 elif variableType == self.ObjM:
318 self.__parseOjm(variableName, value)
319 elif variableType == self.Null:
320 self.__parseNull(variableName, value)
321 elif variableType == self.Undef:
322 self.__parseUndefined(variableName, value)
323 else:
324 raise FlashCookieReaderError(
325 "Unexpected Data Type: " + hex(ord(variableType)))
326 lenVariableName, = struct.unpack(">H", self.__data.read(2))
327 self.__data.read(1) # '\x09'
328
329 def __parseArray(self, variableName, parent):
330 """
331 Private method to parse an array.
332
333 @param variableName name of the variable to be parsed
334 @type str
335 @param parent reference to the dictionary to insert the result into
336 @type dict
337 """
338 arrayLength, = struct.unpack(">L", self.__data.read(4))
339 # unsigned long, big-endian
340
341 value = {}
342 parent[variableName] = ("array; length={0}".format(arrayLength), value)
343
344 lenVariableName, = struct.unpack(">H", self.__data.read(2))
345 # unsigned short, big-endian
346 while lenVariableName != 0:
347 variableName = self.__data.read(lenVariableName)
348 variableName = variableName.decode("utf-8")
349 variableType = self.__data.read(1)
350 if variableType == self.Number:
351 self.__parseNumber(variableName, value)
352 elif variableType == self.Boolean:
353 self.__parseBoolean(variableName, value)
354 elif variableType == self.String:
355 self.__parseString(variableName, value)
356 elif variableType == self.ObjObj:
357 self.__parseObject(variableName, value)
358 elif variableType == self.ObjArr:
359 self.__parseArray(variableName, value)
360 elif variableType == self.ObjDate:
361 self.__parseDate(variableName, value)
362 elif variableType == self.ObjXml:
363 self.__parseXml(variableName, value)
364 elif variableType == self.ObjCc:
365 self.__parseOcc(variableName, value)
366 elif variableType == self.ObjM:
367 self.__parseOjm(variableName, value)
368 elif variableType == self.Null:
369 self.__parseNull(variableName, value)
370 elif variableType == self.Undef:
371 self.__parseUndefined(variableName, value)
372 else:
373 raise FlashCookieReaderError(
374 "Unexpected Data Type: " + hex(ord(variableType)))
375 lenVariableName, = struct.unpack(">H", self.__data.read(2))
376 self.__data.read(1) # '\x09'
377
378 def __parseOcc(self, variableName, parent):
379 """
380 Private method to parse a c_object.
381
382 @param variableName name of the variable to be parsed
383 @type str
384 @param parent reference to the dictionary to insert the result into
385 @type dict
386 """
387 lenCname = struct.unpack(">H", self.__data.read(2))
388 # unsigned short, big-endian
389 cname = self.__data.read(lenCname)
390 cname = cname.decode("utf-8")
391
392 value = {}
393 parent[variableName] = ("c_object; cname={0}".format(cname), value)
394
395 lenVariableName, = struct.unpack(">H", self.__data.read(2))
396 # unsigned short, big-endian
397 while lenVariableName != 0:
398 variableName = self.__data.read(lenVariableName)
399 variableName = variableName.decode("utf-8")
400 variableType = self.__data.read(1)
401 if variableType == self.Number:
402 self.__parseNumber(variableName, value)
403 elif variableType == self.Boolean:
404 self.__parseBoolean(variableName, value)
405 elif variableType == self.String:
406 self.__parseString(variableName, value)
407 elif variableType == self.ObjObj:
408 self.__parseObject(variableName, value)
409 elif variableType == self.ObjArr:
410 self.__parseArray(variableName, value)
411 elif variableType == self.ObjDate:
412 self.__parseDate(variableName, value)
413 elif variableType == self.ObjXml:
414 self.__parseXml(variableName, value)
415 elif variableType == self.ObjCc:
416 self.__parseOcc(variableName, value)
417 elif variableType == self.ObjM:
418 self.__parseOjm(variableName, value)
419 elif variableType == self.Null:
420 self.__parseNull(variableName, value)
421 elif variableType == self.Undef:
422 self.__parseUndefined(variableName, value)
423 else:
424 raise FlashCookieReaderError(
425 "Unexpected Data Type: " + hex(ord(variableType)))
426 lenVariableName, = struct.unpack(">H", self.__data.read(2))
427 self.__data.read(1) # '\x09'

eric ide

mercurial