X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fshared%2Fwadreader.pas;h=2997bce0abac0b94b78c6a49f96b45dca027c65e;hb=7292fe409145dfcbb2776e34bb64d56e32985b9d;hp=ade53adcf7f9343c6ed882a20c7df2b626b0ac7e;hpb=af3c404e11867c6794975f1d45dd98932d804ede;p=d2df-sdl.git diff --git a/src/shared/wadreader.pas b/src/shared/wadreader.pas index ade53ad..2997bce 100644 --- a/src/shared/wadreader.pas +++ b/src/shared/wadreader.pas @@ -1,7 +1,23 @@ +(* Copyright (C) DooM 2D:Forever Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *) {$MODE DELPHI} unit wadreader; {$DEFINE SFS_DWFAD_DEBUG} +{$DEFINE SFS_MAPDETECT_FX} interface @@ -18,6 +34,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 +48,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; @@ -45,10 +65,15 @@ function g_ExtractFilePathName (resourceStr: AnsiString): AnsiString; function findDiskWad (fname: AnsiString): AnsiString; +var + wadoptDebug: Boolean = false; + wadoptFast: Boolean = false; + + implementation uses - SysUtils, Classes, BinEditor, e_log, g_options, utils; + SysUtils, Classes{, BinEditor}, e_log{, g_options}, utils, MAPSTRUCT; function findDiskWad (fname: AnsiString): AnsiString; @@ -130,7 +155,11 @@ begin if (lastSlash < 0) and (resourceStr[f] = '\') or (resourceStr[f] = '/') then lastSlash := f; if resourceStr[f] = ':' then begin - if lastSlash > 0 then result := normSlashes(Copy(resourceStr, f, lastSlash-f)); + if lastSlash > 0 then + begin + result := normSlashes(Copy(resourceStr, f, lastSlash-f)); + while (length(result) > 0) and (result[1] = '/') do Delete(result, 1, 1); + end; exit; end; end; @@ -165,9 +194,12 @@ begin if resourceStr[f] = ':' then begin result := normSlashes(Copy(resourceStr, f+1, length(resourceStr))); + while (length(result) > 0) and (result[1] = '/') do Delete(result, 1, 1); exit; end; end; + result := normSlashes(resourceStr); + while (length(result) > 0) and (result[1] = '/') do Delete(result, 1, 1); end; @@ -199,6 +231,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 +265,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 +299,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 +322,36 @@ 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,9 +367,28 @@ 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 + if wadoptDebug then e_WriteLog(Format('DFWAD: file [%s] FOUND in [%s]; size is %d bytes', [name, fFileName, Len]), MSG_NOTIFY); {$ENDIF} exit; @@ -289,23 +397,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; @@ -327,11 +456,11 @@ begin exit; end; {$IFDEF SFS_DWFAD_DEBUG} - if gSFSDebug then e_WriteLog(Format('TWADFile.ReadFile: FOUND [%s]', [rfn]), MSG_NOTIFY); + if wadoptDebug then e_WriteLog(Format('TWADFile.ReadFile: FOUND [%s]', [rfn]), MSG_NOTIFY); {$ENDIF} // cache this wad try - if gSFSFastMode then + if wadoptFast then begin if not SFSAddDataFile(rfn, true) then exit; end @@ -346,7 +475,7 @@ begin if fIter = nil then Exit; fFileName := rfn; {$IFDEF SFS_DWFAD_DEBUG} - if gSFSDebug then e_WriteLog(Format('TWADFile.ReadFile: [%s] opened', [fFileName]), MSG_NOTIFY); + if wadoptDebug then e_WriteLog(Format('TWADFile.ReadFile: [%s] opened', [fFileName]), MSG_NOTIFY); {$ENDIF} Result := True; end;