7 Parse path in form 'path/to/file.wad:some/section/resouce' to
8 wad = 'path/to/file.wa', section = 'some/section', name = 'resource'
11 Delete file if it exists. Make backup if enabled.
14 Read whole file from wad
15 (data <> nil) and (len > 0) when ok
16 use FreeMem(data) when done
19 Read whole file from folded wad
20 (data <> nil) and (len > 0) when ok
21 use FreeMem(data) when done
28 Add/overwrite file to wad
32 Check that resource exists
41 procedure g_GetResourceSection (path
: String; out wad
, section
, name
: String);
42 procedure g_DeleteFile(wad
: String; backupPostfix
: String = '.bak');
44 procedure g_ReadResource (wad
, section
, name
: String; out data
: PByte; out len
: Integer);
45 procedure g_ReadSubResource (wad
, section0
, name0
, section1
, name1
: String; out data
: PByte; out len
: Integer);
46 procedure g_DeleteResource (wad
, section
, name
: String; out res
: Integer);
47 procedure g_AddResource (wad
, section
, name
: String; const data
: PByte; len
: Integer; out res
: Integer);
48 procedure g_ExistsResource (wad
, section
, name
: String; out res
: Integer);
52 uses sfs
, xstreams
, dfzip
, utils
, Classes
, SysUtils
, WADEDITOR
, e_log
;
54 function NoTrailing (path
: String): String;
58 while (i
> 0) and ((path
[i
] = '/') or (path
[i
] = '\')) do dec(i
);
59 result
:= Copy(path
, 1, i
)
62 function g_CleanPath (path
: String; sys
: Boolean = False): String;
68 (* drop separators at the end *)
69 while (len
> 1) and ((path
[i
] = '/') or (path
[i
] = '\')) do dec(len
);
72 while (i
<= len
) and (path
[i
] <> '/') and (path
[i
] <> '\') do
74 result
:= result
+ path
[i
];
79 result
:= result
+ DirectorySeparator
81 result
:= result
+ '/';
83 while (i
<= len
) and ((path
[i
] = '/') or (path
[i
] = '\')) do inc(i
)
87 procedure g_GetResourceSection (path
: String; out wad
, section
, name
: String);
88 var i
, j
, len
: Integer;
92 while (i
> 0) and (path
[i
] <> '/') and (path
[i
] <> '\') do dec(i
);
93 name
:= Copy(path
, i
+ 1, len
);
95 while (i
> 0) and (path
[i
] <> ':') do dec(i
);
96 section
:= Copy(path
, i
+ 1, j
- i
- 1);
97 wad
:= Copy(path
, 1, i
- 1);
100 procedure g_DeleteFile (wad
: String; backupPostfix
: String = '.bak');
105 if FileExists(wad
) then
107 newwad
:= wad
+ backupPostfix
;
108 if FileExists(newwad
) then
109 ASSERT(DeleteFile(newwad
));
110 ASSERT(RenameFile(wad
, newwad
))
115 if FileExists(wad
) then
116 ASSERT(DeleteFile(wad
))
120 procedure g_AddResourceToDFWAD (wad
, section
, name
: String; const data
: PByte; len
: Integer; out res
: Integer);
123 res
:= 1; (* error *)
125 section
:= utf2win(NoTrailing(section
));
126 name
:= utf2win(name
);
128 f
:= TWADEditor_1
.Create();
129 if not f
.ReadFile(wad
) then
134 f
.RemoveResource(section
, name
);
135 f
.AddResource(data
, len
, name
, section
);
142 procedure g_AddResourceToZip (wad
, section
, name
: String; const data
: PByte; len
: Integer; out res
: Integer);
149 dir
: array of TFileInfo
;
151 procedure Add (name
: String; data
: PByte; len
: Integer);
152 var ds
: TSFSMemoryChunkStream
;
154 SetLength(dir
, n
+ 1);
155 ds
:= TSFSMemoryChunkStream
.Create(data
, len
, False);
156 dir
[n
] := dfzip
.ZipOne(ts
, name
, ds
, Compress
);
163 wad
:= ExpandFileName(wad
);
164 section
:= utf2win(NoTrailing(section
));
165 name
:= utf2win(name
);
167 list
:= SFSFileList(wad
);
168 tmp
:= wad
+ '.tmp' + IntToStr(Random(100000));
169 ts
:= TFileStream
.Create(tmp
, fmCreate
);
174 for i
:= 0 to list
.Count
- 1 do
176 path
:= NoTrailing(list
.Files
[i
].path
);
177 if (path
<> section
) or (list
.Files
[i
].name
<> name
) then
179 g_ReadResource(wad
, path
, list
.Files
[i
].name
, data0
, len0
);
180 ASSERT(data0
<> nil);
182 path
:= list
.Files
[i
].name
184 path
:= path
+ '/' + list
.Files
[i
].name
;
185 Add(path
, data0
, len0
);
195 path
:= section
+ '/' + name
;
196 Add(path
, data
, len
);
198 dfzip
.writeCentralDir(ts
, dir
);
202 ASSERT(RenameFile(tmp
, wad
));
206 procedure g_AddResource (wad
, section
, name
: String; const data
: PByte; len
: Integer; out res
: Integer);
210 res
:= 2; (* unknown type *)
211 ext
:= LowerCase(SysUtils
.ExtractFileExt(wad
));
212 e_WriteLog('g_AddResource "' + wad
+ '" "' + section
+ '" "' + name
+ '"', MSG_NOTIFY
);
214 g_AddResourceToDFWAD(wad
, section
, name
, data
, len
, res
)
216 g_AddResourceToZip(wad
, section
, name
, data
, len
, res
)
219 procedure g_DeleteResourceFromDFWAD (wad
, section
, name
: String; out res
: Integer);
223 res
:= 1; (* error *)
224 section
:= utf2win(NoTrailing(section
));
225 name
:= utf2win(name
);
226 f
:= TWADEditor_1
.Create
;
227 if not f
.ReadFile(wad
) then
233 f
.RemoveResource(section
, name
);
240 procedure g_DeleteResourceFromZip (wad
, section
, name
: String; out res
: Integer);
247 dir
: array of TFileInfo
;
249 procedure Add (name
: String; data
: PByte; len
: Integer);
250 var ds
: TSFSMemoryChunkStream
;
252 SetLength(dir
, n
+ 1);
253 ds
:= TSFSMemoryChunkStream
.Create(data
, len
, False);
254 dir
[n
] := dfzip
.ZipOne(ts
, name
, ds
, Compress
);
261 wad
:= ExpandFileName(wad
);
262 section
:= utf2win(NoTrailing(section
));
263 name
:= utf2win(name
);
265 list
:= SFSFileList(wad
);
266 tmp
:= wad
+ '.tmp' + IntToStr(Random(100000));
267 ts
:= TFileStream
.Create(tmp
, fmCreate
);
272 for i
:= 0 to list
.Count
- 1 do
274 path
:= NoTrailing(list
.Files
[i
].path
);
275 if (path
<> section
) or (list
.Files
[i
].name
<> name
) then
277 g_ReadResource(wad
, path
, list
.Files
[i
].name
, data0
, len0
);
278 ASSERT(data0
<> nil);
280 path
:= list
.Files
[i
].name
282 path
:= path
+ '/' + list
.Files
[i
].name
;
283 Add(path
, data0
, len0
);
290 dfzip
.writeCentralDir(ts
, dir
);
294 ASSERT(RenameFile(tmp
, wad
));
298 procedure g_DeleteResource (wad
, section
, name
: String; out res
: Integer);
302 res
:= 2; (* unknown type *)
303 ext
:= LowerCase(SysUtils
.ExtractFileExt(wad
));
305 g_DeleteResourceFromDFWAD(wad
, section
, name
, res
)
307 g_DeleteResourceFromZip(wad
, section
, name
, res
)
310 procedure g_ExistsResource (wad
, section
, name
: String; out res
: Integer);
311 var str
: String; stream
: TStream
;
314 section
:= utf2win(NoTrailing(section
));
315 name
:= utf2win(name
);
317 if SFSAddDataFileTemp(wad
, TRUE) then
319 str
:= SFSGetLastVirtualName(section
+ '\' + name
);
320 stream
:= SFSFileOpen(wad
+ '::' + str
);
321 if stream
<> nil then
330 procedure g_ReadResource (wad
, section
, name
: String; out data
: PByte; out len
: Integer);
331 var stream
: TStream
; str
: String; i
: Integer;
333 e_WriteLog('g_ReadResource: "' + wad
+ '" "' + section
+ '" "' + name
+ '"', MSG_NOTIFY
);
334 section
:= utf2win(NoTrailing(section
));
335 name
:= utf2win(name
);
338 //ASSERT(name <> '');
339 if name
= '' then Exit
; (* SKY can be void *)
340 if SFSAddDataFileTemp(wad
, TRUE) then
342 str
:= SFSGetLastVirtualName(section
+ '/' + name
);
343 stream
:= SFSFileOpen(wad
+ '::' + str
);
344 if stream
<> nil then
349 //stream.ReadBuffer(data, len); (* leads to segfault *)
350 for i
:= 0 to len
- 1 do
351 data
[i
] := stream
.ReadByte();
358 procedure g_ReadSubResource (wad
, section0
, name0
, section1
, name1
: String; out data
: PByte; out len
: Integer);
359 var stream0
, stream1
: TStream
; str0
, str1
: String; i
: Integer;
363 section0
:= utf2win(NoTrailing(section0
));
364 name0
:= utf2win(name0
);
365 section1
:= utf2win(NoTrailing(section1
));
366 name1
:= utf2win(name1
);
367 //ASSERT(name0 <> '');
368 //ASSERT(name1 <> '');
369 if (wad
= '') OR (name0
= '') OR (name1
= '') then Exit
; (* ??? *)
370 if SFSAddDataFileTemp(wad
, TRUE) then
372 str0
:= SFSGetLastVirtualName(section0
+ '\' + name0
);
373 stream0
:= SFSFileOpen(wad
+ '::' + str0
);
374 if stream0
<> nil then
376 if SFSAddSubDataFile(wad
+ '\' + str0
, stream0
, TRUE) then
378 str1
:= SFSGetLastVirtualName(section1
+ '\' + name1
);
379 stream1
:= SFSFileOpen(wad
+ '\' + str0
+ '::' + str1
);
380 if stream1
<> nil then
385 //stream1.ReadBuffer(data, len); (* leads to segfault *)
386 for i
:= 0 to len
- 1 do
387 data
[i
] := stream1
.ReadByte();