Skip to content

Commit 7d92d91

Browse files
committed
simplify api, add ips patch truncation
1 parent de02e59 commit 7d92d91

File tree

17 files changed

+374
-456
lines changed

17 files changed

+374
-456
lines changed

README.md

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,31 +28,35 @@ an example of how it would look in your code.
2828
```c
2929
uint8_t* apply_patch(
3030
const uint8_t* src_data, size_t src_size,
31-
const uint8_t* patch_data, size_t patch_size, enum PatchType type,
31+
const uint8_t* patch_data, size_t patch_size,
3232
size_t* out_size
3333
) {
34+
enum PatchType type;
35+
if (PatchError_OK != patch_get_type(&type, patch_data, patch_size))
36+
{
37+
return NULL;
38+
}
3439

35-
uint8_t* out = NULL;
36-
37-
const enum PatchError result = patch(
38-
type,
39-
&out, out_size,
40-
src_data, src_size,
41-
patch_data, patch_size
42-
);
43-
44-
// if patch failed, no data is allocated, so out==NULL
45-
if (result != PatchError_OK)
40+
if (PatchError_OK != patch_get_size(type, out_size, src_size, patch_data, patch_size))
4641
{
47-
// handle error here
4842
return NULL;
4943
}
50-
else
44+
45+
uint8_t* out = malloc(out_size);
46+
if (!out)
5147
{
52-
// patch worked, out is now pointing to allocated data.
53-
// remember to call free when done!
54-
return out;
48+
return NULL
5549
}
50+
51+
if (PatchError_OK != patch_apply(type, out, out_size, src_data, src_size, patch_data, patch_size))
52+
{
53+
free(out);
54+
return NULL;
55+
}
56+
57+
// patch worked, out is now pointing to allocated data.
58+
// remember to call free when done!
59+
return out;
5660
}
5761
```
5862

examples/patcher/main.c

Lines changed: 59 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -15,45 +15,47 @@
1515
#include <stdlib.h>
1616
#include <string.h>
1717

18-
static uint8_t* ROM_DATA = {0};
1918
static uint8_t* PATCH_DATA = {0};
19+
static uint8_t* ROM_DATA = {0};
2020
static uint8_t* OUT_DATA = {0};
2121

22-
static size_t ROM_SIZE = {0};
2322
static size_t PATCH_SIZE = {0};
23+
static size_t ROM_SIZE = {0};
2424
static size_t OUT_SIZE = {0};
2525

26-
static int get_patch_type(const char* file_name)
26+
struct SizePair
2727
{
28-
static const char* extentions[] =
29-
{
30-
[PatchType_IPS] = ".ips",
31-
[PatchType_UPS] = ".ups",
32-
[PatchType_BPS] = ".bps",
33-
};
28+
const char* str;
29+
double size;
30+
};
3431

35-
const char* ext = strrchr(file_name, '.');
36-
if (!ext)
37-
{
38-
return -1;
39-
}
32+
static const char* PATCH_TYPE_STR[] =
33+
{
34+
[PatchType_IPS] = "ips",
35+
[PatchType_UPS] = "ups",
36+
[PatchType_BPS] = "bps",
37+
};
4038

41-
if (!strcmp(ext, extentions[PatchType_IPS]))
39+
// not perfect but it'll do
40+
static struct SizePair get_size_pair(size_t size)
41+
{
42+
struct SizePair pair;
43+
if (size > 1024 * 1024 * 100)
4244
{
43-
return PatchType_IPS;
45+
pair.str = "GiB";
46+
pair.size = (double)size / 1024.0 / 1024.0 / 1024.0;
4447
}
45-
46-
if (!strcmp(ext, extentions[PatchType_UPS]))
48+
else if (size > 1024 * 100)
4749
{
48-
return PatchType_UPS;
50+
pair.str = "MiB";
51+
pair.size = (double)size / 1024.0 / 1024.0;
4952
}
50-
51-
if (!strcmp(ext, extentions[PatchType_BPS]))
53+
else
5254
{
53-
return PatchType_BPS;
55+
pair.str = "KiB";
56+
pair.size = (double)size / 1024.0;
5457
}
55-
56-
return -1;
58+
return pair;
5759
}
5860

5961
static uint8_t* readfile(const char* filepath, size_t* size)
@@ -133,51 +135,59 @@ static int cleanup(const char* error_message)
133135
printf("ERROR: %s\n", error_message);
134136
}
135137

136-
if (ROM_DATA)
137-
{
138-
free(ROM_DATA);
139-
ROM_DATA = NULL;
140-
}
141138
if (PATCH_DATA)
142139
{
143140
free(PATCH_DATA);
144-
PATCH_DATA = NULL;
141+
}
142+
if (ROM_DATA)
143+
{
144+
free(ROM_DATA);
145145
}
146146
if (OUT_DATA)
147147
{
148148
free(OUT_DATA);
149-
OUT_DATA = NULL;
150149
}
151150

152-
return 1;
151+
return error_message ? EXIT_FAILURE : EXIT_SUCCESS;
153152
}
154153

