src/util/patch-ips.c (view raw)
1/* Copyright (c) 2013-2014 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "util/patch-ips.h"
7
8#include "util/patch.h"
9#include "util/vfs.h"
10
11static size_t _IPSOutputSize(struct Patch* patch, size_t inSize);
12static bool _IPSApplyPatch(struct Patch* patch, void* in, size_t inSize, void* out, size_t outSize);
13
14bool loadPatchIPS(struct Patch* patch) {
15 patch->vf->seek(patch->vf, 0, SEEK_SET);
16
17 char buffer[5];
18 if (patch->vf->read(patch->vf, buffer, 5) != 5) {
19 return false;
20 }
21
22 if (memcmp(buffer, "PATCH", 5) != 0) {
23 return false;
24 }
25
26 patch->vf->seek(patch->vf, -3, SEEK_END);
27 if (patch->vf->read(patch->vf, buffer, 3) != 3) {
28 return false;
29 }
30
31 if (memcmp(buffer, "EOF", 3) != 0) {
32 return false;
33 }
34
35 patch->outputSize = _IPSOutputSize;
36 patch->applyPatch = _IPSApplyPatch;
37 return true;
38}
39
40size_t _IPSOutputSize(struct Patch* patch, size_t inSize) {
41 UNUSED(patch);
42 return inSize;
43}
44
45bool _IPSApplyPatch(struct Patch* patch, void* in, size_t inSize, void* out, size_t outSize) {
46 if (patch->vf->seek(patch->vf, 5, SEEK_SET) != 5) {
47 return false;
48 }
49 memcpy(out, in, inSize > outSize ? outSize : inSize);
50 uint8_t* buf = out;
51
52 while (true) {
53 uint32_t offset = 0;
54 uint16_t size = 0;
55
56 if (patch->vf->read(patch->vf, &offset, 3) != 3) {
57 return false;
58 }
59
60 if (offset == 0x464F45) {
61 return true;
62 }
63
64 offset = (offset >> 16) | (offset & 0xFF00) | ((offset << 16) & 0xFF0000);
65 if (patch->vf->read(patch->vf, &size, 2) != 2) {
66 return false;
67 }
68 if (!size) {
69 // RLE chunk
70 if (patch->vf->read(patch->vf, &size, 2) != 2) {
71 return false;
72 }
73 size = (size >> 8) | (size << 8);
74 uint8_t byte;
75 if (patch->vf->read(patch->vf, &byte, 1) != 1) {
76 return false;
77 }
78 if (offset + size > outSize) {
79 return false;
80 }
81 memset(&buf[offset], byte, size);
82 } else {
83 size = (size >> 8) | (size << 8);
84 if (offset + size > outSize) {
85 return false;
86 }
87 if (patch->vf->read(patch->vf, &buf[offset], size) != size) {
88 return false;
89 }
90 }
91 }
92}