Commit code, circa 2006
This commit is contained in:
94
source/.svn/text-base/Makefile.svn-base
Executable file
94
source/.svn/text-base/Makefile.svn-base
Executable file
@@ -0,0 +1,94 @@
|
||||
# Visual SlickEdit generated file. Do not edit this file except in designated areas.
|
||||
# -----Begin user-editable area-----
|
||||
|
||||
# -----End user-editable area-----
|
||||
|
||||
# Make command to use for dependencies
|
||||
MAKECMD=gmake
|
||||
|
||||
# If no configuration is specified, "Debug" will be used
|
||||
ifndef "CFG"
|
||||
CFG=Debug
|
||||
endif
|
||||
|
||||
#
|
||||
# Configuration: Debug
|
||||
#
|
||||
ifeq "$(CFG)" "Debug"
|
||||
OUTDIR=Debug
|
||||
OUTFILE=$(OUTDIR)/gcmbrowser
|
||||
CFG_INC=
|
||||
CFG_LIB=
|
||||
CFG_OBJ=
|
||||
COMMON_OBJ=$(OUTDIR)/gcmbrowser.o
|
||||
OBJ=$(COMMON_OBJ) $(CFG_OBJ)
|
||||
|
||||
COMPILE=g++ -c -g -o "$(OUTDIR)/$(*F).o" $(CFG_INC) "$<"
|
||||
LINK=g++ -g -o "$(OUTFILE)" $(OBJ) $(CFG_LIB)
|
||||
|
||||
# Pattern rules
|
||||
$(OUTDIR)/%.o : source/%.cpp
|
||||
$(COMPILE)
|
||||
|
||||
# Build rules
|
||||
all: $(OUTFILE)
|
||||
|
||||
$(OUTFILE): $(OUTDIR) $(OBJ)
|
||||
$(LINK)
|
||||
|
||||
$(OUTDIR):
|
||||
mkdir -p "$(OUTDIR)"
|
||||
|
||||
# Rebuild this project
|
||||
rebuild: cleanall all
|
||||
|
||||
# Clean this project
|
||||
clean:
|
||||
rm -f source/*o
|
||||
rm -f $(CFG)/*o
|
||||
rm -f $(OUTFILE)
|
||||
|
||||
# Clean this project and all dependencies
|
||||
cleanall: clean
|
||||
endif
|
||||
|
||||
#
|
||||
# Configuration: Release
|
||||
#
|
||||
ifeq "$(CFG)" "Release"
|
||||
OUTDIR=Release
|
||||
OUTFILE=$(OUTDIR)/gcmbrowser
|
||||
CFG_INC=
|
||||
CFG_LIB=
|
||||
CFG_OBJ=
|
||||
COMMON_OBJ=$(OUTDIR)/gcmbrowser.o
|
||||
OBJ=$(COMMON_OBJ) $(CFG_OBJ)
|
||||
|
||||
COMPILE=g++ -c -o "$(OUTDIR)/$(*F).o" $(CFG_INC) "$<"
|
||||
LINK=g++ -o "$(OUTFILE)" $(OBJ) $(CFG_LIB)
|
||||
|
||||
# Pattern rules
|
||||
$(OUTDIR)/%.o : source/%.cpp
|
||||
$(COMPILE)
|
||||
|
||||
# Build rules
|
||||
all: $(OUTFILE)
|
||||
|
||||
$(OUTFILE): $(OUTDIR) $(OBJ)
|
||||
$(LINK)
|
||||
|
||||
$(OUTDIR):
|
||||
mkdir -p "$(OUTDIR)"
|
||||
|
||||
# Rebuild this project
|
||||
rebuild: cleanall all
|
||||
|
||||
# Clean this project
|
||||
clean:
|
||||
rm -f source/*o
|
||||
rm -f $(CFG)/*o
|
||||
rm -f $(OUTFILE)
|
||||
|
||||
# Clean this project and all dependencies
|
||||
cleanall: clean
|
||||
endif
|
||||
26
source/.svn/text-base/README.txt.svn-base
Executable file
26
source/.svn/text-base/README.txt.svn-base
Executable file
@@ -0,0 +1,26 @@
|
||||
This is libgcm V0.1a, an early alpha of my library for
|
||||
manipulating gamecube master files. It currently has
|
||||
little functionality, but you can list and extract the contents
|
||||
of GCMs - the only thing I haven't got extracting correctly
|
||||
yet is the apploader stuff, because I haven't even really
|
||||
begun working on that yet, and don't know how to really test
|
||||
the results of that extraction.
|
||||
|
||||
Before this is over, I intend to have the library
|
||||
ready to insert, append, and create entire new images for
|
||||
burning to a GCM. My final test of this ability will be to
|
||||
completely unpack a disc image onto the drive (which it can
|
||||
already do, with the exception of the apploader) and re-pack
|
||||
it and see if it plays.
|
||||
|
||||
Maybe someone will be helped by this code. GPL applies.
|
||||
This code is free as in freedom. If you have any additions you
|
||||
would like to see in the next release, I'd be happy to include them,
|
||||
with credit. Just email them to me or find me in #gcdev on EFNet.
|
||||
|
||||
Enjoy!
|
||||
Andrew K
|
||||
andrew@aklabs.net
|
||||
andrewk in #gcdev on EFNet
|
||||
120817314 ICQ
|
||||
|
||||
163
source/.svn/text-base/gcmbrowser.cpp.svn-base
Executable file
163
source/.svn/text-base/gcmbrowser.cpp.svn-base
Executable file
@@ -0,0 +1,163 @@
|
||||
#include "gcminfo.h"
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// All the interesting stuff is in gcminfo.c|h ; gcmbrowser.cpp is just a proof
|
||||
// and simple util.
|
||||
|
||||
const char *usage =
|
||||
"gcmbrowser V0.01 (C) 2005 Andrew Kesterson (andrew@aklabs.net) \n\
|
||||
\n\
|
||||
Usage: gcmbrowser <.gcm file> <operation>\n\
|
||||
\n\
|
||||
operations:\n\
|
||||
-h : print this help\n\
|
||||
-H : print the disk header (maker, title, etc)\n\
|
||||
-E : explode the filesystem into the current directory\n\
|
||||
-e <file> : extract \"file\" from the gcm. With -o you\n\
|
||||
may specify an optional output filename; by default,\n\
|
||||
the file will be named the same (and reside in the\n\
|
||||
same directory tree) as in the image. You may specify\n\
|
||||
the source file by file number or by filename (full path\n\
|
||||
is necessary when specifying by filename.)\n\
|
||||
-o <filename> : specify the destination for a -e operation.\n\
|
||||
-l : list the names and file numbers of all files in the GCM.\n\
|
||||
All files are printed with full path.\n\
|
||||
-d : when extracting a file, create all needed directories for\n\
|
||||
the output file. This can, but really shouldn't, be used with\n\
|
||||
the -o option.\n\
|
||||
\n";
|
||||
|
||||
const char *shortopts = "hHEe:o:ld";
|
||||
|
||||
#define OP_PRINT_HEADER 0
|
||||
#define OP_EXPLODE 2
|
||||
#define OP_EXTRACT 4
|
||||
#define OP_LIST 8
|
||||
#define OP_CREATE_DIRS 1024
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
std::string gcmFname;
|
||||
std::string outFname;
|
||||
std::string extractFname;
|
||||
unsigned int extractFnumber= -1;
|
||||
int outIsDigit = 1;
|
||||
int ctr = 0;
|
||||
int op = 0;
|
||||
GCM theGCM;
|
||||
unsigned int opt = 0;
|
||||
unsigned int ret = 0;
|
||||
|
||||
if ( argc < 2 ) {
|
||||
fprintf(stderr, usage);
|
||||
return 1;
|
||||
}
|
||||
|
||||
opt = getopt(argc, argv, shortopts);
|
||||
while ( opt != -1) {
|
||||
switch ( opt ){
|
||||
case 'h':
|
||||
fprintf(stderr, usage);
|
||||
return 1;
|
||||
case 'H':
|
||||
op = OP_PRINT_HEADER;
|
||||
break;
|
||||
case 'E':
|
||||
op = OP_EXPLODE;
|
||||
break;
|
||||
case 'e':
|
||||
op = OP_EXTRACT;
|
||||
for ( ctr = 0; ctr < strlen(optarg) ; ctr++ ) {
|
||||
if ( isprint(optarg[ctr]) && !isdigit(optarg[ctr])) {
|
||||
outIsDigit = 0;
|
||||
} else {
|
||||
//printf("DEBUG : extract filename character %c is a digit\n", optarg[ctr]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ( outIsDigit == 0 ) {
|
||||
//printf("DEBUG : extract filename option is NON-DIGIT %s\n", optarg);
|
||||
extractFname.reserve(strlen(optarg));
|
||||
extractFname.assign(optarg);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
//printf("DEBUG : extract filename option is file number %s\n", optarg);
|
||||
extractFnumber = atoi(optarg);
|
||||
break;
|
||||
}
|
||||
case 'o':
|
||||
outFname.reserve(strlen(optarg));
|
||||
outFname.assign(optarg);
|
||||
break;
|
||||
case 'l':
|
||||
op = OP_LIST;
|
||||
break;
|
||||
case 'd':
|
||||
op |= OP_CREATE_DIRS;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "I don't understand option -%c\n", opt);
|
||||
return 1;
|
||||
}
|
||||
opt = getopt(argc, argv, shortopts);
|
||||
}
|
||||
gcmFname.reserve(strlen(argv[optind]));
|
||||
gcmFname.assign(argv[optind]);
|
||||
|
||||
if ( gcmInit((char *)gcmFname.c_str(), &theGCM) ) {
|
||||
printf("Couldn't init GCM file %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int top = 0;
|
||||
if ( op & OP_CREATE_DIRS ) top = op ^ OP_CREATE_DIRS;
|
||||
else top = op;
|
||||
switch ( top ) {
|
||||
case OP_EXPLODE:
|
||||
ret = gcmExplode(&theGCM);
|
||||
if ( ! ret )
|
||||
fprintf(stderr, "Failed to explode filesystem.\n");
|
||||
break;
|
||||
case OP_EXTRACT:
|
||||
if ( extractFnumber == -1 ) {
|
||||
//printf("DEBUG : getting file number for %s\n", extractFname.c_str());
|
||||
extractFnumber = gcmGetFileByName(&theGCM, (char *)extractFname.c_str());
|
||||
//printf("DEBUG: got %d\n", extractFnumber);
|
||||
}
|
||||
if ( extractFnumber > theGCM.fst.stringtable.size() || extractFnumber == -1) {
|
||||
fprintf(stderr, "File number %d requested was beyond the length of the filesystem\n", extractFnumber);
|
||||
break;
|
||||
}
|
||||
if ( outFname.length() == 0 && ( op & OP_CREATE_DIRS ) ) {
|
||||
char *outfile = (char *) new char[GCNDVD_FNAME_LENGTH];
|
||||
gcmGetFullFileName(&theGCM, extractFnumber, outfile);
|
||||
std::string execstring = "";
|
||||
// this is a quick hack to ensure that the output directory exists
|
||||
execstring.append("mkdir -p .");
|
||||
execstring.append("`dirname ");
|
||||
execstring.append(outfile);
|
||||
execstring.append("`");
|
||||
system(execstring.c_str());
|
||||
delete outfile;
|
||||
}
|
||||
if ( outFname.length() > 0 )
|
||||
ret = gcmExtractFile(&theGCM, extractFnumber, (char *)outFname.c_str());
|
||||
else
|
||||
ret = gcmExtractFile(&theGCM, extractFnumber, NULL);
|
||||
if ( ret != 0 )
|
||||
fprintf(stderr, "Failed to extract file number %d to output file %s\n", extractFnumber, outFname.length() > 0 ? (char *)outFname.c_str() : "" );
|
||||
break;
|
||||
case OP_PRINT_HEADER:
|
||||
ret = gcmPrint(&theGCM);
|
||||
break;
|
||||
case OP_LIST:
|
||||
ret = gcmPrintFST(&theGCM);
|
||||
break;
|
||||
}
|
||||
|
||||
gcmFreeStringTable(&theGCM);
|
||||
|
||||
return ret;
|
||||
}
|
||||
674
source/.svn/text-base/gcminfo.cpp.svn-base
Executable file
674
source/.svn/text-base/gcminfo.cpp.svn-base
Executable file
@@ -0,0 +1,674 @@
|
||||
#include "gcminfo.h"
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
int needByteSwap = 0;
|
||||
|
||||
// these are functions that the user really doesn't need to see,
|
||||
// so they're declared here away from the external API. They're
|
||||
// used mainly for populating the internal FST data structure.
|
||||
// All the user-necessary functions are listed out in gcminfo.h.
|
||||
|
||||
int gcmPopulateFST(GCM *data, FILE *file);
|
||||
void *gcmWhichData(int whichdata, GCM *data);
|
||||
int gcmGetData(int whichdata, GCM *data, FILE *file);
|
||||
int gcmGetFile(GCM *data, GCM_FSTEntry *entry, int fnum, FILE *file);
|
||||
int gcmCheckMagic(FILE *file);
|
||||
|
||||
// checks the magic number of the DVD file, and sets needByteSwap
|
||||
// returns the final value of needByteSwap. Returns -1 if the magic
|
||||
// word doesn't match either way and needByteSwap couldn't be set.
|
||||
int gcmCheckMagic(FILE *file)
|
||||
{
|
||||
int magic = 0;
|
||||
fseek(file, GCMPieces[GCM_DHEAD_DVDMAGIC].offset, 0);
|
||||
fread(&magic, GCMPieces[GCM_DHEAD_DVDMAGIC].size, 1, file);
|
||||
|
||||
if ( magic == GCNDVD_MAGICNUM ) {
|
||||
needByteSwap = 0;
|
||||
} else {
|
||||
magic = (((magic&0x000000FF)<<24)+((magic&0x0000FF00)<<8)+
|
||||
((magic&0x00FF0000)>>8)+((magic&0xFF000000)>>24));
|
||||
if ( magic == GCNDVD_MAGICNUM ) {
|
||||
needByteSwap = 1;
|
||||
}
|
||||
else needByteSwap = -1;
|
||||
}
|
||||
|
||||
return needByteSwap;
|
||||
}
|
||||
|
||||
// swap from big to little endian (only needed on intel machines)
|
||||
// only works if needByteSwap is > -1
|
||||
int byteSwap (int nLongNumber)
|
||||
{
|
||||
if ( needByteSwap ) return (((nLongNumber&0x000000FF)<<24)+((nLongNumber&0x0000FF00)<<8)+
|
||||
((nLongNumber&0x00FF0000)>>8)+((nLongNumber&0xFF000000)>>24));
|
||||
else if ( needByteSwap == -1 ) return 0; // refuse to work
|
||||
}
|
||||
|
||||
// return the type (0=file 1=directory) for the given FST entry
|
||||
int gcmGetFSTEntryType(GCM_FSTEntry *entry)
|
||||
{
|
||||
return entry->fname_offset >> 24;
|
||||
}
|
||||
|
||||
// uses one of the GCM_* definitions to return a pointer to
|
||||
// the appropriate point of the GCM struct to read data into.
|
||||
void *gcmWhichData(int whichdata, GCM *data)
|
||||
{
|
||||
void *toPrint = NULL;
|
||||
|
||||
switch (whichdata) {
|
||||
case GCM_DHEAD_GAMECODE:
|
||||
toPrint = &data->head.gamecode;
|
||||
break;
|
||||
case GCM_DHEAD_GAMEMAKER:
|
||||
toPrint = &data->head.gamemaker;
|
||||
break;
|
||||
case GCM_DHEAD_DVDMAGIC:
|
||||
toPrint = &data->head.magicword;
|
||||
break;
|
||||
case GCM_DHEAD_GAMENAME:
|
||||
toPrint = &data->head.gamename;
|
||||
break;
|
||||
case GCM_DHEAD_DEBUGMON:
|
||||
toPrint = &data->head.debugmon;
|
||||
break;
|
||||
case GCM_DHEAD_DEBUGMONADDR:
|
||||
toPrint = &data->head.debugmonaddr;
|
||||
break;
|
||||
case GCM_DHEAD_BOOTFILE:
|
||||
toPrint = &data->head.bootfile;
|
||||
break;
|
||||
case GCM_DHEAD_FST:
|
||||
toPrint = &data->fst.offset;
|
||||
break;
|
||||
case GCM_DHEAD_FSTSIZE:
|
||||
toPrint = &data->fst.size;
|
||||
break;
|
||||
case GCM_DHEAD_FSTMAXSIZE:
|
||||
toPrint = &data->fst.maxsize;
|
||||
break;
|
||||
case GCM_DHEAD_USERPOS:
|
||||
toPrint = &data->head.userpos;
|
||||
break;
|
||||
case GCM_DHEAD_USERLEN:
|
||||
toPrint = &data->head.userlen;
|
||||
break;
|
||||
case GCM_DHEADINF_DEBUGMONSIZE:
|
||||
toPrint = &data->headInf.debugmonsize;
|
||||
break;
|
||||
case GCM_DHEADINF_SIMMEMSIZE:
|
||||
toPrint = &data->headInf.simmemsize;
|
||||
break;
|
||||
case GCM_DHEADINF_ARGOFFSET:
|
||||
toPrint = &data->headInf.simmemsize;
|
||||
break;
|
||||
case GCM_DHEADINF_DEBUGFLAG:
|
||||
toPrint = &data->headInf.debugflag;
|
||||
break;
|
||||
case GCM_DHEADINF_TRACKLOCATION:
|
||||
toPrint = &data->headInf.tracklocation;
|
||||
break;
|
||||
case GCM_DHEADINF_TRACKSIZE:
|
||||
toPrint = &data->headInf.tracksize;
|
||||
break;
|
||||
case GCM_DHEADINF_COUNTRYCODE:
|
||||
toPrint = &data->headInf.countrycode;
|
||||
break;
|
||||
case GCM_APPLOADER_VERSION:
|
||||
toPrint = &data->apploader.datever;
|
||||
break;
|
||||
case GCM_APPLOADER_ENTRY:
|
||||
toPrint = &data->apploader.entry;
|
||||
break;
|
||||
case GCM_APPLOADER_SIZE:
|
||||
toPrint = &data->apploader.size;
|
||||
break;
|
||||
case GCM_APPLOADER_TRAILERSIZE:
|
||||
toPrint = &data->apploader.trailersize;
|
||||
break;
|
||||
case GCM_APPLOADER_BINARY:
|
||||
toPrint = &data->apploader.apploader;
|
||||
break;
|
||||
case GCM_FST_ROOT:
|
||||
toPrint = (void *)"Not implemented yet";
|
||||
break;
|
||||
case GCM_FST_STRINGTABLEOFF:
|
||||
toPrint = &data->fst.stringtable_offset;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return toPrint;
|
||||
}
|
||||
|
||||
// print the info in data as indicated by the GCM_*
|
||||
// passed to whichdata
|
||||
int gcmPrintData(int whichdata, GCM *data)
|
||||
{
|
||||
void *ptr;
|
||||
if ( GCMPieces[whichdata].type == 1) {
|
||||
char *theData = (char *)gcmWhichData(whichdata,data);
|
||||
printf("%-38s:\t %s\n", GCMPieces[whichdata].name, theData);
|
||||
}
|
||||
else {
|
||||
int *theData = (int *)gcmWhichData(whichdata,data);
|
||||
if ( theData ) {
|
||||
printf("%-38s:\t %x\n", GCMPieces[whichdata].name, *theData);
|
||||
}
|
||||
else {
|
||||
printf("%-38s:\t refusing to print NULL pointer...\n",
|
||||
"(untested function/invalid data)"); // this means you're using a feature that doesn't work (yet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print the information for a given file in data (by entry num)
|
||||
int gcmPrintFile(GCM *data, int fnum)
|
||||
{
|
||||
GCM_FSTEntry f;
|
||||
char *fname = NULL;
|
||||
|
||||
// printf("DEBUG : retrieving file data for number %d\n", fnum);
|
||||
f = data->fst.entries.at(fnum);
|
||||
|
||||
// see gcmPrint for how this is laid out...
|
||||
if ( fnum >= data->fst.entries.size() )
|
||||
fname = "(out_of_bounds string)" ;
|
||||
else
|
||||
fname = (char *)data->fst.stringtable.at(fnum)->c_str();
|
||||
|
||||
printf("%-20s%-6d%-6x%-12x%-20d\n",
|
||||
fname,
|
||||
fnum,
|
||||
gcmGetFSTEntryType(&f),
|
||||
f.file_offset,
|
||||
f.file_length);
|
||||
}
|
||||
|
||||
// reads data into dest and returns the number of bytes read
|
||||
// (only used internally by the other gcm functions, this should
|
||||
// be transparent outside the API guts)
|
||||
int gcmGetData(int whichdata, GCM *data, FILE *file)
|
||||
{
|
||||
int offset = 0;
|
||||
void *dest = gcmWhichData(whichdata, data);
|
||||
if ( whichdata > GCM_MAX_PIECES || dest == NULL || file == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch ( GCMPieces[whichdata].area ) {
|
||||
case 0:
|
||||
offset = GCMPieces[whichdata].offset;
|
||||
break;
|
||||
case 1:
|
||||
offset = GCMPieces[GCM_DHEAD].offset + GCMPieces[whichdata].offset;
|
||||
break;
|
||||
case 2:
|
||||
offset = GCMPieces[GCM_DHEADINF].offset + GCMPieces[whichdata].offset;
|
||||
break;
|
||||
case 3:
|
||||
offset = GCMPieces[GCM_APPLOADER].offset + GCMPieces[whichdata].offset;
|
||||
break;
|
||||
case 4:
|
||||
offset = data->fst.offset + GCMPieces[whichdata].offset;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
fseek(file, offset, 0);
|
||||
if ( GCMPieces[whichdata].type == 1 ) {
|
||||
fgets((char *)dest, GCMPieces[whichdata].size, file) == NULL;
|
||||
}
|
||||
else {
|
||||
fread(dest, 1, GCMPieces[whichdata].size, file);
|
||||
int *tmp = (int *)dest;
|
||||
*tmp = byteSwap(*tmp);
|
||||
}
|
||||
rewind(file);
|
||||
return GCMPieces[whichdata].size;
|
||||
}
|
||||
|
||||
// get the file at fnum from file for the GCM data and store it
|
||||
// in entry
|
||||
int gcmGetFile(GCM *data, GCM_FSTEntry *entry, int fnum, FILE *file)
|
||||
{
|
||||
if ( fnum > -1 && file != NULL ) {
|
||||
rewind(file);
|
||||
fseek(file, data->fst.offset + (12 * fnum), 0);
|
||||
|
||||
if ( !feof(file) ) {
|
||||
fread(&entry->fname_offset, 4, 1, file);
|
||||
entry->fname_offset = byteSwap(entry->fname_offset);
|
||||
fread(&entry->file_offset, 4, 1, file);
|
||||
entry->file_offset = byteSwap(entry->file_offset);
|
||||
fread(&entry->file_length, 4, 1, file);
|
||||
entry->file_length = byteSwap(entry->file_length);
|
||||
data->fst.entries.push_back(*entry);
|
||||
}
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
|
||||
// populate the FST of the given GCM from file
|
||||
int gcmPopulateFST(GCM *data, FILE *file)
|
||||
{
|
||||
GCM_FSTEntry *newEntry;
|
||||
GCM_FSTEntry root;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int oldpos = 0;
|
||||
int maxentries = 0;
|
||||
char *tmpbuff = new char[GCNDVD_FNAME_LENGTH];
|
||||
std::string * strdest = new std::string("");
|
||||
char tmp = 0xFF;
|
||||
int f = 0;
|
||||
int *appSize = NULL;
|
||||
|
||||
if ( !tmpbuff ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fseek(file, data->fst.offset, 0);
|
||||
|
||||
// now just loop until there are no more entries...
|
||||
gcmGetFile(data, &root, 0,file);
|
||||
root = data->fst.entries.front();
|
||||
// this is where we inject the filesystem entries for bootloader.bin, apploader.bin,
|
||||
// and game.dol ... these aren't technically part of the filesystem, but we
|
||||
// do this so they can be viewed/extracted like other files.
|
||||
/*
|
||||
appSize = (int *)gcmWhichData(GCM_APPLOADER_SIZE, data);
|
||||
newEntry = new GCM_FSTEntry;
|
||||
newEntry->fname_offset = 0;
|
||||
newEntry->file_offset = GCM_APPLOADER_CODE_LOC;
|
||||
newEntry->file_length = *appSize;
|
||||
newEntry->stringtable_off = 1;
|
||||
data->fst.entries.push_back(*newEntry);
|
||||
delete newEntry;*/
|
||||
for ( int i = 1; i < root.file_length ; i++) {
|
||||
newEntry = new GCM_FSTEntry;
|
||||
gcmGetFile(data, newEntry, i, file);
|
||||
delete newEntry;
|
||||
}
|
||||
|
||||
|
||||
// we're past the FST proper; now the string table...
|
||||
data->fst.stringtable_offset = data->fst.offset + (root.file_length * 12);
|
||||
fseek(file, data->fst.stringtable_offset, 0);
|
||||
//printf("FST string table offset calculated to 0x\%x...\n", data->fst.stringtable_offset);
|
||||
data->fst.stringtable.clear();
|
||||
data->fst.stringtable.push_back(&std::string("/\0"));
|
||||
//data->fst.stringtable.push_back(&std::string("apploader.bin\0"));
|
||||
memset(tmpbuff, GCNDVD_FNAME_LENGTH, 0x00);
|
||||
while ( ftell(file) < (data->fst.offset + data->fst.size) && !feof(file)) {
|
||||
i = 0;
|
||||
while ( 1 ) {
|
||||
tmp = fgetc(file);
|
||||
if ( tmp == 0x00 ) {
|
||||
break;
|
||||
}
|
||||
tmpbuff[i] = tmp;
|
||||
i++;
|
||||
}
|
||||
tmpbuff[i] = '\0';
|
||||
strdest->clear();
|
||||
strdest->reserve(i);
|
||||
strdest->assign(tmpbuff);
|
||||
data->fst.stringtable.push_back(strdest);
|
||||
// printf("DEBUG : FILENAME WAS %s ... added %s\n", strdest,
|
||||
// data->fst.stringtable.at(f+1)->c_str());
|
||||
memset(tmpbuff, GCNDVD_FNAME_LENGTH, 0x00);
|
||||
strdest = new std::string("");
|
||||
f++;
|
||||
}
|
||||
delete tmpbuff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// called inside of gcmInit to make sure everything inside is sane
|
||||
// (only needed internally)
|
||||
int gcmZeroOut(GCM *data)
|
||||
{
|
||||
data->apploader.entry = 0;
|
||||
data->apploader.size = 0;
|
||||
data->apploader.trailersize = 0;
|
||||
data->fst.maxsize = 0;
|
||||
data->fst.offset = 0;
|
||||
data->fst.size = 0;
|
||||
data->head.bootfile = 0;
|
||||
data->head.debugmon = 0;
|
||||
data->head.debugmonaddr = 0;
|
||||
data->head.gamecode = 0;
|
||||
data->head.gamemaker = 0;
|
||||
data->head.magicword = 0;
|
||||
data->head.userlen = 0;
|
||||
data->head.userpos = 0;
|
||||
data->headInf.argoff = 0;
|
||||
data->headInf.countrycode = 0;
|
||||
data->headInf.debugflag = 0;
|
||||
data->headInf.debugmonsize = 0;
|
||||
data->headInf.simmemsize = 0;
|
||||
data->headInf.tracklocation = 0;
|
||||
data->headInf.tracksize = 0;
|
||||
}
|
||||
|
||||
// reads all info from the GCM in gcmname and puts it in data
|
||||
int gcmInit(char *gcmname, GCM *data)
|
||||
{
|
||||
FILE *gcm = fopen(gcmname, "r+b");
|
||||
int i = 0;
|
||||
|
||||
if (!gcm) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gcmZeroOut(data);
|
||||
|
||||
switch ( gcmCheckMagic(gcm) ) {
|
||||
case 0:
|
||||
needByteSwap = 1;
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
case -1:
|
||||
//printf("DEBUG: DVD Magic number on GCM image was incorrect or couldn't be understood!\n");
|
||||
//printf("DEBUG: Aborting in GCMInit! (filename %s)\n", gcmname);
|
||||
fclose(gcm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for ( i = 3; i < GCM_MAX_PIECES ; i++) {
|
||||
gcmGetData(i,data, gcm);
|
||||
}
|
||||
|
||||
gcmPopulateFST(data, gcm);
|
||||
|
||||
fclose(gcm);
|
||||
|
||||
data->fname = new char[strlen(gcmname)+1];
|
||||
if ( !data->fname ) {
|
||||
printf("couldn't store GCM filename for later retrieval. Aborting.\n");
|
||||
gcmFreeStringTable(data);
|
||||
exit(-1);
|
||||
}
|
||||
else strcpy(data->fname, gcmname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// print all information about the GCM in a columnar format,
|
||||
// including the FST.
|
||||
int gcmPrint(GCM *data)
|
||||
{
|
||||
int ml = 0;
|
||||
int i = 0;
|
||||
|
||||
for (i = 3; i < GCM_MAX_PIECES; i++ ) {
|
||||
gcmPrintData(i,data);
|
||||
}
|
||||
|
||||
GCM_FSTEntry root = data->fst.entries.front();
|
||||
|
||||
printf("%-38s:\t%d\n", "Total files in the FST", root.file_length);
|
||||
printf("%-38s:\t%d\n", "Total entries in the FST string table", data->fst.stringtable.size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gcmPrintFST(GCM *data)
|
||||
{
|
||||
int ml = 0;
|
||||
int i = 0;
|
||||
char *tbuff = new char[GCNDVD_FNAME_LENGTH];
|
||||
if (!tbuff) {
|
||||
printf("Couldn't get temporary buffer for full path printing. Aborting.\n");
|
||||
return -1;
|
||||
} else {
|
||||
memset(tbuff, 0x00, GCNDVD_FNAME_LENGTH);
|
||||
}
|
||||
|
||||
GCM_FSTEntry root = data->fst.entries.front();
|
||||
printf("%-38s:\t%d\n", "Total files in the FST", root.file_length);
|
||||
printf("%-38s:\t%d\n", "Total entries in the FST string table", data->fst.stringtable.size());
|
||||
printf("\n\n\n%30s\n", "(FST CONTENTS)");
|
||||
printf("%-16s %-6s %-6s %s %-12s\n",
|
||||
"(name)", "(fnum)", "(type)", "(offset)", "(length)");
|
||||
for (i = 0; i < data->fst.entries.size() - 1 ; i++) {
|
||||
//printf("DEBUG: retrieving file data for number %d\n", i);
|
||||
gcmPrintFile(data, i);
|
||||
}
|
||||
|
||||
printf("\n\t\t\t(PRINTING FILES WITH FULL PATH)\n");
|
||||
for (i = 0; i < data->fst.entries.size() - 1; i++ ) {
|
||||
printf("File %d:", i);
|
||||
gcmGetFullFileName(data, i, tbuff);
|
||||
printf(" %s\n", tbuff);
|
||||
memset(tbuff, 0x00, GCNDVD_FNAME_LENGTH);
|
||||
}
|
||||
|
||||
delete tbuff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// frees memory used by the string table. MUST be called before zeroing
|
||||
// the gcm for new reading (gcmInit) or quitting the application.
|
||||
// This should be accompanied by clearing the entries vector, though the
|
||||
// destructor in that member should take care of cleanup for you.
|
||||
// Thou shalt not leak memory!
|
||||
|
||||
int gcmFreeStringTable(GCM *data)
|
||||
{
|
||||
std::string *string = NULL;
|
||||
int i = 0;
|
||||
|
||||
//printf("freeing memory used by FST string table... ");
|
||||
|
||||
for (i = 0; i < (data->fst.stringtable.size()) ; i++ ) {
|
||||
string = (std::string *)data->fst.stringtable.at(i);
|
||||
// we create the "/" entry for 0 manually, and it's not alloc'ed
|
||||
// so don't try freeing it!
|
||||
if ( string != NULL && i > 0 ) {
|
||||
delete string;
|
||||
}
|
||||
string = NULL;
|
||||
}
|
||||
data->fst.stringtable.clear();
|
||||
delete data->fname;
|
||||
|
||||
//printf(" ...done.\n");
|
||||
}
|
||||
|
||||
GCM_FSTEntry gcmGetFileByFnum(GCM *data, int fnum)
|
||||
{
|
||||
return data->fst.entries.at(fnum);
|
||||
}
|
||||
|
||||
int gcmGetFileByOffset(GCM *data, int offset)
|
||||
{
|
||||
GCM_FSTEntry curr;
|
||||
bool done = false;
|
||||
|
||||
for (int i = 0; i < data->fst.entries.size() -1; i++) {
|
||||
curr = data->fst.entries.at(i);
|
||||
if (curr.file_offset == offset) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// takes in a full pathname and retrieves the fnum
|
||||
// for the appropriate file in the FST
|
||||
unsigned int gcmGetFileByName(GCM *data, char *name)
|
||||
{
|
||||
GCM_FSTEntry curr;
|
||||
bool done = false;
|
||||
int nextStart = 0;
|
||||
int i = 0;
|
||||
char *tmp2 = (char *) new char[GCNDVD_FNAME_LENGTH];
|
||||
if ( !tmp2 ) {
|
||||
fprintf(stderr, "Failed to allocate temporary string storage\n");
|
||||
return -1;
|
||||
}
|
||||
for ( i = 0; i < data->fst.stringtable.size() ; i++ ) {
|
||||
gcmGetFullFileName(data, i, tmp2);
|
||||
//printf("DEBUG : comparing filename %s to original %s...\n", name, tmp2);
|
||||
if ( !strcmp(name, tmp2) ) {
|
||||
delete tmp2;
|
||||
//printf("DEBUG : found filename %s at number %d", name, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
delete tmp2;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// extracts a file into outfile from the GCM given the fnum.
|
||||
// FIXME : allow the user to specify a different output filename?
|
||||
unsigned int gcmExtractFile(GCM *data, int fnum, char *outfname)
|
||||
{
|
||||
FILE *out = NULL;
|
||||
FILE *gcm = NULL;
|
||||
int pos = 0;
|
||||
int endpos = 0;
|
||||
int b = 0;
|
||||
GCM_FSTEntry curr;
|
||||
std::string execstring = "";
|
||||
char *outfile = NULL;
|
||||
std::string tmpStr = "";
|
||||
|
||||
// check that the fnum is in range
|
||||
|
||||
if ( fnum < data->fst.entries.size() - 1) {
|
||||
curr = data->fst.entries.at(fnum);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if it's a file, open the outfile, open the GCM, and perform the copy - clean up and exit
|
||||
if ( gcmGetFSTEntryType(&curr) == 0 ) {
|
||||
if ( outfname ) {
|
||||
outfile = outfname;
|
||||
tmpStr = "";
|
||||
} else {
|
||||
outfile = new char[GCNDVD_FNAME_LENGTH];
|
||||
if ( !outfile ) return -1;
|
||||
else gcmGetFullFileName(data, fnum, outfile);
|
||||
tmpStr = ".";
|
||||
}
|
||||
tmpStr.append(outfile);
|
||||
gcm = fopen(data->fname, "rb");
|
||||
out = fopen(tmpStr.c_str(), "wb");
|
||||
if ( !gcm || !out ) {
|
||||
gcm ? fclose(gcm) : printf("Couldn't read from gcm file\n");
|
||||
out ? fclose(out) : printf("Couldn't write to output file\n");
|
||||
return -1;
|
||||
}
|
||||
fseek(gcm, curr.file_offset, 0);
|
||||
endpos = curr.file_offset + curr.file_length;
|
||||
if ( ftell(gcm) != curr.file_offset || !out || !gcm) {
|
||||
delete outfile;
|
||||
fclose(gcm);
|
||||
fclose(out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ( !feof(gcm) && ftell(gcm) <= endpos) {
|
||||
fread(&b, 1, 1, gcm);
|
||||
if ( needByteSwap == 1 ) b = byteSwap(b); // swap the bytes for the host
|
||||
fwrite(&b, 1, 1, out);
|
||||
}
|
||||
|
||||
if ( outfile && !outfname )delete outfile;
|
||||
fclose(gcm);
|
||||
fclose(out);
|
||||
printf("exploded %s\n", tmpStr.c_str());
|
||||
return 0;
|
||||
}
|
||||
// if it's a dir, construct the mkdir command, do it, clean up and exit.
|
||||
else {
|
||||
if ( outfname )
|
||||
outfile = outfname;
|
||||
else {
|
||||
outfile = new char[GCNDVD_FNAME_LENGTH];
|
||||
if (!outfile ) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
gcmGetFullFileName(data, fnum, outfile);
|
||||
if ( !outfname )
|
||||
execstring.append("mkdir -p .");
|
||||
else
|
||||
execstring.append("mkdir -p ");
|
||||
execstring.append(outfile);
|
||||
int retcode = system(execstring.c_str());
|
||||
if ( outfile && !outfname ) delete outfile;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// explodes the FST onto the host filesystem
|
||||
int gcmExplode(GCM *data)
|
||||
{
|
||||
for ( int i = 0; i <= (data->fst.entries.size() - 1) ; i++ ) {
|
||||
if ( gcmExtractFile(data, i, NULL) < 0 ) return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// retrieves the full filename for fnum with full path
|
||||
int gcmGetFullFileName(GCM *data, int fnum, char *dest)
|
||||
{
|
||||
bool finished = false;
|
||||
GCM_FSTEntry curr;
|
||||
std::vector<int> fnames;
|
||||
int fn = fnum;
|
||||
int depth = 0;
|
||||
std::string work = "";
|
||||
|
||||
curr = data->fst.entries.at(fn);
|
||||
|
||||
while (!finished) {
|
||||
depth++;
|
||||
if ( depth > data->fst.entries.size() - 1) {
|
||||
printf("went too far. aborting.\n");
|
||||
exit(-1);
|
||||
}
|
||||
if ( fn == 0 ) {
|
||||
fnames.push_back(0);
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
if ( gcmGetFSTEntryType(&curr) == 0 ) {
|
||||
// file
|
||||
fnames.push_back(fn);
|
||||
while (gcmGetFSTEntryType(&curr) == 0) {
|
||||
// search up for the parent directory....
|
||||
curr = data->fst.entries.at(fn - 1);
|
||||
fn -= 1;
|
||||
}
|
||||
}
|
||||
else if ( gcmGetFSTEntryType(&curr) == 1) {
|
||||
// directory
|
||||
fnames.push_back(fn);
|
||||
fn = curr.file_offset;
|
||||
curr = data->fst.entries.at(fn);
|
||||
}
|
||||
}
|
||||
|
||||
if ( fnum != 0 ) {
|
||||
for (int i = fnames.size() -1 ; i >= 0; i--) {
|
||||
if ( i < fnames.size()-1 ) {
|
||||
work.append("/");
|
||||
}
|
||||
if ( fnames.at(i) != 0 ) work.append(data->fst.stringtable.at(fnames.at(i))->c_str());
|
||||
}
|
||||
} else work = "/";
|
||||
strcpy(dest, work.c_str());
|
||||
return 0;
|
||||
}
|
||||
217
source/.svn/text-base/gcminfo.h.svn-base
Executable file
217
source/.svn/text-base/gcminfo.h.svn-base
Executable file
@@ -0,0 +1,217 @@
|
||||
// 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 <vector>
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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 <GCM_FSTEntry>entries; // list of entries
|
||||
std::vector <std::string *>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);
|
||||
1709
source/.svn/text-base/sample-output.txt.svn-base
Executable file
1709
source/.svn/text-base/sample-output.txt.svn-base
Executable file
File diff suppressed because it is too large
Load Diff
13
source/.svn/text-base/std_disclaimer.h.svn-base
Executable file
13
source/.svn/text-base/std_disclaimer.h.svn-base
Executable file
@@ -0,0 +1,13 @@
|
||||
/* What you are seeing is a work in progress. Source and comments
|
||||
it contains could be dangerous, profane, or just plain wrong.
|
||||
While I generally don't publish source code unless I feel it's in
|
||||
a semi-production state (or at least to the point where someone
|
||||
somewhere could benefit from it), I can't guarantee anything.
|
||||
|
||||
If you use this code and the genie of your computer (or your cube!) escapes in
|
||||
a puff of smoke, I will not be held liable. You have been warned.
|
||||
This code may be ugly, incomplete, or just plain wrong.
|
||||
|
||||
No F'in warranty implied!
|
||||
|
||||
Andrew K 2005 andrew@aklabs.net */
|
||||
Reference in New Issue
Block a user