mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-22 10:43:38 +00:00
182 lines
6.1 KiB
Python
182 lines
6.1 KiB
Python
from hachoir.field import (FieldSet,
|
|
UInt16, UInt32, Enum, String, Bytes, Bits, TimestampUUID60)
|
|
from hachoir.parser.video.fourcc import video_fourcc_name
|
|
from hachoir.core.bits import str2hex
|
|
from hachoir.core.text_handler import textHandler, hexadecimal
|
|
from hachoir.parser.network.common import MAC48_Address
|
|
|
|
# Dictionary: Windows codepage => Python charset name
|
|
CODEPAGE_CHARSET = {
|
|
874: "CP874",
|
|
# 932: Japanese Shift-JIS
|
|
# 936: Simplified Chinese GBK
|
|
# 949: Korean
|
|
# 950: Traditional Chinese Big5
|
|
1250: "WINDOWS-1250",
|
|
1251: "WINDOWS-1251",
|
|
1252: "WINDOWS-1252",
|
|
1253: "WINDOWS-1253",
|
|
1254: "WINDOWS-1254",
|
|
1255: "WINDOWS-1255",
|
|
1256: "WINDOWS-1256",
|
|
1257: "WINDOWS-1257",
|
|
1258: "WINDOWS-1258",
|
|
10000: "MacRoman",
|
|
65001: "UTF-8",
|
|
}
|
|
|
|
|
|
class PascalStringWin16(FieldSet):
|
|
|
|
def __init__(self, parent, name, description=None, strip=None, charset="UTF-16-LE"):
|
|
FieldSet.__init__(self, parent, name, description)
|
|
length = self["length"].value
|
|
self._size = 16 + length * 16
|
|
self.strip = strip
|
|
self.charset = charset
|
|
|
|
def createFields(self):
|
|
yield UInt16(self, "length", "Length in widechar characters")
|
|
size = self["length"].value
|
|
if size:
|
|
yield String(self, "text", size * 2, charset=self.charset, strip=self.strip)
|
|
|
|
def createValue(self):
|
|
if "text" in self:
|
|
return self["text"].value
|
|
else:
|
|
return None
|
|
|
|
|
|
class PascalStringWin32(FieldSet):
|
|
|
|
def __init__(self, parent, name, description=None, strip=None, charset="UTF-16-LE"):
|
|
FieldSet.__init__(self, parent, name, description)
|
|
length = self["length"].value
|
|
self._size = 32 + length * 16
|
|
self.strip = strip
|
|
self.charset = charset
|
|
|
|
def createFields(self):
|
|
yield UInt32(self, "length", "Length in widechar characters")
|
|
size = self["length"].value
|
|
if size:
|
|
yield String(self, "text", size * 2, charset=self.charset, strip=self.strip)
|
|
|
|
def createValue(self):
|
|
if "text" in self:
|
|
return self["text"].value
|
|
else:
|
|
return None
|
|
|
|
|
|
class GUID(FieldSet):
|
|
"""
|
|
Windows 128 bits Globally Unique Identifier (GUID)
|
|
|
|
See RFC 4122
|
|
"""
|
|
static_size = 128
|
|
NULL = "00000000-0000-0000-0000-000000000000"
|
|
FIELD_NAMES = {
|
|
3: ("sha1_high", "sha1_low"),
|
|
4: ("random_high", "random_low"),
|
|
5: ("md5_high", "md5_low"),
|
|
}
|
|
VERSION_NAME = {
|
|
1: "Timestamp & MAC-48",
|
|
2: "DCE Security version",
|
|
3: "Name SHA-1 hash",
|
|
4: "Randomly generated",
|
|
5: "Name MD5 hash",
|
|
}
|
|
VARIANT_NAME = {
|
|
0: "NCS",
|
|
2: "Leach-Salz",
|
|
# 5: Microsoft Corporation?
|
|
6: "Microsoft Corporation",
|
|
7: "Reserved Future",
|
|
}
|
|
|
|
def __init__(self, *args):
|
|
FieldSet.__init__(self, *args)
|
|
self.version = self.stream.readBits(
|
|
self.absolute_address + 32 + 16 + 12, 4, self.endian)
|
|
|
|
def createFields(self):
|
|
if self.version == 1:
|
|
yield TimestampUUID60(self, "time")
|
|
yield Enum(Bits(self, "version", 4), self.VERSION_NAME)
|
|
yield Enum(Bits(self, "variant", 3), self.VARIANT_NAME)
|
|
yield textHandler(Bits(self, "clock", 13), hexadecimal)
|
|
# yield textHandler(Bits(self, "clock", 16), hexadecimal)
|
|
if self.version == 1:
|
|
yield MAC48_Address(self, "mac", "IEEE 802 MAC address")
|
|
else:
|
|
yield Bytes(self, "node", 6)
|
|
else:
|
|
namea, nameb = self.FIELD_NAMES.get(
|
|
self.version, ("data_a", "data_b"))
|
|
yield textHandler(Bits(self, namea, 60), hexadecimal)
|
|
yield Enum(Bits(self, "version", 4), self.VERSION_NAME)
|
|
yield Enum(Bits(self, "variant", 3), self.VARIANT_NAME)
|
|
yield textHandler(Bits(self, nameb, 61), hexadecimal)
|
|
|
|
def createValue(self):
|
|
addr = self.absolute_address
|
|
a = self.stream.readBits(addr, 32, self.endian)
|
|
b = self.stream.readBits(addr + 32, 16, self.endian)
|
|
c = self.stream.readBits(addr + 48, 16, self.endian)
|
|
d = self.stream.readBytes(addr + 64, 2)
|
|
e = self.stream.readBytes(addr + 80, 6)
|
|
return "%08X-%04X-%04X-%s-%s" % (a, b, c, str2hex(d), str2hex(e))
|
|
|
|
def createDisplay(self):
|
|
value = self.value
|
|
if value == self.NULL:
|
|
name = "Null GUID: "
|
|
else:
|
|
name = "GUID v%u (%s): " % (self.version, self["version"].display)
|
|
return name + value
|
|
|
|
def createRawDisplay(self):
|
|
value = self.stream.readBytes(self.absolute_address, 16)
|
|
return str2hex(value, format=r"\x%02x")
|
|
|
|
|
|
class BitmapInfoHeader(FieldSet):
|
|
""" Win32 BITMAPINFOHEADER structure from GDI """
|
|
static_size = 40 * 8
|
|
|
|
COMPRESSION_NAME = {
|
|
0: "Uncompressed (RGB)",
|
|
1: "RLE (8 bits)",
|
|
2: "RLE (4 bits)",
|
|
3: "Bitfields",
|
|
4: "JPEG",
|
|
5: "PNG"
|
|
}
|
|
|
|
def __init__(self, parent, name, use_fourcc=False):
|
|
FieldSet.__init__(self, parent, name)
|
|
self._use_fourcc = use_fourcc
|
|
|
|
def createFields(self):
|
|
yield UInt32(self, "hdr_size", "Header size (in bytes) (=40)")
|
|
yield UInt32(self, "width", "Width")
|
|
yield UInt32(self, "height", "Height")
|
|
yield UInt16(self, "nb_planes", "Color planes")
|
|
yield UInt16(self, "bpp", "Bits/pixel")
|
|
if self._use_fourcc:
|
|
yield Enum(String(self, "codec", 4, charset="ASCII"), video_fourcc_name)
|
|
else:
|
|
yield Enum(UInt32(self, "codec", "Compression"), self.COMPRESSION_NAME)
|
|
yield UInt32(self, "size", "Image size (in bytes)")
|
|
yield UInt32(self, "xres", "X pixels per meter")
|
|
yield UInt32(self, "yres", "Y pixels per meter")
|
|
yield UInt32(self, "color_used", "Number of used colors")
|
|
yield UInt32(self, "color_important", "Number of important colors")
|
|
|
|
def createDescription(self):
|
|
return "Bitmap info header: %ux%u pixels, %u bits/pixel" % \
|
|
(self["width"].value, self["height"].value, self["bpp"].value)
|