/* * Threads of Fate 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 "cdutils.h" #include "generic.h" #include "Input.h" #include "Output.h" #include "String.h" #include "Main.h" #include "cdabstract.h" CODE_BEGINS public: Appli() : tourne(0), nb_seqs(0), f_def(0), f_iso(0), f_out(0), cdutil(0) {} virtual ~Appli() { delete cdutil; delete f_def; delete f_iso; delete f_out; } private: unsigned int tourne; struct t_index_tab { unsigned long address; unsigned char flags; long pad; long index; long type; }; struct t_sequence { unsigned int n; unsigned int sum; String prefix; String name; int type; }; String title, iso_filename, prefix; unsigned long iso_size; unsigned int nb_records, nb_seqs; struct t_sequence sequences[1000]; Handle * f_def, * f_iso, * f_out; cdutils * cdutil; unsigned char user_data[2352]; virtual int startup() throw (GeneralException) { verbosity = M_INFO; fprintf(stderr, "Threads of Fate 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]); throw Exit(-1); } printm(M_STATUS, "Processing file %s...\n", argv[1]); f_def = new Input(argv[1]); if (process_def_file()) { printm(M_ERROR, "Unable to process the definition file \"%s\"...\n", argv[1]); throw Exit(-1); } iso_filename = argv[2]; printm(M_STATUS, "Begin processing iso file.\n"); f_iso = open_iso(iso_filename); if (check_iso()) { printm(M_ERROR, "Invalid iso file for " + title + "\n"); printm(M_ERROR, "===> Make sure you are using a Genuine iso file.\n"); } else { printm(M_INFO, "Genuine " + title + " iso detected.\n"); } cdutil = new cdutils(f_iso); printm(M_STATUS, "Entering files read sequence\n"); read_files(); throw Exit(0); } /* * Ugly but working... for now */ int process_def_file() { String t; unsigned int n, sum = 0; *f_def >> title; printm(M_INFO, "Read title: " + title + "\n"); *f_def >> t; iso_size = t.to_int(); printm(M_INFO, "Read iso size: %lu bytes\n", iso_size); *f_def >> prefix; printm(M_INFO, "Read global directory prefix: " + prefix + "\n"); *f_def >> t; nb_records = t.to_int(); printm(M_INFO, "Read total of records: %u\n", nb_records); while (1) { *f_def >> t; n = t.to_int(); 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; *f_def >> sequences[nb_seqs].prefix; *f_def >> t; sequences[nb_seqs].type = t.to_int(); *f_def >> sequences[nb_seqs].name; printm(M_INFO, "Read definition of sequence %i:\n===> %5i (sum = %5i) chunks of " + sequences[nb_seqs].name + " (" + sequences[nb_seqs].prefix + ")\n", nb_seqs, n, sum); nb_seqs++; } } long check_iso() { unsigned long length; length = f_iso->GetSize(); if (length < 0) { printm(M_INFO, "Can not get file size, assuming reading from cd.\n"); } else { printm(M_INFO, "Filesize of iso file " + iso_filename + " is %ld bytes\n", length); if (length != iso_size) { return 1; } } return 0; } void read_files() { t_index_tab index_tab[10000]; unsigned long i; unsigned long j; unsigned int seq = 0; unsigned long indexer; unsigned char fat[24576]; #define INDEXPOS 24 cdutil->sector_seek(INDEXPOS); for (i = INDEXPOS; i < (INDEXPOS + 12); i++) { printm(M_INFO, "Reading fat sector %lu\n", i); cdutil->read_sector(&fat[2048 * (i - INDEXPOS)], MODE_2_FORM_1); } indexer = 0; for (j = 0; j < 24576; j += 4) { unsigned char c1, c2, c3; c1 = fat[j]; c2 = fat[j + 1]; c3 = fat[j + 2] & 0x7f; index_tab[indexer].address = c1 + c2 * 256 + c3 * 65536; index_tab[indexer].index = j / 4; index_tab[indexer].flags = fat[j + 2] & 0x80; index_tab[indexer].pad = fat[j + 3]; printm(M_INFO, "Found a quite valid index: number %4lu, address %6lu - flags = %02x - pad = %i\n", indexer, index_tab[indexer].address, fat[j + 3] & 0x80, fat[j + 3] & 0x7f); indexer++; if (indexer == nb_records) break; } printm(M_STATUS, "Index file generation complete.\n\n"); index_tab[indexer].address = f_iso->GetSize() / 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]; size -= index_tab[i].pad * 8; file_dump(index_tab[i].address, size, i, seq); if (verbosity >= M_INFO) { fprintf(stderr, "\n"); } } } fprintf(stderr, "\n"); } void file_dump(unsigned long debut, unsigned long taille, long num, int seq) { long i; long nbsects; String nom; char type = sequences[seq].type; char ptitbidule[] = "-\\|/"; nom = "./" + prefix + "/"; MKDIR(nom.to_charp()); nom += sequences[seq].prefix + "/"; MKDIR(nom.to_charp()); nom += String().set("%04ld.out", num); f_out = new Output(nom); nbsects = taille / sec_sizes[type]; if (taille % sec_sizes[type]) nbsects++; cdutil->sector_seek(debut); for (i = 0; i < nbsects; i++) { if (verbosity < M_INFO) fprintf(stderr, " (%c)\010\010\010\010\010", ptitbidule[((tourne++) >> 8) % 4]); cdutil->read_sector(user_data, type); if (i != (nbsects - 1)) { f_out->write(user_data, sec_sizes[type]); } else { f_out->write(user_data, taille % sec_sizes[type] ? taille % sec_sizes[type] : sec_sizes[type]); } } delete f_out; f_out = 0; printm(M_BARE, " (*) Dumped file number %4ld - type \"" + sequences[seq].name + "\" \r", num); } CODE_ENDS