SickGear/lib/hachoir_parser/program/python.py
echel0n 0d9fbc1ad7 Welcome to our SickBeard-TVRage Edition ...
This version of SickBeard uses both TVDB and TVRage to search and gather it's series data from allowing you to now have access to and download shows that you couldn't before because of being locked into only what TheTVDB had to offer.

Also this edition is based off the code we used in our XEM editon so it does come with scene numbering support as well as all the other features our XEM edition has to offer.

Please before using this with your existing database (sickbeard.db) please make a backup copy of it and delete any other database files such as cache.db and failed.db if present, we HIGHLY recommend starting out with no database files at all to make this a fresh start but the choice is at your own risk!

Enjoy!
2014-03-09 22:39:12 -07:00

334 lines
12 KiB
Python

"""
Python compiled source code parser.
Informations:
- Python 2.4.2 source code:
files Python/marshal.c and Python/import.c
Author: Victor Stinner
Creation: 25 march 2005
"""
DISASSEMBLE = False
from lib.hachoir_parser import Parser
from lib.hachoir_core.field import (FieldSet, UInt8,
UInt16, Int32, UInt32, Int64, ParserError, Float64, Enum,
Character, Bytes, RawBytes, PascalString8, TimestampUnix32)
from lib.hachoir_core.endian import LITTLE_ENDIAN
from lib.hachoir_core.bits import long2raw
from lib.hachoir_core.text_handler import textHandler, hexadecimal
from lib.hachoir_core.i18n import ngettext
if DISASSEMBLE:
from dis import dis
def disassembleBytecode(field):
bytecode = field.value
dis(bytecode)
# --- String and string reference ---
def parseString(parent):
yield UInt32(parent, "length", "Length")
length = parent["length"].value
if parent.name == "lnotab":
bytecode_offset=0
line_number=parent['../firstlineno'].value
for i in range(0,length,2):
bc_off_delta=UInt8(parent, 'bytecode_offset_delta[]')
yield bc_off_delta
bytecode_offset+=bc_off_delta.value
bc_off_delta._description='Bytecode Offset %i'%bytecode_offset
line_number_delta=UInt8(parent, 'line_number_delta[]')
yield line_number_delta
line_number+=line_number_delta.value
line_number_delta._description='Line Number %i'%line_number
elif 0 < length:
yield RawBytes(parent, "text", length, "Content")
if DISASSEMBLE and parent.name == "compiled_code":
disassembleBytecode(parent["text"])
def parseStringRef(parent):
yield textHandler(UInt32(parent, "ref"), hexadecimal)
def createStringRefDesc(parent):
return "String ref: %s" % parent["ref"].display
# --- Integers ---
def parseInt32(parent):
yield Int32(parent, "value")
def parseInt64(parent):
yield Int64(parent, "value")
def parseLong(parent):
yield Int32(parent, "digit_count")
for index in xrange( abs(parent["digit_count"].value) ):
yield UInt16(parent, "digit[]")
# --- Float and complex ---
def parseFloat(parent):
yield PascalString8(parent, "value")
def parseBinaryFloat(parent):
yield Float64(parent, "value")
def parseComplex(parent):
yield PascalString8(parent, "real")
yield PascalString8(parent, "complex")
def parseBinaryComplex(parent):
yield Float64(parent, "real")
yield Float64(parent, "complex")
# --- Tuple and list ---
def parseTuple(parent):
yield Int32(parent, "count", "Item count")
count = parent["count"].value
if count < 0:
raise ParserError("Invalid tuple/list count")
for index in xrange(count):
yield Object(parent, "item[]")
def createTupleDesc(parent):
count = parent["count"].value
items = ngettext("%s item", "%s items", count) % count
return "%s: %s" % (parent.code_info[2], items)
# --- Dict ---
def parseDict(parent):
"""
Format is: (key1, value1, key2, value2, ..., keyn, valuen, NULL)
where each keyi and valuei is an object.
"""
parent.count = 0
while True:
key = Object(parent, "key[]")
yield key
if key["bytecode"].value == "0":
break
yield Object(parent, "value[]")
parent.count += 1
def createDictDesc(parent):
return "Dict: %s" % (ngettext("%s key", "%s keys", parent.count) % parent.count)
# --- Code ---
def parseCode(parent):
if 0x3000000 <= parent.root.getVersion():
yield UInt32(parent, "arg_count", "Argument count")
yield UInt32(parent, "kwonlyargcount", "Keyword only argument count")
yield UInt32(parent, "nb_locals", "Number of local variables")
yield UInt32(parent, "stack_size", "Stack size")
yield UInt32(parent, "flags")
elif 0x2030000 <= parent.root.getVersion():
yield UInt32(parent, "arg_count", "Argument count")
yield UInt32(parent, "nb_locals", "Number of local variables")
yield UInt32(parent, "stack_size", "Stack size")
yield UInt32(parent, "flags")
else:
yield UInt16(parent, "arg_count", "Argument count")
yield UInt16(parent, "nb_locals", "Number of local variables")
yield UInt16(parent, "stack_size", "Stack size")
yield UInt16(parent, "flags")
yield Object(parent, "compiled_code")
yield Object(parent, "consts")
yield Object(parent, "names")
yield Object(parent, "varnames")
if 0x2000000 <= parent.root.getVersion():
yield Object(parent, "freevars")
yield Object(parent, "cellvars")
yield Object(parent, "filename")
yield Object(parent, "name")
if 0x2030000 <= parent.root.getVersion():
yield UInt32(parent, "firstlineno", "First line number")
else:
yield UInt16(parent, "firstlineno", "First line number")
yield Object(parent, "lnotab")
class Object(FieldSet):
bytecode_info = {
# Don't contains any data
'0': ("null", None, "NULL", None),
'N': ("none", None, "None", None),
'F': ("false", None, "False", None),
'T': ("true", None, "True", None),
'S': ("stop_iter", None, "StopIter", None),
'.': ("ellipsis", None, "ELLIPSIS", None),
'?': ("unknown", None, "Unknown", None),
'i': ("int32", parseInt32, "Int32", None),
'I': ("int64", parseInt64, "Int64", None),
'f': ("float", parseFloat, "Float", None),
'g': ("bin_float", parseBinaryFloat, "Binary float", None),
'x': ("complex", parseComplex, "Complex", None),
'y': ("bin_complex", parseBinaryComplex, "Binary complex", None),
'l': ("long", parseLong, "Long", None),
's': ("string", parseString, "String", None),
't': ("interned", parseString, "Interned", None),
'u': ("unicode", parseString, "Unicode", None),
'R': ("string_ref", parseStringRef, "String ref", createStringRefDesc),
'(': ("tuple", parseTuple, "Tuple", createTupleDesc),
'[': ("list", parseTuple, "List", createTupleDesc),
'<': ("set", parseTuple, "Set", createTupleDesc),
'>': ("frozenset", parseTuple, "Frozen set", createTupleDesc),
'{': ("dict", parseDict, "Dict", createDictDesc),
'c': ("code", parseCode, "Code", None),
}
def __init__(self, parent, name, **kw):
FieldSet.__init__(self, parent, name, **kw)
code = self["bytecode"].value
if code not in self.bytecode_info:
raise ParserError('Unknown bytecode: "%s"' % code)
self.code_info = self.bytecode_info[code]
if not name:
self._name = self.code_info[0]
if code == "l":
self.createValue = self.createValueLong
elif code in ("i", "I", "f", "g"):
self.createValue = lambda: self["value"].value
elif code == "T":
self.createValue = lambda: True
elif code == "F":
self.createValue = lambda: False
elif code in ("x", "y"):
self.createValue = self.createValueComplex
elif code in ("s", "t", "u"):
self.createValue = self.createValueString
self.createDisplay = self.createDisplayString
if code == 't':
if not hasattr(self.root,'string_table'):
self.root.string_table=[]
self.root.string_table.append(self)
elif code == 'R':
if hasattr(self.root,'string_table'):
self.createValue = self.createValueStringRef
def createValueString(self):
if "text" in self:
return self["text"].value
else:
return ""
def createDisplayString(self):
if "text" in self:
return self["text"].display
else:
return "(empty)"
def createValueLong(self):
is_negative = self["digit_count"].value < 0
count = abs(self["digit_count"].value)
total = 0
for index in xrange(count-1, -1, -1):
total <<= 15
total += self["digit[%u]" % index].value
if is_negative:
total = -total
return total
def createValueStringRef(self):
return self.root.string_table[self['ref'].value].value
def createDisplayStringRef(self):
return self.root.string_table[self['ref'].value].display
def createValueComplex(self):
return complex(
float(self["real"].value),
float(self["complex"].value))
def createFields(self):
yield Character(self, "bytecode", "Bytecode")
parser = self.code_info[1]
if parser:
for field in parser(self):
yield field
def createDescription(self):
create = self.code_info[3]
if create:
return create(self)
else:
return self.code_info[2]
class PythonCompiledFile(Parser):
PARSER_TAGS = {
"id": "python",
"category": "program",
"file_ext": ("pyc", "pyo"),
"min_size": 9*8,
"description": "Compiled Python script (.pyc/.pyo files)"
}
endian = LITTLE_ENDIAN
# Dictionnary which associate the pyc signature (32-bit integer)
# to a Python version string (eg. "m\xf2\r\n" => "Python 2.4b1").
# This list comes from CPython source code, see "MAGIC"
# and "pyc_magic" in file Python/import.c
MAGIC = {
# Python 1.x
20121: ("1.5", 0x1050000),
# Python 2.x
50823: ("2.0", 0x2000000),
60202: ("2.1", 0x2010000),
60717: ("2.2", 0x2020000),
62011: ("2.3a0", 0x2030000),
62021: ("2.3a0", 0x2030000),
62041: ("2.4a0", 0x2040000),
62051: ("2.4a3", 0x2040000),
62061: ("2.4b1", 0x2040000),
62071: ("2.5a0", 0x2050000),
62081: ("2.5a0 (ast-branch)", 0x2050000),
62091: ("2.5a0 (with)", 0x2050000),
62092: ("2.5a0 (WITH_CLEANUP opcode)", 0x2050000),
62101: ("2.5b3", 0x2050000),
62111: ("2.5b3", 0x2050000),
62121: ("2.5c1", 0x2050000),
62131: ("2.5c2", 0x2050000),
# Python 3.x
3000: ("3.0 (3000)", 0x3000000),
3010: ("3.0 (3010)", 0x3000000),
3020: ("3.0 (3020)", 0x3000000),
3030: ("3.0 (3030)", 0x3000000),
3040: ("3.0 (3040)", 0x3000000),
3050: ("3.0 (3050)", 0x3000000),
3060: ("3.0 (3060)", 0x3000000),
3070: ("3.0 (3070)", 0x3000000),
3080: ("3.0 (3080)", 0x3000000),
3090: ("3.0 (3090)", 0x3000000),
3100: ("3.0 (3100)", 0x3000000),
3102: ("3.0 (3102)", 0x3000000),
3110: ("3.0a4", 0x3000000),
3130: ("3.0a5", 0x3000000),
3131: ("3.0a5 unicode", 0x3000000),
}
# Dictionnary which associate the pyc signature (4-byte long string)
# to a Python version string (eg. "m\xf2\r\n" => "2.4b1")
STR_MAGIC = dict( \
(long2raw(magic | (ord('\r')<<16) | (ord('\n')<<24), LITTLE_ENDIAN), value[0]) \
for magic, value in MAGIC.iteritems())
def validate(self):
signature = self.stream.readBits(0, 16, self.endian)
if signature not in self.MAGIC:
return "Unknown version (%s)" % signature
if self.stream.readBytes(2*8, 2) != "\r\n":
return r"Wrong signature (\r\n)"
if self.stream.readBytes(8*8, 1) != 'c':
return "First object bytecode is not code"
return True
def getVersion(self):
if not hasattr(self, "version"):
signature = self.stream.readBits(0, 16, self.endian)
self.version = self.MAGIC[signature][1]
return self.version
def createFields(self):
yield Enum(Bytes(self, "signature", 4, "Python file signature and version"), self.STR_MAGIC)
yield TimestampUnix32(self, "timestamp", "Timestamp")
yield Object(self, "content")