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');
108 if FileExists(wad
) then
110 newwad
:= wad
+ backupPostfix
;
111 if FileExists(newwad
) then
112 ASSERT(DeleteFile(newwad
), 'Can''t delete file ' + newwad
);
113 ASSERT(RenameFile(wad
, newwad
), 'Can''t rename file ' + wad
+ ' -> ' + newwad
)
118 if FileExists(wad
) then
119 ASSERT(DeleteFile(wad
), 'Can''t delete file ' + newwad
)
123 procedure g_AddResourceToDFWAD (wad
, section
, name
: String; const data
: PByte; len
: Integer; out res
: Integer);
126 res
:= 1; (* error *)
127 section
:= utf2win(NoTrailing(section
));
128 name
:= utf2win(name
);
130 f
:= TWADEditor_1
.Create();
131 if not f
.ReadFile(wad
) then
136 f
.RemoveResource(section
, name
);
137 f
.AddResource(data
, len
, name
, section
);
144 procedure g_AddResourceToZip (wad
, section
, name
: String; const data
: PByte; len
: Integer; out res
: Integer);
151 dir
: array of TFileInfo
;
153 procedure Add (name
: String; data
: PByte; len
: Integer);
154 var ds
: TSFSMemoryChunkStream
;
156 SetLength(dir
, n
+ 1);
157 ds
:= TSFSMemoryChunkStream
.Create(data
, len
, False);
158 dir
[n
] := dfzip
.ZipOne(ts
, name
, ds
, Compress
);
165 wad
:= ExpandFileName(wad
);
166 section
:= utf2win(NoTrailing(section
));
167 name
:= utf2win(name
);
169 list
:= SFSFileList(wad
);
170 tmp
:= wad
+ '.tmp' + IntToStr(Random(100000));
171 ts
:= TFileStream
.Create(tmp
, fmCreate
);
176 for i
:= 0 to list
.Count
- 1 do
178 path
:= NoTrailing(list
.Files
[i
].path
);
179 if (path
<> section
) or (list
.Files
[i
].name
<> name
) then
181 g_ReadResource(wad
, win2utf(path
), win2utf(list
.Files
[i
].name
), data0
, len0
);
182 ASSERT(data0
<> nil);
184 path
:= list
.Files
[i
].name
186 path
:= path
+ '/' + list
.Files
[i
].name
;
187 Add(path
, data0
, len0
);
197 path
:= section
+ '/' + name
;
198 Add(path
, data
, len
);
200 dfzip
.writeCentralDir(ts
, dir
);
204 ASSERT(RenameFile(tmp
, wad
), 'Can''t rename file ' + tmp
+ ' -> ' + wad
);
208 procedure g_AddResource (wad
, section
, name
: String; const data
: PByte; len
: Integer; out res
: Integer);
212 res
:= 2; (* unknown type *)
213 ext
:= LowerCase(SysUtils
.ExtractFileExt(wad
));
214 e_WriteLog('g_AddResource "' + wad
+ '" "' + section
+ '" "' + name
+ '"', MSG_NOTIFY
);
216 g_AddResourceToDFWAD(wad
, section
, name
, data
, len
, res
)
218 g_AddResourceToZip(wad
, section
, name
, data
, len
, res
)
221 procedure g_DeleteResourceFromDFWAD (wad
, section
, name
: String; out res
: Integer);
225 res
:= 1; (* error *)
226 section
:= utf2win(NoTrailing(section
));
227 name
:= utf2win(name
);
228 f
:= TWADEditor_1
.Create
;
229 if not f
.ReadFile(wad
) then
235 f
.RemoveResource(section
, name
);
242 procedure g_DeleteResourceFromZip (wad
, section
, name
: String; out res
: Integer);
249 dir
: array of TFileInfo
;
251 procedure Add (name
: String; data
: PByte; len
: Integer);
252 var ds
: TSFSMemoryChunkStream
;
254 SetLength(dir
, n
+ 1);
255 ds
:= TSFSMemoryChunkStream
.Create(data
, len
, False);
256 dir
[n
] := dfzip
.ZipOne(ts
, name
, ds
, Compress
);
263 wad
:= ExpandFileName(wad
);
264 section
:= utf2win(NoTrailing(section
));
265 name
:= utf2win(name
);
267 list
:= SFSFileList(wad
);
268 tmp
:= wad
+ '.tmp' + IntToStr(Random(100000));
269 ts
:= TFileStream
.Create(tmp
, fmCreate
);
274 for i
:= 0 to list
.Count
- 1 do
276 path
:= NoTrailing(list
.Files
[i
].path
);
277 if (path
<> section
) or (list
.Files
[i
].name
<> name
) then
279 g_ReadResource(wad
, win2utf(path
), win2utf(list
.Files
[i
].name
), data0
, len0
);
280 ASSERT(data0
<> nil);
282 path
:= list
.Files
[i
].name
284 path
:= path
+ '/' + list
.Files
[i
].name
;
285 Add(path
, data0
, len0
);
292 dfzip
.writeCentralDir(ts
, dir
);
296 ASSERT(RenameFile(tmp
, wad
), 'Can''t rename file ' + tmp
+ ' -> ' + wad
);
300 procedure g_DeleteResource (wad
, section
, name
: String; out res
: Integer);
304 res
:= 2; (* unknown type *)
305 ext
:= LowerCase(SysUtils
.ExtractFileExt(wad
));
307 g_DeleteResourceFromDFWAD(wad
, section
, name
, res
)
309 g_DeleteResourceFromZip(wad
, section
, name
, res
)
312 procedure g_ExistsResource (wad
, section
, name
: String; out res
: Integer);
313 var str
: String; stream
: TStream
;
316 section
:= utf2win(NoTrailing(section
));
317 name
:= utf2win(name
);
319 if SFSAddDataFileTemp(wad
, TRUE) then
321 str
:= SFSGetLastVirtualName(section
+ '\' + name
);
322 stream
:= SFSFileOpen(wad
+ '::' + str
);
323 if stream
<> nil then
332 procedure g_ReadResource (wad
, section
, name
: String; out data
: PByte; out len
: Integer);
333 var stream
: TStream
; str
: String; i
: Integer;
335 e_WriteLog('g_ReadResource: "' + wad
+ '" "' + section
+ '" "' + name
+ '"', MSG_NOTIFY
);
336 section
:= utf2win(NoTrailing(section
));
337 name
:= utf2win(name
);
340 //ASSERT(name <> '');
341 if name
= '' then Exit
; (* SKY can be void *)
342 if SFSAddDataFileTemp(wad
, TRUE) then
344 str
:= SFSGetLastVirtualName(section
+ '/' + name
);
345 stream
:= SFSFileOpen(wad
+ '::' + str
);
346 if stream
<> nil then
351 //stream.ReadBuffer(data, len); (* leads to segfault *)
352 for i
:= 0 to len
- 1 do
353 data
[i
] := stream
.ReadByte();
360 procedure g_ReadSubResource (wad
, section0
, name0
, section1
, name1
: String; out data
: PByte; out len
: Integer);
361 var stream0
, stream1
: TStream
; str0
, str1
: String; i
: Integer;
365 section0
:= utf2win(NoTrailing(section0
));
366 name0
:= utf2win(name0
);
367 section1
:= utf2win(NoTrailing(section1
));
368 name1
:= utf2win(name1
);
369 //ASSERT(name0 <> '');
370 //ASSERT(name1 <> '');
371 if (wad
= '') OR (name0
= '') OR (name1
= '') then Exit
; (* ??? *)
372 if SFSAddDataFileTemp(wad
, TRUE) then
374 str0
:= SFSGetLastVirtualName(section0
+ '\' + name0
);
375 stream0
:= SFSFileOpen(wad
+ '::' + str0
);
376 if stream0
<> nil then
378 if SFSAddSubDataFile(wad
+ '\' + str0
, stream0
, TRUE) then
380 str1
:= SFSGetLastVirtualName(section1
+ '\' + name1
);
381 stream1
:= SFSFileOpen(wad
+ '\' + str0
+ '::' + str1
);
382 if stream1
<> nil then
387 //stream1.ReadBuffer(data, len); (* leads to segfault *)
388 for i
:= 0 to len
- 1 do
389 data
[i
] := stream1
.ReadByte();
391 //stream0.Destroy (* leads to memory corruption, it destroyed with stream1? *)