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

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