micetools/src/micetools/micepatch/main.c

114 lines
3.7 KiB
C

#include "../lib/mice/mice.h"
#include "string.h"
void print_patches(patches_t* patches, char* filename) {
for (size_t i = 0; i < patches->nopatchsets; i++) {
patchset_t* patchset = patches->patchsets[i];
bool skip = patchset->name != NULL && strcmp(patchset->name, filename) != 0;
printf("Patch: %s (%s)\n", patchset->name, skip ? "skipped" : patchset->apply ? "applied" : "unapplied");
printf("- %s\n", patchset->description);
if (!skip) {
for (size_t j = 0; j < patchset->nopatches; j++) {
printf(":: %d bytes at %08x\n", patchset->patches[j].count, patchset->patches[j].offset);
}
}
puts("======================");
}
}
void apply_patches(patches_t* patches, char* filename) {
FILE* fp;
fopen_s(&fp, filename, "r+b");
if (fp == NULL) {
fprintf(stderr, "Failed to open %s for modification\n", filename);
return;
}
fseek(fp, 0L, SEEK_END);
size_t sz = ftell(fp);
for (size_t i = 0; i < patches->nopatchsets; i++) {
patchset_t* patchset = patches->patchsets[i];
if (patchset->name != NULL && strcmp(patchset->name, filename) != 0) {
continue;
}
for (size_t j = 0; j < patchset->nopatches; j++) {
patch_t patch = patchset->patches[j];
if (patch.offset + patch.count > sz) {
fprintf(stderr, "E: Patch %s[%d] outside file bounds\n", patchset->name, j);
goto done;
}
fseek(fp, patch.offset, SEEK_SET);
bool matches_from = true;
bool matches_to = true;
for (size_t k = 0; k < patch.count; k++) {
unsigned char seen;
if (!fread(&seen, 1, 1, fp)) {
matches_from = false;
matches_to = false;
break;
}
if (seen != patch.from[k]) matches_from = false;
if (seen != patch.to[k]) matches_to = false;
if (!(matches_from || matches_to)) break;
}
printf("%s[%d]: ", patchset->name, j);
if (patchset->apply) {
if (matches_to) {
puts("Already applied");
continue;
}
if (!matches_from) {
puts("From value missmatch! Ignoring");
continue;
}
fseek(fp, patch.offset, SEEK_SET);
fwrite(patch.to, 1, patch.count, fp);
puts("Patch applied");
} else {
if (matches_from) {
puts("Not applied");
continue;
}
if (!matches_to) {
puts("We didn't perform this patch. Leaving patched");
continue;
}
fseek(fp, patch.offset, SEEK_SET);
fwrite(patch.from, 1, patch.count, fp);
puts("Patch removed");
}
}
}
done:
fclose(fp);
}
int main(int argc, char** argv) {
if (argc != 3) {
fprintf(stderr, "Usage: %s <patch file> <exe>\n", argc > 0 ? argv[0] : "micepatch.exe");
return -1;
}
char error[json_error_max];
patches_t all_patches;
if (!load_patches(&all_patches, argv[1], error)) {
fprintf(stderr, "%s\n", error);
return -1;
}
puts("");
puts("Loaded patches:");
puts("---------------");
print_patches(&all_patches, argv[2]);
apply_patches(&all_patches, argv[2]);
free_patches(&all_patches);
return 0;
}