Example #1
0
    def __init__(self, stream):
        if stream.read_string() != b'UnityFS':
            raise ValueError('Not a UnityFS file!')
        version = stream.read_int()
        if version != 6:
            raise ValueError('Unsupported version: ' + str(version))
        mpv = stream.read_string()
        fev = stream.read_string()
        total_file_size = stream.read_long()
        compressed_size = stream.read_int()
        decompressed_size = stream.read_int()
        flags = stream.read_int()

        if flags & 0x80:
            if total_file_size == 0:
                bundle_info_offset = -1
            else:
                bundle_info_offset = total_file_size - compressed_size
        else:
            if flags & 0x100:
                bundle_info_offset = len(mpv) + len(fev) + 2 + 0x1A + 0x0A
            else:
                bundle_info_offset = len(mpv) + len(fev) + 0x1A + len(
                    'UnityFS') + 3

        compression_mode = flags & 0x3F
        dir_info = flags & 0x40
        bad_list = flags & 0x80
        blocks = []
        files = []

        block = stream.read_bytes(compressed_size)
        if compression_mode in (self.COMP_LZ4, self.COMP_LZ4HC):
            data = lz4.block.decompress(block,
                                        uncompressed_size=decompressed_size)
            s2 = Stream(data)
            s2.skip(16)
            block_count = s2.read_int()
            for _ in range(block_count):
                decomp_size = s2.read_int()
                comp_size = s2.read_int()
                flag = s2.read_short()
                blocks.append((comp_size, decomp_size))
            file_count = s2.read_int()
            for _ in range(file_count):
                f_offset = s2.read_long()
                decomp_size = s2.read_long()
                flag = s2.read_int()
                name = s2.read_string()
                files.append((f_offset, decomp_size, name))
        else:
            raise ValueError('Unsupported compression mode')

        block_data = io.BytesIO()
        for i in blocks:
            bd = stream.read_bytes(i[0])
            dc = lz4.block.decompress(bd, uncompressed_size=i[1])
            block_data.write(dc)

        self.files = {}
        for i in files:
            block_data.seek(i[0])
            self.files[i[2].decode()] = block_data.read(i[1])