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