source: oup/rewrite/DataAccess/Access_OniArchive.pas@ 94

Last change on this file since 94 was 93, checked in by alloc, 18 years ago
File size: 18.4 KB
Line 
1unit Access_OniArchive;
2interface
3
4uses DataAccess, Classes;
5
6type
7{
8 THeader = packed record
9 Ident: array[0..$13] of Byte;
10 Files: LongWord;
11 NamedFiles: LongWord;
12 Extensions: LongWord;
13 DataAddr: LongWord;
14 DataSize: LongWord;
15 NamesAddr: LongWord;
16 NamesSize: LongWord;
17 Ident2: array[0..$F] of Byte;
18 end;
19 TFilesMap = array of packed record
20 Extension: array[0..$3] of Char;
21 DataAddr: LongWord;
22 NameAddr: LongWord;
23 FileSize: LongWord;
24 FileType: LongWord;
25 end;
26
27 TFileInfo = packed record
28 ID: Integer;
29 FileName: String;
30 FileNameHex: String;
31 Extension: String[4];
32 Name: String;
33 Size: LongWord;
34 FileType: LongWord;
35 DatAddr: LongWord;
36 opened: Boolean;
37 end;
38 TFiles = array of TFileInfo;
39
40 TNamedFilesMap = array of packed record
41 FileNumber: LongWord;
42 blubb: LongWord;
43 end;
44 TExtensionsMap = array of packed record
45 Ident: array[0..$7] of Byte;
46 Extension: array[0..$3] of Char;
47 ExtCount: LongWord;
48 end;
49}
50
51 TAccess_OniArchive = class(TDataAccess)
52 private
53{ Fdat_file: TFileStream;
54 Fraw_file: TFileStream;
55 Fsep_file: TFileStream;
56 Fdat_header: THeader;
57 Fdat_filesmap: TFilesMap;
58 Fdat_files: TFiles;
59 Fdat_namedfilesmap: TNamedFilesMap;
60 Fdat_extensionsmap: TExtensionsMap;
61 FUnloadWhenUnused: Boolean;
62 FDatOpened: Boolean;
63 FRawOpened: Boolean;
64 FSepOpened: Boolean;
65 protected
66 public
67 property UnloadWhenUnused: Boolean Read FUnloadWhenUnused Write FUnloadWhenUnused;
68
69 constructor Create(DatFilename: String; var Result: Boolean); override;
70 procedure Close; override;
71
72 function GetFileInfo(fileid: Integer): TFileInfo; override;
73 function GetFilesList(ext: String; pattern: String;
74 NoEmptyFiles: Boolean; sort: TSortType): TStringArray; override;
75 function GetFilesCount: LongWord; override;
76 function GetExtensionsList: TStringArray; override;
77 function GetExtendedExtensionsList: TExtensionsMap; override;
78
79 function LoadDatFile(fileid: LongWord): Tdata; override;
80 procedure UpdateDatFile(fileid: LongWord; Data: Tdata); override;
81 procedure LoadDatFilePart(fileid, offset, size: LongWord; target: Pointer); override;
82 procedure UpdateDatFilePart(fileid, offset, size: LongWord; target: Pointer); override;
83
84 procedure LoadRawOffset(loc_sep: Boolean; raw_addr, size: LongWord; target: Pointer);
85 function GetRawList(fileid: LongWord): TRawList; override;
86 procedure LoadRawFile(fileid, dat_offset: LongWord; target: Pointer); override;
87 procedure UpdateRawFile(fileid, dat_offset: LongWord; size: LongWord;
88 target: Pointer); override;
89 procedure LoadRawFilePart(fileid, dat_offset: LongWord;
90 offset, size: LongWord; target: Pointer); override;
91 procedure UpdateRawFilePart(fileid, dat_offset: LongWord;
92 offset, size: LongWord; target: Pointer); override;
93 function AppendRawFile(loc_sep: Boolean; size: LongWord; target: Pointer): LongWord;
94 override;//Returns new Address
95 published
96} end;
97
98implementation
99
100
101(*
102================================================================================
103 Implementation of TOniDataDat
104*)
105
106{
107constructor TOniDataDat.Create(DatFilename: String; var Result: Boolean);
108const
109 header_ident1_pc: array[0..$13] of Byte =
110 ($1F, $27, $DC, $33, $DF, $BC, $03, $00, $31, $33, $52, $56, $40, $00,
111 $14, $00, $10, $00, $08, $00);
112 header_ident1_mac: array[0..$13] of Byte =
113 ($61, $30, $C1, $23, $DF, $BC, $03, $00, $31, $33, $52, $56, $40, $00,
114 $14, $00, $10, $00, $08, $00);
115 header_ident1_macbeta: array[0..$13] of Byte =
116 ($81, $11, $8D, $23, $DF, $BC, $03, $00, $31, $33, $52, $56, $40, $00,
117 $14, $00, $10, $00, $08, $00);
118 header_ident2: array[0..$F] of Byte =
119 ($99, $CF, $40, $00, $90, $4F, $63, $00, $F4, $55, $5F, $00, $90, $4F, $63, $00);
120var
121 i: LongWord;
122 header_pc, header_mac: Boolean;
123begin
124 FUnloadWhenUnused := True;
125 FDatOpened := False;
126 FRawOpened := False;
127 if not FileExists(DatFilename) then
128 begin
129 ShowMessage('File doesn''t exist!!!');
130 Result := False;
131 Exit;
132 end;
133 FFileName := DatFilename;
134 Fdat_file := TFileStream.Create(FFileName, fmOpenRead);
135 Fdat_file.Read(Fdat_header, SizeOf(Fdat_header));
136 header_pc := True;
137 header_mac := True;
138 for i := 0 to High(Fdat_header.Ident) do
139 begin
140 FLevelInfo.Ident[i] := Fdat_header.Ident[i];
141 if Fdat_header.Ident[i] <> header_ident1_pc[i] then
142 header_pc := False;
143 if Fdat_header.Ident[i] <> header_ident1_mac[i] then
144 header_mac := False;
145 end;
146 if not (header_pc xor header_mac) then
147 begin
148 Result := False;
149 Exit;
150 end
151 else
152 begin
153 if (header_pc and not header_mac) then
154 Fos_mac := False
155 else
156 Fos_mac := True;
157 end;
158 SetLength(Fdat_filesmap, Fdat_header.Files);
159 SetLength(Fdat_files, Fdat_header.Files);
160 for i := 0 to Fdat_header.Files - 1 do
161 Fdat_file.Read(Fdat_filesmap[i], SizeOf(Fdat_filesmap[i]));
162 for i := 0 to Fdat_header.Files - 1 do
163 begin
164 Fdat_files[i].ID := i;
165 Fdat_files[i].Extension := Fdat_filesmap[i].Extension;
166 Fdat_files[i].Extension := ReverseString(Fdat_files[i].Extension);
167 Fdat_files[i].Size := Fdat_filesmap[i].FileSize;
168 Fdat_files[i].FileType := Fdat_filesmap[i].FileType;
169 Fdat_files[i].DatAddr := Fdat_filesmap[i].DataAddr - 8 + Fdat_header.DataAddr;
170 if (Fdat_filesmap[i].FileType and $01) = 0 then
171 begin
172 Fdat_file.Seek(Fdat_filesmap[i].NameAddr + Fdat_header.NamesAddr, soFromBeginning);
173 SetLength(Fdat_files[i].Name, 100);
174 Fdat_file.Read(Fdat_files[i].Name[1], 100);
175 Fdat_files[i].Name := MidStr(Fdat_files[i].Name, 1 + 4, Pos(
176 #0, Fdat_files[i].Name) - 1 - 4);
177 end
178 else
179 begin
180 Fdat_files[i].Name := '';
181 end;
182 Fdat_files[i].FileName :=
183 FormatNumber(i, 5, '0') + '-' + Fdat_files[i].Name + '.' + Fdat_files[i].Extension;
184 Fdat_files[i].FileNameHex :=
185 IntToHex(i, 4) + '-' + Fdat_files[i].Name + '.' + Fdat_files[i].Extension;
186 end;
187 Fdat_file.Seek($40 + Fdat_header.Files * $14, soFromBeginning);
188 SetLength(Fdat_namedfilesmap, Fdat_header.NamedFiles);
189 for i := 0 to Fdat_header.NamedFiles - 1 do
190 Fdat_file.Read(Fdat_namedfilesmap[i], SizeOf(Fdat_namedfilesmap[i]));
191
192 Fdat_file.Seek($40 + Fdat_header.Files * $14 + Fdat_header.NamedFiles * $8, soFromBeginning);
193 SetLength(Fdat_extensionsmap, Fdat_header.Extensions);
194 for i := 0 to Fdat_header.Extensions - 1 do
195 Fdat_file.Read(Fdat_extensionsmap[i], SizeOf(Fdat_extensionsmap[i]));
196
197 Fdat_file.Seek(Fdat_files[0].DatAddr + 7, soFromBeginning);
198 Fdat_file.Read(FLevelInfo.LevelNumber, 1);
199 FLevelInfo.LevelNumber := FLevelInfo.LevelNumber div 2;
200
201 Fdat_file.Free;
202
203 Result := True;
204 FBackend := ODB_Dat;
205end;
206
207
208
209
210procedure TOniDataDat.Close;
211begin
212 if not FUnloadWhenUnused and FDatOpened then
213 Fdat_file.Free;
214 if not FUnloadWhenUnused and FRawOpened then
215 Fraw_file.Free;
216 if not FUnloadWhenUnused and FSepOpened then
217 Fsep_file.Free;
218 Self.Free;
219end;
220
221
222
223
224function TOniDataDat.GetFileInfo(fileid: Integer): TFileInfo;
225begin
226 if fileid = -1 then
227 begin
228 Result := inherited GetFileInfo(fileid);
229 Exit;
230 end;
231 if fileid < Self.GetFilesCount then
232 Result := Fdat_files[fileid]
233 else
234 Result.ID := -1;
235end;
236
237
238
239
240function TOniDataDat.GetFilesList(ext: String; pattern: String;
241 NoEmptyFiles: Boolean; sort: TSortType): TStringArray;
242var
243 i: LongWord;
244 list: TStringList;
245 id, name, extension: String;
246 fields: TStrings;
247
248 procedure getfields;
249 begin
250 fields.CommaText := StringReplace(AnsiQuotedStr(list.Strings[i], '"'), ';', '","', [rfReplaceAll]);
251 if sort in [stIDAsc, stIDDesc] then
252 begin
253 id := fields.Strings[0];
254 name := fields.Strings[1];
255 extension := fields.Strings[2];
256 end;
257 if sort in [stNameAsc, stNameDesc] then
258 begin
259 id := fields.Strings[1];
260 name := fields.Strings[0];
261 extension := fields.Strings[2];
262 end;
263 if sort in [stExtAsc, stExtDesc] then
264 begin
265 id := fields.Strings[1];
266 name := fields.Strings[2];
267 extension := fields.Strings[0];
268 end;
269 end;
270
271begin
272 list := TStringList.Create;
273 list.Sorted := True;
274 for i := 0 to Fdat_header.Files - 1 do
275 begin
276 if ((Length(ext) = 0) or (Pos(Fdat_files[i].Extension, ext) > 0)) and
277 ((Length(pattern) = 0) or
278 (Pos(UpperCase(pattern), UpperCase(Fdat_files[i].Name)) > 0)) then
279 begin
280 if (NoEmptyFiles = False) or ((Fdat_files[i].FileType and $02) = 0) then
281 begin
282 if AppSettings.FilenumbersAsHex then
283 id := IntToHex(Fdat_files[i].ID, 4)
284 else
285 id := FormatNumber(Fdat_files[i].ID, 5, '0');
286 name := Fdat_files[i].Name;
287 extension := Fdat_files[i].Extension;
288
289 case sort of
290 stIDAsc, stIDDesc: list.Add(id + ';' + name + ';' + extension);
291 stNameAsc, stNameDesc: list.Add(name + ';' + id + ';' + extension);
292 stExtAsc, stExtDesc: list.Add(extension + ';' + id + ';' + name);
293 end;
294 end;
295 end;
296 end;
297 SetLength(Result, list.Count);
298 if Length(Result) > 0 then
299 begin
300 fields := TStringList.Create;
301 if sort in [stIDAsc, stNameAsc, stExtAsc] then
302 for i := 0 to list.Count - 1 do
303 begin
304 getfields;
305 Result[i] := id + '-' + name + '.' + extension;
306 end
307 else
308 for i := list.Count - 1 downto 0 do
309 begin
310 getfields;
311 Result[list.Count - i - 1] := id + '-' + name + '.' + extension;
312 end;
313 fields.Free;
314 end;
315 list.Free;
316end;
317
318
319
320
321function TOniDataDat.GetFilesCount: LongWord;
322begin
323 Result := Fdat_header.Files;
324end;
325
326
327
328
329function TOniDataDat.GetExtensionsList: TStringArray;
330var
331 i: LongWord;
332begin
333 SetLength(Result, Fdat_header.Extensions);
334 for i := 0 to Fdat_header.Extensions - 1 do
335 begin
336 with Fdat_extensionsmap[i] do
337 begin
338 Result[i] := Extension[3] + Extension[2] + Extension[1] + Extension[0] +
339 ' (' + IntToStr(ExtCount) + ')';
340 end;
341 end;
342end;
343
344
345
346
347function TOniDataDat.GetExtendedExtensionsList: TExtensionsMap;
348var
349 i: LongWord;
350begin
351 SetLength(Result, Fdat_header.Extensions);
352 for i := 0 to Fdat_header.Extensions - 1 do
353 begin
354 Result[i] := Fdat_extensionsmap[i];
355 end;
356end;
357
358
359
360
361function TOniDataDat.LoadDatFile(fileid: LongWord): Tdata;
362begin
363 if fileid < Self.GetFilesCount then
364 begin
365 if FUnloadWhenUnused or not FDatOpened then
366 Fdat_file := TFileStream.Create(FFileName, fmOpenReadWrite);
367 Fdat_file.Seek(Fdat_files[fileid].DatAddr, soFromBeginning);
368 SetLength(Result, Fdat_files[fileid].Size);
369 Fdat_file.Read(Result[0], Fdat_files[fileid].Size);
370 if UnloadWhenUnused then
371 Fdat_file.Free
372 else
373 FDatOpened := True;
374 end;
375end;
376
377
378
379
380procedure TOniDataDat.UpdateDatFile(fileid: LongWord; Data: Tdata);
381begin
382 if fileid < Self.GetFilesCount then
383 begin
384 if FUnloadWhenUnused or not FDatOpened then
385 Fdat_file := TFileStream.Create(FFileName, fmOpenReadWrite);
386 Fdat_file.Seek(Fdat_files[fileid].DatAddr, soFromBeginning);
387 Fdat_file.Write(Data[0], Length(Data));
388 if UnloadWhenUnused then
389 Fdat_file.Free
390 else
391 FDatOpened := True;
392 end;
393end;
394
395
396
397
398procedure TOniDataDat.LoadDatFilePart(fileid, offset, size: LongWord; target: Pointer);
399begin
400 if fileid < Self.GetFilesCount then
401 begin
402 if FUnloadWhenUnused or not FDatOpened then
403 Fdat_file := TFileStream.Create(FFileName, fmOpenReadWrite);
404 Fdat_file.Seek(Fdat_files[fileid].DatAddr + offset, soFromBeginning);
405 Fdat_file.Read(target^, size);
406 if UnloadWhenUnused then
407 Fdat_file.Free
408 else
409 FDatOpened := True;
410 end;
411end;
412
413
414
415
416procedure TOniDataDat.UpdateDatFilePart(fileid, offset, size: LongWord; target: Pointer);
417begin
418 if fileid < Self.GetFilesCount then
419 begin
420 if FUnloadWhenUnused or not FDatOpened then
421 Fdat_file := TFileStream.Create(FFileName, fmOpenReadWrite);
422 Fdat_file.Seek(Fdat_files[fileid].DatAddr + offset, soFromBeginning);
423 Fdat_file.Write(target^, size);
424 if UnloadWhenUnused then
425 Fdat_file.Free
426 else
427 FDatOpened := True;
428 end;
429end;
430
431
432
433
434function TOniDataDat.GetRawList(fileid: LongWord): TRawList;
435var
436 i: LongWord;
437begin
438 SetLength(Result, 0);
439 for i := 0 to High(RawListHandlers) do
440 if UpperCase(RawListHandlers[i].Ext) = UpperCase(Fdat_files[fileid].extension) then
441 if RawListHandlers[i].needed then
442 begin
443 Result := RawListHandlers[i].Handler(Self, fileid);
444 Break;
445 end
446 else
447 Break;
448end;
449
450
451
452
453procedure TOniDataDat.LoadRawOffset(loc_sep: Boolean; raw_addr, size: LongWord;
454 target: Pointer);
455begin
456 if not loc_sep then
457 begin
458 if FUnloadWhenUnused or not FRawOpened then
459 Fraw_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.raw'),
460 fmOpenReadWrite);
461 if raw_addr <= Fraw_file.Size then
462 begin
463 Fraw_file.Seek(raw_addr, soFromBeginning);
464 Fraw_file.Read(target^, size);
465 end;
466 if UnloadWhenUnused then
467 Fraw_file.Free
468 else
469 FRawOpened := True;
470 end
471 else
472 begin
473 if FUnloadWhenUnused or not FSepOpened then
474 Fsep_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.sep'),
475 fmOpenReadWrite);
476 if raw_addr <= Fsep_file.Size then
477 begin
478 Fsep_file.Seek(raw_addr, soFromBeginning);
479 Fsep_file.Read(target^, size);
480 end;
481 if UnloadWhenUnused then
482 Fsep_file.Free
483 else
484 FSepOpened := True;
485 end;
486end;
487
488
489
490
491procedure TOniDataDat.LoadRawFile(fileid, dat_offset: LongWord; target: Pointer);
492var
493 raw_info: TRawInfo;
494begin
495 if fileid < Self.GetFilesCount then
496 begin
497 raw_info := Self.GetRawInfo(fileid, dat_offset);
498 if not raw_info.loc_sep then
499 begin
500 if FUnloadWhenUnused or not FRawOpened then
501 Fraw_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.raw'),
502 fmOpenReadWrite);
503 Fraw_file.Seek(raw_info.raw_addr, soFromBeginning);
504 Fraw_file.Read(target^, raw_info.raw_size);
505 if UnloadWhenUnused then
506 Fraw_file.Free
507 else
508 FRawOpened := True;
509 end
510 else
511 begin
512 if FUnloadWhenUnused or not FSepOpened then
513 Fsep_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.sep'),
514 fmOpenReadWrite);
515 Fsep_file.Seek(raw_info.raw_addr, soFromBeginning);
516 Fsep_file.Read(target^, raw_info.raw_size);
517 if UnloadWhenUnused then
518 Fsep_file.Free
519 else
520 FSepOpened := True;
521 end;
522 end;
523end;
524
525
526
527
528procedure TOniDataDat.UpdateRawFile(fileid, dat_offset: LongWord;
529 size: LongWord; target: Pointer);
530var
531 raw_info: TRawInfo;
532begin
533 if fileid < Self.GetFilesCount then
534 begin
535 raw_info := Self.GetRawInfo(fileid, dat_offset);
536 if not raw_info.loc_sep then
537 begin
538 if FUnloadWhenUnused or not FRawOpened then
539 Fraw_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.raw'),
540 fmOpenReadWrite);
541 Fraw_file.Seek(raw_info.raw_addr, soFromBeginning);
542 Fraw_file.Write(target^, raw_info.raw_size);
543 if UnloadWhenUnused then
544 Fraw_file.Free
545 else
546 FRawOpened := True;
547 end
548 else
549 begin
550 if FUnloadWhenUnused or not FSepOpened then
551 Fsep_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.sep'),
552 fmOpenReadWrite);
553 Fsep_file.Seek(raw_info.raw_addr, soFromBeginning);
554 Fsep_file.Write(target^, raw_info.raw_size);
555 if UnloadWhenUnused then
556 Fsep_file.Free
557 else
558 FSepOpened := True;
559 end;
560 end;
561end;
562
563
564
565
566procedure TOniDataDat.LoadRawFilePart(fileid, dat_offset: LongWord;
567 offset, size: LongWord; target: Pointer);
568var
569 raw_info: TRawInfo;
570 Data: Tdata;
571 mem: TMemoryStream;
572begin
573 if fileid < Self.GetFilesCount then
574 begin
575 raw_info := Self.GetRawInfo(fileid, dat_offset);
576 SetLength(Data, raw_info.raw_size);
577 Self.LoadRawFile(fileid, dat_offset, @Data[0]);
578 mem := TMemoryStream.Create;
579 mem.Write(Data[offset], size);
580 mem.Read(target^, size);
581 mem.Free;
582 end;
583end;
584
585
586
587
588procedure TOniDataDat.UpdateRawFilePart(fileid, dat_offset: LongWord;
589 offset, size: LongWord; target: Pointer);
590var
591 raw_info: TRawInfo;
592begin
593 if fileid < Self.GetFilesCount then
594 begin
595 raw_info := Self.GetRawInfo(fileid, dat_offset);
596 if not raw_info.loc_sep then
597 begin
598 if FUnloadWhenUnused or not FRawOpened then
599 Fraw_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.raw'),
600 fmOpenReadWrite);
601 Fraw_file.Seek(raw_info.raw_addr + offset, soFromBeginning);
602 Fraw_file.Write(target^, raw_info.raw_size);
603 if UnloadWhenUnused then
604 Fraw_file.Free
605 else
606 FRawOpened := True;
607 end
608 else
609 begin
610 if FUnloadWhenUnused or not FSepOpened then
611 Fsep_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.sep'),
612 fmOpenReadWrite);
613 Fsep_file.Seek(raw_info.raw_addr + offset, soFromBeginning);
614 Fsep_file.Write(target^, raw_info.raw_size);
615 if UnloadWhenUnused then
616 Fsep_file.Free
617 else
618 FSepOpened := True;
619 end;
620 end;
621end;
622
623
624
625
626function TOniDataDat.AppendRawFile(loc_sep: Boolean; size: LongWord;
627 target: Pointer): LongWord; //Returns new Address
628begin
629 if not loc_sep then
630 begin
631 if FUnloadWhenUnused or not FRawOpened then
632 Fraw_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.raw'),
633 fmOpenReadWrite);
634 Result := Fraw_file.Size;
635 Fraw_file.Seek(0, soFromEnd);
636 Fraw_file.Write(target^, size);
637 if UnloadWhenUnused then
638 Fraw_file.Free
639 else
640 FRawOpened := True;
641 end
642 else
643 begin
644 if FUnloadWhenUnused or not FSepOpened then
645 Fsep_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.sep'),
646 fmOpenReadWrite);
647 Result := Fsep_file.Size;
648 Fsep_file.Seek(0, soFromEnd);
649 Fsep_file.Write(target^, size);
650 if UnloadWhenUnused then
651 Fsep_file.Free
652 else
653 FSepOpened := True;
654 end;
655end;
656
657
658}
659
660
661
662
663end.
Note: See TracBrowser for help on using the repository browser.