Skip to content

Commit eae20c6

Browse files
committed
Support bps patching
1 parent 747df5a commit eae20c6

File tree

3 files changed

+106
-13
lines changed

3 files changed

+106
-13
lines changed

Diff for: src/main.c

+19-13
Original file line numberDiff line numberDiff line change
@@ -902,27 +902,33 @@ static const char *kAssetFileCandidates[] = {
902902
};
903903

904904
static void LoadAssets() {
905-
const char *verify_failed = NULL;
906-
907905
size_t length = 0;
908906
uint8 *data = NULL;
909-
for (int i = 0; i < 2 && data == NULL; i++) {
907+
for (int i = 0; i < 2 && data == NULL; i++)
910908
data = ReadWholeFile(kAssetFileCandidates[i], &length);
911-
if (data && !VerifyAssetsFile(data, length)) {
912-
verify_failed = kAssetFileCandidates[i];
913-
free(data);
914-
data = NULL;
915-
}
916-
}
917909

918910
if (!data) {
919-
if (verify_failed)
920-
Die("Invalid assets file - Please re run 'python assets/restool.py'");
921-
else
911+
size_t bps_length, bps_src_length;
912+
uint8 *bps, *bps_src;
913+
914+
bps = ReadWholeFile("smw_assets.bps", &bps_length);
915+
if (!bps)
922916
Die("Failed to read smw_assets.dat. Please see the README for information about how you get this file.");
917+
918+
bps_src = ReadWholeFile("smw.sfc", &bps_src_length);
919+
if (!bps_src)
920+
Die("Missing file: smw.sfc");
921+
if (bps_src_length != 524288)
922+
Die("smw.sfc needs to be the unheadered ROM");
923+
924+
data = ApplyBps(bps_src, bps_src_length, bps, bps_length, &length);
925+
if (!data)
926+
Die("Unable to apply smw_assets.bps");
923927
}
924-
925928

929+
if (!VerifyAssetsFile(data, length))
930+
Die("Mismatching assets file - Please re run 'python assets/restool.py'");
931+
926932
uint32 offset = 88 + kNumberOfAssets * 4 + *(uint32 *)(data + 84);
927933

928934
for (size_t i = 0; i < kNumberOfAssets; i++) {

Diff for: src/util.c

+85
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,88 @@ const uint8 *FindAddrInMemblk(MemBlk data, uint32 addr) {
237237
return 0;
238238
return data.ptr + offset;
239239
}
240+
241+
static uint64 BpsDecodeInt(const uint8 **src) {
242+
uint64 data = 0, shift = 1;
243+
while(true) {
244+
uint8 x = *(*src)++;
245+
data += (x & 0x7f) * shift;
246+
if(x & 0x80) break;
247+
shift <<= 7;
248+
data += shift;
249+
}
250+
return data;
251+
}
252+
253+
#define CRC32_POLYNOMIAL 0xEDB88320
254+
255+
static uint32 crc32(const void *data, size_t length) {
256+
uint32 crc = 0xFFFFFFFF;
257+
const uint8 *byteData = (const uint8 *)data;
258+
for (size_t i = 0; i < length; i++) {
259+
crc ^= byteData[i];
260+
for (int j = 0; j < 8; j++)
261+
crc = (crc >> 1) ^ ((crc & 1) * CRC32_POLYNOMIAL);
262+
}
263+
return crc ^ 0xFFFFFFFF;
264+
}
265+
266+
267+
uint8 *ApplyBps(const uint8 *src, size_t src_size_in,
268+
const uint8 *bps, size_t bps_size, size_t *length_out) {
269+
const uint8 *bps_end = bps + bps_size - 12;
270+
271+
if (memcmp(bps, "BPS1", 4))
272+
return NULL;
273+
if (crc32(src, src_size_in) != *(uint32 *)(bps_end))
274+
return NULL;
275+
if (crc32(bps, bps_size - 4) != *(uint32 *)(bps_end + 8))
276+
return NULL;
277+
278+
bps += 4;
279+
uint32 src_size = BpsDecodeInt(&bps);
280+
uint32 dst_size = BpsDecodeInt(&bps);
281+
uint32 meta_size = BpsDecodeInt(&bps);
282+
uint32 outputOffset = 0;
283+
uint32 sourceRelativeOffset = 0;
284+
uint32 targetRelativeOffset = 0;
285+
if (src_size != src_size_in)
286+
return NULL;
287+
*length_out = dst_size;
288+
uint8 *dst = malloc(dst_size);
289+
if (!dst)
290+
return NULL;
291+
while (bps < bps_end) {
292+
uint32 cmd = BpsDecodeInt(&bps);
293+
uint32 length = (cmd >> 2) + 1;
294+
switch (cmd & 3) {
295+
case 0:
296+
while(length--) {
297+
dst[outputOffset] = src[outputOffset];
298+
outputOffset++;
299+
}
300+
break;
301+
case 1:
302+
while (length--)
303+
dst[outputOffset++] = *bps++;
304+
break;
305+
case 2:
306+
cmd = BpsDecodeInt(&bps);
307+
sourceRelativeOffset += (cmd & 1 ? -1 : +1) * (cmd >> 1);
308+
while (length--)
309+
dst[outputOffset++] = src[sourceRelativeOffset++];
310+
break;
311+
default:
312+
cmd = BpsDecodeInt(&bps);
313+
targetRelativeOffset += (cmd & 1 ? -1 : +1) * (cmd >> 1);
314+
while(length--)
315+
dst[outputOffset++] = dst[targetRelativeOffset++];
316+
break;
317+
}
318+
}
319+
if (dst_size != outputOffset)
320+
return NULL;
321+
if (crc32(dst, dst_size) != *(uint32 *)(bps_end + 4))
322+
return NULL;
323+
return dst;
324+
}

Diff for: src/util.h

+2
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,7 @@ const char *SkipPrefix(const char *big, const char *little);
3535
void StrSet(char **rv, const char *s);
3636
char *StrFmt(const char *fmt, ...);
3737
char *ReplaceFilenameWithNewPath(const char *old_path, const char *new_path);
38+
uint8 *ApplyBps(const uint8 *src, size_t src_size_in,
39+
const uint8 *bps, size_t bps_size, size_t *length_out);
3840

3941
#endif // ZELDA3_UTIL_H_

0 commit comments

Comments
 (0)