User:Effect2/readRMPP.c

From Just Solve the File Format Problem
Revision as of 13:41, 29 September 2019 by Effect2 (Talk | contribs)

Jump to: navigation, search

// "Effect2" at fileformats.archiveteam.org. CC0 (http://creativecommons.org/about/cc0). #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <endian.h> #include <inttypes.h> #include <errno.h> typedef struct { uint32_t typecode; // Always readable in ASCII, as far as has been observed uint32_t length; uint32_t seq; uint32_t offset; } HeaderEntry; void freadParanoid(void *ptr, size_t size, size_t nmemb, FILE *stream) { assert(fread(ptr, size, nmemb, stream) == nmemb); } uint32_t readint32_tFromStream(FILE* stream) { // Works for both int and uint, as endianness conversion doesn't care about that uint32_t orig; uint32_t i; freadParanoid(&orig, sizeof(int32_t), 1, stream); i = le32toh(orig); return i; } // Assumes that the cursor is already in the right place. long readcftc(FILE* stream, HeaderEntry** returnedEntries) { char type[4]; freadParanoid(type, 4, 1, stream); assert(memcmp("cftc", type, 4) == 0 || memcmp("CFTC", type, 4) == 0); uint32_t len = readint32_tFromStream(stream); uint32_t seq = readint32_tFromStream(stream); assert(seq == 0); assert(len % 4 == 0); long numEntries = len / (4 * 4); // 4 fields of 4 bytes each HeaderEntry* entries = malloc(sizeof(HeaderEntry) * numEntries); long numActualEntries = 0; for (long i = 0; i < numEntries; i ++) { HeaderEntry entry; entry.typecode = readint32_tFromStream(stream); entry.length = readint32_tFromStream(stream); entry.seq = readint32_tFromStream(stream); entry.offset = readint32_tFromStream(stream); if (entry.typecode != 0) { entries[numActualEntries] = entry; numActualEntries ++; } } *returnedEntries = entries; // This will probably leave some (from samples, it's going to be much less than a kilobyte) of uninitialized memory in the array, but properly behaving code should never read into it return numActualEntries; } int main(int argc, char** argv) { if (argc != 3) { printf("Usage: [program] [command] [target file]\n"); printf("command can be a combination of:\n"); printf(" l - List sections in file\n"); printf(" d - Dump sections to the current directory, named offset.type\n"); printf(" f - when using d, Fix the dib sections by removing the 2 empty bytes at the start. Does not remove the space at the end of the file extension.\n"); return 0; } int doList = (strchr(argv[1], 'l') != NULL); int doDump = (strchr(argv[1], 'd') != NULL); int doFixDibs = (strchr(argv[1], 'f') != NULL); FILE* f = fopen(argv[2], "r"); if (f == NULL) { printf("Could not open file, errno %d\n", errno); return 2; } char magic[12]; freadParanoid(magic, 12, 1, f); if (!(memcmp(magic, "RIFF ", 4) == 0 && memcmp(magic + 8, "RMMP ", 4) == 0)) { printf("Not an RMMP file\n"); fclose(f); return 2; } HeaderEntry* entries; long h = readcftc(f, &entries); if (doList) { printf("File contains %d entries.\n", h); } for (int i = 0; i < h; i ++) { char* tc = (char*) &(entries[i].typecode); if (doList) { printf("%c%c%c%c : length: % 7d seq: % 5d offset: % 7d\n", tc[0], tc[1], tc[2], tc[3], entries[i].length, entries[i].seq, entries[i].offset); } if (doDump) { fseek(f, entries[i].offset + 12, SEEK_SET); char* tc = (char*) &(entries[i].typecode); char name[30]; snprintf(name, 30, "%d.%c%c%c%c", entries[i].offset, tc[0], tc[1], tc[2], tc[3]); FILE* outf = fopen(name, "w"); fseek(f, entries[i].offset + 12, SEEK_SET); if (doFixDibs && (memcmp(tc, "dib ", 4) == 0 || memcmp(tc, "DIB ", 4) == 0)) { fseek(f, 2, SEEK_CUR); } uint8_t* raw = malloc(entries[i].length - 4); fread(raw, entries[i].length - 4, 1, f); fwrite(raw, entries[i].length - 4, 1, outf); free(raw); fclose(outf); } } }

Personal tools
Namespaces

Variants
Actions
Navigation
Toolbox