source: oup/current/DataAccess/Access_OniSplitArchive.pas @ 254

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