mirror of
https://github.com/snesrev/zelda3.git
synced 2025-07-23 04:13:00 +02:00
Add BPS support
This commit is contained in:
16
src/main.c
16
src/main.c
@@ -811,9 +811,19 @@ uint32 g_asset_sizes[kNumberOfAssets];
|
||||
static void LoadAssets() {
|
||||
size_t length = 0;
|
||||
uint8 *data = ReadWholeFile("zelda3_assets.dat", &length);
|
||||
if (!data)
|
||||
data = ReadWholeFile("tables/zelda3_assets.dat", &length);
|
||||
if (!data) Die("Failed to read zelda3_assets.dat. Please see the README for information about how you get this file.");
|
||||
if (!data) {
|
||||
size_t bps_length, bps_src_length;
|
||||
uint8 *bps, *bps_src;
|
||||
bps = ReadWholeFile("zelda3_assets.bps", &bps_length);
|
||||
if (!bps)
|
||||
Die("Failed to read zelda3_assets.dat. Please see the README for information about how you get this file.");
|
||||
bps_src = ReadWholeFile("zelda3.sfc", &bps_src_length);
|
||||
if (!bps_src)
|
||||
Die("Missing file: zelda3.sfc");
|
||||
data = ApplyBps(bps_src, bps_src_length, bps, bps_length, &length);
|
||||
if (!data)
|
||||
Die("Unable to apply zelda3_assets.bps. Please make sure you got the right version of 'zelda3.sfc'");
|
||||
}
|
||||
|
||||
static const char kAssetsSig[] = { kAssets_Sig };
|
||||
|
||||
|
85
src/util.c
85
src/util.c
@@ -193,3 +193,88 @@ MemBlk FindIndexInMemblk(MemBlk data, size_t i) {
|
||||
return (MemBlk) { 0, 0 };
|
||||
return (MemBlk) { data.ptr + left_off, right_off - left_off };
|
||||
}
|
||||
|
||||
|
||||
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_
|
@@ -202,6 +202,7 @@
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
|
Reference in New Issue
Block a user