WebBrowser/FlashCookieManager/FlashCookieReader.py

branch
QtWebEngine
changeset 4751
f745a556fd6f
parent 4631
5c1a96925da4
child 4934
aeffa295acdb
equal deleted inserted replaced
4750:9fc5d2625d61 4751:f745a556fd6f
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2015 - 2016 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 raise FlashCookieReaderError(
110 "Flash cookie data lengths don't match\n"
111 " file length: {0}\n"
112 " data length: {1}"
113 .format(lenSolData - 6, lenData))
114 sDataType = self.__data.read(4).decode("utf-8") # 'TCSO'
115 if sDataType != "TCSO":
116 raise FlashCookieReaderError(
117 "Flash cookie type is not 'TCSO'; found '{0}'."
118 .format(sDataType))
119 self.__data.read(6)
120 lenSolName, = struct.unpack(">H", self.__data.read(2))
121 # unsigned short, big-endian
122 solName = self.__data.read(lenSolName)
123 solName = solName.decode("utf-8", "replace")
124 self.__result["SolName"] = ("string", solName)
125 self.__data.read(4)
126 while self.__data.tell() < lenSolData:
127 lenVariableName, = struct.unpack(">H", self.__data.read(2))
128 # unsigned short, big-endian
129 variableName = self.__data.read(lenVariableName)
130 variableName = variableName.decode("utf-8", "replace")
131 variableType = self.__data.read(1)
132 if len(variableType):
133 if variableType == self.Number:
134 self.__parseNumber(variableName, self.__result)
135 elif variableType == self.Boolean:
136 self.__parseBoolean(variableName, self.__result)
137 elif variableType == self.String:
138 self.__parseString(variableName, self.__result)
139 elif variableType == self.ObjObj:
140 self.__parseObject(variableName, self.__result)
141 elif variableType == self.ObjArr:
142 self.__parseArray(variableName, self.__result)
143 elif variableType == self.ObjDate:
144 self.__parseDate(variableName, self.__result)
145 elif variableType == self.ObjXml:
146 self.__parseXml(variableName, self.__result)
147 elif variableType == self.ObjCc:
148 self.__parseOcc(variableName, self.__result)
149 elif variableType == self.ObjM:
150 self.__parseOjm(variableName, self.__result)
151 elif variableType == self.Null:
152 self.__parseNull(variableName, self.__result)
153 elif variableType == self.Undef:
154 self.__parseUndefined(variableName, self.__result)
155 else:
156 raise FlashCookieReaderError(
157 "Unexpected Data Type: " + hex(ord(variableType)))
158 self.__data.read(1) # '\x00'
159 self.__data.close()
160 self.__parsed = True
161
162 def __parseNumber(self, variableName, parent):
163 """
164 Private method to parse a number.
165
166 @param variableName name of the variable to be parsed
167 @type str
168 @param parent reference to the dictionary to insert the result into
169 @type dict
170 """
171 b = self.__data.read(8)
172 if b == b"\x7F\xF0\x00\x00\x00\x00\x00\x00":
173 value = "Infinity"
174 elif b == b"\xFF\xF0\x00\x00\x00\x00\x00\x00":
175 value = "-Infinity"
176 elif b == b"\x7F\xF8\x00\x00\x00\x00\x00\x00":
177 value = "NaN"
178 else:
179 value, = struct.unpack(">d", b) # double, big-endian
180 value = str(value)
181 parent[variableName] = ("number", value)
182
183 def __parseBoolean(self, variableName, parent):
184 """
185 Private method to parse a boolean.
186
187 @param variableName name of the variable to be parsed
188 @type str
189 @param parent reference to the dictionary to insert the result into
190 @type dict
191 """
192 b = self.__data.read(1)
193 if b == b"\x00":
194 value = "False"
195 elif b == b"\x01":
196 value = "True"
197 else:
198 # boolean value error; default to True
199 value = "True"
200 parent[variableName] = ("boolean", value)
201
202 def __parseString(self, variableName, parent):
203 """
204 Private method to parse a string.
205
206 @param variableName name of the variable to be parsed
207 @type str
208 @param parent reference to the dictionary to insert the result into
209 @type dict
210 """
211 lenStr, = struct.unpack(">H", self.__data.read(2))
212 # unsigned short, big-endian
213 b = self.__data.read(lenStr)
214 value = b.decode("utf-8", "replace")
215 parent[variableName] = ("string", value)
216
217 def __parseDate(self, variableName, parent):
218 """
219 Private method to parse a date.
220
221 @param variableName name of the variable to be parsed
222 @type str
223 @param parent reference to the dictionary to insert the result into
224 @type dict
225 """
226 msec, = struct.unpack(">d", self.__data.read(8))
227 # double, big-endian
228 # DateObject: Milliseconds Count From Dec. 1, 1969
229 msec -= self.EpochCorrectionMsecs # correct for Unix epoch
230 minOffset, = struct.unpack(">h", self.__data.read(2))
231 # short, big-endian
232 offset = minOffset // 60 # offset in hours
233 # Timezone: UTC + Offset
234 value = QDateTime()
235 value.setMSecsSinceEpoch(msec)
236 value.setOffsetFromUtc(offset * 3600)
237 parent[variableName] = ("date",
238 value.toString("yyyy-MM-dd HH:mm:ss t"))
239
240 def __parseXml(self, variableName, parent):
241 """
242 Private method to parse XML.
243
244 @param variableName name of the variable to be parsed
245 @type str
246 @param parent reference to the dictionary to insert the result into
247 @type dict
248 """
249 lenCData, = struct.unpack(">L", self.__data.read(4))
250 # unsigned long, big-endian
251 cData = self.__data.read(lenCData)
252 value = cData.decode("utf-8", "replace")
253 parent[variableName] = ("xml", value)
254
255 def __parseOjm(self, variableName, parent):
256 """
257 Private method to parse an m_object.
258
259 @param variableName name of the variable to be parsed
260 @type str
261 @param parent reference to the dictionary to insert the result into
262 @type dict
263 """
264 parent[variableName] = ("m_object", "")
265
266 def __parseNull(self, variableName, parent):
267 """
268 Private method to parse a null object.
269
270 @param variableName name of the variable to be parsed
271 @type str
272 @param parent reference to the dictionary to insert the result into
273 @type dict
274 """
275 parent[variableName] = ("null", "")
276
277 def __parseUndefined(self, variableName, parent):
278 """
279 Private method to parse an undefined object.
280
281 @param variableName name of the variable to be parsed
282 @type str
283 @param parent reference to the dictionary to insert the result into
284 @type dict
285 """
286 parent[variableName] = ("undefined", "")
287
288 def __parseObject(self, variableName, parent):
289 """
290 Private method to parse an object.
291
292 @param variableName name of the variable to be parsed
293 @type str
294 @param parent reference to the dictionary to insert the result into
295 @type dict
296 @exception FlashCookieReaderError raised when an issue with the cookie
297 file is found
298 """
299 value = {}
300 parent[variableName] = ("object", value)
301
302 lenVariableName, = struct.unpack(">H", self.__data.read(2))
303 # unsigned short, big-endian
304 while lenVariableName != 0:
305 variableName = self.__data.read(lenVariableName)
306 variableName = variableName.decode("utf-8", "replace")
307 variableType = self.__data.read(1)
308 if variableType == self.Number:
309 self.__parseNumber(variableName, value)
310 elif variableType == self.Boolean:
311 self.__parseBoolean(variableName, value)
312 elif variableType == self.String:
313 self.__parseString(variableName, value)
314 elif variableType == self.ObjObj:
315 self.__parseObject(variableName, value)
316 elif variableType == self.ObjArr:
317 self.__parseArray(variableName, value)
318 elif variableType == self.ObjDate:
319 self.__parseDate(variableName, value)
320 elif variableType == self.ObjXml:
321 self.__parseXml(variableName, value)
322 elif variableType == self.ObjCc:
323 self.__parseOcc(variableName, value)
324 elif variableType == self.ObjM:
325 self.__parseOjm(variableName, value)
326 elif variableType == self.Null:
327 self.__parseNull(variableName, value)
328 elif variableType == self.Undef:
329 self.__parseUndefined(variableName, value)
330 else:
331 raise FlashCookieReaderError(
332 "Unexpected Data Type: " + hex(ord(variableType)))
333 lenVariableName, = struct.unpack(">H", self.__data.read(2))
334 self.__data.read(1) # '\x09'
335
336 def __parseArray(self, variableName, parent):
337 """
338 Private method to parse an array.
339
340 @param variableName name of the variable to be parsed
341 @type str
342 @param parent reference to the dictionary to insert the result into
343 @type dict
344 @exception FlashCookieReaderError raised when an issue with the cookie
345 file is found
346 """
347 arrayLength, = struct.unpack(">L", self.__data.read(4))
348 # unsigned long, big-endian
349
350 value = {}
351 parent[variableName] = ("array; length={0}".format(arrayLength), value)
352
353 lenVariableName, = struct.unpack(">H", self.__data.read(2))
354 # unsigned short, big-endian
355 while lenVariableName != 0:
356 variableName = self.__data.read(lenVariableName)
357 variableName = variableName.decode("utf-8", "replace")
358 variableType = self.__data.read(1)
359 if variableType == self.Number:
360 self.__parseNumber(variableName, value)
361 elif variableType == self.Boolean:
362 self.__parseBoolean(variableName, value)
363 elif variableType == self.String:
364 self.__parseString(variableName, value)
365 elif variableType == self.ObjObj:
366 self.__parseObject(variableName, value)
367 elif variableType == self.ObjArr:
368 self.__parseArray(variableName, value)
369 elif variableType == self.ObjDate:
370 self.__parseDate(variableName, value)
371 elif variableType == self.ObjXml:
372 self.__parseXml(variableName, value)
373 elif variableType == self.ObjCc:
374 self.__parseOcc(variableName, value)
375 elif variableType == self.ObjM:
376 self.__parseOjm(variableName, value)
377 elif variableType == self.Null:
378 self.__parseNull(variableName, value)
379 elif variableType == self.Undef:
380 self.__parseUndefined(variableName, value)
381 else:
382 raise FlashCookieReaderError(
383 "Unexpected Data Type: " + hex(ord(variableType)))
384 lenVariableName, = struct.unpack(">H", self.__data.read(2))
385 self.__data.read(1) # '\x09'
386
387 def __parseOcc(self, variableName, parent):
388 """
389 Private method to parse a c_object.
390
391 @param variableName name of the variable to be parsed
392 @type str
393 @param parent reference to the dictionary to insert the result into
394 @type dict
395 @exception FlashCookieReaderError raised when an issue with the cookie
396 file is found
397 """
398 lenCname = struct.unpack(">H", self.__data.read(2))
399 # unsigned short, big-endian
400 cname = self.__data.read(lenCname)
401 cname = cname.decode("utf-8", "replace")
402
403 value = {}
404 parent[variableName] = ("c_object; cname={0}".format(cname), value)
405
406 lenVariableName, = struct.unpack(">H", self.__data.read(2))
407 # unsigned short, big-endian
408 while lenVariableName != 0:
409 variableName = self.__data.read(lenVariableName)
410 variableName = variableName.decode("utf-8", "replace")
411 variableType = self.__data.read(1)
412 if variableType == self.Number:
413 self.__parseNumber(variableName, value)
414 elif variableType == self.Boolean:
415 self.__parseBoolean(variableName, value)
416 elif variableType == self.String:
417 self.__parseString(variableName, value)
418 elif variableType == self.ObjObj:
419 self.__parseObject(variableName, value)
420 elif variableType == self.ObjArr:
421 self.__parseArray(variableName, value)
422 elif variableType == self.ObjDate:
423 self.__parseDate(variableName, value)
424 elif variableType == self.ObjXml:
425 self.__parseXml(variableName, value)
426 elif variableType == self.ObjCc:
427 self.__parseOcc(variableName, value)
428 elif variableType == self.ObjM:
429 self.__parseOjm(variableName, value)
430 elif variableType == self.Null:
431 self.__parseNull(variableName, value)
432 elif variableType == self.Undef:
433 self.__parseUndefined(variableName, value)
434 else:
435 raise FlashCookieReaderError(
436 "Unexpected Data Type: " + hex(ord(variableType)))
437 lenVariableName, = struct.unpack(">H", self.__data.read(2))
438 self.__data.read(1) # '\x09'
439
440 def toString(self, indent=0, parent=None):
441 """
442 Public method to convert the parsed cookie to a string representation.
443
444 @param indent indentation level
445 @type int
446 @param parent reference to the dictionary to be converted
447 @type dict
448 @return string representation of the cookie
449 @rtype str
450 """
451 indentStr = " " * indent
452 strArr = []
453
454 if parent is None:
455 parent = self.__result
456
457 if not parent:
458 return ""
459
460 for variableName in sorted(parent.keys()):
461 variableType, value = parent[variableName]
462 if isinstance(value, dict):
463 resultStr = self.toString(indent + 1, value)
464 if resultStr:
465 strArr.append("{0}{1}:\n{2}"
466 .format(indentStr, variableName, resultStr))
467 else:
468 strArr.append("{0}{1}:"
469 .format(indentStr, variableName))
470 else:
471 strArr.append("{0}{1}: {2}"
472 .format(indentStr, variableName, value))
473
474 return "\n".join(strArr)

eric ide

mercurial