If you are still using the old URL (datacrystal.romhacking.net), please update your bookmarks! The old URL may stop working soon.
The current URL is datacrystal.tcrf.net.
The current URL is datacrystal.tcrf.net.
Yggdra Union: We'll Never Fight Alone (PlayStation Portable)/Notes
Jump to navigation
Jump to search
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))
Internal Data for Yggdra Union
| |
---|---|