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

Last change on this file since 836 was 254, checked in by alloc, 17 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.