mirror of https://github.com/snesrev/smw.git
Support bps patching
This commit is contained in:
parent
747df5a2c7
commit
eae20c65c5
36
src/main.c
36
src/main.c
|
|
@ -902,27 +902,33 @@ static const char *kAssetFileCandidates[] = {
|
|||
};
|
||||
|
||||
static void LoadAssets() {
|
||||
const char *verify_failed = NULL;
|
||||
|
||||
size_t length = 0;
|
||||
uint8 *data = NULL;
|
||||
for (int i = 0; i < 2 && data == NULL; i++) {
|
||||
for (int i = 0; i < 2 && data == NULL; i++)
|
||||
data = ReadWholeFile(kAssetFileCandidates[i], &length);
|
||||
if (data && !VerifyAssetsFile(data, length)) {
|
||||
verify_failed = kAssetFileCandidates[i];
|
||||
free(data);
|
||||
data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
if (verify_failed)
|
||||
Die("Invalid assets file - Please re run 'python assets/restool.py'");
|
||||
else
|
||||
Die("Failed to read smw_assets.dat. Please see the README for information about how you get this file.");
|
||||
}
|
||||
|
||||
size_t bps_length, bps_src_length;
|
||||
uint8 *bps, *bps_src;
|
||||
|
||||
bps = ReadWholeFile("smw_assets.bps", &bps_length);
|
||||
if (!bps)
|
||||
Die("Failed to read smw_assets.dat. Please see the README for information about how you get this file.");
|
||||
|
||||
bps_src = ReadWholeFile("smw.sfc", &bps_src_length);
|
||||
if (!bps_src)
|
||||
Die("Missing file: smw.sfc");
|
||||
if (bps_src_length != 524288)
|
||||
Die("smw.sfc needs to be the unheadered ROM");
|
||||
|
||||
data = ApplyBps(bps_src, bps_src_length, bps, bps_length, &length);
|
||||
if (!data)
|
||||
Die("Unable to apply smw_assets.bps");
|
||||
}
|
||||
|
||||
if (!VerifyAssetsFile(data, length))
|
||||
Die("Mismatching assets file - Please re run 'python assets/restool.py'");
|
||||
|
||||
uint32 offset = 88 + kNumberOfAssets * 4 + *(uint32 *)(data + 84);
|
||||
|
||||
for (size_t i = 0; i < kNumberOfAssets; i++) {
|
||||
|
|
|
|||
85
src/util.c
85
src/util.c
|
|
@ -237,3 +237,88 @@ const uint8 *FindAddrInMemblk(MemBlk data, uint32 addr) {
|
|||
return 0;
|
||||
return data.ptr + offset;
|
||||
}
|
||||
|
||||
static uint64 BpsDecodeInt(const uint8 **src) {
|
||||
uint64 data = 0, shift = 1;
|
||||
while(true) {
|
||||
uint8 x = *(*src)++;
|
||||
data += (x & 0x7f) * shift;
|
||||
if(x & 0x80) break;
|
||||
shift <<= 7;
|
||||
data += shift;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
#define CRC32_POLYNOMIAL 0xEDB88320
|
||||
|
||||
static uint32 crc32(const void *data, size_t length) {
|
||||
uint32 crc = 0xFFFFFFFF;
|
||||
const uint8 *byteData = (const uint8 *)data;
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
crc ^= byteData[i];
|
||||
for (int j = 0; j < 8; j++)
|
||||
crc = (crc >> 1) ^ ((crc & 1) * CRC32_POLYNOMIAL);
|
||||
}
|
||||
return crc ^ 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
|
||||
uint8 *ApplyBps(const uint8 *src, size_t src_size_in,
|
||||
const uint8 *bps, size_t bps_size, size_t *length_out) {
|
||||
const uint8 *bps_end = bps + bps_size - 12;
|
||||
|
||||
if (memcmp(bps, "BPS1", 4))
|
||||
return NULL;
|
||||
if (crc32(src, src_size_in) != *(uint32 *)(bps_end))
|
||||
return NULL;
|
||||
if (crc32(bps, bps_size - 4) != *(uint32 *)(bps_end + 8))
|
||||
return NULL;
|
||||
|
||||
bps += 4;
|
||||
uint32 src_size = BpsDecodeInt(&bps);
|
||||
uint32 dst_size = BpsDecodeInt(&bps);
|
||||
uint32 meta_size = BpsDecodeInt(&bps);
|
||||
uint32 outputOffset = 0;
|
||||
uint32 sourceRelativeOffset = 0;
|
||||
uint32 targetRelativeOffset = 0;
|
||||
if (src_size != src_size_in)
|
||||
return NULL;
|
||||
*length_out = dst_size;
|
||||
uint8 *dst = malloc(dst_size);
|
||||
if (!dst)
|
||||
return NULL;
|
||||
while (bps < bps_end) {
|
||||
uint32 cmd = BpsDecodeInt(&bps);
|
||||
uint32 length = (cmd >> 2) + 1;
|
||||
switch (cmd & 3) {
|
||||
case 0:
|
||||
while(length--) {
|
||||
dst[outputOffset] = src[outputOffset];
|
||||
outputOffset++;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
while (length--)
|
||||
dst[outputOffset++] = *bps++;
|
||||
break;
|
||||
case 2:
|
||||
cmd = BpsDecodeInt(&bps);
|
||||
sourceRelativeOffset += (cmd & 1 ? -1 : +1) * (cmd >> 1);
|
||||
while (length--)
|
||||
dst[outputOffset++] = src[sourceRelativeOffset++];
|
||||
break;
|
||||
default:
|
||||
cmd = BpsDecodeInt(&bps);
|
||||
targetRelativeOffset += (cmd & 1 ? -1 : +1) * (cmd >> 1);
|
||||
while(length--)
|
||||
dst[outputOffset++] = dst[targetRelativeOffset++];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dst_size != outputOffset)
|
||||
return NULL;
|
||||
if (crc32(dst, dst_size) != *(uint32 *)(bps_end + 4))
|
||||
return NULL;
|
||||
return dst;
|
||||
}
|
||||
|
|
@ -35,5 +35,7 @@ const char *SkipPrefix(const char *big, const char *little);
|
|||
void StrSet(char **rv, const char *s);
|
||||
char *StrFmt(const char *fmt, ...);
|
||||
char *ReplaceFilenameWithNewPath(const char *old_path, const char *new_path);
|
||||
uint8 *ApplyBps(const uint8 *src, size_t src_size_in,
|
||||
const uint8 *bps, size_t bps_size, size_t *length_out);
|
||||
|
||||
#endif // ZELDA3_UTIL_H_
|
||||
Loading…
Reference in New Issue