all repos — mgba @ e6ea94d2296eae963a48a18d009217a38d92bf9b

mGBA Game Boy Advance Emulator

src/util/patch-ips.c (view raw)

 1#include "util/patch-ips.h"
 2
 3#include "util/patch.h"
 4#include "util/vfs.h"
 5
 6static size_t _IPSOutputSize(struct Patch* patch, size_t inSize);
 7static bool _IPSApplyPatch(struct Patch* patch, void* out, size_t outSize);
 8
 9bool loadPatchIPS(struct Patch* patch) {
10	patch->vf->seek(patch->vf, 0, SEEK_SET);
11
12	char buffer[5];
13	if (patch->vf->read(patch->vf, buffer, 5) != 5) {
14		return false;
15	}
16
17	if (memcmp(buffer, "PATCH", 5) != 0) {
18		return false;
19	}
20
21	patch->vf->seek(patch->vf, -3, SEEK_END);
22	if (patch->vf->read(patch->vf, buffer, 3) != 3) {
23		return false;
24	}
25
26	if (memcmp(buffer, "EOF", 3) != 0) {
27		return false;
28	}
29
30	patch->outputSize = _IPSOutputSize;
31	patch->applyPatch = _IPSApplyPatch;
32	return true;
33}
34
35size_t _IPSOutputSize(struct Patch* patch, size_t inSize) {
36	UNUSED(patch);
37	return inSize;
38}
39
40bool _IPSApplyPatch(struct Patch* patch, void* out, size_t outSize) {
41	if (patch->vf->seek(patch->vf, 5, SEEK_SET) != 5) {
42		return false;
43	}
44	uint8_t* buf = out;
45
46	while (true) {
47		uint32_t offset = 0;
48		uint16_t size = 0;
49
50		if (patch->vf->read(patch->vf, &offset, 3) != 3) {
51			return false;
52		}
53
54		if (offset == 0x464F45) {
55			return true;
56		}
57
58		offset = (offset >> 16) | (offset & 0xFF00) | ((offset << 16) & 0xFF0000);
59		if (patch->vf->read(patch->vf, &size, 2) != 2) {
60			return false;
61		}
62		if (!size) {
63			// RLE chunk
64			if (patch->vf->read(patch->vf, &size, 2) != 2) {
65				return false;
66			}
67			size = (size >> 8) | (size << 8);
68			uint8_t byte;
69			if (patch->vf->read(patch->vf, &byte, 1) != 1) {
70				return false;
71			}
72			if (offset + size > outSize) {
73				return false;
74			}
75			memset(&buf[offset], byte, size);
76		} else {
77			size = (size >> 8) | (size << 8);
78			if (offset + size > outSize) {
79				return false;
80			}
81			if (patch->vf->read(patch->vf, &buf[offset], size) != size) {
82				return false;
83			}
84		}
85	}
86}