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

Last change on this file since 253 was 252, checked in by alloc, 17 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, fmOpenReadWrite);
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.