Skip to content

Instantly share code, notes, and snippets.

@ahmubashshir
Created March 13, 2020 05:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ahmubashshir/39831cb534ebc05c7483ec2e4de2f2d5 to your computer and use it in GitHub Desktop.
Save ahmubashshir/39831cb534ebc05c7483ec2e4de2f2d5 to your computer and use it in GitHub Desktop.
To the Moon.rgssad extractor, forked from http://ancurio.bplaced.net/stuff/ttm_pack.c and edited...
/*
* ttm_unpack: An unpacker for the game "To the Moon"'s datafiles.
*
* Copyright (c) 2012, David Gow <david@ingeniumdigital.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* To compile: cc -o ttm_unpack ttm_unpack.c
*
* To run: cd <path to To the Moon>
* ttm_unpack [optional packname]
* mv To\ the\ Moon.rgssad To\ the\ Moon.rgssad.old
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/stat.h>
#define MAXBUF 1024
uint32_t decryptState = 0xdeadcafe;
unsigned char* strip(unsigned char* str, const size_t n)
{
unsigned char buffer[MAXBUF] = {'\0'};
size_t i = 0;
size_t j = 0;
size_t max = (n<MAXBUF)? n : MAXBUF -1;
while (i < max )
{
if ( str[i]>=32 && str[i]<=255 )
{
buffer[j++] = str[i];
}
i++;
}
memset(str, '\0', max);
i = 0;
while( i < j)
{
str[i] = buffer[i];
i++;
}
str[j] = '\0';
return str;
}
void advanceDecryptor()
{
decryptState = decryptState * 7 + 3;
}
void extractAll(FILE *packfile)
{
uint32_t sig;
fread(&sig,sizeof(sig),1,packfile);
if (sig != 1397966674)
{
printf("Error: not a valid 'To the Moon' datafile.\n");
exit(-1);
}
fread(&sig,sizeof(sig),1,packfile);
if (sig != 16794689)
{
printf("Error: not a valid 'To the Moon' datafile.\n");
exit(-1);
}
int numFiles = 0;
// For each file...
while (!feof(packfile))
{
// Get the length of the filename
uint32_t fileNameLen;
fread(&fileNameLen,sizeof(fileNameLen),1,packfile);
fileNameLen ^= decryptState;
advanceDecryptor();
// feof(), of course, won't trigger unless we've tried to read _after_ the
// end of the file, so re-check here.
if (feof(packfile)) break;
// Read and decrypt the filename
char *fileName = malloc(fileNameLen+1);
fread(fileName,sizeof(char),fileNameLen,packfile);
// Better make this compile as c89
int i;
for (i = 0; i < fileNameLen; ++i)
{
fileName[i] ^= (decryptState & 0xFF);
advanceDecryptor();
// A nice hack to mkdir everything.
if (fileName[i] == '\\')
{
fileName[i] = '\0';
mkdir(fileName, S_IRWXU);
fileName[i] = '/';
}
}
strip( fileName, fileNameLen );
printf("Extracting: \"%s\"...\n",fileName);
// Get the file size
uint32_t fileSize;
fread(&fileSize, sizeof(fileSize),1,packfile);
fileSize ^= decryptState;
advanceDecryptor();
// Save off the decryptor state, we need to restore it later
uint32_t oldDecryptState = decryptState;
// Open an output file
FILE *outFile = fopen(fileName,"wb");
if (!outFile)
{
printf("Error: could not create \"%s\".\n",fileName);
printf("Check that you have write permissions to the current directory.\n");
printf("Extraction will now halt.\n");
fclose(packfile);
exit(-1);
}
// Read and decrypt the file
long idx;
for (idx = 0; idx < fileSize; ++idx)
{
char c = fgetc(packfile);
char xorValue = ((char*)(&decryptState))[(idx&3)];
c ^= xorValue;
fputc(c, outFile);
if ((idx&3) == 3) advanceDecryptor();
}
// Close
fclose(outFile);
// And finally, restore the decryptor state.
// This is a bit weird, but seems to have been done
// to make sure the game has fast random-access to packed
// files.
decryptState = oldDecryptState;
numFiles++;
}
printf("Extracted %d files!\n", numFiles);
}
int main(int argc, char **argv)
{
char *filename = "To the Moon.rgssad";
if (argc > 1)
{
filename = argv[1];
}
FILE *packfile = fopen(filename, "rb");
if (!packfile)
{
printf("Error: could not open pack file \"%s\".\n", filename);
printf("Make sure you're in the game directory.\n");
return -1;
}
extractAll(packfile);
fclose(packfile);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment