Advertisement
Guest User

Nintendo Switch romfs extract

a guest
Jul 19th, 2017
444
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.96 KB | None | 0 0
  1. from struct import unpack as up
  2. import sys, os
  3.  
  4. dirs, files = None, None
  5.  
  6. def read_at(fp, off, len):
  7.     fp.seek(off)
  8.     return fp.read(len)
  9.  
  10. def read_u8(fp, off):
  11.     return up('<B', read_at(fp, off, 1))[0]
  12.  
  13. def read_u16(fp, off):
  14.     return up('<H', read_at(fp, off, 2))[0]
  15.  
  16. def read_u32(fp, off):
  17.     return up('<I', read_at(fp, off, 4))[0]
  18.  
  19. def read_u64(fp, off):
  20.     return up('<Q', read_at(fp, off, 8))[0]
  21.  
  22. def read_filename(fp, off, l):
  23.     if l == 0:
  24.         return ''
  25.     s = read_at(fp, off, l)
  26.     if '\0' in s:
  27.         s = s[:s.index('\0')]
  28.     return s
  29.  
  30. def dump_file(name, offset, size):
  31.     global archive, out_dir
  32.     path = os.path.join(out_dir, name[1:])
  33.     print 'Dumping %s (%012X-%012X) to %s...' % (name, offset, offset+size, path)
  34.     archive.seek(offset)
  35.     with open(path, 'wb') as f:
  36.         ofs = 0
  37.         sz = 0x800000
  38.         while ofs < size:
  39.             if size - ofs < sz:
  40.                 sz = size - ofs
  41.             f.write(archive.read(sz))
  42.             ofs += sz
  43.     print 'Dumped!'
  44.  
  45. def parse_file(off, path = ''):
  46.     global archive, dirs_off, files_off, fdata_off
  47.     sibling = 0
  48.     while sibling != 0xFFFFFFFF:
  49.         archive.seek(files_off + off)
  50.         (parent, sibling, ofs, size, hsh, namelen) = up('<IIQQII', archive.read(0x20))
  51.         name = read_filename(archive, files_off + off + 0x20, namelen)
  52.         filepath = '%s%s' % (path, name)
  53.         dump_file(filepath, fdata_off+ofs, size)
  54.         off = sibling
  55.  
  56. def parse_dir(off, path = ''):
  57.     global archive, dirs_off, files_off, fdata_off, out_dir
  58.     archive.seek(dirs_off + off)
  59.     (sibling, child, file, hsh, namelen) = up('<IIIII', archive.read(0x14))
  60.     name = read_filename(archive, dirs_off + off + 0x14, namelen)
  61.     if path:
  62.         newpath = '%s%s/' % (path, name)
  63.     else:
  64.         newpath = '%s/' % name
  65.     dirp = os.path.dirname(os.path.join(out_dir, newpath[1:])).replace('/', os.path.sep)
  66.     if not os.path.exists(dirp):
  67.         os.mkdir(dirp)
  68.     if file != 0xFFFFFFFF:
  69.         parse_file(file, newpath)
  70.     if sibling != 0xFFFFFFFF:
  71.         parse_dir(sibling, path)
  72.     if child != 0xFFFFFFFF:
  73.         parse_dir(child, newpath)
  74.  
  75. def main(argc, argv):
  76.     if argc != 3:
  77.         print 'Usage: %s in_file out_dir' % argv[0]
  78.         return
  79.     global archive, dirs_off, files_off, fdata_off
  80.     try:
  81.         archive = open(argv[1], 'rb')
  82.         if read_u64(archive, 0) != 0x50:
  83.             print 'Error: Invalid archive.'
  84.             return
  85.         dirs_off = read_u64(archive, 0x18)+4
  86.         files_off = read_u64(archive, 0x38)
  87.         fdata_off = read_u64(archive, 0x48)
  88.         print 'Directory Metadata at %08X' % dirs_off
  89.         print 'File Metadata at %08X' % files_off
  90.     except:
  91.         print 'Failed to open %s.' % argv[1]
  92.         return
  93.  
  94.     global out_dir
  95.     out_dir = argv[2]
  96.  
  97.     sys.setrecursionlimit(100000)
  98.     parse_dir(0)
  99.  
  100. if __name__ == '__main__':
  101.     main(len(sys.argv), sys.argv)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement