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

From Data Crystal
Jump to navigation Jump to search

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))