Commit code, circa 2006
This commit is contained in:
69
Makefile
Executable file
69
Makefile
Executable file
@@ -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
|
||||
215
gcmbrowser.bakvpj
Executable file
215
gcmbrowser.bakvpj
Executable file
@@ -0,0 +1,215 @@
|
||||
<!DOCTYPE Project SYSTEM "http://www.slickedit.com/dtd/vse/8.1/vpj.dtd">
|
||||
<Project
|
||||
Version="8.1"
|
||||
VendorName="SlickEdit"
|
||||
WorkingDir="."
|
||||
BuildSystem="vsbuild"
|
||||
BuildMakeFile="">
|
||||
<Config
|
||||
Name="Debug"
|
||||
Type="gnuc"
|
||||
DebugCallbackName="gdb"
|
||||
Version="1"
|
||||
OutputFile="%bdgcmbrowser">
|
||||
<Menu>
|
||||
<Target
|
||||
Name="Compile"
|
||||
MenuCaption="&Compile"
|
||||
Dialog="_gnuc_options_form Compile"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
OutputExts="*.o"
|
||||
SaveOption="SaveCurrent"
|
||||
RunFromDir="%rw">
|
||||
<Exec CmdLine='g++ -c %xup -g3 -ggdb -o "%bd%n%oe" %i "%f"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Link"
|
||||
MenuCaption="&Link"
|
||||
ShowOnMenu="Never"
|
||||
Dialog="_gnuc_options_form Link"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveCurrent"
|
||||
RunFromDir="%rw">
|
||||
<Exec CmdLine='g++ %xup -g3 -ggdb -nostdlibs -o "%o" %f %libs'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Build"
|
||||
MenuCaption="&Build"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveWorkspaceFiles"
|
||||
RunFromDir="%rw"
|
||||
Dialog="_gnuc_options_form Compile">
|
||||
<Exec CmdLine='"%(VSLICKBIN1)vsbuild" build "%w" "%r"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Rebuild"
|
||||
MenuCaption="&Rebuild"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveWorkspaceFiles"
|
||||
RunFromDir="%rw"
|
||||
Dialog="_gnuc_options_form Compile">
|
||||
<Exec CmdLine='"%(VSLICKBIN1)vsbuild" rebuild "%w" "%r"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Debug"
|
||||
MenuCaption="&Debug"
|
||||
Dialog="_gnuc_options_form Run/Debug"
|
||||
BuildFirst="1"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveNone"
|
||||
RunFromDir="%rw">
|
||||
<Exec CmdLine='vsdebugio -prog "%o"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Execute"
|
||||
MenuCaption="E&xecute"
|
||||
Dialog="_gnuc_options_form Run/Debug"
|
||||
BuildFirst="1"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveWorkspaceFiles"
|
||||
RunFromDir="%rw">
|
||||
<Exec CmdLine='"%o"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="dash"
|
||||
MenuCaption="-"
|
||||
Deletable="0">
|
||||
<Exec/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="GNU C Options"
|
||||
MenuCaption="GNU C &Options..."
|
||||
ShowOnMenu="HideIfNoCmdLine"
|
||||
Deletable="0"
|
||||
SaveOption="SaveNone">
|
||||
<Exec
|
||||
CmdLine="gnucoptions"
|
||||
Type="Slick-C"/>
|
||||
</Target>
|
||||
</Menu>
|
||||
<Includes/>
|
||||
<Libs/>
|
||||
</Config>
|
||||
<Config
|
||||
Name="Release"
|
||||
Type="gnuc"
|
||||
DebugCallbackName="gdb"
|
||||
Version="1"
|
||||
OutputFile="%bdgcmbrowser">
|
||||
<Menu>
|
||||
<Target
|
||||
Name="Compile"
|
||||
MenuCaption="&Compile"
|
||||
Dialog="_gnuc_options_form Compile"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
OutputExts="*.o"
|
||||
SaveOption="SaveCurrent"
|
||||
RunFromDir="%rw">
|
||||
<Exec CmdLine='g++ -c %xup -g3 -ggdb -o "%bd%n%oe" %i "%f"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Link"
|
||||
MenuCaption="&Link"
|
||||
ShowOnMenu="Never"
|
||||
Dialog="_gnuc_options_form Link"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveCurrent"
|
||||
RunFromDir="%rw">
|
||||
<Exec CmdLine='g++ %xup -g3 -ggdb -o "%o" %f %libs'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Build"
|
||||
MenuCaption="&Build"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveWorkspaceFiles"
|
||||
RunFromDir="%rw"
|
||||
Dialog="_gnuc_options_form Compile">
|
||||
<Exec CmdLine='"%(VSLICKBIN1)vsbuild" build "%w" "%r"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Rebuild"
|
||||
MenuCaption="&Rebuild"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveWorkspaceFiles"
|
||||
RunFromDir="%rw"
|
||||
Dialog="_gnuc_options_form Compile">
|
||||
<Exec CmdLine='"%(VSLICKBIN1)vsbuild" rebuild "%w" "%r"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Debug"
|
||||
MenuCaption="&Debug"
|
||||
Dialog="_gnuc_options_form Run/Debug"
|
||||
BuildFirst="1"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveNone"
|
||||
RunFromDir="%rw">
|
||||
<Exec CmdLine='vsdebugio -prog "%o"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Execute"
|
||||
MenuCaption="E&xecute"
|
||||
Dialog="_gnuc_options_form Run/Debug"
|
||||
BuildFirst="1"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveWorkspaceFiles"
|
||||
RunFromDir="%rw">
|
||||
<Exec CmdLine='"%o"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="dash"
|
||||
MenuCaption="-"
|
||||
Deletable="0">
|
||||
<Exec/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="GNU C Options"
|
||||
MenuCaption="GNU C &Options..."
|
||||
ShowOnMenu="HideIfNoCmdLine"
|
||||
Deletable="0"
|
||||
SaveOption="SaveNone">
|
||||
<Exec
|
||||
CmdLine="gnucoptions"
|
||||
Type="Slick-C"/>
|
||||
</Target>
|
||||
</Menu>
|
||||
<Includes/>
|
||||
<Libs/>
|
||||
</Config>
|
||||
<Files>
|
||||
<Folder
|
||||
Name="Source Files"
|
||||
Filters="*.c;*.C;*.cc;*.cpp;*.cp;*.cxx;*.prg;*.pas;*.dpr;*.asm;*.s;*.bas;*.java;*.cs;*.sc;*.e;*.cob;*.html;*.rc;*.tcl;*.py;*.pl">
|
||||
<F N="source/gcmbrowser.cpp"/>
|
||||
<F N="source/gcminfo.cpp"/>
|
||||
</Folder>
|
||||
<Folder
|
||||
Name="Header Files"
|
||||
Filters="*.h;*.H;*.hh;*.hpp;*.hxx;*.inc;*.sh;*.cpy;*.if">
|
||||
<F N="source/gcminfo.h"/>
|
||||
<F N="source/std_disclaimer.h"/>
|
||||
</Folder>
|
||||
<Folder
|
||||
Name="Resource Files"
|
||||
Filters="*.ico;*.cur;*.dlg"/>
|
||||
<Folder
|
||||
Name="Bitmaps"
|
||||
Filters="*.bmp"/>
|
||||
<Folder
|
||||
Name="Other Files"
|
||||
Filters="">
|
||||
<F N="source/README.txt"/>
|
||||
</Folder>
|
||||
</Files>
|
||||
</Project>
|
||||
6
gcmbrowser.bakvpw
Executable file
6
gcmbrowser.bakvpw
Executable file
@@ -0,0 +1,6 @@
|
||||
<!DOCTYPE Workspace SYSTEM "http://www.slickedit.com/dtd/vse/8.1/vpw.dtd">
|
||||
<Workspace Version="8.1" VendorName="SlickEdit">
|
||||
<Projects>
|
||||
<Project File="gcmbrowser.vpj"/>
|
||||
</Projects>
|
||||
</Workspace>
|
||||
221
gcmbrowser.vpj
Executable file
221
gcmbrowser.vpj
Executable file
@@ -0,0 +1,221 @@
|
||||
<!DOCTYPE Project SYSTEM "http://www.slickedit.com/dtd/vse/10.0/vpj.dtd">
|
||||
<Project
|
||||
Version="10.0"
|
||||
VendorName="SlickEdit"
|
||||
WorkingDir="."
|
||||
BuildSystem="vsbuild"
|
||||
BuildMakeFile="">
|
||||
<Config
|
||||
Name="Debug"
|
||||
Type="gnuc"
|
||||
DebugCallbackName="gdb"
|
||||
Version="1"
|
||||
OutputFile="%bdgcmbrowser"
|
||||
CompilerConfigName="Latest Version">
|
||||
<Menu>
|
||||
<Target
|
||||
Name="Compile"
|
||||
MenuCaption="&Compile"
|
||||
Dialog="_gnuc_options_form Compile"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
OutputExts="*.o"
|
||||
SaveOption="SaveCurrent"
|
||||
RunFromDir="%rw">
|
||||
<Exec CmdLine='g++ -c %xup -g3 -ggdb -o "%bd%n%oe" %i "%f"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Link"
|
||||
MenuCaption="&Link"
|
||||
ShowOnMenu="Never"
|
||||
Dialog="_gnuc_options_form Link"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveCurrent"
|
||||
RunFromDir="%rw">
|
||||
<Exec CmdLine='g++ %xup -g3 -ggdb -nostdlibs -o "%o" %f %libs'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Build"
|
||||
MenuCaption="&Build"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveWorkspaceFiles"
|
||||
RunFromDir="%rw"
|
||||
Dialog="_gnuc_options_form Compile">
|
||||
<Exec CmdLine='"%(VSLICKBIN1)vsbuild" build "%w" "%r"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Rebuild"
|
||||
MenuCaption="&Rebuild"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveWorkspaceFiles"
|
||||
RunFromDir="%rw"
|
||||
Dialog="_gnuc_options_form Compile">
|
||||
<Exec CmdLine='"%(VSLICKBIN1)vsbuild" rebuild "%w" "%r"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Debug"
|
||||
MenuCaption="&Debug"
|
||||
Dialog="_gnuc_options_form Run/Debug"
|
||||
BuildFirst="1"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveNone"
|
||||
RunFromDir="%rw">
|
||||
<Exec CmdLine='vsdebugio -prog "%o"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Execute"
|
||||
MenuCaption="E&xecute"
|
||||
Dialog="_gnuc_options_form Run/Debug"
|
||||
BuildFirst="1"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveWorkspaceFiles"
|
||||
RunFromDir="%rw">
|
||||
<Exec CmdLine='"%o"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="dash"
|
||||
MenuCaption="-"
|
||||
Deletable="0">
|
||||
<Exec/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="GNU C Options"
|
||||
MenuCaption="GNU C &Options..."
|
||||
ShowOnMenu="HideIfNoCmdLine"
|
||||
Deletable="0"
|
||||
SaveOption="SaveNone">
|
||||
<Exec
|
||||
CmdLine="gnucoptions"
|
||||
Type="Slick-C"/>
|
||||
</Target>
|
||||
</Menu>
|
||||
<Includes/>
|
||||
<Libs/>
|
||||
</Config>
|
||||
<Config
|
||||
Name="Release"
|
||||
Type="gnuc"
|
||||
DebugCallbackName="gdb"
|
||||
Version="1"
|
||||
OutputFile="%bdgcmbrowser"
|
||||
CompilerConfigName="Latest Version">
|
||||
<Menu>
|
||||
<Target
|
||||
Name="Compile"
|
||||
MenuCaption="&Compile"
|
||||
Dialog="_gnuc_options_form Compile"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
OutputExts="*.o"
|
||||
SaveOption="SaveCurrent"
|
||||
RunFromDir="%rw">
|
||||
<Exec CmdLine='g++ -c %xup -g3 -ggdb -o "%bd%n%oe" %i "%f"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Link"
|
||||
MenuCaption="&Link"
|
||||
ShowOnMenu="Never"
|
||||
Dialog="_gnuc_options_form Link"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveCurrent"
|
||||
RunFromDir="%rw">
|
||||
<Exec CmdLine='g++ %xup -g3 -ggdb -o "%o" %f %libs'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Build"
|
||||
MenuCaption="&Build"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveWorkspaceFiles"
|
||||
RunFromDir="%rw"
|
||||
Dialog="_gnuc_options_form Compile">
|
||||
<Exec CmdLine='"%(VSLICKBIN1)vsbuild" build "%w" "%r"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Rebuild"
|
||||
MenuCaption="&Rebuild"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveWorkspaceFiles"
|
||||
RunFromDir="%rw"
|
||||
Dialog="_gnuc_options_form Compile">
|
||||
<Exec CmdLine='"%(VSLICKBIN1)vsbuild" rebuild "%w" "%r"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Debug"
|
||||
MenuCaption="&Debug"
|
||||
Dialog="_gnuc_options_form Run/Debug"
|
||||
BuildFirst="1"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveNone"
|
||||
RunFromDir="%rw">
|
||||
<Exec CmdLine='vsdebugio -prog "%o"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="Execute"
|
||||
MenuCaption="E&xecute"
|
||||
Dialog="_gnuc_options_form Run/Debug"
|
||||
BuildFirst="1"
|
||||
CaptureOutputWith="ProcessBuffer"
|
||||
Deletable="0"
|
||||
SaveOption="SaveWorkspaceFiles"
|
||||
RunFromDir="%rw">
|
||||
<Exec CmdLine='"%o"'/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="dash"
|
||||
MenuCaption="-"
|
||||
Deletable="0">
|
||||
<Exec/>
|
||||
</Target>
|
||||
<Target
|
||||
Name="GNU C Options"
|
||||
MenuCaption="GNU C &Options..."
|
||||
ShowOnMenu="HideIfNoCmdLine"
|
||||
Deletable="0"
|
||||
SaveOption="SaveNone">
|
||||
<Exec
|
||||
CmdLine="gnucoptions"
|
||||
Type="Slick-C"/>
|
||||
</Target>
|
||||
</Menu>
|
||||
<Includes/>
|
||||
<Libs/>
|
||||
</Config>
|
||||
<Files>
|
||||
<Folder
|
||||
Name="Source Files"
|
||||
Filters="*.c;*.C;*.cc;*.cpp;*.cp;*.cxx;*.prg;*.pas;*.dpr;*.asm;*.s;*.bas;*.java;*.cs;*.sc;*.e;*.cob;*.html;*.rc;*.tcl;*.py;*.pl">
|
||||
<F N="source/gcmbrowser.cpp"/>
|
||||
<F N="source/gcminfo.cpp"/>
|
||||
</Folder>
|
||||
<Folder
|
||||
Name="Header Files"
|
||||
Filters="*.h;*.H;*.hh;*.hpp;*.hxx;*.inc;*.sh;*.cpy;*.if">
|
||||
<F N="source/gcminfo.h"/>
|
||||
<F N="source/std_disclaimer.h"/>
|
||||
</Folder>
|
||||
<Folder
|
||||
Name="Resource Files"
|
||||
Filters="*.ico;*.cur;*.dlg"/>
|
||||
<Folder
|
||||
Name="Bitmaps"
|
||||
Filters="*.bmp"/>
|
||||
<Folder
|
||||
Name="Other Files"
|
||||
Filters="">
|
||||
<F N="source/README.txt"/>
|
||||
</Folder>
|
||||
</Files>
|
||||
<CompatibleVersions>
|
||||
<PrevVersion VersionNumber="9.0"/>
|
||||
<PrevVersion VersionNumber="9.1"/>
|
||||
</CompatibleVersions>
|
||||
</Project>
|
||||
10
gcmbrowser.vpw
Executable file
10
gcmbrowser.vpw
Executable file
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE Workspace SYSTEM "http://www.slickedit.com/dtd/vse/10.0/vpw.dtd">
|
||||
<Workspace Version="10.0" VendorName="SlickEdit">
|
||||
<Projects>
|
||||
<Project File="gcmbrowser.vpj"/>
|
||||
</Projects>
|
||||
<CompatibleVersions>
|
||||
<PrevVersion VersionNumber="9.0"/>
|
||||
<PrevVersion VersionNumber="9.1"/>
|
||||
</CompatibleVersions>
|
||||
</Workspace>
|
||||
52
gcmbrowser.vpwhistu
Executable file
52
gcmbrowser.vpwhistu
Executable file
@@ -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::*
|
||||
########
|
||||
BIN
gcmbrowser.vtg
Executable file
BIN
gcmbrowser.vtg
Executable file
Binary file not shown.
47
source/.svn/all-wcprops
Executable file
47
source/.svn/all-wcprops
Executable file
@@ -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
|
||||
269
source/.svn/entries
Executable file
269
source/.svn/entries
Executable file
@@ -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
|
||||
|
||||
5
source/.svn/prop-base/Makefile.svn-base
Executable file
5
source/.svn/prop-base/Makefile.svn-base
Executable file
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 0
|
||||
|
||||
END
|
||||
5
source/.svn/prop-base/README.txt.svn-base
Executable file
5
source/.svn/prop-base/README.txt.svn-base
Executable file
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 0
|
||||
|
||||
END
|
||||
5
source/.svn/prop-base/gcmbrowser.cpp.svn-base
Executable file
5
source/.svn/prop-base/gcmbrowser.cpp.svn-base
Executable file
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 0
|
||||
|
||||
END
|
||||
5
source/.svn/prop-base/gcminfo.cpp.svn-base
Executable file
5
source/.svn/prop-base/gcminfo.cpp.svn-base
Executable file
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 0
|
||||
|
||||
END
|
||||
5
source/.svn/prop-base/gcminfo.h.svn-base
Executable file
5
source/.svn/prop-base/gcminfo.h.svn-base
Executable file
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 0
|
||||
|
||||
END
|
||||
5
source/.svn/prop-base/sample-output.txt.svn-base
Executable file
5
source/.svn/prop-base/sample-output.txt.svn-base
Executable file
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 0
|
||||
|
||||
END
|
||||
5
source/.svn/prop-base/std_disclaimer.h.svn-base
Executable file
5
source/.svn/prop-base/std_disclaimer.h.svn-base
Executable file
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 0
|
||||
|
||||
END
|
||||
94
source/.svn/text-base/Makefile.svn-base
Executable file
94
source/.svn/text-base/Makefile.svn-base
Executable file
@@ -0,0 +1,94 @@
|
||||
# Visual SlickEdit generated file. Do not edit this file except in designated areas.
|
||||
# -----Begin user-editable area-----
|
||||
|
||||
# -----End user-editable area-----
|
||||
|
||||
# Make command to use for dependencies
|
||||
MAKECMD=gmake
|
||||
|
||||
# If no configuration is specified, "Debug" will be used
|
||||
ifndef "CFG"
|
||||
CFG=Debug
|
||||
endif
|
||||
|
||||
#
|
||||
# Configuration: Debug
|
||||
#
|
||||
ifeq "$(CFG)" "Debug"
|
||||
OUTDIR=Debug
|
||||
OUTFILE=$(OUTDIR)/gcmbrowser
|
||||
CFG_INC=
|
||||
CFG_LIB=
|
||||
CFG_OBJ=
|
||||
COMMON_OBJ=$(OUTDIR)/gcmbrowser.o
|
||||
OBJ=$(COMMON_OBJ) $(CFG_OBJ)
|
||||
|
||||
COMPILE=g++ -c -g -o "$(OUTDIR)/$(*F).o" $(CFG_INC) "$<"
|
||||
LINK=g++ -g -o "$(OUTFILE)" $(OBJ) $(CFG_LIB)
|
||||
|
||||
# Pattern rules
|
||||
$(OUTDIR)/%.o : source/%.cpp
|
||||
$(COMPILE)
|
||||
|
||||
# Build rules
|
||||
all: $(OUTFILE)
|
||||
|
||||
$(OUTFILE): $(OUTDIR) $(OBJ)
|
||||
$(LINK)
|
||||
|
||||
$(OUTDIR):
|
||||
mkdir -p "$(OUTDIR)"
|
||||
|
||||
# Rebuild this project
|
||||
rebuild: cleanall all
|
||||
|
||||
# Clean this project
|
||||
clean:
|
||||
rm -f source/*o
|
||||
rm -f $(CFG)/*o
|
||||
rm -f $(OUTFILE)
|
||||
|
||||
# Clean this project and all dependencies
|
||||
cleanall: clean
|
||||
endif
|
||||
|
||||
#
|
||||
# Configuration: Release
|
||||
#
|
||||
ifeq "$(CFG)" "Release"
|
||||
OUTDIR=Release
|
||||
OUTFILE=$(OUTDIR)/gcmbrowser
|
||||
CFG_INC=
|
||||
CFG_LIB=
|
||||
CFG_OBJ=
|
||||
COMMON_OBJ=$(OUTDIR)/gcmbrowser.o
|
||||
OBJ=$(COMMON_OBJ) $(CFG_OBJ)
|
||||
|
||||
COMPILE=g++ -c -o "$(OUTDIR)/$(*F).o" $(CFG_INC) "$<"
|
||||
LINK=g++ -o "$(OUTFILE)" $(OBJ) $(CFG_LIB)
|
||||
|
||||
# Pattern rules
|
||||
$(OUTDIR)/%.o : source/%.cpp
|
||||
$(COMPILE)
|
||||
|
||||
# Build rules
|
||||
all: $(OUTFILE)
|
||||
|
||||
$(OUTFILE): $(OUTDIR) $(OBJ)
|
||||
$(LINK)
|
||||
|
||||
$(OUTDIR):
|
||||
mkdir -p "$(OUTDIR)"
|
||||
|
||||
# Rebuild this project
|
||||
rebuild: cleanall all
|
||||
|
||||
# Clean this project
|
||||
clean:
|
||||
rm -f source/*o
|
||||
rm -f $(CFG)/*o
|
||||
rm -f $(OUTFILE)
|
||||
|
||||
# Clean this project and all dependencies
|
||||
cleanall: clean
|
||||
endif
|
||||
26
source/.svn/text-base/README.txt.svn-base
Executable file
26
source/.svn/text-base/README.txt.svn-base
Executable file
@@ -0,0 +1,26 @@
|
||||
This is libgcm V0.1a, an early alpha of my library for
|
||||
manipulating gamecube master files. It currently has
|
||||
little functionality, but you can list and extract the contents
|
||||
of GCMs - the only thing I haven't got extracting correctly
|
||||
yet is the apploader stuff, because I haven't even really
|
||||
begun working on that yet, and don't know how to really test
|
||||
the results of that extraction.
|
||||
|
||||
Before this is over, I intend to have the library
|
||||
ready to insert, append, and create entire new images for
|
||||
burning to a GCM. My final test of this ability will be to
|
||||
completely unpack a disc image onto the drive (which it can
|
||||
already do, with the exception of the apploader) and re-pack
|
||||
it and see if it plays.
|
||||
|
||||
Maybe someone will be helped by this code. GPL applies.
|
||||
This code is free as in freedom. If you have any additions you
|
||||
would like to see in the next release, I'd be happy to include them,
|
||||
with credit. Just email them to me or find me in #gcdev on EFNet.
|
||||
|
||||
Enjoy!
|
||||
Andrew K
|
||||
andrew@aklabs.net
|
||||
andrewk in #gcdev on EFNet
|
||||
120817314 ICQ
|
||||
|
||||
163
source/.svn/text-base/gcmbrowser.cpp.svn-base
Executable file
163
source/.svn/text-base/gcmbrowser.cpp.svn-base
Executable file
@@ -0,0 +1,163 @@
|
||||
#include "gcminfo.h"
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// All the interesting stuff is in gcminfo.c|h ; gcmbrowser.cpp is just a proof
|
||||
// and simple util.
|
||||
|
||||
const char *usage =
|
||||
"gcmbrowser V0.01 (C) 2005 Andrew Kesterson (andrew@aklabs.net) \n\
|
||||
\n\
|
||||
Usage: gcmbrowser <.gcm file> <operation>\n\
|
||||
\n\
|
||||
operations:\n\
|
||||
-h : print this help\n\
|
||||
-H : print the disk header (maker, title, etc)\n\
|
||||
-E : explode the filesystem into the current directory\n\
|
||||
-e <file> : extract \"file\" from the gcm. With -o you\n\
|
||||
may specify an optional output filename; by default,\n\
|
||||
the file will be named the same (and reside in the\n\
|
||||
same directory tree) as in the image. You may specify\n\
|
||||
the source file by file number or by filename (full path\n\
|
||||
is necessary when specifying by filename.)\n\
|
||||
-o <filename> : specify the destination for a -e operation.\n\
|
||||
-l : list the names and file numbers of all files in the GCM.\n\
|
||||
All files are printed with full path.\n\
|
||||
-d : when extracting a file, create all needed directories for\n\
|
||||
the output file. This can, but really shouldn't, be used with\n\
|
||||
the -o option.\n\
|
||||
\n";
|
||||
|
||||
const char *shortopts = "hHEe:o:ld";
|
||||
|
||||
#define OP_PRINT_HEADER 0
|
||||
#define OP_EXPLODE 2
|
||||
#define OP_EXTRACT 4
|
||||
#define OP_LIST 8
|
||||
#define OP_CREATE_DIRS 1024
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
std::string gcmFname;
|
||||
std::string outFname;
|
||||
std::string extractFname;
|
||||
unsigned int extractFnumber= -1;
|
||||
int outIsDigit = 1;
|
||||
int ctr = 0;
|
||||
int op = 0;
|
||||
GCM theGCM;
|
||||
unsigned int opt = 0;
|
||||
unsigned int ret = 0;
|
||||
|
||||
if ( argc < 2 ) {
|
||||
fprintf(stderr, usage);
|
||||
return 1;
|
||||
}
|
||||
|
||||
opt = getopt(argc, argv, shortopts);
|
||||
while ( opt != -1) {
|
||||
switch ( opt ){
|
||||
case 'h':
|
||||
fprintf(stderr, usage);
|
||||
return 1;
|
||||
case 'H':
|
||||
op = OP_PRINT_HEADER;
|
||||
break;
|
||||
case 'E':
|
||||
op = OP_EXPLODE;
|
||||
break;
|
||||
case 'e':
|
||||
op = OP_EXTRACT;
|
||||
for ( ctr = 0; ctr < strlen(optarg) ; ctr++ ) {
|
||||
if ( isprint(optarg[ctr]) && !isdigit(optarg[ctr])) {
|
||||
outIsDigit = 0;
|
||||
} else {
|
||||
//printf("DEBUG : extract filename character %c is a digit\n", optarg[ctr]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ( outIsDigit == 0 ) {
|
||||
//printf("DEBUG : extract filename option is NON-DIGIT %s\n", optarg);
|
||||
extractFname.reserve(strlen(optarg));
|
||||
extractFname.assign(optarg);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
//printf("DEBUG : extract filename option is file number %s\n", optarg);
|
||||
extractFnumber = atoi(optarg);
|
||||
break;
|
||||
}
|
||||
case 'o':
|
||||
outFname.reserve(strlen(optarg));
|
||||
outFname.assign(optarg);
|
||||
break;
|
||||
case 'l':
|
||||
op = OP_LIST;
|
||||
break;
|
||||
case 'd':
|
||||
op |= OP_CREATE_DIRS;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "I don't understand option -%c\n", opt);
|
||||
return 1;
|
||||
}
|
||||
opt = getopt(argc, argv, shortopts);
|
||||
}
|
||||
gcmFname.reserve(strlen(argv[optind]));
|
||||
gcmFname.assign(argv[optind]);
|
||||
|
||||
if ( gcmInit((char *)gcmFname.c_str(), &theGCM) ) {
|
||||
printf("Couldn't init GCM file %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int top = 0;
|
||||
if ( op & OP_CREATE_DIRS ) top = op ^ OP_CREATE_DIRS;
|
||||
else top = op;
|
||||
switch ( top ) {
|
||||
case OP_EXPLODE:
|
||||
ret = gcmExplode(&theGCM);
|
||||
if ( ! ret )
|
||||
fprintf(stderr, "Failed to explode filesystem.\n");
|
||||
break;
|
||||
case OP_EXTRACT:
|
||||
if ( extractFnumber == -1 ) {
|
||||
//printf("DEBUG : getting file number for %s\n", extractFname.c_str());
|
||||
extractFnumber = gcmGetFileByName(&theGCM, (char *)extractFname.c_str());
|
||||
//printf("DEBUG: got %d\n", extractFnumber);
|
||||
}
|
||||
if ( extractFnumber > theGCM.fst.stringtable.size() || extractFnumber == -1) {
|
||||
fprintf(stderr, "File number %d requested was beyond the length of the filesystem\n", extractFnumber);
|
||||
break;
|
||||
}
|
||||
if ( outFname.length() == 0 && ( op & OP_CREATE_DIRS ) ) {
|
||||
char *outfile = (char *) new char[GCNDVD_FNAME_LENGTH];
|
||||
gcmGetFullFileName(&theGCM, extractFnumber, outfile);
|
||||
std::string execstring = "";
|
||||
// this is a quick hack to ensure that the output directory exists
|
||||
execstring.append("mkdir -p .");
|
||||
execstring.append("`dirname ");
|
||||
execstring.append(outfile);
|
||||
execstring.append("`");
|
||||
system(execstring.c_str());
|
||||
delete outfile;
|
||||
}
|
||||
if ( outFname.length() > 0 )
|
||||
ret = gcmExtractFile(&theGCM, extractFnumber, (char *)outFname.c_str());
|
||||
else
|
||||
ret = gcmExtractFile(&theGCM, extractFnumber, NULL);
|
||||
if ( ret != 0 )
|
||||
fprintf(stderr, "Failed to extract file number %d to output file %s\n", extractFnumber, outFname.length() > 0 ? (char *)outFname.c_str() : "" );
|
||||
break;
|
||||
case OP_PRINT_HEADER:
|
||||
ret = gcmPrint(&theGCM);
|
||||
break;
|
||||
case OP_LIST:
|
||||
ret = gcmPrintFST(&theGCM);
|
||||
break;
|
||||
}
|
||||
|
||||
gcmFreeStringTable(&theGCM);
|
||||
|
||||
return ret;
|
||||
}
|
||||
674
source/.svn/text-base/gcminfo.cpp.svn-base
Executable file
674
source/.svn/text-base/gcminfo.cpp.svn-base
Executable file
@@ -0,0 +1,674 @@
|
||||
#include "gcminfo.h"
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
int needByteSwap = 0;
|
||||
|
||||
// these are functions that the user really doesn't need to see,
|
||||
// so they're declared here away from the external API. They're
|
||||
// used mainly for populating the internal FST data structure.
|
||||
// All the user-necessary functions are listed out in gcminfo.h.
|
||||
|
||||
int gcmPopulateFST(GCM *data, FILE *file);
|
||||
void *gcmWhichData(int whichdata, GCM *data);
|
||||
int gcmGetData(int whichdata, GCM *data, FILE *file);
|
||||
int gcmGetFile(GCM *data, GCM_FSTEntry *entry, int fnum, FILE *file);
|
||||
int gcmCheckMagic(FILE *file);
|
||||
|
||||
// checks the magic number of the DVD file, and sets needByteSwap
|
||||
// returns the final value of needByteSwap. Returns -1 if the magic
|
||||
// word doesn't match either way and needByteSwap couldn't be set.
|
||||
int gcmCheckMagic(FILE *file)
|
||||
{
|
||||
int magic = 0;
|
||||
fseek(file, GCMPieces[GCM_DHEAD_DVDMAGIC].offset, 0);
|
||||
fread(&magic, GCMPieces[GCM_DHEAD_DVDMAGIC].size, 1, file);
|
||||
|
||||
if ( magic == GCNDVD_MAGICNUM ) {
|
||||
needByteSwap = 0;
|
||||
} else {
|
||||
magic = (((magic&0x000000FF)<<24)+((magic&0x0000FF00)<<8)+
|
||||
((magic&0x00FF0000)>>8)+((magic&0xFF000000)>>24));
|
||||
if ( magic == GCNDVD_MAGICNUM ) {
|
||||
needByteSwap = 1;
|
||||
}
|
||||
else needByteSwap = -1;
|
||||
}
|
||||
|
||||
return needByteSwap;
|
||||
}
|
||||
|
||||
// swap from big to little endian (only needed on intel machines)
|
||||
// only works if needByteSwap is > -1
|
||||
int byteSwap (int nLongNumber)
|
||||
{
|
||||
if ( needByteSwap ) return (((nLongNumber&0x000000FF)<<24)+((nLongNumber&0x0000FF00)<<8)+
|
||||
((nLongNumber&0x00FF0000)>>8)+((nLongNumber&0xFF000000)>>24));
|
||||
else if ( needByteSwap == -1 ) return 0; // refuse to work
|
||||
}
|
||||
|
||||
// return the type (0=file 1=directory) for the given FST entry
|
||||
int gcmGetFSTEntryType(GCM_FSTEntry *entry)
|
||||
{
|
||||
return entry->fname_offset >> 24;
|
||||
}
|
||||
|
||||
// uses one of the GCM_* definitions to return a pointer to
|
||||
// the appropriate point of the GCM struct to read data into.
|
||||
void *gcmWhichData(int whichdata, GCM *data)
|
||||
{
|
||||
void *toPrint = NULL;
|
||||
|
||||
switch (whichdata) {
|
||||
case GCM_DHEAD_GAMECODE:
|
||||
toPrint = &data->head.gamecode;
|
||||
break;
|
||||
case GCM_DHEAD_GAMEMAKER:
|
||||
toPrint = &data->head.gamemaker;
|
||||
break;
|
||||
case GCM_DHEAD_DVDMAGIC:
|
||||
toPrint = &data->head.magicword;
|
||||
break;
|
||||
case GCM_DHEAD_GAMENAME:
|
||||
toPrint = &data->head.gamename;
|
||||
break;
|
||||
case GCM_DHEAD_DEBUGMON:
|
||||
toPrint = &data->head.debugmon;
|
||||
break;
|
||||
case GCM_DHEAD_DEBUGMONADDR:
|
||||
toPrint = &data->head.debugmonaddr;
|
||||
break;
|
||||
case GCM_DHEAD_BOOTFILE:
|
||||
toPrint = &data->head.bootfile;
|
||||
break;
|
||||
case GCM_DHEAD_FST:
|
||||
toPrint = &data->fst.offset;
|
||||
break;
|
||||
case GCM_DHEAD_FSTSIZE:
|
||||
toPrint = &data->fst.size;
|
||||
break;
|
||||
case GCM_DHEAD_FSTMAXSIZE:
|
||||
toPrint = &data->fst.maxsize;
|
||||
break;
|
||||
case GCM_DHEAD_USERPOS:
|
||||
toPrint = &data->head.userpos;
|
||||
break;
|
||||
case GCM_DHEAD_USERLEN:
|
||||
toPrint = &data->head.userlen;
|
||||
break;
|
||||
case GCM_DHEADINF_DEBUGMONSIZE:
|
||||
toPrint = &data->headInf.debugmonsize;
|
||||
break;
|
||||
case GCM_DHEADINF_SIMMEMSIZE:
|
||||
toPrint = &data->headInf.simmemsize;
|
||||
break;
|
||||
case GCM_DHEADINF_ARGOFFSET:
|
||||
toPrint = &data->headInf.simmemsize;
|
||||
break;
|
||||
case GCM_DHEADINF_DEBUGFLAG:
|
||||
toPrint = &data->headInf.debugflag;
|
||||
break;
|
||||
case GCM_DHEADINF_TRACKLOCATION:
|
||||
toPrint = &data->headInf.tracklocation;
|
||||
break;
|
||||
case GCM_DHEADINF_TRACKSIZE:
|
||||
toPrint = &data->headInf.tracksize;
|
||||
break;
|
||||
case GCM_DHEADINF_COUNTRYCODE:
|
||||
toPrint = &data->headInf.countrycode;
|
||||
break;
|
||||
case GCM_APPLOADER_VERSION:
|
||||
toPrint = &data->apploader.datever;
|
||||
break;
|
||||
case GCM_APPLOADER_ENTRY:
|
||||
toPrint = &data->apploader.entry;
|
||||
break;
|
||||
case GCM_APPLOADER_SIZE:
|
||||
toPrint = &data->apploader.size;
|
||||
break;
|
||||
case GCM_APPLOADER_TRAILERSIZE:
|
||||
toPrint = &data->apploader.trailersize;
|
||||
break;
|
||||
case GCM_APPLOADER_BINARY:
|
||||
toPrint = &data->apploader.apploader;
|
||||
break;
|
||||
case GCM_FST_ROOT:
|
||||
toPrint = (void *)"Not implemented yet";
|
||||
break;
|
||||
case GCM_FST_STRINGTABLEOFF:
|
||||
toPrint = &data->fst.stringtable_offset;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return toPrint;
|
||||
}
|
||||
|
||||
// print the info in data as indicated by the GCM_*
|
||||
// passed to whichdata
|
||||
int gcmPrintData(int whichdata, GCM *data)
|
||||
{
|
||||
void *ptr;
|
||||
if ( GCMPieces[whichdata].type == 1) {
|
||||
char *theData = (char *)gcmWhichData(whichdata,data);
|
||||
printf("%-38s:\t %s\n", GCMPieces[whichdata].name, theData);
|
||||
}
|
||||
else {
|
||||
int *theData = (int *)gcmWhichData(whichdata,data);
|
||||
if ( theData ) {
|
||||
printf("%-38s:\t %x\n", GCMPieces[whichdata].name, *theData);
|
||||
}
|
||||
else {
|
||||
printf("%-38s:\t refusing to print NULL pointer...\n",
|
||||
"(untested function/invalid data)"); // this means you're using a feature that doesn't work (yet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print the information for a given file in data (by entry num)
|
||||
int gcmPrintFile(GCM *data, int fnum)
|
||||
{
|
||||
GCM_FSTEntry f;
|
||||
char *fname = NULL;
|
||||
|
||||
// printf("DEBUG : retrieving file data for number %d\n", fnum);
|
||||
f = data->fst.entries.at(fnum);
|
||||
|
||||
// see gcmPrint for how this is laid out...
|
||||
if ( fnum >= data->fst.entries.size() )
|
||||
fname = "(out_of_bounds string)" ;
|
||||
else
|
||||
fname = (char *)data->fst.stringtable.at(fnum)->c_str();
|
||||
|
||||
printf("%-20s%-6d%-6x%-12x%-20d\n",
|
||||
fname,
|
||||
fnum,
|
||||
gcmGetFSTEntryType(&f),
|
||||
f.file_offset,
|
||||
f.file_length);
|
||||
}
|
||||
|
||||
// reads data into dest and returns the number of bytes read
|
||||
// (only used internally by the other gcm functions, this should
|
||||
// be transparent outside the API guts)
|
||||
int gcmGetData(int whichdata, GCM *data, FILE *file)
|
||||
{
|
||||
int offset = 0;
|
||||
void *dest = gcmWhichData(whichdata, data);
|
||||
if ( whichdata > GCM_MAX_PIECES || dest == NULL || file == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch ( GCMPieces[whichdata].area ) {
|
||||
case 0:
|
||||
offset = GCMPieces[whichdata].offset;
|
||||
break;
|
||||
case 1:
|
||||
offset = GCMPieces[GCM_DHEAD].offset + GCMPieces[whichdata].offset;
|
||||
break;
|
||||
case 2:
|
||||
offset = GCMPieces[GCM_DHEADINF].offset + GCMPieces[whichdata].offset;
|
||||
break;
|
||||
case 3:
|
||||
offset = GCMPieces[GCM_APPLOADER].offset + GCMPieces[whichdata].offset;
|
||||
break;
|
||||
case 4:
|
||||
offset = data->fst.offset + GCMPieces[whichdata].offset;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
fseek(file, offset, 0);
|
||||
if ( GCMPieces[whichdata].type == 1 ) {
|
||||
fgets((char *)dest, GCMPieces[whichdata].size, file) == NULL;
|
||||
}
|
||||
else {
|
||||
fread(dest, 1, GCMPieces[whichdata].size, file);
|
||||
int *tmp = (int *)dest;
|
||||
*tmp = byteSwap(*tmp);
|
||||
}
|
||||
rewind(file);
|
||||
return GCMPieces[whichdata].size;
|
||||
}
|
||||
|
||||
// get the file at fnum from file for the GCM data and store it
|
||||
// in entry
|
||||
int gcmGetFile(GCM *data, GCM_FSTEntry *entry, int fnum, FILE *file)
|
||||
{
|
||||
if ( fnum > -1 && file != NULL ) {
|
||||
rewind(file);
|
||||
fseek(file, data->fst.offset + (12 * fnum), 0);
|
||||
|
||||
if ( !feof(file) ) {
|
||||
fread(&entry->fname_offset, 4, 1, file);
|
||||
entry->fname_offset = byteSwap(entry->fname_offset);
|
||||
fread(&entry->file_offset, 4, 1, file);
|
||||
entry->file_offset = byteSwap(entry->file_offset);
|
||||
fread(&entry->file_length, 4, 1, file);
|
||||
entry->file_length = byteSwap(entry->file_length);
|
||||
data->fst.entries.push_back(*entry);
|
||||
}
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
|
||||
// populate the FST of the given GCM from file
|
||||
int gcmPopulateFST(GCM *data, FILE *file)
|
||||
{
|
||||
GCM_FSTEntry *newEntry;
|
||||
GCM_FSTEntry root;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int oldpos = 0;
|
||||
int maxentries = 0;
|
||||
char *tmpbuff = new char[GCNDVD_FNAME_LENGTH];
|
||||
std::string * strdest = new std::string("");
|
||||
char tmp = 0xFF;
|
||||
int f = 0;
|
||||
int *appSize = NULL;
|
||||
|
||||
if ( !tmpbuff ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fseek(file, data->fst.offset, 0);
|
||||
|
||||
// now just loop until there are no more entries...
|
||||
gcmGetFile(data, &root, 0,file);
|
||||
root = data->fst.entries.front();
|
||||
// this is where we inject the filesystem entries for bootloader.bin, apploader.bin,
|
||||
// and game.dol ... these aren't technically part of the filesystem, but we
|
||||
// do this so they can be viewed/extracted like other files.
|
||||
/*
|
||||
appSize = (int *)gcmWhichData(GCM_APPLOADER_SIZE, data);
|
||||
newEntry = new GCM_FSTEntry;
|
||||
newEntry->fname_offset = 0;
|
||||
newEntry->file_offset = GCM_APPLOADER_CODE_LOC;
|
||||
newEntry->file_length = *appSize;
|
||||
newEntry->stringtable_off = 1;
|
||||
data->fst.entries.push_back(*newEntry);
|
||||
delete newEntry;*/
|
||||
for ( int i = 1; i < root.file_length ; i++) {
|
||||
newEntry = new GCM_FSTEntry;
|
||||
gcmGetFile(data, newEntry, i, file);
|
||||
delete newEntry;
|
||||
}
|
||||
|
||||
|
||||
// we're past the FST proper; now the string table...
|
||||
data->fst.stringtable_offset = data->fst.offset + (root.file_length * 12);
|
||||
fseek(file, data->fst.stringtable_offset, 0);
|
||||
//printf("FST string table offset calculated to 0x\%x...\n", data->fst.stringtable_offset);
|
||||
data->fst.stringtable.clear();
|
||||
data->fst.stringtable.push_back(&std::string("/\0"));
|
||||
//data->fst.stringtable.push_back(&std::string("apploader.bin\0"));
|
||||
memset(tmpbuff, GCNDVD_FNAME_LENGTH, 0x00);
|
||||
while ( ftell(file) < (data->fst.offset + data->fst.size) && !feof(file)) {
|
||||
i = 0;
|
||||
while ( 1 ) {
|
||||
tmp = fgetc(file);
|
||||
if ( tmp == 0x00 ) {
|
||||
break;
|
||||
}
|
||||
tmpbuff[i] = tmp;
|
||||
i++;
|
||||
}
|
||||
tmpbuff[i] = '\0';
|
||||
strdest->clear();
|
||||
strdest->reserve(i);
|
||||
strdest->assign(tmpbuff);
|
||||
data->fst.stringtable.push_back(strdest);
|
||||
// printf("DEBUG : FILENAME WAS %s ... added %s\n", strdest,
|
||||
// data->fst.stringtable.at(f+1)->c_str());
|
||||
memset(tmpbuff, GCNDVD_FNAME_LENGTH, 0x00);
|
||||
strdest = new std::string("");
|
||||
f++;
|
||||
}
|
||||
delete tmpbuff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// called inside of gcmInit to make sure everything inside is sane
|
||||
// (only needed internally)
|
||||
int gcmZeroOut(GCM *data)
|
||||
{
|
||||
data->apploader.entry = 0;
|
||||
data->apploader.size = 0;
|
||||
data->apploader.trailersize = 0;
|
||||
data->fst.maxsize = 0;
|
||||
data->fst.offset = 0;
|
||||
data->fst.size = 0;
|
||||
data->head.bootfile = 0;
|
||||
data->head.debugmon = 0;
|
||||
data->head.debugmonaddr = 0;
|
||||
data->head.gamecode = 0;
|
||||
data->head.gamemaker = 0;
|
||||
data->head.magicword = 0;
|
||||
data->head.userlen = 0;
|
||||
data->head.userpos = 0;
|
||||
data->headInf.argoff = 0;
|
||||
data->headInf.countrycode = 0;
|
||||
data->headInf.debugflag = 0;
|
||||
data->headInf.debugmonsize = 0;
|
||||
data->headInf.simmemsize = 0;
|
||||
data->headInf.tracklocation = 0;
|
||||
data->headInf.tracksize = 0;
|
||||
}
|
||||
|
||||
// reads all info from the GCM in gcmname and puts it in data
|
||||
int gcmInit(char *gcmname, GCM *data)
|
||||
{
|
||||
FILE *gcm = fopen(gcmname, "r+b");
|
||||
int i = 0;
|
||||
|
||||
if (!gcm) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gcmZeroOut(data);
|
||||
|
||||
switch ( gcmCheckMagic(gcm) ) {
|
||||
case 0:
|
||||
needByteSwap = 1;
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
case -1:
|
||||
//printf("DEBUG: DVD Magic number on GCM image was incorrect or couldn't be understood!\n");
|
||||
//printf("DEBUG: Aborting in GCMInit! (filename %s)\n", gcmname);
|
||||
fclose(gcm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for ( i = 3; i < GCM_MAX_PIECES ; i++) {
|
||||
gcmGetData(i,data, gcm);
|
||||
}
|
||||
|
||||
gcmPopulateFST(data, gcm);
|
||||
|
||||
fclose(gcm);
|
||||
|
||||
data->fname = new char[strlen(gcmname)+1];
|
||||
if ( !data->fname ) {
|
||||
printf("couldn't store GCM filename for later retrieval. Aborting.\n");
|
||||
gcmFreeStringTable(data);
|
||||
exit(-1);
|
||||
}
|
||||
else strcpy(data->fname, gcmname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// print all information about the GCM in a columnar format,
|
||||
// including the FST.
|
||||
int gcmPrint(GCM *data)
|
||||
{
|
||||
int ml = 0;
|
||||
int i = 0;
|
||||
|
||||
for (i = 3; i < GCM_MAX_PIECES; i++ ) {
|
||||
gcmPrintData(i,data);
|
||||
}
|
||||
|
||||
GCM_FSTEntry root = data->fst.entries.front();
|
||||
|
||||
printf("%-38s:\t%d\n", "Total files in the FST", root.file_length);
|
||||
printf("%-38s:\t%d\n", "Total entries in the FST string table", data->fst.stringtable.size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gcmPrintFST(GCM *data)
|
||||
{
|
||||
int ml = 0;
|
||||
int i = 0;
|
||||
char *tbuff = new char[GCNDVD_FNAME_LENGTH];
|
||||
if (!tbuff) {
|
||||
printf("Couldn't get temporary buffer for full path printing. Aborting.\n");
|
||||
return -1;
|
||||
} else {
|
||||
memset(tbuff, 0x00, GCNDVD_FNAME_LENGTH);
|
||||
}
|
||||
|
||||
GCM_FSTEntry root = data->fst.entries.front();
|
||||
printf("%-38s:\t%d\n", "Total files in the FST", root.file_length);
|
||||
printf("%-38s:\t%d\n", "Total entries in the FST string table", data->fst.stringtable.size());
|
||||
printf("\n\n\n%30s\n", "(FST CONTENTS)");
|
||||
printf("%-16s %-6s %-6s %s %-12s\n",
|
||||
"(name)", "(fnum)", "(type)", "(offset)", "(length)");
|
||||
for (i = 0; i < data->fst.entries.size() - 1 ; i++) {
|
||||
//printf("DEBUG: retrieving file data for number %d\n", i);
|
||||
gcmPrintFile(data, i);
|
||||
}
|
||||
|
||||
printf("\n\t\t\t(PRINTING FILES WITH FULL PATH)\n");
|
||||
for (i = 0; i < data->fst.entries.size() - 1; i++ ) {
|
||||
printf("File %d:", i);
|
||||
gcmGetFullFileName(data, i, tbuff);
|
||||
printf(" %s\n", tbuff);
|
||||
memset(tbuff, 0x00, GCNDVD_FNAME_LENGTH);
|
||||
}
|
||||
|
||||
delete tbuff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// frees memory used by the string table. MUST be called before zeroing
|
||||
// the gcm for new reading (gcmInit) or quitting the application.
|
||||
// This should be accompanied by clearing the entries vector, though the
|
||||
// destructor in that member should take care of cleanup for you.
|
||||
// Thou shalt not leak memory!
|
||||
|
||||
int gcmFreeStringTable(GCM *data)
|
||||
{
|
||||
std::string *string = NULL;
|
||||
int i = 0;
|
||||
|
||||
//printf("freeing memory used by FST string table... ");
|
||||
|
||||
for (i = 0; i < (data->fst.stringtable.size()) ; i++ ) {
|
||||
string = (std::string *)data->fst.stringtable.at(i);
|
||||
// we create the "/" entry for 0 manually, and it's not alloc'ed
|
||||
// so don't try freeing it!
|
||||
if ( string != NULL && i > 0 ) {
|
||||
delete string;
|
||||
}
|
||||
string = NULL;
|
||||
}
|
||||
data->fst.stringtable.clear();
|
||||
delete data->fname;
|
||||
|
||||
//printf(" ...done.\n");
|
||||
}
|
||||
|
||||
GCM_FSTEntry gcmGetFileByFnum(GCM *data, int fnum)
|
||||
{
|
||||
return data->fst.entries.at(fnum);
|
||||
}
|
||||
|
||||
int gcmGetFileByOffset(GCM *data, int offset)
|
||||
{
|
||||
GCM_FSTEntry curr;
|
||||
bool done = false;
|
||||
|
||||
for (int i = 0; i < data->fst.entries.size() -1; i++) {
|
||||
curr = data->fst.entries.at(i);
|
||||
if (curr.file_offset == offset) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// takes in a full pathname and retrieves the fnum
|
||||
// for the appropriate file in the FST
|
||||
unsigned int gcmGetFileByName(GCM *data, char *name)
|
||||
{
|
||||
GCM_FSTEntry curr;
|
||||
bool done = false;
|
||||
int nextStart = 0;
|
||||
int i = 0;
|
||||
char *tmp2 = (char *) new char[GCNDVD_FNAME_LENGTH];
|
||||
if ( !tmp2 ) {
|
||||
fprintf(stderr, "Failed to allocate temporary string storage\n");
|
||||
return -1;
|
||||
}
|
||||
for ( i = 0; i < data->fst.stringtable.size() ; i++ ) {
|
||||
gcmGetFullFileName(data, i, tmp2);
|
||||
//printf("DEBUG : comparing filename %s to original %s...\n", name, tmp2);
|
||||
if ( !strcmp(name, tmp2) ) {
|
||||
delete tmp2;
|
||||
//printf("DEBUG : found filename %s at number %d", name, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
delete tmp2;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// extracts a file into outfile from the GCM given the fnum.
|
||||
// FIXME : allow the user to specify a different output filename?
|
||||
unsigned int gcmExtractFile(GCM *data, int fnum, char *outfname)
|
||||
{
|
||||
FILE *out = NULL;
|
||||
FILE *gcm = NULL;
|
||||
int pos = 0;
|
||||
int endpos = 0;
|
||||
int b = 0;
|
||||
GCM_FSTEntry curr;
|
||||
std::string execstring = "";
|
||||
char *outfile = NULL;
|
||||
std::string tmpStr = "";
|
||||
|
||||
// check that the fnum is in range
|
||||
|
||||
if ( fnum < data->fst.entries.size() - 1) {
|
||||
curr = data->fst.entries.at(fnum);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if it's a file, open the outfile, open the GCM, and perform the copy - clean up and exit
|
||||
if ( gcmGetFSTEntryType(&curr) == 0 ) {
|
||||
if ( outfname ) {
|
||||
outfile = outfname;
|
||||
tmpStr = "";
|
||||
} else {
|
||||
outfile = new char[GCNDVD_FNAME_LENGTH];
|
||||
if ( !outfile ) return -1;
|
||||
else gcmGetFullFileName(data, fnum, outfile);
|
||||
tmpStr = ".";
|
||||
}
|
||||
tmpStr.append(outfile);
|
||||
gcm = fopen(data->fname, "rb");
|
||||
out = fopen(tmpStr.c_str(), "wb");
|
||||
if ( !gcm || !out ) {
|
||||
gcm ? fclose(gcm) : printf("Couldn't read from gcm file\n");
|
||||
out ? fclose(out) : printf("Couldn't write to output file\n");
|
||||
return -1;
|
||||
}
|
||||
fseek(gcm, curr.file_offset, 0);
|
||||
endpos = curr.file_offset + curr.file_length;
|
||||
if ( ftell(gcm) != curr.file_offset || !out || !gcm) {
|
||||
delete outfile;
|
||||
fclose(gcm);
|
||||
fclose(out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ( !feof(gcm) && ftell(gcm) <= endpos) {
|
||||
fread(&b, 1, 1, gcm);
|
||||
if ( needByteSwap == 1 ) b = byteSwap(b); // swap the bytes for the host
|
||||
fwrite(&b, 1, 1, out);
|
||||
}
|
||||
|
||||
if ( outfile && !outfname )delete outfile;
|
||||
fclose(gcm);
|
||||
fclose(out);
|
||||
printf("exploded %s\n", tmpStr.c_str());
|
||||
return 0;
|
||||
}
|
||||
// if it's a dir, construct the mkdir command, do it, clean up and exit.
|
||||
else {
|
||||
if ( outfname )
|
||||
outfile = outfname;
|
||||
else {
|
||||
outfile = new char[GCNDVD_FNAME_LENGTH];
|
||||
if (!outfile ) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
gcmGetFullFileName(data, fnum, outfile);
|
||||
if ( !outfname )
|
||||
execstring.append("mkdir -p .");
|
||||
else
|
||||
execstring.append("mkdir -p ");
|
||||
execstring.append(outfile);
|
||||
int retcode = system(execstring.c_str());
|
||||
if ( outfile && !outfname ) delete outfile;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// explodes the FST onto the host filesystem
|
||||
int gcmExplode(GCM *data)
|
||||
{
|
||||
for ( int i = 0; i <= (data->fst.entries.size() - 1) ; i++ ) {
|
||||
if ( gcmExtractFile(data, i, NULL) < 0 ) return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// retrieves the full filename for fnum with full path
|
||||
int gcmGetFullFileName(GCM *data, int fnum, char *dest)
|
||||
{
|
||||
bool finished = false;
|
||||
GCM_FSTEntry curr;
|
||||
std::vector<int> fnames;
|
||||
int fn = fnum;
|
||||
int depth = 0;
|
||||
std::string work = "";
|
||||
|
||||
curr = data->fst.entries.at(fn);
|
||||
|
||||
while (!finished) {
|
||||
depth++;
|
||||
if ( depth > data->fst.entries.size() - 1) {
|
||||
printf("went too far. aborting.\n");
|
||||
exit(-1);
|
||||
}
|
||||
if ( fn == 0 ) {
|
||||
fnames.push_back(0);
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
if ( gcmGetFSTEntryType(&curr) == 0 ) {
|
||||
// file
|
||||
fnames.push_back(fn);
|
||||
while (gcmGetFSTEntryType(&curr) == 0) {
|
||||
// search up for the parent directory....
|
||||
curr = data->fst.entries.at(fn - 1);
|
||||
fn -= 1;
|
||||
}
|
||||
}
|
||||
else if ( gcmGetFSTEntryType(&curr) == 1) {
|
||||
// directory
|
||||
fnames.push_back(fn);
|
||||
fn = curr.file_offset;
|
||||
curr = data->fst.entries.at(fn);
|
||||
}
|
||||
}
|
||||
|
||||
if ( fnum != 0 ) {
|
||||
for (int i = fnames.size() -1 ; i >= 0; i--) {
|
||||
if ( i < fnames.size()-1 ) {
|
||||
work.append("/");
|
||||
}
|
||||
if ( fnames.at(i) != 0 ) work.append(data->fst.stringtable.at(fnames.at(i))->c_str());
|
||||
}
|
||||
} else work = "/";
|
||||
strcpy(dest, work.c_str());
|
||||
return 0;
|
||||
}
|
||||
217
source/.svn/text-base/gcminfo.h.svn-base
Executable file
217
source/.svn/text-base/gcminfo.h.svn-base
Executable file
@@ -0,0 +1,217 @@
|
||||
// thanks to groepaz and everyone else who wrote YAGCD, most of my info came from it
|
||||
// also thanks to WntrMute for loaning me some source to clear things up about the FST
|
||||
|
||||
// (C) 2005 Andrew K andrew@aklabs.net
|
||||
// License: Take all you want, but credit for all you take.
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define LIBGCMVERSION "libGCM Version 0.1a (build Sep 4 2005)"
|
||||
|
||||
// defines for internal program control (not necessarily GCM-related)
|
||||
|
||||
#define GCNDVD_MAGICNUM 0xc2339f3d // if this isn't correct in the GCM,
|
||||
// the program will abort.
|
||||
|
||||
#define GCNDVD_SECTORS 712880 // not really used, but left for future updates that might use it
|
||||
#define GCNDVD_SECTORSIZE 2048 // " "
|
||||
#define GCNDVD_FNAME_LENGTH 1024
|
||||
|
||||
|
||||
#define GCM_MAX_PIECES 29 // change this if (for whatever reason) you add a new entry in GCMPieces
|
||||
|
||||
// these all define indices in the GCMPieces global array where
|
||||
// information about (where to look in the GCM for) a given piece
|
||||
// of data about the GCM can be found. The rationale should
|
||||
// be easy enough to follow.
|
||||
#define GCM_DHEAD 0
|
||||
#define GCM_DHEADINF 1
|
||||
#define GCM_APPLOADER 2
|
||||
|
||||
#define GCM_DHEAD_GAMECODE 3
|
||||
#define GCM_DHEAD_GAMEMAKER 4
|
||||
#define GCM_DHEAD_DVDMAGIC 5
|
||||
#define GCM_DHEAD_GAMENAME 6
|
||||
#define GCM_DHEAD_DEBUGMON 7
|
||||
#define GCM_DHEAD_DEBUGMONADDR 8
|
||||
#define GCM_DHEAD_BOOTFILE 9
|
||||
#define GCM_DHEAD_FST 10
|
||||
#define GCM_DHEAD_FSTSIZE 11
|
||||
#define GCM_DHEAD_FSTMAXSIZE 12
|
||||
#define GCM_DHEAD_USERPOS 13
|
||||
#define GCM_DHEAD_USERLEN 14
|
||||
|
||||
#define GCM_DHEADINF_DEBUGMONSIZE 15
|
||||
#define GCM_DHEADINF_SIMMEMSIZE 16
|
||||
#define GCM_DHEADINF_ARGOFFSET 17
|
||||
#define GCM_DHEADINF_DEBUGFLAG 18
|
||||
#define GCM_DHEADINF_TRACKLOCATION 19
|
||||
#define GCM_DHEADINF_TRACKSIZE 20
|
||||
#define GCM_DHEADINF_COUNTRYCODE 21
|
||||
|
||||
#define GCM_APPLOADER_VERSION 22
|
||||
#define GCM_APPLOADER_ENTRY 23
|
||||
#define GCM_APPLOADER_SIZE 24
|
||||
#define GCM_APPLOADER_TRAILERSIZE 25
|
||||
#define GCM_APPLOADER_BINARY 26
|
||||
#define GCM_APPLOADER_CODE_LOC 0x2450
|
||||
|
||||
#define GCM_FST_ROOT 28
|
||||
#define GCM_FST_STRINGTABLEOFF 29
|
||||
|
||||
typedef struct {
|
||||
int area; // 0 = basic structure, 1 = header, 2= header info, 3 = apploader, 4 = FST
|
||||
char *name;
|
||||
long offset;
|
||||
long size;
|
||||
int type; // 1 for string, 0 for numeric value (strings aren't byteswapped)
|
||||
} GCMPiece;
|
||||
|
||||
// pieces with area 1 add the base of the disk header to their offset
|
||||
// pieces with area 2 add the base of the disk header info to their offset
|
||||
// pieces with area 3 add the base of the apploader to their offset
|
||||
// pieces with area 4 add the base of the FST to their offset (garnered from the disk header)
|
||||
static GCMPiece GCMPieces [] ={
|
||||
// root disc pieces
|
||||
{0, "Disk Header (boot.bin)", 0x00000000, 0x0440, 0},
|
||||
{0, "Disk Header Information (bi2.bin)", 0x00000440, 0x2000, 0},
|
||||
{0, "Apploader (appldr.bin)", 0x00002440, 0x2000, 0}, // 0x2000 size is an estimate I think
|
||||
// disk header
|
||||
{1, "Game code", 0x0000, 0x0004, 0},
|
||||
{1, "Game maker code", 0x0004, 0x0002, 0},
|
||||
{1, "DVD Magic Word", 0x001c, 0x0004, 0},
|
||||
{1, "Game name", 0x0020, 0x03e0, 1},
|
||||
{1, "Debug monitor offset", 0x0400, 0x0004, 0},
|
||||
{1, "Debug monitor load address", 0x0404, 0x0004, 0},
|
||||
{1, "Bootfile offset", 0x0420, 0x0004, 0},
|
||||
{1, "FST offset", 0x0424, 0x0004, 0},
|
||||
{1, "FST size", 0x0428, 0x0004, 0},
|
||||
{1, "FST Max Size", 0x042c, 0x0004, 0},
|
||||
{1, "User position", 0x0430, 0x0004, 0},
|
||||
{1, "User length", 0x0434, 0x0004, 0},
|
||||
|
||||
// the disk header info is loaded to 0x800000f4 when the disc is loaded by the IPL (tho we're reading it straight
|
||||
// out of the .gcm image, so YMMV)
|
||||
{2, "Debug-monitor size", 0x0000, 0x0004, 0},
|
||||
{2, "Simulated memory size", 0x0004, 0x0004, 0},
|
||||
{2, "Argument offset", 0x0008, 0x0004, 0},
|
||||
{2, "Debug flag", 0x000c, 0x0004, 0},
|
||||
{2, "Track location", 0x0010, 0x0004, 0},
|
||||
{2, "Track size", 0x0014, 0x0004, 0},
|
||||
{2, "Countrycode", 0x0018, 0x0004, 0},
|
||||
|
||||
// apploader header info
|
||||
{3, "Version/Date", 0x0000, 0x000F, 1}, // don't include the padding in the date
|
||||
{3, "Apploader entry point", 0x0010, 0x0004, 0},
|
||||
{3, "Apploader size", 0x0014, 0x0004, 0},
|
||||
{3, "Trailer size", 0x0018, 0x0004, 0},
|
||||
{3, "Apploader binary", 0x0020, 0, 1}, // no length given - taken from the "apploader size"
|
||||
|
||||
// FST info
|
||||
{4, "Root directory entry", 0x00, 0x0c, 0},
|
||||
{4, "FST String table offset", 0x0008, 0x0004, 0}
|
||||
|
||||
};
|
||||
|
||||
// primary GCM disk header
|
||||
typedef struct GCM_DiskHeader{
|
||||
int gamecode;
|
||||
int gamemaker;
|
||||
int magicword;
|
||||
char gamename[0x03e0];
|
||||
int debugmon;
|
||||
int debugmonaddr;
|
||||
int bootfile;
|
||||
int userpos;
|
||||
int userlen;
|
||||
};
|
||||
|
||||
// the GCM disk header additional info
|
||||
typedef struct GCM_DiskHeaderInfo {
|
||||
int debugmonsize;
|
||||
int simmemsize;
|
||||
int argoff;
|
||||
int debugflag;
|
||||
int tracklocation;
|
||||
int tracksize;
|
||||
int countrycode;
|
||||
};
|
||||
|
||||
// information about the apploader on the GCM
|
||||
typedef struct GCM_ApploaderInfo{
|
||||
char datever[10];
|
||||
int entry;
|
||||
int size;
|
||||
int trailersize;
|
||||
char apploader[0x200]; // actual apploader data
|
||||
};
|
||||
|
||||
// information about a particular file in the FST
|
||||
typedef struct GCM_FSTEntry {
|
||||
int fname_offset; // offset into the FST string table for the filename
|
||||
// the offset is only actually 3 bytes, but
|
||||
// we're only reading, not writing so it doesn't matter
|
||||
// if we're grande sized ....
|
||||
// the first byte of fname_offset is actually the flags of the file; 0: file 1: dir
|
||||
int file_offset; // if this is a directory, this is actually the offset of the parent
|
||||
int file_length; // actually the number of entries (root) or next_offset (dir)
|
||||
int stringtable_off; // offset in the string table
|
||||
};
|
||||
|
||||
// information about the names and locations of files in the GCM
|
||||
typedef struct GCM_FST {
|
||||
int size;
|
||||
int offset;
|
||||
int stringtable_offset;
|
||||
int maxsize;
|
||||
std::vector <GCM_FSTEntry>entries; // list of entries
|
||||
std::vector <std::string *>stringtable; // string table
|
||||
};
|
||||
|
||||
// GCM image data structure
|
||||
typedef struct GCM {
|
||||
GCM_DiskHeader head;
|
||||
GCM_DiskHeaderInfo headInf;
|
||||
GCM_ApploaderInfo apploader;
|
||||
GCM_FST fst;
|
||||
char *fname;
|
||||
};
|
||||
|
||||
// these are just the functions that the user would need beyond
|
||||
// the functionality provided by gcmInit's loader; more internal
|
||||
// functions can be found inside gcminfo.c
|
||||
|
||||
// returns 0 for a regular file, 1 for a directory
|
||||
extern int gcmGetFSTEntryType(GCM_FSTEntry *entry);
|
||||
// initialises the GCM data structures with FST and such;
|
||||
extern int gcmInit(char *gcmname, GCM *data);
|
||||
// prints a given portion of the GCM data
|
||||
// whichdata should be an indice into the GCMPieces array
|
||||
extern int gcmPrintData(int whichdata, GCM *data);
|
||||
// prints all the data in the GCM in a (fairly) columnar format
|
||||
extern int gcmPrint(GCM *data);
|
||||
// prints a comprehensive listing of all files in the GCM
|
||||
extern int gcmPrintFST(GCM *data);
|
||||
// retrieves a given file and puts it in the FST entries,
|
||||
// given the fnum
|
||||
extern int gcmGetFile(GCM *data, GCM_FSTEntry *entry, int fnum, FILE *file);
|
||||
// prints information for a given fname
|
||||
extern int gcmPrintFile(GCM *data, int fnum);
|
||||
// frees all data in the FST stringtable
|
||||
extern int gcmFreeStringTable(GCM *data);
|
||||
// extracts a file, given the fnum, into the current dir, unless outfname is specified
|
||||
extern unsigned int gcmExtractFile(GCM *data, int fnum, char *outfname);
|
||||
// puts the full filename (with path) into dest, given fnum
|
||||
extern int gcmGetFullFileName(GCM *data, int fnum, char *dest);
|
||||
// returns the fnum of a given file by its offset
|
||||
extern int gcmGetFileByOffset(GCM *data, int offset);
|
||||
// returns the fnum of a given file by its full pathname
|
||||
extern unsigned int gcmGetFileByName(GCM *data, char *name);
|
||||
// returns the actual entry of a file given its fnum
|
||||
extern GCM_FSTEntry gcmGetFileByFnum(GCM *data, int fnum);
|
||||
// explodes the FST onto the host filesystem in the current directory
|
||||
extern int gcmExplode(GCM *data);
|
||||
1709
source/.svn/text-base/sample-output.txt.svn-base
Executable file
1709
source/.svn/text-base/sample-output.txt.svn-base
Executable file
File diff suppressed because it is too large
Load Diff
13
source/.svn/text-base/std_disclaimer.h.svn-base
Executable file
13
source/.svn/text-base/std_disclaimer.h.svn-base
Executable file
@@ -0,0 +1,13 @@
|
||||
/* What you are seeing is a work in progress. Source and comments
|
||||
it contains could be dangerous, profane, or just plain wrong.
|
||||
While I generally don't publish source code unless I feel it's in
|
||||
a semi-production state (or at least to the point where someone
|
||||
somewhere could benefit from it), I can't guarantee anything.
|
||||
|
||||
If you use this code and the genie of your computer (or your cube!) escapes in
|
||||
a puff of smoke, I will not be held liable. You have been warned.
|
||||
This code may be ugly, incomplete, or just plain wrong.
|
||||
|
||||
No F'in warranty implied!
|
||||
|
||||
Andrew K 2005 andrew@aklabs.net */
|
||||
23
source/CVS/.svn/all-wcprops
Executable file
23
source/CVS/.svn/all-wcprops
Executable file
@@ -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
|
||||
130
source/CVS/.svn/entries
Executable file
130
source/CVS/.svn/entries
Executable file
@@ -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
|
||||
|
||||
8
source/CVS/.svn/text-base/Entries.svn-base
Executable file
8
source/CVS/.svn/text-base/Entries.svn-base
Executable file
@@ -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
|
||||
1
source/CVS/.svn/text-base/Repository.svn-base
Executable file
1
source/CVS/.svn/text-base/Repository.svn-base
Executable file
@@ -0,0 +1 @@
|
||||
utils/gcmbrowser/source
|
||||
1
source/CVS/.svn/text-base/Root.svn-base
Executable file
1
source/CVS/.svn/text-base/Root.svn-base
Executable file
@@ -0,0 +1 @@
|
||||
andrew@gabbo:/home/cvsd
|
||||
8
source/CVS/Entries
Executable file
8
source/CVS/Entries
Executable file
@@ -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
|
||||
1
source/CVS/Repository
Executable file
1
source/CVS/Repository
Executable file
@@ -0,0 +1 @@
|
||||
utils/gcmbrowser/source
|
||||
1
source/CVS/Root
Executable file
1
source/CVS/Root
Executable file
@@ -0,0 +1 @@
|
||||
andrew@gabbo:/home/cvsd
|
||||
94
source/Makefile
Executable file
94
source/Makefile
Executable file
@@ -0,0 +1,94 @@
|
||||
# Visual SlickEdit generated file. Do not edit this file except in designated areas.
|
||||
# -----Begin user-editable area-----
|
||||
|
||||
# -----End user-editable area-----
|
||||
|
||||
# Make command to use for dependencies
|
||||
MAKECMD=gmake
|
||||
|
||||
# If no configuration is specified, "Debug" will be used
|
||||
ifndef "CFG"
|
||||
CFG=Debug
|
||||
endif
|
||||
|
||||
#
|
||||
# Configuration: Debug
|
||||
#
|
||||
ifeq "$(CFG)" "Debug"
|
||||
OUTDIR=Debug
|
||||
OUTFILE=$(OUTDIR)/gcmbrowser
|
||||
CFG_INC=
|
||||
CFG_LIB=
|
||||
CFG_OBJ=
|
||||
COMMON_OBJ=$(OUTDIR)/gcmbrowser.o
|
||||
OBJ=$(COMMON_OBJ) $(CFG_OBJ)
|
||||
|
||||
COMPILE=g++ -c -g -o "$(OUTDIR)/$(*F).o" $(CFG_INC) "$<"
|
||||
LINK=g++ -g -o "$(OUTFILE)" $(OBJ) $(CFG_LIB)
|
||||
|
||||
# Pattern rules
|
||||
$(OUTDIR)/%.o : source/%.cpp
|
||||
$(COMPILE)
|
||||
|
||||
# Build rules
|
||||
all: $(OUTFILE)
|
||||
|
||||
$(OUTFILE): $(OUTDIR) $(OBJ)
|
||||
$(LINK)
|
||||
|
||||
$(OUTDIR):
|
||||
mkdir -p "$(OUTDIR)"
|
||||
|
||||
# Rebuild this project
|
||||
rebuild: cleanall all
|
||||
|
||||
# Clean this project
|
||||
clean:
|
||||
rm -f source/*o
|
||||
rm -f $(CFG)/*o
|
||||
rm -f $(OUTFILE)
|
||||
|
||||
# Clean this project and all dependencies
|
||||
cleanall: clean
|
||||
endif
|
||||
|
||||
#
|
||||
# Configuration: Release
|
||||
#
|
||||
ifeq "$(CFG)" "Release"
|
||||
OUTDIR=Release
|
||||
OUTFILE=$(OUTDIR)/gcmbrowser
|
||||
CFG_INC=
|
||||
CFG_LIB=
|
||||
CFG_OBJ=
|
||||
COMMON_OBJ=$(OUTDIR)/gcmbrowser.o
|
||||
OBJ=$(COMMON_OBJ) $(CFG_OBJ)
|
||||
|
||||
COMPILE=g++ -c -o "$(OUTDIR)/$(*F).o" $(CFG_INC) "$<"
|
||||
LINK=g++ -o "$(OUTFILE)" $(OBJ) $(CFG_LIB)
|
||||
|
||||
# Pattern rules
|
||||
$(OUTDIR)/%.o : source/%.cpp
|
||||
$(COMPILE)
|
||||
|
||||
# Build rules
|
||||
all: $(OUTFILE)
|
||||
|
||||
$(OUTFILE): $(OUTDIR) $(OBJ)
|
||||
$(LINK)
|
||||
|
||||
$(OUTDIR):
|
||||
mkdir -p "$(OUTDIR)"
|
||||
|
||||
# Rebuild this project
|
||||
rebuild: cleanall all
|
||||
|
||||
# Clean this project
|
||||
clean:
|
||||
rm -f source/*o
|
||||
rm -f $(CFG)/*o
|
||||
rm -f $(OUTFILE)
|
||||
|
||||
# Clean this project and all dependencies
|
||||
cleanall: clean
|
||||
endif
|
||||
26
source/README.txt
Executable file
26
source/README.txt
Executable file
@@ -0,0 +1,26 @@
|
||||
This is libgcm V0.1a, an early alpha of my library for
|
||||
manipulating gamecube master files. It currently has
|
||||
little functionality, but you can list and extract the contents
|
||||
of GCMs - the only thing I haven't got extracting correctly
|
||||
yet is the apploader stuff, because I haven't even really
|
||||
begun working on that yet, and don't know how to really test
|
||||
the results of that extraction.
|
||||
|
||||
Before this is over, I intend to have the library
|
||||
ready to insert, append, and create entire new images for
|
||||
burning to a GCM. My final test of this ability will be to
|
||||
completely unpack a disc image onto the drive (which it can
|
||||
already do, with the exception of the apploader) and re-pack
|
||||
it and see if it plays.
|
||||
|
||||
Maybe someone will be helped by this code. GPL applies.
|
||||
This code is free as in freedom. If you have any additions you
|
||||
would like to see in the next release, I'd be happy to include them,
|
||||
with credit. Just email them to me or find me in #gcdev on EFNet.
|
||||
|
||||
Enjoy!
|
||||
Andrew K
|
||||
andrew@aklabs.net
|
||||
andrewk in #gcdev on EFNet
|
||||
120817314 ICQ
|
||||
|
||||
163
source/gcmbrowser.cpp
Executable file
163
source/gcmbrowser.cpp
Executable file
@@ -0,0 +1,163 @@
|
||||
#include "gcminfo.h"
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// All the interesting stuff is in gcminfo.c|h ; gcmbrowser.cpp is just a proof
|
||||
// and simple util.
|
||||
|
||||
const char *usage =
|
||||
"gcmbrowser V0.01 (C) 2005 Andrew Kesterson (andrew@aklabs.net) \n\
|
||||
\n\
|
||||
Usage: gcmbrowser <.gcm file> <operation>\n\
|
||||
\n\
|
||||
operations:\n\
|
||||
-h : print this help\n\
|
||||
-H : print the disk header (maker, title, etc)\n\
|
||||
-E : explode the filesystem into the current directory\n\
|
||||
-e <file> : extract \"file\" from the gcm. With -o you\n\
|
||||
may specify an optional output filename; by default,\n\
|
||||
the file will be named the same (and reside in the\n\
|
||||
same directory tree) as in the image. You may specify\n\
|
||||
the source file by file number or by filename (full path\n\
|
||||
is necessary when specifying by filename.)\n\
|
||||
-o <filename> : specify the destination for a -e operation.\n\
|
||||
-l : list the names and file numbers of all files in the GCM.\n\
|
||||
All files are printed with full path.\n\
|
||||
-d : when extracting a file, create all needed directories for\n\
|
||||
the output file. This can, but really shouldn't, be used with\n\
|
||||
the -o option.\n\
|
||||
\n";
|
||||
|
||||
const char *shortopts = "hHEe:o:ld";
|
||||
|
||||
#define OP_PRINT_HEADER 0
|
||||
#define OP_EXPLODE 2
|
||||
#define OP_EXTRACT 4
|
||||
#define OP_LIST 8
|
||||
#define OP_CREATE_DIRS 1024
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
std::string gcmFname;
|
||||
std::string outFname;
|
||||
std::string extractFname;
|
||||
unsigned int extractFnumber= -1;
|
||||
int outIsDigit = 1;
|
||||
int ctr = 0;
|
||||
int op = 0;
|
||||
GCM theGCM;
|
||||
unsigned int opt = 0;
|
||||
unsigned int ret = 0;
|
||||
|
||||
if ( argc < 2 ) {
|
||||
fprintf(stderr, usage);
|
||||
return 1;
|
||||
}
|
||||
|
||||
opt = getopt(argc, argv, shortopts);
|
||||
while ( opt != -1) {
|
||||
switch ( opt ){
|
||||
case 'h':
|
||||
fprintf(stderr, usage);
|
||||
return 1;
|
||||
case 'H':
|
||||
op = OP_PRINT_HEADER;
|
||||
break;
|
||||
case 'E':
|
||||
op = OP_EXPLODE;
|
||||
break;
|
||||
case 'e':
|
||||
op = OP_EXTRACT;
|
||||
for ( ctr = 0; ctr < strlen(optarg) ; ctr++ ) {
|
||||
if ( isprint(optarg[ctr]) && !isdigit(optarg[ctr])) {
|
||||
outIsDigit = 0;
|
||||
} else {
|
||||
//printf("DEBUG : extract filename character %c is a digit\n", optarg[ctr]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ( outIsDigit == 0 ) {
|
||||
//printf("DEBUG : extract filename option is NON-DIGIT %s\n", optarg);
|
||||
extractFname.reserve(strlen(optarg));
|
||||
extractFname.assign(optarg);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
//printf("DEBUG : extract filename option is file number %s\n", optarg);
|
||||
extractFnumber = atoi(optarg);
|
||||
break;
|
||||
}
|
||||
case 'o':
|
||||
outFname.reserve(strlen(optarg));
|
||||
outFname.assign(optarg);
|
||||
break;
|
||||
case 'l':
|
||||
op = OP_LIST;
|
||||
break;
|
||||
case 'd':
|
||||
op |= OP_CREATE_DIRS;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "I don't understand option -%c\n", opt);
|
||||
return 1;
|
||||
}
|
||||
opt = getopt(argc, argv, shortopts);
|
||||
}
|
||||
gcmFname.reserve(strlen(argv[optind]));
|
||||
gcmFname.assign(argv[optind]);
|
||||
|
||||
if ( gcmInit((char *)gcmFname.c_str(), &theGCM) ) {
|
||||
printf("Couldn't init GCM file %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int top = 0;
|
||||
if ( op & OP_CREATE_DIRS ) top = op ^ OP_CREATE_DIRS;
|
||||
else top = op;
|
||||
switch ( top ) {
|
||||
case OP_EXPLODE:
|
||||
ret = gcmExplode(&theGCM);
|
||||
if ( ! ret )
|
||||
fprintf(stderr, "Failed to explode filesystem.\n");
|
||||
break;
|
||||
case OP_EXTRACT:
|
||||
if ( extractFnumber == -1 ) {
|
||||
//printf("DEBUG : getting file number for %s\n", extractFname.c_str());
|
||||
extractFnumber = gcmGetFileByName(&theGCM, (char *)extractFname.c_str());
|
||||
//printf("DEBUG: got %d\n", extractFnumber);
|
||||
}
|
||||
if ( extractFnumber > theGCM.fst.stringtable.size() || extractFnumber == -1) {
|
||||
fprintf(stderr, "File number %d requested was beyond the length of the filesystem\n", extractFnumber);
|
||||
break;
|
||||
}
|
||||
if ( outFname.length() == 0 && ( op & OP_CREATE_DIRS ) ) {
|
||||
char *outfile = (char *) new char[GCNDVD_FNAME_LENGTH];
|
||||
gcmGetFullFileName(&theGCM, extractFnumber, outfile);
|
||||
std::string execstring = "";
|
||||
// this is a quick hack to ensure that the output directory exists
|
||||
execstring.append("mkdir -p .");
|
||||
execstring.append("`dirname ");
|
||||
execstring.append(outfile);
|
||||
execstring.append("`");
|
||||
system(execstring.c_str());
|
||||
delete outfile;
|
||||
}
|
||||
if ( outFname.length() > 0 )
|
||||
ret = gcmExtractFile(&theGCM, extractFnumber, (char *)outFname.c_str());
|
||||
else
|
||||
ret = gcmExtractFile(&theGCM, extractFnumber, NULL);
|
||||
if ( ret != 0 )
|
||||
fprintf(stderr, "Failed to extract file number %d to output file %s\n", extractFnumber, outFname.length() > 0 ? (char *)outFname.c_str() : "" );
|
||||
break;
|
||||
case OP_PRINT_HEADER:
|
||||
ret = gcmPrint(&theGCM);
|
||||
break;
|
||||
case OP_LIST:
|
||||
ret = gcmPrintFST(&theGCM);
|
||||
break;
|
||||
}
|
||||
|
||||
gcmFreeStringTable(&theGCM);
|
||||
|
||||
return ret;
|
||||
}
|
||||
674
source/gcminfo.cpp
Executable file
674
source/gcminfo.cpp
Executable file
@@ -0,0 +1,674 @@
|
||||
#include "gcminfo.h"
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
int needByteSwap = 0;
|
||||
|
||||
// these are functions that the user really doesn't need to see,
|
||||
// so they're declared here away from the external API. They're
|
||||
// used mainly for populating the internal FST data structure.
|
||||
// All the user-necessary functions are listed out in gcminfo.h.
|
||||
|
||||
int gcmPopulateFST(GCM *data, FILE *file);
|
||||
void *gcmWhichData(int whichdata, GCM *data);
|
||||
int gcmGetData(int whichdata, GCM *data, FILE *file);
|
||||
int gcmGetFile(GCM *data, GCM_FSTEntry *entry, int fnum, FILE *file);
|
||||
int gcmCheckMagic(FILE *file);
|
||||
|
||||
// checks the magic number of the DVD file, and sets needByteSwap
|
||||
// returns the final value of needByteSwap. Returns -1 if the magic
|
||||
// word doesn't match either way and needByteSwap couldn't be set.
|
||||
int gcmCheckMagic(FILE *file)
|
||||
{
|
||||
int magic = 0;
|
||||
fseek(file, GCMPieces[GCM_DHEAD_DVDMAGIC].offset, 0);
|
||||
fread(&magic, GCMPieces[GCM_DHEAD_DVDMAGIC].size, 1, file);
|
||||
|
||||
if ( magic == GCNDVD_MAGICNUM ) {
|
||||
needByteSwap = 0;
|
||||
} else {
|
||||
magic = (((magic&0x000000FF)<<24)+((magic&0x0000FF00)<<8)+
|
||||
((magic&0x00FF0000)>>8)+((magic&0xFF000000)>>24));
|
||||
if ( magic == GCNDVD_MAGICNUM ) {
|
||||
needByteSwap = 1;
|
||||
}
|
||||
else needByteSwap = -1;
|
||||
}
|
||||
|
||||
return needByteSwap;
|
||||
}
|
||||
|
||||
// swap from big to little endian (only needed on intel machines)
|
||||
// only works if needByteSwap is > -1
|
||||
int byteSwap (int nLongNumber)
|
||||
{
|
||||
if ( needByteSwap ) return (((nLongNumber&0x000000FF)<<24)+((nLongNumber&0x0000FF00)<<8)+
|
||||
((nLongNumber&0x00FF0000)>>8)+((nLongNumber&0xFF000000)>>24));
|
||||
else if ( needByteSwap == -1 ) return 0; // refuse to work
|
||||
}
|
||||
|
||||
// return the type (0=file 1=directory) for the given FST entry
|
||||
int gcmGetFSTEntryType(GCM_FSTEntry *entry)
|
||||
{
|
||||
return entry->fname_offset >> 24;
|
||||
}
|
||||
|
||||
// uses one of the GCM_* definitions to return a pointer to
|
||||
// the appropriate point of the GCM struct to read data into.
|
||||
void *gcmWhichData(int whichdata, GCM *data)
|
||||
{
|
||||
void *toPrint = NULL;
|
||||
|
||||
switch (whichdata) {
|
||||
case GCM_DHEAD_GAMECODE:
|
||||
toPrint = &data->head.gamecode;
|
||||
break;
|
||||
case GCM_DHEAD_GAMEMAKER:
|
||||
toPrint = &data->head.gamemaker;
|
||||
break;
|
||||
case GCM_DHEAD_DVDMAGIC:
|
||||
toPrint = &data->head.magicword;
|
||||
break;
|
||||
case GCM_DHEAD_GAMENAME:
|
||||
toPrint = &data->head.gamename;
|
||||
break;
|
||||
case GCM_DHEAD_DEBUGMON:
|
||||
toPrint = &data->head.debugmon;
|
||||
break;
|
||||
case GCM_DHEAD_DEBUGMONADDR:
|
||||
toPrint = &data->head.debugmonaddr;
|
||||
break;
|
||||
case GCM_DHEAD_BOOTFILE:
|
||||
toPrint = &data->head.bootfile;
|
||||
break;
|
||||
case GCM_DHEAD_FST:
|
||||
toPrint = &data->fst.offset;
|
||||
break;
|
||||
case GCM_DHEAD_FSTSIZE:
|
||||
toPrint = &data->fst.size;
|
||||
break;
|
||||
case GCM_DHEAD_FSTMAXSIZE:
|
||||
toPrint = &data->fst.maxsize;
|
||||
break;
|
||||
case GCM_DHEAD_USERPOS:
|
||||
toPrint = &data->head.userpos;
|
||||
break;
|
||||
case GCM_DHEAD_USERLEN:
|
||||
toPrint = &data->head.userlen;
|
||||
break;
|
||||
case GCM_DHEADINF_DEBUGMONSIZE:
|
||||
toPrint = &data->headInf.debugmonsize;
|
||||
break;
|
||||
case GCM_DHEADINF_SIMMEMSIZE:
|
||||
toPrint = &data->headInf.simmemsize;
|
||||
break;
|
||||
case GCM_DHEADINF_ARGOFFSET:
|
||||
toPrint = &data->headInf.simmemsize;
|
||||
break;
|
||||
case GCM_DHEADINF_DEBUGFLAG:
|
||||
toPrint = &data->headInf.debugflag;
|
||||
break;
|
||||
case GCM_DHEADINF_TRACKLOCATION:
|
||||
toPrint = &data->headInf.tracklocation;
|
||||
break;
|
||||
case GCM_DHEADINF_TRACKSIZE:
|
||||
toPrint = &data->headInf.tracksize;
|
||||
break;
|
||||
case GCM_DHEADINF_COUNTRYCODE:
|
||||
toPrint = &data->headInf.countrycode;
|
||||
break;
|
||||
case GCM_APPLOADER_VERSION:
|
||||
toPrint = &data->apploader.datever;
|
||||
break;
|
||||
case GCM_APPLOADER_ENTRY:
|
||||
toPrint = &data->apploader.entry;
|
||||
break;
|
||||
case GCM_APPLOADER_SIZE:
|
||||
toPrint = &data->apploader.size;
|
||||
break;
|
||||
case GCM_APPLOADER_TRAILERSIZE:
|
||||
toPrint = &data->apploader.trailersize;
|
||||
break;
|
||||
case GCM_APPLOADER_BINARY:
|
||||
toPrint = &data->apploader.apploader;
|
||||
break;
|
||||
case GCM_FST_ROOT:
|
||||
toPrint = (void *)"Not implemented yet";
|
||||
break;
|
||||
case GCM_FST_STRINGTABLEOFF:
|
||||
toPrint = &data->fst.stringtable_offset;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return toPrint;
|
||||
}
|
||||
|
||||
// print the info in data as indicated by the GCM_*
|
||||
// passed to whichdata
|
||||
int gcmPrintData(int whichdata, GCM *data)
|
||||
{
|
||||
void *ptr;
|
||||
if ( GCMPieces[whichdata].type == 1) {
|
||||
char *theData = (char *)gcmWhichData(whichdata,data);
|
||||
printf("%-38s:\t %s\n", GCMPieces[whichdata].name, theData);
|
||||
}
|
||||
else {
|
||||
int *theData = (int *)gcmWhichData(whichdata,data);
|
||||
if ( theData ) {
|
||||
printf("%-38s:\t %x\n", GCMPieces[whichdata].name, *theData);
|
||||
}
|
||||
else {
|
||||
printf("%-38s:\t refusing to print NULL pointer...\n",
|
||||
"(untested function/invalid data)"); // this means you're using a feature that doesn't work (yet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print the information for a given file in data (by entry num)
|
||||
int gcmPrintFile(GCM *data, int fnum)
|
||||
{
|
||||
GCM_FSTEntry f;
|
||||
char *fname = NULL;
|
||||
|
||||
// printf("DEBUG : retrieving file data for number %d\n", fnum);
|
||||
f = data->fst.entries.at(fnum);
|
||||
|
||||
// see gcmPrint for how this is laid out...
|
||||
if ( fnum >= data->fst.entries.size() )
|
||||
fname = "(out_of_bounds string)" ;
|
||||
else
|
||||
fname = (char *)data->fst.stringtable.at(fnum)->c_str();
|
||||
|
||||
printf("%-20s%-6d%-6x%-12x%-20d\n",
|
||||
fname,
|
||||
fnum,
|
||||
gcmGetFSTEntryType(&f),
|
||||
f.file_offset,
|
||||
f.file_length);
|
||||
}
|
||||
|
||||
// reads data into dest and returns the number of bytes read
|
||||
// (only used internally by the other gcm functions, this should
|
||||
// be transparent outside the API guts)
|
||||
int gcmGetData(int whichdata, GCM *data, FILE *file)
|
||||
{
|
||||
int offset = 0;
|
||||
void *dest = gcmWhichData(whichdata, data);
|
||||
if ( whichdata > GCM_MAX_PIECES || dest == NULL || file == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch ( GCMPieces[whichdata].area ) {
|
||||
case 0:
|
||||
offset = GCMPieces[whichdata].offset;
|
||||
break;
|
||||
case 1:
|
||||
offset = GCMPieces[GCM_DHEAD].offset + GCMPieces[whichdata].offset;
|
||||
break;
|
||||
case 2:
|
||||
offset = GCMPieces[GCM_DHEADINF].offset + GCMPieces[whichdata].offset;
|
||||
break;
|
||||
case 3:
|
||||
offset = GCMPieces[GCM_APPLOADER].offset + GCMPieces[whichdata].offset;
|
||||
break;
|
||||
case 4:
|
||||
offset = data->fst.offset + GCMPieces[whichdata].offset;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
fseek(file, offset, 0);
|
||||
if ( GCMPieces[whichdata].type == 1 ) {
|
||||
fgets((char *)dest, GCMPieces[whichdata].size, file) == NULL;
|
||||
}
|
||||
else {
|
||||
fread(dest, 1, GCMPieces[whichdata].size, file);
|
||||
int *tmp = (int *)dest;
|
||||
*tmp = byteSwap(*tmp);
|
||||
}
|
||||
rewind(file);
|
||||
return GCMPieces[whichdata].size;
|
||||
}
|
||||
|
||||
// get the file at fnum from file for the GCM data and store it
|
||||
// in entry
|
||||
int gcmGetFile(GCM *data, GCM_FSTEntry *entry, int fnum, FILE *file)
|
||||
{
|
||||
if ( fnum > -1 && file != NULL ) {
|
||||
rewind(file);
|
||||
fseek(file, data->fst.offset + (12 * fnum), 0);
|
||||
|
||||
if ( !feof(file) ) {
|
||||
fread(&entry->fname_offset, 4, 1, file);
|
||||
entry->fname_offset = byteSwap(entry->fname_offset);
|
||||
fread(&entry->file_offset, 4, 1, file);
|
||||
entry->file_offset = byteSwap(entry->file_offset);
|
||||
fread(&entry->file_length, 4, 1, file);
|
||||
entry->file_length = byteSwap(entry->file_length);
|
||||
data->fst.entries.push_back(*entry);
|
||||
}
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
|
||||
// populate the FST of the given GCM from file
|
||||
int gcmPopulateFST(GCM *data, FILE *file)
|
||||
{
|
||||
GCM_FSTEntry *newEntry;
|
||||
GCM_FSTEntry root;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int oldpos = 0;
|
||||
int maxentries = 0;
|
||||
char *tmpbuff = new char[GCNDVD_FNAME_LENGTH];
|
||||
std::string * strdest = new std::string("");
|
||||
char tmp = 0xFF;
|
||||
int f = 0;
|
||||
int *appSize = NULL;
|
||||
|
||||
if ( !tmpbuff ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fseek(file, data->fst.offset, 0);
|
||||
|
||||
// now just loop until there are no more entries...
|
||||
gcmGetFile(data, &root, 0,file);
|
||||
root = data->fst.entries.front();
|
||||
// this is where we inject the filesystem entries for bootloader.bin, apploader.bin,
|
||||
// and game.dol ... these aren't technically part of the filesystem, but we
|
||||
// do this so they can be viewed/extracted like other files.
|
||||
/*
|
||||
appSize = (int *)gcmWhichData(GCM_APPLOADER_SIZE, data);
|
||||
newEntry = new GCM_FSTEntry;
|
||||
newEntry->fname_offset = 0;
|
||||
newEntry->file_offset = GCM_APPLOADER_CODE_LOC;
|
||||
newEntry->file_length = *appSize;
|
||||
newEntry->stringtable_off = 1;
|
||||
data->fst.entries.push_back(*newEntry);
|
||||
delete newEntry;*/
|
||||
for ( int i = 1; i < root.file_length ; i++) {
|
||||
newEntry = new GCM_FSTEntry;
|
||||
gcmGetFile(data, newEntry, i, file);
|
||||
delete newEntry;
|
||||
}
|
||||
|
||||
|
||||
// we're past the FST proper; now the string table...
|
||||
data->fst.stringtable_offset = data->fst.offset + (root.file_length * 12);
|
||||
fseek(file, data->fst.stringtable_offset, 0);
|
||||
//printf("FST string table offset calculated to 0x\%x...\n", data->fst.stringtable_offset);
|
||||
data->fst.stringtable.clear();
|
||||
data->fst.stringtable.push_back(&std::string("/\0"));
|
||||
//data->fst.stringtable.push_back(&std::string("apploader.bin\0"));
|
||||
memset(tmpbuff, GCNDVD_FNAME_LENGTH, 0x00);
|
||||
while ( ftell(file) < (data->fst.offset + data->fst.size) && !feof(file)) {
|
||||
i = 0;
|
||||
while ( 1 ) {
|
||||
tmp = fgetc(file);
|
||||
if ( tmp == 0x00 ) {
|
||||
break;
|
||||
}
|
||||
tmpbuff[i] = tmp;
|
||||
i++;
|
||||
}
|
||||
tmpbuff[i] = '\0';
|
||||
strdest->clear();
|
||||
strdest->reserve(i);
|
||||
strdest->assign(tmpbuff);
|
||||
data->fst.stringtable.push_back(strdest);
|
||||
// printf("DEBUG : FILENAME WAS %s ... added %s\n", strdest,
|
||||
// data->fst.stringtable.at(f+1)->c_str());
|
||||
memset(tmpbuff, GCNDVD_FNAME_LENGTH, 0x00);
|
||||
strdest = new std::string("");
|
||||
f++;
|
||||
}
|
||||
delete tmpbuff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// called inside of gcmInit to make sure everything inside is sane
|
||||
// (only needed internally)
|
||||
int gcmZeroOut(GCM *data)
|
||||
{
|
||||
data->apploader.entry = 0;
|
||||
data->apploader.size = 0;
|
||||
data->apploader.trailersize = 0;
|
||||
data->fst.maxsize = 0;
|
||||
data->fst.offset = 0;
|
||||
data->fst.size = 0;
|
||||
data->head.bootfile = 0;
|
||||
data->head.debugmon = 0;
|
||||
data->head.debugmonaddr = 0;
|
||||
data->head.gamecode = 0;
|
||||
data->head.gamemaker = 0;
|
||||
data->head.magicword = 0;
|
||||
data->head.userlen = 0;
|
||||
data->head.userpos = 0;
|
||||
data->headInf.argoff = 0;
|
||||
data->headInf.countrycode = 0;
|
||||
data->headInf.debugflag = 0;
|
||||
data->headInf.debugmonsize = 0;
|
||||
data->headInf.simmemsize = 0;
|
||||
data->headInf.tracklocation = 0;
|
||||
data->headInf.tracksize = 0;
|
||||
}
|
||||
|
||||
// reads all info from the GCM in gcmname and puts it in data
|
||||
int gcmInit(char *gcmname, GCM *data)
|
||||
{
|
||||
FILE *gcm = fopen(gcmname, "r+b");
|
||||
int i = 0;
|
||||
|
||||
if (!gcm) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gcmZeroOut(data);
|
||||
|
||||
switch ( gcmCheckMagic(gcm) ) {
|
||||
case 0:
|
||||
needByteSwap = 1;
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
case -1:
|
||||
//printf("DEBUG: DVD Magic number on GCM image was incorrect or couldn't be understood!\n");
|
||||
//printf("DEBUG: Aborting in GCMInit! (filename %s)\n", gcmname);
|
||||
fclose(gcm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for ( i = 3; i < GCM_MAX_PIECES ; i++) {
|
||||
gcmGetData(i,data, gcm);
|
||||
}
|
||||
|
||||
gcmPopulateFST(data, gcm);
|
||||
|
||||
fclose(gcm);
|
||||
|
||||
data->fname = new char[strlen(gcmname)+1];
|
||||
if ( !data->fname ) {
|
||||
printf("couldn't store GCM filename for later retrieval. Aborting.\n");
|
||||
gcmFreeStringTable(data);
|
||||
exit(-1);
|
||||
}
|
||||
else strcpy(data->fname, gcmname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// print all information about the GCM in a columnar format,
|
||||
// including the FST.
|
||||
int gcmPrint(GCM *data)
|
||||
{
|
||||
int ml = 0;
|
||||
int i = 0;
|
||||
|
||||
for (i = 3; i < GCM_MAX_PIECES; i++ ) {
|
||||
gcmPrintData(i,data);
|
||||
}
|
||||
|
||||
GCM_FSTEntry root = data->fst.entries.front();
|
||||
|
||||
printf("%-38s:\t%d\n", "Total files in the FST", root.file_length);
|
||||
printf("%-38s:\t%d\n", "Total entries in the FST string table", data->fst.stringtable.size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gcmPrintFST(GCM *data)
|
||||
{
|
||||
int ml = 0;
|
||||
int i = 0;
|
||||
char *tbuff = new char[GCNDVD_FNAME_LENGTH];
|
||||
if (!tbuff) {
|
||||
printf("Couldn't get temporary buffer for full path printing. Aborting.\n");
|
||||
return -1;
|
||||
} else {
|
||||
memset(tbuff, 0x00, GCNDVD_FNAME_LENGTH);
|
||||
}
|
||||
|
||||
GCM_FSTEntry root = data->fst.entries.front();
|
||||
printf("%-38s:\t%d\n", "Total files in the FST", root.file_length);
|
||||
printf("%-38s:\t%d\n", "Total entries in the FST string table", data->fst.stringtable.size());
|
||||
printf("\n\n\n%30s\n", "(FST CONTENTS)");
|
||||
printf("%-16s %-6s %-6s %s %-12s\n",
|
||||
"(name)", "(fnum)", "(type)", "(offset)", "(length)");
|
||||
for (i = 0; i < data->fst.entries.size() - 1 ; i++) {
|
||||
//printf("DEBUG: retrieving file data for number %d\n", i);
|
||||
gcmPrintFile(data, i);
|
||||
}
|
||||
|
||||
printf("\n\t\t\t(PRINTING FILES WITH FULL PATH)\n");
|
||||
for (i = 0; i < data->fst.entries.size() - 1; i++ ) {
|
||||
printf("File %d:", i);
|
||||
gcmGetFullFileName(data, i, tbuff);
|
||||
printf(" %s\n", tbuff);
|
||||
memset(tbuff, 0x00, GCNDVD_FNAME_LENGTH);
|
||||
}
|
||||
|
||||
delete tbuff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// frees memory used by the string table. MUST be called before zeroing
|
||||
// the gcm for new reading (gcmInit) or quitting the application.
|
||||
// This should be accompanied by clearing the entries vector, though the
|
||||
// destructor in that member should take care of cleanup for you.
|
||||
// Thou shalt not leak memory!
|
||||
|
||||
int gcmFreeStringTable(GCM *data)
|
||||
{
|
||||
std::string *string = NULL;
|
||||
int i = 0;
|
||||
|
||||
//printf("freeing memory used by FST string table... ");
|
||||
|
||||
for (i = 0; i < (data->fst.stringtable.size()) ; i++ ) {
|
||||
string = (std::string *)data->fst.stringtable.at(i);
|
||||
// we create the "/" entry for 0 manually, and it's not alloc'ed
|
||||
// so don't try freeing it!
|
||||
if ( string != NULL && i > 0 ) {
|
||||
delete string;
|
||||
}
|
||||
string = NULL;
|
||||
}
|
||||
data->fst.stringtable.clear();
|
||||
delete data->fname;
|
||||
|
||||
//printf(" ...done.\n");
|
||||
}
|
||||
|
||||
GCM_FSTEntry gcmGetFileByFnum(GCM *data, int fnum)
|
||||
{
|
||||
return data->fst.entries.at(fnum);
|
||||
}
|
||||
|
||||
int gcmGetFileByOffset(GCM *data, int offset)
|
||||
{
|
||||
GCM_FSTEntry curr;
|
||||
bool done = false;
|
||||
|
||||
for (int i = 0; i < data->fst.entries.size() -1; i++) {
|
||||
curr = data->fst.entries.at(i);
|
||||
if (curr.file_offset == offset) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// takes in a full pathname and retrieves the fnum
|
||||
// for the appropriate file in the FST
|
||||
unsigned int gcmGetFileByName(GCM *data, char *name)
|
||||
{
|
||||
GCM_FSTEntry curr;
|
||||
bool done = false;
|
||||
int nextStart = 0;
|
||||
int i = 0;
|
||||
char *tmp2 = (char *) new char[GCNDVD_FNAME_LENGTH];
|
||||
if ( !tmp2 ) {
|
||||
fprintf(stderr, "Failed to allocate temporary string storage\n");
|
||||
return -1;
|
||||
}
|
||||
for ( i = 0; i < data->fst.stringtable.size() ; i++ ) {
|
||||
gcmGetFullFileName(data, i, tmp2);
|
||||
//printf("DEBUG : comparing filename %s to original %s...\n", name, tmp2);
|
||||
if ( !strcmp(name, tmp2) ) {
|
||||
delete tmp2;
|
||||
//printf("DEBUG : found filename %s at number %d", name, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
delete tmp2;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// extracts a file into outfile from the GCM given the fnum.
|
||||
// FIXME : allow the user to specify a different output filename?
|
||||
unsigned int gcmExtractFile(GCM *data, int fnum, char *outfname)
|
||||
{
|
||||
FILE *out = NULL;
|
||||
FILE *gcm = NULL;
|
||||
int pos = 0;
|
||||
int endpos = 0;
|
||||
int b = 0;
|
||||
GCM_FSTEntry curr;
|
||||
std::string execstring = "";
|
||||
char *outfile = NULL;
|
||||
std::string tmpStr = "";
|
||||
|
||||
// check that the fnum is in range
|
||||
|
||||
if ( fnum < data->fst.entries.size() - 1) {
|
||||
curr = data->fst.entries.at(fnum);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if it's a file, open the outfile, open the GCM, and perform the copy - clean up and exit
|
||||
if ( gcmGetFSTEntryType(&curr) == 0 ) {
|
||||
if ( outfname ) {
|
||||
outfile = outfname;
|
||||
tmpStr = "";
|
||||
} else {
|
||||
outfile = new char[GCNDVD_FNAME_LENGTH];
|
||||
if ( !outfile ) return -1;
|
||||
else gcmGetFullFileName(data, fnum, outfile);
|
||||
tmpStr = ".";
|
||||
}
|
||||
tmpStr.append(outfile);
|
||||
gcm = fopen(data->fname, "rb");
|
||||
out = fopen(tmpStr.c_str(), "wb");
|
||||
if ( !gcm || !out ) {
|
||||
gcm ? fclose(gcm) : printf("Couldn't read from gcm file\n");
|
||||
out ? fclose(out) : printf("Couldn't write to output file\n");
|
||||
return -1;
|
||||
}
|
||||
fseek(gcm, curr.file_offset, 0);
|
||||
endpos = curr.file_offset + curr.file_length;
|
||||
if ( ftell(gcm) != curr.file_offset || !out || !gcm) {
|
||||
delete outfile;
|
||||
fclose(gcm);
|
||||
fclose(out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ( !feof(gcm) && ftell(gcm) <= endpos) {
|
||||
fread(&b, 1, 1, gcm);
|
||||
if ( needByteSwap == 1 ) b = byteSwap(b); // swap the bytes for the host
|
||||
fwrite(&b, 1, 1, out);
|
||||
}
|
||||
|
||||
if ( outfile && !outfname )delete outfile;
|
||||
fclose(gcm);
|
||||
fclose(out);
|
||||
printf("exploded %s\n", tmpStr.c_str());
|
||||
return 0;
|
||||
}
|
||||
// if it's a dir, construct the mkdir command, do it, clean up and exit.
|
||||
else {
|
||||
if ( outfname )
|
||||
outfile = outfname;
|
||||
else {
|
||||
outfile = new char[GCNDVD_FNAME_LENGTH];
|
||||
if (!outfile ) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
gcmGetFullFileName(data, fnum, outfile);
|
||||
if ( !outfname )
|
||||
execstring.append("mkdir -p .");
|
||||
else
|
||||
execstring.append("mkdir -p ");
|
||||
execstring.append(outfile);
|
||||
int retcode = system(execstring.c_str());
|
||||
if ( outfile && !outfname ) delete outfile;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// explodes the FST onto the host filesystem
|
||||
int gcmExplode(GCM *data)
|
||||
{
|
||||
for ( int i = 0; i <= (data->fst.entries.size() - 1) ; i++ ) {
|
||||
if ( gcmExtractFile(data, i, NULL) < 0 ) return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// retrieves the full filename for fnum with full path
|
||||
int gcmGetFullFileName(GCM *data, int fnum, char *dest)
|
||||
{
|
||||
bool finished = false;
|
||||
GCM_FSTEntry curr;
|
||||
std::vector<int> fnames;
|
||||
int fn = fnum;
|
||||
int depth = 0;
|
||||
std::string work = "";
|
||||
|
||||
curr = data->fst.entries.at(fn);
|
||||
|
||||
while (!finished) {
|
||||
depth++;
|
||||
if ( depth > data->fst.entries.size() - 1) {
|
||||
printf("went too far. aborting.\n");
|
||||
exit(-1);
|
||||
}
|
||||
if ( fn == 0 ) {
|
||||
fnames.push_back(0);
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
if ( gcmGetFSTEntryType(&curr) == 0 ) {
|
||||
// file
|
||||
fnames.push_back(fn);
|
||||
while (gcmGetFSTEntryType(&curr) == 0) {
|
||||
// search up for the parent directory....
|
||||
curr = data->fst.entries.at(fn - 1);
|
||||
fn -= 1;
|
||||
}
|
||||
}
|
||||
else if ( gcmGetFSTEntryType(&curr) == 1) {
|
||||
// directory
|
||||
fnames.push_back(fn);
|
||||
fn = curr.file_offset;
|
||||
curr = data->fst.entries.at(fn);
|
||||
}
|
||||
}
|
||||
|
||||
if ( fnum != 0 ) {
|
||||
for (int i = fnames.size() -1 ; i >= 0; i--) {
|
||||
if ( i < fnames.size()-1 ) {
|
||||
work.append("/");
|
||||
}
|
||||
if ( fnames.at(i) != 0 ) work.append(data->fst.stringtable.at(fnames.at(i))->c_str());
|
||||
}
|
||||
} else work = "/";
|
||||
strcpy(dest, work.c_str());
|
||||
return 0;
|
||||
}
|
||||
217
source/gcminfo.h
Executable file
217
source/gcminfo.h
Executable file
@@ -0,0 +1,217 @@
|
||||
// thanks to groepaz and everyone else who wrote YAGCD, most of my info came from it
|
||||
// also thanks to WntrMute for loaning me some source to clear things up about the FST
|
||||
|
||||
// (C) 2005 Andrew K andrew@aklabs.net
|
||||
// License: Take all you want, but credit for all you take.
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define LIBGCMVERSION "libGCM Version 0.1a (build Sep 4 2005)"
|
||||
|
||||
// defines for internal program control (not necessarily GCM-related)
|
||||
|
||||
#define GCNDVD_MAGICNUM 0xc2339f3d // if this isn't correct in the GCM,
|
||||
// the program will abort.
|
||||
|
||||
#define GCNDVD_SECTORS 712880 // not really used, but left for future updates that might use it
|
||||
#define GCNDVD_SECTORSIZE 2048 // " "
|
||||
#define GCNDVD_FNAME_LENGTH 1024
|
||||
|
||||
|
||||
#define GCM_MAX_PIECES 29 // change this if (for whatever reason) you add a new entry in GCMPieces
|
||||
|
||||
// these all define indices in the GCMPieces global array where
|
||||
// information about (where to look in the GCM for) a given piece
|
||||
// of data about the GCM can be found. The rationale should
|
||||
// be easy enough to follow.
|
||||
#define GCM_DHEAD 0
|
||||
#define GCM_DHEADINF 1
|
||||
#define GCM_APPLOADER 2
|
||||
|
||||
#define GCM_DHEAD_GAMECODE 3
|
||||
#define GCM_DHEAD_GAMEMAKER 4
|
||||
#define GCM_DHEAD_DVDMAGIC 5
|
||||
#define GCM_DHEAD_GAMENAME 6
|
||||
#define GCM_DHEAD_DEBUGMON 7
|
||||
#define GCM_DHEAD_DEBUGMONADDR 8
|
||||
#define GCM_DHEAD_BOOTFILE 9
|
||||
#define GCM_DHEAD_FST 10
|
||||
#define GCM_DHEAD_FSTSIZE 11
|
||||
#define GCM_DHEAD_FSTMAXSIZE 12
|
||||
#define GCM_DHEAD_USERPOS 13
|
||||
#define GCM_DHEAD_USERLEN 14
|
||||
|
||||
#define GCM_DHEADINF_DEBUGMONSIZE 15
|
||||
#define GCM_DHEADINF_SIMMEMSIZE 16
|
||||
#define GCM_DHEADINF_ARGOFFSET 17
|
||||
#define GCM_DHEADINF_DEBUGFLAG 18
|
||||
#define GCM_DHEADINF_TRACKLOCATION 19
|
||||
#define GCM_DHEADINF_TRACKSIZE 20
|
||||
#define GCM_DHEADINF_COUNTRYCODE 21
|
||||
|
||||
#define GCM_APPLOADER_VERSION 22
|
||||
#define GCM_APPLOADER_ENTRY 23
|
||||
#define GCM_APPLOADER_SIZE 24
|
||||
#define GCM_APPLOADER_TRAILERSIZE 25
|
||||
#define GCM_APPLOADER_BINARY 26
|
||||
#define GCM_APPLOADER_CODE_LOC 0x2450
|
||||
|
||||
#define GCM_FST_ROOT 28
|
||||
#define GCM_FST_STRINGTABLEOFF 29
|
||||
|
||||
typedef struct {
|
||||
int area; // 0 = basic structure, 1 = header, 2= header info, 3 = apploader, 4 = FST
|
||||
char *name;
|
||||
long offset;
|
||||
long size;
|
||||
int type; // 1 for string, 0 for numeric value (strings aren't byteswapped)
|
||||
} GCMPiece;
|
||||
|
||||
// pieces with area 1 add the base of the disk header to their offset
|
||||
// pieces with area 2 add the base of the disk header info to their offset
|
||||
// pieces with area 3 add the base of the apploader to their offset
|
||||
// pieces with area 4 add the base of the FST to their offset (garnered from the disk header)
|
||||
static GCMPiece GCMPieces [] ={
|
||||
// root disc pieces
|
||||
{0, "Disk Header (boot.bin)", 0x00000000, 0x0440, 0},
|
||||
{0, "Disk Header Information (bi2.bin)", 0x00000440, 0x2000, 0},
|
||||
{0, "Apploader (appldr.bin)", 0x00002440, 0x2000, 0}, // 0x2000 size is an estimate I think
|
||||
// disk header
|
||||
{1, "Game code", 0x0000, 0x0004, 0},
|
||||
{1, "Game maker code", 0x0004, 0x0002, 0},
|
||||
{1, "DVD Magic Word", 0x001c, 0x0004, 0},
|
||||
{1, "Game name", 0x0020, 0x03e0, 1},
|
||||
{1, "Debug monitor offset", 0x0400, 0x0004, 0},
|
||||
{1, "Debug monitor load address", 0x0404, 0x0004, 0},
|
||||
{1, "Bootfile offset", 0x0420, 0x0004, 0},
|
||||
{1, "FST offset", 0x0424, 0x0004, 0},
|
||||
{1, "FST size", 0x0428, 0x0004, 0},
|
||||
{1, "FST Max Size", 0x042c, 0x0004, 0},
|
||||
{1, "User position", 0x0430, 0x0004, 0},
|
||||
{1, "User length", 0x0434, 0x0004, 0},
|
||||
|
||||
// the disk header info is loaded to 0x800000f4 when the disc is loaded by the IPL (tho we're reading it straight
|
||||
// out of the .gcm image, so YMMV)
|
||||
{2, "Debug-monitor size", 0x0000, 0x0004, 0},
|
||||
{2, "Simulated memory size", 0x0004, 0x0004, 0},
|
||||
{2, "Argument offset", 0x0008, 0x0004, 0},
|
||||
{2, "Debug flag", 0x000c, 0x0004, 0},
|
||||
{2, "Track location", 0x0010, 0x0004, 0},
|
||||
{2, "Track size", 0x0014, 0x0004, 0},
|
||||
{2, "Countrycode", 0x0018, 0x0004, 0},
|
||||
|
||||
// apploader header info
|
||||
{3, "Version/Date", 0x0000, 0x000F, 1}, // don't include the padding in the date
|
||||
{3, "Apploader entry point", 0x0010, 0x0004, 0},
|
||||
{3, "Apploader size", 0x0014, 0x0004, 0},
|
||||
{3, "Trailer size", 0x0018, 0x0004, 0},
|
||||
{3, "Apploader binary", 0x0020, 0, 1}, // no length given - taken from the "apploader size"
|
||||
|
||||
// FST info
|
||||
{4, "Root directory entry", 0x00, 0x0c, 0},
|
||||
{4, "FST String table offset", 0x0008, 0x0004, 0}
|
||||
|
||||
};
|
||||
|
||||
// primary GCM disk header
|
||||
typedef struct GCM_DiskHeader{
|
||||
int gamecode;
|
||||
int gamemaker;
|
||||
int magicword;
|
||||
char gamename[0x03e0];
|
||||
int debugmon;
|
||||
int debugmonaddr;
|
||||
int bootfile;
|
||||
int userpos;
|
||||
int userlen;
|
||||
};
|
||||
|
||||
// the GCM disk header additional info
|
||||
typedef struct GCM_DiskHeaderInfo {
|
||||
int debugmonsize;
|
||||
int simmemsize;
|
||||
int argoff;
|
||||
int debugflag;
|
||||
int tracklocation;
|
||||
int tracksize;
|
||||
int countrycode;
|
||||
};
|
||||
|
||||
// information about the apploader on the GCM
|
||||
typedef struct GCM_ApploaderInfo{
|
||||
char datever[10];
|
||||
int entry;
|
||||
int size;
|
||||
int trailersize;
|
||||
char apploader[0x200]; // actual apploader data
|
||||
};
|
||||
|
||||
// information about a particular file in the FST
|
||||
typedef struct GCM_FSTEntry {
|
||||
int fname_offset; // offset into the FST string table for the filename
|
||||
// the offset is only actually 3 bytes, but
|
||||
// we're only reading, not writing so it doesn't matter
|
||||
// if we're grande sized ....
|
||||
// the first byte of fname_offset is actually the flags of the file; 0: file 1: dir
|
||||
int file_offset; // if this is a directory, this is actually the offset of the parent
|
||||
int file_length; // actually the number of entries (root) or next_offset (dir)
|
||||
int stringtable_off; // offset in the string table
|
||||
};
|
||||
|
||||
// information about the names and locations of files in the GCM
|
||||
typedef struct GCM_FST {
|
||||
int size;
|
||||
int offset;
|
||||
int stringtable_offset;
|
||||
int maxsize;
|
||||
std::vector <GCM_FSTEntry>entries; // list of entries
|
||||
std::vector <std::string *>stringtable; // string table
|
||||
};
|
||||
|
||||
// GCM image data structure
|
||||
typedef struct GCM {
|
||||
GCM_DiskHeader head;
|
||||
GCM_DiskHeaderInfo headInf;
|
||||
GCM_ApploaderInfo apploader;
|
||||
GCM_FST fst;
|
||||
char *fname;
|
||||
};
|
||||
|
||||
// these are just the functions that the user would need beyond
|
||||
// the functionality provided by gcmInit's loader; more internal
|
||||
// functions can be found inside gcminfo.c
|
||||
|
||||
// returns 0 for a regular file, 1 for a directory
|
||||
extern int gcmGetFSTEntryType(GCM_FSTEntry *entry);
|
||||
// initialises the GCM data structures with FST and such;
|
||||
extern int gcmInit(char *gcmname, GCM *data);
|
||||
// prints a given portion of the GCM data
|
||||
// whichdata should be an indice into the GCMPieces array
|
||||
extern int gcmPrintData(int whichdata, GCM *data);
|
||||
// prints all the data in the GCM in a (fairly) columnar format
|
||||
extern int gcmPrint(GCM *data);
|
||||
// prints a comprehensive listing of all files in the GCM
|
||||
extern int gcmPrintFST(GCM *data);
|
||||
// retrieves a given file and puts it in the FST entries,
|
||||
// given the fnum
|
||||
extern int gcmGetFile(GCM *data, GCM_FSTEntry *entry, int fnum, FILE *file);
|
||||
// prints information for a given fname
|
||||
extern int gcmPrintFile(GCM *data, int fnum);
|
||||
// frees all data in the FST stringtable
|
||||
extern int gcmFreeStringTable(GCM *data);
|
||||
// extracts a file, given the fnum, into the current dir, unless outfname is specified
|
||||
extern unsigned int gcmExtractFile(GCM *data, int fnum, char *outfname);
|
||||
// puts the full filename (with path) into dest, given fnum
|
||||
extern int gcmGetFullFileName(GCM *data, int fnum, char *dest);
|
||||
// returns the fnum of a given file by its offset
|
||||
extern int gcmGetFileByOffset(GCM *data, int offset);
|
||||
// returns the fnum of a given file by its full pathname
|
||||
extern unsigned int gcmGetFileByName(GCM *data, char *name);
|
||||
// returns the actual entry of a file given its fnum
|
||||
extern GCM_FSTEntry gcmGetFileByFnum(GCM *data, int fnum);
|
||||
// explodes the FST onto the host filesystem in the current directory
|
||||
extern int gcmExplode(GCM *data);
|
||||
1709
source/sample-output.txt
Executable file
1709
source/sample-output.txt
Executable file
File diff suppressed because it is too large
Load Diff
13
source/std_disclaimer.h
Executable file
13
source/std_disclaimer.h
Executable file
@@ -0,0 +1,13 @@
|
||||
/* What you are seeing is a work in progress. Source and comments
|
||||
it contains could be dangerous, profane, or just plain wrong.
|
||||
While I generally don't publish source code unless I feel it's in
|
||||
a semi-production state (or at least to the point where someone
|
||||
somewhere could benefit from it), I can't guarantee anything.
|
||||
|
||||
If you use this code and the genie of your computer (or your cube!) escapes in
|
||||
a puff of smoke, I will not be held liable. You have been warned.
|
||||
This code may be ugly, incomplete, or just plain wrong.
|
||||
|
||||
No F'in warranty implied!
|
||||
|
||||
Andrew K 2005 andrew@aklabs.net */
|
||||
Reference in New Issue
Block a user