Skip to content

Commit

Permalink
Revise file size handling in file breakpoints.
Browse files Browse the repository at this point in the history
After changing the variable names to better reflect their actual usage and removing unnecessary conditional branches and intransparent additions, the code becomes a lot clearer.

Most notably though, this fixes a bug in patch configurations that have both a replacement file bigger than the original and a .jdiff patch on top: Previously, patchhooks_run() would have only received the size of the game's original file, cutting off the replacement file in the process.
Thanks to Gamer251's Mima patch for creating such a configuration and revealing this flaw.
  • Loading branch information
nmlgc committed May 26, 2014
1 parent bfcd6a4 commit f6fa4cb
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 41 deletions.
48 changes: 19 additions & 29 deletions thcrap/src/bp_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
#include "thcrap.h"
#include "bp_file.h"

#define POST_JSON_SIZE(fr) (fr)->pre_json_size + (fr)->patch_size

static int file_rep_hooks_run(file_rep_t *fr)
{
return patchhooks_run(
fr->hooks, fr->game_buffer, fr->rep_size, fr->game_size, fr->patch
fr->hooks, fr->game_buffer, POST_JSON_SIZE(fr), fr->pre_json_size, fr->patch
);
}

Expand All @@ -25,8 +27,8 @@ int file_rep_clear(file_rep_t *fr)
SAFE_FREE(fr->rep_buffer);
fr->patch = json_decref_safe(fr->patch);
fr->hooks = json_decref_safe(fr->hooks);
fr->rep_size = 0;
fr->game_size = 0;
fr->patch_size = 0;
fr->pre_json_size = 0;
fr->object = NULL;
SAFE_FREE(fr->name);
return 0;
Expand Down Expand Up @@ -81,7 +83,7 @@ int BP_file_name(x86_reg_t *regs, json_t *bp_info)
}
fn_len = strlen(*file_name) + 1;
fr->name = EnsureUTF8(*file_name, fn_len);
fr->rep_buffer = stack_game_file_resolve(fr->name, &fr->rep_size);
fr->rep_buffer = stack_game_file_resolve(fr->name, &fr->pre_json_size);
fr->hooks = patchhooks_build(fr->name);
if(fr->hooks) {
size_t diff_fn_len = fn_len + strlen(".jdiff") + 1;
Expand All @@ -93,7 +95,7 @@ int BP_file_name(x86_reg_t *regs, json_t *bp_info)
fr->patch = stack_game_json_resolve(diff_fn, &diff_size);
VLA_FREE(diff_fn);
}
fr->rep_size += diff_size;
fr->patch_size += diff_size;
}
return 1;
}
Expand All @@ -107,30 +109,15 @@ int BP_file_size(x86_reg_t *regs, json_t *bp_info)
size_t *file_size = json_object_get_register(bp_info, regs, "file_size");
int set_patch_size = !(json_is_false(json_object_get(bp_info, "set_patch_size")));
// ----------

// Other breakpoints
// -----------------
BP_file_name(regs, bp_info);
// -----------------

if(!file_size) {
return 1;
if(file_size && !fr->pre_json_size) {
fr->pre_json_size = *file_size;
}

fr->game_size = *file_size;

if(fr->patch) {
// If we only have a patch and no replacement file, the replacement size
// doesn't yet include the actual base file part
if(!fr->rep_buffer) {
fr->rep_size += fr->game_size;
}
if(set_patch_size) {
*file_size = fr->rep_size;
}
} else if(fr->rep_buffer && fr->rep_size) {
// Set size of replacement file
*file_size = fr->rep_size;
if(set_patch_size) {
BP_file_size_patch(regs, bp_info);
}
return 1;
}
Expand All @@ -143,8 +130,11 @@ int BP_file_size_patch(x86_reg_t *regs, json_t *bp_info)
// ----------
size_t *file_size = json_object_get_register(bp_info, regs, "file_size");
// ----------
if(file_size && fr->rep_size && fr->game_size != fr->rep_size) {
*file_size = fr->rep_size;
size_t post_json_size = POST_JSON_SIZE(fr);
// Yes, these checks are necessary because th08 needs to place this
// breakpoint on a generic memory allocation call.
if(file_size && fr->pre_json_size && fr->pre_json_size != post_json_size) {
*file_size = post_json_size;
}
return 1;
}
Expand Down Expand Up @@ -179,12 +169,12 @@ int BP_file_load(x86_reg_t *regs, json_t *bp_info)
BP_file_buffer(regs, bp_info);
// -----------------

if(!fr->game_buffer || !fr->rep_buffer || !fr->rep_size) {
if(!fr->game_buffer || !fr->rep_buffer || !fr->pre_json_size) {
return 1;
}

// Let's do it
memcpy(fr->game_buffer, fr->rep_buffer, fr->rep_size);
memcpy(fr->game_buffer, fr->rep_buffer, fr->pre_json_size);

file_rep_hooks_run(fr);

Expand Down Expand Up @@ -217,7 +207,7 @@ int DumpDatFile(const char *dir, const file_rep_t *fr)
sprintf(fn, "%s/%s", dir, fr->name);

if(!PathFileExists(fn)) {
file_write(fn, fr->game_buffer, fr->game_size);
file_write(fn, fr->game_buffer, fr->pre_json_size);
}
VLA_FREE(fn);
}
Expand Down
24 changes: 12 additions & 12 deletions thcrap/src/bp_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,21 @@

// File replacement state
typedef struct {
// Combined JSON patch that will be applied to the file
// Combined JSON patch to be applied to the file, and its maximum size
json_t *patch;
size_t patch_size;
// JSON array of hook functions to be run on this file
json_t *hooks;

// File name. Enforced to be in UTF-8
char *name;

// Size of the thing we're replacing the game's file with
size_t rep_size;
// Size of the game's own file in the game's own memory
size_t game_size;

// Potential replacement file, applied before the JSON patch
void *rep_buffer;
// Size of [rep_buffer] if we have one; otherwise, size of the original
// game file. [game_buffer] is guaranteed to be at least this large.
size_t pre_json_size;

void *game_buffer;

// Pointer to an object of the game's file class.
Expand Down Expand Up @@ -76,8 +77,7 @@ int BP_file_name(x86_reg_t *regs, json_t *bp_info);
* Type: register
*
* [set_patch_size]
* Set to false to not write the size of the patched file
* to the [file_size] register.
* Set to false to skip the call to BP_file_size().
* Type: bool
*
* Other breakpoints called
Expand All @@ -87,10 +87,10 @@ int BP_file_name(x86_reg_t *regs, json_t *bp_info);
int BP_file_size(x86_reg_t *regs, json_t *bp_info);

/**
* If we define a larger buffer in [BP_file_size], the game's decompression
* algorithm may produce bogus data after the end of the original file.
* This breakpoint can be used to write the actual size of the completely
* patched file separately from [BP_file_size].
* Writes the post-JSON file size to the game's memory. This is a separate
* breakpoint because th08's archive decompression algorithm produces bogus
* data after the end of the original file in case a larger than expected
* file size is written at BP_file_size().
*
* Own JSON parameters
* -------------------
Expand Down

0 comments on commit f6fa4cb

Please sign in to comment.