This will display the contents of the Q3A directory. Double-click a file to extract and launch it.
'===============================================================
'Abstract File System by Leadwerks Software
'===============================================================
window:TGadget=CreateWindow("File System Browser",200,200,640,480)
treeview:TGadget=CreateTreeView(0,0,window.clientwidth(),window.clientheight(),window)
SetGadgetLayout treeview,1,1,1,1
'Clean up temp dir
DeleteDir AppDir+"/temp",True
'vd:TVirtualDir=RegisterPath(AppDir)
vd:TVirtualDir=RegisterPath("C:\Program Files\Quake III Arena\baseq3")
do vd,TreeViewRoot(treeview)
ActivateGadget window
While WaitEvent()
Select EventID()
Case EVENT_GADGETACTION
For vf:TVirtualFile=EachIn TVirtualFile.list
If HandleToObject(vf.userdata)=SelectedTreeViewNode(treeview)
OpenURL vf.RealURL()
Exit
EndIf
Next
Case EVENT_WINDOWCLOSE
End
End Select
Wend
Function do(vd:TVirtualDir,node:TGadget)
For sd:TVirtualDir=EachIn vd.kids
snode:TGadget=AddTreeViewNode(StripDir(sd.url),node)
do(sd,snode)
Next
For vf:TVirtualFile=EachIn vd.files
snode:TGadget=AddTreeViewNode(StripDir(vf.url),node)
vf.userdata=HandleFromObject(snode)
Next
EndFunction
Function RegisterPath:TVirtualDir(url$,parentdir:TVirtualDir=Null)
url=RealPath(url)
d=ReadDir(url)
If Not d Return
vd:TVirtualDir=TVirtualDir.find(url,parentdir)
Repeat
file$=NextFile(d)
If file="" Exit
Select FileType(url+"/"+file)
Case 1
pr:TPackageReader=TPackageReader.ExtensionSupported(Lower(ExtractExt(file)))
If pr
pr.Read(url+"/"+file,vd)
Else
TVirtualFile.Register(url+"/"+file,vd)
EndIf
Case 2
If file<>"." And file<>".."
RegisterPath(url+"/"+file,vd)
EndIf
EndSelect
Forever
CloseDir d
Return vd
EndFunction
Type TVirtualFile
Global list:TList=New TList
Field url$
Field lurl$
Field tempurl$
Field rpath$=""
Field source
Field userdata:Int
Field package:TPackage
Method New()
list.addlast(Self)
EndMethod
Method Read:TStream()
If package=Null
tempurl=url
Return ReadFile(url)
Else
Return package.readfile(Self)
EndIf
EndMethod
Method RealURL$()
If package=Null
Return url
Else
package.extract(Self)
Return tempurl
EndIf
EndMethod
Function Find:TVirtualFile(url$)
url=RealPath(url)
lurl$=Lower(url)
For vf:TVirtualFile=EachIn list
If vf.lurl=lurl Return vf
Next
EndFunction
Function Register:TVirtualFile(url$,vd:TVirtualDir,package:TPackage=Null,rpath$="")
If Find(url) Return Null
vf:TVirtualFile=New TVirtualFile
vf.url=RealPath(url)
vf.lurl$=Lower(url)
vf.rpath=rpath
vf.package=package
vd.files.addlast(vf)
Return vf
EndFunction
EndType
Type TPackage
Field url$
Field files:TList=New TList
Field vf:TVirtualDir
Field parent:TPackage
Field kids:TList=New TList
Field reader:TPackageReader
Function Load:TPackage(url$,vd:TVirtualDir)
url=RealPath(url)
ext$=Lower(ExtractExt(url))
For pr:TPackageReader=EachIn TPackageReader.list
If pr.extensions.contains(ext)
package:TPackage=pr.Read(url,vd)
EndIf
Next
Return package
EndFunction
Method Extract:Int(vf:TVirtualFile)
Return reader.extract(vf)
EndMethod
Method ReadFile:TStream(vf:TVirtualFile)
Return reader.readfile(vf)
EndMethod
EndType
Type TPackageReader
Global list:TList=New TList
Field extensions:TList=New TList
Method New()
list.addfirst(Self)
EndMethod
Method Read:TPackage(url$,vd:TVirtualDir) Abstract
Method Extract:Int(vf:TVirtualFile) Abstract
Method ReadFile:TStream(vf:TVirtualFile) Abstract
Function ExtensionSupported:TPackageReader(ext$)
For pr:TPackageReader=EachIn TPackageReader.list
If pr.extensions.contains(ext)
Return pr
EndIf
Next
Return Null
EndFunction
EndType
Type TZipPackageReader Extends TPackageReader
Global pr:TPackageReader=New TZipPackageReader
Field zrObject:ZipReader
Method New()
extensions.addlast("zip")
extensions.addlast("pk3")
EndMethod
Method GenerateExtractPath$(url$)
Local index=0
file$=StripAll(url)
ext$=ExtractExt(url)
path$=AppDir+"/temp/"+file+"."+ext
While FileType(path)=1
path$=AppDir+"/temp/"+file+"_"+index+"."+ext
index:+1
Wend
Return path
EndMethod
Method Extract:Int(vf:TVirtualFile)
If Not zrObject.OpenZip(vf.package.url) Return False
If FileType(AppDir+"/temp")<>2 CreateDir(AppDir+"/temp")
If FileType(AppDir+"/temp")<>2 Return Null
vf.tempurl=GenerateExtractPath$(vf.url)
zrObject.ExtractFileToDisk(vf.rpath,vf.tempurl,False,"")
zrObject.closezip()
Return True
EndMethod
Method ReadFile:TStream(vf:TVirtualFile)
If Not Extract(vf) Return Null
stream:TStream=ReadStream(vf.tempurl)
Return stream
EndMethod
Method Read:TPackage(url$,vd:TVirtualDir)
zrObject=New ZipReader
If Not zrObject.OpenZip(url) Return Null
package:TPackage=New TPackage
package.url=url
package.reader=Self
package.vf=vd
For Local i:Int=0 To zrObject.getFileCount()-1
file$=zrObject.getFileInfo(i).zipFileName
ext$=Lower(ExtractExt(file))
Select ext
Case ""
dirname$=ExtractDir(url)+"/"+file
vfd:TVirtualDir=TVirtualDir.Find(dirname,Null,True)
Default
If Instr(file,"/")
dirname$=ExtractDir(url)+"/"+ExtractDir(file)
vfd:TVirtualDir=TVirtualDir.Find(dirname,Null,True)
Else
vfd=vd
EndIf
realfile$=vfd.url+"/"+StripDir(file)
TVirtualFile.Register realfile,vfd,package,file
EndSelect
Next
zrObject.CloseZip()
Return package
EndMethod
EndType
Type TVirtualDir
Global list:TList=New TList
Field parent:TVirtualDir
Field kids:TList=New TList
Field url$,lurl$
Field files:TList=New TList
Method New()
list.addlast(Self)
EndMethod
Function Find:TVirtualDir(url$,parent:TVirtualDir=Null,fix=False)
url=RealPath(url)
lurl$=Lower(url)
For vf:TVirtualDir=EachIn list
If vf.lurl=lurl Return vf
Next
vf=New TVirtualDir
vf.url=url
vf.lurl=lurl
If parent=Null
If fix
dirname$=ExtractDir(url)
parent=Find(dirname)
EndIf
EndIf
If parent parent.kids.addlast(vf)
Return vf
EndFunction
Method Display(ws$="",test=False)
For f:TVirtualFile=EachIn files
Print ws+"File: "+f.url
If test
stream:TStream=f.read()
If stream
stream.close()
Else
Notify "Error reading virtual file "+Chr(34)+f.url+Chr(34)
EndIf
EndIf
Next
For d:TVirtualDir=EachIn kids
Print ws+"Folder: "+d.url
d.display ws+" ",test
Next
EndMethod
EndType