155154
int main(int argc, char** argv)
156155
{
157156
if (argc < 4)
158157
{
159-
return cleanup("missing args: ./exe rom.bin patch.ips out.bin");
158+
return cleanup("missing args: ./exe patch.ips rom.bin out.bin");
160159
}
161160

162-
const char* rom_filename = argv[1];
163-
const char* patch_filename = argv[2];
161+
const char* patch_filename = argv[1];
162+
const char* rom_filename = argv[2];
164163
const char* out_filename = argv[3];
165164

166-
ROM_DATA = readfile(rom_filename, &ROM_SIZE);
167165
PATCH_DATA = readfile(patch_filename, &PATCH_SIZE);
166+
ROM_DATA = readfile(rom_filename, &ROM_SIZE);
168167

169-
if (!ROM_DATA || !ROM_SIZE || !PATCH_DATA || !PATCH_SIZE)
168+
if (!PATCH_DATA || !PATCH_SIZE || !ROM_DATA || !ROM_SIZE)
170169
{
171170
return cleanup("failed to read files");
172171
}
173172

174-
const int patch_type = get_patch_type(patch_filename);
175-
if (patch_type == -1)
173+
enum PatchType type;
174+
if (PatchError_OK != patch_get_type(&type, PATCH_DATA, PATCH_SIZE))
176175
{
177176
return cleanup("unknown patch type");
178177
}
179178

180-
if (PatchError_OK != patch(patch_type, &OUT_DATA, &OUT_SIZE, ROM_DATA, ROM_SIZE, PATCH_DATA, PATCH_SIZE))
179+
if (PatchError_OK != patch_get_size(type, &OUT_SIZE, ROM_SIZE, PATCH_DATA, PATCH_SIZE))
180+
{
181+
return cleanup("unknown patch size");
182+
}
183+
184+
OUT_DATA = malloc(OUT_SIZE);
185+
if (!OUT_DATA)
186+
{
187+
return cleanup("failed to allocate output");
188+
}
189+
190+
if (PatchError_OK != patch_apply(type, OUT_DATA, OUT_SIZE, ROM_DATA, ROM_SIZE, PATCH_DATA, PATCH_SIZE))
181191
{
182192
return cleanup("failed to patch file");
183193
}
@@ -187,8 +197,14 @@ int main(int argc, char** argv)
187197
return cleanup("failed to write patched file");
188198
}
189199

190-
printf("patched: %s\n", out_filename);
191-
cleanup(NULL);
200+
printf("patched!\n");
201+
printf("\tpatch_file: %s\n", patch_filename);
202+
printf("\tinput_file: %s\n", rom_filename);
203+
printf("\toutput_file: %s\n", out_filename);
204+
printf("\tpatch_type: %s\n", PATCH_TYPE_STR[type]);
205+
printf("\tpatch_size: %.2f %s\n", get_size_pair(PATCH_SIZE).size, get_size_pair(PATCH_SIZE).str);
206+
printf("\tsrc_size: %.2f %s\n", get_size_pair(ROM_SIZE).size, get_size_pair(ROM_SIZE).str);
207+
printf("\tdst_size: %.2f %s\n", get_size_pair(OUT_SIZE).size, get_size_pair(OUT_SIZE).str);
192208

193-
return 0;
209+
return cleanup(NULL);
194210
}

src/CMakeLists.txt

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
cmake_minimum_required(VERSION 3.0.2)
22

33
project(patch LANGUAGES C)
4-
add_library(patch patch.c)
4+
add_library(patch
5+
patch.c
6+
bps/bps.c
7+
ips/ips.c
8+
ups/ups.c
9+
common/common.c
10+
)
511

6-
add_subdirectory(ips)
7-
add_subdirectory(ups)
8-
add_subdirectory(bps)
12+
# add_subdirectory(ips)
13+
# add_subdirectory(ups)
14+
# add_subdirectory(bps)
915

