mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-04 18:33:38 +00:00
980e05cc99
Backported 400 revisions from rev 1de4961-8897c5b (2018-2014). Move core/benchmark, core/cmd_line, core/memory, core/profiler and core/timeout to core/optional/* Remove metadata/qt* PORT: Version 2.0a3 (inline with 3.0a3 @ f80c7d5). Basic Support for XMP Packets. tga: improvements to adhere more closely to the spec. pdf: slightly improved parsing. rar: fix TypeError on unknown block types. Add MacRoman win32 codepage. tiff/exif: support SubIFDs and tiled images. Add method to export metadata in dictionary. mpeg_video: don't attempt to parse Stream past length. mpeg_video: parse ESCR correctly, add SCR value. Change centralise CustomFragments. field: don't set parser class if class is None, to enable autodetect. field: add value/display for CustomFragment. parser: inline warning to enable tracebacks in debug mode. Fix empty bytestrings in makePrintable. Fix contentSize in jpeg.py to account for image_data blocks. Fix the ELF parser. Enhance the AR archive parser. elf parser: fix wrong wrong fields order in parsing little endian section flags. elf parser: add s390 as a machine type. Flesh out mp4 parser. PORT: Version 2.0a1 (inline with 3.0a1). Major refactoring and PEP8. Fix ResourceWarning warnings on files. Add a close() method and support for the context manager protocol ("with obj: ...") to parsers, input and output streams. metadata: get comment from ZIP. Support for InputIOStream.read(0). Fix sizeGe when size is None. Remove unused new_seekable_field_set file. Remove parser Mapsforge .map. Remove parser Parallel Realities Starfighter .pak files. sevenzip: fix for newer archives. java: update access flags and modifiers for Java 1.7 and update description text for most recent Java. Support ustar prefix field in tar archives. Remove file_system* parsers. Remove misc parsers 3d0, 3ds, gnome_keyring, msoffice*, mstask, ole*, word*. Remove program parsers macho, nds, prc. Support non-8bit Character subclasses. Python parser supports Python 3.7. Enhance mpeg_ts parser to support MTS/M2TS. Support for creation date in tiff. Change don't hardcode errno constant. PORT: 1.9.1 Internal Only: The following are legacy reference to upstream commit messages. Relevant changes up to b0a115f8. Use integer division. Replace HACHOIR_ERRORS with Exception. Fix metadata.Data: make it sortable. Import fixes from e7de492. PORT: Version 2.0a1 (inline with 3.0a1 @ e9f8fad). Replace hachoir.core.field with hachoir.field Replace hachoir.core.stream with hachoir.stream Remove the compatibility module for PY1.5 to PY2.5. metadata: support TIFF picture. metadata: fix string normalization. metadata: fix datetime regex Fix hachoir bug #57. FileFromInputStream: fix comparison between None and an int. InputIOStream: open the file in binary mode.
128 lines
4.6 KiB
Python
128 lines
4.6 KiB
Python
"""
|
|
Tar archive parser.
|
|
|
|
Author: Victor Stinner
|
|
"""
|
|
|
|
from hachoir.parser import Parser
|
|
from hachoir.field import (FieldSet,
|
|
Enum, UInt8, SubFile, String, NullBytes)
|
|
from hachoir.core.tools import humanFilesize, paddingSize, timestampUNIX
|
|
from hachoir.core.endian import BIG_ENDIAN
|
|
import re
|
|
|
|
|
|
class FileEntry(FieldSet):
|
|
type_name = {
|
|
# 48 is "0", 49 is "1", ...
|
|
0: u"Normal disk file (old format)",
|
|
48: u"Normal disk file",
|
|
49: u"Link to previously dumped file",
|
|
50: u"Symbolic link",
|
|
51: u"Character special file",
|
|
52: u"Block special file",
|
|
53: u"Directory",
|
|
54: u"FIFO special file",
|
|
55: u"Contiguous file"
|
|
}
|
|
|
|
def getOctal(self, name):
|
|
return self.octal2int(self[name].value)
|
|
|
|
def getDatetime(self):
|
|
"""
|
|
Create modification date as Unicode string, may raise ValueError.
|
|
"""
|
|
timestamp = self.getOctal("mtime")
|
|
return timestampUNIX(timestamp)
|
|
|
|
def createFields(self):
|
|
yield String(self, "name", 100, "Name", strip="\0", charset="ISO-8859-1")
|
|
yield String(self, "mode", 8, "Mode", strip=" \0", charset="ASCII")
|
|
yield String(self, "uid", 8, "User ID", strip=" \0", charset="ASCII")
|
|
yield String(self, "gid", 8, "Group ID", strip=" \0", charset="ASCII")
|
|
yield String(self, "size", 12, "Size", strip=" \0", charset="ASCII")
|
|
yield String(self, "mtime", 12, "Modification time", strip=" \0", charset="ASCII")
|
|
yield String(self, "check_sum", 8, "Check sum", strip=" \0", charset="ASCII")
|
|
yield Enum(UInt8(self, "type", "Type"), self.type_name)
|
|
yield String(self, "lname", 100, "Link name", strip=" \0", charset="ISO-8859-1")
|
|
yield String(self, "magic", 8, "Magic", strip=" \0", charset="ASCII")
|
|
yield String(self, "uname", 32, "User name", strip=" \0", charset="ISO-8859-1")
|
|
yield String(self, "gname", 32, "Group name", strip=" \0", charset="ISO-8859-1")
|
|
yield String(self, "devmajor", 8, "Dev major", strip=" \0", charset="ASCII")
|
|
yield String(self, "devminor", 8, "Dev minor", strip=" \0", charset="ASCII")
|
|
yield String(self, "prefix", 155, "Prefix for filename", strip="\0", charset="ASCII")
|
|
yield NullBytes(self, "padding", 12, "Padding (zero)")
|
|
|
|
filesize = self.getOctal("size")
|
|
if filesize:
|
|
yield SubFile(self, "content", filesize, filename=self["name"].value)
|
|
|
|
size = paddingSize(self.current_size // 8, 512)
|
|
if size:
|
|
yield NullBytes(self, "padding_end", size, "Padding (512 align)")
|
|
|
|
def convertOctal(self, chunk):
|
|
return self.octal2int(chunk.value)
|
|
|
|
def isEmpty(self):
|
|
return self["name"].value == ""
|
|
|
|
def octal2int(self, text):
|
|
try:
|
|
return int(text, 8)
|
|
except ValueError:
|
|
return 0
|
|
|
|
def createDescription(self):
|
|
if self.isEmpty():
|
|
desc = "(terminator, empty header)"
|
|
else:
|
|
filename = self["name"].value
|
|
if self["prefix"].value:
|
|
filename = self["prefix"].value + '/' + filename
|
|
filesize = humanFilesize(self.getOctal("size"))
|
|
desc = "(%s: %s, %s)" % \
|
|
(filename, self["type"].display, filesize)
|
|
return "Tar File " + desc
|
|
|
|
|
|
class TarFile(Parser):
|
|
endian = BIG_ENDIAN
|
|
PARSER_TAGS = {
|
|
"id": "tar",
|
|
"category": "archive",
|
|
"file_ext": ("tar",),
|
|
"mime": (u"application/x-tar", u"application/x-gtar"),
|
|
"min_size": 512 * 8,
|
|
"magic": (("ustar \0", 257 * 8),),
|
|
"subfile": "skip",
|
|
"description": "TAR archive",
|
|
}
|
|
_sign = re.compile("ustar *\0|[ \0]*$")
|
|
|
|
def validate(self):
|
|
if not self._sign.match(self.stream.readBytes(257 * 8, 8)):
|
|
return "Invalid magic number"
|
|
if self[0].name == "terminator":
|
|
return "Don't contain any file"
|
|
try:
|
|
int(self["file[0]/uid"].value, 8)
|
|
int(self["file[0]/gid"].value, 8)
|
|
int(self["file[0]/size"].value, 8)
|
|
except ValueError:
|
|
return "Invalid file size"
|
|
return True
|
|
|
|
def createFields(self):
|
|
while not self.eof:
|
|
field = FileEntry(self, "file[]")
|
|
if field.isEmpty():
|
|
yield NullBytes(self, "terminator", 512)
|
|
break
|
|
yield field
|
|
if self.current_size < self._size:
|
|
yield self.seekBit(self._size, "end")
|
|
|
|
def createContentSize(self):
|
|
return self["terminator"].address + self["terminator"].size
|