// thanks to groepaz and everyone else who wrote YAGCD, most of my info came from it // also thanks to WntrMute for loaning me some source to clear things up about the FST // (C) 2005 Andrew K andrew@aklabs.net // License: Take all you want, but credit for all you take. #include #include #include #include #include #define LIBGCMVERSION "libGCM Version 0.1a (build Sep 4 2005)" // defines for internal program control (not necessarily GCM-related) #define GCNDVD_MAGICNUM 0xc2339f3d // if this isn't correct in the GCM, // the program will abort. #define GCNDVD_SECTORS 712880 // not really used, but left for future updates that might use it #define GCNDVD_SECTORSIZE 2048 // " " #define GCNDVD_FNAME_LENGTH 1024 #define GCM_MAX_PIECES 29 // change this if (for whatever reason) you add a new entry in GCMPieces // these all define indices in the GCMPieces global array where // information about (where to look in the GCM for) a given piece // of data about the GCM can be found. The rationale should // be easy enough to follow. #define GCM_DHEAD 0 #define GCM_DHEADINF 1 #define GCM_APPLOADER 2 #define GCM_DHEAD_GAMECODE 3 #define GCM_DHEAD_GAMEMAKER 4 #define GCM_DHEAD_DVDMAGIC 5 #define GCM_DHEAD_GAMENAME 6 #define GCM_DHEAD_DEBUGMON 7 #define GCM_DHEAD_DEBUGMONADDR 8 #define GCM_DHEAD_BOOTFILE 9 #define GCM_DHEAD_FST 10 #define GCM_DHEAD_FSTSIZE 11 #define GCM_DHEAD_FSTMAXSIZE 12 #define GCM_DHEAD_USERPOS 13 #define GCM_DHEAD_USERLEN 14 #define GCM_DHEADINF_DEBUGMONSIZE 15 #define GCM_DHEADINF_SIMMEMSIZE 16 #define GCM_DHEADINF_ARGOFFSET 17 #define GCM_DHEADINF_DEBUGFLAG 18 #define GCM_DHEADINF_TRACKLOCATION 19 #define GCM_DHEADINF_TRACKSIZE 20 #define GCM_DHEADINF_COUNTRYCODE 21 #define GCM_APPLOADER_VERSION 22 #define GCM_APPLOADER_ENTRY 23 #define GCM_APPLOADER_SIZE 24 #define GCM_APPLOADER_TRAILERSIZE 25 #define GCM_APPLOADER_BINARY 26 #define GCM_APPLOADER_CODE_LOC 0x2450 #define GCM_FST_ROOT 28 #define GCM_FST_STRINGTABLEOFF 29 typedef struct { int area; // 0 = basic structure, 1 = header, 2= header info, 3 = apploader, 4 = FST char *name; long offset; long size; int type; // 1 for string, 0 for numeric value (strings aren't byteswapped) } GCMPiece; // pieces with area 1 add the base of the disk header to their offset // pieces with area 2 add the base of the disk header info to their offset // pieces with area 3 add the base of the apploader to their offset // pieces with area 4 add the base of the FST to their offset (garnered from the disk header) static GCMPiece GCMPieces [] ={ // root disc pieces {0, "Disk Header (boot.bin)", 0x00000000, 0x0440, 0}, {0, "Disk Header Information (bi2.bin)", 0x00000440, 0x2000, 0}, {0, "Apploader (appldr.bin)", 0x00002440, 0x2000, 0}, // 0x2000 size is an estimate I think // disk header {1, "Game code", 0x0000, 0x0004, 0}, {1, "Game maker code", 0x0004, 0x0002, 0}, {1, "DVD Magic Word", 0x001c, 0x0004, 0}, {1, "Game name", 0x0020, 0x03e0, 1}, {1, "Debug monitor offset", 0x0400, 0x0004, 0}, {1, "Debug monitor load address", 0x0404, 0x0004, 0}, {1, "Bootfile offset", 0x0420, 0x0004, 0}, {1, "FST offset", 0x0424, 0x0004, 0}, {1, "FST size", 0x0428, 0x0004, 0}, {1, "FST Max Size", 0x042c, 0x0004, 0}, {1, "User position", 0x0430, 0x0004, 0}, {1, "User length", 0x0434, 0x0004, 0}, // the disk header info is loaded to 0x800000f4 when the disc is loaded by the IPL (tho we're reading it straight // out of the .gcm image, so YMMV) {2, "Debug-monitor size", 0x0000, 0x0004, 0}, {2, "Simulated memory size", 0x0004, 0x0004, 0}, {2, "Argument offset", 0x0008, 0x0004, 0}, {2, "Debug flag", 0x000c, 0x0004, 0}, {2, "Track location", 0x0010, 0x0004, 0}, {2, "Track size", 0x0014, 0x0004, 0}, {2, "Countrycode", 0x0018, 0x0004, 0}, // apploader header info {3, "Version/Date", 0x0000, 0x000F, 1}, // don't include the padding in the date {3, "Apploader entry point", 0x0010, 0x0004, 0}, {3, "Apploader size", 0x0014, 0x0004, 0}, {3, "Trailer size", 0x0018, 0x0004, 0}, {3, "Apploader binary", 0x0020, 0, 1}, // no length given - taken from the "apploader size" // FST info {4, "Root directory entry", 0x00, 0x0c, 0}, {4, "FST String table offset", 0x0008, 0x0004, 0} }; // primary GCM disk header typedef struct GCM_DiskHeader{ int gamecode; int gamemaker; int magicword; char gamename[0x03e0]; int debugmon; int debugmonaddr; int bootfile; int userpos; int userlen; }; // the GCM disk header additional info typedef struct GCM_DiskHeaderInfo { int debugmonsize; int simmemsize; int argoff; int debugflag; int tracklocation; int tracksize; int countrycode; }; // information about the apploader on the GCM typedef struct GCM_ApploaderInfo{ char datever[10]; int entry; int size; int trailersize; char apploader[0x200]; // actual apploader data }; // information about a particular file in the FST typedef struct GCM_FSTEntry { int fname_offset; // offset into the FST string table for the filename // the offset is only actually 3 bytes, but // we're only reading, not writing so it doesn't matter // if we're grande sized .... // the first byte of fname_offset is actually the flags of the file; 0: file 1: dir int file_offset; // if this is a directory, this is actually the offset of the parent int file_length; // actually the number of entries (root) or next_offset (dir) int stringtable_off; // offset in the string table }; // information about the names and locations of files in the GCM typedef struct GCM_FST { int size; int offset; int stringtable_offset; int maxsize; std::vector entries; // list of entries std::vector stringtable; // string table }; // GCM image data structure typedef struct GCM { GCM_DiskHeader head; GCM_DiskHeaderInfo headInf; GCM_ApploaderInfo apploader; GCM_FST fst; char *fname; }; // these are just the functions that the user would need beyond // the functionality provided by gcmInit's loader; more internal // functions can be found inside gcminfo.c // returns 0 for a regular file, 1 for a directory extern int gcmGetFSTEntryType(GCM_FSTEntry *entry); // initialises the GCM data structures with FST and such; extern int gcmInit(char *gcmname, GCM *data); // prints a given portion of the GCM data // whichdata should be an indice into the GCMPieces array extern int gcmPrintData(int whichdata, GCM *data); // prints all the data in the GCM in a (fairly) columnar format extern int gcmPrint(GCM *data); // prints a comprehensive listing of all files in the GCM extern int gcmPrintFST(GCM *data); // retrieves a given file and puts it in the FST entries, // given the fnum extern int gcmGetFile(GCM *data, GCM_FSTEntry *entry, int fnum, FILE *file); // prints information for a given fname extern int gcmPrintFile(GCM *data, int fnum); // frees all data in the FST stringtable extern int gcmFreeStringTable(GCM *data); // extracts a file, given the fnum, into the current dir, unless outfname is specified extern unsigned int gcmExtractFile(GCM *data, int fnum, char *outfname); // puts the full filename (with path) into dest, given fnum extern int gcmGetFullFileName(GCM *data, int fnum, char *dest); // returns the fnum of a given file by its offset extern int gcmGetFileByOffset(GCM *data, int offset); // returns the fnum of a given file by its full pathname extern unsigned int gcmGetFileByName(GCM *data, char *name); // returns the actual entry of a file given its fnum extern GCM_FSTEntry gcmGetFileByFnum(GCM *data, int fnum); // explodes the FST onto the host filesystem in the current directory extern int gcmExplode(GCM *data);