2 std/os, std/streams, std/strutils, std/tables,
3 vfs/[common, dfwad, zip],
7 streams, common, dfwad, zip
10 archiveExts* = [".zip", ".dfz", ".pk3", ".wad"]
13 archives: seq[FsArchive] = @[]
14 mapArchive*: FsArchive = nil
15 mapDeps*: seq[FsArchive] = @[]
17 proc openArchive*(path: string, write: bool, forceExisting: bool = false): FsArchive =
19 let existing = fileExists(path)
20 let (dir, name, ext) = splitFile(path)
21 let arcName = name & ext
22 let mode = (if write: (if forceExisting: fmReadWriteExisting else: fmReadWrite) else: fmRead)
23 var stream = newFileStream(path, mode)
25 if stream.checkIfWad():
26 result = newFsWadArchive(arcName, path)
27 elif stream.checkIfZip():
28 result = newFsZipArchive(arcName, path)
30 raise newException(FsFormatError, "Unknown archive format extension: " & ext)
31 result.stream = stream
32 result.writeable = write
33 result.existing = existing
36 raise newException(IOError, "Could not open " & path)
38 proc openArchive*(name: string, stream: Stream): FsArchive =
40 if stream.checkIfWad():
41 result = newFsWadArchive(name, "")
42 elif stream.checkIfZip():
43 result = newFsZipArchive(name, "")
46 result.stream = stream
47 result.writeable = false
48 result.existing = true
51 proc unmount*(self: FsArchive) =
52 var idx = archives.find(self)
56 if self == mapArchive:
59 idx = mapDeps.find(self)
66 while archives.len() > 0:
67 var ar = archives.pop()
72 proc unmountMapDeps*() =
73 while mapDeps.len() > 0:
74 var ar = mapDeps.pop()
82 proc findArchive*(arName: string): FsArchive =
85 for i, ar in archives:
86 if cmpIgnoreCase(ar.name, arName) == 0:
90 proc mount*(path: string, write: bool, forceExisting: bool = false, isMapArchive: bool = false, isMapDep: bool = false): FsArchive {.discardable.} =
92 let (dir, name, ext) = splitFile(path)
93 var ar = findArchive(name & ext)
94 if ar != nil: return ar # don't mount it again
99 result = openArchive(path, write, forceExisting)
110 addExitProc(vfs.unmountAll)
112 proc splitResPath*(path: string): tuple[archive, path: string] =
113 var toks = path.split(':')
115 raise newException(ValueError, "Invalid resource path: " & path)
116 if toks[1][0] == '/':
117 result = (toks[0], toks[1][1 .. ^1].toUpperAscii())
119 result = (toks[0], toks[1].toUpperAscii())
121 proc open*(path: string, write: bool): Stream =
122 let (arName, localPath) = path.splitResPath()
123 var ar = findArchive(arName)
126 return ar.writeFile(localPath)
128 return ar.readFile(localPath)
130 # can't find archive in vfs; try to mount one
132 if fileExists(arName):
133 ar = vfs.mount(arName, write, not write, isMapDep = not write)
134 elif fileExists("wads/" & arName):
135 ar = vfs.mount("wads/" & arName, write, not write, isMapDep = not write)
138 # archive found, get the res
141 return ar.writeFile(localPath)
143 return ar.readFile(localPath)
146 proc resExists*(path: string): bool =
147 let (arName, localPath) = path.splitResPath()
148 var ar = findArchive(arName)
152 result = (ar.findFile(localPath) != nil)
154 iterator resources*(self: FsArchive, prefix: string = ""): FsFileEntry =
155 let upperPrefix = prefix.toUpperAscii()
156 for fname, f in self.files:
157 if fname.startsWith(upperPrefix):
160 iterator resources*(prefix: string): FsFileEntry =
161 let (arName, localPath) = prefix.splitResPath()
162 var ar = findArchive(arName)
164 for fname, f in ar.files:
165 if fname.startsWith(localPath):