eric6/WebBrowser/FlashCookieManager/FlashCookieReader.py

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

eric ide

mercurial