Skip to content

Instantly share code, notes, and snippets.

@idimiter
Last active August 29, 2015 14:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save idimiter/8e9c6c987b3862c920eb to your computer and use it in GitHub Desktop.
Save idimiter/8e9c6c987b3862c920eb to your computer and use it in GitHub Desktop.
Reversing tools for Road To El Dorado & In Cold Blood game file formats
#include <stdio.h>
#include <stdlib.h>
#define MAX_FILENAME 256
typedef struct {
char magic[4]; // CLU
int version; // 2
int header_size;
int count;
int hash;
int sector_number; // -1
char name[60];
} CLUHeader;
typedef struct {
int name_offset;
int data_size;
int data_offset;
int hash;
} CLUFile;
int main(int ac, char** av) {
FILE *fp;
FILE *out;
CLUHeader header;
char** filenames;
CLUFile *files;
void *buf = NULL;
int bIsExtracted = 0;
if (ac < 2) {
printf("Usage: %s [clu filename]\n", av[0]);
return 0;
}
if ( !(fp = fopen(av[1], "rb")) ) {
printf("Cannot open file: %s", av[1]);
return -1;
}
fread(&header, sizeof(CLUHeader), 1, fp);
printf("%s\n\nMagic: %s\nName: %s\nVersion: %d\nFiles count: %d\n\n", av[1], header.magic, header.name, header.version, header.count);
// Allocate memory for filenames
filenames = (char **) malloc(header.count * sizeof(char *));
for (int i = 0; i < header.count; i++)
filenames[i] = (char *) malloc(MAX_FILENAME);
files = (CLUFile *) malloc(header.count * sizeof(CLUFile));
fread(files, sizeof(CLUFile), header.count, fp);
for (int i = 0; i < header.count; i++) {
fseek(fp, files[i].name_offset, SEEK_SET);
fgets(filenames[i], MAX_FILENAME, fp);
printf("[%d] %s\n\tSize: %d bytes\n\tHash: %04X\n\tOffset: 0x%08X\n", i, filenames[i], files[i].data_size, files[i].hash, files[i].data_offset);
// Extract file data
if (!bIsExtracted && ac > 2) {
if ( i == atoi(av[2]) ) {
// if ( (out = fopen(filenames[i], "wb")) ) {
if ( (out = fopen(av[2], "wb")) ) {
buf = malloc(files[i].data_size);
fseek(fp, files[i].data_offset, SEEK_SET);
fread(buf, files[i].data_size, 1, fp);
fwrite(buf, files[i].data_size, 1, out);
fclose(out);
free(buf);
bIsExtracted = 1;
}
}
}
}
fclose(fp);
if (ac > 2) {
if (bIsExtracted)
printf("\nFile %s extacted successfully!\n", filenames[atoi(av[2])]);
else
printf("\nCould not extact %s!\n", av[2]);
}
// Memory cleanup
for (int i = 0; i < header.count; i++)
free(filenames[i]);
free(filenames);
free(files);
return 0;
}
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define MAX_STRING 1024
typedef struct {
int version; // 1
char magic[16]; // LNKT
char description[32];
int count;
int unknown; // 6
} LNKTHeader; // 60 bytes
typedef struct {
int start_offset;
int offset;
int size;
int hash;
} LNKTEntry; // 16 bytes
int main(int ac, char **av) {
FILE* fp;
LNKTHeader header;
LNKTEntry* entries;
char buf[MAX_STRING];
if (ac < 2) {
printf("Usage: %s <LNKT file>\n", av[0]);
return 0;
}
if (!(fp = fopen(av[1], "rb")) ) {
printf("Cannot open: %s!\n", av[1]);
return -1;
}
fread(&header, sizeof(LNKTHeader), 1, fp);
printf("%s\n\nVersion: %d\nMagic: %s\nDescription: %s\nCount: %d\n", av[1], header.version, header.magic, header.description, header.count);
entries = (LNKTEntry*) calloc(header.count, sizeof(LNKTEntry));
fread(entries, sizeof(LNKTEntry), header.count, fp);
for (int i = 0; i < header.count; i++) {
fseek(fp, entries[i].offset, SEEK_SET);
bzero(buf, MAX_STRING);
fread(buf, entries[i].size, 1, fp);
printf("[%d]:\n\tUNKNOWN: %04X\n\tOffset: %04X\n\tSize: %d\n\tHash: %04X\n\n%s\n\n==================\n\n", i, entries[i].unknown1, entries[i].offset, entries[i].size, entries[i].hash, buf);
}
fclose(fp);
free(entries);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int make_hash(const char* s) {
int hash = 0;
for (int i = 0; i < strlen(s); i++) {
hash = s[i] + 131 * hash;
}
return hash;
}
int main(int ac, char** av) {
if (ac < 2) {
printf("Usage: %s <string>\n", av[0]);
return 0;
}
printf("%s: %04X\n", av[1], make_hash(av[1]));
return 0;
}
#include <stdio.h>
#include <stdlib.h>
typedef struct {
unsigned char R;
unsigned char G;
unsigned char B;
unsigned char A;
} ColMap;
typedef struct {
char magic[4];
int version; // 1
ColMap pallete[256];
int frames_count;
} PCBHeader;
typedef struct {
int atlas_x;
int atlas_y;
int width;
int height;
} PCBFrame;
void dumpFile(int offset, FILE *fp, PCBHeader *hdr) {
FILE *out;
unsigned char *data;
PCBFrame frame;
char outfile[256];
sprintf(outfile, "out_%08X.ppm", offset);
fseek(fp, offset, SEEK_SET);
fread(&frame, sizeof(frame), 1, fp);
printf(" size: %dx%d u1:%d u2:%d\n", frame.width, frame.height, frame.atlas_x, frame.atlas_y);
int dataSize = frame.width * frame.height;
data = (unsigned char*) malloc(dataSize);
fread(data, dataSize, 1, fp);
// Export data to PPM
out = fopen(outfile, "wb");
fprintf(out, "P6\n# pcb2ppm\n%d %d\n255\n", frame.width, frame.height);
for (int i = 0; i < dataSize; i++) {
ColMap color = hdr->pallete[data[i]];
fwrite(&color.B, 1, 1, out);
fwrite(&color.G, 1, 1, out);
fwrite(&color.R, 1, 1, out);
}
free(data);
fclose(out);
}
int main(int ac, char** av) {
FILE *fp;
PCBHeader hdr;
int* frame_offsets;
if ( ac < 2 ) {
printf("Usage: %s [PCB file]\n", av[0]);
return 0;
}
if ( !(fp = fopen(av[1], "rb")) ) {
printf("Cannot open [%s]\n", av[1]);
return -1;
}
fread(&hdr, sizeof(PCBHeader), 1, fp);
printf("%s\n\nMagic: %s\nVersion: %d\nFrames: %d\n", av[1], hdr.magic, hdr.version, hdr.frames_count);
// Read frames offsets
frame_offsets = (int *) malloc(hdr.frames_count * sizeof(int));
fread(frame_offsets, sizeof(int), hdr.frames_count, fp);
for (int i = 0; i < hdr.frames_count; i++) {
printf("Frame [%d]: 0x%08X", i, frame_offsets[i]);
dumpFile(frame_offsets[i], fp, &hdr);
}
free(frame_offsets);
fclose(fp);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
typedef struct {
unsigned char R;
unsigned char G;
unsigned char B;
unsigned char A;
} ColMap;
typedef struct {
char magic[4]; // RTX
int version; // 2
int unknown; // 1
ColMap pallete[256];
int width;
int height;
int data_offset; // most of the time 256x256
// Those are smaller images of the above all power of two, for the mipmaps
int offset1; // 128x128
int offset2; // 64x64
int offset3; // 32x32
int offset4; // 16x16
int offset5; // 8x8
int offset6; // 4x4
int offset7; // 2x2
int offset8; // EOF
} RTXHeader;
int main(int ac, char** av) {
FILE *fp;
FILE *out;
RTXHeader hdr;
int* frame_offsets;
unsigned char* data;
if ( ac < 2 ) {
printf("Usage: %s [RevTex file]\n", av[0]);
return 0;
}
if ( !(fp = fopen(av[1], "rb")) ) {
printf("Cannot open [%s]\n", av[1]);
return -1;
}
fread(&hdr, sizeof(RTXHeader), 1, fp);
printf("%s\n\nMagic: %s\nVersion: %d\nResolution: %dx%d\n", av[1], hdr.magic, hdr.version, hdr.width, hdr.height);
int data_size = hdr.width * hdr.height;
printf("First size: %d\n", data_size);
fseek(fp, hdr.data_offset, SEEK_SET);
data = (unsigned char *) malloc(data_size);
fread(data, data_size, 1, fp);
fclose(fp);
// Export data to PPM
out = fopen("RTX_export.ppm", "wb");
fprintf(out, "P6\n# pcb2ppm\n%d %d\n255\n", hdr.width, hdr.height);
for (int i = 0; i < data_size; i++) {
ColMap color = hdr.pallete[data[i]];
fwrite(&color.B, 1, 1, out);
fwrite(&color.G, 1, 1, out);
fwrite(&color.R, 1, 1, out);
}
fclose(out);
free(data);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment