From: Ketmar Dark Date: Fri, 22 Apr 2016 15:03:11 +0000 (+0300) Subject: sfs, wadreader: much better searching for files inside archives with extra dirs in... X-Git-Url: http://deadsoftware.ru/gitweb?p=d2df-sdl.git;a=commitdiff_plain;h=7908eab8a8bb5a2de31a03e588b2f12900c898c5 sfs, wadreader: much better searching for files inside archives with extra dirs in pathnames --- diff --git a/src/game/g_gui.pas b/src/game/g_gui.pas index 9319e45..cd9d3b9 100644 --- a/src/game/g_gui.pas +++ b/src/game/g_gui.pas @@ -2484,7 +2484,7 @@ begin end; //k8: ignores path again - if not WAD.GetResource(g_ExtractFileName(Res), Data, Len) then + if not WAD.GetMapResource(g_ExtractFileName(Res), Data, Len) then begin WAD.Free(); Exit; diff --git a/src/game/g_map.pas b/src/game/g_map.pas index 6c156ca..2c61144 100644 --- a/src/game/g_map.pas +++ b/src/game/g_map.pas @@ -799,7 +799,7 @@ begin end; //k8: why loader ignores path here? mapResName := g_ExtractFileName(Res); - if not WAD.GetResource(mapResName, Data, Len) then + if not WAD.GetMapResource(mapResName, Data, Len) then begin g_FatalError(Format(_lc[I_GAME_ERROR_MAP_RES], [mapResName])); WAD.Free(); @@ -1267,7 +1267,7 @@ begin end; //k8: it ignores path again - if not WAD.GetResource(g_ExtractFileName(Res), Data, Len) then + if not WAD.GetMapResource(g_ExtractFileName(Res), Data, Len) then begin WAD.Free(); Exit; @@ -1305,37 +1305,23 @@ var WAD: TWADFile; a: Integer; ResList: SArray; - Data: Pointer; - Len: Integer; - Sign: Array [0..2] of Char; begin Result := nil; - WAD := TWADFile.Create(); if not WAD.ReadFile(WADName) then begin WAD.Free(); Exit; end; - - ResList := WAD.GetRootResources(); - + ResList := WAD.GetMapResources(); if ResList <> nil then + begin for a := 0 to High(ResList) do begin - if not WAD.GetResource(ResList[a], Data, Len) then Continue; - CopyMemory(@Sign[0], Data, 3); - FreeMem(Data); - - if Sign = MAP_SIGNATURE then - begin - SetLength(Result, Length(Result)+1); - Result[High(Result)] := ResList[a]; - end; - - Sign := ''; + SetLength(Result, Length(Result)+1); + Result[High(Result)] := ResList[a]; end; - + end; WAD.Free(); end; @@ -1357,7 +1343,7 @@ begin Exit; end; - ResList := WAD.GetRootResources(); + ResList := WAD.GetMapResources(); WAD.Free(); mnn := g_ExtractFileName(Res); diff --git a/src/sfs/sfs.pas b/src/sfs/sfs.pas index 948b470..d4ebdeb 100644 --- a/src/sfs/sfs.pas +++ b/src/sfs/sfs.pas @@ -70,8 +70,6 @@ type // íèêàêèõ ïàäåíèé íà íåïðàâèëüíûå èíäåêñû! function GetFiles (index: Integer): TSFSFileInfo; virtual; - procedure removeCommonPath (); virtual; - public // pSt íå îáÿçàòåëüíî çàïîìèíàòü, åñëè îí íå íóæåí. constructor Create (const pFileName: AnsiString; pSt: TStream); virtual; @@ -744,10 +742,6 @@ begin fFiles := TObjectList.Create(true); end; -procedure TSFSVolume.removeCommonPath (); -begin -end; - procedure TSFSVolume.DoDirectoryRead (); var f, c: Integer; @@ -779,7 +773,6 @@ begin sfi.fPath := normalizePath(sfi.fPath); if (length(sfi.fPath) = 0) and (length(sfi.fName) = 0) then sfi.Free else Inc(f); end; - removeCommonPath(); end; destructor TSFSVolume.Destroy (); diff --git a/src/sfs/sfsZipFS.pas b/src/sfs/sfsZipFS.pas index c39eb43..d76114c 100644 --- a/src/sfs/sfsZipFS.pas +++ b/src/sfs/sfsZipFS.pas @@ -28,7 +28,6 @@ type procedure DFWADReadDirectory (); procedure ReadDirectory (); override; - procedure removeCommonPath (); override; public function OpenFileByIndex (const index: Integer): TStream; override; @@ -114,65 +113,6 @@ begin end; -function maxPrefix (s0: string; s1: string): Integer; -var - f: Integer; -begin - for f := 1 to length(s0) do - begin - if f > length(s1) then begin result := f; exit; end; - if UpCase1251(s0[f]) <> UpCase1251(s1[f]) then begin result := f; exit; end; - end; - result := length(s0); -end; - - -procedure TSFSZipVolume.removeCommonPath (); -var - f, pl, maxsc, sc, c: integer; - cp, s: string; - fi: TSFSZipFileInfo; -begin - if fType <> sfszvZIP then exit; - maxsc := 0; - if fFiles.Count = 0 then exit; - cp := ''; - for f := 0 to fFiles.Count-1 do - begin - fi := TSFSZipFileInfo(fFiles[f]); - s := fi.fPath; - if length(s) > 0 then begin cp := s; break; end; - end; - if length(cp) = 0 then exit; - for f := 0 to fFiles.Count-1 do - begin - fi := TSFSZipFileInfo(fFiles[f]); - s := fi.fPath; - if length(s) = 0 then continue; - pl := maxPrefix(cp, s); - //writeln('s=[', s, ']; cp=[', cp, ']; pl=', pl); - if pl = 0 then exit; // no common prefix at all - cp := Copy(cp, 1, pl); - sc := 0; - for c := 1 to length(s) do if s[c] = '/' then Inc(sc); - if sc > maxsc then maxsc := sc; - end; - if maxsc < 2 then exit; // alas - while (length(cp) > 0) and (cp[length(cp)] <> '/') do cp := Copy(cp, 1, length(cp)-1); - if length(cp) < 2 then exit; // nothing to do - for f := 0 to fFiles.Count-1 do - begin - fi := TSFSZipFileInfo(fFiles[f]); - if length(fi.fPath) >= length(cp) then - begin - s := fi.fPath; - fi.fPath := Copy(fi.fPath, length(cp)+1, length(fi.fPath)); - //writeln('FIXED [', s, '] -> [', fi.fPath, ']'); - end; - end; -end; - - { TSFSZipVolume } procedure TSFSZipVolume.ZIPReadDirectory (); var diff --git a/src/shared/wadreader.pas b/src/shared/wadreader.pas index ade53ad..1c5fb19 100644 --- a/src/shared/wadreader.pas +++ b/src/shared/wadreader.pas @@ -2,6 +2,7 @@ unit wadreader; {$DEFINE SFS_DWFAD_DEBUG} +{$DEFINE SFS_MAPDETECT_FX} interface @@ -18,6 +19,9 @@ type fIter: TSFSFileList; function getIsOpen (): Boolean; + function isMapResource (idx: Integer): Boolean; + + function GetResourceEx (name: AnsiString; wantMap: Boolean; var pData: Pointer; var Len: Integer): Boolean; public constructor Create(); @@ -29,7 +33,8 @@ type function ReadMemory (Data: Pointer; Len: LongWord): Boolean; function GetResource (name: AnsiString; var pData: Pointer; var Len: Integer): Boolean; - function GetRootResources (): SArray; + function GetMapResource (name: AnsiString; var pData: Pointer; var Len: Integer): Boolean; + function GetMapResources (): SArray; property isOpen: Boolean read getIsOpen; end; @@ -48,7 +53,7 @@ function findDiskWad (fname: AnsiString): AnsiString; implementation uses - SysUtils, Classes, BinEditor, e_log, g_options, utils; + SysUtils, Classes, BinEditor, e_log, g_options, utils, MAPSTRUCT; function findDiskWad (fname: AnsiString): AnsiString; @@ -199,6 +204,25 @@ begin fFileName := ''; end; +function TWADFile.isMapResource (idx: Integer): Boolean; +var + sign: packed array [0..2] of Char; + fs: TStream; +begin + result := false; + if not isOpen or (fIter = nil) then exit; + if (idx < 0) or (idx >= fIter.Count) then exit; + fs := nil; + try + fs := fIter.volume.OpenFileByIndex(idx); + fs.readBuffer(sign, 3); + result := (sign = MAP_SIGNATURE); + except + if fs <> nil then fs.Free(); + exit; + end; + fs.Free(); +end; function removeExt (s: AnsiString): AnsiString; var @@ -214,14 +238,15 @@ begin result := s; end; -function TWADFile.GetResource (name: AnsiString; var pData: Pointer; var Len: Integer): Boolean; +function TWADFile.GetResourceEx (name: AnsiString; wantMap: Boolean; var pData: Pointer; var Len: Integer): Boolean; var f, lastSlash: Integer; fi: TSFSFileInfo; fs: TStream; fpp: Pointer; rpath, rname: AnsiString; - //fn: AnsiString; + sign: array [0..2] of Char; + goodMap: Boolean; begin Result := False; if not isOpen or (fIter = nil) then Exit; @@ -247,12 +272,22 @@ begin begin fi := fIter.Files[f]; if fi = nil then continue; - //e_WriteLog(Format('DFWAD: searching for [%s : %s] in [%s]; current is [%s : %s]', [Section, Resource, fFileName, fi.path, fi.name]), MSG_NOTIFY); - if StrEquCI1251(fi.path, rpath) and StrEquCI1251(removeExt(fi.name), rname) then + if StrEquCI1251(removeExt(fi.name), rname) then begin - // i found her! - //fn := fFileName+'::'+fi.path+fi.name; - //fs := SFSFileOpen(fn); + // i found her (maybe) + if not wantMap then + begin + if length(fi.path) < length(rpath) then continue; // alas + if length(fi.path) = length(rpath) then + begin + if not StrEquCI1251(fi.path, rpath) then continue; // alas + end + else + begin + if fi.path[length(fi.path)-length(rpath)] <> '/' then continue; // alas + if not StrEquCI1251(Copy(fi.path, length(fi.path)+1-length(rpath), length(fi.path)), rpath) then continue; // alas + end; + end; try fs := fIter.volume.OpenFileByIndex(f); except @@ -260,9 +295,34 @@ begin end; if fs = nil then begin + if wantMap then continue; e_WriteLog(Format('DFWAD: can''t open file [%s] in [%s]', [name, fFileName]), MSG_WARNING); break; end; + // if we want only maps, check if this is map +{$IFDEF SFS_MAPDETECT_FX} + if wantMap then + begin + goodMap := false; + e_WriteLog(Format('DFWAD: checking for good map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]), MSG_NOTIFY); + try + fs.readBuffer(sign, 3); + goodMap := (sign = MAP_SIGNATURE); + if goodMap then + e_WriteLog(Format(' GOOD map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]), MSG_NOTIFY) + else + e_WriteLog(Format(' BAD map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]), MSG_NOTIFY); + except + end; + if not goodMap then + begin + e_WriteLog(Format(' not a map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]), MSG_NOTIFY); + fs.Free(); + continue; + end; + fs.position := 0; + end; +{$ENDIF} Len := Integer(fs.size); GetMem(pData, Len); fpp := pData; @@ -278,6 +338,25 @@ begin end; fs.Free; end; +{$IFNDEF SFS_MAPDETECT_FX} + if wantMap then + begin + goodMap := false; + if Len >= 3 then + begin + Move(pData^, sign, 3); + goodMap := (sign = MAP_SIGNATURE); + end; + if not goodMap then + begin + e_WriteLog(Format(' not a map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]), MSG_NOTIFY); + FreeMem(pData); + pData := nil; + Len := 0; + continue; + end; + end; +{$ENDIF} result := true; {$IFDEF SFS_DWFAD_DEBUG} if gSFSDebug then @@ -289,23 +368,44 @@ begin e_WriteLog(Format('DFWAD: file [%s] not found in [%s]', [name, fFileName]), MSG_WARNING); end; +function TWADFile.GetResource (name: AnsiString; var pData: Pointer; var Len: Integer): Boolean; +begin + result := GetResourceEx(name, false, pData, Len); +end; -function TWADFile.GetRootResources (): SArray; +function TWADFile.GetMapResource (name: AnsiString; var pData: Pointer; var Len: Integer): Boolean; +begin + result := GetResourceEx(name, true, pData, Len); +end; + +function TWADFile.GetMapResources (): SArray; var - f: Integer; + f, c: Integer; fi: TSFSFileInfo; + s: AnsiString; begin Result := nil; if not isOpen or (fIter = nil) then Exit; - for f := 0 to fIter.Count-1 do + for f := fIter.Count-1 downto 0 do begin fi := fIter.Files[f]; if fi = nil then continue; if length(fi.name) = 0 then continue; - if length(fi.path) = 0 then + e_WriteLog(Format('DFWAD: checking for map in wad [%s], file [%s] (#%d)', [fFileName, fi.fname, f]), MSG_NOTIFY); + if isMapResource(f) then begin - SetLength(result, Length(result)+1); - result[high(result)] := removeExt(fi.name); + s := removeExt(fi.name); + c := High(result); + while c >= 0 do + begin + if StrEquCI1251(result[c], s) then break; + Dec(c); + end; + if c < 0 then + begin + SetLength(result, Length(result)+1); + result[high(result)] := removeExt(fi.name); + end; end; end; end;