[Xenogears] Filesystem

  • Thread starter Thread starter Micky
  • Start date Start date
Status
Not open for further replies.
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]
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:])
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.
 
Last edited:
Status
Not open for further replies.
Back
Top