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

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