DEADSOFTWARE

wadeditor: fix g_ProcessResourceStr
[d2df-editor.git] / src / shared / WADEDITOR.pas
1 {$INCLUDE ../shared/a_modes.inc}
3 unit WADEDITOR;
5 // TWADEditor errors:
6 // - Create = DFWAD_NOERROR
7 // - FreeWAD = DFWAD_NOERROR
8 // - ReadFile -> DFWAD_ERROR_WADNOTFOUND, DFWAD_ERROR_CANTOPENWAD, DFWAD_ERROR_FILENOTWAD, DFWAD_ERROR_WRONGVERSION, DFWAD_ERROR_READWAD, DFWAD_NOERROR
9 // - ReadMemory -> DFWAD_ERROR_FILENOTWAD, DFWAD_ERROR_WRONGVERSION, DFWAD_NOERROR
10 // - CreateImage -> DFWAD_ERROR_WADNOTLOADED, DFWAD_OPENED_MEMORY, DFWAD_ERROR_CANTOPENWAD, DFWAD_NOERROR
11 // - AddResource (pointer)
12 // - AddResource (filename) -> DFWAD_ERROR_CANTOPENWAD, DFWAD_ERROR_READWAD, DFWAD_NOERROR
13 // - AddAlias
14 // - AddSection
15 // - RemoveResource
16 // - SaveTo
17 // - HaveResource
18 // - HaveSection
19 // - GetResource -> DFWAD_ERROR_WADNOTLOADED, DFWAD_ERROR_RESOURCENOTFOUND, DFWAD_ERROR_CANTOPENWAD, DFWAD_NOERROR
20 // - GetSectionList
21 // - GetResourcesList
23 interface
25 uses Classes;
27 const
28 DFWAD_NOERROR = 0;
29 DFWAD_ERROR_WADNOTFOUND = -1;
30 DFWAD_ERROR_CANTOPENWAD = -2;
31 DFWAD_ERROR_RESOURCENOTFOUND = -3;
32 DFWAD_ERROR_FILENOTWAD = -4;
33 DFWAD_ERROR_WADNOTLOADED = -5;
34 DFWAD_ERROR_READRESOURCE = -6;
35 DFWAD_ERROR_READWAD = -7;
36 DFWAD_ERROR_WRONGVERSION = -8;
38 type
39 SArray = array of ShortString;
41 TWADEditor = class abstract(TObject)
42 public
43 function ReadFile(FileName: string): Boolean;
45 function ReadFile2(FileName: string): Boolean; virtual; abstract;
46 function ReadMemory(Data: Pointer; Len: LongWord): Boolean; virtual; abstract;
47 procedure FreeWAD(); virtual; abstract;
48 procedure CreateImage(); virtual; abstract;
49 function AddResource(Data: Pointer; Len: LongWord; Name: string; Section: string): Boolean; virtual; abstract; overload;
50 function AddResource(FileName, Name, Section: string): Boolean; overload; virtual; abstract;
51 function AddAlias(Res, Alias: string): Boolean; virtual; abstract;
52 procedure AddSection(Name: string); virtual; abstract;
53 procedure RemoveResource(Section, Resource: string); virtual; abstract;
54 procedure SaveTo(FileName: string); virtual; abstract;
55 function HaveResource(Section, Resource: string): Boolean; virtual; abstract;
56 function HaveSection(Section: string): Boolean; virtual; abstract;
57 function GetResource(Section, Resource: string; var pData: Pointer; var Len: Integer): Boolean; virtual; abstract;
58 function GetSectionList(): SArray; virtual; abstract;
59 function GetResourcesList(Section: string): SArray; virtual; abstract;
61 function GetLastError: Integer; virtual; abstract;
62 function GetLastErrorStr: String; virtual; abstract;
63 function GetResourcesCount: Word; virtual; abstract;
64 function GetVersion: Byte; virtual; abstract;
65 end;
67 TWADEditorClass = class of TWADEditor;
69 TWADEditorMapping = class sealed(TObject)
70 private
71 FName: String;
72 FWADEditorClass: TWADEditorClass;
73 public
74 constructor CreateEx(const name: String; const eclass: TWADEditorClass);
75 property Name: String read FName;
76 property WADEditorClass: TWADEditorClass read FWADEditorClass;
77 end;
79 TWADEditorFactory = class sealed(TObject)
80 private
81 FMappings: TStringList;
82 FDefault: TWADEditorClass;
83 public
84 constructor Create;
85 destructor Destroy; override;
86 procedure RegisterEditor(const name: String; const eclass: TWADEditorClass);
87 procedure SetDefaultEditor(const name: String);
88 function CreateEditor(const name: String): TWADEditor;
89 function CreateDefaultEditor(): TWADEditor;
90 function OpenFile(FileName: String): TWADEditor;
91 function OpenMemory(Data: Pointer; Len: Integer): TWADEditor;
92 procedure GetRegistredEditors(var list: TStringList);
93 end;
95 // TWADEditor_1 deprecated
96 TWADEditor_1 = class sealed(TObject)
97 private
98 FBase: TWADEditor;
99 public
100 constructor Create();
101 destructor Destroy(); override;
102 procedure FreeWAD();
103 function ReadFile(FileName: string): Boolean;
104 function ReadMemory(Data: Pointer; Len: LongWord): Boolean;
105 procedure CreateImage();
106 function AddResource(Data: Pointer; Len: LongWord; Name: string; Section: string): Boolean; overload;
107 function AddResource(FileName, Name, Section: string): Boolean; overload;
108 function AddAlias(Res, Alias: string): Boolean;
109 procedure AddSection(Name: string);
110 procedure RemoveResource(Section, Resource: string);
111 procedure SaveTo(FileName: string);
112 function HaveResource(Section, Resource: string): Boolean;
113 function HaveSection(Section: string): Boolean;
114 function GetResource(Section, Resource: string; var pData: Pointer; var Len: Integer): Boolean;
115 function GetSectionList(): SArray;
116 function GetResourcesList(Section: string): SArray;
118 function GetLastError: Integer;
119 function GetLastErrorStr: String;
120 function GetResourcesCount: Word;
121 function GetVersion: Byte;
122 end;
124 procedure g_ProcessResourceStr(ResourceStr: String; var FileName, SectionName, ResourceName: String); overload;
125 procedure g_ProcessResourceStr(ResourceStr: String; FileName, SectionName, ResourceName: PString); overload;
127 function gWADEditorFactory: TWADEditorFactory;
129 implementation
131 uses SysUtils, Math, utils;
133 var
134 uWADEditorFactory: TWADEditorFactory;
136 // EBNF:
137 // Resource = [Archive ":"] [{slash} Section {slash}slash] Name.
138 // slash = "/" | "\".
139 procedure g_ProcessResourceStr(ResourceStr: String; var FileName, SectionName, ResourceName: String);
140 begin
141 g_ProcessResourceStr(ResourceStr, @FileName, @SectionName, @ResourceName);
142 end;
144 procedure g_ProcessResourceStr(ResourceStr: AnsiString; FileName, SectionName, ResourceName: PAnsiString);
145 var i, j: Integer; sn: AnsiString;
146 begin
147 i := Max(1, LastDelimiter(':', ResourceStr));
149 if FileName <> nil then
150 FileName^ := LeftStr(ResourceStr, i - 1);
152 if (SectionName <> nil) or (ResourceName <> nil) then
153 begin
154 for i := i to High(ResourceStr) do
155 if ResourceStr[i] in ['\', '/', ':'] = False then
156 break;
157 sn := Copy(ResourceStr, i);
159 j := LastDelimiter('/\', sn);
160 if ResourceName <> nil then
161 ResourceName^ := Copy(sn, j + 1);
163 if SectionName <> nil then
164 begin
165 for j := j downto 0 do
166 if (j > 0) and (sn[j] in ['\', '/'] = False) then
167 break;
168 if SectionName <> nil then
169 SectionName^ := LeftStr(sn, j);
170 end;
171 end;
172 end;
174 { TWADEditor }
176 function TWADEditor.ReadFile(FileName: String): Boolean;
177 var fname: String;
178 begin
179 fname := findFileCIStr(FileName);
180 Result := ReadFile2(fname);
181 end;
183 { TWADEditorMapping }
185 constructor TWADEditorMapping.CreateEx(const name: String; const eclass: TWADEditorClass);
186 begin
187 Create;
188 FName := name;
189 FWADEditorClass := eclass;
190 end;
192 { TWADEditorFactory }
194 constructor TWADEditorFactory.Create;
195 begin
196 FMappings := TStringList.Create();
197 FDefault := nil;
198 end;
200 destructor TWADEditorFactory.Destroy;
201 var i: Integer;
202 begin
203 for i := 0 to FMappings.Count - 1 do
204 FMappings.Objects[i].Free();
205 FMappings.Free();
206 FDefault := nil;
207 end;
209 procedure TWADEditorFactory.RegisterEditor(const name: String; const eclass: TWADEditorClass);
210 begin
211 if FMappings.IndexOf(UpperCase(name)) <> -1 then
212 raise Exception.Create('Registering a duplicate WAD Editor name <' + name + '>');
213 if FDefault = nil then
214 FDefault := eclass;
215 FMappings.AddObject(UpperCase(name), TWADEditorMapping.CreateEx(name, eclass));
216 end;
218 procedure TWADEditorFactory.SetDefaultEditor(const name: String);
219 var i: Integer;
220 begin
221 i := FMappings.IndexOf(UpperCase(name));
222 if i = -1 then
223 raise Exception.Create('No WAD Editor was registred by the name <' + name + '>');
224 FDefault := TWADEditorMapping(FMappings.Objects[i]).WADEditorClass;
225 end;
227 function TWADEditorFactory.CreateEditor(const name: String): TWADEditor;
228 var i: Integer;
229 begin
230 if name = '' then
231 begin
232 Result := CreateDefaultEditor();
233 end
234 else
235 begin
236 i := FMappings.IndexOf(UpperCase(name));
237 if i = -1 then
238 raise Exception.Create('No WAD Editor was registred by the name <' + name + '>');
239 Result := TWADEditorMapping(FMappings.Objects[i]).WADEditorClass.Create();
240 end;
241 end;
243 function TWADEditorFactory.CreateDefaultEditor(): TWADEditor;
244 begin
245 if FDefault = nil then
246 raise Exception.Create('No default WAD Editor was registred');
247 Result := FDefault.Create();
248 end;
250 function TWADEditorFactory.OpenFile(FileName: String): TWADEditor;
251 var i: Integer; tmp: TWADEditor; fname: String;
252 begin
253 Result := nil;
254 if FMappings <> nil then
255 begin
256 fname := findFileCIStr(FileName);
257 for i := 0 to FMappings.Count - 1 do
258 begin
259 tmp := gWADEditorFactory.CreateEditor(FMappings[i]);
260 if tmp.ReadFile2(fname) then
261 begin
262 Result := tmp;
263 break;
264 end;
265 FreeAndNil(tmp);
266 end;
267 end;
268 end;
270 function TWADEditorFactory.OpenMemory(Data: Pointer; Len: Integer): TWADEditor;
271 var i: Integer; tmp: TWADEditor;
272 begin
273 Result := nil;
274 if FMappings <> nil then
275 begin
276 for i := 0 to FMappings.Count - 1 do
277 begin
278 tmp := gWADEditorFactory.CreateEditor(FMappings[i]);
279 if tmp.ReadMemory(Data, Len) then
280 begin
281 Result := tmp;
282 break;
283 end;
284 FreeAndNil(tmp);
285 end;
286 end;
287 end;
289 procedure TWADEditorFactory.GetRegistredEditors(var list: TStringList);
290 var i: Integer;
291 begin
292 list.Clear();
293 for i := 0 to FMappings.Count - 1 do
294 list.Add(TWADEditorMapping(FMappings.Objects[i]).Name);
295 end;
297 function gWADEditorFactory: TWADEditorFactory;
298 begin
299 if not Assigned(uWADEditorFactory) then
300 uWADEditorFactory := TWADEditorFactory.Create();
301 Result := uWADEditorFactory;
302 end;
304 { TWADEditor_1 }
306 constructor TWADEditor_1.Create();
307 begin
308 FBase := gWADEditorFactory.CreateDefaultEditor();
309 end;
311 destructor TWADEditor_1.Destroy();
312 begin
313 if FBase <> nil then
314 FBase.Free();
315 inherited;
316 end;
318 procedure TWADEditor_1.CreateImage();
319 begin
320 FBase.CreateImage();
321 end;
323 procedure TWADEditor_1.FreeWAD();
324 begin
325 FBase.FreeWAD();
326 end;
328 function TWADEditor_1.ReadFile(FileName: String): Boolean;
329 var tmp: TWADEditor;
330 begin
331 Result := FBase.ReadFile(FileName);
332 if Result = False then
333 begin
334 tmp := gWADEditorFactory.OpenFile(FileName);
335 if tmp <> nil then
336 begin
337 FreeAndNil(FBase);
338 FBase := tmp;
339 Result := True;
340 end;
341 end;
342 end;
344 function TWADEditor_1.ReadMemory(Data: Pointer; Len: LongWord): Boolean;
345 var tmp: TWADEditor;
346 begin
347 Result := FBase.ReadMemory(Data, Len);
348 if Result = False then
349 begin
350 tmp := gWADEditorFactory.OpenMemory(Data, Len);
351 if tmp <> nil then
352 begin
353 FreeAndNil(FBase);
354 FBase := tmp;
355 Result := True;
356 end;
357 end;
358 end;
360 procedure TWADEditor_1.SaveTo(FileName: string);
361 var fname: AnsiString;
362 begin
363 fname := findFileCIStr(FileName);
364 FBase.SaveTo(fname);
365 end;
367 function TWADEditor_1.AddAlias(Res, Alias: string): Boolean;
368 begin
369 Result := FBase.AddAlias(Res, Alias);
370 end;
372 function TWADEditor_1.AddResource(Data: Pointer; Len: LongWord; Name: string; Section: string): Boolean;
373 begin
374 Result := FBase.AddResource(Data, Len, Name, Section);
375 end;
377 function TWADEditor_1.AddResource(FileName, Name, Section: string): Boolean;
378 var fname: AnsiString;
379 begin
380 fname := findFileCIStr(FileName);
381 Result := FBase.AddResource(fname, Name, Section);
382 end;
384 procedure TWADEditor_1.AddSection(Name: string);
385 begin
386 FBase.AddSection(Name);
387 end;
389 function TWADEditor_1.GetSectionList(): SArray;
390 begin
391 Result := FBase.GetSectionList();
392 end;
394 function TWADEditor_1.HaveSection(Section: string): Boolean;
395 begin
396 Result := FBase.HaveSection(Section);
397 end;
399 function TWADEditor_1.GetResourcesList(Section: string): SArray;
400 begin
401 Result := FBase.GetResourcesList(Section);
402 end;
404 function TWADEditor_1.HaveResource(Section, Resource: string): Boolean;
405 begin
406 Result := FBase.HaveResource(Section, Resource);
407 end;
409 function TWADEditor_1.GetResource(Section, Resource: string; var pData: Pointer; var Len: Integer): Boolean;
410 begin
411 Result := FBase.GetResource(Section, Resource, pData, Len);
412 end;
414 procedure TWADEditor_1.RemoveResource(Section, Resource: string);
415 begin
416 FBase.RemoveResource(Section, Resource);
417 end;
419 function TWADEditor_1.GetLastError: Integer;
420 begin
421 Result := FBase.GetLastError();
422 end;
424 function TWADEditor_1.GetLastErrorStr: String;
425 begin
426 Result := FBase.GetLastErrorStr();
427 end;
429 function TWADEditor_1.GetResourcesCount: Word;
430 begin
431 Result := FBase.GetResourcesCount();
432 end;
434 function TWADEditor_1.GetVersion: Byte;
435 begin
436 Result := FBase.GetVersion;
437 end;
439 finalization
440 FreeAndNil(uWADEditorFactory);
441 end.