shithub: zelda3

Download patch

ref: fbbb3f967a51fafe642e6140d0753979e73b4090
parent: 43db8cc0f529a2b8004a684526d91582d0d6d5d7
author: Snesrev <snesrev@protonmail.com>
date: Wed Aug 16 23:16:50 EDT 2023

Add BPS support

--- a/src/main.c
+++ b/src/main.c
@@ -811,9 +811,19 @@
 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 };
 
--- a/src/util.c
+++ b/src/util.c
@@ -193,3 +193,88 @@
     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;
+}
\ No newline at end of file
--- a/src/util.h
+++ b/src/util.h
@@ -35,5 +35,7 @@
 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_
\ No newline at end of file
--- a/zelda3.vcxproj
+++ b/zelda3.vcxproj
@@ -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>