def _read_record(self, depth):
        record = lib.Manifest(self,
                              header=[
                                  ('data_offset', self.read(4)),
                                  ('data_size', self.read(4)),
                                  ('id', self.read(4)),
                                  ('filename_offset', self.read(4)),
                                  ('padding', self.expect(0x0, 4)),
                              ])

        position = self.file.tell()
        if record.int32('filename_offset') > 0:
            self.file.seek(record.int32('filename_offset'))
            record.filename = self.read_null_terminated_string()

        if record.int32('data_offset') > 0:
            record.path = lib.filesystem.normalize_filepath(
                record.filename, self.path) + ".dds"
            self.file.seek(record.int32('data_offset'))
            self.log(
                "Reading data, size = {}, filename = {}, actual filename = {}".
                format(record.int32('data_size'), record.filename,
                       record.path), depth)
            data = self.read(record.int32('data_size'))
            lib.filesystem.write_data(record.path, data)

        self.file.seek(position)

        return record
    def _read_record(self, depth):
        record = lib.Manifest(self,
                              header=[
                                  ("record_separator", self.expect(0x40, 4)),
                                  ('record_size', self.read(4)),
                                  ('record_offset', self.read(4)),
                                  ('id', self.read(4)),
                                  ('filename_offset', self.read(4)),
                                  ('redundant_size', self.read(4)),
                              ])

        if record.header['record_size'] != record.header['redundant_size']:
            raise ValueError("Data sizes don't match: {} != {}".format(
                record.header['record_size'], record.header['redundant_size']))

        position = self.file.tell()
        self.file.seek(record.int32('filename_offset'))

        record.record_name = self.read_null_terminated_string()
        if not record.record_name:
            raise ValueError("Got empty record name")
        record.path = lib.filesystem.normalize_filepath(
            record.record_name, self.path)

        self.file.seek(position)
        return record
    def extract_file(self, depth):
        self.log("Parsing file {}".format(self.path), depth)

        manifest = lib.Manifest(
            self,
            header=[
                ("signature", self.expect(self.MAGIC_HEADER)),
                ("unknown1", self.expect(b"\xff\x00\x00\x00\x01\x00\x00\x00")),
                ("file_size", self.read(4)),
                ("bin_count", self.read(4)),
                ("bin_record_offset", self.read(4)),
            ])
        manifest.records = []
        manifest.bin_records = []

        # self.log(self.to_int32(manifest['header']['file_size']), depth)

        for i in range(manifest.int32('bin_count')):
            self.log("Reading bin #{}".format(i), depth)
            bin_record = self._read_bin(depth)
            manifest.bin_records.append(bin_record)
            # Add ability to iterate over records for uniformity with BHF3File
            manifest.records += bin_record.records

        self.file.close()

        return manifest
示例#4
0
    def extract_file(self, depth):
        self.log("Reading file {}".format(self.path), depth)

        manifest = lib.Manifest(
            self,
            header=[
                ("signature", self.expect(self.MAGIC_HEADER)),
                ("unknown1", self.expect(0x10000, 4)),
                ("dcs_offset", self.expect(0x18, 4)),
                ("dcp_offset", self.expect(0x24, 4)),
                ("redundant_dcp_offset", self.expect(0x24, 4)),
                ("dcs_header_size", self.expect(0x2c, 4)),
                ("dcs_signature", self.expect(b"DCS\x00")),
                ("uncompressed_size", self.read(4)),
                ("compressed_size", self.read(4)),
                ("dcp_signature", self.expect(b"DCP\x00")),
                ("dcp_method", self.expect(b"DFLT")),
                ("dca_offset", self.expect(0x20, 4)),
                ("compression_level", self.expect(0x09000000, 4)),
                ("unknown2", self.expect(0x0, 12)),
                ("zlib_version", self.expect(0x00010100, 4)),
                ("dca_signature", self.expect(b"DCA\x00")),
                ("dca_header_size", self.expect(0x8, 4)),
            ])
        manifest.end_header_pos = self.file.tell()

        compressed_data = self.read(manifest.int32('compressed_size'))
        uncompressed_data = zlib.decompress(compressed_data)
        if len(uncompressed_data) != manifest.int32('uncompressed_size'):
            msg = "Expected uncompressed size {}, got {}".format(
                manifest.int32('uncompressed_size'), len(uncompressed_data))
            raise ValueError(msg)

        uncompressed_filename = lib.filesystem.normalize_filepath(
            os.path.basename(self.path)[:-4], self.path)
        manifest.uncompressed_filename = uncompressed_filename

        file_cls = self.class_for_data(uncompressed_data)
        if file_cls:
            manifest.sub_manifest = file_cls(
                io.BytesIO(uncompressed_data),
                uncompressed_filename).extract_file(depth + 1)
        else:
            self.log(
                "Writing uncompressed data to {}".format(
                    uncompressed_filename), depth)
            lib.filesystem.write_data(uncompressed_filename, uncompressed_data)

        return manifest
    def _read_bin(self, depth):
        bin_record = lib.Manifest(self,
                                  header=[
                                      ("record_count", self.read(4)),
                                      ("offset", self.read(4)),
                                  ])
        bin_record.records = []

        position = self.file.tell()
        self.file.seek(bin_record.int32('offset'))
        for i in range(bin_record.int32('record_count')):
            bin_record.records.append(self._read_record())
        self.file.seek(position)

        return bin_record
    def extract_file(self, depth):
        self.log("Reading file {}".format(self.path), depth)

        manifest = lib.Manifest(self,
                                header=[
                                    ('signature',
                                     self.expect(self.MAGIC_HEADER)),
                                    ("size_sum", self.read(4)),
                                    ("record_count", self.read(4)),
                                    ("flags", self.expect(0x20300, 4)),
                                ])
        manifest.records = []

        for i in range(manifest.int32('record_count')):
            self.log("Reading record #{}".format(i), depth)
            manifest.records.append(self._read_record(depth + 1))

        manifest.end_header_pos = self.file.tell()

        return manifest
    def _read_record(self):
        record = lib.Manifest(self,
                              header=[
                                  ('record_hash', self.read(4)),
                                  ('record_size', self.read(4)),
                                  ('record_offset', self.read(4)),
                                  ('padding', self.expect(0x0, 4)),
                              ])

        record_hash = record.int32('record_hash')
        try:
            record.record_name = lib.filesystem.get_name_from_hash(
                record_hash).lstrip("/").replace("/", os.sep)
        except KeyError:
            raise ValueError(
                "Failed to find {} in name hash dict".format(record_hash))

        record.path = lib.filesystem.normalize_filepath(
            record.record_name, self.path)

        return record
