Skip to content

Commit

Permalink
Added Menu:File:Add External item to load external files, mainly to b…
Browse files Browse the repository at this point in the history
…e used for GenZero save files
  • Loading branch information
kk49 committed Jan 2, 2020
1 parent 9c92a58 commit 2738a1b
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 35 deletions.
2 changes: 2 additions & 0 deletions deca/export_import_adf.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ def adf_export(vfs: VfsStructure, vnodes: List[VfsNode], export_path, allow_over

s = adf.dump_to_string()

fn_dir = os.path.dirname(fn)
os.makedirs(fn_dir, exist_ok=True)
with open(fn, 'wt') as f:
f.write(s)

Expand Down
2 changes: 1 addition & 1 deletion deca/ff_adf.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ def dump_type(type_id, type_map, offset=0, displayed_types=None):
else:
raise Exception('Unknown Typedef Type {}'.format(type_def.metatype))

print(sbuf)
# print(sbuf)

return sbuf

Expand Down
33 changes: 26 additions & 7 deletions deca/gui/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -882,26 +882,34 @@ def __init__(self):

# Menu
self.menu = self.menuBar()
self.file_menu = self.menu.addMenu('File')
self.edit_menu = self.menu.addMenu('Edit')
self.tools_menu = self.menu.addMenu('Tools')
self.file_menu = self.menu.addMenu('&File')
self.edit_menu = self.menu.addMenu('&Edit')
self.tools_menu = self.menu.addMenu('&Tools')

self.action_project_new = QAction("&New Project...")
self.action_project_new.triggered.connect(self.project_new)
self.file_menu.addAction(self.action_project_new)

self.action_project_open = QAction("&Open Project...")
self.action_project_open.triggered.connect(self.project_open)
self.file_menu.addAction(self.action_project_open)

self.action_external_add = QAction("&Add External...")
self.action_external_add.triggered.connect(self.external_add)
self.action_external_add.setEnabled(False)
self.file_menu.addAction(self.action_external_add)

# self.action_external_manage = QAction("Manage &Externals...")
# self.action_external_manage.triggered.connect(self.external_manage)
# self.file_menu.addAction(self.action_external_manage)

self.action_exit = QAction("E&xit", self)
self.action_exit.setShortcut("Ctrl+Q")
self.action_exit.triggered.connect(self.exit_app)
self.file_menu.addAction(self.action_exit)

self.action_make_web_map = QAction("Make &Web Map")
self.action_make_web_map.triggered.connect(self.tool_make_web_map)

self.file_menu.addAction(self.action_project_new)
self.file_menu.addAction(self.action_project_open)
self.file_menu.addAction(self.action_exit)
self.tools_menu.addAction(self.action_make_web_map)

# Status Bar
Expand Down Expand Up @@ -936,6 +944,7 @@ def vfs_set(self, vfs):
self.status.showMessage(
"Data loaded and plotted: {}".format('hash_map_missing: {}'.format(len(vfs.hash_map_missing))))
self.main_widget.vfs_set(vfs)
self.action_external_add.setEnabled(True)

@Slot()
def project_new(self, checked):
Expand Down Expand Up @@ -987,6 +996,16 @@ def project_open(self, checked):
else:
self.logger.log('Cannot Open {}'.format(filename))

@Slot()
def external_add(self, checked):
filename = QFileDialog.getOpenFileName(self, 'Open External File ...', '.', 'Any File (*)')
if filename is not None and len(filename[0]) > 0:
filename = filename[0]
self.vfs.external_file_add(filename)
self.main_widget.vfs_set(self.vfs)
else:
self.logger.log('Cannot Open {}'.format(filename))

@Slot()
def exit_app(self, checked):
self.close()
Expand Down
80 changes: 53 additions & 27 deletions deca/vfs_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class VfsStructure(VfsBase):
def __init__(self, game_info: GameInfo, working_dir, logger):
VfsBase.__init__(self, game_info, working_dir, logger)
self.adf_db = None
self.external_files = set()

def prepare_adf_db(self, debug=False):
save_dir = os.path.join(self.working_dir, 'adf_types')
Expand Down Expand Up @@ -220,6 +221,27 @@ def dump_status(self):
for vp in vps:
self.logger.log('CONFLICT: {:08X} {}'.format(vid, vp))

def node_update_vpath_mapping(self, vnode):
vid = vnode.vhash
if vnode.vpath is None:
self.hash_map_missing.add(vid)
else:
self.hash_map_present.add(vid)
vpath = vnode.vpath
if vid in self.map_hash_to_vpath:
self.map_hash_to_vpath[vid].add(vpath)
if len(self.map_hash_to_vpath[vid]) > 1:
self.hash_map_conflict.add(vid)
else:
self.map_hash_to_vpath[vid] = {vpath}

vl = self.map_vpath_to_vfsnodes.get(vpath, [])
if vnode.offset is None:
vl = vl + [vnode]
else:
vl = [vnode] + vl
self.map_vpath_to_vfsnodes[vpath] = vl

def process_vpaths(self):
self.logger.log('process_vpaths: Input count {}'.format(len(self.possible_vpath_map.nodes)))

Expand Down Expand Up @@ -259,33 +281,15 @@ def process_vpaths(self):
vnode: VfsNode = vnode
if vnode.is_valid():
if vnode.vhash is not None:
vid = vnode.vhash
if vnode.vpath is None:
self.hash_map_missing.add(vid)
else:
self.hash_map_present.add(vid)
vpath = vnode.vpath
if vid in self.map_hash_to_vpath:
self.map_hash_to_vpath[vid].add(vpath)
if len(self.map_hash_to_vpath[vid]) > 1:
self.hash_map_conflict.add(vid)
else:
self.map_hash_to_vpath[vid] = {vpath}

vl = self.map_vpath_to_vfsnodes.get(vpath, [])
if vnode.offset is None:
vl = vl + [vnode]
else:
vl = [vnode] + vl
self.map_vpath_to_vfsnodes[vpath] = vl

# tag atx file type since they have no header info
if vnode.ftype is None:
file, ext = os.path.splitext(vnode.vpath)
if ext[0:4] == b'.atx':
vnode.ftype = FTYPE_ATX
elif ext == b'.hmddsc':
vnode.ftype = FTYPE_HMDDSC
self.node_update_vpath_mapping(vnode)

# tag atx file type since they have no header info
if vnode.ftype is None:
file, ext = os.path.splitext(vnode.vpath)
if ext[0:4] == b'.atx':
vnode.ftype = FTYPE_ATX
elif ext == b'.hmddsc':
vnode.ftype = FTYPE_HMDDSC

found_vpaths = list(found_vpaths)
found_vpaths.sort()
Expand Down Expand Up @@ -776,6 +780,28 @@ def find_vpath_by_assoc(self, vpath_map):

self.logger.log('STRINGS BY FILE NAME ASSOCIATION: Found {}'.format(len(assoc_strings)))

def external_file_add(self, filename):
if not hasattr(self, 'external_files'):
self.external_files = set()

if filename not in self.external_files and os.path.isfile(filename):
with open(filename, 'rb') as f:
ftype, fsize = determine_file_type_and_size(f, os.stat(filename).st_size)

vpath = ('__EXTERNAL_FILES__' + filename).encode('ascii')
vhash = deca.hash_jenkins.hash_little(vpath)
vnode = VfsNode(
vhash=vhash, vpath=vpath, pvpath=filename, ftype=ftype,
size_u=fsize, size_c=fsize, offset=0)
self.node_add(vnode)
self.node_update_vpath_mapping(vnode)

self.external_files.add(filename)

self.logger.log('ADDED {} TO EXTERNAL FILES'.format(filename))
else:
self.logger.log('FAILED TO OPEN: {}'.format(filename))


def vfs_structure_prep(game_info, working_dir, logger=None, debug=False):
os.makedirs(working_dir, exist_ok=True)
Expand Down

0 comments on commit 2738a1b

Please sign in to comment.