from hachoir.field import Bytes from hachoir.core.tools import makePrintable, humanFilesize from hachoir.stream import InputIOStream class SubFile(Bytes): """ File stored in another file """ def __init__(self, parent, name, length, description=None, parser=None, filename=None, mime_type=None, parser_class=None): if filename: if not isinstance(filename, str): filename = makePrintable(filename, "ISO-8859-1") if not description: description = 'File "%s" (%s)' % ( filename, humanFilesize(length)) Bytes.__init__(self, parent, name, length, description) def createInputStream(cis, **args): tags = args.setdefault("tags", []) if parser_class: tags.append(("class", parser_class)) if parser is not None: tags.append(("id", parser.PARSER_TAGS["id"])) if mime_type: tags.append(("mime", mime_type)) if filename: tags.append(("filename", filename)) return cis(**args) self.setSubIStream(createInputStream) class CompressedStream: offset = 0 def __init__(self, stream, decompressor): self.stream = stream self.decompressor = decompressor(stream) self._buffer = b'' def read(self, size): d = self._buffer data = [d[:size]] size -= len(d) if size > 0: d = self.decompressor(size) data.append(d[:size]) size -= len(d) while size > 0: n = 4096 if self.stream.size: n = min(self.stream.size - self.offset, n) if not n: break d = self.stream.read(self.offset, n)[1] self.offset += 8 * len(d) d = self.decompressor(size, d) data.append(d[:size]) size -= len(d) self._buffer = d[size + len(d):] return b''.join(data) def CompressedField(field, decompressor): def createInputStream(cis, source=None, **args): if field._parent: stream = cis(source=source) args.setdefault("tags", []).extend(stream.tags) else: stream = field.stream input = CompressedStream(stream, decompressor) if source is None: source = "Compressed source: '%s' (offset=%s)" % ( stream.source, field.absolute_address) return InputIOStream(input, source=source, **args) field.setSubIStream(createInputStream) return field