farmerbb / RED-Project

ROM Extraction Documentation Project
181 stars 8 forks source link

Sonic Mega Collection (GameCube) #138

Open RealRelativeEase opened 6 months ago

RealRelativeEase commented 6 months ago

isixwayiso over on Reddit has shared an executable of the script mentioned in #53 to extract the Mega Drive ROMs, so it's a little more user-friendly.

You'll also need Dolphin and a copy of Sonic Mega Collection, I've used the PAL version.

  1. Open Dolphin, right-click Sonic Mega Collection and select Properties.
  2. Go to Filesystem, expand sonic, then data. Right-click roms and select Extract Files... to extract to a folder of your choice. There are two subfolders, EU and US containing the ROMs in .dat format.
  3. Place the dat2bin.exe in the same folder as the ROMs, then open a command line interface and type in cd [directory of dat2bin.exe and ROMs in .dat format], press Enter to confirm.
  4. Type in dat2bin.exe [Name of ROM.dat] "[Name of ROM.bin]" and press Enter to confirm to save a copy of the ROM in .bin format. E.g.: dat2bin.exe flicky.dat "Flicky.bin".
aceofstax commented 5 months ago

So it looks like that webpage with the original C++ code was taken down. That's unfortunate. I vaguely remember that zenhax site from no-intro database entries for some of the titles found on the Gamecube edition of this game. It's kind that someone decided to compile it for people who don't know how, but I think people safety conscious would just prefer the source code.

I believe I have a copy of that source code still, but no idea who to credit if that was indeed the original place it was posted. I'm a terrible coder, but decent tinkerer. Played around with it enough and found that you need to compile it in Visual Studio for it to compile correctly. Something about the header file Visual Studio uses.

Here is the source code. As is, it should compile fine on VS2017. However later versions of Visual Studio do not use "stdafx.h". Replace that text with "pch.h" and it should compile without issues. Or at least it did in mid 2023.

Do not credit me for the source code. All credit goes to the original author.

#include "stdafx.h"
#include <fstream>

int processdata(unsigned char *InData, unsigned char *OutData, int filedatasize) // OutData=0 to get size
{
   int CurrIn = 0x4; //Skip size
   int CurrOut = 0;
   while (CurrIn < filedatasize)
   {
      int Code = InData[CurrIn++];
      for (int i = 0; (i < 8) && (CurrIn < filedatasize); i++)
      {
         if (Code & 1)
         {
            if (OutData)
               OutData[CurrOut] = InData[CurrIn];
            CurrOut++;
            CurrIn++;
         }
         else
         {
            int OutDict = InData[CurrIn++];
            int OutCnt = InData[CurrIn++];
            OutDict |= ((OutCnt << 4) & 0xF00);
            OutCnt = (OutCnt & 0xF) + 2;
            OutDict |= (CurrOut & ~0xFFF);
            OutDict += 0x12;
            if (OutDict >= CurrOut)
               OutDict -= 0x1000;
            for (int j = 0; j <= OutCnt; j++)
            {
               if (OutData)
                  OutData[CurrOut] = OutDict >= 0 ? OutData[OutDict] : 0;
               CurrOut++;
               OutDict++;
            }
         }
         Code >>= 1;
      }
   }
   return CurrOut;
}

int _tmain(int argc, _TCHAR* argv[])
{
   if (argc < 3)
   {
      printf("Wrong number of arguments");
      return -1;
   }
   std::ifstream InFile(argv[1], std::ios::binary);
   InFile.seekg(0, std::ios::end);
   int filesize = InFile.tellg();
   InFile.seekg(0, std::ios::beg);
   unsigned char *InData = new unsigned char[filesize];
   InFile.read((char*)InData, filesize);
   int swapend = 0x702;
   if (filesize <= swapend)
      swapend = filesize-1;
   for (int i = 0; (3 * i) < swapend; i++)
   {
      char Tmp = InData[i];
      InData[i] = InData[swapend - i];
      InData[swapend - i] = Tmp;
   }
   int filedatasize = 0;
   for (int Curr = 0; Curr < 4; Curr++)
   {
      filedatasize <<= 8;
      filedatasize |= InData[3 - Curr];
   }

   for (int i = 0; i < filedatasize; i++)
      InData[i] ^= 0x54;

   // Only calling to get the output size.  Will be same as OutSize below.
   // Can skip this if using e.g. push_back() instead of unsigned char[]
   // or just set MaxBinSize large enough (max output file size).
   const int MaxBinSize = processdata(InData, 0, filedatasize);

   unsigned char* OutData = new unsigned char[MaxBinSize];
   const int OutSize = processdata(InData, OutData, filedatasize);
   swapend = 156;
   for (int i = 0; i < OutSize; i += (swapend + 1))
   {
      if (i + swapend >= OutSize)
         swapend = OutSize - i - 1;
      for (int j = 0; (j * 3) < swapend; j++)
      {
         char Tmp = OutData[i+j];
         OutData[i+j] = OutData[i+swapend-j];
         OutData[i+swapend-j] = Tmp;
      }
   }

   std::ofstream OutFile(argv[2], std::ios::binary);
   OutFile.write((char*)OutData, OutSize);

   delete[] InData;
   delete[] OutData;
   return 0;
}

Usage is the same as you described in your original post.