DEADSOFTWARE

dfzip: more checks and user visible errors
[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 const
39 DFWAD_LOG_SILENT = 0;
40 DFWAD_LOG_FATAL = 1;
41 DFWAD_LOG_ERROR = 2;
42 DFWAD_LOG_WARN = 3;
43 DFWAD_LOG_INFO = 4;
44 DFWAD_LOG_DEBUG = 5;
45 DFWAD_LOG_TRACE = 6;
46 DFWAD_LOG_DEFAULT = DFWAD_LOG_INFO;
48 type
49 SArray = array of ShortString;
51 TWADEditor = class abstract(TObject)
52 public
53 function ReadFile(FileName: string): Boolean;
55 function ReadFile2(FileName: string): Boolean; virtual; abstract;
56 function ReadMemory(Data: Pointer; Len: LongWord): Boolean; virtual; abstract;
57 procedure FreeWAD(); virtual; abstract;
58 procedure CreateImage(); virtual; abstract;
59 function AddResource(Data: Pointer; Len: LongWord; Name: string; Section: string): Boolean; virtual; abstract; overload;
60 function AddResource(FileName, Name, Section: string): Boolean; overload; virtual; abstract;
61 function AddAlias(Res, Alias: string): Boolean; virtual; abstract;
62 procedure AddSection(Name: string); virtual; abstract;
63 procedure RemoveResource(Section, Resource: string); virtual; abstract;
64 procedure SaveTo(FileName: string); virtual; abstract;
65 function HaveResource(Section, Resource: string): Boolean; virtual; abstract;
66 function HaveSection(Section: string): Boolean; virtual; abstract;
67 function GetResource(Section, Resource: string; var pData: Pointer; var Len: Integer): Boolean; virtual; abstract;
68 function GetSectionList(): SArray; virtual; abstract;
69 function GetResourcesList(Section: string): SArray; virtual; abstract;
71 function GetLastError: Integer; virtual; abstract;
72 function GetLastErrorStr: String; virtual; abstract;
73 function GetResourcesCount: Word; virtual; abstract;
74 function GetVersion: Byte; virtual; abstract;
75 end;
77 TWADEditorClass = class of TWADEditor;
79 TWADEditorMapping = class sealed(TObject)
80 private
81 FName: String;
82 FWADEditorClass: TWADEditorClass;
83 public
84 constructor CreateEx(const name: String; const eclass: TWADEditorClass);
85 property Name: String read FName;
86 property WADEditorClass: TWADEditorClass read FWADEditorClass;
87 end;
89 TWADEditorFactory = class sealed(TObject)
90 private
91 FMappings: TStringList;
92 FDefault: TWADEditorClass;
93 public
94 constructor Create;
95 destructor Destroy; override;
96 procedure RegisterEditor(const name: String; const eclass: TWADEditorClass);
97 procedure SetDefaultEditor(const name: String);
98 function CreateEditor(const name: String): TWADEditor;
99 function CreateDefaultEditor(): TWADEditor;
100 function OpenFile(FileName: String): TWADEditor;
101 function OpenMemory(Data: Pointer; Len: Integer): TWADEditor;
102 procedure GetRegistredEditors(var list: TStringList);
103 end;
105 // TWADEditor_1 deprecated
106 TWADEditor_1 = class sealed(TObject)
107 private
108 FBase: TWADEditor;
109 public
110 constructor Create();
111 destructor Destroy(); override;
112 procedure FreeWAD();
113 function ReadFile(FileName: string): Boolean;
114 function ReadMemory(Data: Pointer; Len: LongWord): Boolean;
115 procedure CreateImage();
116 function AddResource(Data: Pointer; Len: LongWord; Name: string; Section: string): Boolean; overload;
117 function AddResource(FileName, Name, Section: string): Boolean; overload;
118 function AddAlias(Res, Alias: string): Boolean;
119 procedure AddSection(Name: string);
120 procedure RemoveResource(Section, Resource: string);
121 procedure SaveTo(FileName: string);
122 function HaveResource(Section, Resource: string): Boolean;
123 function HaveSection(Section: string): Boolean;
124 function GetResource(Section, Resource: string; var pData: Pointer; var Len: Integer): Boolean;
125 function GetSectionList(): SArray;
126 function GetResourcesList(Section: string): SArray;
128 function GetLastError: Integer;
129 function GetLastErrorStr: String;
130 function GetResourcesCount: Word;
131 function GetVersion: Byte;
132 end;
134 procedure g_ProcessResourceStr(ResourceStr: String; var FileName, SectionName, ResourceName: String); overload;
135 procedure g_ProcessResourceStr(ResourceStr: String; FileName, SectionName, ResourceName: PString); overload;
137 function gWADEditorFactory: TWADEditorFactory;
139 var
140 gWADEditorLogLevel: Integer = DFWAD_LOG_INFO;
142 implementation
144 uses SysUtils, Math, utils;
146 var
147 uWADEditorFactory: TWADEditorFactory;
149 // EBNF:
150 // Resource = [Archive ":"] [{slash} Section {slash}slash] Name.
151 // slash = "/" | "\".
152 procedure g_ProcessResourceStr(ResourceStr: String; var FileName, SectionName, ResourceName: String);
153 begin
154 g_ProcessResourceStr(ResourceStr, @FileName, @SectionName, @ResourceName);
155 end;
157 procedure g_ProcessResourceStr(ResourceStr: AnsiString; FileName, SectionName, ResourceName: PAnsiString);
158 var i, j: Integer; sn: AnsiString;
159 begin
160 i := Max(1, LastDelimiter(':', ResourceStr));
162 if FileName <> nil then
163 FileName^ := LeftStr(ResourceStr, i - 1);
165 if (SectionName <> nil) or (ResourceName <> nil) then
166 begin
167 for i := i to High(ResourceStr) do
168 if ResourceStr[i] in ['\', '/', ':'] = False then
169 break;
170 sn := Copy(ResourceStr, i);
172 j := LastDelimiter('/\', sn);
173 if ResourceName <> nil then
174 ResourceName^ := Copy(sn, j + 1);
176 if SectionName <> nil then
177 begin
178 for j := j downto 0 do
179 if (j > 0) and (sn[j] in ['\', '/'] = False) then
180 break;
181 if SectionName <> nil then
182 SectionName^ := LeftStr(sn, j);
183 end;
184 end;
185 end;
187 { TWADEditor }
189 function TWADEditor.ReadFile(FileName: String): Boolean;
190 var fname: String;
191 begin
192 fname := findFileCIStr(FileName);
193 Result := ReadFile2(fname);
194 end;
196 { TWADEditorMapping }
198 constructor TWADEditorMapping.CreateEx(const name: String; const eclass: TWADEditorClass);
199 begin
200 Create;
201 FName := name;
202 FWADEditorClass := eclass;
203 end;
205 { TWADEditorFactory }
207 constructor TWADEditorFactory.Create;
208 begin
209 FMappings := TStringList.Create();
210 FDefault := nil;
211 end;
213 destructor TWADEditorFactory.Destroy;
214 var i: Integer;
215 begin
216 for i := 0 to FMappings.Count - 1 do
217 FMappings.Objects[i].Free();
218 FMappings.Free();
219 FDefault := nil;
220 end;
222 procedure TWADEditorFactory.RegisterEditor(const name: String; const eclass: TWADEditorClass);
223 begin
224 if FMappings.IndexOf(UpperCase(name)) <> -1 then
225 raise Exception.Create('Registering a duplicate WAD Editor name <' + name + '>');
226 if FDefault = nil then
227 FDefault := eclass;
228 FMappings.AddObject(UpperCase(name), TWADEditorMapping.CreateEx(name, eclass));
229 end;
231 procedure TWADEditorFactory.SetDefaultEditor(const name: String);
232 var i: Integer;
233 begin
234 i := FMappings.IndexOf(UpperCase(name));
235 if i = -1 then
236 raise Exception.Create('No WAD Editor was registred by the name <' + name + '>');
237 FDefault := TWADEditorMapping(FMappings.Objects[i]).WADEditorClass;
238 end;
240 function TWADEditorFactory.CreateEditor(const name: String): TWADEditor;
241 var i: Integer;
242 begin
243 if name = '' then
244 begin
245 Result := CreateDefaultEditor();
246 end
247 else
248 begin
249 i := FMappings.IndexOf(UpperCase(name));
250 if i = -1 then
251 raise Exception.Create('No WAD Editor was registred by the name <' + name + '>');
252 Result := TWADEditorMapping(FMappings.Objects[i]).WADEditorClass.Create();
253 end;
254 end;
256 function TWADEditorFactory.CreateDefaultEditor(): TWADEditor;
257 begin
258 if FDefault = nil then
259 raise Exception.Create('No default WAD Editor was registred');
260 Result := FDefault.Create();
261 end;
263 function TWADEditorFactory.OpenFile(FileName: String): TWADEditor;
264 var i: Integer; tmp: TWADEditor; fname: String;
265 begin
266 Result := nil;
267 if FMappings <> nil then
268 begin
269 fname := findFileCIStr(FileName);
270 for i := 0 to FMappings.Count - 1 do
271 begin
272 tmp := TWADEditorMapping(FMappings.Objects[i]).WADEditorClass.Create();
273 if tmp.ReadFile2(fname) then
274 begin
275 Result := tmp;
276 break;
277 end;
278 FreeAndNil(tmp);
279 end;
280 end;
281 end;
283 function TWADEditorFactory.OpenMemory(Data: Pointer; Len: Integer): TWADEditor;
284 var i: Integer; tmp: TWADEditor;
285 begin
286 Result := nil;
287 if FMappings <> nil then
288 begin
289 for i := 0 to FMappings.Count - 1 do
290 begin
291 tmp := TWADEditorMapping(FMappings.Objects[i]).WADEditorClass.Create();
292 if tmp.ReadMemory(Data, Len) then
293 begin
294 Result := tmp;
295 break;
296 end;
297 FreeAndNil(tmp);
298 end;
299 end;
300 end;
302 procedure TWADEditorFactory.GetRegistredEditors(var list: TStringList);
303 var i: Integer;
304 begin
305 list.Clear();
306 for i := 0 to FMappings.Count - 1 do
307 list.Add(TWADEditorMapping(FMappings.Objects[i]).Name);
308 end;
310 function gWADEditorFactory: TWADEditorFactory;
311 begin
312 if not Assigned(uWADEditorFactory) then
313 uWADEditorFactory := TWADEditorFactory.Create();
314 Result := uWADEditorFactory;
315 end;
317 { TWADEditor_1 }
319 constructor TWADEditor_1.Create();
320 begin
321 FBase := gWADEditorFactory.CreateDefaultEditor();
322 end;
324 destructor TWADEditor_1.Destroy();
325 begin
326 if FBase <> nil then
327 FBase.Free();
328 inherited;
329 end;
331 procedure TWADEditor_1.CreateImage();
332 begin
333 FBase.CreateImage();
334 end;
336 procedure TWADEditor_1.FreeWAD();
337 begin
338 FBase.FreeWAD();
339 end;
341 function TWADEditor_1.ReadFile(FileName: String): Boolean;
342 var tmp: TWADEditor;
343 begin
344 Result := FBase.ReadFile(FileName);
345 if Result = False then
346 begin
347 tmp := gWADEditorFactory.OpenFile(FileName);
348 if tmp <> nil then
349 begin
350 FreeAndNil(FBase);
351 FBase := tmp;
352 Result := True;
353 end;
354 end;
355 end;
357 function TWADEditor_1.ReadMemory(Data: Pointer; Len: LongWord): Boolean;
358 var tmp: TWADEditor;
359 begin
360 Result := FBase.ReadMemory(Data, Len);
361 if Result = False then
362 begin
363 tmp := gWADEditorFactory.OpenMemory(Data, Len);
364 if tmp <> nil then
365 begin
366 FreeAndNil(FBase);
367 FBase := tmp;
368 Result := True;
369 end;
370 end;
371 end;
373 procedure TWADEditor_1.SaveTo(FileName: string);
374 var fname: AnsiString;
375 begin
376 fname := findFileCIStr(FileName);
377 FBase.SaveTo(fname);
378 end;
380 function TWADEditor_1.AddAlias(Res, Alias: string): Boolean;
381 begin
382 Result := FBase.AddAlias(Res, Alias);
383 end;
385 function TWADEditor_1.AddResource(Data: Pointer; Len: LongWord; Name: string; Section: string): Boolean;
386 begin
387 Result := FBase.AddResource(Data, Len, Name, Section);
388 end;
390 function TWADEditor_1.AddResource(FileName, Name, Section: string): Boolean;
391 var fname: AnsiString;
392 begin
393 fname := findFileCIStr(FileName);
394 Result := FBase.AddResource(fname, Name, Section);
395 end;
397 procedure TWADEditor_1.AddSection(Name: string);
398 begin
399 FBase.AddSection(Name);
400 end;
402 function TWADEditor_1.GetSectionList(): SArray;
403 begin
404 Result := FBase.GetSectionList();
405 end;
407 function TWADEditor_1.HaveSection(Section: string): Boolean;
408 begin
409 Result := FBase.HaveSection(Section);
410 end;
412 function TWADEditor_1.GetResourcesList(Section: string): SArray;
413 begin
414 Result := FBase.GetResourcesList(Section);
415 end;
417 function TWADEditor_1.HaveResource(Section, Resource: string): Boolean;
418 begin
419 Result := FBase.HaveResource(Section, Resource);
420 end;
422 function TWADEditor_1.GetResource(Section, Resource: string; var pData: Pointer; var Len: Integer): Boolean;
423 begin
424 Result := FBase.GetResource(Section, Resource, pData, Len);
425 end;
427 procedure TWADEditor_1.RemoveResource(Section, Resource: string);
428 begin
429 FBase.RemoveResource(Section, Resource);
430 end;
432 function TWADEditor_1.GetLastError: Integer;
433 begin
434 Result := FBase.GetLastError();
435 end;
437 function TWADEditor_1.GetLastErrorStr: String;
438 begin
439 Result := FBase.GetLastErrorStr();
440 end;
442 function TWADEditor_1.GetResourcesCount: Word;
443 begin
444 Result := FBase.GetResourcesCount();
445 end;
447 function TWADEditor_1.GetVersion: Byte;
448 begin
449 Result := FBase.GetVersion;
450 end;
452 finalization
453 FreeAndNil(uWADEditorFactory);
454 end.