M
Micky
Guest
(In extension to this old thread)
I cross referenced the info from jpsxdec with the data from my extraction tool, and found a bug in my length calculation for movie scenes. But aside from that, it looks like my assumption that the negative number that shows the start of a directory is actually the number of files in the directory is correct. For the movie directory it matches the number of movies reported by jpsxdec, and interestingly the last two entries after the movies point to the executable and config file, at exactly the same sector positions as reported by the iso9660 filesystem.
Unfortunately this leaves quite a few files that don't get put into any directory, so there is maybe still something I'm missing.
Here is the current version of my extraction code:
Code: (Python) [Select]
It can give you CSV tables for the ISO filesystem and the file table used for game data. Note that both the config file and the boot file are referenced from both tables.
You need a raw disc image for it to work from.
I cross referenced the info from jpsxdec with the data from my extraction tool, and found a bug in my length calculation for movie scenes. But aside from that, it looks like my assumption that the negative number that shows the start of a directory is actually the number of files in the directory is correct. For the movie directory it matches the number of movies reported by jpsxdec, and interestingly the last two entries after the movies point to the executable and config file, at exactly the same sector positions as reported by the iso9660 filesystem.
Unfortunately this leaves quite a few files that don't get put into any directory, so there is maybe still something I'm missing.
Here is the current version of my extraction code:
Code: (Python) [Select]
Code:
import sys, os, struct, re, csvre_name = re.compile(r"(.*);([0-9]+)")block_size = 2352def readSectorForm1(f, lba, count): f.seek(lba * block_size) data = "" for i in xrange(count): block = f.read(block_size) data += block[24:2048+24] del block return datadef readDir( f, path, dir_pos, dir_size, parent): dir = readSectorForm1(f, dir_pos, (dir_size + 2047) / 2048) list = [] pos = 0 while pos < len(dir): (entry_size, file_pos, file_len, attr, name_len) = struct.unpack_from("<BxIxxxxIxxxxxxxxxxxBxxxxxxB", dir, pos) if entry_size > 0: hidden = (attr & 1) != 0 subdir = (attr & 2) != 0 if file_pos != dir_pos and file_pos != parent: name = dir[pos+33:pos+33+name_len] if not subdir: pat = re_name.match(name) if pat: name = pat.group(1) file_path = os.path.join(path, name) if subdir: list.extend( readDir(f, file_path, file_pos, file_len, dir_pos) ) else: list.append( (file_path, file_pos, file_len) ) pos += entry_size else: pos = (pos + 2047) & ~2047 del dir return listdef readFileTable(f): fileTable = readSectorForm1( f, 24, 16 ) index = 0 fileCount = 0 dirCount = 0 dirIndex = 0 movies = False list = [] while True: startSector = struct.unpack_from("<I", fileTable, index * 7 + 0)[0] & 0xFFFFFF if startSector == 0xFFFFFF: break fileSize = struct.unpack_from("<i", fileTable, index * 7 + 3)[0] if fileSize < 0: fileCount = 0 dirIndex = dirCount movies = dirCount == 0 dirCount += 1 elif fileSize > 0: file_path = os.path.join("dir%i" % dirIndex, "file%i.bin" % fileCount) list.append( (file_path, startSector, fileSize, movies) ) fileCount += 1 index += 1 return listdef main(*argv): for arg in argv: f = open(arg, "rb") # identify the disk volume_descriptor = readSectorForm1( f, 16, 1 ) (system_identifier, volume_identifier) = struct.unpack_from("<32s32s", volume_descriptor, 8) system_identifier = system_identifier.strip() if system_identifier != "PLAYSTATION": print "Not a playstation image: \"%s\"" % system_identifier f.close() return volume_identifier = volume_identifier.strip() if volume_identifier != "XENOGEARS": print "Not a Xenogears image: \"%s\"" % volume_identifier f.close() return # read the filesystem (root_pos,) = struct.unpack_from("<I", volume_descriptor, 156 + 2) (root_len,) = struct.unpack_from("<I", volume_descriptor, 156 + 10) list = readDir( f, "", root_pos, root_len, root_pos) # find if we're disk 1 or disk 2 disk = None for file in list: if file[0] == 'SLUS_006.64': disk = 1 break elif file[0] == 'SLUS_006.69': disk = 2 break if disk is None: print "Failed to find executable" print "Please post this to the tech-related forum on http://forums.qhimm.com/" print list f.close() return # export normal files if True: for (name, startSector, fileSize) in list: blocks = (fileSize + 2047) / 2048 data = readSectorForm1(f, startSector, blocks) path = os.path.join("disk%i" % disk, name) dirname = os.path.dirname(path) if not os.path.exists(dirname): os.makedirs(dirname) d = open(path, "wb") d.write(data[:fileSize]) d.close() del data # export directory table if False: c = open("xenogears_iso%i.csv" % disk, "wt") w = csv.writer(c) w.writerows(list) c.close() # get hidden file table list = readFileTable(f) # export hidden files if True: for (name, startSector, fileSize, movieFlag) in list: if movieFlag: blocks = (fileSize + 2335) / 2336 f.seek(startSector * block_size) data = f.read(blocks * block_size) else: blocks = (fileSize + 2047) / 2048 data = readSectorForm1(f, startSector, blocks) path = os.path.join("disk%i" % disk, name) dirname = os.path.dirname(path) if not os.path.exists(dirname): os.makedirs(dirname) d = open(path, "wb") d.write(data[:fileSize]) d.close() del data # export file table if False: c = open("xenogears_table%i.csv" % disk, "wt") w = csv.writer(c) w.writerows(list) c.close() f.close()if __name__ == "__main__": main(*sys.argv[1:])
You need a raw disc image for it to work from.
Last edited: