save_patches always emitted the address element as fmt::format("0x%.8x"),
but for move_file and hide_file that element is a VFS path: load() keeps the
text in original_offset and skips u32 validation for those two types.
Round-tripping such a patch through save_patches replaced the source path
with 0x00000000.
The entry stays syntactically valid and keeps loading, so the patch is still
listed and can still be toggled in the Patch Manager while silently matching
no file. Re-downloading does not repair it either, since append_patches
discards an incoming patch whose Patch Version is not strictly greater.
Gate the emit on patch_type_uses_hex_offset, the predicate that already
existed for this and was used only on the load side. The numeric branch
keeps using offset rather than original_offset on purpose: an address
modifier is folded into offset at load time and the flat form emitted here
has nowhere to put it.
Co-Authored-By: Claude Opus 5 <[email protected]>
save_patches opened the target with fs::rewrite (write + create + trunc),
then discarded the result of file.write() and returned true unconditionally.
A write that fails part way leaves a truncated file, load() rejects the
whole file on a parse error, and import_patches refuses to write when
load() fails, so every later import returns -1 with no in-app recovery.
75e66ab5e made the patch config and the pad config atomic but missed this
function; save_config, 70 lines up in the same file, already writes through
fs::pending_file and checks the result. Do the same here.
Co-Authored-By: Claude Opus 5 <[email protected]>
sceNpTrophy fixes
- sceNpTrophyGetTrophyUnlockState: signed 1 was potentially shifted by 31(UB)
- sceNpTrophyUnlockTrophy: used a reader_lock and was missing check for read only context
cellGame fixes
- cellHddGameCheck: missing log parameters
- cellGameDataCheckCreate2: missing log parameter
- cellGameThemeInstall: condition inverted checking for extension + added tolower just in case
- cellGameThemeInstallFromBuffer: OOB access, buf is always filled from the start and then used as a parameter to the CB
sceNp fixes
- sceNpManagerGetTicket: Made accurate from RE
- sceNpDrmGetTimelimit: Fix msec calculation
sceNp2 fixes
-sceNpMatching2ContextStartAsync: avoid capturing ctx
-sceNpMatching2ContextStop: Minor error value swap
rpcn_client fixes
-add_friend: missing log parameter
-handle_friend_notification: misc validation issue
np_handler fixes
-ticket: Missing move in move constructor
-ticket::parse: Misc validation fix
-get_player_history_entry: potential UB fix
np_requests fixes
-Wrong CB event_type set for get_room_member_data_external_list!
-reply_tus_get_data was not copying status data!
-Order of error check in reply_get_room_member_data_external_list was wrong
-Improved logging
np_requests_gui:
-Added missing guards for gui_notifications
upnp_handler fixes
-Highest density of bugs per line of code in the west, let's pretend I never wrote this
signaling_handler fixes
-Swapped to multimap to avoid collisions on timestamps
Misc fixes