mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-01 08:53:37 +00:00
0d9fbc1ad7
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!
125 lines
4.5 KiB
Python
125 lines
4.5 KiB
Python
"""
|
|
Microsoft Cabinet (CAB) archive.
|
|
|
|
Author: Victor Stinner
|
|
Creation date: 31 january 2007
|
|
"""
|
|
|
|
from lib.hachoir_parser import Parser
|
|
from lib.hachoir_core.field import (FieldSet, Enum,
|
|
CString, String,
|
|
UInt16, UInt32, Bit, Bits, PaddingBits, NullBits,
|
|
DateTimeMSDOS32, RawBytes)
|
|
from lib.hachoir_parser.common.msdos import MSDOSFileAttr16
|
|
from lib.hachoir_core.text_handler import textHandler, hexadecimal, filesizeHandler
|
|
from lib.hachoir_core.endian import LITTLE_ENDIAN
|
|
|
|
MAX_NB_FOLDER = 30
|
|
|
|
COMPRESSION_NONE = 0
|
|
COMPRESSION_NAME = {
|
|
0: "Uncompressed",
|
|
1: "Deflate",
|
|
2: "Quantum",
|
|
3: "LZX",
|
|
}
|
|
|
|
class Folder(FieldSet):
|
|
def createFields(self):
|
|
yield UInt32(self, "off_data", "Offset of data")
|
|
yield UInt16(self, "cf_data")
|
|
yield Enum(Bits(self, "compr_method", 4, "Compression method"), COMPRESSION_NAME)
|
|
yield Bits(self, "compr_level", 5, "Compression level")
|
|
yield PaddingBits(self, "padding", 7)
|
|
|
|
def createDescription(self):
|
|
text= "Folder: compression %s" % self["compr_method"].display
|
|
if self["compr_method"].value != COMPRESSION_NONE:
|
|
text += " (level %u)" % self["compr_level"].value
|
|
return text
|
|
|
|
class File(FieldSet):
|
|
def createFields(self):
|
|
yield filesizeHandler(UInt32(self, "filesize", "Uncompressed file size"))
|
|
yield UInt32(self, "offset", "File offset after decompression")
|
|
yield UInt16(self, "iFolder", "file control id")
|
|
yield DateTimeMSDOS32(self, "timestamp")
|
|
yield MSDOSFileAttr16(self, "attributes")
|
|
yield CString(self, "filename", charset="ASCII")
|
|
|
|
def createDescription(self):
|
|
return "File %s (%s)" % (
|
|
self["filename"].display, self["filesize"].display)
|
|
|
|
class Reserved(FieldSet):
|
|
def createFields(self):
|
|
yield UInt32(self, "size")
|
|
size = self["size"].value
|
|
if size:
|
|
yield RawBytes(self, "data", size)
|
|
|
|
class Flags(FieldSet):
|
|
static_size = 16
|
|
def createFields(self):
|
|
yield Bit(self, "has_previous")
|
|
yield Bit(self, "has_next")
|
|
yield Bit(self, "has_reserved")
|
|
yield NullBits(self, "padding", 13)
|
|
|
|
class CabFile(Parser):
|
|
endian = LITTLE_ENDIAN
|
|
MAGIC = "MSCF"
|
|
PARSER_TAGS = {
|
|
"id": "cab",
|
|
"category": "archive",
|
|
"file_ext": ("cab",),
|
|
"mime": (u"application/vnd.ms-cab-compressed",),
|
|
"magic": ((MAGIC, 0),),
|
|
"min_size": 1*8, # header + file entry
|
|
"description": "Microsoft Cabinet archive"
|
|
}
|
|
|
|
def validate(self):
|
|
if self.stream.readBytes(0, 4) != self.MAGIC:
|
|
return "Invalid magic"
|
|
if self["cab_version"].value != 0x0103:
|
|
return "Unknown version (%s)" % self["cab_version"].display
|
|
if not (1 <= self["nb_folder"].value <= MAX_NB_FOLDER):
|
|
return "Invalid number of folder (%s)" % self["nb_folder"].value
|
|
return True
|
|
|
|
def createFields(self):
|
|
yield String(self, "magic", 4, "Magic (MSCF)", charset="ASCII")
|
|
yield textHandler(UInt32(self, "hdr_checksum", "Header checksum (0 if not used)"), hexadecimal)
|
|
yield filesizeHandler(UInt32(self, "filesize", "Cabinet file size"))
|
|
yield textHandler(UInt32(self, "fld_checksum", "Folders checksum (0 if not used)"), hexadecimal)
|
|
yield UInt32(self, "off_file", "Offset of first file")
|
|
yield textHandler(UInt32(self, "files_checksum", "Files checksum (0 if not used)"), hexadecimal)
|
|
yield textHandler(UInt16(self, "cab_version", "Cabinet version"), hexadecimal)
|
|
yield UInt16(self, "nb_folder", "Number of folders")
|
|
yield UInt16(self, "nb_files", "Number of files")
|
|
yield Flags(self, "flags")
|
|
yield UInt16(self, "setid")
|
|
yield UInt16(self, "number", "Zero-based cabinet number")
|
|
|
|
# --- TODO: Support flags
|
|
if self["flags/has_reserved"].value:
|
|
yield Reserved(self, "reserved")
|
|
#(3) Previous cabinet name, if CAB_HEADER.flags & CAB_FLAG_HASPREV
|
|
#(4) Previous disk name, if CAB_HEADER.flags & CAB_FLAG_HASPREV
|
|
#(5) Next cabinet name, if CAB_HEADER.flags & CAB_FLAG_HASNEXT
|
|
#(6) Next disk name, if CAB_HEADER.flags & CAB_FLAG_HASNEXT
|
|
# ----
|
|
|
|
for index in xrange(self["nb_folder"].value):
|
|
yield Folder(self, "folder[]")
|
|
for index in xrange(self["nb_files"].value):
|
|
yield File(self, "file[]")
|
|
|
|
end = self.seekBit(self.size, "endraw")
|
|
if end:
|
|
yield end
|
|
|
|
def createContentSize(self):
|
|
return self["filesize"].value * 8
|
|
|