source: oup/current/DataAccess/Access_OniArchive.pas@ 145

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