all repos — mgba @ ecee71cfa1ccd99ce3de8a0ebb38ba37292439bb

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