Last active
January 8, 2022 16:50
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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