示例#8
0
    def extract_file(self, depth):
        self.log("Reading file {}".format(self.path), depth)

        manifest = lib.Manifest(self, header=[
            ("signature", self.expect(self.MAGIC_HEADER)),
            ("id", self.expect(self.MAGIC_ID)),
            ("padding", self.expect(0x0, 6)),
        ])

        if self.path.endswith(self.C4110_FILENAME):
            data = io.BytesIO(fixed_data.c4110_replacement.DATA)
            manifest.header_manifest = lib.BHF3File(data, self.path[:-3] + "bhd").extract_file(depth + 1)
        else:
            header_filename = lib.filesystem.find_bdt_header_filename(self.path, depth)
            if not header_filename:
                raise FileNotFoundError("Got no results searching for BHD for BDT {}".format(self.path))
            self.log("Using header file {}".format(header_filename), depth)
            manifest.header_manifest = self._get_header_extractor(header_filename, depth).extract_file(depth + 1)

        self._extract_records(manifest.header_manifest.records, depth)

        return manifest
    def _read_record(self, flags, depth):
        record = lib.Manifest(self, header=[
            ("record_sep", self.expect(0x40, 4)),
            ('data_size', self.read(4)),
            ('data_offset', self.read(4)),
            ('id', self.read(4)),
            ("filename_offset", self.read(4)),
        ])

        if flags in (0x74, 0x54):
            record.header['redundant_size'] = self.read(4)
            if record.header['redundant_size'] != record.header['data_size']:
                raise ValueError("Expected size {}, got {}".format(
                    record.header['data_size'],
                    record.header['redundant_size'])
                )

        position = self.file.tell()
        if record.int32('filename_offset') > 0:
            self.file.seek(record.int32('filename_offset'))
            record.filename = self.read_null_terminated_string()
            record.path = lib.filesystem.normalize_filepath(record.filename, self.path)
            # self.log("got filename %s" % record['filename'])

        if record.int32('data_offset') > 0:
            self.file.seek(record.int32('data_offset'))
            self.log("Reading data, size = {}, filename = {}".format(record.int32('data_size'), record.filename), depth)
            data = self.read(record.int32('data_size'))
            file_cls = self.class_for_data(data)
            if file_cls:
                record.sub_manifest = file_cls(io.BytesIO(data), record.path).extract_file(depth + 1)
            else:
                self.log("Writing data to {}".format(record.path), depth)
                lib.filesystem.write_data(record.path, data)

        self.file.seek(position)

        return record
    def extract_file(self, depth):
        self.log("Reading file {}".format(self.path), depth)

        manifest = lib.Manifest(self, header=[
            ("signature", self.expect(self.MAGIC_HEADER)),
            ("id", self.read(8)),
            ("flags", self.read(4)),
            ("record_count", self.read(4)),
            ("header_size", self.read(4)),
            ("padding", self.expect(0x0, 8)),
        ])
        manifest.records = []

        if manifest.int32('flags') not in (0x74, 0x54, 0x70):
            raise ValueError("Invalid flags: {:02X}".format(manifest.int32('flags')))

        for i in range(manifest.int32('record_count')):
            self.log("Reading record #{}".format(i), depth)
            manifest.records.append(self._read_record(manifest.int32('flags'), depth + 1))

        manifest.end_header_pos = self.file.tell()

        return manifest
    def extract_file(self, depth):
        self.log("Parsing file {}".format(self.path), depth)

        manifest = lib.Manifest(self,
                                header=[
                                    ("signature",
                                     self.expect(self.MAGIC_HEADER)),
                                    ("id", self.expect(b"07D7R6\x00\x00")),
                                    ("version", self.read(4)),
                                    ("record_count", self.read(4)),
                                    ("header_size", self.read(4)),
                                    ("padding", self.expect(0x0, 8)),
                                ])
        manifest.records = []

        if manifest.int32('version') not in (0x74, 0x54):
            raise ValueError("Invalid version: {:02X}".format(
                manifest.int32('version')))

        for i in range(manifest.int32('record_count')):
            manifest.records.append(self._read_record(depth))

        self.file.close()
        return manifest