GP-5372: PyGhidra now respects the application.settingsdir property set

in Ghidra's launch.properties (Closes #7481)
This commit is contained in:
Ryan Kurtz
2025-02-12 10:00:26 -05:00
parent ce62f9ce7e
commit 034c696512
2 changed files with 41 additions and 5 deletions
@@ -305,3 +305,12 @@ underscore appended to the package name:
import pdb # imports Python's pdb
import pdb_ # imports Ghidra's pdb
```
## Change History
__2.0.1:__
* PyGhidra now respects the `application.settingsdir` property set in Ghidra's `launch.properties`
file.
* Fixed an issue that prevented accessing Java getters/setters as properties on non-public classes.
* PyGhidra can now find modules that live in directories specified by Ghidra's _"Bundle Manager"_.
__2.0.0:__
* Initial Release.
@@ -29,24 +29,49 @@ def get_application_properties(install_dir: Path) -> Dict[str, str]:
with open(app_properties_path, 'r') as f:
for line in f:
line = line.strip()
if line.startswith('#') or line.startswith('!'):
if not line or line.startswith('#') or line.startswith('!'):
continue
key, value = line.split('=', 1)
if key:
props[key] = value
return props
def get_launch_properties(install_dir: Path, dev: bool) -> List[str]:
if dev:
launch_properties_path: Path = install_dir / 'Ghidra' / 'RuntimeScripts' / 'Common' / 'support' / 'launch.properties'
else:
launch_properties_path: Path = install_dir / 'support' / 'launch.properties'
props: List[str] = []
with open(launch_properties_path, 'r') as f:
for line in f:
line = line.strip()
if not line or line.startswith('#') or line.startswith('!'):
continue
props.append(line)
return props
def get_user_settings_dir(install_dir: Path, dev: bool) -> Path:
props: Dict[str, str] = get_application_properties(install_dir)
app_name: str = props['application.name'].replace(' ', '').lower()
app_version: str = props['application.version']
app_release_name: str = props['application.release.name']
app_props: Dict[str, str] = get_application_properties(install_dir)
app_name: str = app_props['application.name'].replace(' ', '').lower()
app_version: str = app_props['application.version']
app_release_name: str = app_props['application.release.name']
versioned_name: str = f'{app_name}_{app_version}_{app_release_name}'
if dev:
versioned_name += f'_location_{install_dir.parent.name}'
# Check for application.settingsdir in launch.properties
for launch_prop in get_launch_properties(install_dir, dev):
if launch_prop.startswith('VMARGS=-Dapplication.settingsdir='):
application_settingsdir = launch_prop[launch_prop.rindex('=')+1:]
if application_settingsdir:
return Path(application_settingsdir) / app_name / versioned_name
# Check for XDG_CONFIG_HOME environment variable
xdg_config_home: str = os.environ.get('XDG_CONFIG_HOME')
if xdg_config_home:
return Path(xdg_config_home) / app_name / versioned_name
# Default to platform-specific locations
if platform.system() == 'Windows':
return Path(os.environ['APPDATA']) / app_name / versioned_name
if platform.system() == 'Darwin':
@@ -136,6 +161,8 @@ def get_saved_python_cmd(install_dir: Path, dev: bool) -> List[str]:
def save_python_cmd(install_dir: Path, python_cmd: List[str], dev: bool) -> None:
user_settings_dir: Path = get_user_settings_dir(install_dir, dev)
if not user_settings_dir.is_dir():
user_settings_dir.mkdir(parents=True, exist_ok=True)
save_file: Path = user_settings_dir / 'python_command.save'
with open(save_file, 'w') as f:
f.write('\n'.join(python_cmd) + '\n')