User:Effect2/readRMPP.c
From Just Solve the File Format Problem
(Difference between revisions)
(Created page with " <nowiki> // "Effect2" at fileformats.archiveteam.org. CC0 (http://creativecommons.org/about/cc0). #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert...") |
m (Fixed the nowiki tag usage) |
||
(3 intermediate revisions by one user not shown) | |||
Line 33: | Line 33: | ||
char type[4]; | char type[4]; | ||
freadParanoid(type, 4, 1, stream); | freadParanoid(type, 4, 1, stream); | ||
− | assert(memcmp("cftc", type, 4) == 0); | + | assert(memcmp("cftc", type, 4) == 0 || memcmp("CFTC", type, 4) == 0); |
uint32_t len = readint32_tFromStream(stream); | uint32_t len = readint32_tFromStream(stream); | ||
Line 100: | Line 100: | ||
FILE* outf = fopen(name, "w"); | FILE* outf = fopen(name, "w"); | ||
fseek(f, entries[i].offset + 12, SEEK_SET); | fseek(f, entries[i].offset + 12, SEEK_SET); | ||
− | if (doFixDibs && memcmp(tc, "dib ", 4) == 0) { | + | if (doFixDibs && (memcmp(tc, "dib ", 4) == 0 || memcmp(tc, "DIB ", 4) == 0)) { |
fseek(f, 2, SEEK_CUR); | fseek(f, 2, SEEK_CUR); | ||
} | } | ||
− | uint8_t* raw = malloc(entries[i].length); | + | uint8_t* raw = malloc(entries[i].length - 4); |
− | fread(raw, entries[i].length, 1, f); | + | fread(raw, entries[i].length - 4, 1, f); |
− | fwrite(raw, entries[i].length, 1, outf); | + | fwrite(raw, entries[i].length - 4, 1, outf); |
free(raw); | free(raw); | ||
fclose(outf); | fclose(outf); |
Latest revision as of 13:42, 29 September 2019
// "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); } } }