Welcome to Data Crystal's new home! Data Crystal is now part of the TCRF family (sort of).
The wiki has recently moved; please report any issues in Discord. Pardon the dust.

Yggdra Union: We'll Never Fight Alone (PlayStation Portable)/Notes: Difference between revisions

From Data Crystal
Jump to navigation Jump to search
No edit summary
 
(One intermediate revision by one other user not shown)
(No difference)

Latest revision as of 20:39, 28 January 2024

Chip tiny.png The following article is a Notes Page for Yggdra Union: We'll Never Fight Alone (PlayStation Portable).

AFS extract for Python 3

import ntpath
import os
import struct
from functools import partial

def chunk(iterable, chunk_size):
    """Generate sequences of `chunk_size` elements from `iterable`."""
    iterable = iter(iterable)
    while True:
        chunk = []
        try:
            for _ in range(chunk_size):
                chunk.append(next(iterable))
            yield chunk
        except StopIteration:
            if chunk:
                yield chunk
            break

def afs_extract(filename):
    basename = os.path.splitext(ntpath.basename(filename))[0]
    if not os.path.exists(basename):
        os.mkdir(basename)
    path = ntpath.split(filename)[0]
    tgt_path = os.path.join(path, basename)

    with open(filename, 'rb') as f:
        #Header info
        file_ID = f.read(4)
        if file_ID != b'AFS\x00':
            raise ValueError('ID string does not match "AFS\x00"')
        num_of_files = struct.unpack('<I', f.read(4))[0]
        #File offsets table
        offsets_table = struct.unpack(
            ''.join(('<', 'I' * 2 * num_of_files)),
            f.read(8 * num_of_files))
        #Pointer to file information table
        iter_file_offsets = chunk(offsets_table, 2)
        info_table_offset, info_table_size = struct.unpack('<II', f.read(8))

        for subfile_number in range(num_of_files):
            #Get file name
            f.seek(info_table_offset + 0x30 * subfile_number)
            subfilename = []
            for b in iter(partial(f.read, 1), b'\x00'):
                subfilename.append(b)
            subfilename = b''.join(subfilename).decode('ascii')

            tgt_filename = ''.join((
                '{:0>4}'.format(subfile_number),
                '-',
                subfilename))

            #Write the file
            start, size = next(iter_file_offsets)
            f.seek(start)
            with open(os.path.join(tgt_path, tgt_filename), 'wb') as g:
                g.write(f.read(size))