/* * Valkyrie Profile extractor by Nicolas "Pixel" Noble (nicolas@nobis-crew.org) * Highly based upon Yazoo's Chrono Cross CD extractor * * ******** Original disclaimer by Yazoo ******** * * Chrono Cross CD extractor Copyright 2000-2001 by Yazoo (hamm@efrei.fr) Revision 0.1b ANSI C * * * Features: * * Dump the complete content of Chrono Chross CD1/CD2 US and Japanese version It requires a iso * named Chrono1.iso in the same directory * * Todo list: * * Find a way to locate end of the last file Better support for CD2 Dump in subdirectory according * to CD1/CD2 repartition Recompilation in Visual C++ 6 for disk speed optimisation Source comment * and reorganisation Log feature (Optional since you can redirect output with > ) Progression * indicator Better detection of the ISO with error control Major code optimisation Integration in * main Chrono Cross Hacking tool * * ******** End of original disclaimer by Yazoo ******** * */ #include #include #include #include #include "fileutils.h" #include "cdutils.h" #include "generic.h" unsigned int tourne = 0; struct t_index_tab { unsigned long address; unsigned char flags; long type; long index; }; struct t_sequence { unsigned int n; unsigned int sum; char *prefix; char *name; int type; }; char *title, *iso_filename, *prefix; unsigned long iso_size; unsigned int nb_records, nb_seqs = 0; struct t_sequence sequences[1000]; long check_iso(FILE * f_iso); void read_files(FILE * f_iso); void file_dump(FILE * f_iso, unsigned long debut, unsigned long taille, long num, int seq); int process_def_file(FILE * f_def); unsigned char user_data[2352]; int main(int argc, char **argv) { FILE * f_def, * f_iso; verbosity = M_STATUS; fprintf(stderr, "Valkyrie Profile File Extractor by Nicolas \"Pixel\" Noble\n" "Highly based upon the Chrono Cross File Extractor By Yazoo\n\n"); if (argc != 3) { fprintf(stderr, "Usage: %s \nSee readme.txt for details\n", argv[0]); exit(-1); } printm(M_STATUS, "Processing file %s...\n", argv[1]); if (!(f_def = fopen(argv[1], "r"))) { printm(M_ERROR, "Unable to open the definition file \"%s\"...\n", argv[1]); exit(-1); } if (process_def_file(f_def)) { fclose(f_def); printm(M_ERROR, "Unable to process the definition file \"%s\"...\n", argv[1]); exit(-1); } iso_filename = argv[2]; printm(M_STATUS, "Begin processing iso file.\n"); if (!(f_iso = fopen(iso_filename, "r"))) { printm(M_ERROR, "Unable to open the iso file \"%s\"...\n", iso_filename); exit(-1); } if (check_iso(f_iso)) { printm(M_ERROR, "Invalid iso file for %s\n", title); printm(M_ERROR, "===> Make sure you are using a Genuine iso file.\n"); } else { printm(M_INFO, "Genuine %s iso detected.\n", title); } printm(M_STATUS, "Entering files read sequence\n"); read_files(f_iso); fclose(f_iso); exit(0); } /* * Ugly but working... for now */ int process_def_file(FILE * f_def) { char t[1024], *p; unsigned int n, sum = 0; if ((p = strchr(fgets(t, 1024, f_def), '\n')) == NULL) return 1; *p = 0; printm(M_INFO, "Read title: %s\n", t); title = strdup(t); if (fscanf(f_def, "%lu\n", &iso_size) != 1) return 1; printm(M_INFO, "Read iso size: %lu bytes\n", iso_size); if ((p = strchr(fgets(t, 1024, f_def), '\n')) == NULL) return 1; *p = 0; printm(M_INFO, "Read global directory prefix: %s\n", t); prefix = strdup(t); if (fscanf(f_def, "%u\n", &nb_records) != 1) return 1; printm(M_INFO, "Read total of records: %u\n", nb_records); while (1) { if (fscanf(f_def, "%u\n", &n) != 1) return 1; if (!n) { if (sum == nb_records) { printm(M_INFO, "Definition file seems coherent\n"); return 0; } else { printm(M_ERROR, "Definition file incoherent\n"); return 1; } } sum += n; sequences[nb_seqs].n = n; sequences[nb_seqs].sum = sum; if ((p = strchr(fgets(t, 1024, f_def), '\n')) == NULL) return 1; *p = 0; sequences[nb_seqs].prefix = strdup(t); if (fscanf(f_def, "%u\n", &n) != 1) return 1; sequences[nb_seqs].type = n; if ((p = strchr(fgets(t, 1024, f_def), '\n')) == NULL) return 1; *p = 0; sequences[nb_seqs].name = strdup(t); printm(M_INFO, "Read definition of sequence %i:\n===> %5i (sum = %5i) chunks of %s (%s)\n", nb_seqs, n, sum, t, sequences[nb_seqs].prefix); nb_seqs++; } } long check_iso(FILE * f_iso) { unsigned long length; length = filesize(f_iso); printm(M_INFO, "Filesize of iso file %s is %ld bytes\n", iso_filename, length); if (length != iso_size) { return 1; } return 0; } void read_files(FILE * f_iso) { t_index_tab index_tab[10000]; unsigned long i; unsigned long j; unsigned int seq = 0; unsigned long indexer; unsigned char fat[20480]; unsigned char key[256]; #define INDEXPOS 150 sector_seek(f_iso, INDEXPOS); for (i = INDEXPOS; i < (INDEXPOS + 10); i++) { printm(M_INFO, "Reading fat sector %lu\n", i); read_sector(f_iso, &fat[2048 * (i - INDEXPOS)], MODE_2_FORM_1); } memcpy(key, fat + 0x4f00, 256); printm(M_INFO, "Decrypting.\n"); for (i = 0; i < 20480; i++) { fat[i] ^= key[i % 256]; } indexer = 0; for (j = 4; j < 20480; j += 4) { unsigned char m, s, f; m = fat[j]; s = fat[j + 1]; f = fat[j + 2]; index_tab[indexer].address = from_MSF(m, s, f); if (m || s || f) { index_tab[indexer].index = j / 4; index_tab[indexer].flags = fat[j + 3]; printm(M_INFO, "Found a quite valid index: number %4lu, address %6lu - flags = %02x\n", indexer, index_tab[indexer].address, fat[j + 3]); indexer++; if (indexer == nb_records) break; } else { printm(M_WARNING, "Ignored invalid index chunk number %4lu\n", j / 4); } } printm(M_STATUS, "Index file generation complete.\n\n"); index_tab[indexer].address = filesize(f_iso) / 2352; for (i = 0; i < nb_records; i++) { if (sequences[seq].sum == i) seq++; index_tab[i].type = sequences[seq].type; if (sequences[seq].type == 0) { printm(M_INFO, "%6lu - %02x: ignored\n", index_tab[i].address, index_tab[i].flags); } else { int size; printm(M_INFO, "%6lu - %02x: ", index_tab[i].address, index_tab[i].flags); size = index_tab[i + 1].address - index_tab[i].address; size *= sec_sizes[index_tab[i].type]; file_dump(f_iso, index_tab[i].address, size, i, seq); if (verbosity >= M_INFO) { fprintf(stderr, "\n"); } } } fprintf(stderr, "\n"); } void file_dump(FILE * f_iso, unsigned long debut, unsigned long taille, long num, int seq) { long i; long nbsects; char nom[1000] = ""; char *extention = ".out"; char nom_t[1000] = ""; int f_out; char type = sequences[seq].type; char ptitbidule[] = "-\\|/"; sprintf(nom_t, "%ld", num); strcat(nom, "./"); strcat(nom, prefix); strcat(nom, "/"); MKDIR(nom); strcat(nom, sequences[seq].prefix); strcat(nom, "/"); MKDIR(nom); if (num < 10) strcat(nom, "0"); if (num < 100) strcat(nom, "0"); if (num < 1000) strcat(nom, "0"); strcat(nom, nom_t); strcat(nom, extention); f_out = open(nom, O_WRONLY | O_CREAT | O_TRUNC, 00644); nbsects = taille / sec_sizes[type]; if (taille % sec_sizes[type]) nbsects++; sector_seek(f_iso, debut); for (i = 0; i < nbsects; i++) { if (verbosity < M_INFO) fprintf(stderr, " (%c)\010\010\010\010\010", ptitbidule[((tourne++) >> 8) % 4]); read_sector(f_iso, user_data, type); if (i != (nbsects - 1)) { write(f_out, user_data, sec_sizes[type]); } else { write(f_out, user_data, taille % sec_sizes[type] ? taille % sec_sizes[type] : sec_sizes[type]); } } close(f_out); fprintf(stderr, " (*) Dumped file number %4ld - type \"%s\" \r", num, sequences[seq].name); }