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 *)
124 section
:= utf2win(NoTrailing(section
));
125 name
:= utf2win(name
);
127 f
:= TWADEditor_1
.Create();
128 if not f
.ReadFile(wad
) then
133 f
.RemoveResource(section
, name
);
134 f
.AddResource(data
, len
, name
, section
);
141 procedure g_AddResourceToZip (wad
, section
, name
: String; const data
: PByte; len
: Integer; out res
: Integer);
148 dir
: array of TFileInfo
;
150 procedure Add (name
: String; data
: PByte; len
: Integer);
151 var ds
: TSFSMemoryChunkStream
;
153 SetLength(dir
, n
+ 1);
154 ds
:= TSFSMemoryChunkStream
.Create(data
, len
, False);
155 dir
[n
] := dfzip
.ZipOne(ts
, name
, ds
, Compress
);
162 wad
:= ExpandFileName(wad
);
163 section
:= utf2win(NoTrailing(section
));
164 name
:= utf2win(name
);
166 list
:= SFSFileList(wad
);
167 tmp
:= wad
+ '.tmp' + IntToStr(Random(100000));
168 ts
:= TFileStream
.Create(tmp
, fmCreate
);
173 for i
:= 0 to list
.Count
- 1 do
175 path
:= NoTrailing(list
.Files
[i
].path
);
176 if (path
<> section
) or (list
.Files
[i
].name
<> name
) then
178 g_ReadResource(wad
, win2utf(path
), win2utf(list
.Files
[i
].name
), data0
, len0
);
179 ASSERT(data0
<> nil);
181 path
:= list
.Files
[i
].name
183 path
:= path
+ '/' + list
.Files
[i
].name
;
184 Add(path
, data0
, len0
);
194 path
:= section
+ '/' + name
;
195 Add(path
, data
, len
);
197 dfzip
.writeCentralDir(ts
, dir
);
201 ASSERT(RenameFile(tmp
, wad
));
205 procedure g_AddResource (wad
, section
, name
: String; const data
: PByte; len
: Integer; out res
: Integer);
209 res
:= 2; (* unknown type *)
210 ext
:= LowerCase(SysUtils
.ExtractFileExt(wad
));
211 e_WriteLog('g_AddResource "' + wad
+ '" "' + section
+ '" "' + name
+ '"', MSG_NOTIFY
);
213 g_AddResourceToDFWAD(wad
, section
, name
, data
, len
, res
)
215 g_AddResourceToZip(wad
, section
, name
, data
, len
, res
)
218 procedure g_DeleteResourceFromDFWAD (wad
, section
, name
: String; out res
: Integer);
222 res
:= 1; (* error *)
223 section
:= utf2win(NoTrailing(section
));
224 name
:= utf2win(name
);
225 f
:= TWADEditor_1
.Create
;
226 if not f
.ReadFile(wad
) then
232 f
.RemoveResource(section
, name
);
239 procedure g_DeleteResourceFromZip (wad
, section
, name
: String; out res
: Integer);
246 dir
: array of TFileInfo
;
248 procedure Add (name
: String; data
: PByte; len
: Integer);
249 var ds
: TSFSMemoryChunkStream
;
251 SetLength(dir
, n
+ 1);
252 ds
:= TSFSMemoryChunkStream
.Create(data
, len
, False);
253 dir
[n
] := dfzip
.ZipOne(ts
, name
, ds
, Compress
);
260 wad
:= ExpandFileName(wad
);
261 section
:= utf2win(NoTrailing(section
));
262 name
:= utf2win(name
);
264 list
:= SFSFileList(wad
);
265 tmp
:= wad
+ '.tmp' + IntToStr(Random(100000));
266 ts
:= TFileStream
.Create(tmp
, fmCreate
);
271 for i
:= 0 to list
.Count
- 1 do
273 path
:= NoTrailing(list
.Files
[i
].path
);
274 if (path
<> section
) or (list
.Files
[i
].name
<> name
) then
276 g_ReadResource(wad
, win2utf(path
), win2utf(list
.Files
[i
].name
), data0
, len0
);
277 ASSERT(data0
<> nil);
279 path
:= list
.Files
[i
].name
281 path
:= path
+ '/' + list
.Files
[i
].name
;
282 Add(path
, data0
, len0
);
289 dfzip
.writeCentralDir(ts
, dir
);
293 ASSERT(RenameFile(tmp
, wad
));
297 procedure g_DeleteResource (wad
, section
, name
: String; out res
: Integer);
301 res
:= 2; (* unknown type *)
302 ext
:= LowerCase(SysUtils
.ExtractFileExt(wad
));
304 g_DeleteResourceFromDFWAD(wad
, section
, name
, res
)
306 g_DeleteResourceFromZip(wad
, section
, name
, res
)
309 procedure g_ExistsResource (wad
, section
, name
: String; out res
: Integer);
310 var str
: String; stream
: TStream
;
313 section
:= utf2win(NoTrailing(section
));
314 name
:= utf2win(name
);
316 if SFSAddDataFileTemp(wad
, TRUE) then
318 str
:= SFSGetLastVirtualName(section
+ '\' + name
);
319 stream
:= SFSFileOpen(wad
+ '::' + str
);
320 if stream
<> nil then
329 procedure g_ReadResource (wad
, section
, name
: String; out data
: PByte; out len
: Integer);
330 var stream
: TStream
; str
: String; i
: Integer;
332 e_WriteLog('g_ReadResource: "' + wad
+ '" "' + section
+ '" "' + name
+ '"', MSG_NOTIFY
);
333 section
:= utf2win(NoTrailing(section
));
334 name
:= utf2win(name
);
337 //ASSERT(name <> '');
338 if name
= '' then Exit
; (* SKY can be void *)
339 if SFSAddDataFileTemp(wad
, TRUE) then
341 str
:= SFSGetLastVirtualName(section
+ '/' + name
);
342 stream
:= SFSFileOpen(wad
+ '::' + str
);
343 if stream
<> nil then
348 //stream.ReadBuffer(data, len); (* leads to segfault *)
349 for i
:= 0 to len
- 1 do
350 data
[i
] := stream
.ReadByte();
357 procedure g_ReadSubResource (wad
, section0
, name0
, section1
, name1
: String; out data
: PByte; out len
: Integer);
358 var stream0
, stream1
: TStream
; str0
, str1
: String; i
: Integer;
362 section0
:= utf2win(NoTrailing(section0
));
363 name0
:= utf2win(name0
);
364 section1
:= utf2win(NoTrailing(section1
));
365 name1
:= utf2win(name1
);
366 //ASSERT(name0 <> '');
367 //ASSERT(name1 <> '');
368 if (wad
= '') OR (name0
= '') OR (name1
= '') then Exit
; (* ??? *)
369 if SFSAddDataFileTemp(wad
, TRUE) then
371 str0
:= SFSGetLastVirtualName(section0
+ '\' + name0
);
372 stream0
:= SFSFileOpen(wad
+ '::' + str0
);
373 if stream0
<> nil then
375 if SFSAddSubDataFile(wad
+ '\' + str0
, stream0
, TRUE) then
377 str1
:= SFSGetLastVirtualName(section1
+ '\' + name1
);
378 stream1
:= SFSFileOpen(wad
+ '\' + str0
+ '::' + str1
);
379 if stream1
<> nil then
384 //stream1.ReadBuffer(data, len); (* leads to segfault *)
385 for i
:= 0 to len
- 1 do
386 data
[i
] := stream1
.ReadByte();