def _get_lzma_decompressor(self, coders: List[Dict[str, Any]], unpacksize: int): filters: List[Dict[str, Any]] = [] lzma1 = False for coder in coders: if coder["numinstreams"] != 1 or coder["numoutstreams"] != 1: raise UnsupportedCompressionMethodError( coders, "Only a simple compression method is currently supported.") if not SupportedMethods.is_native_coder(coder): raise UnsupportedCompressionMethodError( coders, "Non python native method is requested.") properties = coder.get("properties", None) filter_id = SupportedMethods.get_filter_id(coder) if filter_id == FILTER_LZMA: lzma1 = True if properties is not None: filters[:0] = [ lzma._decode_filter_properties(filter_id, properties) ] # type: ignore else: filters[:0] = [{"id": filter_id}] if lzma1: return LZMA1Decompressor(filters, unpacksize) else: return lzma.LZMADecompressor(format=lzma.FORMAT_RAW, filters=filters)
def _get_alternative_decompressor( self, coder: Dict[str, Any], unpacksize=None, password=None ) -> Union[bz2.BZ2Decompressor, lzma.LZMADecompressor, ISevenZipDecompressor]: # noqa filter_id = SupportedMethods.get_filter_id(coder) # Special treatment for BCJ filters if filter_id in [ FILTER_X86, FILTER_ARM, FILTER_ARMTHUMB, FILTER_POWERPC, FILTER_SPARC ]: return algorithm_class_map[filter_id][1](size=unpacksize) # Check supported? if SupportedMethods.is_native_coder(coder): raise UnsupportedCompressionMethodError( 'Unknown method code:{}'.format(coder['method'])) if filter_id not in algorithm_class_map: raise UnsupportedCompressionMethodError( 'Unknown method filter_id:{}'.format(filter_id)) # if SupportedMethods.is_crypto_id(filter_id): return algorithm_class_map[filter_id][1](coder['properties'], password) elif SupportedMethods.need_property(filter_id): return algorithm_class_map[filter_id][1](coder['properties']) else: return algorithm_class_map[filter_id][1]()
def __init__(self, properties: bytes, blocksize: int): if len(properties) not in [3, 5]: raise UnsupportedCompressionMethodError( properties, "Zstd takes 3 or 5 bytes properties.") if (properties[0], properties[1], 0) > pyzstd.zstd_version_info: raise UnsupportedCompressionMethodError( properties, "Zstd version of archive is higher than us.") self.decompressor = pyzstd.ZstdDecompressor()
def __init__(self, filters=None, password=None, blocksize: Optional[int] = None): self.filters: List[Dict[str, Any]] = [] self.chain: List[ISevenZipCompressor] = [] self.digest = 0 self.packsize = 0 self._unpacksizes: List[int] = [] if blocksize: self._block_size = blocksize else: self._block_size = get_default_blocksize() if filters is None: self.filters = [{ "id": lzma.FILTER_LZMA2, "preset": 7 | lzma.PRESET_EXTREME }] else: self.filters = filters if len(self.filters) > 4: raise UnsupportedCompressionMethodError( filters, "Maximum cascade of filters is 4 but got {}.".format( len(self.filters))) self.methods_map = [ SupportedMethods.is_native_filter(filter) for filter in self.filters ] self.coders: List[Dict[str, Any]] = [] if all(self.methods_map) and SupportedMethods.is_compressor( self.filters[-1]): # all native self._set_native_compressors_coders(self.filters) return # has_lzma2 = False for f in self.filters: if f["id"] == FILTER_LZMA2: has_lzma2 = True break if not has_lzma2: # when specified other than lzma2, BCJ filters should be alternative for i, f in enumerate(self.filters): if (f["id"] == FILTER_X86 or f["id"] == FILTER_ARM or f["id"] == FILTER_ARMTHUMB or f["id"] == FILTER_SPARC or f["id"] == FILTER_POWERPC): self.methods_map[i] = False # if not any(self.methods_map): # all alternative for f in filters: self._set_alternate_compressors_coders(f, password) elif SupportedMethods.is_crypto_id(self.filters[-1]["id"]) and all( self.methods_map[:-1]): self._set_native_compressors_coders(self.filters[:-1]) self._set_alternate_compressors_coders(self.filters[-1], password) else: raise UnsupportedCompressionMethodError( filters, "Unknown combination of methods.")
def __init__(self, properties: bytes, block_size: int): if len(properties) != 3: raise UnsupportedCompressionMethodError( properties, "Unknown size of properties are passed") if (properties[0], properties[1]) > (brotli_major, brotli_minor): raise UnsupportedCompressionMethodError( properties, "Unsupported brotli version: {}.{} our {}.{}".format( properties[0], properties[1], brotli_major, brotli_minor), ) self._prefix_checked = False self._decompressor = brotli.Decompressor()
def __init__(self, properties: bytes, blocksize: Optional[int] = None): if not isinstance(properties, bytes): raise UnsupportedCompressionMethodError( properties, "Unknown type of properties is passed") if len(properties) == 5: order, mem = struct.unpack("<BL", properties) elif len(properties) == 7: order, mem, _, _ = struct.unpack("<BLBB", properties) else: raise UnsupportedCompressionMethodError( properties, "Unknown size of properties is passed") self.decoder = pyppmd.Ppmd7Decoder(order, mem)
def __init__(self, filters=None, password=None): self.filters = [] # type: List[ISevenZipCompressor] self.chain = [] self.digest = 0 self.packsize = 0 self._unpacksizes = [] if filters is None: self.filters = [{"id": lzma.FILTER_LZMA2, "preset": 7 | lzma.PRESET_EXTREME}] else: self.filters = filters if len(self.filters) > 4: raise UnsupportedCompressionMethodError('Maximum cascade of filters is 4 but got {}.'.format(len(self.filters))) self.methods_map = [SupportedMethods.is_native_filter(filter) for filter in self.filters] self.coders = [] if all(self.methods_map) and SupportedMethods.is_compressor(self.filters[-1]): # all native self._set_native_compressors_coders(self.filters) return # for i, f in enumerate(self.filters): if f['id'] == FILTER_X86: self.methods_map[i] = False # if not any(self.methods_map): # all alternative for f in filters: self._set_alternate_compressors_coders(f, password) elif SupportedMethods.is_crypto_id(self.filters[-1]['id']) and all(self.methods_map[:-1]): self._set_native_compressors_coders(self.filters[:-1]) self._set_alternate_compressors_coders(self.filters[-1], password) else: raise UnsupportedCompressionMethodError
def _get_headerdata_from_streams(self, fp: BinaryIO, streams: StreamsInfo) -> BytesIO: """get header data from given streams.unpackinfo and packinfo. folder data are stored in raw data positioned in afterheader.""" buffer = io.BytesIO() src_start = self._start_pos for folder in streams.unpackinfo.folders: if folder.is_encrypted(): raise UnsupportedCompressionMethodError() uncompressed = folder.unpacksizes if not isinstance(uncompressed, (list, tuple)): uncompressed = [uncompressed] * len(folder.coders) compressed_size = streams.packinfo.packsizes[0] uncompressed_size = uncompressed[-1] src_start += streams.packinfo.packpos fp.seek(src_start, 0) decompressor = folder.get_decompressor(compressed_size) folder_data = decompressor.decompress( fp.read(compressed_size))[:uncompressed_size] src_start += uncompressed_size if folder.digestdefined: if folder.crc != calculate_crc32(folder_data): raise Bad7zFile('invalid block data') buffer.write(folder_data) buffer.seek(0, 0) return buffer
def __init__(self, aes_properties: bytes, password: str, blocksize: Optional[int] = None) -> None: firstbyte = aes_properties[0] numcyclespower = firstbyte & 0x3F if firstbyte & 0xC0 != 0: saltsize = (firstbyte >> 7) & 1 ivsize = (firstbyte >> 6) & 1 secondbyte = aes_properties[1] saltsize += secondbyte >> 4 ivsize += secondbyte & 0x0F assert len(aes_properties) == 2 + saltsize + ivsize salt = aes_properties[2:2 + saltsize] iv = aes_properties[2 + saltsize:2 + saltsize + ivsize] assert len(salt) == saltsize assert len(iv) == ivsize assert numcyclespower <= 24 if ivsize < 16: iv += bytes("\x00" * (16 - ivsize), "ascii") key = calculate_key(password.encode("utf-16LE"), numcyclespower, salt, "sha256") self.cipher = AES.new(key, AES.MODE_CBC, iv) if blocksize: self.buf = Buffer(size=blocksize + 16) else: self.buf = Buffer(size=get_default_blocksize() + 16) else: raise UnsupportedCompressionMethodError(firstbyte, "Wrong 7zAES properties")
def decompress(self, data: Union[bytes, bytearray, memoryview], max_length: int = -1): if not self._prefix_checked: # check first 4bytes if data[:4] == b"\x50\x2a\x4d\x18": raise UnsupportedCompressionMethodError( data[:4], "Unauthorized and modified Brotli data (skipable frame) found." ) self._prefix_checked = True return self._decompressor.process(data)
def raise_unsupported_method_id(cls, coder): if coder["method"] == COMPRESSION_METHOD.P7Z_BCJ2: raise UnsupportedCompressionMethodError( coder["method"], "BCJ2 filter is not supported by py7zr." " Please consider to contribute to XZ/liblzma project" " and help Python core team implementing it." " Or please use another tool to extract it.", ) if coder["method"] == COMPRESSION_METHOD.MISC_DEFLATE64: raise UnsupportedCompressionMethodError( coder["method"], "DEFLATE64 compression is not supported by py7zr yet." " Please check the progress in py7zr project home page.", ) if coder["method"] == COMPRESSION_METHOD.MISC_LZ4: raise UnsupportedCompressionMethodError( coder["method"], "Archive is compressed by an unsupported algorythm LZ4.") raise UnsupportedCompressionMethodError( coder["method"], "Archive is compressed by an unsupported compression algorythm.")
def decompress(self, data: Union[bytes, bytearray, memoryview], max_length: int = -1) -> bytes: if not self._enabled: raise UnsupportedCompressionMethodError( None, "inflate64 is not installed.") if len(data) == 0: if self.flushed: return b"" else: self.flushed = True return self._decompressor.inflate(b"") return self._decompressor.inflate(data)
def _set_alternate_compressors_coders(self, alt_filter, password=None): filter_id = alt_filter["id"] properties = None if filter_id not in algorithm_class_map: raise UnsupportedCompressionMethodError( filter_id, "Unknown filter_id is given.") elif SupportedMethods.is_crypto_id(filter_id): compressor = algorithm_class_map[filter_id][0](password) elif SupportedMethods.need_property(filter_id): if filter_id == FILTER_ZSTD: level = alt_filter.get("level", 3) properties = struct.pack("BBBBB", pyzstd.zstd_version_info[0], pyzstd.zstd_version_info[1], level, 0, 0) compressor = algorithm_class_map[filter_id][0](level=level) elif filter_id == FILTER_PPMD: properties = PpmdCompressor.encode_filter_properties( alt_filter) compressor = algorithm_class_map[filter_id][0](properties) elif filter_id == FILTER_BROTLI: level = alt_filter.get("level", 11) properties = struct.pack("BBB", brotli_major, brotli_minor, level) compressor = algorithm_class_map[filter_id][0](level) else: compressor = algorithm_class_map[filter_id][0]() if SupportedMethods.is_crypto_id(filter_id): properties = compressor.encode_filter_properties() self.chain.append(compressor) self._unpacksizes.append(0) self.coders.insert( 0, { "method": SupportedMethods.get_method_id(filter_id), "properties": properties, "numinstreams": 1, "numoutstreams": 1, }, )
def __init__(self, coders: List[Dict[str, Any]], packsize: int, unpacksizes: List[int], crc: Optional[int], password: Optional[str] = None) -> None: self.input_size = packsize self.unpacksizes = unpacksizes self.consumed = 0 # type: int self.crc = crc self.digest = 0 if len(coders) > 4: raise UnsupportedCompressionMethodError( 'Maximum cascade of filters is 4 but got {}.'.format( len(coders))) self.methods_map = [ SupportedMethods.is_native_coder(coder) for coder in coders ] # type: List[bool] # Check if password given for encrypted archive if SupportedMethods.needs_password(coders) and password is None: raise PasswordRequired( "Password is required for extracting given archive.") # Check filters combination and required parameters if len(coders) >= 2: target_compressor = False has_bcj = False bcj_index = -1 for i, coder in enumerate(coders): filter_id = SupportedMethods.get_filter_id(coder) if SupportedMethods.is_compressor_id( filter_id) and filter_id != FILTER_LZMA2: target_compressor = True if filter_id in [ FILTER_X86, FILTER_ARM, FILTER_ARMTHUMB, FILTER_POWERPC, FILTER_SPARC ]: has_bcj = True bcj_index = i # hack for LZMA1+BCJ which should be native+alternative if target_compressor and has_bcj: self.methods_map[bcj_index] = False break self.chain = [ ] # type: List[Union[bz2.BZ2Decompressor, lzma.LZMADecompressor, ISevenZipDecompressor]] self._unpacksizes = [] # type: List[int] self.input_size = self.input_size shift = 0 prev = False for i, r in enumerate(self.methods_map): shift += 1 if r and prev else 0 prev = r self._unpacksizes.append(unpacksizes[i - shift]) self._unpacked = [0 for _ in range(len(self._unpacksizes))] self.consumed = 0 self._unused = bytearray() self._buf = bytearray() # --- if all(self.methods_map): decompressor = self._get_lzma_decompressor(coders, unpacksizes[-1]) self.chain.append(decompressor) elif not any(self.methods_map): for i in range(len(coders)): self.chain.append( self._get_alternative_decompressor(coders[i], unpacksizes[i], password)) elif any(self.methods_map): for i in range(len(coders)): if (not any(self.methods_map[:i])) and all( self.methods_map[i:]): for j in range(i): self.chain.append( self._get_alternative_decompressor( coders[j], unpacksizes[j], password)) self.chain.append( self._get_lzma_decompressor(coders[i:], unpacksizes[i])) break else: for i in range(len(coders)): if self.methods_map[i]: self.chain.append( self._get_lzma_decompressor([coders[i]], unpacksizes[i])) else: self.chain.append( self._get_alternative_decompressor( coders[i], unpacksizes[i], password)) else: raise UnsupportedCompressionMethodError
def need_property(cls, filter_id): method = cls._find_method("filter_id", filter_id) if method is None: raise UnsupportedCompressionMethodError( filter_id, "Found an sunpported filter id.") return method["need_prop"]
def raise_unsupported_filter_id(cls, filter_id): raise UnsupportedCompressionMethodError( filter_id, "Found an unsupported filter id is specified." "Please use another compression method.")
def is_native_filter(cls, filter) -> bool: method = cls._find_method("filter_id", filter["id"]) if method is None: raise UnsupportedCompressionMethodError( filter["id"], "Unknown method id is given.") return method["native"]