4 {$DEFINE SFS_DWFAD_DEBUG}
5 {$DEFINE SFS_MAPDETECT_FX}
14 SArray
= array of ShortString;
16 TWADFile
= class(TObject
)
18 fFileName
: AnsiString; // empty: not opened
21 function getIsOpen (): Boolean;
22 function isMapResource (idx
: Integer): Boolean;
24 function GetResourceEx (name
: AnsiString; wantMap
: Boolean; var pData
: Pointer; var Len
: Integer): Boolean;
28 destructor Destroy(); override;
32 function ReadFile (FileName
: AnsiString): Boolean;
33 function ReadMemory (Data
: Pointer; Len
: LongWord): Boolean;
35 function GetResource (name
: AnsiString; var pData
: Pointer; var Len
: Integer): Boolean;
36 function GetMapResource (name
: AnsiString; var pData
: Pointer; var Len
: Integer): Boolean;
37 function GetMapResources (): SArray
;
39 property isOpen
: Boolean read getIsOpen
;
43 function g_ExtractWadName (resourceStr
: AnsiString): AnsiString;
44 function g_ExtractWadNameNoPath (resourceStr
: AnsiString): AnsiString;
45 function g_ExtractFilePath (resourceStr
: AnsiString): AnsiString;
46 function g_ExtractFileName (resourceStr
: AnsiString): AnsiString; // without path
47 function g_ExtractFilePathName (resourceStr
: AnsiString): AnsiString;
49 // return fixed AnsiString or empty AnsiString
50 function findDiskWad (fname
: AnsiString): AnsiString;
56 SysUtils
, Classes
, BinEditor
, e_log
, g_options
, utils
, MAPSTRUCT
;
59 function findDiskWad (fname
: AnsiString): AnsiString;
62 if not findFileCI(fname
) then
64 //e_WriteLog(Format('findDiskWad: error looking for [%s]', [fname]), MSG_NOTIFY);
65 if StrEquCI1251(ExtractFileExt(fname
), '.wad') then
67 fname
:= ChangeFileExt(fname
, '.pk3');
68 //e_WriteLog(Format(' looking for [%s]', [fname]), MSG_NOTIFY);
69 if not findFileCI(fname
) then
71 fname
:= ChangeFileExt(fname
, '.zip');
72 //e_WriteLog(Format(' looking for [%s]', [fname]), MSG_NOTIFY);
73 if not findFileCI(fname
) then exit
;
81 //e_WriteLog(Format('findDiskWad: FOUND [%s]', [fname]), MSG_NOTIFY);
86 function normSlashes (s
: AnsiString): AnsiString;
90 for f
:= 1 to length(s
) do if s
[f
] = '\' then s
[f
] := '/';
94 function g_ExtractWadNameNoPath (resourceStr
: AnsiString): AnsiString;
98 for f
:= length(resourceStr
) downto 1 do
100 if resourceStr
[f
] = ':' then
102 result
:= normSlashes(Copy(resourceStr
, 1, f
-1));
104 while (c
> 0) and (result
[c
] <> '/') do Dec(c
);
105 if c
> 0 then result
:= Copy(result
, c
+1, length(result
));
112 function g_ExtractWadName (resourceStr
: AnsiString): AnsiString;
116 for f
:= length(resourceStr
) downto 1 do
118 if resourceStr
[f
] = ':' then
120 result
:= normSlashes(Copy(resourceStr
, 1, f
-1));
127 function g_ExtractFilePath (resourceStr
: AnsiString): AnsiString;
129 f
, lastSlash
: Integer;
133 for f
:= length(resourceStr
) downto 1 do
135 if (lastSlash
< 0) and (resourceStr
[f
] = '\') or (resourceStr
[f
] = '/') then lastSlash
:= f
;
136 if resourceStr
[f
] = ':' then
138 if lastSlash
> 0 then result
:= normSlashes(Copy(resourceStr
, f
, lastSlash
-f
));
142 if lastSlash
> 0 then result
:= normSlashes(Copy(resourceStr
, 1, lastSlash
-1));
145 function g_ExtractFileName (resourceStr
: AnsiString): AnsiString; // without path
147 f
, lastSlash
: Integer;
151 for f
:= length(resourceStr
) downto 1 do
153 if (lastSlash
< 0) and (resourceStr
[f
] = '\') or (resourceStr
[f
] = '/') then lastSlash
:= f
;
154 if resourceStr
[f
] = ':' then
156 if lastSlash
> 0 then result
:= Copy(resourceStr
, lastSlash
+1, length(resourceStr
));
160 if lastSlash
> 0 then result
:= Copy(resourceStr
, lastSlash
+1, length(resourceStr
));
163 function g_ExtractFilePathName (resourceStr
: AnsiString): AnsiString;
168 for f
:= length(resourceStr
) downto 1 do
170 if resourceStr
[f
] = ':' then
172 result
:= normSlashes(Copy(resourceStr
, f
+1, length(resourceStr
)));
181 constructor TWADFile
.Create();
187 destructor TWADFile
.Destroy();
194 function TWADFile
.getIsOpen (): Boolean;
196 result
:= (fFileName
<> '');
200 procedure TWADFile
.FreeWAD();
202 if fIter
<> nil then FreeAndNil(fIter
);
203 //if fFileName <> '' then e_WriteLog(Format('TWADFile.ReadFile: [%s] closed', [fFileName]), MSG_NOTIFY);
207 function TWADFile
.isMapResource (idx
: Integer): Boolean;
209 sign
: packed array [0..2] of Char;
213 if not isOpen
or (fIter
= nil) then exit
;
214 if (idx
< 0) or (idx
>= fIter
.Count
) then exit
;
217 fs
:= fIter
.volume
.OpenFileByIndex(idx
);
218 fs
.readBuffer(sign
, 3);
219 result
:= (sign
= MAP_SIGNATURE
);
221 if fs
<> nil then fs
.Free();
227 function removeExt (s
: AnsiString): AnsiString;
232 while (i
> 1) and (s
[i
-1] <> '.') and (s
[i
-1] <> '/') do Dec(i
);
233 if (i
> 1) and (s
[i
-1] = '.') then
235 //writeln('[', s, '] -> [', Copy(s, 1, i-2), ']');
236 s
:= Copy(s
, 1, i
-2);
241 function TWADFile
.GetResourceEx (name
: AnsiString; wantMap
: Boolean; var pData
: Pointer; var Len
: Integer): Boolean;
243 f
, lastSlash
: Integer;
247 rpath
, rname
: AnsiString;
248 sign
: array [0..2] of Char;
252 if not isOpen
or (fIter
= nil) then Exit
;
253 rname
:= removeExt(name
);
254 if length(rname
) = 0 then Exit
; // just in case
256 for f
:= 1 to length(rname
) do
258 if rname
[f
] = '\' then rname
[f
] := '/';
259 if rname
[f
] = '/' then lastSlash
:= f
;
261 if lastSlash
> 0 then
263 rpath
:= Copy(rname
, 1, lastSlash
);
264 Delete(rname
, 1, lastSlash
);
270 // backwards, due to possible similar names and such
271 for f
:= fIter
.Count
-1 downto 0 do
273 fi
:= fIter
.Files
[f
];
274 if fi
= nil then continue
;
275 if StrEquCI1251(removeExt(fi
.name
), rname
) then
277 // i found her (maybe)
280 if length(fi
.path
) < length(rpath
) then continue
; // alas
281 if length(fi
.path
) = length(rpath
) then
283 if not StrEquCI1251(fi
.path
, rpath
) then continue
; // alas
287 if fi
.path
[length(fi
.path
)-length(rpath
)] <> '/' then continue
; // alas
288 if not StrEquCI1251(Copy(fi
.path
, length(fi
.path
)+1-length(rpath
), length(fi
.path
)), rpath
) then continue
; // alas
292 fs
:= fIter
.volume
.OpenFileByIndex(f
);
298 if wantMap
then continue
;
299 e_WriteLog(Format('DFWAD: can''t open file [%s] in [%s]', [name
, fFileName
]), MSG_WARNING
);
302 // if we want only maps, check if this is map
303 {$IFDEF SFS_MAPDETECT_FX}
307 //e_WriteLog(Format('DFWAD: checking for good map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]), MSG_NOTIFY);
309 fs
.readBuffer(sign
, 3);
310 goodMap
:= (sign
= MAP_SIGNATURE
);
313 e_WriteLog(Format(' GOOD map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]), MSG_NOTIFY)
315 e_WriteLog(Format(' BAD map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]), MSG_NOTIFY);
321 //e_WriteLog(Format(' not a map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]), MSG_NOTIFY);
328 Len
:= Integer(fs
.size
);
332 fs
.ReadBuffer(pData
^, Len
);
343 {$IFNDEF SFS_MAPDETECT_FX}
349 Move(pData
^, sign
, 3);
350 goodMap
:= (sign
= MAP_SIGNATURE
);
354 //e_WriteLog(Format(' not a map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]), MSG_NOTIFY);
363 {$IFDEF SFS_DWFAD_DEBUG}
365 e_WriteLog(Format('DFWAD: file [%s] FOUND in [%s]; size is %d bytes', [name
, fFileName
, Len
]), MSG_NOTIFY
);
370 e_WriteLog(Format('DFWAD: file [%s] not found in [%s]', [name
, fFileName
]), MSG_WARNING
);
373 function TWADFile
.GetResource (name
: AnsiString; var pData
: Pointer; var Len
: Integer): Boolean;
375 result
:= GetResourceEx(name
, false, pData
, Len
);
378 function TWADFile
.GetMapResource (name
: AnsiString; var pData
: Pointer; var Len
: Integer): Boolean;
380 result
:= GetResourceEx(name
, true, pData
, Len
);
383 function TWADFile
.GetMapResources (): SArray
;
390 if not isOpen
or (fIter
= nil) then Exit
;
391 for f
:= fIter
.Count
-1 downto 0 do
393 fi
:= fIter
.Files
[f
];
394 if fi
= nil then continue
;
395 if length(fi
.name
) = 0 then continue
;
396 //e_WriteLog(Format('DFWAD: checking for map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]), MSG_NOTIFY);
397 if isMapResource(f
) then
399 s
:= removeExt(fi
.name
);
403 if StrEquCI1251(result
[c
], s
) then break
;
408 SetLength(result
, Length(result
)+1);
409 result
[high(result
)] := removeExt(fi
.name
);
416 function TWADFile
.ReadFile (FileName
: AnsiString): Boolean;
423 //e_WriteLog(Format('TWADFile.ReadFile: [%s]', [FileName]), MSG_NOTIFY);
425 rfn
:= findDiskWad(FileName
);
426 if length(rfn
) = 0 then
428 e_WriteLog(Format('TWADFile.ReadFile: error looking for [%s]', [FileName
]), MSG_NOTIFY
);
431 {$IFDEF SFS_DWFAD_DEBUG}
432 if gSFSDebug
then e_WriteLog(Format('TWADFile.ReadFile: FOUND [%s]', [rfn
]), MSG_NOTIFY
);
438 if not SFSAddDataFile(rfn
, true) then exit
;
442 if not SFSAddDataFileTemp(rfn
, true) then exit
;
447 fIter
:= SFSFileList(rfn
);
448 if fIter
= nil then Exit
;
450 {$IFDEF SFS_DWFAD_DEBUG}
451 if gSFSDebug
then e_WriteLog(Format('TWADFile.ReadFile: [%s] opened', [fFileName
]), MSG_NOTIFY
);
458 uniqueCounter
: Integer = 0;
460 function TWADFile
.ReadMemory (Data
: Pointer; Len
: LongWord): Boolean;
469 if (Data
= nil) or (Len
= 0) then
471 e_WriteLog('TWADFile.ReadMemory: EMPTY SUBWAD!', MSG_WARNING
);
475 fn
:= Format(' -- memwad %d -- ', [uniqueCounter
]);
477 {$IFDEF SFS_DWFAD_DEBUG}
478 e_WriteLog(Format('TWADFile.ReadMemory: [%s]', [fn
]), MSG_NOTIFY
);
482 st
:= TSFSMemoryStreamRO
.Create(Data
, Len
);
483 if not SFSAddSubDataFile(fn
, st
, true) then
493 fIter
:= SFSFileList(fn
);
494 if fIter
= nil then Exit
;
497 {$IFDEF SFS_DWFAD_DEBUG}
498 e_WriteLog(Format('TWADFile.ReadMemory: [%s] opened', [fFileName
]), MSG_NOTIFY
);
502 for f := 0 to fIter.Count-1 do
504 fi := fIter.Files[f];
505 if fi = nil then continue;
506 st := fIter.volume.OpenFileByIndex(f);
509 e_WriteLog(Format('[%s]: [%s : %s] CAN''T OPEN', [fFileName, fi.path, fi.name]), MSG_NOTIFY);
513 e_WriteLog(Format('[%s]: [%s : %s] %u', [fFileName, fi.path, fi.name, st.size]), MSG_NOTIFY);
517 //fIter.volume.OpenFileByIndex(0);
525 sfsDiskDirs
:= '<exedir>/data'; //FIXME