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: u"Uncompressed (RGB)", 1: u"RLE (8 bits)", 2: u"RLE (4 bits)", 3: u"Bitfields", 4: u"JPEG", 5: u"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)