ddr-tools/tcb-extract.c

161 lines
4.2 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include "BemaniLZ/BemaniLZ.h"
#if defined(_WIN32)
#define MKDIR(a) _mkdir(a);
#else
#define MKDIR(a) mkdir(a, 0777);
#endif
int search_for_tcbs(const unsigned char *data, size_t dataLength, uint32_t *offsets, char *isCompressed)
{
int numFound = 0;
for(unsigned int i = 0; i < dataLength; i++)
{
if(data[i] == 'T' && data[i+1] == 'C' && data[i+2] == 'B')
{
if(data[i+3] == 0
&& data[i+4] == 0
&& data[i+5] == 0
&& data[i+6] == 0
&& data[i+7] == 0
&& data[i+8] == 0
&& data[i+9] == 0
&& data[i+10] == 0)
{
offsets[numFound] = i;
isCompressed[numFound] = 0;
numFound++;
}
else if(i > 0 && (data[i-1] == 0x10 || data[i-1] == 0x90))
{
offsets[numFound] = i - 1;
isCompressed[numFound] = 1;
numFound++;
}
}
}
return numFound;
}
int main(int argc, char *argv[])
{
if(argc != 3)
{
printf("TCB Extractor\n");
printf("Usage:\n");
printf("%s <MODE> <file containing TCBs>\n", argv[0]);
printf("Modes:\n");
printf("1 - Bruteforce search for compressed and uncompressed TCBs\n");
printf("2 - Extract from file beginning with table (compressed entries)\n");
printf("3 - Extract from file beginning with table (uncompressed entries)\n");
return EXIT_FAILURE;
}
FILE *compressed = fopen(argv[2], "rb");
if(!compressed)
{
printf("Error opening %s\n", argv[2]);
return EXIT_FAILURE;
}
/* Get input data */
printf("Loading %s...\n", argv[2]);
fseek(compressed, 0, SEEK_END);
int length = ftell(compressed);
fseek(compressed, 0, SEEK_SET);
unsigned char *compressedData = malloc(length);
fread(compressedData, length, 1, compressed);
fclose(compressed);
/* Search for TCBs */
printf("Searching for TCBs...\n");
uint32_t offsets[8000];
char isCompressed[8000] = {0};
int numEntries = 0;
// file has table
if(argv[1][0] == '2' || argv[1][0] == '3')
{
int offset = 0;
uint32_t firstEntry = (uint32_t)compressedData[0];
if(firstEntry % 4)
{
printf("WARNING: First entry is number of entries to follow (%d).\n", firstEntry);
}
printf("first entry at 0x%08X\n", firstEntry);
memcpy(offsets, compressedData, firstEntry);
numEntries = firstEntry/4;
if(argv[1][0] == '2')
{
for(int i = 0; i < numEntries; i++)
{
isCompressed[i] = 1;
}
}
}
else // no table, need to search for TCBs
{
numEntries = search_for_tcbs(compressedData, length, offsets, isCompressed);
}
offsets[numEntries] = length;
printf("Found %d TCBs\n", numEntries);
int numCompressed = 0;
for(int i = 0; i < sizeof(isCompressed); i++)
{
if(isCompressed[i] == 1)
numCompressed++;
}
printf("%d are compressed\n", numCompressed);
/* Decompress and save TCBs */
char outFolderName[100];
snprintf(outFolderName, 100, "_%s", argv[2]);
MKDIR(outFolderName);
chdir(outFolderName);
uint8_t *buffer = malloc(1024*1024*10);
for(unsigned int i = 0; i < numEntries; i++)
{
if (offsets[i+1] == 0)
break;
printf("Extracting files: %04d/%d [%d%%]\r", i+1, numEntries, ((i+1)*100)/numEntries);
int len = offsets[i+1] - offsets[i];
char filename[100];
snprintf(filename, 100, "%08X.tcb", offsets[i]);
FILE *out = fopen(filename, "wb");
if(isCompressed[i])
{
int decLen = decompress(compressedData + offsets[i], len, buffer, 1024*1024*10);
fwrite(buffer, decLen, 1, out);
}
else
{
fwrite(compressedData + offsets[i], len, 1, out);
}
fclose(out);
}
printf("\n");
free(compressedData);
free(buffer);
return 0;
}