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

Last change on this file since 255 was 252, checked in by alloc, 17 years ago
File size: 17.2 KB
RevLine 
[93]1unit Access_OniArchive;
2interface
3
[101]4uses DataAccess, Classes, TypeDefs;
[93]5
6type
7 TAccess_OniArchive = class(TDataAccess)
8 private
[101]9 Fdat_file: TFileStream;
10 Fraw_file: TFileStream;
11 Fsep_file: TFileStream;
12 Fdat_files: TFiles;
13 Fdat_extensionsmap: TExtensionsMap;
[93]14 protected
15 public
[101]16 constructor Create(DatFilename: String; ConnectionID: Integer; var Msg: TStatusMessages); override;
[93]17 procedure Close; override;
18
[101]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;
[93]24
[101]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;
[93]29
[113]30 function GetDatLinks(FileID: Integer): TDatLinkList; override;
[116]31 function GetDatLink(FileID, DatOffset: Integer): TDatLink; override;
[101]32 function GetRawList(FileID: Integer): TRawDataList; override;
33 function GetRawInfo(FileID, DatOffset: Integer): TRawDataInfo; override;
[241]34 function GetRawsForType(RawType: String): TRawDataList; override;
[101]35
[148]36 procedure LoadRawOffset(LocSep: Boolean; RawAddr, Size: Integer; var target: TStream); overload;
37 procedure LoadRawOffset(LocSep: Boolean; RawAddr, Size: Integer; target: Pointer); overload;
[101]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
[105]43 function AppendRawFile(LocSep: Boolean; Src: TStream): Integer; overload; override;
[93]44 published
[101]45 end;
[93]46
47implementation
48
[101]49uses
[192]50 SysUtils, StrUtils, Data, Functions, RawList, DatLinks, Math;
[93]51
[101]52
[93]53(*
54================================================================================
55 Implementation of TOniDataDat
56*)
57
[101]58
59constructor TAccess_OniArchive.Create(DatFilename: String; ConnectionID: Integer; var Msg: TStatusMessages);
[93]60var
[101]61 i: Integer;
62 header_pc, header_mac, header_macbeta: Boolean;
63 Fdat_header: THeader;
64 Fdat_filesmap: TFilesMap;
65 Fdat_namedfilesmap: TNamedFilesMap;
[93]66begin
[101]67 Msg := SM_UnknownError;
[93]68 if not FileExists(DatFilename) then
69 begin
[101]70 Msg := SM_FileNotFound;
[93]71 Exit;
72 end;
73 FFileName := DatFilename;
[252]74 Fdat_file := TFileStream.Create(FFileName, fmOpenReadWrite);
[93]75 Fdat_file.Read(Fdat_header, SizeOf(Fdat_header));
76 header_pc := True;
77 header_mac := True;
[101]78 header_macbeta := True;
[113]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
[93]87 begin
[113]88 if Fdat_header.OSIdent[i] <> HeaderOSIdentWin[i] then
[93]89 header_pc := False;
[113]90 if Fdat_header.OSIdent[i] <> HeaderOSIdentMac[i] then
[93]91 header_mac := False;
[113]92 if Fdat_header.OSIdent[i] <> HeaderOSIdentMacBeta[i] then
[101]93 header_macbeta := False;
[93]94 end;
[101]95 if not (header_pc xor header_mac xor header_macbeta) then
[93]96 begin
[101]97 Msg := SM_IncompatibleFile;
[93]98 Exit;
99 end
100 else
101 begin
[101]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;
[93]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);
[101]145 Fdat_file.Read(FLevelNumber, 1);
146 FLevelNumber := FLevelNumber div 2;
[93]147
[248]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);
[93]153
[101]154 Msg := SM_OK;
155 FBackend := DB_ONI;
[105]156 FConnectionID := ConnectionID;
[101]157 FChangeRights := [CR_EditDat, CR_EditRaw, CR_AppendRaw];
[229]158
159 inherited;
[93]160end;
161
162
163
164
[101]165procedure TAccess_OniArchive.Close;
[93]166begin
[248]167 if Assigned(Fdat_file) then
[93]168 Fdat_file.Free;
[248]169 if Assigned(Fraw_file) then
[93]170 Fraw_file.Free;
[248]171 if Assigned(Fsep_file) then
[93]172 Fsep_file.Free;
173 Self.Free;
174end;
175
176
177
178
[101]179function TAccess_OniArchive.GetFileInfo(fileid: Integer): TFileInfo;
[93]180begin
181 if fileid = -1 then
182 begin
183 Result := inherited GetFileInfo(fileid);
184 Exit;
185 end;
[101]186 if fileid < Self.GetFileCount then
[93]187 Result := Fdat_files[fileid]
188 else
189 Result.ID := -1;
190end;
191
192
193
194
[101]195function TAccess_OniArchive.GetFilesList(ext: String; pattern: String;
196 NoEmptyFiles: Boolean; SortType: TSortType): TStrings;
[93]197var
[101]198 i: Integer;
199 list: TStringList;
[93]200 id, name, extension: String;
201 fields: TStrings;
202
203 procedure getfields;
204 begin
[101]205 fields.CommaText := StringReplace(AnsiQuotedStr(list.Strings[i], '"'), ';', '","', [rfReplaceAll]);
206 if SortType in [ST_IDAsc, ST_IDDesc] then
[93]207 begin
208 id := fields.Strings[0];
209 name := fields.Strings[1];
210 extension := fields.Strings[2];
211 end;
[101]212 if SortType in [ST_NameAsc, ST_NameDesc] then
[93]213 begin
214 id := fields.Strings[1];
215 name := fields.Strings[0];
216 extension := fields.Strings[2];
217 end;
[101]218 if SortType in [ST_ExtAsc, ST_ExtDesc] then
[93]219 begin
220 id := fields.Strings[1];
221 name := fields.Strings[2];
222 extension := fields.Strings[0];
223 end;
[112]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;
[93]230 end;
231
232begin
233 list := TStringList.Create;
234 list.Sorted := True;
[241]235 if ext = '*' then
236 ext := '';
[101]237 for i := 0 to GetFileCount - 1 do
[93]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
[112]245 id := FormatNumber(Fdat_files[i].ID, 5, '0');
[93]246 name := Fdat_files[i].Name;
247 extension := Fdat_files[i].Extension;
248
[101]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);
[112]253 ST_ExtNameAsc, ST_ExtNameDesc: list.Add(name + ';' + extension + ';' + id);
[93]254 end;
255 end;
256 end;
257 end;
[113]258 if not Assigned(Result) then
259 Result := TStringList.Create;
[101]260 if list.Count > 0 then
[93]261 begin
262 fields := TStringList.Create;
[112]263 if SortType in [ST_IDAsc, ST_NameAsc, ST_ExtAsc, ST_ExtNameAsc] then
[93]264 for i := 0 to list.Count - 1 do
265 begin
266 getfields;
[101]267 Result.Add(id + '-' + name + '.' + extension);
[93]268 end
269 else
270 for i := list.Count - 1 downto 0 do
271 begin
272 getfields;
[101]273 Result.Add(id + '-' + name + '.' + extension);
[93]274 end;
275 fields.Free;
276 end;
277 list.Free;
278end;
279
280
281
282
[101]283function TAccess_OniArchive.GetFileCount: Integer;
[93]284begin
[101]285 Result := Length(Fdat_files);
[93]286end;
287
288
289
290
[101]291function TAccess_OniArchive.GetExtensionsList(ExtListFormat: TExtensionFormat): TStrings;
[93]292var
[101]293 i: Integer;
[93]294begin
[113]295 if not Assigned(Result) then
296 Result := TStringList.Create;
297 if Result is TStringList then
298 TStringList(Result).Sorted := True;
[101]299 for i := 0 to Length(Fdat_extensionsmap) - 1 do
[93]300 begin
301 with Fdat_extensionsmap[i] do
302 begin
[101]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;
[93]310 end;
311 end;
312end;
313
314
315
[101]316procedure TAccess_OniArchive.LoadDatFile(FileID: Integer; var Target: TStream);
[93]317var
[101]318 streampos: Integer;
[93]319begin
[101]320 if fileid < GetFileCount then
[93]321 begin
[248]322 if not Assigned(Target) then
323 Target := TMemoryStream.Create;
[231]324 if GetFileInfo(FileID).Size > 0 then
[101]325 begin
[231]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;
[93]331 end;
332end;
333
[101]334procedure TAccess_OniArchive.UpdateDatFile(FileID: Integer; Src: TStream);
[93]335begin
[101]336 if fileid < GetFileCount then
[93]337 begin
338 Fdat_file.Seek(Fdat_files[fileid].DatAddr, soFromBeginning);
[101]339 Fdat_file.CopyFrom(Src, Fdat_files[fileid].Size);
[93]340 end;
341end;
342
[101]343procedure TAccess_OniArchive.LoadDatFilePart(FileID, Offset, Size: Integer; var Target: TStream);
344var
345 streampos: Integer;
[93]346begin
[101]347 if fileid < GetFileCount then
[93]348 begin
[101]349 if not Assigned(Target) then
350 Target := TMemoryStream.Create;
[93]351 Fdat_file.Seek(Fdat_files[fileid].DatAddr + offset, soFromBeginning);
[101]352 streampos := Target.Position;
353 Target.CopyFrom(Fdat_file, size);
354 Target.Seek(streampos, soFromBeginning);
[93]355 end;
356end;
357
[101]358procedure TAccess_OniArchive.UpdateDatFilePart(FileID, Offset, Size: Integer; Src: TStream);
[93]359begin
[101]360 if fileid < GetFileCount then
[93]361 begin
362 Fdat_file.Seek(Fdat_files[fileid].DatAddr + offset, soFromBeginning);
[101]363 Fdat_file.CopyFrom(Src, Size);
[93]364 end;
365end;
366
367
368
[116]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
[101]402function TAccess_OniArchive.GetRawList(FileID: Integer): TRawDataList;
403begin
404 Result := RawLists.GetRawList(FConnectionID, FileID);
405end;
[93]406
[101]407
[241]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
[243]421 if (list[j].RawType = RawType) and (list[j].RawSize > 0) then
[241]422 begin
423 SetLength(Result, Length(Result)+1);
424 Result[High(Result)] := list[j];
425 end;
426 end;
427 end;
428end;
429
430
[101]431function TAccess_OniArchive.GetRawInfo(FileID, DatOffset: Integer): TRawDataInfo;
[93]432begin
[101]433 Result := RawLists.GetRawInfo(FConnectionID, FileID, DatOffset);
[93]434end;
435
436
437
[148]438procedure TAccess_OniArchive.LoadRawOffset(LocSep: Boolean; RawAddr, Size: Integer; var target: TStream);
[93]439begin
[148]440 if not Assigned(Target) then
441 Target := TMemoryStream.Create;
[101]442 if not LocSep then
[93]443 begin
[101]444 if RawAddr <= Fraw_file.Size then
[93]445 begin
[101]446 Fraw_file.Seek(RawAddr, soFromBeginning);
[148]447 Target.CopyFrom(Fraw_file, size);
448 Target.Seek(0, soFromBeginning);
[93]449 end;
450 end
451 else
452 begin
[101]453 if RawAddr <= Fsep_file.Size then
[93]454 begin
[101]455 Fsep_file.Seek(RawAddr, soFromBeginning);
[148]456 Target.CopyFrom(Fsep_file, size);
457 Target.Seek(0, soFromBeginning);
[93]458 end;
459 end;
460end;
461
[148]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
[101]472procedure TAccess_OniArchive.LoadRawFile(FileID, DatOffset: Integer; var Target: TStream);
[93]473var
[101]474 raw_info: TRawDataInfo;
475 streampos: Integer;
[93]476begin
[101]477 if not Assigned(Target) then
478 Target := TMemoryStream.Create;
479 if fileid < GetFileCount then
[93]480 begin
[101]481 raw_info := Self.GetRawInfo(FileID, DatOffset);
482 if not raw_info.LocSep then
[93]483 begin
[101]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);
[93]488 end
489 else
490 begin
[101]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);
[93]495 end;
496 end;
497end;
498
[101]499procedure TAccess_OniArchive.UpdateRawFile(FileID, DatOffset: Integer; Src: TStream);
[93]500var
[101]501 raw_info: TRawDataInfo;
[93]502begin
[101]503 if fileid < GetFileCount then
[93]504 begin
[101]505 raw_info := GetRawInfo(FileID, DatOffset);
506 if not raw_info.LocSep then
[93]507 begin
[101]508 Fraw_file.Seek(raw_info.RawAddr, soFromBeginning);
[192]509 Fraw_file.CopyFrom(Src, Min(raw_info.RawSize, Src.Size));
[93]510 end
511 else
512 begin
[101]513 Fsep_file.Seek(raw_info.RawAddr, soFromBeginning);
514 Fsep_file.CopyFrom(Src, raw_info.RawSize);
[93]515 end;
516 end;
517end;
518
[101]519procedure TAccess_OniArchive.LoadRawFilePart(FileID, DatOffset, Offset, Size: Integer; var Target: TStream);
[93]520var
[101]521 Data: TStream;
522 streampos: Integer;
[93]523begin
[101]524 if not Assigned(Target) then
525 Target := TMemoryStream.Create;
526 if fileid < Self.GetFileCount then
[93]527 begin
[101]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);
[93]534 end;
535end;
536
[148]537
[101]538procedure TAccess_OniArchive.UpdateRawFilePart(FileID, DatOffset, Offset, Size: Integer; Src: TStream);
[93]539var
[101]540 raw_info: TRawDataInfo;
[93]541begin
[101]542 if fileid < GetFileCount then
[93]543 begin
[101]544 raw_info := GetRawInfo(FileID, DatOffset);
545 if not raw_info.LocSep then
[93]546 begin
[101]547 Fraw_file.Seek(raw_info.RawAddr + Offset, soFromBeginning);
548 Fraw_file.CopyFrom(Src, Size);
[93]549 end
550 else
551 begin
[101]552 Fsep_file.Seek(raw_info.RawAddr + Offset, soFromBeginning);
553 Fsep_file.CopyFrom(Src, Size);
[93]554 end;
555 end;
556end;
557
[105]558function TAccess_OniArchive.AppendRawFile(LocSep: Boolean; Src: TStream): Integer;
[173]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 );
[93]562begin
[101]563 if not LocSep then
[93]564 begin
[173]565 if (Fraw_file.Size mod 32) > 0 then
566 Fraw_file.Write(EmptyBytes[0], 32 - (Fraw_file.Size mod 32));
[93]567 Result := Fraw_file.Size;
568 Fraw_file.Seek(0, soFromEnd);
[105]569 Fraw_file.CopyFrom(Src, Src.Size);
[173]570 if (Fraw_file.Size mod 32) > 0 then
571 Fraw_file.Write(EmptyBytes[0], 32 - (Fraw_file.Size mod 32));
[93]572 end
573 else
574 begin
[173]575 if (Fsep_file.Size mod 32) > 0 then
576 Fsep_file.Write(EmptyBytes[0], 32 - (Fsep_file.Size mod 32));
[93]577 Result := Fsep_file.Size;
578 Fsep_file.Seek(0, soFromEnd);
[105]579 Fsep_file.CopyFrom(Src, Src.Size);
[173]580 if (Fsep_file.Size mod 32) > 0 then
581 Fsep_file.Write(EmptyBytes[0], 32 - (Fsep_file.Size mod 32));
[93]582 end;
583end;
584
585end.
Note: See TracBrowser for help on using the repository browser.