Skip to content

Instantly share code, notes, and snippets.

@Bl4ckSh4rk
Last active January 8, 2022 16:50
Show Gist options
  • Save Bl4ckSh4rk/c4ba0696d140a56aa285ff2eddbc88a3 to your computer and use it in GitHub Desktop.
Save Bl4ckSh4rk/c4ba0696d140a56aa285ff2eddbc88a3 to your computer and use it in GitHub Desktop.
tool to (de)compress Pokemon Rumble World save data files (contents of 00slot00), uses https://github.com/madler/zlib
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <zlib.h> // https://github.com/madler/zlib
// zlib bugfix
#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
# include <fcntl.h>
# include <io.h>
# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
#else
# define SET_BINARY_MODE(file)
#endif
#define DATA_HEADER_SIZE 0x30
#define CRC32_OFFSET 0x08
#define COMPRESSION_FLAG_OFFSET 0x28
#define DECOMPRESSED_SIZE_OFFSET 0x2E
int main(int argc, char** argv)
{
if(argc < 2)
{
printf("Argument error!\n\n");
return 0;
}
FILE *fp_in = fopen(argv[1], "rb");
if (!fp_in)
{
printf("Reading failed!\n\n");
return 0;
}
// get full file size
fseek (fp_in, 0, SEEK_END);
int fileSize = ftell(fp_in);
rewind (fp_in);
// read data header
Bytef *data_header = (Bytef *)malloc(DATA_HEADER_SIZE);
if(data_header == NULL)
{
printf("Failed to allocated memory!\n\n");
fclose(fp_in);
return 0;
}
fread(data_header, 1, DATA_HEADER_SIZE, fp_in);
// read (de)compressed data area
int dataAreaSize = fileSize - DATA_HEADER_SIZE;
Bytef *data = (Bytef *)malloc(dataAreaSize);
if(data == NULL)
{
printf("Failed to allocated memory!\n\n");
fclose(fp_in);
return 0;
}
fseek (fp_in, 0, DATA_HEADER_SIZE);
fread(data, 1, dataAreaSize, fp_in);
fclose(fp_in);
// reserve memory for new (de)compressed data
int newDataAreaSize = (data_header[DECOMPRESSED_SIZE_OFFSET] << 8 & 0xFFFF) + data_header[DECOMPRESSED_SIZE_OFFSET + 1]; // size of the decompressed data
Bytef *new_data = (Bytef *)malloc(newDataAreaSize);
if(new_data == NULL)
{
printf("Failed to allocated memory!\n\n");
fclose(fp_in);
return 0;
}
z_stream stream;
int checksum;
if(data_header[0x28] == 1) // compressed -> decompress
{
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
stream.avail_in = dataAreaSize;
stream.next_in = (Bytef *)data;
stream.avail_out = newDataAreaSize;
stream.next_out = (Bytef *)new_data;
inflateInit(&stream);
inflate(&stream, Z_NO_FLUSH);
inflateEnd(&stream);
data_header[0x28] = 0;
}
else if (data_header[0x28] == 0) // decompressed -> compress
{
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
stream.avail_in = dataAreaSize;
stream.next_in = (Bytef *)data;
stream.avail_out = compressBound(dataAreaSize);
stream.next_out = (Bytef *)new_data;
deflateInit(&stream, Z_BEST_COMPRESSION);
deflate(&stream, Z_FINISH);
deflateEnd(&stream);
newDataAreaSize = stream.total_out;
data_header[0x28] = 1;
checksum = crc32(0, new_data, newDataAreaSize);
data_header[CRC32_OFFSET] = checksum >> 24;
data_header[CRC32_OFFSET + 1] = checksum >> 16;
data_header[CRC32_OFFSET + 2] = checksum >> 8;
data_header[CRC32_OFFSET + 3] = checksum;
}
else
{
printf("Invalid compression flag. Please check your file.");
free(data_header);
free(data);
free(new_data);
return 0;
}
FILE *fp_out;
if(argc == 3)
fp_out = fopen(argv[2], "wb");
else
fp_out = fopen(argv[1], "wb");
if (!fp_out)
{
printf("Writing failed!\n\n");
return 0;
}
// write all the data back to a file
fwrite(data_header, 1, DATA_HEADER_SIZE, fp_out);
fseek (fp_out, 0, 0x30);
fwrite(new_data, 1, newDataAreaSize, fp_out);
fclose(fp_out);
free(data_header);
free(data);
free(new_data);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment