summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 029af84)
raw | patch | inline | side by side (parent: 029af84)
author | DeaDDooMER <deaddoomer@deadsoftware.ru> | |
Wed, 13 Sep 2023 15:34:18 +0000 (18:34 +0300) | ||
committer | DeaDDooMER <deaddoomer@deadsoftware.ru> | |
Wed, 13 Sep 2023 15:35:19 +0000 (18:35 +0300) |
src/shared/WADEDITOR_dfwad.pas | patch | blob | history |
index f011d30a62f531b0602d955ee0f7796fba23d9c7..97097bb2f7c47ac3fa2c406ee6dfb8368810f9d6 100644 (file)
+{$INCLUDE ../shared/a_modes.inc}
+
unit WADEDITOR_dfwad;
-{
------------------------------------
-WADEDITOR.PAS ÂÅÐÑÈß ÎÒ 26.08.08
+interface
-Ïîääåðæêà âàäîâ âåðñèè 1
------------------------------------
-}
+ uses Classes, WADEDITOR;
-interface
+ type
+ TData = class
+ ref: Integer; // number of links
+ pos: Int64; // position in source (if pos < 0 -> not in source file)
+ csize: Int64; // compressed size
+ usize: Int64; // decompressed size (usize < 0 -> unknown)
+ stream: TMemoryStream; // copy of compressed data
+ end;
-uses WADEDITOR, WADSTRUCT;
-
-type
- TWADEditor_1 = class sealed(WADEDITOR.TWADEditor)
- private
- FResData: Pointer;
- FResTable: packed array of TResourceTableRec_1;
- FHeader: TWADHeaderRec_1;
- FDataSize: LongWord;
- FOffset: LongWord;
- FFileName: string;
- FWADOpened: Byte;
- FLastError: Integer;
- FVersion: Byte;
- function LastErrorString(): string;
- function GetResName(ResName: string): Char16;
- public
- constructor Create();
- destructor Destroy(); override;
- procedure FreeWAD(); override;
- function ReadFile2(FileName: string): Boolean; override;
- function ReadMemory(Data: Pointer; Len: LongWord): Boolean; override;
- procedure CreateImage(); override;
- function AddResource(Data: Pointer; Len: LongWord; Name: string;
- Section: string): Boolean; override; overload;
- function AddResource(FileName, Name, Section: string): Boolean; override; overload;
- function AddAlias(Res, Alias: string): Boolean; override;
- procedure AddSection(Name: string); override;
- procedure RemoveResource(Section, Resource: string); override;
- procedure SaveTo(FileName: string); override;
- function HaveResource(Section, Resource: string): Boolean; override;
- function HaveSection(Section: string): Boolean; override;
- function GetResource(Section, Resource: string; var pData: Pointer;
- var Len: Integer): Boolean; override;
- function GetSectionList(): SArray; override;
- function GetResourcesList(Section: string): SArray; override;
-
- function GetLastError: Integer; override;
- function GetLastErrorStr: String; override;
- function GetResourcesCount: Word; override;
- function GetVersion: Byte; override;
-
- // property GetLastError: Integer read FLastError;
- // property GetLastErrorStr: string read LastErrorString;
- // property GetResourcesCount: Word read FHeader.RecordsCount;
- // property GetVersion: Byte read FVersion;
- end;
-
-const
- DFWAD_NOERROR = 0;
- DFWAD_ERROR_WADNOTFOUND = -1;
- DFWAD_ERROR_CANTOPENWAD = -2;
- DFWAD_ERROR_RESOURCENOTFOUND = -3;
- DFWAD_ERROR_FILENOTWAD = -4;
- DFWAD_ERROR_WADNOTLOADED = -5;
- DFWAD_ERROR_READRESOURCE = -6;
- DFWAD_ERROR_READWAD = -7;
- DFWAD_ERROR_WRONGVERSION = -8;
+ TResource = record
+ name: AnsiString;
+ data: TData;
+ end;
+
+ TSection = record
+ name: AnsiString;
+ list: array of TResource;
+ end;
+
+ PResource = ^TResource;
+ PSection = ^TSection;
+
+ TDFWEditor = class sealed(WADEDITOR.TWADEditor)
+ private
+ FSection: array of TSection;
+ FData: array of TData;
+ FStream: TStream;
+ FLastError: Integer;
+ FVersion: Byte;
+
+ function FindSectionIDRAW(name: AnsiString; caseSensitive: Boolean): Integer;
+ function FindSectionRAW(name: AnsiString; caseSensitive: Boolean): PSection;
+ function InsertSectionRAW(name: AnsiString): PSection;
+
+ function FindSectionID(name: AnsiString): Integer;
+ function FindSection(name: AnsiString): PSection;
+ function InsertSection(name: AnsiString): PSection;
+
+ function FindDataID(pos: Int64): Integer;
+ function FindData(pos: Int64): TData;
+ function InsertData(ref, pos, csize, usize: Int64; stream: TMemoryStream): TData;
+
+ function InsertFileInfoS(p: PSection; const name: AnsiString; pos, csize, usize: Int64; stream: TMemoryStream): PResource;
+ function InsertFileInfo(const section, name: AnsiString; pos, csize, usize: Int64; stream: TMemoryStream): PResource;
+ function Preload(data: TData): Boolean;
+ function GetSourceStream(p: PResource): TStream;
+
+ procedure Clear();
+ procedure Collect();
+ procedure ReadFromStream(s: TStream);
+ procedure SaveToStream(s: TStream);
+
+ public
+ constructor Create();
+ destructor Destroy(); override;
+ procedure FreeWAD(); override;
+ function ReadFile2(FileName: string): Boolean; override;
+ function ReadMemory(Data: Pointer; Len: LongWord): Boolean; override;
+ procedure CreateImage(); override;
+ function AddResource(Data: Pointer; Len: LongWord; Name, Section: String): Boolean; override; overload;
+ function AddResource(FileName, Name, Section: String): Boolean; override; overload;
+ function AddAlias(Res, Alias: String): Boolean; override;
+ procedure AddSection(Name: String); override;
+ procedure RemoveResource(Section, Resource: String); override;
+ procedure SaveTo(FileName: String); override;
+ function HaveResource(Section, Resource: String): Boolean; override;
+ function HaveSection(Section: string): Boolean; override;
+ function GetResource(Section, Resource: String; var pData: Pointer; var Len: Integer): Boolean; override;
+ function GetSectionList(): SArray; override;
+ function GetResourcesList(Section: String): SArray; override;
+
+ function GetLastError: Integer; override;
+ function GetLastErrorStr: String; override;
+ function GetResourcesCount: Word; override;
+ function GetVersion: Byte; override;
+ end;
implementation
-uses
- SysUtils, BinEditor, ZLib, utils, e_log;
+ uses SysUtils, StrUtils, DateUtils, Math, utils, zstream, crc, e_log;
-const
- DFWAD_OPENED_NONE = 0;
- DFWAD_OPENED_FILE = 1;
- DFWAD_OPENED_MEMORY = 2;
+ function PrepString(const s: AnsiString; caseSensitive, extSensitive: Boolean): AnsiString; inline;
+ var i: Integer;
+ begin
+ Result := s;
+ if caseSensitive = False then
+ begin
+ Result := UpperCase(Result);
+ end;
+ if extSensitive = False then
+ begin
+ i := Pos('.', Result); // fix dotfiles
+ if i > 1 then
+ SetLength(Result, i - 1);
+ end;
+ end;
-procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
- OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer);
-var
- strm: TZStreamRec;
- P: Pointer;
- BufInc: Integer;
-begin
- FillChar(strm, sizeof(strm), 0);
- BufInc := (InBytes + 255) and not 255;
- if OutEstimate = 0 then
- OutBytes := BufInc
- else
- OutBytes := OutEstimate;
- GetMem(OutBuf, OutBytes);
- try
- strm.next_in := InBuf;
- strm.avail_in := InBytes;
- strm.next_out := OutBuf;
- strm.avail_out := OutBytes;
- inflateInit_(strm, zlib_version, sizeof(strm));
- try
- while inflate(strm, Z_FINISH) <> Z_STREAM_END do
+ function FindResourceIDRAW(p: PSection; name: AnsiString; caseSensitive, extSensitive: Boolean): Integer;
+ var i: Integer; pname: AnsiString;
+ begin
+ if p <> nil then
+ begin
+ pname := PrepString(name, caseSensitive, extSensitive);
+ for i := 0 to High(p.list) do
begin
- P := OutBuf;
- Inc(OutBytes, BufInc);
- ReallocMem(OutBuf, OutBytes);
- strm.next_out := PByteF(PChar(OutBuf) + (PChar(strm.next_out) - PChar(P)));
- strm.avail_out := BufInc;
+ if PrepString(p.list[i].name, caseSensitive, extSensitive) = pname then
+ begin
+ Result := i;
+ exit;
+ end;
end;
- finally
- inflateEnd(strm);
end;
- ReallocMem(OutBuf, strm.total_out);
- OutBytes := strm.total_out;
- except
- FreeMem(OutBuf);
- raise
- end;
-end;
-
-procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
- out OutBuf: Pointer; out OutBytes: Integer);
-var
- strm: TZStreamRec;
- P: Pointer;
-begin
- FillChar(strm, sizeof(strm), 0);
- OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255;
- GetMem(OutBuf, OutBytes);
- try
- strm.next_in := InBuf;
- strm.avail_in := InBytes;
- strm.next_out := OutBuf;
- strm.avail_out := OutBytes;
- deflateInit_(strm, Z_BEST_COMPRESSION, zlib_version, sizeof(strm));
- try
- while deflate(strm, Z_FINISH) <> Z_STREAM_END do
+ Result := -1;
+ end;
+
+ function FindResourceID(p: PSection; name: AnsiString): Integer;
+ var i: Integer;
+ begin
+ i := FindResourceIDRAW(p, name, True, True); // CaSeNaMe.Ext
+ if i < 0 then
+ begin
+ i := FindResourceIDRAW(p, name, False, True); // CASENAME.EXT
+ if i < 0 then
begin
- P := OutBuf;
- Inc(OutBytes, 256);
- ReallocMem(OutBuf, OutBytes);
- strm.next_out := PByteF(PtrUInt(OutBuf + (strm.next_out - P)));
- strm.avail_out := 256;
+ i := FindResourceIDRAW(p, name, True, False); // CaSeNaMe
+ if i < 0 then
+ begin
+ i := FindResourceIDRAW(p, name, False, False); // CASENAME
+ end;
end;
- finally
- deflateEnd(strm);
end;
- ReallocMem(OutBuf, strm.total_out);
- OutBytes := strm.total_out;
- except
- FreeMem(OutBuf);
- raise
- end;
-end;
-
-{ TWADEditor_1 }
-
-function TWADEditor_1.AddResource(Data: Pointer; Len: LongWord; Name: string;
- Section: string): Boolean;
-var
- ResCompressed: Pointer;
- ResCompressedSize: Integer;
- a, b: Integer;
-begin
- Result := False;
-
- SetLength(FResTable, Length(FResTable)+1);
-
- if Section = '' then
- begin
- if Length(FResTable) > 1 then
- for a := High(FResTable) downto 1 do
- FResTable[a] := FResTable[a-1];
-
- a := 0;
- end
- else
- begin
- Section := AnsiUpperCase(Section);
- b := -1;
-
- for a := 0 to High(FResTable) do
- if (FResTable[a].Length = 0) and (FResTable[a].ResourceName = Section) then
- begin
- for b := High(FResTable) downto a+2 do
- FResTable[b] := FResTable[b-1];
-
- b := a+1;
- Break;
- end;
+ Result := i;
+ end;
- if b = -1 then
+ function FindResource(p: PSection; name: AnsiString): PResource;
+ var i: Integer;
begin
- SetLength(FResTable, Length(FResTable)-1);
- Exit;
+ i := FindResourceID(p, name);
+ if i >= 0 then Result := @p.list[i] else Result := nil;
end;
- a := b;
- end;
-
- ResCompressed := nil;
- ResCompressedSize := 0;
- CompressBuf(Data, Len, ResCompressed, ResCompressedSize);
- if ResCompressed = nil then Exit;
- e_WriteLog('Fuck me (D)', MSG_NOTIFY);
- if FResData = nil then FResData := AllocMem(ResCompressedSize)
- else ReallocMem(FResData, FDataSize+Cardinal(ResCompressedSize));
- FDataSize := FDataSize+LongWord(ResCompressedSize);
- CopyMemory(Pointer(PChar(FResData)+FDataSize-PChar(ResCompressedSize)),
- ResCompressed, ResCompressedSize);
- FreeMemory(ResCompressed);
-
- Inc(FHeader.RecordsCount);
-
- with FResTable[a] do
- begin
- ResourceName := GetResName(Name);
- Address := FOffset;
- Length := ResCompressedSize;
- end;
-
- FOffset := FOffset+Cardinal(ResCompressedSize);
-
- Result := True;
-end;
-
-function TWADEditor_1.AddAlias(Res, Alias: string): Boolean;
-var
- a, b: Integer;
- ares: Char16;
-begin
- Result := False;
-
- if FResTable = nil then Exit;
-
- b := -1;
- ares := GetResName(Alias);
- for a := 0 to High(FResTable) do
- if FResTable[a].ResourceName = Res then
+ function TDFWEditor.FindSectionIDRAW(name: AnsiString; caseSensitive: Boolean): Integer;
+ var i: Integer; pname: AnsiString;
begin
- b := a;
- Break;
+ if FSection <> nil then
+ begin
+ pname := PrepString(name, caseSensitive, True);
+ for i := 0 to High(FSection) do
+ begin
+ if PrepString(FSection[i].name, caseSensitive, True) = pname then
+ begin
+ Result := i;
+ exit;
+ end;
+ end;
+ end;
+ Result := -1;
end;
- if b = -1 then Exit;
-
- Inc(FHeader.RecordsCount);
-
- SetLength(FResTable, Length(FResTable)+1);
-
- with FResTable[High(FResTable)] do
- begin
- ResourceName := ares;
- Address := FResTable[b].Address;
- Length := FResTable[b].Length;
- end;
-
- Result := True;
-end;
-
-function TWADEditor_1.AddResource(FileName, Name, Section: string): Boolean;
-var
- ResCompressed: Pointer;
- ResCompressedSize: Integer;
- ResourceFile: File;
- TempResource: Pointer;
- OriginalSize: Integer;
- a, b: Integer;
-begin
- Result := False;
-
- AssignFile(ResourceFile, FileName);
-
- try
- Reset(ResourceFile, 1);
- except
- FLastError := DFWAD_ERROR_CANTOPENWAD;
- Exit;
- end;
-
- OriginalSize := FileSize(ResourceFile);
- GetMem(TempResource, OriginalSize);
-
- try
- BlockRead(ResourceFile, TempResource^, OriginalSize);
- except
- FLastError := DFWAD_ERROR_READWAD;
- FreeMemory(TempResource);
- CloseFile(ResourceFile);
- Exit;
- end;
-
- CloseFile(ResourceFile);
-
- ResCompressed := nil;
- ResCompressedSize := 0;
- CompressBuf(TempResource, OriginalSize, ResCompressed, ResCompressedSize);
- FreeMemory(TempResource);
- if ResCompressed = nil then Exit;
-
- SetLength(FResTable, Length(FResTable)+1);
-
- if Section = '' then
- begin
- if Length(FResTable) > 1 then
- for a := High(FResTable) downto 1 do
- FResTable[a] := FResTable[a-1];
-
- a := 0;
- end
- else
- begin
- Section := AnsiUpperCase(Section);
- b := -1;
-
- for a := 0 to High(FResTable) do
- if (FResTable[a].Length = 0) and (FResTable[a].ResourceName = Section) then
- begin
- for b := High(FResTable) downto a+2 do
- FResTable[b] := FResTable[b-1];
-
- b := a+1;
- Break;
- end;
-
- if b = -1 then
+ function TDFWEditor.FindSectionRAW(name: AnsiString; caseSensitive: Boolean): PSection;
+ var i: Integer;
begin
- FreeMemory(ResCompressed);
- SetLength(FResTable, Length(FResTable)-1);
- Exit;
+ i := FindSectionIDRAW(name, caseSensitive);
+ if i >= 0 then Result := @FSection[i] else Result := nil;
end;
- a := b;
- end;
-
- if FResData = nil then FResData := AllocMem(ResCompressedSize)
- else ReallocMem(FResData, FDataSize+Cardinal(ResCompressedSize));
-
- FDataSize := FDataSize+LongWord(ResCompressedSize);
- CopyMemory(Pointer(PChar(FResData)+FDataSize-PChar(ResCompressedSize)),
- ResCompressed, ResCompressedSize);
- FreeMemory(ResCompressed);
-
- Inc(FHeader.RecordsCount);
-
- with FResTable[a] do
- begin
- ResourceName := GetResName(Name);
- Address := FOffset;
- Length := ResCompressedSize;
- end;
-
- FOffset := FOffset+Cardinal(ResCompressedSize);
-
- Result := True;
-end;
-
-procedure TWADEditor_1.AddSection(Name: string);
-begin
- if Name = '' then Exit;
-
- Inc(FHeader.RecordsCount);
-
- SetLength(FResTable, Length(FResTable)+1);
- with FResTable[High(FResTable)] do
- begin
- ResourceName := GetResName(Name);
- Address := $00000000;
- Length := $00000000;
- end;
-end;
-
-constructor TWADEditor_1.Create();
-begin
- FResData := nil;
- FResTable := nil;
- FDataSize := 0;
- FOffset := 0;
- FHeader.RecordsCount := 0;
- FFileName := '';
- FWADOpened := DFWAD_OPENED_NONE;
- FLastError := DFWAD_NOERROR;
- FVersion := DFWAD_VERSION;
-end;
-
-procedure TWADEditor_1.CreateImage();
-var
- WADFile: File;
- b: LongWord;
-begin
- if FWADOpened = DFWAD_OPENED_NONE then
- begin
- FLastError := DFWAD_ERROR_WADNOTLOADED;
- Exit;
- end;
-
- if FWADOpened = DFWAD_OPENED_MEMORY then Exit;
-
- if FResData <> nil then FreeMem(FResData);
-
- try
- AssignFile(WADFile, FFileName);
- Reset(WADFile, 1);
-
- b := 6+SizeOf(TWADHeaderRec_1)+SizeOf(TResourceTableRec_1)*Length(FResTable);
-
- FDataSize := LongWord(FileSize(WADFile))-b;
-
- GetMem(FResData, FDataSize);
-
- Seek(WADFile, b);
- BlockRead(WADFile, FResData^, FDataSize);
-
- CloseFile(WADFile);
-
- FOffset := FDataSize;
- except
- FLastError := DFWAD_ERROR_CANTOPENWAD;
- CloseFile(WADFile);
- Exit;
- end;
-
- FLastError := DFWAD_NOERROR;
-end;
-
-destructor TWADEditor_1.Destroy();
-begin
- FreeWAD();
-
- inherited;
-end;
-
-procedure TWADEditor_1.FreeWAD();
-begin
- if FResData <> nil then FreeMem(FResData);
- FResTable := nil;
- FDataSize := 0;
- FOffset := 0;
- FHeader.RecordsCount := 0;
- FFileName := '';
- FWADOpened := DFWAD_OPENED_NONE;
- FLastError := DFWAD_NOERROR;
- FVersion := DFWAD_VERSION;
-end;
-
-function TWADEditor_1.GetResName(ResName: string): Char16;
-begin
- ZeroMemory(@Result[0], 16);
- if ResName = '' then Exit;
-
- ResName := Trim(UpperCase(ResName));
- if Length(ResName) > 16 then SetLength(ResName, 16);
-
- CopyMemory(@Result[0], @ResName[1], Length(ResName));
-end;
-
-function TWADEditor_1.HaveResource(Section, Resource: string): Boolean;
-var
- a: Integer;
- CurrentSection: string;
-begin
- Result := False;
+ function TDFWEditor.InsertSectionRAW(name: AnsiString): PSection;
+ var i: Integer;
+ begin
+ if FSection = nil then i := 0 else i := Length(FSection);
+ SetLength(FSection, i + 1);
+ FSection[i] := Default(TSection);
+ FSection[i].name := name;
+ Result := @FSection[i];
+ end;
- if FResTable = nil then Exit;
- CurrentSection := '';
- Section := AnsiUpperCase(Section);
- Resource := AnsiUpperCase(Resource);
- for a := 0 to High(FResTable) do
- begin
- if FResTable[a].Length = 0 then
+ function TDFWEditor.FindSectionID(name: AnsiString): Integer;
+ var fixName: AnsiString;
begin
- CurrentSection := FResTable[a].ResourceName;
- Continue;
+ fixName := StringReplace(name, '\', '/', [rfReplaceAll], TStringReplaceAlgorithm.sraManySmall);
+ Result := FindSectionIDRAW(fixName, True); // CaSeNaMe
+ if Result < 0 then
+ Result := FindSectionIDRAW(fixName, False); // CASENAME
end;
- if (FResTable[a].ResourceName = Resource) and
- (CurrentSection = Section) then
+ function TDFWEditor.FindSection(name: AnsiString): PSection;
+ var fixName: AnsiString;
begin
- Result := True;
- Break;
+ fixName := StringReplace(name, '\', '/', [rfReplaceAll], TStringReplaceAlgorithm.sraManySmall);
+ Result := FindSectionRAW(fixName, True); // CaSeNaMe
+ if Result = nil then
+ Result := FindSectionRAW(fixName, False); // CASENAME
end;
- end;
-end;
-function TWADEditor_1.HaveSection(Section: string): Boolean;
-var
- a: Integer;
-begin
- Result := False;
-
- if FResTable = nil then Exit;
- if Section = '' then
- begin
- Result := True;
- Exit;
- end;
-
- Section := AnsiUpperCase(Section);
-
- for a := 0 to High(FResTable) do
- if (FResTable[a].Length = 0) and (FResTable[a].ResourceName = Section) then
- begin
- Result := True;
- Exit;
- end;
-end;
-
-function TWADEditor_1.GetResource(Section, Resource: string;
- var pData: Pointer; var Len: Integer): Boolean;
-var
- a: LongWord;
- i: Integer;
- WADFile: File;
- CurrentSection: string;
- TempData: Pointer;
- OutBytes: Integer;
-begin
- Result := False;
-
- CurrentSection := '';
-
- if FWADOpened = DFWAD_OPENED_NONE then
- begin
- FLastError := DFWAD_ERROR_WADNOTLOADED;
- Exit;
- end;
-
- Section := toLowerCase1251(Section);
- Resource := toLowerCase1251(Resource);
-
- i := -1;
- for a := 0 to High(FResTable) do
- begin
- if FResTable[a].Length = 0 then
- begin
- CurrentSection := toLowerCase1251(FResTable[a].ResourceName);
- Continue;
- end;
-
- if (toLowerCase1251(FResTable[a].ResourceName) = Resource) and
- (CurrentSection = Section) then
- begin
- i := a;
- Break;
- end;
- end;
-
- if i = -1 then
- begin
- FLastError := DFWAD_ERROR_RESOURCENOTFOUND;
- Exit;
- end;
-
- if FWADOpened = DFWAD_OPENED_FILE then
- begin
- try
- AssignFile(WADFile, FFileName);
- Reset(WADFile, 1);
-
- Seek(WADFile, FResTable[i].Address+6+
- LongWord(SizeOf(TWADHeaderRec_1)+SizeOf(TResourceTableRec_1)*Length(FResTable)));
- TempData := GetMemory(FResTable[i].Length);
- BlockRead(WADFile, TempData^, FResTable[i].Length);
- DecompressBuf(TempData, FResTable[i].Length, 0, pData, OutBytes);
- FreeMem(TempData);
-
- Len := OutBytes;
-
- CloseFile(WADFile);
- except
- FLastError := DFWAD_ERROR_CANTOPENWAD;
- CloseFile(WADFile);
- Exit;
- end;
- end
- else
- begin
- TempData := GetMemory(FResTable[i].Length);
- CopyMemory(TempData, Pointer(PtrUInt(FResData)+FResTable[i].Address+6+
- PtrUInt(SizeOf(TWADHeaderRec_1)+SizeOf(TResourceTableRec_1)*Length(FResTable))),
- FResTable[i].Length);
- DecompressBuf(TempData, FResTable[i].Length, 0, pData, OutBytes);
- FreeMem(TempData);
-
- Len := OutBytes;
- end;
-
- FLastError := DFWAD_NOERROR;
- Result := True;
-end;
-
-function TWADEditor_1.GetResourcesList(Section: string): SArray;
-var
- a: Integer;
- CurrentSection: Char16;
-begin
- Result := nil;
+ function TDFWEditor.InsertSection(name: AnsiString): PSection;
+ begin
+ Result := FindSection(name);
+ if Result = nil then
+ Result := InsertSectionRAW(name);
+ end;
- if FResTable = nil then Exit;
- if Length(Section) > 16 then Exit;
- CurrentSection := '';
- for a := 0 to High(FResTable) do
- begin
- if FResTable[a].Length = 0 then
+ function TDFWEditor.FindDataID(pos: Int64): Integer;
+ var i: Integer;
begin
- CurrentSection := FResTable[a].ResourceName;
- Continue;
+ if (pos >= 0) and (FData <> nil) then
+ begin
+ for i := 0 to High(FData) do
+ begin
+ if FData[i].pos = pos then
+ begin
+ Result := i;
+ exit;
+ end;
+ end;
+ end;
+ Result := -1;
end;
- if CurrentSection = Section then
+ function TDFWEditor.FindData(pos: Int64): TData;
+ var i: Integer;
begin
- SetLength(Result, Length(Result)+1);
- Result[High(Result)] := FResTable[a].ResourceName;
+ i := FindDataID(pos);
+ if i >= 0 then Result := FData[i] else Result := nil;
end;
- end;
-end;
-function TWADEditor_1.GetSectionList(): SArray;
-var
- i: DWORD;
-begin
- Result := nil;
+ function TDFWEditor.InsertData(ref, pos, csize, usize: Int64; stream: TMemoryStream): TData;
+ var i: Integer; data: TData;
+ begin
+ data := TData.Create();
+ data.ref := ref;
+ data.pos := pos;
+ data.csize := csize;
+ data.usize := usize;
+ data.stream := stream;
+
+ if FData = nil then i := 0 else i := Length(FData);
+ SetLength(FData, i + 1);
+ FData[i] := data;
+ Result := data;
+ end;
- if FResTable = nil then Exit;
- if FResTable[0].Length <> 0 then
- begin
- SetLength(Result, 1);
- Result[0] := '';
- end;
- for i := 0 to High(FResTable) do
- if FResTable[i].Length = 0 then
+ function TDFWEditor.InsertFileInfoS(p: PSection; const name: AnsiString; pos, csize, usize: Int64; stream: TMemoryStream): PResource;
+ var i: Integer; data: TData;
begin
- SetLength(Result, Length(Result)+1);
- Result[High(Result)] := FResTable[i].ResourceName;
+ Result := nil;
+ if p = nil then
+ exit;
+
+ data := FindData(pos);
+ if data = nil then
+ data := InsertData(0, pos, csize, usize, stream);
+
+ if p.list = nil then i := 0 else i := Length(p.list);
+ SetLength(p.list, i + 1);
+ Inc(data.ref);
+ p.list[i] := Default(TResource);
+ p.list[i].name := name;
+ p.list[i].data := data;
+ Result := @p.list[i];
end;
-end;
-
-function TWADEditor_1.LastErrorString(): string;
-begin
- case FLastError of
- DFWAD_NOERROR: Result := '';
- DFWAD_ERROR_WADNOTFOUND: Result := 'DFWAD file not found';
- DFWAD_ERROR_CANTOPENWAD: Result := 'Can''t open DFWAD file';
- DFWAD_ERROR_RESOURCENOTFOUND: Result := 'Resource not found';
- DFWAD_ERROR_FILENOTWAD: Result := 'File is not DFWAD';
- DFWAD_ERROR_WADNOTLOADED: Result := 'DFWAD file is not loaded';
- DFWAD_ERROR_READRESOURCE: Result := 'Read resource error';
- DFWAD_ERROR_READWAD: Result := 'Read DFWAD error';
- end;
-end;
-
-function TWADEditor_1.ReadFile2(FileName: string): Boolean;
-var
- WADFile: File;
- Signature: array[0..4] of Char;
- a: Integer;
-begin
- FreeWAD();
-
- Result := False;
- if not FileExists(FileName) then
- begin
- FLastError := DFWAD_ERROR_WADNOTFOUND;
- Exit;
- end;
+ function TDFWEditor.InsertFileInfo(const section, name: AnsiString; pos, csize, usize: Int64; stream: TMemoryStream): PResource;
+ var p: PSection;
+ begin
+ p := FindSectionRAW(section, True);
+ if p = nil then
+ p := InsertSectionRAW(section);
- FFileName := FileName;
+ Result := InsertFileInfoS(p, name, pos, csize, usize, stream);
+ end;
- AssignFile(WADFile, FFileName);
- try
- Reset(WADFile, 1);
- except
- FLastError := DFWAD_ERROR_CANTOPENWAD;
- Exit;
- end;
- try
- BlockRead(WADFile, Signature, 5);
- if Signature <> DFWAD_SIGNATURE then
+ function TDFWEditor.AddAlias(Res, Alias: String): Boolean;
begin
- FLastError := DFWAD_ERROR_FILENOTWAD;
- CloseFile(WADFile);
- Exit;
+ // New hard-links are not supported
+ // However, they never created by editor
+ Result := False;
end;
- BlockRead(WADFile, FVersion, 1);
- if FVersion <> DFWAD_VERSION then
+ function TDFWEditor.AddResource(Data: Pointer; Len: LongWord; Name, Section: String): Boolean;
+ const level: TCompressionLevel = TCompressionLevel.clMax;
+ var s: TMemoryStream; cs: TCompressionStream; p: PResource;
begin
- FLastError := DFWAD_ERROR_WRONGVERSION;
- CloseFile(WADFile);
- Exit;
+ Name := win2utf(Name);
+ Section := win2utf(Section);
+ Result := False;
+ if Name <> '' then
+ begin
+ s := TMemoryStream.Create();
+ try
+ cs := TCompressionStream.Create(level, s, False);
+ try
+ cs.WriteBuffer(PByte(Data)[0], Len);
+ cs.Flush();
+ finally
+ cs.Free();
+ end;
+ p := InsertFileInfo(Section, Name, -1, s.Size, Len, s);
+ Result := p <> nil;
+ except
+ s.Free();
+ raise;
+ end;
+ end;
end;
- BlockRead(WADFile, FHeader, SizeOf(TWADHeaderRec_1));
- FHeader.RecordsCount := LEtoN(FHeader.RecordsCount);
- SetLength(FResTable, FHeader.RecordsCount);
- if FResTable <> nil then
+ function TDFWEditor.AddResource(FileName, Name, Section: String): Boolean;
+ var s: TFileStream; ptr: PByte;
begin
- BlockRead(WADFile, FResTable[0], SizeOf(TResourceTableRec_1)*FHeader.RecordsCount);
-
- for a := 0 to High(FResTable) do
- begin
- FResTable[a].Address := LEtoN(FResTable[a].Address);
- FResTable[a].Length := LEtoN(FResTable[a].Length);
- if FResTable[a].Length <> 0 then
- FResTable[a].Address := FResTable[a].Address-6-(LongWord(SizeOf(TWADHeaderRec_1)+
- SizeOf(TResourceTableRec_1)*Length(FResTable)));
- end;
+ Result := False;
+ FLastError := DFWAD_ERROR_READWAD;
+ try
+ s := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
+ try
+ GetMem(ptr, s.Size);
+ try
+ s.ReadBuffer(ptr[0], s.Size);
+ Result := AddResource(ptr, s.Size, Name, Section);
+ if Result = True then FLastError := DFWAD_NOERROR;
+ finally
+ FreeMem(ptr);
+ end;
+ finally
+ s.Free();
+ end;
+ except
+ on e: EFOpenError do
+ begin
+ if gWADEditorLogLevel >= DFWAD_LOG_INFO then
+ e_WriteLog('DFWAD: AddResource: failed to open file ' + FileName, MSG_NOTIFY);
+ FLastError := DFWAD_ERROR_CANTOPENWAD;
+ end;
+ end;
end;
- CloseFile(WADFile);
- except
- FLastError := DFWAD_ERROR_READWAD;
- CloseFile(WADFile);
- Exit;
- end;
-
- FWADOpened := DFWAD_OPENED_FILE;
- FLastError := DFWAD_NOERROR;
- Result := True;
-end;
-
-function TWADEditor_1.ReadMemory(Data: Pointer; Len: LongWord): Boolean;
-var
- Signature: array[0..4] of Char;
- a: Integer;
-begin
- FreeWAD();
-
- Result := False;
-
- CopyMemory(@Signature[0], Data, 5);
- if Signature <> DFWAD_SIGNATURE then
- begin
- FLastError := DFWAD_ERROR_FILENOTWAD;
- Exit;
- end;
+ constructor TDFWEditor.Create();
+ begin
+ FSection := nil;
+ FData := nil;
+ FStream := nil;
+ FLastError := DFWAD_NOERROR;
+ FVersion := 1;
+ FreeWAD();
+ end;
- CopyMemory(@FVersion, Pointer(PtrUInt(Data)+5), 1);
- if FVersion <> DFWAD_VERSION then
- begin
- FLastError := DFWAD_ERROR_WRONGVERSION;
- Exit;
- end;
+ destructor TDFWEditor.Destroy();
+ begin
+ Clear();
+ inherited;
+ end;
- CopyMemory(@FHeader, Pointer(PtrUInt(Data)+6), SizeOf(TWADHeaderRec_1));
- FHeader.RecordsCount := LEtoN(FHeader.RecordsCount);
+ procedure TDFWEditor.Clear();
+ var i: Integer;
+ begin
+ if FSection <> nil then
+ begin
+ for i := 0 to High(FSection) do
+ if FSection[i].list <> nil then
+ SetLength(FSection[i].list, 0);
+ SetLength(FSection, 0);
+ end;
+ if FData <> nil then
+ begin
+ for i := 0 to High(FData) do
+ begin
+ if FData[i] <> nil then
+ begin
+ if FData[i].stream <> nil then
+ FreeAndNil(FData[i].stream);
+ FreeAndNil(FData[i]);
+ end;
+ end;
+ SetLength(FData, 0);
+ end;
+ if FStream <> nil then
+ FreeAndNil(FStream);
+ end;
- SetLength(FResTable, FHeader.RecordsCount);
- if FResTable <> nil then
- begin
- CopyMemory(@FResTable[0], Pointer(PtrUInt(Data)+6+SizeOf(TWADHeaderRec_1)),
- SizeOf(TResourceTableRec_1)*FHeader.RecordsCount);
+ procedure TDFWEditor.FreeWAD();
+ begin
+ Clear();
+ FLastError := DFWAD_NOERROR;
+ FVersion := 1;
+ end;
- for a := 0 to High(FResTable) do
+ function TDFWEditor.Preload(data: TData): Boolean;
+ var s: TMemoryStream;
begin
- FResTable[a].Address := LEtoN(FResTable[a].Address);
- FResTable[a].Length := LEtoN(FResTable[a].Length);
- if FResTable[a].Length <> 0 then
- FResTable[a].Address := FResTable[a].Address-6-(LongWord(SizeOf(TWADHeaderRec_1)+
- SizeOf(TResourceTableRec_1)*Length(FResTable)));
+ Result := False;
+ if data <> nil then
+ begin
+ Result := data.stream <> nil;
+ if (data.stream = nil) and (FStream <> nil) then
+ begin
+ s := TMemoryStream.Create();
+ try
+ if data.csize > 0 then
+ begin
+ FStream.Seek(data.pos, TSeekOrigin.soBeginning);
+ s.CopyFrom(FStream, data.csize);
+ end;
+ Assert(s.Size = data.csize); // wtf, random size if copied zero bytes!
+ data.stream := s;
+ Result := True;
+ except
+ s.Free();
+ end;
+ end;
+ end;
end;
- end;
- GetMem(FResData, Len);
- CopyMemory(FResData, Data, Len);
+ procedure TDFWEditor.CreateImage();
+ var i, j: Integer;
+ begin
+ if FStream = nil then
+ begin
+ if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then
+ e_WriteLog('DFWAD: CreateImage: File not assigned', MSG_NOTIFY);
+ FLastError := DFWAD_ERROR_WADNOTLOADED;
+ end
+ else if FStream is TMemoryStream then
+ begin
+ if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then
+ e_WriteLog('DFWAD: CreateImage: Memory stream', MSG_NOTIFY);
+ FLastError := DFWAD_NOERROR;
+ end
+ else
+ begin
+ if FSection <> nil then
+ begin
+ for i := 0 to High(FData) do
+ begin
+ if Preload(FData[i]) = False then
+ begin
+ if gWADEditorLogLevel >= DFWAD_LOG_WARN then
+ e_WriteLog('DFWAD: CreateImage: failed to preload resource data #' + IntToStr(i), MSG_WARNING);
+ FLastError := DFWAD_ERROR_CANTOPENWAD;
+ exit;
+ end;
+ FData[i].pos := -1;
+ end;
+ end;
+ FreeAndNil(FStream);
+ FLastError := DFWAD_NOERROR;
+ end;
+ end;
- FWADOpened := DFWAD_OPENED_MEMORY;
- FLastError := DFWAD_NOERROR;
+ procedure TDFWEditor.AddSection(Name: String);
+ begin
+ Name := win2utf(Name);
+ if InsertSection(Name) = nil then
+ raise Exception.Create('DFWAD: AddSection[' + Name + ']: failed to insert');
+ end;
- Result := True;
-end;
+ function TDFWEditor.HaveResource(Section, Resource: String): Boolean;
+ begin
+ Section := win2utf(Section);
+ Resource := win2utf(Resource);
+ Result := FindResource(FindSection(Section), Resource) <> nil;
+ end;
-procedure TWADEditor_1.RemoveResource(Section, Resource: string);
-var
- a, i: Integer;
- CurrentSection: Char16;
- b, c, d: LongWord;
-begin
- if FResTable = nil then Exit;
+ function TDFWEditor.HaveSection(Section: String): Boolean;
+ begin
+ Section := win2utf(Section);
+ Result := FindSection(Section) <> nil;
+ end;
- e_WriteLog('Fuck me (B) ' + Section + ' ' + Resource, MSG_NOTIFY);
+ function TDFWEditor.GetSourceStream(p: PResource): TStream;
+ var src: TStream;
+ begin
+ src := nil;
+ if p.data.stream <> nil then
+ begin
+ src := p.data.stream;
+ src.Seek(0, TSeekOrigin.soBeginning);
+ end
+ else if (p.data.pos >= 0) and (FStream <> nil) then
+ begin
+ src := FStream;
+ src.Seek(p.data.pos, TSeekOrigin.soBeginning);
+ end;
+ Result := src;
+ end;
- i := -1;
- b := 0;
- c := 0;
- CurrentSection := '';
+ function TDFWEditor.GetResource(Section, Resource: String; var pData: Pointer; var Len: Integer): Boolean;
+ const BLOCK_STEP = 4096;
+ var p: PResource; src: TStream; tmp: TDecompressionStream; ptr: PByte; size, r: Int64;
+ begin
+ Section := win2utf(Section);
+ Resource := win2utf(Resource);
+ FLastError := DFWAD_ERROR_CANTOPENWAD;
+ Result := False;
+ pData := nil;
+ Len := 0;
+ p := FindResource(FindSection(Section), Resource);
+ if p <> nil then
+ begin
+ src := GetSourceStream(p);
+ if src <> nil then
+ begin
+ try
+ tmp := TDecompressionStream.Create(src, False);
+ try
+ if p.data.usize < 0 then
+ begin
+ size := 0;
+ GetMem(ptr, BLOCK_STEP);
+ try
+ repeat
+ r := tmp.Read(ptr[size], BLOCK_STEP);
+ size := size + r;
+ if r <> 0 then
+ ReallocMem(ptr, size + BLOCK_STEP);
+ until r = 0;
+ ReallocMem(ptr, size);
+ p.data.usize := size; // cache size
+ pData := ptr;
+ Len := size;
+ Result := True;
+ except
+ FreeMem(ptr);
+ raise;
+ end;
+ end
+ else
+ begin
+ GetMem(ptr, p.data.usize);
+ try
+ tmp.ReadBuffer(ptr[0], p.data.usize);
+ pData := ptr;
+ Len := p.data.usize;
+ Result := True;
+ except
+ FreeMem(ptr);
+ raise;
+ end;
+ end;
+ finally
+ tmp.Free();
+ end;
+ except
+ on e: EStreamError do
+ begin
+ if gWADEditorLogLevel >= DFWAD_LOG_INFO then
+ e_WriteLog('DFWAD: Failed to decompress DEFLATEd data, reason: ' + e.Message, MSG_WARNING);
+ raise e;
+ end;
+ end;
+ end
+ else
+ begin
+ if gWADEditorLogLevel >= DFWAD_LOG_WARN then
+ e_WriteLog('DFWAD: No available source for file data', MSG_WARNING);
+ FLastError := DFWAD_ERROR_WADNOTLOADED;
+ end;
+ end
+ else
+ begin
+ if gWADEditorLogLevel >= DFWAD_LOG_DEBUG then
+ e_WriteLog('DFWAD: Resource not found', MSG_NOTIFY);
+ FLastError := DFWAD_ERROR_RESOURCENOTFOUND;
+ end;
+ end;
- for a := 0 to High(FResTable) do
- begin
- if FResTable[a].Length = 0 then
+ function TDFWEditor.GetResourcesList(Section: String): SArray;
+ var p: PSection; i: Integer;
begin
- CurrentSection := FResTable[a].ResourceName;
- Continue;
+ Section := win2utf(Section);
+ Result := nil;
+ p := FindSection(Section);
+ if (p <> nil) and (p.list <> nil) then
+ begin
+ SetLength(Result, Length(p.list));
+ for i := 0 to High(p.list) do
+ begin
+ Result[i] := utf2win(p.list[i].name);
+ end;
+ end;
end;
- if (FResTable[a].ResourceName = Resource) and
- (CurrentSection = Section) then
+ function TDFWEditor.GetSectionList(): SArray;
+ var i: Integer;
begin
- i := a;
- b := FResTable[a].Length;
- c := FResTable[a].Address;
- Break;
+ Result := nil;
+ if FSection <> nil then
+ begin
+ SetLength(Result, Length(FSection));
+ for i := 0 to High(FSection) do
+ begin
+ Result[i] := utf2win(FSection[i].name);
+ end;
+ end;
end;
- end;
- if i = -1 then Exit;
+ procedure TDFWEditor.ReadFromStream(s: TStream);
+ var sig: packed array [0..4] of Char;
+ var ver: UInt8; nrec: UInt16; offset, csize: UInt32;
+ var name1251: packed array [0..16] of Char;
+ var section, name: AnsiString;
+ var i: Integer;
+ var sec: PSection;
+ var res: PResource;
+ begin
+ s.ReadBuffer(sig[0], 5);
+ if sig = 'DFWAD' then
+ begin
+ ver := s.ReadByte();
+ if ver = 1 then
+ begin
+ nrec := LEtoN(s.ReadWord());
+ section := '';
+ for i := 0 to nrec - 1 do
+ begin
+ s.ReadBuffer(name1251[0], 16);
+ name1251[16] := #0;
+ name := win2utf(PChar(@name1251[0]));
+ offset := LEtoN(s.ReadDWord());
+ csize := LEtoN(s.ReadDWord());
+ if csize = 0 then
+ begin
+ section := name;
+ sec := InsertSectionRAW(section);
+ if sec = nil then
+ raise Exception.Create('Failed to register section [' + section + ']');
+ end
+ else
+ begin
+ if sec = nil then
+ sec := InsertSectionRAW('');
+ res := InsertFileInfoS(sec, name, offset, csize, -1, nil);
+ if res = nil then
+ raise Exception.Create('Failed to register resource [' + section + '][' + name + ']');
+ if res.data.csize <> csize then
+ raise Exception.Create('Invalid compressed size for [' + section + '][' + name + '] (corrupted archive?)');
+ end;
+ end;
+ end
+ else
+ begin
+ FLastError := DFWAD_ERROR_WRONGVERSION;
+ raise Exception.Create('Unsupported DFWAD version ' + IntToStr(ver) + ' (expected 1)');
+ end;
+ end
+ else
+ begin
+ FLastError := DFWAD_ERROR_FILENOTWAD;
+ raise Exception.Create('Not DFWAD file');
+ end;
+ end;
- e_WriteLog('Fuck me (C) ' + Section + ' ' + Resource, MSG_NOTIFY);
+ function TDFWEditor.ReadFile2(FileName: String): Boolean;
+ var s: TFileStream;
+ begin
+ FreeWAD();
+ Result := False;
+ try
+ try
+ s := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
+ try
+ ReadFromStream(s);
+ FStream := s;
+ FLastError := DFWAD_NOERROR;
+ Result := True;
+ except
+ s.Free();
+ raise;
+ end;
+ except
+ on e: Exception do
+ begin
+ if gWADEditorLogLevel >= DFWAD_LOG_INFO then
+ e_WriteLog('DFWAD: Failed to read DFWAD from file ' + FileName + ', reason: ' + e.Message, MSG_WARNING);
+ Clear();
+ end;
+ end;
+ except
+ on e: EFOpenError do
+ begin
+ if gWADEditorLogLevel >= DFWAD_LOG_INFO then
+ e_WriteLog('DFWAD: Failed to open file ' + FileName + ', reason: ' + e.Message, MSG_WARNING);
+ if FileExists(FileName) then
+ FLastError := DFWAD_ERROR_CANTOPENWAD
+ else
+ FLastError := DFWAD_ERROR_WADNOTFOUND;
+ end;
+ end;
+ end;
- for a := i to High(FResTable)-1 do
- FResTable[a] := FResTable[a+1];
+ function TDFWEditor.ReadMemory(Data: Pointer; Len: LongWord): Boolean;
+ var s: TMemoryStream;
+ begin
+ FreeWAD();
+ Result := False;
+ try
+ s := TMemoryStream.Create;
+ try
+ s.SetSize(Len);
+ s.WriteBuffer(PByte(Data)[0], Len);
+ s.Seek(0, soBeginning);
+ ReadFromStream(s);
+ FStream := s;
+ FLastError := DFWAD_NOERROR;
+ Result := True;
+ except
+ s.Free();
+ raise;
+ end;
+ except
+ on e: Exception do
+ begin
+ if gWADEditorLogLevel >= DFWAD_LOG_INFO then
+ e_WriteLog('DFWAD: Failed to read DFWAD from memory, reason: ' + e.Message, MSG_WARNING);
+ Clear();
+ end;
+ end;
+ end;
- SetLength(FResTable, Length(FResTable)-1);
+ procedure TDFWEditor.Collect();
+ var i, n: Integer;
+ begin
+ if FData <> nil then
+ begin
+ n := 0;
+ for i := 0 to High(FData) do
+ begin
+ if FData[i] <> nil then
+ begin
+ if FData[i].ref > 0 then
+ begin
+ FData[n] := FData[i];
+ Inc(n);
+ end
+ else
+ begin
+ if FData[i].stream <> nil then
+ FreeAndNil(FData[i].stream);
+ FreeAndNil(FData[i]);
+ end;
+ end;
+ end;
+ SetLength(FData, n);
+ end;
+ end;
- d := 0;
- for a := 0 to High(FResTable) do
- if (FResTable[a].Length <> 0) and (FResTable[a].Address > c) then
+ procedure TDFWEditor.RemoveResource(Section, Resource: String);
+ var p: PSection; i: Integer; data: TData;
begin
- FResTable[a].Address := FResTable[a].Address-b;
- d := d+FResTable[a].Length;
+ Section := win2utf(Section);
+ Resource := win2utf(Resource);
+ p := FindSection(Section);
+ i := FindResourceID(p, Resource);
+ if i >= 0 then
+ begin
+ data := p.list[i].data;
+ for i := i + 1 to High(p.list) do
+ begin
+ p.list[i - 1] := p.list[i];
+ end;
+ SetLength(p.list, High(p.list));
+ Dec(data.ref);
+ if data.ref <= 0 then
+ Collect();
+ end;
end;
- CopyMemory(Pointer(PtrUInt(FResData)+c), Pointer(PtrUInt(FResData)+c+b), d);
+ procedure TDFWEditor.SaveToStream(s: TStream);
+ type TName16 = packed array [0..16] of Char;
+ var count: UInt16;
+ var name1251: TName16;
+ var i, j: Integer;
+ var p: PResource;
+ var data: TData;
+
+ function GetOffset(data: TData): UInt32;
+ var i: Integer;
+ begin
+ Assert(data <> nil);
+ Result := 6 + 2 + count * 24;
+ for i := 0 to High(FData) do
+ begin
+ if FData[i] = data then
+ exit;
+ if FData[i] <> nil then
+ Result := Result + FData[i].csize;
+ end;
+ raise Exception.Create('Failed to calculate offset (BUG!)');
+ end;
- FDataSize := FDataSize-b;
- FOffset := FOffset-b;
- ReallocMem(FResData, FDataSize);
+ begin
+ count := GetResourcesCount();
+ s.WriteBuffer('DFWAD', 5);
+ s.WriteByte(1);
+ WriteInt(s, UInt16(count));
+ if FSection <> nil then
+ begin
+ for i := 0 to High(FSection) do
+ begin
+ if (i <> 0) or (FSection[i].name <> '') then
+ begin
+ name1251 := Default(TName16);
+ name1251 := utf2win(FSection[i].name);
+ s.WriteBuffer(name1251[0], 16);
+ WriteInt(s, UInt32(0));
+ WriteInt(s, UInt32(0));
+ end;
+ if FSection[i].list <> nil then
+ begin
+ for j := 0 to High(FSection[i].list) do
+ begin
+ p := @FSection[i].list[j];
+ name1251 := Default(TName16);
+ name1251 := utf2win(p.name);
+ s.WriteBuffer(name1251[0], 16);
+ WriteInt(s, UInt32(GetOffset(p.data)));
+ WriteInt(s, UInt32(p.data.csize));
+ end;
+ end;
+ end;
+ if FData <> nil then
+ begin
+ for i := 0 to High(FData) do
+ begin
+ data := FData[i];
+ if data <> nil then
+ begin
+ Assert(s.Position = GetOffset(data));
+ if data.stream <> nil then
+ begin
+ Assert(data.stream.Size = data.csize);
+ data.stream.SaveToStream(s);
+ end
+ else if (data.pos >= 0) and (FStream <> nil) then
+ begin
+ FStream.Seek(data.pos, TSeekOrigin.soBeginning);
+ s.CopyFrom(FStream, data.csize);
+ end
+ else
+ begin
+ raise Exception.Create('No data source available (somethig very wrong)');
+ end;
+ end;
+ end;
+ end;
+ end;
+ end;
- FHeader.RecordsCount := FHeader.RecordsCount-1;
-end;
+ procedure TDFWEditor.SaveTo(FileName: String);
+ var s: TFileStream;
+ begin
+ try
+ s := TFileStream.Create(FileName, fmCreate);
+ try
+ SaveToStream(s);
+ finally
+ s.Free();
+ end;
+ except
+ on e: Exception do
+ begin
+ if gWADEditorLogLevel >= DFWAD_LOG_INFO then
+ e_WriteLog('DFWAD: Failed to create file ' + FileName + ', reason: ' + e.Message, MSG_WARNING);
+ raise e;
+ end;
+ end;
+ end;
-procedure TWADEditor_1.SaveTo(FileName: string);
-var
- WADFile: File;
- sign: string;
- ver: Byte;
- Header, HeaderLE: TWADHeaderRec_1;
- i: Integer;
-begin
- sign := DFWAD_SIGNATURE;
- ver := DFWAD_VERSION;
-
- Header.RecordsCount := Length(FResTable);
- HeaderLE := Header;
- HeaderLE.RecordsCount := NtoLE(HeaderLE.RecordsCount);
-
- if FResTable <> nil then
- for i := 0 to High(FResTable) do
- begin
- if FResTable[i].Length <> 0 then
- FResTable[i].Address := FResTable[i].Address+6+SizeOf(TWADHeaderRec_1)+
- SizeOf(TResourceTableRec_1)*Header.RecordsCount;
-{$IFDEF FPC_BIG_ENDIAN}
- FResTable[i].Address := NtoLE(FResTable[i].Address);
- FResTable[i].Length := NtoLE(FResTable[i].Length);
-{$ENDIF}
- end;
-
- AssignFile(WADFile, FileName);
- Rewrite(WADFile, 1);
- BlockWrite(WADFile, sign[1], 5);
- BlockWrite(WADFile, ver, 1);
- BlockWrite(WADFile, HeaderLE, SizeOf(TWADHeaderRec_1));
- if FResTable <> nil then BlockWrite(WADFile, FResTable[0],
- SizeOf(TResourceTableRec_1)*Header.RecordsCount);
- if FResData <> nil then BlockWrite(WADFile, FResData^, FDataSize);
- CloseFile(WADFile);
-
-{$IFDEF FPC_BIG_ENDIAN}
- // restore back to native endian
- if FResTable <> nil then
- for i := 0 to High(FResTable) do
- begin
- FResTable[i].Address := LEtoN(FResTable[i].Address);
- FResTable[i].Length := LEtoN(FResTable[i].Length);
- end;
-{$ENDIF}
-end;
-
-function TWADEditor_1.GetLastError: Integer;
-begin
- Result := FLastError;
-end;
+ function TDFWEditor.GetLastError: Integer;
+ begin
+ Result := FLastError;
+ end;
-function TWADEditor_1.GetLastErrorStr: String;
-begin
- Result := LastErrorString();
-end;
+ function TDFWEditor.GetLastErrorStr: String;
+ begin
+ case FLastError of
+ DFWAD_NOERROR: Result := '';
+ DFWAD_ERROR_WADNOTFOUND: Result := 'DFWAD file not found';
+ DFWAD_ERROR_CANTOPENWAD: Result := 'Can''t open DFWAD file';
+ DFWAD_ERROR_RESOURCENOTFOUND: Result := 'Resource not found';
+ DFWAD_ERROR_FILENOTWAD: Result := 'File is not DFWAD';
+ DFWAD_ERROR_WADNOTLOADED: Result := 'DFWAD file is not loaded';
+ DFWAD_ERROR_READRESOURCE: Result := 'Read resource error';
+ DFWAD_ERROR_READWAD: Result := 'Read DFWAD error';
+ otherwise Result := IntToStr(FLastError);
+ end;
+ end;
-function TWADEditor_1.GetResourcesCount: Word;
-begin
- Result := FHeader.RecordsCount;
-end;
+ function TDFWEditor.GetResourcesCount: Word;
+ var i: Integer;
+ begin
+ Result := 0;
+ if FSection <> nil then
+ begin
+ Result := Result + Length(FSection);
+ for i := 0 to High(FSection) do
+ if FSection[i].list <> nil then
+ Result := Result + Length(FSection[i].list);
+ if FSection[0].name = '' then
+ Dec(Result); // First root section not counted
+ end;
+ end;
-function TWADEditor_1.GetVersion: Byte;
-begin
- Result := FVersion;
-end;
+ function TDFWEditor.GetVersion: Byte;
+ begin
+ Result := FVersion;
+ end;
begin
- gWADEditorFactory.RegisterEditor('DFWAD', TWADEditor_1);
+ gWADEditorFactory.RegisterEditor('DFWAD', TDFWEditor);
end.