10-
target_link_libraries(patch PRIVATE ips ups bps)
16+
# target_link_libraries(patch PRIVATE ips ups bps)
1117
target_include_directories(patch PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
1218

1319
target_compile_options(patch PRIVATE

src/bps/CMakeLists.txt

Lines changed: 0 additions & 15 deletions
This file was deleted.

src/bps/bps.c

Lines changed: 13 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -5,60 +5,11 @@
55

66
/* SOURCE: https://www.romhacking.net/documents/764/ */
77
#include "bps.h"
8-
#include <string.h>
8+
#include "common/common.h"
99

10-
11-
#define PATCH_HEADER_SIZE 0x4
10+
#define PATCH_HEADER_SIZE 0x4U
1211
/* header + src / dst / meta sizes + command + crc32 */
13-
#define PATCH_MIN_SIZE (PATCH_HEADER_SIZE + 3 + 1 + 12)
14-
15-
16-
/* SOURCE: https://web.archive.org/web/20190108202303/http://www.hackersdelight.org/hdcodetxt/crc.c.txt */
17-
static uint32_t crc32(const uint8_t* data, const size_t size)
18-
{
19-
int crc;
20-
unsigned int byte, c;
21-
const unsigned int g0 = 0xEDB88320, g1 = g0>>1,
22-
g2 = g0>>2, g3 = g0>>3, g4 = g0>>4, g5 = g0>>5,
23-
g6 = (g0>>6)^g0, g7 = ((g0>>6)^g0)>>1;
24-
25-
crc = 0xFFFFFFFF;
26-
for (size_t i = 0; i < size; i++) {
27-
byte = data[i];
28-
crc = crc ^ byte;
29-
c = ((crc<<31>>31) & g7) ^ ((crc<<30>>31) & g6) ^
30-
((crc<<29>>31) & g5) ^ ((crc<<28>>31) & g4) ^
31-
((crc<<27>>31) & g3) ^ ((crc<<26>>31) & g2) ^
32-
((crc<<25>>31) & g1) ^ ((crc<<24>>31) & g0);
33-
crc = ((unsigned)crc >> 8) ^ c;
34-
}
35-
return ~crc;
36-
}
37-
38-
/* this can fail if the int is bigger than 8 bytes */
39-
static size_t vln_read(const uint8_t* data, size_t* offset)
40-
{
41-
size_t result = 0;
42-
size_t shift = 0;
43-
44-
/* just in case its a bad patch, only run until max size */
45-
for (uint8_t i = 0; i < sizeof(size_t); ++i)
46-
{
47-
const uint8_t value = data[*offset];
48-
++*offset;
49-
50-
if (value & 0x80)
51-
{
52-
result += (value & 0x7F) << shift;
53-
break;
54-
}
55-
56-
result += (value | 0x80) << shift;
57-
shift += 7;
58-
}
59-
60-
return result;
61-
}
12+
#define PATCH_MIN_SIZE (PATCH_HEADER_SIZE + 3U + 1U + 12U)
6213

6314
bool bps_verify_header(const uint8_t* patch, size_t patch_size)
6415
{
@@ -75,7 +26,7 @@ bool bps_verify_header(const uint8_t* patch, size_t patch_size)
7526
return true;
7627
}
7728

78-
bool bps_get_sizes(
29+
bool bps_get_size(
7930
const uint8_t* patch, size_t patch_size,
8031
size_t* dst_size, size_t* src_size, size_t* meta_size, size_t* offset
8132
) {
@@ -109,7 +60,7 @@ bool bps_get_sizes(
10960
}
11061

11162
/* dst_size: large enough to fit entire output */
112-
bool bps_patch(
63+
bool bps_patch_apply(
11364
uint8_t* dst, size_t dst_size,
11465
const uint8_t* src, size_t src_size,
11566
const uint8_t* patch, size_t patch_size
@@ -128,7 +79,7 @@ bool bps_patch(
12879
size_t target_size = 0;
12980
size_t metadata_size = 0;
13081

131-
if (!bps_get_sizes(patch, patch_size, &target_size, &source_size, &metadata_size, &patch_offset))
82+
if (!bps_get_size(patch, patch_size, &target_size, &source_size, &metadata_size, &patch_offset))
13283
{
13384
return false;
13485
}
@@ -147,23 +98,19 @@ bool bps_patch(
14798
patch_offset += metadata_size;
14899

149100
/* crc's are at the last 12 bytes, each 4 bytes each. */
150-
uint32_t src_crc = 0;
151-
uint32_t dst_crc = 0;
152-
uint32_t patch_crc = 0;
153-
154-
memcpy(&src_crc, patch + (patch_size - 12), sizeof(src_crc));
155-
memcpy(&dst_crc, patch + (patch_size - 8), sizeof(dst_crc));
156-
memcpy(&patch_crc, patch + (patch_size - 4), sizeof(patch_crc));
101+
const uint32_t src_crc = read32(patch, patch_size - 12);
102+
const uint32_t dst_crc = read32(patch, patch_size - 8);
103+
const uint32_t patch_crc = read32(patch, patch_size - 4);
157104

158105
/* check that the src and patch is valid. */
159106
/* dst is checked at the end. */
160-
if (src_crc != crc32(src, src_size))
107+
if (src_crc != patch_crc32(src, src_size))
161108
{
162109
return false;
163110
}
164111

165112
/* we don't check it's own crc32 (obviously) */
166-
if (patch_crc != crc32(patch, patch_size - 4))
113+
if (patch_crc != patch_crc32(patch, patch_size - 4))
167114
{
168115
return false;
169116
}
@@ -188,8 +135,7 @@ bool bps_patch(
188135
switch (action)
189136
{
190137
case SourceRead: {
191-
while (len--)
192-
{
138+
while (len--) {
193139
dst[dst_offset] = src[dst_offset];
194140
dst_offset++;
195141
}
@@ -223,7 +169,7 @@ bool bps_patch(
223169
}
224170
}
225171

226-
if (dst_crc != crc32(dst, dst_size))
172+
if (dst_crc != patch_crc32(dst, dst_size))
227173
{
228174
return false;
229175
}

0 commit comments

Comments
 (0)