commit 6358fb3415cf9c2275fe8fa9dd333d9b516bf510 Author: Andrew Kesterson Date: Mon May 18 12:36:54 2026 -0400 Commit code, circa 2006 diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..7304636 --- /dev/null +++ b/Makefile @@ -0,0 +1,69 @@ +# This makefile is a bit hackish. I wrote it early in the AM. +# Fohgiveuhness, please!! + +ifndef $(CFG) + CFG=Debug +endif + +TARGET=libgcm +PROJECTHOME=$(shell pwd) +LIBDIR=/usr/lib +HEADERDIR=/usr/include + +ifeq "$(CFG)" "Debug" + OUTDIR=Debug + LIBTARGET=$(TARGET)-dbg.so + LINKLIB=gcm-dbg +# CFLAGS really should be -Werror... + CFLAGS=-g -ggdb -gstabs -Wall -c + LDFLAGS=-shared -fPIC -o $(OUTDIR)/$(LIBTARGET) +endif + +ifeq "$(CFG)" "Release" + OUTDIR=Release + LIBTARGET=$(TARGET).so + LINKLIB=gcm + CFLAGS=-O2 -fomit-frame-pointer -pipe -c + LDFLAGS=-shared -fPIC -o $(OUTDIR)/$(LIBTARGET) +endif + +LIBSRC=source/gcminfo.cpp +TESTSRC=source/gcmbrowser.cpp + +LIBOBJ=$(OUTDIR)/gcminfo.o +TESTOBJ=$(OUTDIR)/gcmbrowser.o + +CC = gcc +CXX = g++ +LD = $(CXX) + + +$(OUTDIR)/%.o : source/%.cpp + $(CXX) $(CFLAGS) -o $@ $< + +all: lib bin + +lib: $(LIBOBJ) $(TESTOBJ) + $(LD) $(LDFLAGS) $(LIBOBJ) + +bin: + $(LD) -o $(OUTDIR)/gcmbrowser \ + $(LIBOBJ) $(TESTOBJ) + + +.PHONY: clean +clean: + rm $(OUTDIR)/*.o + rm $(OUTDIR)/gcmbrowser + rm $(OUTDIR)/$(LIBTARGET) + +.PHONY: rebuild +rebuild: + make clean + make CFG=$(CFG) + + +.PHONY: install +install: + $(INSTALL) $(OUTDIR)/$(LIBTARGET) $(LIBDIR)/$(TARGET) + $(INSTALL) source/gcminfo.h $(HEADERDIR)/libgcm.h diff --git a/gcmbrowser.bakvpj b/gcmbrowser.bakvpj new file mode 100755 index 0000000..242f865 --- /dev/null +++ b/gcmbrowser.bakvpj @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gcmbrowser.bakvpw b/gcmbrowser.bakvpw new file mode 100755 index 0000000..02a8993 --- /dev/null +++ b/gcmbrowser.bakvpw @@ -0,0 +1,6 @@ + + + + + + diff --git a/gcmbrowser.vpj b/gcmbrowser.vpj new file mode 100755 index 0000000..a151818 --- /dev/null +++ b/gcmbrowser.vpj @@ -0,0 +1,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gcmbrowser.vpw b/gcmbrowser.vpw new file mode 100755 index 0000000..788eb4b --- /dev/null +++ b/gcmbrowser.vpw @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/gcmbrowser.vpwhistu b/gcmbrowser.vpwhistu new file mode 100755 index 0000000..eb40ca1 --- /dev/null +++ b/gcmbrowser.vpwhistu @@ -0,0 +1,52 @@ +[Global] +CurrentProject=gcmbrowser.vpj +[ProjectDates] +gcmbrowser.vpj=20060801143843000 +[ActiveConfig] +gcmbrowser.vpj=,Debug +[TreeExpansion2] +- gcmbrowser.vpj + - Source Files + - Header Files + - Resource Files + - Bitmaps + - Other Files +scroll:0 +[State] +SCREEN: 1600 1200 73 36 1121 898 0 0 N 0 0 0 0 893 567 +CWD: ../stlini/ +BUFFER: BN="source/std_disclaimer.h" +BI: MA=1 74 1 TABS=1 5 WWS=1 IWT=1 ST=0 IN=2 BW=0 US=32000 RO=0 SE=1 SN=0 BIN=0 MN=C HM=0 MF=808 TL=0 MLL=0 ASE=0 LNL=6 LCF=0 CAPS=0 E=0 ESBU2=-1 +VIEW: LN=.0 CL=1 LE=0 CX=1 CY=0 WI=5 BI=36 HT=0 HN=0 HF=0 HC=4 +BUFFER: BN="source/gcmbrowser.cpp" +BI: MA=1 74 1 TABS=1 5 WWS=1 IWT=1 ST=0 IN=2 BW=0 US=32000 RO=0 SE=1 SN=0 BIN=0 MN=C HM=0 MF=8 TL=0 MLL=0 ASE=0 LNL=6 LCF=0 CAPS=0 E=0 ESBU2=-1 +VIEW: LN=.0 CL=1 LE=0 CX=1 CY=1 WI=5 BI=35 HT=0 HN=0 HF=0 HC=4 +BUFFER: BN="source/gcminfo.h" +BI: MA=1 74 1 TABS=1 5 WWS=1 IWT=1 ST=0 IN=2 BW=0 US=32000 RO=0 SE=1 SN=0 BIN=0 MN=C HM=0 MF=872 TL=0 MLL=0 ASE=0 LNL=6 LCF=0 CAPS=0 E=0 ESBU2=-1 +VIEW: LN=.8219 CL=15 LE=0 CX=15 CY=22 WI=5 BI=13 HT=0 HN=0 HF=0 HC=4 +BUFFER: BN="source/gcminfo.cpp" +BI: MA=1 74 1 TABS=1 5 WWS=1 IWT=1 ST=0 IN=2 BW=0 US=32000 RO=0 SE=1 SN=0 BIN=0 MN=C HM=0 MF=872 TL=0 MLL=0 ASE=0 LNL=6 LCF=0 CAPS=0 E=0 ESBU2=-1 +VIEW: LN=.14666 CL=1 LE=0 CX=1 CY=2 WI=5 BI=40 HT=0 HN=0 HF=0 HC=4 +WINDOW: 25 25 602 382 0 0 N WF=0 WT=4 "Default Fixed Font,10,0,1" +BUFFER: BN="source/gcminfo.h" +VIEW: LN=.8219 CL=15 LE=0 CX=15 CY=22 WI=278 BI=13 HT=0 HN=0 HF=0 HC=4 +WINDOW: 0 0 604 446 0 0 N WF=0 WT=2 "OEM Fixed Font,10,0,1" +BUFFER: BN="source/gcmbrowser.cpp" +VIEW: LN=.0 CL=1 LE=0 CX=1 CY=0 WI=253 BI=35 HT=0 HN=0 HF=0 HC=4 +WINDOW: 162 160 602 382 0 0 N WF=0 WT=3 "Default Fixed Font,10,0,1" +BUFFER: BN="source/std_disclaimer.h" +VIEW: LN=.0 CL=1 LE=0 CX=1 CY=0 WI=281 BI=36 HT=0 HN=0 HF=0 HC=4 +WINDOW: 0 0 604 445 0 0 N WF=0 WT=1 "OEM Fixed Font,10,0,1" +BUFFER: BN="source/gcminfo.cpp" +VIEW: LN=.15877 CL=13 LE=0 CX=13 CY=20 WI=68 BI=40 HT=0 HN=0 HF=0 HC=4 +FILEHIST: 5 +source/gcmbrowser.cpp +source/README.txt +source/gcminfo.cpp +source/gcminfo.h +source/std_disclaimer.h +DEBUG: 0 0 0 0 4 0 +printf +strcpy +std::* +######## diff --git a/gcmbrowser.vtg b/gcmbrowser.vtg new file mode 100755 index 0000000..4cb024f Binary files /dev/null and b/gcmbrowser.vtg differ diff --git a/source/.svn/all-wcprops b/source/.svn/all-wcprops new file mode 100755 index 0000000..641081a --- /dev/null +++ b/source/.svn/all-wcprops @@ -0,0 +1,47 @@ +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/aklabs/!svn/ver/25/trunk/gcmbrowser/source +END +gcminfo.cpp +K 25 +svn:wc:ra_dav:version-url +V 59 +/svn/aklabs/!svn/ver/24/trunk/gcmbrowser/source/gcminfo.cpp +END +gcminfo.h +K 25 +svn:wc:ra_dav:version-url +V 57 +/svn/aklabs/!svn/ver/24/trunk/gcmbrowser/source/gcminfo.h +END +README.txt +K 25 +svn:wc:ra_dav:version-url +V 58 +/svn/aklabs/!svn/ver/10/trunk/gcmbrowser/source/README.txt +END +gcmbrowser.cpp +K 25 +svn:wc:ra_dav:version-url +V 62 +/svn/aklabs/!svn/ver/24/trunk/gcmbrowser/source/gcmbrowser.cpp +END +std_disclaimer.h +K 25 +svn:wc:ra_dav:version-url +V 64 +/svn/aklabs/!svn/ver/10/trunk/gcmbrowser/source/std_disclaimer.h +END +Makefile +K 25 +svn:wc:ra_dav:version-url +V 56 +/svn/aklabs/!svn/ver/25/trunk/gcmbrowser/source/Makefile +END +sample-output.txt +K 25 +svn:wc:ra_dav:version-url +V 65 +/svn/aklabs/!svn/ver/10/trunk/gcmbrowser/source/sample-output.txt +END diff --git a/source/.svn/entries b/source/.svn/entries new file mode 100755 index 0000000..35e0387 --- /dev/null +++ b/source/.svn/entries @@ -0,0 +1,269 @@ +10 + +dir +44 +https://127.0.0.1/svn/aklabs/trunk/gcmbrowser/source +https://127.0.0.1/svn/aklabs + + + +2007-05-27T20:05:31.207389Z +25 +andrew + + + + + + + + + + + + + + +eb184899-6090-47d4-a65b-558f62f6ea1c + +gcminfo.cpp +file + + + + +2010-02-05T03:38:38.541998Z +f4e061c5d6e899ea81768ef33af43eed +2007-05-27T14:56:28.897284Z +24 +andrew +has-props + + + + + + + + + + + + + + + + + + + + +19049 + +gcminfo.h +file + + + + +2010-02-05T03:38:38.541998Z +45b77c7de27c88dbba375497f893b3bc +2007-05-27T14:56:28.897284Z +24 +andrew +has-props + + + + + + + + + + + + + + + + + + + + +8477 + +CVS +dir + +README.txt +file + + + + +2010-02-05T03:38:38.557623Z +44c75865d8249141bcbb012aa7f91c54 +2007-05-26T21:39:54.335125Z +10 +andrew +has-props + + + + + + + + + + + + + + + + + + + + +1051 + +gcmbrowser.cpp +file + + + + +2010-02-05T03:38:38.557623Z +760c844cea5a9f808445086b72ed53d0 +2007-05-27T14:56:28.897284Z +24 +andrew +has-props + + + + + + + + + + + + + + + + + + + + +4752 + +std_disclaimer.h +file + + + + +2010-02-05T03:38:38.573248Z +37573d2d9d55617fcd2389453c136e9c +2007-05-26T21:39:54.335125Z +10 +andrew +has-props + + + + + + + + + + + + + + + + + + + + +598 + +Makefile +file + + + + +2010-02-05T03:38:38.573248Z +c9ec6ab95ab487f534b622cfc2066ca0 +2007-05-27T20:05:31.207389Z +25 +andrew +has-props + + + + + + + + + + + + + + + + + + + + +1588 + +sample-output.txt +file + + + + +2010-02-05T03:38:38.588873Z +2a0f20021a4bcf1427dfe7b8042583f2 +2007-05-26T21:39:54.335125Z +10 +andrew +has-props + + + + + + + + + + + + + + + + + + + + +110329 + diff --git a/source/.svn/prop-base/Makefile.svn-base b/source/.svn/prop-base/Makefile.svn-base new file mode 100755 index 0000000..a669705 --- /dev/null +++ b/source/.svn/prop-base/Makefile.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 0 + +END diff --git a/source/.svn/prop-base/README.txt.svn-base b/source/.svn/prop-base/README.txt.svn-base new file mode 100755 index 0000000..a669705 --- /dev/null +++ b/source/.svn/prop-base/README.txt.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 0 + +END diff --git a/source/.svn/prop-base/gcmbrowser.cpp.svn-base b/source/.svn/prop-base/gcmbrowser.cpp.svn-base new file mode 100755 index 0000000..a669705 --- /dev/null +++ b/source/.svn/prop-base/gcmbrowser.cpp.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 0 + +END diff --git a/source/.svn/prop-base/gcminfo.cpp.svn-base b/source/.svn/prop-base/gcminfo.cpp.svn-base new file mode 100755 index 0000000..a669705 --- /dev/null +++ b/source/.svn/prop-base/gcminfo.cpp.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 0 + +END diff --git a/source/.svn/prop-base/gcminfo.h.svn-base b/source/.svn/prop-base/gcminfo.h.svn-base new file mode 100755 index 0000000..a669705 --- /dev/null +++ b/source/.svn/prop-base/gcminfo.h.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 0 + +END diff --git a/source/.svn/prop-base/sample-output.txt.svn-base b/source/.svn/prop-base/sample-output.txt.svn-base new file mode 100755 index 0000000..a669705 --- /dev/null +++ b/source/.svn/prop-base/sample-output.txt.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 0 + +END diff --git a/source/.svn/prop-base/std_disclaimer.h.svn-base b/source/.svn/prop-base/std_disclaimer.h.svn-base new file mode 100755 index 0000000..a669705 --- /dev/null +++ b/source/.svn/prop-base/std_disclaimer.h.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 0 + +END diff --git a/source/.svn/text-base/Makefile.svn-base b/source/.svn/text-base/Makefile.svn-base new file mode 100755 index 0000000..0d0fbba --- /dev/null +++ b/source/.svn/text-base/Makefile.svn-base @@ -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 diff --git a/source/.svn/text-base/README.txt.svn-base b/source/.svn/text-base/README.txt.svn-base new file mode 100755 index 0000000..67606d5 --- /dev/null +++ b/source/.svn/text-base/README.txt.svn-base @@ -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 + diff --git a/source/.svn/text-base/gcmbrowser.cpp.svn-base b/source/.svn/text-base/gcmbrowser.cpp.svn-base new file mode 100755 index 0000000..c31bdd7 --- /dev/null +++ b/source/.svn/text-base/gcmbrowser.cpp.svn-base @@ -0,0 +1,163 @@ +#include "gcminfo.h" +#include +#include + +// 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> \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 : 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 : 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; +} diff --git a/source/.svn/text-base/gcminfo.cpp.svn-base b/source/.svn/text-base/gcminfo.cpp.svn-base new file mode 100755 index 0000000..6d8d4f2 --- /dev/null +++ b/source/.svn/text-base/gcminfo.cpp.svn-base @@ -0,0 +1,674 @@ +#include "gcminfo.h" +#include +#include +#include + +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 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; +} diff --git a/source/.svn/text-base/gcminfo.h.svn-base b/source/.svn/text-base/gcminfo.h.svn-base new file mode 100755 index 0000000..04eadd1 --- /dev/null +++ b/source/.svn/text-base/gcminfo.h.svn-base @@ -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 +#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); diff --git a/source/.svn/text-base/sample-output.txt.svn-base b/source/.svn/text-base/sample-output.txt.svn-base new file mode 100755 index 0000000..a2cfd4d --- /dev/null +++ b/source/.svn/text-base/sample-output.txt.svn-base @@ -0,0 +1,1709 @@ +DEBUG: turning on byte swapping... +FST string table offset calculated to 0x209e6c... +Game code : 47475345 +Game maker code : 41340000 +DVD Magic Word : c2339f3d +Game name : METAL GEAR SOLID THE TWIN SNAKES +Debug monitor offset : 1d224 +Debug monitor load address : 80280060 +Bootfile offset : 1f700 +FST offset : 205000 +FST size : 729c +FST Max Size : 729c +User position : 803f8d60 +User length : 210000 +Debug-monitor size : 0 +Simulated memory size : 0 +Argument offset : 0 +Debug flag : 0 +Track location : 0 +Track size : 0 +Countrycode : 1 +Version/Date : 2003/04/17 +Apploader entry point : 81200258 +Apploader size : 1954 +Trailer size : 1b8b0 +Apploader binary : +(untested function/invalid data) : refusing to print NULL pointer... +FST String table offset : 20746f4e +Total files in the FST : 1673 +Total entries in the FST string table : 1673 + + + + (FST CONTENTS) +(name) (fnum) (type) (offset) (length) +(root) 0 1 0 1673 +.sbas 1 1 0 1673 +Sync 2 1 0 4 +SyncLock 3 0 210000 329 +audio 4 0 21014c 0 +banks 5 1 0 89 +.sbas 6 1 4 33 +Sync 7 1 5 9 +SyncLock 8 0 21014c 2054 +bank017.spd 9 0 210954 0 +bank017.spt 10 0 210954 1531467 +bank018.spd 11 0 3867a0 19566 +bank018.spt 12 0 38b410 1404419 +bank021.spd 13 0 4e2214 18020 +bank021.spt 14 0 4e6878 2109832 +bank022.spd 15 0 6e9a00 22244 +bank022.spt 16 0 6ef0e4 2120391 +bank024.spd 17 0 8f4bac 21982 +bank024.spt 18 0 8fa18c 2273772 +bank027.spd 19 0 b25378 24108 +bank027.spt 20 0 b2b1a4 2398383 +bank032.spd 21 0 d74a54 24198 +bank032.spt 22 0 d7a8dc 1749186 +bank033.spd 23 0 f259a0 13510 +bank033.spt 24 0 f28e68 2413943 +bank034.spd 25 0 11763e0 18922 +bank034.spt 26 0 117adcc 1511074 +bank035.spd 27 0 12ebc70 18602 +bank035.spt 28 0 12f051c 1115266 +bank037.spd 29 0 14009a0 13212 +bank037.spt 30 0 1403d3c 1955346 +bank042.spd 31 0 15e1350 20640 +bank042.spt 32 0 15e63f0 2013550 +stream 33 0 17d1d60 22834 +.sbas 34 1 4 89 +Sync 35 1 21 37 +SyncLock 36 0 17d7694 3933 +0005L 37 0 17d85f4 0 +0005R 38 0 17d85f4 811392 +0006L 39 0 189e774 811392 +0006R 40 0 19648f4 811392 +0007L 41 0 1a2aa74 811392 +0007R 42 0 1af0bf4 1036896 +0008L 43 0 1bede54 1036896 +0008R 44 0 1ceb0b4 811392 +0009L 45 0 1db1234 811392 +0009R 46 0 1e773b4 786528 +0014L 47 0 1f37414 786528 +0014R 48 0 1ff7474 2991552 +0015L 49 0 22d1a34 2991552 +0015R 50 0 25abff4 2051243 +0016L 51 0 27a0ca0 2051243 +0016R 52 0 299594c 1907543 +0045L 53 0 2b674a4 1907543 +0045R 54 0 2d38ffc 1156416 +0046L 55 0 2e5353c 1156416 +0046R 56 0 2f6da7c 1008883 +0047L 57 0 3063f70 1008883 +0047R 58 0 315a464 1251687 +0048L 59 0 328bdcc 1251687 +0048R 60 0 33bd734 1119205 +0049L 61 0 34ceb1c 1119205 +0049R 62 0 35dff04 1313742 +0050L 63 0 3720ad4 1313742 +0050R 64 0 38616a4 816956 +0051L 65 0 3928de0 816956 +0051R 66 0 39f051c 1140687 +0052L 67 0 3b06cec 1140687 +0052R 68 0 3c1d4bc 1013143 +0053L 69 0 3d14a54 1013143 +0053R 70 0 3e0bfec 812108 +0055L 71 0 3ed2438 812108 +0055R 72 0 3f98884 1142278 +0069L 73 0 40af68c 1142278 +0069R 74 0 41c6494 1647860 +0092L 75 0 4358988 1647860 +0092R 76 0 44eae7c 1134096 +0093L 77 0 45ffc8c 1134096 +0093R 78 0 4714a9c 1319660 +0094L 79 0 4856d88 1319660 +0094R 80 0 4999074 1209696 +0095L 81 0 4ac05d4 1209696 +0095R 82 0 4be7b34 1134096 +0096L 83 0 4cfc944 1134096 +0096R 84 0 4e11754 1707767 +0097L 85 0 4fb264c 1707767 +0097R 86 0 5153544 901216 +0098L 87 0 522f5a4 901216 +0098R 88 0 530b604 3042839 +demo.dat 89 0 55f241c 3042839 +opening.bnr 90 0 58e0000 585379840 +stage.dat 91 0 28723000 6496 +shared 92 0 28728000 203001856 +.sbas 93 1 0 1673 +Sync 94 1 5c 96 +SyncLock 95 0 348c1000 1137 +audio 96 0 348c1474 0 +banks 97 1 5c 1661 +.sbas 98 1 60 129 +Sync 99 1 61 101 +SyncLock 100 0 348c1474 5484 +bank001.spd 101 0 348c29e0 0 +bank001.spt 102 0 348c29e0 2481256 +bank003.spd 103 0 34b20648 21606 +bank003.spt 104 0 34b25ab0 2167834 +bank006.spd 105 0 34d36ecc 26310 +bank006.spt 106 0 34d3d594 2032853 +bank008.spd 107 0 34f2da6c 21772 +bank008.spt 108 0 34f32f78 2098461 +bank013.spd 109 0 35133498 18456 +bank013.spt 110 0 35137cb0 2033464 +bank015.spd 111 0 353283e8 21044 +bank015.spt 112 0 3532d61c 1723454 +bank019.spd 113 0 354d225c 20526 +bank019.spt 114 0 354d728c 1772357 +bank020.spd 115 0 35687dd4 13284 +bank020.spt 116 0 3568b1b8 1816099 +bank023.spd 117 0 358467dc 24434 +bank023.spt 118 0 3584c750 1654605 +bank025.spd 119 0 359e06a0 17574 +bank025.spt 120 0 359e4b48 2475099 +bank026.spd 121 0 35c40fa4 17080 +bank026.spt 122 0 35c4525c 768478 +bank031.spd 123 0 35d00c3c 4642 +bank031.spt 124 0 35d01e60 1700085 +bank048.spd 125 0 35ea0f58 17916 +bank048.spt 126 0 35ea5554 1470612 +bank049.spd 127 0 3600c5e8 348 +bank049.spt 128 0 3600c744 1557407 +stream 129 0 36188ae4 20094 +.sbas 130 1 60 1661 +Sync 131 1 81 133 +SyncLock 132 0 3618d964 109211 +0001L 133 0 361a8400 0 +0001R 134 0 361a8400 1111103 +0003L 135 0 362b7840 1111103 +0003R 136 0 363c6c80 2077232 +0004L 137 0 365c1eb0 2077232 +0004R 138 0 367bd0e0 9072096 +0010L 139 0 37063ec0 9072096 +0010R 140 0 3790aca0 1895483 +0012L 141 0 37ad98dc 1895483 +0012R 142 0 37ca8518 1064426 +0013L 143 0 37dac304 1064426 +0013R 144 0 37eb00f0 908239 +0018L 145 0 37f8dcc0 908239 +0018R 146 0 3806b890 1601047 +0019L 147 0 381f26a8 1601047 +0019R 148 0 383794c0 1357627 +0021L 149 0 384c4bfc 1357627 +0021R 150 0 38610338 581006 +0022L 151 0 3869e0c8 581006 +0022R 152 0 3872be58 2977574 +0039L 153 0 38a02d80 2977574 +0039R 154 0 38cd9ca8 663524 +0041L 155 0 38d7bc8c 663524 +0041R 156 0 38e1dc70 2496360 +0044L 157 0 3907f3d8 2496360 +0044R 158 0 392e0b40 644350 +0054L 159 0 3937e040 644350 +0054R 160 0 3941b540 2301474 +0056L 161 0 3964d364 2301474 +0056R 162 0 3987f188 3144654 +0057L 163 0 39b7ed58 3144654 +0057R 164 0 39e7e928 603090 +0058L 165 0 39f11cfc 603090 +0058R 166 0 39fa50d0 655160 +0059L 167 0 3a045008 655160 +0059R 168 0 3a0e4f40 2124019 +0060L 169 0 3a2eb834 2124019 +0060R 170 0 3a4f2128 2031712 +0061L 171 0 3a6e2188 2031712 +0061R 172 0 3a8d21e8 2980611 +0065L 173 0 3aba9cec 2980611 +0065R 174 0 3ae817f0 3709712 +0071L 175 0 3b20b300 3709712 +0071R 176 0 3b594e10 1743822 +0072L 177 0 3b73e9e0 1743822 +0072R 178 0 3b8e85b0 5456703 +0073L 179 0 3be1c8f0 5456703 +0073R 180 0 3c350c30 5454150 +0074L 181 0 3c884578 5454150 +0074R 182 0 3cdb7ec0 1714831 +0075L 183 0 3cf5a950 1714831 +0075R 184 0 3d0fd3e0 1792950 +0076L 185 0 3d2b2f98 1792950 +0076R 186 0 3d468b50 1542354 +0077L 187 0 3d5e1424 1542354 +0077R 188 0 3d759cf8 1815539 +0078L 189 0 3d9150ec 1815539 +0078R 190 0 3dad04e0 3943551 +0079L 191 0 3de93160 3943551 +0079R 192 0 3e255de0 4840754 +0081L 193 0 3e6f3b14 4840754 +0081R 194 0 3eb91848 4721399 +0088L 195 0 3f012340 4721399 +0088R 196 0 3f492e38 1700167 +0089L 197 0 3f631f80 1700167 +0089R 198 0 3f7d10c8 1543711 +0090L 199 0 3f949ee8 1543711 +0090R 200 0 3fac2d08 1540725 +0091L 201 0 3fc3af80 1540725 +0091R 202 0 3fdb31f8 1540182 +0099L 203 0 3ff2b250 1540182 +0099R 204 0 400a32a8 726808 +0100L 205 0 401549c0 726808 +0100R 206 0 402060d8 1104846 +0176L 207 0 40313ca8 1104846 +0176R 208 0 40421878 196688 +0177L 209 0 404518c8 196688 +0177R 210 0 40481918 243863 +0178L 211 0 404bd1b0 243863 +0178R 212 0 404f8a48 109582 +0179 213 0 40513658 109582 +0180L 214 0 4052e268 100917 +0180R 215 0 40546ca0 67110 +0181G 216 0 405572c8 67110 +0184L 217 0 405678f0 4689496 +0184R 218 0 409e0748 804523 +0200L 219 0 40aa4df4 804523 +0200R 220 0 40b694a0 183522 +0201L 221 0 40b96184 183522 +0201R 222 0 40bc2e68 183522 +0202L 223 0 40befb4c 183522 +0202R 224 0 40c1c830 183522 +0203L 225 0 40c49514 183522 +0203R 226 0 40c761f8 183522 +0204L 227 0 40ca2edc 183522 +0204R 228 0 40ccfbc0 183522 +0205L 229 0 40cfc8a4 183522 +0205R 230 0 40d29588 183522 +0206L 231 0 40d5626c 183522 +0206R 232 0 40d82f50 183522 +0207L 233 0 40dafc34 183522 +0207R 234 0 40ddc918 183522 +0208L 235 0 40e095fc 183522 +0208R 236 0 40e362e0 183522 +0209L 237 0 40e62fc4 183522 +0209R 238 0 40e8fca8 183522 +0210L 239 0 40ebc98c 183522 +0210R 240 0 40ee9670 183522 +0211L 241 0 40f16354 183522 +0211R 242 0 40f43038 183522 +0212L 243 0 40f6fd1c 183522 +0212R 244 0 40f9ca00 183522 +0213L 245 0 40fc96e4 183522 +0213R 246 0 40ff63c8 183522 +0214L 247 0 410230ac 183522 +0214R 248 0 4104fd90 183522 +0215L 249 0 4107ca74 183522 +0215R 250 0 410a9758 183522 +0216L 251 0 410d643c 183522 +0216R 252 0 41103120 183522 +0217L 253 0 4112fe04 183522 +0217R 254 0 4115cae8 183522 +0218L 255 0 411897cc 183522 +0218R 256 0 411b64b0 183522 +0300 257 0 411e3194 183522 +0301 258 0 4120fe78 65975 +0302 259 0 41220030 126765 +0303 260 0 4123ef60 29839 +0304 261 0 412463f0 26164 +0305 262 0 4124ca24 24740 +0306 263 0 41252ac8 30594 +0307 264 0 4125a24c 58267 +0308 265 0 412685e8 12099 +0309 266 0 4126b52c 20171 +0310 267 0 412703f8 25303 +0311 268 0 412766d0 112501 +0312 269 0 41291e48 48847 +0313 270 0 4129dd18 32677 +0314 271 0 412a5cc0 9035 +0315 272 0 412a800c 6997 +0316 273 0 412a9b64 8270 +0317 274 0 412abbb4 7208 +0318 275 0 412ad7dc 7102 +0319 276 0 412af39c 6120 +0320 277 0 412b0b84 7496 +0321 278 0 412b28cc 29839 +0322 279 0 412b9d5c 21614 +0323 280 0 412bf1cc 24740 +0324 281 0 412c5270 30594 +0325 282 0 412cc9f4 58267 +0326 283 0 412dad90 12099 +0327 284 0 412ddcd4 20171 +0328 285 0 412e2ba0 25303 +0329 286 0 412e8e78 112501 +0330 287 0 413045f0 48847 +0331 288 0 413104c0 32677 +0332 289 0 41318468 41599 +0333 290 0 413226e8 28662 +0334 291 0 413296e0 38514 +0335 292 0 41332d54 32363 +0336 293 0 4133abc0 50631 +0337 294 0 41347188 40078 +0338 295 0 41350e18 23958 +0339 296 0 41356bb0 43062 +0340 297 0 413613e8 46852 +0341 298 0 4136caec 50962 +0342 299 0 41379200 25123 +0343 300 0 4137f424 34300 +0344 301 0 41387a20 46322 +0345 302 0 41392f14 26469 +0346 303 0 4139967c 65317 +0347 304 0 413a95a4 23974 +0348 305 0 413af34c 88500 +0349 306 0 413c4d00 46328 +0350 307 0 413d01f8 10230 +0351 308 0 413d29f0 22531 +0352 309 0 413d81f4 18926 +0353 310 0 413dcbe4 22548 +0354 311 0 413e23f8 29200 +0355 312 0 413e9608 24056 +0356 313 0 413ef400 20917 +0357 314 0 413f45b8 40851 +0358 315 0 413fe54c 37106 +0359 316 0 41407640 20987 +0360 317 0 4140c83c 23414 +0361 318 0 414123b4 33325 +0362 319 0 4141a5e4 18546 +0363 320 0 4141ee58 26203 +0364L 321 0 414254b4 19068 +0364R 322 0 41429f30 183522 +0398L 323 0 41456c14 183522 +0398R 324 0 414838f8 972860 +0399L 325 0 41571134 972860 +0399R 326 0 4165e970 581266 +0401 327 0 416ec804 581266 +0402 328 0 4177a698 1001766 +0403 329 0 4186efc0 10812 +0404 330 0 418719fc 32640 +0405 331 0 4187997c 12211 +0406 332 0 4187c930 17888 +0407 333 0 41880f10 20906 +0408 334 0 418860bc 9094 +0409 335 0 41888444 17100 +0410 336 0 4188c710 18866 +0411 337 0 418910c4 25472 +0412 338 0 41897444 11799 +0413 339 0 4189a25c 23776 +0414 340 0 4189ff3c 21930 +0415 341 0 418a54e8 34399 +0416 342 0 418adb48 39324 +0417 343 0 418b74e4 42410 +0418 344 0 418c1a90 16028 +0419 345 0 418c592c 21677 +0420L 346 0 418caddc 23637 +0420R 347 0 418d0a34 11386 +0421L 348 0 418d36b0 11386 +0421R 349 0 418d632c 8131 +0422L 350 0 418d82f0 8131 +0422R 351 0 418da2b4 9311 +0423L 352 0 418dc714 9311 +0423R 353 0 418deb74 10502 +0424L 354 0 418e147c 10502 +0424R 355 0 418e3d84 14510 +0425L 356 0 418e7634 14510 +0425R 357 0 418eaee4 13276 +0426L 358 0 418ee2c0 13276 +0426R 359 0 418f169c 17687 +0427L 360 0 418f5bb4 17687 +0427R 361 0 418fa0cc 9136 +0428L 362 0 418fc47c 9136 +0428R 363 0 418fe82c 9578 +0429L 364 0 41900d98 9578 +0429R 365 0 41903304 17037 +0430L 366 0 41907594 17037 +0430R 367 0 4190b824 11518 +0431L 368 0 4190e524 11518 +0431R 369 0 41911224 10483 +0432L 370 0 41913b18 10483 +0432R 371 0 4191640c 14786 +0433L 372 0 41919dd0 14786 +0433R 373 0 4191d794 22163 +0434L 374 0 41922e28 22163 +0434R 375 0 419284bc 20381 +0435L 376 0 4192d45c 20381 +0435R 377 0 419323fc 19231 +0436L 378 0 41936f1c 19231 +0436R 379 0 4193ba3c 12934 +0437L 380 0 4193ecc4 12934 +0437R 381 0 41941f4c 8432 +0438L 382 0 4194403c 8432 +0438R 383 0 4194612c 21332 +0439L 384 0 4194b480 21332 +0439R 385 0 419507d4 12295 +0440L 386 0 419537dc 12295 +0440R 387 0 419567e4 16010 +0441L 388 0 4195a670 16010 +0441R 389 0 4195e4fc 17893 +0442L 390 0 41962ae4 17893 +0442R 391 0 419670cc 10917 +0443L 392 0 41969b74 10917 +0443R 393 0 4196c61c 9560 +0444L 394 0 4196eb74 9560 +0444R 395 0 419710cc 15203 +0445L 396 0 41974c30 15203 +0445R 397 0 41978794 24724 +0446L 398 0 4197e828 24724 +0446R 399 0 419848bc 20384 +0447L 400 0 4198985c 20384 +0447R 401 0 4198e7fc 10214 +0448L 402 0 41990fe4 10214 +0448R 403 0 419937cc 16367 +0449L 404 0 419977bc 16367 +0449R 405 0 4199b7ac 25891 +0450L 406 0 419a1cd0 25891 +0450R 407 0 419a81f4 27610 +0451L 408 0 419aedd0 27610 +0451R 409 0 419b59ac 10204 +0452L 410 0 419b8188 10204 +0452R 411 0 419ba964 23686 +0453L 412 0 419c05ec 23686 +0453R 413 0 419c6274 15286 +0454L 414 0 419c9e2c 15286 +0454R 415 0 419cd9e4 30948 +0455L 416 0 419d52c8 30948 +0455R 417 0 419dcbac 22895 +0456L 418 0 419e251c 22895 +0456R 419 0 419e7e8c 23864 +0457L 420 0 419edbc4 23864 +0457R 421 0 419f38fc 18500 +0458L 422 0 419f8140 18500 +0458R 423 0 419fc984 25748 +0459L 424 0 41a02e18 25748 +0459R 425 0 41a092ac 15614 +0460L 426 0 41a0cfac 15614 +0460R 427 0 41a10cac 28422 +0461L 428 0 41a17bb4 28422 +0461R 429 0 41a1eabc 31965 +0462L 430 0 41a2679c 31965 +0462R 431 0 41a2e47c 16885 +0463L 432 0 41a32674 16885 +0463R 433 0 41a3686c 47013 +0464L 434 0 41a42014 47013 +0464R 435 0 41a4d7bc 16440 +0465L 436 0 41a517f4 16440 +0465R 437 0 41a5582c 17767 +0466L 438 0 41a59d94 17767 +0466R 439 0 41a5e2fc 26783 +0467L 440 0 41a64b9c 26783 +0467R 441 0 41a6b43c 27442 +0468L 442 0 41a71f70 27442 +0468R 443 0 41a78aa4 20384 +0469L 444 0 41a7da44 20384 +0469R 445 0 41a829e4 16026 +0470L 446 0 41a86880 16026 +0470R 447 0 41a8a71c 14351 +0471L 448 0 41a8df2c 14351 +0471R 449 0 41a9173c 19980 +0472L 450 0 41a96548 19980 +0472R 451 0 41a9b354 31226 +0473L 452 0 41aa2d50 31226 +0473R 453 0 41aaa74c 26982 +0474L 454 0 41ab10b4 26982 +0474R 455 0 41ab7a1c 32544 +0475L 456 0 41abf93c 32544 +0475R 457 0 41ac785c 33387 +0476L 458 0 41acfac8 33387 +0476R 459 0 41ad7d34 18807 +0477L 460 0 41adc6ac 18807 +0477R 461 0 41ae1024 26851 +0478L 462 0 41ae7908 26851 +0478R 463 0 41aee1ec 15645 +0479L 464 0 41af1f0c 15645 +0479R 465 0 41af5c2c 19476 +0481 466 0 41afa840 19476 +0482 467 0 41aff454 56298 +0483 468 0 41b0d040 172587 +0485L 469 0 41b3726c 61067 +0485R 470 0 41b460f8 237560 +0486L 471 0 41b800f0 237560 +0486R 472 0 41bba0e8 23423 +0487L 473 0 41bbfc68 23423 +0487R 474 0 41bc57e8 31476 +0488L 475 0 41bcd2dc 31476 +0488R 476 0 41bd4dd0 54989 +0489L 477 0 41be24a0 54989 +0489R 478 0 41befb70 50591 +0490L 479 0 41bfc110 50591 +0490R 480 0 41c086b0 23610 +0491L 481 0 41c0e2ec 23610 +0491R 482 0 41c13f28 29578 +0492L 483 0 41c1b2b4 29578 +0492R 484 0 41c22640 985152 +0493L 485 0 41d12e80 985152 +0493R 486 0 41e036c0 265146 +0494L 487 0 41e4427c 265146 +0494R 488 0 41e84e38 985152 +0495L 489 0 41f75678 985152 +0495R 490 0 42065eb8 88854 +0496L 491 0 4207b9d0 88854 +0496R 492 0 420914e8 100800 +0497L 493 0 420a9ea8 100800 +0497R 494 0 420c2868 69309 +0498L 495 0 420d3728 69309 +0498R 496 0 420e45e8 81798 +0499L 497 0 420f8570 81798 +0499R 498 0 4210c4f8 120578 +0500 499 0 42129bfc 120578 +0501 500 0 42147300 58672 +0502 501 0 42155830 58151 +0503 502 0 42163b58 58672 +0504 503 0 42172088 58151 +0505 504 0 421803b0 58151 +0506 505 0 4218e6d8 15443 +0507 506 0 4219232c 15682 +0508 507 0 42196070 13181 +0509 508 0 421993f0 92506 +0510 509 0 421afd4c 72343 +0511 510 0 421c17e4 96814 +0512 511 0 421d9214 92506 +0513 512 0 421efb70 72343 +0514 513 0 42201608 96814 +3000 514 0 42219038 6255 +3001 515 0 4221a8a8 47346 +3002 516 0 4222619c 39570 +3003 517 0 4222fc30 49178 +3004 518 0 4223bc4c 35975 +3005 519 0 422448d4 43831 +3006 520 0 4224f40c 71614 +3007 521 0 42260bcc 85710 +3008 522 0 42275a9c 62590 +3009 523 0 42284f1c 92310 +3010 524 0 4229b7b4 46668 +3011 525 0 422a6e00 45935 +3012 526 0 422b2170 48613 +3013 527 0 422bdf58 102390 +3014 528 0 422d6f50 58677 +3015 529 0 422e5488 59019 +3016 530 0 422f3b14 82221 +3017 531 0 42307c44 67316 +3018 532 0 42318338 73426 +3019 533 0 4232a20c 75043 +3020 534 0 4233c730 69002 +3021 535 0 4234d4bc 70172 +3022 536 0 4235e6d8 51711 +3023 537 0 4236b0d8 59727 +3024 538 0 42379a28 92135 +3025 539 0 42390210 94042 +3026 540 0 423a716c 96240 +3027 541 0 423be95c 107578 +3028 542 0 423d8d98 102533 +3029 543 0 423f1e20 96541 +3030 544 0 42409740 59895 +3031 545 0 42418138 62635 +3032 546 0 424275e4 74283 +3033 547 0 42439810 69892 +3034 548 0 4244a914 62880 +3035 549 0 42459eb4 62752 +3036 550 0 424693d4 72789 +3037 551 0 4247b02c 64782 +3038 552 0 4248ad3c 84140 +3039 553 0 4249f5e8 66904 +3040 554 0 424afb40 68350 +3041 555 0 424c0640 69332 +3042 556 0 424d1514 72782 +3043 557 0 424e3164 64802 +3044 558 0 424f2e88 53655 +3045 559 0 42500020 76360 +3046 560 0 42512a68 78622 +3047 561 0 42525d88 66566 +3048 562 0 42536190 57372 +3049 563 0 425441ac 79499 +3050 564 0 42557838 72911 +3051 565 0 42569508 76807 +3052 566 0 4257c110 87396 +3053 567 0 42591674 98775 +3054 568 0 425a984c 78256 +3055 569 0 425bc9fc 70354 +3056 570 0 425cdcd0 77398 +3057 571 0 425e0b28 68391 +3058 572 0 425f1650 49080 +3059 573 0 425fd608 54448 +3060 574 0 4260aab8 64755 +3061 575 0 4261a7ac 51221 +3062 576 0 42626fc4 50504 +3063 577 0 4263350c 75942 +3064 578 0 42645db4 90654 +3065 579 0 4265bfd4 119691 +3066 580 0 42679360 110942 +3067 581 0 426944c0 106523 +3068 582 0 426ae4dc 108998 +3069 583 0 426c8ea4 114087 +3070 584 0 426e4c4c 100885 +3071 585 0 426fd664 81798 +3072 586 0 427115ec 90015 +3073 587 0 4272758c 132968 +3074 588 0 42747cf4 121743 +3075 589 0 42765884 123368 +3076 590 0 42783a6c 111124 +3077 591 0 4279ec80 115304 +3078 592 0 427baee8 139670 +3079 593 0 427dd080 98205 +3080 594 0 427f5020 84154 +3081 595 0 428098dc 111856 +3082 596 0 42824dcc 94909 +3083 597 0 4283c08c 101383 +3084 598 0 42854c94 71415 +3085 599 0 4286638c 111604 +3086 600 0 42881780 112548 +3087 601 0 4289cf24 113563 +3088 602 0 428b8ac0 94251 +3089 603 0 428cfaec 83218 +3090 604 0 428e4000 96000 +3091 605 0 428fb700 100980 +3092 606 0 42914174 74998 +3093 607 0 4292666c 105563 +3094 608 0 429402c8 71597 +3095 609 0 42951a78 95468 +3096 610 0 42968f64 85367 +3097 611 0 4297dcdc 92598 +3098 612 0 42994694 86228 +3099 613 0 429a9768 102244 +3100 614 0 429c26cc 89059 +3101 615 0 429d82b0 110742 +3102 616 0 429f3348 97402 +3103 617 0 42a0afc4 95935 +3104 618 0 42a22684 103316 +3105 619 0 42a3ba18 105822 +3106 620 0 42a55778 98530 +3107 621 0 42a6d85c 70406 +3108 622 0 42a7eb64 60644 +3109 623 0 42a8d848 40095 +3110 624 0 42a974e8 40014 +3111 625 0 42aa1138 26596 +3112 626 0 42aa791c 41235 +3113 627 0 42ab1a30 41091 +3114 628 0 42abbab4 23310 +3115 629 0 42ac15c4 26011 +3116 630 0 42ac7b60 75950 +3117 631 0 42ada410 72266 +3118 632 0 42aebe5c 98728 +3119 633 0 42b04004 92943 +3120 634 0 42b1ab14 96142 +3121 635 0 42b322a4 77411 +3122 636 0 42b45108 118490 +3123 637 0 42b61fe4 119263 +3124 638 0 42b7f1c4 119507 +3125 639 0 42b9c498 77676 +3126 640 0 42baf404 90588 +3127 641 0 42bc55e0 83250 +3128 642 0 42bd9b14 91583 +3129 643 0 42bf00d4 100991 +3130 644 0 42c08b54 89838 +3131 645 0 42c1ea44 82482 +3132 646 0 42c32c78 83630 +3133 647 0 42c47328 81562 +3134 648 0 42c5b1c4 84604 +3135 649 0 42c6fc40 87533 +3136 650 0 42c85230 102620 +3137 651 0 42c9e30c 96704 +3138 652 0 42cb5ccc 92925 +3139 653 0 42ccc7cc 67520 +3140 654 0 42cdcf8c 29010 +3141 655 0 42ce40e0 22050 +3142 656 0 42ce9704 23066 +3143 657 0 42cef120 48010 +3144 658 0 42cfacac 41578 +3145 659 0 42d04f18 46311 +3146 660 0 42d10400 52527 +3147 661 0 42d1d130 58220 +3148 662 0 42d2b49c 52574 +3149 663 0 42d381fc 56923 +3150 664 0 42d46058 64436 +3151 665 0 42d55c0c 74594 +3152 666 0 42d67f70 73187 +3153 667 0 42d79d54 57523 +3154 668 0 42d87e08 53629 +3155 669 0 42d94f88 46470 +3156 670 0 42da0510 34429 +3157 671 0 42da8b90 88221 +3158 672 0 42dbe430 45333 +3159 673 0 42dc9548 48600 +3160 674 0 42dd5320 43080 +3161 675 0 42ddfb68 51892 +3162 676 0 42dec61c 33995 +3163 677 0 42df4ae8 35046 +3164 678 0 42dfd3d0 41021 +3165 679 0 42e07410 36839 +3166 680 0 42e103f8 41094 +3167 681 0 42e1a480 25608 +3168 682 0 42e20888 33667 +3169 683 0 42e28c0c 30720 +3170 684 0 42e3040c 35995 +3171 685 0 42e390a8 15117 +3172 686 0 42e3cbb8 17134 +3173 687 0 42e40ea8 12547 +3174 688 0 42e43fac 12686 +3175 689 0 42e4713c 15112 +3176 690 0 42e4ac44 17839 +3177 691 0 42e4f1f4 33003 +3178 692 0 42e572e0 39551 +3179 693 0 42e60d60 40045 +3180 694 0 42e6a9d0 45258 +3181 695 0 42e75a9c 40114 +3182 696 0 42e7f750 30764 +3183 697 0 42e86f7c 39723 +3184 698 0 42e90aa8 37359 +3185 699 0 42e99c98 41071 +3186 700 0 42ea3d08 31933 +3187 701 0 42eab9c8 67868 +3188 702 0 42ebc2e4 32178 +3189 703 0 42ec4098 26963 +3190 704 0 42eca9ec 36096 +3191 705 0 42ed36ec 43629 +3192 706 0 42ede15c 13658 +3193 707 0 42ee16b8 15290 +3194 708 0 42ee5274 9093 +3195 709 0 42ee75fc 9358 +3196 710 0 42ee9a8c 44852 +3197 711 0 42ef49c0 33726 +3198 712 0 42efcd80 24092 +3199 713 0 42f02b9c 33565 +3200 714 0 42f0aebc 6188 +3201 715 0 42f0c6e8 29511 +3202 716 0 42f13a30 42866 +3203 717 0 42f1e1a4 5554 +3204 718 0 42f1f758 32528 +3205 719 0 42f27668 32858 +3206 720 0 42f2f6c4 7109 +3207 721 0 42f3128c 20758 +3208 722 0 42f363a4 8058 +3209 723 0 42f38320 20707 +3210 724 0 42f3d404 33955 +3211 725 0 42f458a8 7733 +3212 726 0 42f476e0 18044 +3213 727 0 42f4bd5c 6282 +3214 728 0 42f4d5e8 11710 +3215 729 0 42f503a8 9632 +3216 730 0 42f52948 34410 +3217 731 0 42f5afb4 35530 +3218 732 0 42f63a80 15846 +3219 733 0 42f67868 65007 +3220 734 0 42f77658 24829 +3221 735 0 42f7d758 7424 +3222 736 0 42f7f458 21013 +3223 737 0 42f84670 7926 +3224 738 0 42f86568 9866 +3225 739 0 42f88bf4 21748 +3226 740 0 42f8e0e8 9384 +3227 741 0 42f90590 9468 +3228 742 0 42f92a8c 11701 +3229 743 0 42f95844 8749 +3230 744 0 42f97a74 11090 +3231 745 0 42f9a5c8 5472 +3232 746 0 42f9bb28 6178 +3233 747 0 42f9d34c 6624 +3234 748 0 42f9ed2c 8328 +3235 749 0 42fa0db4 12620 +3236 750 0 42fa3f00 13428 +3237 751 0 42fa7374 10258 +3238 752 0 42fa9b88 13259 +3239 753 0 42facf54 11614 +3240 754 0 42fafcb4 9418 +3241 755 0 42fb2180 14768 +3242 756 0 42fb5b30 16463 +3243 757 0 42fb9b80 22076 +3244 758 0 42fbf1bc 14925 +3245 759 0 42fc2c0c 20047 +3246 760 0 42fc7a5c 13459 +3247 761 0 42fcaef0 13158 +3248 762 0 42fce258 11423 +3249 763 0 42fd0ef8 21738 +3250 764 0 42fd63e4 11294 +3251 765 0 42fd9004 8934 +3252 766 0 42fdb2ec 12795 +3253 767 0 42fde4e8 7395 +3254 768 0 42fe01cc 21603 +3255 769 0 42fe5630 19549 +3256 770 0 42fea290 21610 +3257 771 0 42fef6fc 16669 +3258 772 0 42ff381c 13047 +3259 773 0 42ff6b14 12845 +3260 774 0 42ff9d44 23829 +3261 775 0 42fffa5c 20918 +3262 776 0 43004c14 21432 +3263 777 0 43009fcc 21967 +3264 778 0 4300f59c 20212 +3265 779 0 43014490 22378 +3266 780 0 43019bfc 27784 +3267 781 0 43020884 12669 +3268 782 0 43023a04 21645 +3269 783 0 43028e94 14387 +3270 784 0 4302c6c8 15568 +3271 785 0 43030398 12144 +3272 786 0 43033308 12699 +3273 787 0 430364a4 21978 +3274 788 0 4303ba80 22796 +3275 789 0 4304138c 15912 +3276 790 0 430451b4 21664 +3277 791 0 4304a654 16158 +3278 792 0 4304e574 20979 +3279 793 0 43053768 11879 +3280 794 0 430565d0 25287 +3281 795 0 4305c898 40155 +3282 796 0 43066574 29647 +3283 797 0 4306d944 29320 +3284 798 0 43074bcc 22733 +3285 799 0 4307a49c 13883 +3286 800 0 4307dad8 12560 +3287 801 0 43080be8 14559 +3288 802 0 430844c8 12821 +3289 803 0 430876e0 10900 +3290 804 0 4308a174 14669 +3291 805 0 4308dac4 12062 +3292 806 0 430909e4 59622 +3293 807 0 4309f2cc 39031 +3294 808 0 430a8b44 62318 +3295 809 0 430b7eb4 52256 +3296 810 0 430c4ad4 47055 +3297 811 0 430d02a4 45757 +3298 812 0 430db564 46331 +3299 813 0 430e6a60 70203 +3300 814 0 430f7c9c 35140 +3301 815 0 431005e0 41468 +3302 816 0 4310a7dc 52544 +3303 817 0 4311751c 62187 +3304 818 0 43126808 7676 +3305 819 0 43128604 17020 +3306 820 0 4312c880 18666 +3307 821 0 4313116c 10236 +3308 822 0 43133968 8203 +3309 823 0 43135974 13031 +3310 824 0 43138c5c 41125 +3311 825 0 43142d04 83491 +3312 826 0 43157328 39879 +3313 827 0 43160ef0 55247 +3314 828 0 4316e6c0 50387 +3315 829 0 4317ab94 57571 +3316 830 0 43188c78 55470 +3317 831 0 43196528 53728 +3318 832 0 431a3708 47314 +3319 833 0 431aefdc 91907 +3320 834 0 431c56e0 72948 +3321 835 0 431d73d4 50725 +3322 836 0 431e39fc 75098 +3323 837 0 431f5f58 64383 +3324 838 0 43205ad8 67826 +3325 839 0 432163cc 62984 +3326 840 0 432259d4 41064 +3327 841 0 4322fa3c 13406 +3328 842 0 43232e9c 13206 +3329 843 0 43236234 9194 +3330 844 0 43238620 10164 +3331 845 0 4323add4 53589 +3332 846 0 43247f2c 37253 +3333 847 0 432510b4 24259 +3334 848 0 43256f78 34414 +3335 849 0 4325f5e8 10416 +3336 850 0 43261e98 24522 +3337 851 0 43267e64 30023 +3338 852 0 4326f3ac 7420 +3339 853 0 432710a8 32472 +3340 854 0 43278f80 32678 +3341 855 0 43280f28 11432 +3342 856 0 43283bd0 18740 +3343 857 0 43288504 10203 +3344 858 0 4328ace0 24314 +3345 859 0 43290bdc 34874 +3346 860 0 43299418 6741 +3347 861 0 4329ae70 22839 +3348 862 0 432a07a8 8799 +3349 863 0 432a2a08 17312 +3350 864 0 432a6da8 10436 +3351 865 0 432a966c 36970 +3352 866 0 432b26d8 33677 +3353 867 0 432baa68 10189 +3354 868 0 432bd238 117612 +3355 869 0 432d9da4 36818 +3356 870 0 432e2d78 15780 +3357 871 0 432e6b1c 19907 +3358 872 0 432eb8e0 19804 +3359 873 0 432f063c 26196 +3360 874 0 432f6c90 29898 +3361 875 0 432fe15c 16118 +3362 876 0 43302054 6183 +3363 877 0 4330387c 8490 +3364 878 0 433059a8 8147 +3365 879 0 4330797c 10967 +3366 880 0 4330a454 14795 +3367 881 0 4330de20 7554 +3368 882 0 4330fba4 10739 +3369 883 0 43312598 7754 +3370 884 0 433143e4 11574 +3371 885 0 4331711c 10886 +3372 886 0 43319ba4 8380 +3373 887 0 4331bc60 11879 +3374 888 0 4331eac8 11159 +3375 889 0 43321660 10140 +3376 890 0 43323dfc 14299 +3377 891 0 433275d8 15933 +3378 892 0 4332b418 20747 +3379 893 0 43330524 15820 +3380 894 0 433342f0 18887 +3381 895 0 43338cb8 14642 +3382 896 0 4333c5ec 12828 +3383 897 0 4333f808 13718 +3384 898 0 43342da0 21206 +3385 899 0 43348078 11883 +3386 900 0 4334aee4 9213 +3387 901 0 4334d2e4 9518 +3388 902 0 4334f814 9199 +3389 903 0 43351c04 18235 +3390 904 0 43356340 16310 +3391 905 0 4335a2f8 18032 +3392 906 0 4335e968 20741 +3393 907 0 43363a70 19151 +3394 908 0 43368540 19187 +3395 909 0 4336d034 56447 +3396 910 0 4337acb4 34807 +3397 911 0 433834ac 32307 +3398 912 0 4338b2e0 22388 +3399 913 0 43390a54 54485 +3400 914 0 4339df2c 26428 +3401 915 0 433a4668 56668 +3402 916 0 433b23c4 16231 +3403 917 0 433b632c 11990 +3404 918 0 433b9204 12366 +3405 919 0 433bc254 17319 +3406 920 0 433c05fc 14808 +3407 921 0 433c3fd4 14967 +3408 922 0 433c7a4c 27172 +3409 923 0 433ce470 36864 +3410 924 0 433d7470 17511 +3411 925 0 433db8d8 18428 +3412 926 0 433e00d4 8383 +3413 927 0 433e2194 23430 +3414 928 0 433e7d1c 21883 +3415 929 0 433ed298 18430 +3416 930 0 433f1a98 17286 +3417 931 0 433f5e20 17823 +3418 932 0 433fa3c0 19071 +3419 933 0 433fee40 15940 +3420 934 0 43402c84 11560 +3421 935 0 434059ac 14646 +3422 936 0 434092e4 10420 +3423 937 0 4340bb98 14367 +3424 938 0 4340f3b8 11116 +3425 939 0 43411f24 57111 +3426 940 0 4341fe3c 39959 +3427 941 0 43429a54 34163 +3428 942 0 43431fc8 49202 +3429 943 0 4343dffc 36354 +3430 944 0 43446e00 33583 +3431 945 0 4344f130 35661 +3432 946 0 43457c80 56604 +3433 947 0 4346599c 45654 +3434 948 0 43470bf4 34602 +3435 949 0 43479320 29148 +3436 950 0 434804fc 49291 +3437 951 0 4348c588 50051 +3438 952 0 4349890c 12674 +3439 953 0 4349ba90 14398 +3440 954 0 4349f2d0 8387 +3441 955 0 434a1394 11647 +3442 956 0 434a4114 16108 +3443 957 0 434a8000 18901 +3444 958 0 434ac9d8 64472 +3445 959 0 434bc5b0 60538 +3446 960 0 434cb22c 34847 +3447 961 0 434d3a4c 34312 +3448 962 0 434dc054 40227 +3449 963 0 434e5d78 30251 +3450 964 0 434ed3a4 39325 +3451 965 0 434f6d44 36488 +3452 966 0 434ffbcc 39480 +3453 967 0 43509604 72782 +3454 968 0 4351b254 36362 +3455 969 0 43524060 29427 +3456 970 0 4352b354 35286 +3457 971 0 43533d2c 63693 +3458 972 0 435435fc 37359 +3459 973 0 4354c7ec 13525 +3460 974 0 4354fcc4 12530 +3461 975 0 43552db8 8138 +3462 976 0 43554d84 7922 +3463 977 0 43556c78 55108 +3464 978 0 435643bc 29747 +3465 979 0 4356b7f0 26822 +3466 980 0 435720b8 34880 +3467 981 0 4357a8f8 6994 +3468 982 0 4357c44c 34466 +3469 983 0 43584af0 33847 +3470 984 0 4358cf28 6307 +3471 985 0 4358e7cc 35586 +3472 986 0 435972d0 8752 +3473 987 0 43599500 8728 +3474 988 0 4359b718 16327 +3475 989 0 4359f6e0 11912 +3476 990 0 435a2568 33940 +3477 991 0 435aa9fc 29037 +3478 992 0 435b1b6c 14383 +3479 993 0 435b539c 12012 +3480 994 0 435b8288 14327 +3481 995 0 435bba80 12827 +3482 996 0 435bec9c 11772 +3483 997 0 435c1a98 35351 +3484 998 0 435ca4b0 34182 +3485 999 0 435d2a38 9469 +3486 1000 0 435d4f38 145452 +3487 1001 0 435f8764 32087 +3488 1002 0 436004bc 25294 +3489 1003 0 4360678c 39789 +3490 1004 0 436102fc 22067 +3491 1005 0 43615930 48699 +3492 1006 0 4362176c 29554 +3493 1007 0 43628ae0 23139 +3494 1008 0 4362e544 8077 +3495 1009 0 436304d4 9864 +3496 1010 0 43632b5c 9019 +3497 1011 0 43634e98 9756 +3498 1012 0 436374b4 7328 +3499 1013 0 43639154 8650 +3500 1014 0 4363b320 14189 +3501 1015 0 4363ea90 6293 +3502 1016 0 43640328 12501 +3503 1017 0 43643400 11667 +3504 1018 0 43646194 11056 +3505 1019 0 43648cc4 11773 +3506 1020 0 4364bac4 13567 +3507 1021 0 4364efc4 10844 +3508 1022 0 43651a20 16496 +3509 1023 0 43655a90 17957 +3510 1024 0 4365a0b8 18894 +3511 1025 0 4365ea88 18292 +3512 1026 0 436631fc 19290 +3513 1027 0 43667d58 14381 +3514 1028 0 4366b588 16858 +3515 1029 0 4366f764 14662 +3516 1030 0 436730ac 19621 +3517 1031 0 43677d54 12599 +3518 1032 0 4367ae8c 9902 +3519 1033 0 4367d53c 8430 +3520 1034 0 4367f62c 7979 +3521 1035 0 43681558 16796 +3522 1036 0 436856f4 14398 +3523 1037 0 43688f34 14482 +3524 1038 0 4368c7c8 15807 +3525 1039 0 43690588 30403 +3526 1040 0 43697c4c 33424 +3527 1041 0 4369fedc 26765 +3528 1042 0 436a676c 44404 +3529 1043 0 436b14e0 30888 +3530 1044 0 436b8d88 24060 +3531 1045 0 436beb84 26879 +3532 1046 0 436c5484 10739 +3533 1047 0 436c7e78 17816 +3534 1048 0 436cc410 11542 +3535 1049 0 436cf128 13982 +3536 1050 0 436d27c8 15480 +3537 1051 0 436d6440 24114 +3538 1052 0 436dc274 11930 +3539 1053 0 436df110 14268 +3540 1054 0 436e28cc 16767 +3541 1055 0 436e6a4c 22935 +3542 1056 0 436ec3e4 16399 +3543 1057 0 436f03f4 18885 +3544 1058 0 436f4dbc 9770 +3545 1059 0 436f73e8 23253 +3546 1060 0 436fcec0 29816 +3547 1061 0 43704338 26156 +3548 1062 0 4370a964 43140 +3549 1063 0 437151e8 26064 +3550 1064 0 4371b7b8 20179 +3551 1065 0 4372068c 12496 +3552 1066 0 4372375c 15306 +3553 1067 0 43727328 16248 +3554 1068 0 4372b2a0 10571 +3555 1069 0 4372dbec 14392 +3556 1070 0 43731424 11330 +3557 1071 0 43734068 51784 +3558 1072 0 43740ab0 52477 +3559 1073 0 4374d7b0 50395 +3560 1074 0 43759c8c 41962 +3561 1075 0 43764078 34605 +3562 1076 0 4376c7a8 46464 +3563 1077 0 43777d28 45098 +3564 1078 0 43782d54 36435 +3565 1079 0 4378bba8 19403 +3566 1080 0 43790774 41600 +3567 1081 0 4379a9f4 46066 +3568 1082 0 437a5de8 42587 +3569 1083 0 437b0444 11447 +3570 1084 0 437b30fc 10485 +3571 1085 0 437b59f4 14104 +3572 1086 0 437b910c 9948 +3573 1087 0 437bb7e8 20876 +3574 1088 0 437c0974 68399 +3575 1089 0 437d14a4 37752 +3576 1090 0 437da81c 48061 +3577 1091 0 437e63dc 38304 +3578 1092 0 437ef97c 53918 +3579 1093 0 437fcc1c 55182 +3580 1094 0 4380a3ac 43284 +3581 1095 0 43814cc0 64166 +3582 1096 0 43824768 58655 +3583 1097 0 43832c88 71051 +3584 1098 0 43844214 39580 +3585 1099 0 4384dcb0 76024 +3586 1100 0 438605a8 44792 +3587 1101 0 4386b4a0 34429 +3588 1102 0 43873b20 48979 +3589 1103 0 4387fa74 11295 +3590 1104 0 43882694 13584 +3591 1105 0 43885ba4 7804 +3592 1106 0 43887a20 7228 +3593 1107 0 4388965c 56183 +3594 1108 0 438971d4 25742 +3595 1109 0 4389d664 31941 +3596 1110 0 438a532c 40539 +3597 1111 0 438af188 6144 +3598 1112 0 438b0988 26237 +3599 1113 0 438b7008 32525 +3600 1114 0 438bef18 3965 +3601 1115 0 438bfe98 35378 +3602 1116 0 438c88cc 39836 +3603 1117 0 438d2468 9706 +3604 1118 0 438d4a54 17855 +3605 1119 0 438d9014 9987 +3606 1120 0 438db718 15922 +3607 1121 0 438df54c 38920 +3608 1122 0 438e8d54 51370 +3609 1123 0 438f5600 6922 +3610 1124 0 438f710c 80212 +3611 1125 0 4390aa60 9988 +3612 1126 0 4390d164 14552 +3613 1127 0 43910a3c 48600 +3614 1128 0 4391c814 42222 +3615 1129 0 43926d04 11492 +3616 1130 0 439299e8 138899 +3617 1131 0 4394b87c 45256 +3618 1132 0 43956944 15382 +3619 1133 0 4395a55c 39415 +3620 1134 0 43963f54 7414 +3621 1135 0 43965c4c 30807 +3622 1136 0 4396d4a4 13306 +3623 1137 0 439708a0 13180 +3624 1138 0 43973c1c 5787 +3625 1139 0 439752b8 8666 +3626 1140 0 43977494 8491 +3627 1141 0 439795c0 9435 +3628 1142 0 4397ba9c 5292 +3629 1143 0 4397cf48 6134 +3630 1144 0 4397e740 7342 +3631 1145 0 439803f0 6170 +3632 1146 0 43981c0c 12208 +3633 1147 0 43984bbc 10300 +3634 1148 0 439873f8 13925 +3635 1149 0 4398aa60 13339 +3636 1150 0 4398de7c 10506 +3637 1151 0 43990788 8899 +3638 1152 0 43992a4c 18334 +3639 1153 0 439971ec 16075 +3640 1154 0 4399b0b8 18902 +3641 1155 0 4399fa90 15957 +3642 1156 0 439a38e8 20510 +3643 1157 0 439a8908 12490 +3644 1158 0 439ab9d4 15261 +3645 1159 0 439af574 11461 +3646 1160 0 439b223c 18624 +3647 1161 0 439b6afc 11022 +3648 1162 0 439b960c 9571 +3649 1163 0 439bbb70 11827 +3650 1164 0 439be9a4 8005 +3651 1165 0 439c08ec 15004 +3652 1166 0 439c4388 14206 +3653 1167 0 439c7b08 13218 +3654 1168 0 439caeac 15900 +3655 1169 0 439cecc8 12411 +3656 1170 0 439d1d44 14412 +3657 1171 0 439d5590 17628 +3658 1172 0 439d9a6c 35208 +3659 1173 0 439e23f4 24100 +3660 1174 0 439e8218 24356 +3661 1175 0 439ee13c 14334 +3662 1176 0 439f193c 22653 +3663 1177 0 439f71bc 17064 +3664 1178 0 439fb464 17415 +3665 1179 0 439ff86c 12591 +3666 1180 0 43a0299c 16871 +3667 1181 0 43a06b84 16656 +3668 1182 0 43a0ac94 20183 +3669 1183 0 43a0fb6c 16317 +3670 1184 0 43a13b2c 18915 +3671 1185 0 43a18510 24264 +3672 1186 0 43a1e3d8 21983 +3673 1187 0 43a239b8 13016 +3674 1188 0 43a26c90 21432 +3675 1189 0 43a2c048 11096 +3676 1190 0 43a2eba0 25312 +3677 1191 0 43a34e80 13478 +3678 1192 0 43a38328 17196 +3679 1193 0 43a3c654 13839 +3680 1194 0 43a3fc64 17877 +3681 1195 0 43a4423c 12367 +3682 1196 0 43a4728c 10214 +3683 1197 0 43a49a74 14210 +3684 1198 0 43a4d1f8 11368 +3685 1199 0 43a4fe60 15774 +3686 1200 0 43a53c00 14701 +3687 1201 0 43a57570 11141 +5007 1202 0 43a5a0f8 46477 +5012 1203 0 43a65688 640047 +5013 1204 0 43b01ab8 23575 +5014 1205 0 43b076d0 20695 +5015 1206 0 43b0c7a8 20215 +5016 1207 0 43b116a0 38310 +5017 1208 0 43b1ac48 34419 +5018 1209 0 43b232bc 159757 +5019 1210 0 43b4a2cc 52030 +5020 1211 0 43b56e0c 9391 +5021 1212 0 43b592bc 8402 +5022 1213 0 43b5b390 22550 +5023 1214 0 43b60ba8 32140 +5024 1215 0 43b68934 14916 +5025 1216 0 43b6c378 80836 +5026 1217 0 43b7ff3c 108395 +5027 1218 0 43b9a6a8 36101 +5028 1219 0 43ba33b0 26803 +5029 1220 0 43ba9c64 39000 +5030 1221 0 43bb34bc 44566 +5031 1222 0 43bbe2d4 48923 +5032 1223 0 43bca1f0 71959 +5033 1224 0 43bdbb08 71640 +5034 1225 0 43bed2e0 30422 +5035 1226 0 43bf49b8 148274 +5036 1227 0 43c18cec 67780 +5037 1228 0 43c295b0 20662 +5038 1229 0 43c2e668 16238 +5039 1230 0 43c325d8 105980 +5040 1231 0 43c4c3d4 13413 +5041 1232 0 43c4f83c 23038 +5042 1233 0 43c5523c 30671 +5043 1234 0 43c5ca0c 15644 +5044 1235 0 43c60728 32135 +5045 1236 0 43c684b0 40408 +5046 1237 0 43c72288 64462 +5047 1238 0 43c81e58 36012 +5048 1239 0 43c8ab04 100327 +5049 1240 0 43ca32ec 124575 +5050 1241 0 43cc198c 118612 +5051 1242 0 43cde8e0 91659 +5052 1243 0 43cf4eec 56183 +5053 1244 0 43d02a64 74730 +5054 1245 0 43d14e50 100022 +5055 1246 0 43d2d508 97661 +5056 1247 0 43d45288 154875 +5057 1248 0 43d6af84 28372 +5058 1249 0 43d71e58 84919 +5059 1250 0 43d86a10 78912 +5060 1251 0 43d99e50 61212 +5061 1252 0 43da8d6c 184423 +5062 1253 0 43dd5dd4 38390 +5074 1254 0 43ddf3cc 52208 +5075 1255 0 43debfbc 15956 +5076 1256 0 43defe10 19190 +5077 1257 0 43df4908 25990 +5078 1258 0 43dfae90 10427 +5079 1259 0 43dfd74c 23940 +5080L 1260 0 43e034d0 69970 +5080R 1261 0 43e14624 87775 +5081L 1262 0 43e29d04 87775 +5081R 1263 0 43e3f3e4 87775 +5083 1264 0 43e54ac4 87775 +5084 1265 0 43e6a1a4 97204 +5085 1266 0 43e81d58 36141 +5086 1267 0 43e8aa88 31888 +5087 1268 0 43e92718 44632 +5088 1269 0 43e9d570 13856 +5089 1270 0 43ea0b90 61796 +5090 1271 0 43eafcf4 58118 +5091L 1272 0 43ebdffc 46763 +5091R 1273 0 43ec96a8 59327 +5092 1274 0 43ed7e68 59327 +5093 1275 0 43ee6628 13736 +5094 1276 0 43ee9bd0 14581 +5095 1277 0 43eed4c8 9974 +5096 1278 0 43eefbc0 9102 +5097 1279 0 43ef1f50 18036 +5098 1280 0 43ef65c4 13923 +5099 1281 0 43ef9c28 50204 +5100 1282 0 43f06044 61390 +5101 1283 0 43f15014 61842 +5102 1284 0 43f241a8 40950 +5103 1285 0 43f2e1a0 56283 +5104 1286 0 43f3bd7c 170942 +5105 1287 0 43f6593c 266150 +5106 1288 0 43fa68e4 10870 +5107 1289 0 43fa935c 10048 +5108 1290 0 43faba9c 7964 +5109 1291 0 43fad9b8 18295 +5110 1292 0 43fb2130 16221 +5111 1293 0 43fb6090 14450 +5112 1294 0 43fb9904 176608 +5113 1295 0 43fe4ae4 90615 +5114 1296 0 43ffacdc 57728 +5115 1297 0 44008e5c 375564 +5116 1298 0 44064968 338599 +5121 1299 0 440b7410 494404 +5122 1300 0 4412ff54 124874 +5123 1301 0 4414e720 380559 +5124 1302 0 441ab5b0 32339 +5125 1303 0 441b3404 21976 +5126 1304 0 441b89dc 59128 +5127 1305 0 441c70d4 56560 +5128 1306 0 441d4dc4 63612 +5129 1307 0 441e4640 61458 +5130 1308 0 441f3654 26480 +5131 1309 0 441f9dc4 40579 +5132 1310 0 44203c48 34483 +5133 1311 0 4420c2fc 27914 +5134 1312 0 44213008 80915 +5135 1313 0 44226c1c 27778 +5136 1314 0 4422d8a0 24514 +5137 1315 0 44233864 26959 +5138 1316 0 4423a1b4 59653 +5143 1317 0 44248abc 63530 +5144 1318 0 442582e8 376884 +5156 1319 0 442b431c 64926 +5161 1320 0 442c40bc 214674 +5162 1321 0 442f8750 40091 +5165 1322 0 443023ec 58147 +5166 1323 0 44310710 140955 +5167 1324 0 44332dac 125652 +5168 1325 0 44351880 106892 +5169 1326 0 4436ba0c 118386 +5170 1327 0 44388880 82543 +5172 1328 0 4439caf0 49719 +5173 1329 0 443a8d28 43936 +5174 1330 0 443b38c8 29181 +5175 1331 0 443baac8 101018 +5176 1332 0 443d3564 6538 +5177 1333 0 443d4ef0 23184 +5178 1334 0 443da980 13551 +5179 1335 0 443dde70 60004 +5180 1336 0 443ec8d4 44700 +5181 1337 0 443f7770 48951 +5191 1338 0 444036a8 11506 +5192 1339 0 4440639c 7706 +5193 1340 0 444081b8 11096 +5194 1341 0 4440ad10 37380 +5195 1342 0 44413f14 55746 +5197 1343 0 444218d8 77903 +5198 1344 0 44434928 38734 +5199 1345 0 4443e078 8333 +5200 1346 0 44440108 7554 +5201 1347 0 44441e8c 10492 +5202 1348 0 44444788 27011 +5204 1349 0 4444b10c 10659 +5205 1350 0 4444dab0 52786 +5206 1351 0 4445a8e4 25021 +5207 1352 0 44460aa4 27444 +5208 1353 0 444675d8 24988 +5209 1354 0 4446d774 46802 +5210 1355 0 44478e48 15846 +5211 1356 0 4447cc30 31264 +5212 1357 0 44484650 71885 +5213 1358 0 44495f20 17558 +5214 1359 0 4449a3b8 27850 +5215 1360 0 444a1084 19596 +5220 1361 0 444a5d10 74480 +5239 1362 0 444b8000 29132 +5240 1363 0 444bf1cc 31688 +5241 1364 0 444c6d94 43635 +5244 1365 0 444d1808 17404 +5245 1366 0 444d5c04 24630 +5246 1367 0 444dbc3c 84140 +5247 1368 0 444f04e8 101602 +5248 1369 0 445091cc 131893 +5249 1370 0 44529504 33613 +5250 1371 0 44531854 49840 +5251 1372 0 4453db04 40990 +5252 1373 0 44547b24 25267 +5253 1374 0 4454ddd8 19190 +5254 1375 0 445528d0 36738 +5255 1376 0 4455b854 11302 +5256 1377 0 4455e47c 40141 +5257 1378 0 4456814c 15170 +5258 1379 0 4456bc90 28538 +5259 1380 0 44572c0c 9272 +5260 1381 0 44575044 54757 +5261 1382 0 4458262c 35710 +5262 1383 0 4458b1ac 13126 +5263 1384 0 4458e4f4 13126 +5264 1385 0 4459183c 11555 +5265 1386 0 44594560 32724 +5266 1387 0 4459c534 36280 +5267 1388 0 445a52ec 24590 +5268 1389 0 445ab2fc 21784 +5269 1390 0 445b0814 16456 +5270 1391 0 445b485c 23920 +5271 1392 0 445ba5cc 30582 +5272 1393 0 445c1d44 13764 +5273 1394 0 445c5308 12589 +5274 1395 0 445c8438 27589 +5275 1396 0 445cf000 24279 +5276 1397 0 445d4ed8 21253 +5277 1398 0 445da1e0 30780 +5278 1399 0 445e1a1c 26972 +5279 1400 0 445e8378 64502 +5280 1401 0 445f7f70 11309 +5281 1402 0 445faba0 12861 +5282 1403 0 445fdde0 22560 +5283 1404 0 44603600 25128 +5284 1405 0 44609828 39074 +5285 1406 0 446130cc 36087 +5286 1407 0 4461bdc4 10267 +5287 1408 0 4461e5e0 11787 +5288 1409 0 446213ec 14904 +5289 1410 0 44624e24 65079 +5290 1411 0 44634c5c 13956 +5291 1412 0 446382e0 23158 +5292 1413 0 4463dd58 16988 +5293 1414 0 44641fb4 11056 +5294 1415 0 44644ae4 38181 +5295 1416 0 4464e00c 23662 +5296 1417 0 44653c7c 18461 +5297 1418 0 4465849c 18594 +5298 1419 0 4465cd40 20557 +5299 1420 0 44661d90 44679 +5300 1421 0 4466cc18 16922 +5301 1422 0 44670e34 36559 +5302 1423 0 44679d04 886966 +5303 1424 0 447525bc 713058 +5312 1425 0 44800720 330072 +5313 1426 0 44851078 28551 +5314 1427 0 44858000 15754 +5315 1428 0 4485bd8c 30034 +5316 1429 0 448632e0 24365 +5317 1430 0 44869210 35683 +5318 1431 0 44871d74 60602 +5319 1432 0 44880a30 28903 +5320 1433 0 44887b18 20093 +5321 1434 0 4488c998 14427 +5322 1435 0 448901f4 14847 +5323 1436 0 44893bf4 23082 +5324 1437 0 44899620 24086 +5325 1438 0 4489f438 33534 +5326 1439 0 448a7738 21976 +5327 1440 0 448acd10 22142 +5328 1441 0 448b2390 27669 +5329 1442 0 448b8fa8 19797 +5330 1443 0 448bdd00 34047 +5331 1444 0 448c6200 30582 +5332 1445 0 448cd978 19071 +5333 1446 0 448d23f8 40566 +5334 1447 0 448dc270 18925 +5335 1448 0 448e0c60 34708 +5336 1449 0 448e93f4 32631 +5337 1450 0 448f136c 44254 +5338 1451 0 448fc04c 81195 +5339 1452 0 4490fd78 34117 +5340 1453 0 449182c0 30959 +5341 1454 0 4491fbb0 17160 +5342 1455 0 44923eb8 14583 +5343 1456 0 449277b0 32711 +5344 1457 0 4492f778 37142 +5345 1458 0 44938890 37979 +5346 1459 0 44941cec 36054 +5347 1460 0 4494a9c4 30482 +5348 1461 0 449520d8 39372 +5349 1462 0 4495baa4 29519 +5352 1463 0 44962df4 38350 +5353 1464 0 4496c3c4 7951 +5354 1465 0 4496e2d4 7951 +5355 1466 0 449701e4 7278 +5356 1467 0 44971e54 13866 +5357 1468 0 44975480 41509 +5358 1469 0 4497f6a8 15541 +5360L 1470 0 44983360 7951 +5360R 1471 0 44985270 350174 +5361L 1472 0 449daa50 350174 +5361R 1473 0 44a30230 105333 +5362L 1474 0 44a49da8 105333 +5362R 1475 0 44a63920 108931 +5363L 1476 0 44a7e2a4 108931 +5363R 1477 0 44a98c28 106759 +5364L 1478 0 44ab2d30 106759 +5364R 1479 0 44acce38 92504 +5365L 1480 0 44ae3790 92504 +5365R 1481 0 44afa0e8 78215 +5366L 1482 0 44b0d270 78215 +5366R 1483 0 44b203f8 88301 +5367L 1484 0 44b35ce8 88301 +5367R 1485 0 44b4b5d8 88837 +5368L 1486 0 44b610e0 88837 +5368R 1487 0 44b76be8 87636 +5369L 1488 0 44b8c23c 87636 +5369R 1489 0 44ba1890 96818 +5370L 1490 0 44bb92c4 96818 +5370R 1491 0 44bd0cf8 81519 +5371L 1492 0 44be4b68 81519 +5371R 1493 0 44bf89d8 122104 +5372L 1494 0 44c166d0 122104 +5372R 1495 0 44c343c8 123187 +5373L 1496 0 44c524fc 123187 +5373R 1497 0 44c70630 152708 +5374L 1498 0 44c95ab4 152708 +5374R 1499 0 44cbaf38 98028 +5375L 1500 0 44cd2e24 98028 +5375R 1501 0 44cead10 77455 +5376L 1502 0 44cfdba0 77455 +5376R 1503 0 44d10a30 87788 +5377L 1504 0 44d2611c 87788 +5377R 1505 0 44d3b808 115101 +5378L 1506 0 44d579a8 115101 +5378R 1507 0 44d73b48 67219 +5379L 1508 0 44d841dc 67219 +5379R 1509 0 44d94870 69499 +5380L 1510 0 44da57ec 69499 +5380R 1511 0 44db6768 87702 +5381L 1512 0 44dcbe00 87702 +5381R 1513 0 44de1498 73383 +5382L 1514 0 44df3340 73383 +5382R 1515 0 44e051e8 63434 +5383L 1516 0 44e149b4 63434 +5383R 1517 0 44e24180 62638 +5384L 1518 0 44e33630 62638 +5384R 1519 0 44e42ae0 69590 +5385L 1520 0 44e53ab8 69590 +5385R 1521 0 44e64a90 80763 +5386L 1522 0 44e7860c 80763 +5386R 1523 0 44e8c188 80976 +5387L 1524 0 44e9fdd8 80976 +5387R 1525 0 44eb3a28 68343 +5388L 1526 0 44ec4520 68343 +5388R 1527 0 44ed5018 88837 +5389L 1528 0 44eeab20 88837 +5389R 1529 0 44f00628 88220 +5390 1530 0 44f15ec4 88220 +5391 1531 0 44f2b760 90535 +5392 1532 0 44f41908 134693 +5393 1533 0 44f62730 163141 +5394 1534 0 44f8a478 77830 +5395 1535 0 44f9d480 68456 +5396 1536 0 44fadfe8 63362 +5397 1537 0 44fbd76c 102092 +5398 1538 0 44fd6638 131296 +5399 1539 0 44ff6718 71640 +5400 1540 0 45007ef0 97754 +5401 1541 0 4501fccc 147855 +5402 1542 0 45043e5c 94144 +5403 1543 0 4505ae1c 81195 +5404 1544 0 4506eb48 76524 +5405 1545 0 45081634 134693 +5406 1546 0 450a245c 83954 +5407 1547 0 450b6c50 158895 +5408 1548 0 450dd900 123653 +5409 1549 0 450fbc08 98178 +5410 1550 0 45113b8c 117285 +5411 1551 0 451305b4 97754 +5412 1552 0 45148390 83264 +5413 1553 0 4515c8d0 87139 +5414 1554 0 45171d34 90110 +5415 1555 0 45187d34 61238 +5416 1556 0 45196c6c 201354 +5417 1557 0 451c7ef8 79071 +5418 1558 0 451db3d8 75462 +5419 1559 0 451edaa0 93932 +5420 1560 0 4520498c 81619 +5421 1561 0 45218860 140213 +5422 1562 0 4523ac18 128324 +5423 1563 0 4525a15c 155498 +5424 1564 0 452800c8 123229 +5425 1565 0 4529e228 310050 +5426 1566 0 452e9d4c 152101 +5427 1567 0 4530ef74 99876 +5428 1568 0 45327598 63573 +5429 1569 0 45336df0 31304 +5430 1570 0 4533e838 273535 +5431 1571 0 453814b8 99452 +5432 1572 0 45399934 80982 +5433 1573 0 453ad58c 69093 +5434 1574 0 453be374 44254 +5435 1575 0 453c9054 44043 +5436 1576 0 453d3c60 88837 +5437 1577 0 453e9768 90959 +5438 1578 0 453ffab8 53171 +5439 1579 0 4540ca6c 63998 +5440 1580 0 4541c46c 73127 +5441 1581 0 4542e214 37886 +5442 1582 0 45437614 54232 +5443 1583 0 454449ec 38310 +5444 1584 0 4544df94 40858 +5445 1585 0 45457f30 81406 +5446 1586 0 4546bd30 119630 +5447 1587 0 45489080 82314 +5448 1588 0 4549d20c 107848 +5449 1589 0 454b7754 48724 +5450 1590 0 454c35a8 35947 +5451 1591 0 454cc214 261844 +5452 1592 0 4550c0e8 142931 +5453 1593 0 4552ef3c 55852 +5454 1594 0 4553c968 35349 +5455 1595 0 45545380 46867 +5456 1596 0 45550a94 43821 +5457 1597 0 4555b5c4 43821 +5458 1598 0 455660f4 63581 +5459 1599 0 45575954 79983 +5460 1600 0 455891c4 71138 +5461 1601 0 4559a7a8 33663 +5462 1602 0 455a2b28 58783 +5463 1603 0 455b10c8 51467 +5464 1604 0 455bd9d4 30387 +5465 1605 0 455c5088 35903 +5466 1606 0 455cdcc8 30798 +5467 1607 0 455d5518 30240 +5468 1608 0 455dcb38 61966 +5469 1609 0 455ebd48 44014 +5470 1610 0 455f6938 30904 +5471 1611 0 455fe1f0 50794 +5472 1612 0 4560a85c 44902 +5473 1613 0 456157c4 77646 +5474 1614 0 45628714 42527 +5475 1615 0 45632d34 32702 +5476 1616 0 4563acf4 45716 +5477 1617 0 45645f88 40186 +5478 1618 0 4564fc84 34646 +5479 1619 0 456583dc 59830 +5480L 1620 0 45666d94 508373 +5480R 1621 0 456e2f6c 88854 +5481L 1622 0 456f8a84 88854 +5481R 1623 0 4570e59c 100800 +5482L 1624 0 45726f5c 100800 +5482R 1625 0 4573f91c 75015 +5483L 1626 0 45751e24 75015 +5483R 1627 0 4576432c 76886 +5484L 1628 0 45776f84 76886 +5484R 1629 0 45789bdc 106846 +5485L 1630 0 457a3d3c 106846 +5485R 1631 0 457bde9c 75592 +5486L 1632 0 457d05e4 75592 +5486R 1633 0 457e2d2c 71459 +5487L 1634 0 457f4450 71459 +5487R 1635 0 45805b74 69309 +5488L 1636 0 45816a34 69309 +5488R 1637 0 458278f4 83878 +5489L 1638 0 4583c09c 83878 +5489R 1639 0 45850844 84092 +5490L 1640 0 458650c0 84092 +5490R 1641 0 4587993c 68434 +5491L 1642 0 4588a490 68434 +5491R 1643 0 4589afe4 79526 +5492L 1644 0 458ae68c 79526 +5492R 1645 0 458c1d34 73709 +5493L 1646 0 458d3d24 73709 +5493R 1647 0 458e5d14 75413 +5494L 1648 0 458f83ac 75413 +5494R 1649 0 4590aa44 81798 +5495L 1650 0 4591e9cc 81798 +5495R 1651 0 45932954 136661 +5496L 1652 0 45953f2c 136661 +5496R 1653 0 45975504 99269 +5603L 1654 0 4598d8cc 99269 +5603R 1655 0 459a5c94 251260 +6010 1656 0 459e3210 251260 +6011 1657 0 45a2078c 10318 +6012 1658 0 45a22fdc 43850 +6013 1659 0 45a2db28 199019 +6014 1660 0 45a5e494 66546 +codec.dat 1661 0 45a6e888 34276 +DebugImages.tpl 1662 0 45a78000 12409824 +dummy.tpl 1663 0 4664dbe0 1835136 +face.dat 1664 0 4680dc60 256 +ip.cfg 1665 0 46810000 7034880 +mgso.rel 1666 0 46ec5800 48 +mgso.str 1667 0 46ec5830 5729024 +movie.dat 1668 0 4743c330 35 +stage 1669 0 47440000 94935040 +preview 1670 1 5c 1672 +data.cnf 1671 1 685 1672 +vox.dat 1672 0 4cec9800 175 +freeing memory used by FST string table... ...done. diff --git a/source/.svn/text-base/std_disclaimer.h.svn-base b/source/.svn/text-base/std_disclaimer.h.svn-base new file mode 100755 index 0000000..6e8827c --- /dev/null +++ b/source/.svn/text-base/std_disclaimer.h.svn-base @@ -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 */ diff --git a/source/CVS/.svn/all-wcprops b/source/CVS/.svn/all-wcprops new file mode 100755 index 0000000..1d14ac4 --- /dev/null +++ b/source/CVS/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 51 +/svn/aklabs/!svn/ver/10/trunk/gcmbrowser/source/CVS +END +Repository +K 25 +svn:wc:ra_dav:version-url +V 62 +/svn/aklabs/!svn/ver/10/trunk/gcmbrowser/source/CVS/Repository +END +Root +K 25 +svn:wc:ra_dav:version-url +V 56 +/svn/aklabs/!svn/ver/10/trunk/gcmbrowser/source/CVS/Root +END +Entries +K 25 +svn:wc:ra_dav:version-url +V 59 +/svn/aklabs/!svn/ver/10/trunk/gcmbrowser/source/CVS/Entries +END diff --git a/source/CVS/.svn/entries b/source/CVS/.svn/entries new file mode 100755 index 0000000..981ec34 --- /dev/null +++ b/source/CVS/.svn/entries @@ -0,0 +1,130 @@ +10 + +dir +44 +https://127.0.0.1/svn/aklabs/trunk/gcmbrowser/source/CVS +https://127.0.0.1/svn/aklabs + + + +2007-05-26T21:39:54.335125Z +10 +andrew + + + + + + + + + + + + + + +eb184899-6090-47d4-a65b-558f62f6ea1c + +Repository +file + + + + +2010-02-05T03:38:38.432623Z +dd9ce8b79f776a0af94e6e826fafa5a5 +2007-05-26T21:39:54.335125Z +10 +andrew + + + + + + + + + + + + + + + + + + + + + +24 + +Root +file + + + + +2010-02-05T03:38:38.432623Z +7af14a164593104c1e7a07a572dd352a +2007-05-26T21:39:54.335125Z +10 +andrew + + + + + + + + + + + + + + + + + + + + + +24 + +Entries +file + + + + +2010-02-05T03:38:38.432623Z +e1a46804a276c986516219ef14fc2ee1 +2007-05-26T21:39:54.335125Z +10 +andrew + + + + + + + + + + + + + + + + + + + + + +346 + diff --git a/source/CVS/.svn/text-base/Entries.svn-base b/source/CVS/.svn/text-base/Entries.svn-base new file mode 100755 index 0000000..d8bbddb --- /dev/null +++ b/source/CVS/.svn/text-base/Entries.svn-base @@ -0,0 +1,8 @@ +/Makefile/1.1.1.1/Sun Jan 1 00:15:04 2006// +/README.txt/1.1.1.1/Sun Jan 1 00:15:04 2006// +/gcmbrowser.cpp/1.1.1.1/Sun Jan 1 00:15:04 2006// +/gcminfo.cpp/1.1.1.1/Sun Jan 1 00:15:04 2006// +/gcminfo.h/1.1.1.1/Sun Jan 1 00:15:04 2006// +/sample-output.txt/1.1.1.1/Sun Jan 1 00:15:04 2006// +/std_disclaimer.h/1.1.1.1/Sun Jan 1 00:15:04 2006// +D diff --git a/source/CVS/.svn/text-base/Repository.svn-base b/source/CVS/.svn/text-base/Repository.svn-base new file mode 100755 index 0000000..5468d98 --- /dev/null +++ b/source/CVS/.svn/text-base/Repository.svn-base @@ -0,0 +1 @@ +utils/gcmbrowser/source diff --git a/source/CVS/.svn/text-base/Root.svn-base b/source/CVS/.svn/text-base/Root.svn-base new file mode 100755 index 0000000..180ad4a --- /dev/null +++ b/source/CVS/.svn/text-base/Root.svn-base @@ -0,0 +1 @@ +andrew@gabbo:/home/cvsd diff --git a/source/CVS/Entries b/source/CVS/Entries new file mode 100755 index 0000000..d8bbddb --- /dev/null +++ b/source/CVS/Entries @@ -0,0 +1,8 @@ +/Makefile/1.1.1.1/Sun Jan 1 00:15:04 2006// +/README.txt/1.1.1.1/Sun Jan 1 00:15:04 2006// +/gcmbrowser.cpp/1.1.1.1/Sun Jan 1 00:15:04 2006// +/gcminfo.cpp/1.1.1.1/Sun Jan 1 00:15:04 2006// +/gcminfo.h/1.1.1.1/Sun Jan 1 00:15:04 2006// +/sample-output.txt/1.1.1.1/Sun Jan 1 00:15:04 2006// +/std_disclaimer.h/1.1.1.1/Sun Jan 1 00:15:04 2006// +D diff --git a/source/CVS/Repository b/source/CVS/Repository new file mode 100755 index 0000000..5468d98 --- /dev/null +++ b/source/CVS/Repository @@ -0,0 +1 @@ +utils/gcmbrowser/source diff --git a/source/CVS/Root b/source/CVS/Root new file mode 100755 index 0000000..180ad4a --- /dev/null +++ b/source/CVS/Root @@ -0,0 +1 @@ +andrew@gabbo:/home/cvsd diff --git a/source/Makefile b/source/Makefile new file mode 100755 index 0000000..0d0fbba --- /dev/null +++ b/source/Makefile @@ -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 diff --git a/source/README.txt b/source/README.txt new file mode 100755 index 0000000..67606d5 --- /dev/null +++ b/source/README.txt @@ -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 + diff --git a/source/gcmbrowser.cpp b/source/gcmbrowser.cpp new file mode 100755 index 0000000..c31bdd7 --- /dev/null +++ b/source/gcmbrowser.cpp @@ -0,0 +1,163 @@ +#include "gcminfo.h" +#include +#include + +// 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> \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 : 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 : 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; +} diff --git a/source/gcminfo.cpp b/source/gcminfo.cpp new file mode 100755 index 0000000..6d8d4f2 --- /dev/null +++ b/source/gcminfo.cpp @@ -0,0 +1,674 @@ +#include "gcminfo.h" +#include +#include +#include + +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 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; +} diff --git a/source/gcminfo.h b/source/gcminfo.h new file mode 100755 index 0000000..04eadd1 --- /dev/null +++ b/source/gcminfo.h @@ -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 +#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); diff --git a/source/sample-output.txt b/source/sample-output.txt new file mode 100755 index 0000000..a2cfd4d --- /dev/null +++ b/source/sample-output.txt @@ -0,0 +1,1709 @@ +DEBUG: turning on byte swapping... +FST string table offset calculated to 0x209e6c... +Game code : 47475345 +Game maker code : 41340000 +DVD Magic Word : c2339f3d +Game name : METAL GEAR SOLID THE TWIN SNAKES +Debug monitor offset : 1d224 +Debug monitor load address : 80280060 +Bootfile offset : 1f700 +FST offset : 205000 +FST size : 729c +FST Max Size : 729c +User position : 803f8d60 +User length : 210000 +Debug-monitor size : 0 +Simulated memory size : 0 +Argument offset : 0 +Debug flag : 0 +Track location : 0 +Track size : 0 +Countrycode : 1 +Version/Date : 2003/04/17 +Apploader entry point : 81200258 +Apploader size : 1954 +Trailer size : 1b8b0 +Apploader binary : +(untested function/invalid data) : refusing to print NULL pointer... +FST String table offset : 20746f4e +Total files in the FST : 1673 +Total entries in the FST string table : 1673 + + + + (FST CONTENTS) +(name) (fnum) (type) (offset) (length) +(root) 0 1 0 1673 +.sbas 1 1 0 1673 +Sync 2 1 0 4 +SyncLock 3 0 210000 329 +audio 4 0 21014c 0 +banks 5 1 0 89 +.sbas 6 1 4 33 +Sync 7 1 5 9 +SyncLock 8 0 21014c 2054 +bank017.spd 9 0 210954 0 +bank017.spt 10 0 210954 1531467 +bank018.spd 11 0 3867a0 19566 +bank018.spt 12 0 38b410 1404419 +bank021.spd 13 0 4e2214 18020 +bank021.spt 14 0 4e6878 2109832 +bank022.spd 15 0 6e9a00 22244 +bank022.spt 16 0 6ef0e4 2120391 +bank024.spd 17 0 8f4bac 21982 +bank024.spt 18 0 8fa18c 2273772 +bank027.spd 19 0 b25378 24108 +bank027.spt 20 0 b2b1a4 2398383 +bank032.spd 21 0 d74a54 24198 +bank032.spt 22 0 d7a8dc 1749186 +bank033.spd 23 0 f259a0 13510 +bank033.spt 24 0 f28e68 2413943 +bank034.spd 25 0 11763e0 18922 +bank034.spt 26 0 117adcc 1511074 +bank035.spd 27 0 12ebc70 18602 +bank035.spt 28 0 12f051c 1115266 +bank037.spd 29 0 14009a0 13212 +bank037.spt 30 0 1403d3c 1955346 +bank042.spd 31 0 15e1350 20640 +bank042.spt 32 0 15e63f0 2013550 +stream 33 0 17d1d60 22834 +.sbas 34 1 4 89 +Sync 35 1 21 37 +SyncLock 36 0 17d7694 3933 +0005L 37 0 17d85f4 0 +0005R 38 0 17d85f4 811392 +0006L 39 0 189e774 811392 +0006R 40 0 19648f4 811392 +0007L 41 0 1a2aa74 811392 +0007R 42 0 1af0bf4 1036896 +0008L 43 0 1bede54 1036896 +0008R 44 0 1ceb0b4 811392 +0009L 45 0 1db1234 811392 +0009R 46 0 1e773b4 786528 +0014L 47 0 1f37414 786528 +0014R 48 0 1ff7474 2991552 +0015L 49 0 22d1a34 2991552 +0015R 50 0 25abff4 2051243 +0016L 51 0 27a0ca0 2051243 +0016R 52 0 299594c 1907543 +0045L 53 0 2b674a4 1907543 +0045R 54 0 2d38ffc 1156416 +0046L 55 0 2e5353c 1156416 +0046R 56 0 2f6da7c 1008883 +0047L 57 0 3063f70 1008883 +0047R 58 0 315a464 1251687 +0048L 59 0 328bdcc 1251687 +0048R 60 0 33bd734 1119205 +0049L 61 0 34ceb1c 1119205 +0049R 62 0 35dff04 1313742 +0050L 63 0 3720ad4 1313742 +0050R 64 0 38616a4 816956 +0051L 65 0 3928de0 816956 +0051R 66 0 39f051c 1140687 +0052L 67 0 3b06cec 1140687 +0052R 68 0 3c1d4bc 1013143 +0053L 69 0 3d14a54 1013143 +0053R 70 0 3e0bfec 812108 +0055L 71 0 3ed2438 812108 +0055R 72 0 3f98884 1142278 +0069L 73 0 40af68c 1142278 +0069R 74 0 41c6494 1647860 +0092L 75 0 4358988 1647860 +0092R 76 0 44eae7c 1134096 +0093L 77 0 45ffc8c 1134096 +0093R 78 0 4714a9c 1319660 +0094L 79 0 4856d88 1319660 +0094R 80 0 4999074 1209696 +0095L 81 0 4ac05d4 1209696 +0095R 82 0 4be7b34 1134096 +0096L 83 0 4cfc944 1134096 +0096R 84 0 4e11754 1707767 +0097L 85 0 4fb264c 1707767 +0097R 86 0 5153544 901216 +0098L 87 0 522f5a4 901216 +0098R 88 0 530b604 3042839 +demo.dat 89 0 55f241c 3042839 +opening.bnr 90 0 58e0000 585379840 +stage.dat 91 0 28723000 6496 +shared 92 0 28728000 203001856 +.sbas 93 1 0 1673 +Sync 94 1 5c 96 +SyncLock 95 0 348c1000 1137 +audio 96 0 348c1474 0 +banks 97 1 5c 1661 +.sbas 98 1 60 129 +Sync 99 1 61 101 +SyncLock 100 0 348c1474 5484 +bank001.spd 101 0 348c29e0 0 +bank001.spt 102 0 348c29e0 2481256 +bank003.spd 103 0 34b20648 21606 +bank003.spt 104 0 34b25ab0 2167834 +bank006.spd 105 0 34d36ecc 26310 +bank006.spt 106 0 34d3d594 2032853 +bank008.spd 107 0 34f2da6c 21772 +bank008.spt 108 0 34f32f78 2098461 +bank013.spd 109 0 35133498 18456 +bank013.spt 110 0 35137cb0 2033464 +bank015.spd 111 0 353283e8 21044 +bank015.spt 112 0 3532d61c 1723454 +bank019.spd 113 0 354d225c 20526 +bank019.spt 114 0 354d728c 1772357 +bank020.spd 115 0 35687dd4 13284 +bank020.spt 116 0 3568b1b8 1816099 +bank023.spd 117 0 358467dc 24434 +bank023.spt 118 0 3584c750 1654605 +bank025.spd 119 0 359e06a0 17574 +bank025.spt 120 0 359e4b48 2475099 +bank026.spd 121 0 35c40fa4 17080 +bank026.spt 122 0 35c4525c 768478 +bank031.spd 123 0 35d00c3c 4642 +bank031.spt 124 0 35d01e60 1700085 +bank048.spd 125 0 35ea0f58 17916 +bank048.spt 126 0 35ea5554 1470612 +bank049.spd 127 0 3600c5e8 348 +bank049.spt 128 0 3600c744 1557407 +stream 129 0 36188ae4 20094 +.sbas 130 1 60 1661 +Sync 131 1 81 133 +SyncLock 132 0 3618d964 109211 +0001L 133 0 361a8400 0 +0001R 134 0 361a8400 1111103 +0003L 135 0 362b7840 1111103 +0003R 136 0 363c6c80 2077232 +0004L 137 0 365c1eb0 2077232 +0004R 138 0 367bd0e0 9072096 +0010L 139 0 37063ec0 9072096 +0010R 140 0 3790aca0 1895483 +0012L 141 0 37ad98dc 1895483 +0012R 142 0 37ca8518 1064426 +0013L 143 0 37dac304 1064426 +0013R 144 0 37eb00f0 908239 +0018L 145 0 37f8dcc0 908239 +0018R 146 0 3806b890 1601047 +0019L 147 0 381f26a8 1601047 +0019R 148 0 383794c0 1357627 +0021L 149 0 384c4bfc 1357627 +0021R 150 0 38610338 581006 +0022L 151 0 3869e0c8 581006 +0022R 152 0 3872be58 2977574 +0039L 153 0 38a02d80 2977574 +0039R 154 0 38cd9ca8 663524 +0041L 155 0 38d7bc8c 663524 +0041R 156 0 38e1dc70 2496360 +0044L 157 0 3907f3d8 2496360 +0044R 158 0 392e0b40 644350 +0054L 159 0 3937e040 644350 +0054R 160 0 3941b540 2301474 +0056L 161 0 3964d364 2301474 +0056R 162 0 3987f188 3144654 +0057L 163 0 39b7ed58 3144654 +0057R 164 0 39e7e928 603090 +0058L 165 0 39f11cfc 603090 +0058R 166 0 39fa50d0 655160 +0059L 167 0 3a045008 655160 +0059R 168 0 3a0e4f40 2124019 +0060L 169 0 3a2eb834 2124019 +0060R 170 0 3a4f2128 2031712 +0061L 171 0 3a6e2188 2031712 +0061R 172 0 3a8d21e8 2980611 +0065L 173 0 3aba9cec 2980611 +0065R 174 0 3ae817f0 3709712 +0071L 175 0 3b20b300 3709712 +0071R 176 0 3b594e10 1743822 +0072L 177 0 3b73e9e0 1743822 +0072R 178 0 3b8e85b0 5456703 +0073L 179 0 3be1c8f0 5456703 +0073R 180 0 3c350c30 5454150 +0074L 181 0 3c884578 5454150 +0074R 182 0 3cdb7ec0 1714831 +0075L 183 0 3cf5a950 1714831 +0075R 184 0 3d0fd3e0 1792950 +0076L 185 0 3d2b2f98 1792950 +0076R 186 0 3d468b50 1542354 +0077L 187 0 3d5e1424 1542354 +0077R 188 0 3d759cf8 1815539 +0078L 189 0 3d9150ec 1815539 +0078R 190 0 3dad04e0 3943551 +0079L 191 0 3de93160 3943551 +0079R 192 0 3e255de0 4840754 +0081L 193 0 3e6f3b14 4840754 +0081R 194 0 3eb91848 4721399 +0088L 195 0 3f012340 4721399 +0088R 196 0 3f492e38 1700167 +0089L 197 0 3f631f80 1700167 +0089R 198 0 3f7d10c8 1543711 +0090L 199 0 3f949ee8 1543711 +0090R 200 0 3fac2d08 1540725 +0091L 201 0 3fc3af80 1540725 +0091R 202 0 3fdb31f8 1540182 +0099L 203 0 3ff2b250 1540182 +0099R 204 0 400a32a8 726808 +0100L 205 0 401549c0 726808 +0100R 206 0 402060d8 1104846 +0176L 207 0 40313ca8 1104846 +0176R 208 0 40421878 196688 +0177L 209 0 404518c8 196688 +0177R 210 0 40481918 243863 +0178L 211 0 404bd1b0 243863 +0178R 212 0 404f8a48 109582 +0179 213 0 40513658 109582 +0180L 214 0 4052e268 100917 +0180R 215 0 40546ca0 67110 +0181G 216 0 405572c8 67110 +0184L 217 0 405678f0 4689496 +0184R 218 0 409e0748 804523 +0200L 219 0 40aa4df4 804523 +0200R 220 0 40b694a0 183522 +0201L 221 0 40b96184 183522 +0201R 222 0 40bc2e68 183522 +0202L 223 0 40befb4c 183522 +0202R 224 0 40c1c830 183522 +0203L 225 0 40c49514 183522 +0203R 226 0 40c761f8 183522 +0204L 227 0 40ca2edc 183522 +0204R 228 0 40ccfbc0 183522 +0205L 229 0 40cfc8a4 183522 +0205R 230 0 40d29588 183522 +0206L 231 0 40d5626c 183522 +0206R 232 0 40d82f50 183522 +0207L 233 0 40dafc34 183522 +0207R 234 0 40ddc918 183522 +0208L 235 0 40e095fc 183522 +0208R 236 0 40e362e0 183522 +0209L 237 0 40e62fc4 183522 +0209R 238 0 40e8fca8 183522 +0210L 239 0 40ebc98c 183522 +0210R 240 0 40ee9670 183522 +0211L 241 0 40f16354 183522 +0211R 242 0 40f43038 183522 +0212L 243 0 40f6fd1c 183522 +0212R 244 0 40f9ca00 183522 +0213L 245 0 40fc96e4 183522 +0213R 246 0 40ff63c8 183522 +0214L 247 0 410230ac 183522 +0214R 248 0 4104fd90 183522 +0215L 249 0 4107ca74 183522 +0215R 250 0 410a9758 183522 +0216L 251 0 410d643c 183522 +0216R 252 0 41103120 183522 +0217L 253 0 4112fe04 183522 +0217R 254 0 4115cae8 183522 +0218L 255 0 411897cc 183522 +0218R 256 0 411b64b0 183522 +0300 257 0 411e3194 183522 +0301 258 0 4120fe78 65975 +0302 259 0 41220030 126765 +0303 260 0 4123ef60 29839 +0304 261 0 412463f0 26164 +0305 262 0 4124ca24 24740 +0306 263 0 41252ac8 30594 +0307 264 0 4125a24c 58267 +0308 265 0 412685e8 12099 +0309 266 0 4126b52c 20171 +0310 267 0 412703f8 25303 +0311 268 0 412766d0 112501 +0312 269 0 41291e48 48847 +0313 270 0 4129dd18 32677 +0314 271 0 412a5cc0 9035 +0315 272 0 412a800c 6997 +0316 273 0 412a9b64 8270 +0317 274 0 412abbb4 7208 +0318 275 0 412ad7dc 7102 +0319 276 0 412af39c 6120 +0320 277 0 412b0b84 7496 +0321 278 0 412b28cc 29839 +0322 279 0 412b9d5c 21614 +0323 280 0 412bf1cc 24740 +0324 281 0 412c5270 30594 +0325 282 0 412cc9f4 58267 +0326 283 0 412dad90 12099 +0327 284 0 412ddcd4 20171 +0328 285 0 412e2ba0 25303 +0329 286 0 412e8e78 112501 +0330 287 0 413045f0 48847 +0331 288 0 413104c0 32677 +0332 289 0 41318468 41599 +0333 290 0 413226e8 28662 +0334 291 0 413296e0 38514 +0335 292 0 41332d54 32363 +0336 293 0 4133abc0 50631 +0337 294 0 41347188 40078 +0338 295 0 41350e18 23958 +0339 296 0 41356bb0 43062 +0340 297 0 413613e8 46852 +0341 298 0 4136caec 50962 +0342 299 0 41379200 25123 +0343 300 0 4137f424 34300 +0344 301 0 41387a20 46322 +0345 302 0 41392f14 26469 +0346 303 0 4139967c 65317 +0347 304 0 413a95a4 23974 +0348 305 0 413af34c 88500 +0349 306 0 413c4d00 46328 +0350 307 0 413d01f8 10230 +0351 308 0 413d29f0 22531 +0352 309 0 413d81f4 18926 +0353 310 0 413dcbe4 22548 +0354 311 0 413e23f8 29200 +0355 312 0 413e9608 24056 +0356 313 0 413ef400 20917 +0357 314 0 413f45b8 40851 +0358 315 0 413fe54c 37106 +0359 316 0 41407640 20987 +0360 317 0 4140c83c 23414 +0361 318 0 414123b4 33325 +0362 319 0 4141a5e4 18546 +0363 320 0 4141ee58 26203 +0364L 321 0 414254b4 19068 +0364R 322 0 41429f30 183522 +0398L 323 0 41456c14 183522 +0398R 324 0 414838f8 972860 +0399L 325 0 41571134 972860 +0399R 326 0 4165e970 581266 +0401 327 0 416ec804 581266 +0402 328 0 4177a698 1001766 +0403 329 0 4186efc0 10812 +0404 330 0 418719fc 32640 +0405 331 0 4187997c 12211 +0406 332 0 4187c930 17888 +0407 333 0 41880f10 20906 +0408 334 0 418860bc 9094 +0409 335 0 41888444 17100 +0410 336 0 4188c710 18866 +0411 337 0 418910c4 25472 +0412 338 0 41897444 11799 +0413 339 0 4189a25c 23776 +0414 340 0 4189ff3c 21930 +0415 341 0 418a54e8 34399 +0416 342 0 418adb48 39324 +0417 343 0 418b74e4 42410 +0418 344 0 418c1a90 16028 +0419 345 0 418c592c 21677 +0420L 346 0 418caddc 23637 +0420R 347 0 418d0a34 11386 +0421L 348 0 418d36b0 11386 +0421R 349 0 418d632c 8131 +0422L 350 0 418d82f0 8131 +0422R 351 0 418da2b4 9311 +0423L 352 0 418dc714 9311 +0423R 353 0 418deb74 10502 +0424L 354 0 418e147c 10502 +0424R 355 0 418e3d84 14510 +0425L 356 0 418e7634 14510 +0425R 357 0 418eaee4 13276 +0426L 358 0 418ee2c0 13276 +0426R 359 0 418f169c 17687 +0427L 360 0 418f5bb4 17687 +0427R 361 0 418fa0cc 9136 +0428L 362 0 418fc47c 9136 +0428R 363 0 418fe82c 9578 +0429L 364 0 41900d98 9578 +0429R 365 0 41903304 17037 +0430L 366 0 41907594 17037 +0430R 367 0 4190b824 11518 +0431L 368 0 4190e524 11518 +0431R 369 0 41911224 10483 +0432L 370 0 41913b18 10483 +0432R 371 0 4191640c 14786 +0433L 372 0 41919dd0 14786 +0433R 373 0 4191d794 22163 +0434L 374 0 41922e28 22163 +0434R 375 0 419284bc 20381 +0435L 376 0 4192d45c 20381 +0435R 377 0 419323fc 19231 +0436L 378 0 41936f1c 19231 +0436R 379 0 4193ba3c 12934 +0437L 380 0 4193ecc4 12934 +0437R 381 0 41941f4c 8432 +0438L 382 0 4194403c 8432 +0438R 383 0 4194612c 21332 +0439L 384 0 4194b480 21332 +0439R 385 0 419507d4 12295 +0440L 386 0 419537dc 12295 +0440R 387 0 419567e4 16010 +0441L 388 0 4195a670 16010 +0441R 389 0 4195e4fc 17893 +0442L 390 0 41962ae4 17893 +0442R 391 0 419670cc 10917 +0443L 392 0 41969b74 10917 +0443R 393 0 4196c61c 9560 +0444L 394 0 4196eb74 9560 +0444R 395 0 419710cc 15203 +0445L 396 0 41974c30 15203 +0445R 397 0 41978794 24724 +0446L 398 0 4197e828 24724 +0446R 399 0 419848bc 20384 +0447L 400 0 4198985c 20384 +0447R 401 0 4198e7fc 10214 +0448L 402 0 41990fe4 10214 +0448R 403 0 419937cc 16367 +0449L 404 0 419977bc 16367 +0449R 405 0 4199b7ac 25891 +0450L 406 0 419a1cd0 25891 +0450R 407 0 419a81f4 27610 +0451L 408 0 419aedd0 27610 +0451R 409 0 419b59ac 10204 +0452L 410 0 419b8188 10204 +0452R 411 0 419ba964 23686 +0453L 412 0 419c05ec 23686 +0453R 413 0 419c6274 15286 +0454L 414 0 419c9e2c 15286 +0454R 415 0 419cd9e4 30948 +0455L 416 0 419d52c8 30948 +0455R 417 0 419dcbac 22895 +0456L 418 0 419e251c 22895 +0456R 419 0 419e7e8c 23864 +0457L 420 0 419edbc4 23864 +0457R 421 0 419f38fc 18500 +0458L 422 0 419f8140 18500 +0458R 423 0 419fc984 25748 +0459L 424 0 41a02e18 25748 +0459R 425 0 41a092ac 15614 +0460L 426 0 41a0cfac 15614 +0460R 427 0 41a10cac 28422 +0461L 428 0 41a17bb4 28422 +0461R 429 0 41a1eabc 31965 +0462L 430 0 41a2679c 31965 +0462R 431 0 41a2e47c 16885 +0463L 432 0 41a32674 16885 +0463R 433 0 41a3686c 47013 +0464L 434 0 41a42014 47013 +0464R 435 0 41a4d7bc 16440 +0465L 436 0 41a517f4 16440 +0465R 437 0 41a5582c 17767 +0466L 438 0 41a59d94 17767 +0466R 439 0 41a5e2fc 26783 +0467L 440 0 41a64b9c 26783 +0467R 441 0 41a6b43c 27442 +0468L 442 0 41a71f70 27442 +0468R 443 0 41a78aa4 20384 +0469L 444 0 41a7da44 20384 +0469R 445 0 41a829e4 16026 +0470L 446 0 41a86880 16026 +0470R 447 0 41a8a71c 14351 +0471L 448 0 41a8df2c 14351 +0471R 449 0 41a9173c 19980 +0472L 450 0 41a96548 19980 +0472R 451 0 41a9b354 31226 +0473L 452 0 41aa2d50 31226 +0473R 453 0 41aaa74c 26982 +0474L 454 0 41ab10b4 26982 +0474R 455 0 41ab7a1c 32544 +0475L 456 0 41abf93c 32544 +0475R 457 0 41ac785c 33387 +0476L 458 0 41acfac8 33387 +0476R 459 0 41ad7d34 18807 +0477L 460 0 41adc6ac 18807 +0477R 461 0 41ae1024 26851 +0478L 462 0 41ae7908 26851 +0478R 463 0 41aee1ec 15645 +0479L 464 0 41af1f0c 15645 +0479R 465 0 41af5c2c 19476 +0481 466 0 41afa840 19476 +0482 467 0 41aff454 56298 +0483 468 0 41b0d040 172587 +0485L 469 0 41b3726c 61067 +0485R 470 0 41b460f8 237560 +0486L 471 0 41b800f0 237560 +0486R 472 0 41bba0e8 23423 +0487L 473 0 41bbfc68 23423 +0487R 474 0 41bc57e8 31476 +0488L 475 0 41bcd2dc 31476 +0488R 476 0 41bd4dd0 54989 +0489L 477 0 41be24a0 54989 +0489R 478 0 41befb70 50591 +0490L 479 0 41bfc110 50591 +0490R 480 0 41c086b0 23610 +0491L 481 0 41c0e2ec 23610 +0491R 482 0 41c13f28 29578 +0492L 483 0 41c1b2b4 29578 +0492R 484 0 41c22640 985152 +0493L 485 0 41d12e80 985152 +0493R 486 0 41e036c0 265146 +0494L 487 0 41e4427c 265146 +0494R 488 0 41e84e38 985152 +0495L 489 0 41f75678 985152 +0495R 490 0 42065eb8 88854 +0496L 491 0 4207b9d0 88854 +0496R 492 0 420914e8 100800 +0497L 493 0 420a9ea8 100800 +0497R 494 0 420c2868 69309 +0498L 495 0 420d3728 69309 +0498R 496 0 420e45e8 81798 +0499L 497 0 420f8570 81798 +0499R 498 0 4210c4f8 120578 +0500 499 0 42129bfc 120578 +0501 500 0 42147300 58672 +0502 501 0 42155830 58151 +0503 502 0 42163b58 58672 +0504 503 0 42172088 58151 +0505 504 0 421803b0 58151 +0506 505 0 4218e6d8 15443 +0507 506 0 4219232c 15682 +0508 507 0 42196070 13181 +0509 508 0 421993f0 92506 +0510 509 0 421afd4c 72343 +0511 510 0 421c17e4 96814 +0512 511 0 421d9214 92506 +0513 512 0 421efb70 72343 +0514 513 0 42201608 96814 +3000 514 0 42219038 6255 +3001 515 0 4221a8a8 47346 +3002 516 0 4222619c 39570 +3003 517 0 4222fc30 49178 +3004 518 0 4223bc4c 35975 +3005 519 0 422448d4 43831 +3006 520 0 4224f40c 71614 +3007 521 0 42260bcc 85710 +3008 522 0 42275a9c 62590 +3009 523 0 42284f1c 92310 +3010 524 0 4229b7b4 46668 +3011 525 0 422a6e00 45935 +3012 526 0 422b2170 48613 +3013 527 0 422bdf58 102390 +3014 528 0 422d6f50 58677 +3015 529 0 422e5488 59019 +3016 530 0 422f3b14 82221 +3017 531 0 42307c44 67316 +3018 532 0 42318338 73426 +3019 533 0 4232a20c 75043 +3020 534 0 4233c730 69002 +3021 535 0 4234d4bc 70172 +3022 536 0 4235e6d8 51711 +3023 537 0 4236b0d8 59727 +3024 538 0 42379a28 92135 +3025 539 0 42390210 94042 +3026 540 0 423a716c 96240 +3027 541 0 423be95c 107578 +3028 542 0 423d8d98 102533 +3029 543 0 423f1e20 96541 +3030 544 0 42409740 59895 +3031 545 0 42418138 62635 +3032 546 0 424275e4 74283 +3033 547 0 42439810 69892 +3034 548 0 4244a914 62880 +3035 549 0 42459eb4 62752 +3036 550 0 424693d4 72789 +3037 551 0 4247b02c 64782 +3038 552 0 4248ad3c 84140 +3039 553 0 4249f5e8 66904 +3040 554 0 424afb40 68350 +3041 555 0 424c0640 69332 +3042 556 0 424d1514 72782 +3043 557 0 424e3164 64802 +3044 558 0 424f2e88 53655 +3045 559 0 42500020 76360 +3046 560 0 42512a68 78622 +3047 561 0 42525d88 66566 +3048 562 0 42536190 57372 +3049 563 0 425441ac 79499 +3050 564 0 42557838 72911 +3051 565 0 42569508 76807 +3052 566 0 4257c110 87396 +3053 567 0 42591674 98775 +3054 568 0 425a984c 78256 +3055 569 0 425bc9fc 70354 +3056 570 0 425cdcd0 77398 +3057 571 0 425e0b28 68391 +3058 572 0 425f1650 49080 +3059 573 0 425fd608 54448 +3060 574 0 4260aab8 64755 +3061 575 0 4261a7ac 51221 +3062 576 0 42626fc4 50504 +3063 577 0 4263350c 75942 +3064 578 0 42645db4 90654 +3065 579 0 4265bfd4 119691 +3066 580 0 42679360 110942 +3067 581 0 426944c0 106523 +3068 582 0 426ae4dc 108998 +3069 583 0 426c8ea4 114087 +3070 584 0 426e4c4c 100885 +3071 585 0 426fd664 81798 +3072 586 0 427115ec 90015 +3073 587 0 4272758c 132968 +3074 588 0 42747cf4 121743 +3075 589 0 42765884 123368 +3076 590 0 42783a6c 111124 +3077 591 0 4279ec80 115304 +3078 592 0 427baee8 139670 +3079 593 0 427dd080 98205 +3080 594 0 427f5020 84154 +3081 595 0 428098dc 111856 +3082 596 0 42824dcc 94909 +3083 597 0 4283c08c 101383 +3084 598 0 42854c94 71415 +3085 599 0 4286638c 111604 +3086 600 0 42881780 112548 +3087 601 0 4289cf24 113563 +3088 602 0 428b8ac0 94251 +3089 603 0 428cfaec 83218 +3090 604 0 428e4000 96000 +3091 605 0 428fb700 100980 +3092 606 0 42914174 74998 +3093 607 0 4292666c 105563 +3094 608 0 429402c8 71597 +3095 609 0 42951a78 95468 +3096 610 0 42968f64 85367 +3097 611 0 4297dcdc 92598 +3098 612 0 42994694 86228 +3099 613 0 429a9768 102244 +3100 614 0 429c26cc 89059 +3101 615 0 429d82b0 110742 +3102 616 0 429f3348 97402 +3103 617 0 42a0afc4 95935 +3104 618 0 42a22684 103316 +3105 619 0 42a3ba18 105822 +3106 620 0 42a55778 98530 +3107 621 0 42a6d85c 70406 +3108 622 0 42a7eb64 60644 +3109 623 0 42a8d848 40095 +3110 624 0 42a974e8 40014 +3111 625 0 42aa1138 26596 +3112 626 0 42aa791c 41235 +3113 627 0 42ab1a30 41091 +3114 628 0 42abbab4 23310 +3115 629 0 42ac15c4 26011 +3116 630 0 42ac7b60 75950 +3117 631 0 42ada410 72266 +3118 632 0 42aebe5c 98728 +3119 633 0 42b04004 92943 +3120 634 0 42b1ab14 96142 +3121 635 0 42b322a4 77411 +3122 636 0 42b45108 118490 +3123 637 0 42b61fe4 119263 +3124 638 0 42b7f1c4 119507 +3125 639 0 42b9c498 77676 +3126 640 0 42baf404 90588 +3127 641 0 42bc55e0 83250 +3128 642 0 42bd9b14 91583 +3129 643 0 42bf00d4 100991 +3130 644 0 42c08b54 89838 +3131 645 0 42c1ea44 82482 +3132 646 0 42c32c78 83630 +3133 647 0 42c47328 81562 +3134 648 0 42c5b1c4 84604 +3135 649 0 42c6fc40 87533 +3136 650 0 42c85230 102620 +3137 651 0 42c9e30c 96704 +3138 652 0 42cb5ccc 92925 +3139 653 0 42ccc7cc 67520 +3140 654 0 42cdcf8c 29010 +3141 655 0 42ce40e0 22050 +3142 656 0 42ce9704 23066 +3143 657 0 42cef120 48010 +3144 658 0 42cfacac 41578 +3145 659 0 42d04f18 46311 +3146 660 0 42d10400 52527 +3147 661 0 42d1d130 58220 +3148 662 0 42d2b49c 52574 +3149 663 0 42d381fc 56923 +3150 664 0 42d46058 64436 +3151 665 0 42d55c0c 74594 +3152 666 0 42d67f70 73187 +3153 667 0 42d79d54 57523 +3154 668 0 42d87e08 53629 +3155 669 0 42d94f88 46470 +3156 670 0 42da0510 34429 +3157 671 0 42da8b90 88221 +3158 672 0 42dbe430 45333 +3159 673 0 42dc9548 48600 +3160 674 0 42dd5320 43080 +3161 675 0 42ddfb68 51892 +3162 676 0 42dec61c 33995 +3163 677 0 42df4ae8 35046 +3164 678 0 42dfd3d0 41021 +3165 679 0 42e07410 36839 +3166 680 0 42e103f8 41094 +3167 681 0 42e1a480 25608 +3168 682 0 42e20888 33667 +3169 683 0 42e28c0c 30720 +3170 684 0 42e3040c 35995 +3171 685 0 42e390a8 15117 +3172 686 0 42e3cbb8 17134 +3173 687 0 42e40ea8 12547 +3174 688 0 42e43fac 12686 +3175 689 0 42e4713c 15112 +3176 690 0 42e4ac44 17839 +3177 691 0 42e4f1f4 33003 +3178 692 0 42e572e0 39551 +3179 693 0 42e60d60 40045 +3180 694 0 42e6a9d0 45258 +3181 695 0 42e75a9c 40114 +3182 696 0 42e7f750 30764 +3183 697 0 42e86f7c 39723 +3184 698 0 42e90aa8 37359 +3185 699 0 42e99c98 41071 +3186 700 0 42ea3d08 31933 +3187 701 0 42eab9c8 67868 +3188 702 0 42ebc2e4 32178 +3189 703 0 42ec4098 26963 +3190 704 0 42eca9ec 36096 +3191 705 0 42ed36ec 43629 +3192 706 0 42ede15c 13658 +3193 707 0 42ee16b8 15290 +3194 708 0 42ee5274 9093 +3195 709 0 42ee75fc 9358 +3196 710 0 42ee9a8c 44852 +3197 711 0 42ef49c0 33726 +3198 712 0 42efcd80 24092 +3199 713 0 42f02b9c 33565 +3200 714 0 42f0aebc 6188 +3201 715 0 42f0c6e8 29511 +3202 716 0 42f13a30 42866 +3203 717 0 42f1e1a4 5554 +3204 718 0 42f1f758 32528 +3205 719 0 42f27668 32858 +3206 720 0 42f2f6c4 7109 +3207 721 0 42f3128c 20758 +3208 722 0 42f363a4 8058 +3209 723 0 42f38320 20707 +3210 724 0 42f3d404 33955 +3211 725 0 42f458a8 7733 +3212 726 0 42f476e0 18044 +3213 727 0 42f4bd5c 6282 +3214 728 0 42f4d5e8 11710 +3215 729 0 42f503a8 9632 +3216 730 0 42f52948 34410 +3217 731 0 42f5afb4 35530 +3218 732 0 42f63a80 15846 +3219 733 0 42f67868 65007 +3220 734 0 42f77658 24829 +3221 735 0 42f7d758 7424 +3222 736 0 42f7f458 21013 +3223 737 0 42f84670 7926 +3224 738 0 42f86568 9866 +3225 739 0 42f88bf4 21748 +3226 740 0 42f8e0e8 9384 +3227 741 0 42f90590 9468 +3228 742 0 42f92a8c 11701 +3229 743 0 42f95844 8749 +3230 744 0 42f97a74 11090 +3231 745 0 42f9a5c8 5472 +3232 746 0 42f9bb28 6178 +3233 747 0 42f9d34c 6624 +3234 748 0 42f9ed2c 8328 +3235 749 0 42fa0db4 12620 +3236 750 0 42fa3f00 13428 +3237 751 0 42fa7374 10258 +3238 752 0 42fa9b88 13259 +3239 753 0 42facf54 11614 +3240 754 0 42fafcb4 9418 +3241 755 0 42fb2180 14768 +3242 756 0 42fb5b30 16463 +3243 757 0 42fb9b80 22076 +3244 758 0 42fbf1bc 14925 +3245 759 0 42fc2c0c 20047 +3246 760 0 42fc7a5c 13459 +3247 761 0 42fcaef0 13158 +3248 762 0 42fce258 11423 +3249 763 0 42fd0ef8 21738 +3250 764 0 42fd63e4 11294 +3251 765 0 42fd9004 8934 +3252 766 0 42fdb2ec 12795 +3253 767 0 42fde4e8 7395 +3254 768 0 42fe01cc 21603 +3255 769 0 42fe5630 19549 +3256 770 0 42fea290 21610 +3257 771 0 42fef6fc 16669 +3258 772 0 42ff381c 13047 +3259 773 0 42ff6b14 12845 +3260 774 0 42ff9d44 23829 +3261 775 0 42fffa5c 20918 +3262 776 0 43004c14 21432 +3263 777 0 43009fcc 21967 +3264 778 0 4300f59c 20212 +3265 779 0 43014490 22378 +3266 780 0 43019bfc 27784 +3267 781 0 43020884 12669 +3268 782 0 43023a04 21645 +3269 783 0 43028e94 14387 +3270 784 0 4302c6c8 15568 +3271 785 0 43030398 12144 +3272 786 0 43033308 12699 +3273 787 0 430364a4 21978 +3274 788 0 4303ba80 22796 +3275 789 0 4304138c 15912 +3276 790 0 430451b4 21664 +3277 791 0 4304a654 16158 +3278 792 0 4304e574 20979 +3279 793 0 43053768 11879 +3280 794 0 430565d0 25287 +3281 795 0 4305c898 40155 +3282 796 0 43066574 29647 +3283 797 0 4306d944 29320 +3284 798 0 43074bcc 22733 +3285 799 0 4307a49c 13883 +3286 800 0 4307dad8 12560 +3287 801 0 43080be8 14559 +3288 802 0 430844c8 12821 +3289 803 0 430876e0 10900 +3290 804 0 4308a174 14669 +3291 805 0 4308dac4 12062 +3292 806 0 430909e4 59622 +3293 807 0 4309f2cc 39031 +3294 808 0 430a8b44 62318 +3295 809 0 430b7eb4 52256 +3296 810 0 430c4ad4 47055 +3297 811 0 430d02a4 45757 +3298 812 0 430db564 46331 +3299 813 0 430e6a60 70203 +3300 814 0 430f7c9c 35140 +3301 815 0 431005e0 41468 +3302 816 0 4310a7dc 52544 +3303 817 0 4311751c 62187 +3304 818 0 43126808 7676 +3305 819 0 43128604 17020 +3306 820 0 4312c880 18666 +3307 821 0 4313116c 10236 +3308 822 0 43133968 8203 +3309 823 0 43135974 13031 +3310 824 0 43138c5c 41125 +3311 825 0 43142d04 83491 +3312 826 0 43157328 39879 +3313 827 0 43160ef0 55247 +3314 828 0 4316e6c0 50387 +3315 829 0 4317ab94 57571 +3316 830 0 43188c78 55470 +3317 831 0 43196528 53728 +3318 832 0 431a3708 47314 +3319 833 0 431aefdc 91907 +3320 834 0 431c56e0 72948 +3321 835 0 431d73d4 50725 +3322 836 0 431e39fc 75098 +3323 837 0 431f5f58 64383 +3324 838 0 43205ad8 67826 +3325 839 0 432163cc 62984 +3326 840 0 432259d4 41064 +3327 841 0 4322fa3c 13406 +3328 842 0 43232e9c 13206 +3329 843 0 43236234 9194 +3330 844 0 43238620 10164 +3331 845 0 4323add4 53589 +3332 846 0 43247f2c 37253 +3333 847 0 432510b4 24259 +3334 848 0 43256f78 34414 +3335 849 0 4325f5e8 10416 +3336 850 0 43261e98 24522 +3337 851 0 43267e64 30023 +3338 852 0 4326f3ac 7420 +3339 853 0 432710a8 32472 +3340 854 0 43278f80 32678 +3341 855 0 43280f28 11432 +3342 856 0 43283bd0 18740 +3343 857 0 43288504 10203 +3344 858 0 4328ace0 24314 +3345 859 0 43290bdc 34874 +3346 860 0 43299418 6741 +3347 861 0 4329ae70 22839 +3348 862 0 432a07a8 8799 +3349 863 0 432a2a08 17312 +3350 864 0 432a6da8 10436 +3351 865 0 432a966c 36970 +3352 866 0 432b26d8 33677 +3353 867 0 432baa68 10189 +3354 868 0 432bd238 117612 +3355 869 0 432d9da4 36818 +3356 870 0 432e2d78 15780 +3357 871 0 432e6b1c 19907 +3358 872 0 432eb8e0 19804 +3359 873 0 432f063c 26196 +3360 874 0 432f6c90 29898 +3361 875 0 432fe15c 16118 +3362 876 0 43302054 6183 +3363 877 0 4330387c 8490 +3364 878 0 433059a8 8147 +3365 879 0 4330797c 10967 +3366 880 0 4330a454 14795 +3367 881 0 4330de20 7554 +3368 882 0 4330fba4 10739 +3369 883 0 43312598 7754 +3370 884 0 433143e4 11574 +3371 885 0 4331711c 10886 +3372 886 0 43319ba4 8380 +3373 887 0 4331bc60 11879 +3374 888 0 4331eac8 11159 +3375 889 0 43321660 10140 +3376 890 0 43323dfc 14299 +3377 891 0 433275d8 15933 +3378 892 0 4332b418 20747 +3379 893 0 43330524 15820 +3380 894 0 433342f0 18887 +3381 895 0 43338cb8 14642 +3382 896 0 4333c5ec 12828 +3383 897 0 4333f808 13718 +3384 898 0 43342da0 21206 +3385 899 0 43348078 11883 +3386 900 0 4334aee4 9213 +3387 901 0 4334d2e4 9518 +3388 902 0 4334f814 9199 +3389 903 0 43351c04 18235 +3390 904 0 43356340 16310 +3391 905 0 4335a2f8 18032 +3392 906 0 4335e968 20741 +3393 907 0 43363a70 19151 +3394 908 0 43368540 19187 +3395 909 0 4336d034 56447 +3396 910 0 4337acb4 34807 +3397 911 0 433834ac 32307 +3398 912 0 4338b2e0 22388 +3399 913 0 43390a54 54485 +3400 914 0 4339df2c 26428 +3401 915 0 433a4668 56668 +3402 916 0 433b23c4 16231 +3403 917 0 433b632c 11990 +3404 918 0 433b9204 12366 +3405 919 0 433bc254 17319 +3406 920 0 433c05fc 14808 +3407 921 0 433c3fd4 14967 +3408 922 0 433c7a4c 27172 +3409 923 0 433ce470 36864 +3410 924 0 433d7470 17511 +3411 925 0 433db8d8 18428 +3412 926 0 433e00d4 8383 +3413 927 0 433e2194 23430 +3414 928 0 433e7d1c 21883 +3415 929 0 433ed298 18430 +3416 930 0 433f1a98 17286 +3417 931 0 433f5e20 17823 +3418 932 0 433fa3c0 19071 +3419 933 0 433fee40 15940 +3420 934 0 43402c84 11560 +3421 935 0 434059ac 14646 +3422 936 0 434092e4 10420 +3423 937 0 4340bb98 14367 +3424 938 0 4340f3b8 11116 +3425 939 0 43411f24 57111 +3426 940 0 4341fe3c 39959 +3427 941 0 43429a54 34163 +3428 942 0 43431fc8 49202 +3429 943 0 4343dffc 36354 +3430 944 0 43446e00 33583 +3431 945 0 4344f130 35661 +3432 946 0 43457c80 56604 +3433 947 0 4346599c 45654 +3434 948 0 43470bf4 34602 +3435 949 0 43479320 29148 +3436 950 0 434804fc 49291 +3437 951 0 4348c588 50051 +3438 952 0 4349890c 12674 +3439 953 0 4349ba90 14398 +3440 954 0 4349f2d0 8387 +3441 955 0 434a1394 11647 +3442 956 0 434a4114 16108 +3443 957 0 434a8000 18901 +3444 958 0 434ac9d8 64472 +3445 959 0 434bc5b0 60538 +3446 960 0 434cb22c 34847 +3447 961 0 434d3a4c 34312 +3448 962 0 434dc054 40227 +3449 963 0 434e5d78 30251 +3450 964 0 434ed3a4 39325 +3451 965 0 434f6d44 36488 +3452 966 0 434ffbcc 39480 +3453 967 0 43509604 72782 +3454 968 0 4351b254 36362 +3455 969 0 43524060 29427 +3456 970 0 4352b354 35286 +3457 971 0 43533d2c 63693 +3458 972 0 435435fc 37359 +3459 973 0 4354c7ec 13525 +3460 974 0 4354fcc4 12530 +3461 975 0 43552db8 8138 +3462 976 0 43554d84 7922 +3463 977 0 43556c78 55108 +3464 978 0 435643bc 29747 +3465 979 0 4356b7f0 26822 +3466 980 0 435720b8 34880 +3467 981 0 4357a8f8 6994 +3468 982 0 4357c44c 34466 +3469 983 0 43584af0 33847 +3470 984 0 4358cf28 6307 +3471 985 0 4358e7cc 35586 +3472 986 0 435972d0 8752 +3473 987 0 43599500 8728 +3474 988 0 4359b718 16327 +3475 989 0 4359f6e0 11912 +3476 990 0 435a2568 33940 +3477 991 0 435aa9fc 29037 +3478 992 0 435b1b6c 14383 +3479 993 0 435b539c 12012 +3480 994 0 435b8288 14327 +3481 995 0 435bba80 12827 +3482 996 0 435bec9c 11772 +3483 997 0 435c1a98 35351 +3484 998 0 435ca4b0 34182 +3485 999 0 435d2a38 9469 +3486 1000 0 435d4f38 145452 +3487 1001 0 435f8764 32087 +3488 1002 0 436004bc 25294 +3489 1003 0 4360678c 39789 +3490 1004 0 436102fc 22067 +3491 1005 0 43615930 48699 +3492 1006 0 4362176c 29554 +3493 1007 0 43628ae0 23139 +3494 1008 0 4362e544 8077 +3495 1009 0 436304d4 9864 +3496 1010 0 43632b5c 9019 +3497 1011 0 43634e98 9756 +3498 1012 0 436374b4 7328 +3499 1013 0 43639154 8650 +3500 1014 0 4363b320 14189 +3501 1015 0 4363ea90 6293 +3502 1016 0 43640328 12501 +3503 1017 0 43643400 11667 +3504 1018 0 43646194 11056 +3505 1019 0 43648cc4 11773 +3506 1020 0 4364bac4 13567 +3507 1021 0 4364efc4 10844 +3508 1022 0 43651a20 16496 +3509 1023 0 43655a90 17957 +3510 1024 0 4365a0b8 18894 +3511 1025 0 4365ea88 18292 +3512 1026 0 436631fc 19290 +3513 1027 0 43667d58 14381 +3514 1028 0 4366b588 16858 +3515 1029 0 4366f764 14662 +3516 1030 0 436730ac 19621 +3517 1031 0 43677d54 12599 +3518 1032 0 4367ae8c 9902 +3519 1033 0 4367d53c 8430 +3520 1034 0 4367f62c 7979 +3521 1035 0 43681558 16796 +3522 1036 0 436856f4 14398 +3523 1037 0 43688f34 14482 +3524 1038 0 4368c7c8 15807 +3525 1039 0 43690588 30403 +3526 1040 0 43697c4c 33424 +3527 1041 0 4369fedc 26765 +3528 1042 0 436a676c 44404 +3529 1043 0 436b14e0 30888 +3530 1044 0 436b8d88 24060 +3531 1045 0 436beb84 26879 +3532 1046 0 436c5484 10739 +3533 1047 0 436c7e78 17816 +3534 1048 0 436cc410 11542 +3535 1049 0 436cf128 13982 +3536 1050 0 436d27c8 15480 +3537 1051 0 436d6440 24114 +3538 1052 0 436dc274 11930 +3539 1053 0 436df110 14268 +3540 1054 0 436e28cc 16767 +3541 1055 0 436e6a4c 22935 +3542 1056 0 436ec3e4 16399 +3543 1057 0 436f03f4 18885 +3544 1058 0 436f4dbc 9770 +3545 1059 0 436f73e8 23253 +3546 1060 0 436fcec0 29816 +3547 1061 0 43704338 26156 +3548 1062 0 4370a964 43140 +3549 1063 0 437151e8 26064 +3550 1064 0 4371b7b8 20179 +3551 1065 0 4372068c 12496 +3552 1066 0 4372375c 15306 +3553 1067 0 43727328 16248 +3554 1068 0 4372b2a0 10571 +3555 1069 0 4372dbec 14392 +3556 1070 0 43731424 11330 +3557 1071 0 43734068 51784 +3558 1072 0 43740ab0 52477 +3559 1073 0 4374d7b0 50395 +3560 1074 0 43759c8c 41962 +3561 1075 0 43764078 34605 +3562 1076 0 4376c7a8 46464 +3563 1077 0 43777d28 45098 +3564 1078 0 43782d54 36435 +3565 1079 0 4378bba8 19403 +3566 1080 0 43790774 41600 +3567 1081 0 4379a9f4 46066 +3568 1082 0 437a5de8 42587 +3569 1083 0 437b0444 11447 +3570 1084 0 437b30fc 10485 +3571 1085 0 437b59f4 14104 +3572 1086 0 437b910c 9948 +3573 1087 0 437bb7e8 20876 +3574 1088 0 437c0974 68399 +3575 1089 0 437d14a4 37752 +3576 1090 0 437da81c 48061 +3577 1091 0 437e63dc 38304 +3578 1092 0 437ef97c 53918 +3579 1093 0 437fcc1c 55182 +3580 1094 0 4380a3ac 43284 +3581 1095 0 43814cc0 64166 +3582 1096 0 43824768 58655 +3583 1097 0 43832c88 71051 +3584 1098 0 43844214 39580 +3585 1099 0 4384dcb0 76024 +3586 1100 0 438605a8 44792 +3587 1101 0 4386b4a0 34429 +3588 1102 0 43873b20 48979 +3589 1103 0 4387fa74 11295 +3590 1104 0 43882694 13584 +3591 1105 0 43885ba4 7804 +3592 1106 0 43887a20 7228 +3593 1107 0 4388965c 56183 +3594 1108 0 438971d4 25742 +3595 1109 0 4389d664 31941 +3596 1110 0 438a532c 40539 +3597 1111 0 438af188 6144 +3598 1112 0 438b0988 26237 +3599 1113 0 438b7008 32525 +3600 1114 0 438bef18 3965 +3601 1115 0 438bfe98 35378 +3602 1116 0 438c88cc 39836 +3603 1117 0 438d2468 9706 +3604 1118 0 438d4a54 17855 +3605 1119 0 438d9014 9987 +3606 1120 0 438db718 15922 +3607 1121 0 438df54c 38920 +3608 1122 0 438e8d54 51370 +3609 1123 0 438f5600 6922 +3610 1124 0 438f710c 80212 +3611 1125 0 4390aa60 9988 +3612 1126 0 4390d164 14552 +3613 1127 0 43910a3c 48600 +3614 1128 0 4391c814 42222 +3615 1129 0 43926d04 11492 +3616 1130 0 439299e8 138899 +3617 1131 0 4394b87c 45256 +3618 1132 0 43956944 15382 +3619 1133 0 4395a55c 39415 +3620 1134 0 43963f54 7414 +3621 1135 0 43965c4c 30807 +3622 1136 0 4396d4a4 13306 +3623 1137 0 439708a0 13180 +3624 1138 0 43973c1c 5787 +3625 1139 0 439752b8 8666 +3626 1140 0 43977494 8491 +3627 1141 0 439795c0 9435 +3628 1142 0 4397ba9c 5292 +3629 1143 0 4397cf48 6134 +3630 1144 0 4397e740 7342 +3631 1145 0 439803f0 6170 +3632 1146 0 43981c0c 12208 +3633 1147 0 43984bbc 10300 +3634 1148 0 439873f8 13925 +3635 1149 0 4398aa60 13339 +3636 1150 0 4398de7c 10506 +3637 1151 0 43990788 8899 +3638 1152 0 43992a4c 18334 +3639 1153 0 439971ec 16075 +3640 1154 0 4399b0b8 18902 +3641 1155 0 4399fa90 15957 +3642 1156 0 439a38e8 20510 +3643 1157 0 439a8908 12490 +3644 1158 0 439ab9d4 15261 +3645 1159 0 439af574 11461 +3646 1160 0 439b223c 18624 +3647 1161 0 439b6afc 11022 +3648 1162 0 439b960c 9571 +3649 1163 0 439bbb70 11827 +3650 1164 0 439be9a4 8005 +3651 1165 0 439c08ec 15004 +3652 1166 0 439c4388 14206 +3653 1167 0 439c7b08 13218 +3654 1168 0 439caeac 15900 +3655 1169 0 439cecc8 12411 +3656 1170 0 439d1d44 14412 +3657 1171 0 439d5590 17628 +3658 1172 0 439d9a6c 35208 +3659 1173 0 439e23f4 24100 +3660 1174 0 439e8218 24356 +3661 1175 0 439ee13c 14334 +3662 1176 0 439f193c 22653 +3663 1177 0 439f71bc 17064 +3664 1178 0 439fb464 17415 +3665 1179 0 439ff86c 12591 +3666 1180 0 43a0299c 16871 +3667 1181 0 43a06b84 16656 +3668 1182 0 43a0ac94 20183 +3669 1183 0 43a0fb6c 16317 +3670 1184 0 43a13b2c 18915 +3671 1185 0 43a18510 24264 +3672 1186 0 43a1e3d8 21983 +3673 1187 0 43a239b8 13016 +3674 1188 0 43a26c90 21432 +3675 1189 0 43a2c048 11096 +3676 1190 0 43a2eba0 25312 +3677 1191 0 43a34e80 13478 +3678 1192 0 43a38328 17196 +3679 1193 0 43a3c654 13839 +3680 1194 0 43a3fc64 17877 +3681 1195 0 43a4423c 12367 +3682 1196 0 43a4728c 10214 +3683 1197 0 43a49a74 14210 +3684 1198 0 43a4d1f8 11368 +3685 1199 0 43a4fe60 15774 +3686 1200 0 43a53c00 14701 +3687 1201 0 43a57570 11141 +5007 1202 0 43a5a0f8 46477 +5012 1203 0 43a65688 640047 +5013 1204 0 43b01ab8 23575 +5014 1205 0 43b076d0 20695 +5015 1206 0 43b0c7a8 20215 +5016 1207 0 43b116a0 38310 +5017 1208 0 43b1ac48 34419 +5018 1209 0 43b232bc 159757 +5019 1210 0 43b4a2cc 52030 +5020 1211 0 43b56e0c 9391 +5021 1212 0 43b592bc 8402 +5022 1213 0 43b5b390 22550 +5023 1214 0 43b60ba8 32140 +5024 1215 0 43b68934 14916 +5025 1216 0 43b6c378 80836 +5026 1217 0 43b7ff3c 108395 +5027 1218 0 43b9a6a8 36101 +5028 1219 0 43ba33b0 26803 +5029 1220 0 43ba9c64 39000 +5030 1221 0 43bb34bc 44566 +5031 1222 0 43bbe2d4 48923 +5032 1223 0 43bca1f0 71959 +5033 1224 0 43bdbb08 71640 +5034 1225 0 43bed2e0 30422 +5035 1226 0 43bf49b8 148274 +5036 1227 0 43c18cec 67780 +5037 1228 0 43c295b0 20662 +5038 1229 0 43c2e668 16238 +5039 1230 0 43c325d8 105980 +5040 1231 0 43c4c3d4 13413 +5041 1232 0 43c4f83c 23038 +5042 1233 0 43c5523c 30671 +5043 1234 0 43c5ca0c 15644 +5044 1235 0 43c60728 32135 +5045 1236 0 43c684b0 40408 +5046 1237 0 43c72288 64462 +5047 1238 0 43c81e58 36012 +5048 1239 0 43c8ab04 100327 +5049 1240 0 43ca32ec 124575 +5050 1241 0 43cc198c 118612 +5051 1242 0 43cde8e0 91659 +5052 1243 0 43cf4eec 56183 +5053 1244 0 43d02a64 74730 +5054 1245 0 43d14e50 100022 +5055 1246 0 43d2d508 97661 +5056 1247 0 43d45288 154875 +5057 1248 0 43d6af84 28372 +5058 1249 0 43d71e58 84919 +5059 1250 0 43d86a10 78912 +5060 1251 0 43d99e50 61212 +5061 1252 0 43da8d6c 184423 +5062 1253 0 43dd5dd4 38390 +5074 1254 0 43ddf3cc 52208 +5075 1255 0 43debfbc 15956 +5076 1256 0 43defe10 19190 +5077 1257 0 43df4908 25990 +5078 1258 0 43dfae90 10427 +5079 1259 0 43dfd74c 23940 +5080L 1260 0 43e034d0 69970 +5080R 1261 0 43e14624 87775 +5081L 1262 0 43e29d04 87775 +5081R 1263 0 43e3f3e4 87775 +5083 1264 0 43e54ac4 87775 +5084 1265 0 43e6a1a4 97204 +5085 1266 0 43e81d58 36141 +5086 1267 0 43e8aa88 31888 +5087 1268 0 43e92718 44632 +5088 1269 0 43e9d570 13856 +5089 1270 0 43ea0b90 61796 +5090 1271 0 43eafcf4 58118 +5091L 1272 0 43ebdffc 46763 +5091R 1273 0 43ec96a8 59327 +5092 1274 0 43ed7e68 59327 +5093 1275 0 43ee6628 13736 +5094 1276 0 43ee9bd0 14581 +5095 1277 0 43eed4c8 9974 +5096 1278 0 43eefbc0 9102 +5097 1279 0 43ef1f50 18036 +5098 1280 0 43ef65c4 13923 +5099 1281 0 43ef9c28 50204 +5100 1282 0 43f06044 61390 +5101 1283 0 43f15014 61842 +5102 1284 0 43f241a8 40950 +5103 1285 0 43f2e1a0 56283 +5104 1286 0 43f3bd7c 170942 +5105 1287 0 43f6593c 266150 +5106 1288 0 43fa68e4 10870 +5107 1289 0 43fa935c 10048 +5108 1290 0 43faba9c 7964 +5109 1291 0 43fad9b8 18295 +5110 1292 0 43fb2130 16221 +5111 1293 0 43fb6090 14450 +5112 1294 0 43fb9904 176608 +5113 1295 0 43fe4ae4 90615 +5114 1296 0 43ffacdc 57728 +5115 1297 0 44008e5c 375564 +5116 1298 0 44064968 338599 +5121 1299 0 440b7410 494404 +5122 1300 0 4412ff54 124874 +5123 1301 0 4414e720 380559 +5124 1302 0 441ab5b0 32339 +5125 1303 0 441b3404 21976 +5126 1304 0 441b89dc 59128 +5127 1305 0 441c70d4 56560 +5128 1306 0 441d4dc4 63612 +5129 1307 0 441e4640 61458 +5130 1308 0 441f3654 26480 +5131 1309 0 441f9dc4 40579 +5132 1310 0 44203c48 34483 +5133 1311 0 4420c2fc 27914 +5134 1312 0 44213008 80915 +5135 1313 0 44226c1c 27778 +5136 1314 0 4422d8a0 24514 +5137 1315 0 44233864 26959 +5138 1316 0 4423a1b4 59653 +5143 1317 0 44248abc 63530 +5144 1318 0 442582e8 376884 +5156 1319 0 442b431c 64926 +5161 1320 0 442c40bc 214674 +5162 1321 0 442f8750 40091 +5165 1322 0 443023ec 58147 +5166 1323 0 44310710 140955 +5167 1324 0 44332dac 125652 +5168 1325 0 44351880 106892 +5169 1326 0 4436ba0c 118386 +5170 1327 0 44388880 82543 +5172 1328 0 4439caf0 49719 +5173 1329 0 443a8d28 43936 +5174 1330 0 443b38c8 29181 +5175 1331 0 443baac8 101018 +5176 1332 0 443d3564 6538 +5177 1333 0 443d4ef0 23184 +5178 1334 0 443da980 13551 +5179 1335 0 443dde70 60004 +5180 1336 0 443ec8d4 44700 +5181 1337 0 443f7770 48951 +5191 1338 0 444036a8 11506 +5192 1339 0 4440639c 7706 +5193 1340 0 444081b8 11096 +5194 1341 0 4440ad10 37380 +5195 1342 0 44413f14 55746 +5197 1343 0 444218d8 77903 +5198 1344 0 44434928 38734 +5199 1345 0 4443e078 8333 +5200 1346 0 44440108 7554 +5201 1347 0 44441e8c 10492 +5202 1348 0 44444788 27011 +5204 1349 0 4444b10c 10659 +5205 1350 0 4444dab0 52786 +5206 1351 0 4445a8e4 25021 +5207 1352 0 44460aa4 27444 +5208 1353 0 444675d8 24988 +5209 1354 0 4446d774 46802 +5210 1355 0 44478e48 15846 +5211 1356 0 4447cc30 31264 +5212 1357 0 44484650 71885 +5213 1358 0 44495f20 17558 +5214 1359 0 4449a3b8 27850 +5215 1360 0 444a1084 19596 +5220 1361 0 444a5d10 74480 +5239 1362 0 444b8000 29132 +5240 1363 0 444bf1cc 31688 +5241 1364 0 444c6d94 43635 +5244 1365 0 444d1808 17404 +5245 1366 0 444d5c04 24630 +5246 1367 0 444dbc3c 84140 +5247 1368 0 444f04e8 101602 +5248 1369 0 445091cc 131893 +5249 1370 0 44529504 33613 +5250 1371 0 44531854 49840 +5251 1372 0 4453db04 40990 +5252 1373 0 44547b24 25267 +5253 1374 0 4454ddd8 19190 +5254 1375 0 445528d0 36738 +5255 1376 0 4455b854 11302 +5256 1377 0 4455e47c 40141 +5257 1378 0 4456814c 15170 +5258 1379 0 4456bc90 28538 +5259 1380 0 44572c0c 9272 +5260 1381 0 44575044 54757 +5261 1382 0 4458262c 35710 +5262 1383 0 4458b1ac 13126 +5263 1384 0 4458e4f4 13126 +5264 1385 0 4459183c 11555 +5265 1386 0 44594560 32724 +5266 1387 0 4459c534 36280 +5267 1388 0 445a52ec 24590 +5268 1389 0 445ab2fc 21784 +5269 1390 0 445b0814 16456 +5270 1391 0 445b485c 23920 +5271 1392 0 445ba5cc 30582 +5272 1393 0 445c1d44 13764 +5273 1394 0 445c5308 12589 +5274 1395 0 445c8438 27589 +5275 1396 0 445cf000 24279 +5276 1397 0 445d4ed8 21253 +5277 1398 0 445da1e0 30780 +5278 1399 0 445e1a1c 26972 +5279 1400 0 445e8378 64502 +5280 1401 0 445f7f70 11309 +5281 1402 0 445faba0 12861 +5282 1403 0 445fdde0 22560 +5283 1404 0 44603600 25128 +5284 1405 0 44609828 39074 +5285 1406 0 446130cc 36087 +5286 1407 0 4461bdc4 10267 +5287 1408 0 4461e5e0 11787 +5288 1409 0 446213ec 14904 +5289 1410 0 44624e24 65079 +5290 1411 0 44634c5c 13956 +5291 1412 0 446382e0 23158 +5292 1413 0 4463dd58 16988 +5293 1414 0 44641fb4 11056 +5294 1415 0 44644ae4 38181 +5295 1416 0 4464e00c 23662 +5296 1417 0 44653c7c 18461 +5297 1418 0 4465849c 18594 +5298 1419 0 4465cd40 20557 +5299 1420 0 44661d90 44679 +5300 1421 0 4466cc18 16922 +5301 1422 0 44670e34 36559 +5302 1423 0 44679d04 886966 +5303 1424 0 447525bc 713058 +5312 1425 0 44800720 330072 +5313 1426 0 44851078 28551 +5314 1427 0 44858000 15754 +5315 1428 0 4485bd8c 30034 +5316 1429 0 448632e0 24365 +5317 1430 0 44869210 35683 +5318 1431 0 44871d74 60602 +5319 1432 0 44880a30 28903 +5320 1433 0 44887b18 20093 +5321 1434 0 4488c998 14427 +5322 1435 0 448901f4 14847 +5323 1436 0 44893bf4 23082 +5324 1437 0 44899620 24086 +5325 1438 0 4489f438 33534 +5326 1439 0 448a7738 21976 +5327 1440 0 448acd10 22142 +5328 1441 0 448b2390 27669 +5329 1442 0 448b8fa8 19797 +5330 1443 0 448bdd00 34047 +5331 1444 0 448c6200 30582 +5332 1445 0 448cd978 19071 +5333 1446 0 448d23f8 40566 +5334 1447 0 448dc270 18925 +5335 1448 0 448e0c60 34708 +5336 1449 0 448e93f4 32631 +5337 1450 0 448f136c 44254 +5338 1451 0 448fc04c 81195 +5339 1452 0 4490fd78 34117 +5340 1453 0 449182c0 30959 +5341 1454 0 4491fbb0 17160 +5342 1455 0 44923eb8 14583 +5343 1456 0 449277b0 32711 +5344 1457 0 4492f778 37142 +5345 1458 0 44938890 37979 +5346 1459 0 44941cec 36054 +5347 1460 0 4494a9c4 30482 +5348 1461 0 449520d8 39372 +5349 1462 0 4495baa4 29519 +5352 1463 0 44962df4 38350 +5353 1464 0 4496c3c4 7951 +5354 1465 0 4496e2d4 7951 +5355 1466 0 449701e4 7278 +5356 1467 0 44971e54 13866 +5357 1468 0 44975480 41509 +5358 1469 0 4497f6a8 15541 +5360L 1470 0 44983360 7951 +5360R 1471 0 44985270 350174 +5361L 1472 0 449daa50 350174 +5361R 1473 0 44a30230 105333 +5362L 1474 0 44a49da8 105333 +5362R 1475 0 44a63920 108931 +5363L 1476 0 44a7e2a4 108931 +5363R 1477 0 44a98c28 106759 +5364L 1478 0 44ab2d30 106759 +5364R 1479 0 44acce38 92504 +5365L 1480 0 44ae3790 92504 +5365R 1481 0 44afa0e8 78215 +5366L 1482 0 44b0d270 78215 +5366R 1483 0 44b203f8 88301 +5367L 1484 0 44b35ce8 88301 +5367R 1485 0 44b4b5d8 88837 +5368L 1486 0 44b610e0 88837 +5368R 1487 0 44b76be8 87636 +5369L 1488 0 44b8c23c 87636 +5369R 1489 0 44ba1890 96818 +5370L 1490 0 44bb92c4 96818 +5370R 1491 0 44bd0cf8 81519 +5371L 1492 0 44be4b68 81519 +5371R 1493 0 44bf89d8 122104 +5372L 1494 0 44c166d0 122104 +5372R 1495 0 44c343c8 123187 +5373L 1496 0 44c524fc 123187 +5373R 1497 0 44c70630 152708 +5374L 1498 0 44c95ab4 152708 +5374R 1499 0 44cbaf38 98028 +5375L 1500 0 44cd2e24 98028 +5375R 1501 0 44cead10 77455 +5376L 1502 0 44cfdba0 77455 +5376R 1503 0 44d10a30 87788 +5377L 1504 0 44d2611c 87788 +5377R 1505 0 44d3b808 115101 +5378L 1506 0 44d579a8 115101 +5378R 1507 0 44d73b48 67219 +5379L 1508 0 44d841dc 67219 +5379R 1509 0 44d94870 69499 +5380L 1510 0 44da57ec 69499 +5380R 1511 0 44db6768 87702 +5381L 1512 0 44dcbe00 87702 +5381R 1513 0 44de1498 73383 +5382L 1514 0 44df3340 73383 +5382R 1515 0 44e051e8 63434 +5383L 1516 0 44e149b4 63434 +5383R 1517 0 44e24180 62638 +5384L 1518 0 44e33630 62638 +5384R 1519 0 44e42ae0 69590 +5385L 1520 0 44e53ab8 69590 +5385R 1521 0 44e64a90 80763 +5386L 1522 0 44e7860c 80763 +5386R 1523 0 44e8c188 80976 +5387L 1524 0 44e9fdd8 80976 +5387R 1525 0 44eb3a28 68343 +5388L 1526 0 44ec4520 68343 +5388R 1527 0 44ed5018 88837 +5389L 1528 0 44eeab20 88837 +5389R 1529 0 44f00628 88220 +5390 1530 0 44f15ec4 88220 +5391 1531 0 44f2b760 90535 +5392 1532 0 44f41908 134693 +5393 1533 0 44f62730 163141 +5394 1534 0 44f8a478 77830 +5395 1535 0 44f9d480 68456 +5396 1536 0 44fadfe8 63362 +5397 1537 0 44fbd76c 102092 +5398 1538 0 44fd6638 131296 +5399 1539 0 44ff6718 71640 +5400 1540 0 45007ef0 97754 +5401 1541 0 4501fccc 147855 +5402 1542 0 45043e5c 94144 +5403 1543 0 4505ae1c 81195 +5404 1544 0 4506eb48 76524 +5405 1545 0 45081634 134693 +5406 1546 0 450a245c 83954 +5407 1547 0 450b6c50 158895 +5408 1548 0 450dd900 123653 +5409 1549 0 450fbc08 98178 +5410 1550 0 45113b8c 117285 +5411 1551 0 451305b4 97754 +5412 1552 0 45148390 83264 +5413 1553 0 4515c8d0 87139 +5414 1554 0 45171d34 90110 +5415 1555 0 45187d34 61238 +5416 1556 0 45196c6c 201354 +5417 1557 0 451c7ef8 79071 +5418 1558 0 451db3d8 75462 +5419 1559 0 451edaa0 93932 +5420 1560 0 4520498c 81619 +5421 1561 0 45218860 140213 +5422 1562 0 4523ac18 128324 +5423 1563 0 4525a15c 155498 +5424 1564 0 452800c8 123229 +5425 1565 0 4529e228 310050 +5426 1566 0 452e9d4c 152101 +5427 1567 0 4530ef74 99876 +5428 1568 0 45327598 63573 +5429 1569 0 45336df0 31304 +5430 1570 0 4533e838 273535 +5431 1571 0 453814b8 99452 +5432 1572 0 45399934 80982 +5433 1573 0 453ad58c 69093 +5434 1574 0 453be374 44254 +5435 1575 0 453c9054 44043 +5436 1576 0 453d3c60 88837 +5437 1577 0 453e9768 90959 +5438 1578 0 453ffab8 53171 +5439 1579 0 4540ca6c 63998 +5440 1580 0 4541c46c 73127 +5441 1581 0 4542e214 37886 +5442 1582 0 45437614 54232 +5443 1583 0 454449ec 38310 +5444 1584 0 4544df94 40858 +5445 1585 0 45457f30 81406 +5446 1586 0 4546bd30 119630 +5447 1587 0 45489080 82314 +5448 1588 0 4549d20c 107848 +5449 1589 0 454b7754 48724 +5450 1590 0 454c35a8 35947 +5451 1591 0 454cc214 261844 +5452 1592 0 4550c0e8 142931 +5453 1593 0 4552ef3c 55852 +5454 1594 0 4553c968 35349 +5455 1595 0 45545380 46867 +5456 1596 0 45550a94 43821 +5457 1597 0 4555b5c4 43821 +5458 1598 0 455660f4 63581 +5459 1599 0 45575954 79983 +5460 1600 0 455891c4 71138 +5461 1601 0 4559a7a8 33663 +5462 1602 0 455a2b28 58783 +5463 1603 0 455b10c8 51467 +5464 1604 0 455bd9d4 30387 +5465 1605 0 455c5088 35903 +5466 1606 0 455cdcc8 30798 +5467 1607 0 455d5518 30240 +5468 1608 0 455dcb38 61966 +5469 1609 0 455ebd48 44014 +5470 1610 0 455f6938 30904 +5471 1611 0 455fe1f0 50794 +5472 1612 0 4560a85c 44902 +5473 1613 0 456157c4 77646 +5474 1614 0 45628714 42527 +5475 1615 0 45632d34 32702 +5476 1616 0 4563acf4 45716 +5477 1617 0 45645f88 40186 +5478 1618 0 4564fc84 34646 +5479 1619 0 456583dc 59830 +5480L 1620 0 45666d94 508373 +5480R 1621 0 456e2f6c 88854 +5481L 1622 0 456f8a84 88854 +5481R 1623 0 4570e59c 100800 +5482L 1624 0 45726f5c 100800 +5482R 1625 0 4573f91c 75015 +5483L 1626 0 45751e24 75015 +5483R 1627 0 4576432c 76886 +5484L 1628 0 45776f84 76886 +5484R 1629 0 45789bdc 106846 +5485L 1630 0 457a3d3c 106846 +5485R 1631 0 457bde9c 75592 +5486L 1632 0 457d05e4 75592 +5486R 1633 0 457e2d2c 71459 +5487L 1634 0 457f4450 71459 +5487R 1635 0 45805b74 69309 +5488L 1636 0 45816a34 69309 +5488R 1637 0 458278f4 83878 +5489L 1638 0 4583c09c 83878 +5489R 1639 0 45850844 84092 +5490L 1640 0 458650c0 84092 +5490R 1641 0 4587993c 68434 +5491L 1642 0 4588a490 68434 +5491R 1643 0 4589afe4 79526 +5492L 1644 0 458ae68c 79526 +5492R 1645 0 458c1d34 73709 +5493L 1646 0 458d3d24 73709 +5493R 1647 0 458e5d14 75413 +5494L 1648 0 458f83ac 75413 +5494R 1649 0 4590aa44 81798 +5495L 1650 0 4591e9cc 81798 +5495R 1651 0 45932954 136661 +5496L 1652 0 45953f2c 136661 +5496R 1653 0 45975504 99269 +5603L 1654 0 4598d8cc 99269 +5603R 1655 0 459a5c94 251260 +6010 1656 0 459e3210 251260 +6011 1657 0 45a2078c 10318 +6012 1658 0 45a22fdc 43850 +6013 1659 0 45a2db28 199019 +6014 1660 0 45a5e494 66546 +codec.dat 1661 0 45a6e888 34276 +DebugImages.tpl 1662 0 45a78000 12409824 +dummy.tpl 1663 0 4664dbe0 1835136 +face.dat 1664 0 4680dc60 256 +ip.cfg 1665 0 46810000 7034880 +mgso.rel 1666 0 46ec5800 48 +mgso.str 1667 0 46ec5830 5729024 +movie.dat 1668 0 4743c330 35 +stage 1669 0 47440000 94935040 +preview 1670 1 5c 1672 +data.cnf 1671 1 685 1672 +vox.dat 1672 0 4cec9800 175 +freeing memory used by FST string table... ...done. diff --git a/source/std_disclaimer.h b/source/std_disclaimer.h new file mode 100755 index 0000000..6e8827c --- /dev/null +++ b/source/std_disclaimer.h @@ -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 */