unit Unit15_Classes; interface uses Unit3_data, Unit9_data_structures, Classes, SysUtils, StrUtils, Dialogs, ABSDecUtil, ABSMain, DB; type TOniData = class private FFileName:String; FLevelInfo:TLevelInfo; FBackend:Integer; Fos_mac:Boolean; protected public property FileName:String read FFileName write FFileName; property Backend:Integer read FBackend write FBackend; property OSisMac:Boolean read Fos_mac write Fos_mac; property LevelInfo:TLevelinfo read FLevelInfo write FLevelInfo; constructor Create(filename:String; var Result:Boolean); virtual; abstract; procedure Close; virtual; abstract; function GetFileInfo(fileid:LongWord):TFileInfo; virtual; abstract; function GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray; virtual; abstract; function GetFilesCount:LongWord; virtual; abstract; function GetExtensionsList:TStringArray; virtual; abstract; function GetExtendedExtensionsList:TExtensionsMap; virtual; abstract; function ExtractFileID(name:String):Integer; function GetFileIDByName(name:String):Integer; function LoadDatFile(fileid:LongWord):Tdata; virtual; abstract; procedure UpdateDatFile(fileid:LongWord; data:Tdata); virtual; abstract; procedure LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer); virtual; abstract; procedure UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer); virtual; abstract; function GetRawList(fileid:LongWord):TRawList; virtual; abstract; function GetRawInfo(fileid,dat_offset:LongWord):TRawInfo; procedure LoadRawFile(fileid,dat_offset:LongWord; target:Pointer); virtual; abstract; procedure UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer); virtual; abstract; procedure LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); virtual; abstract; procedure UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); virtual; abstract; function AppendRawFile(loc_sep:Boolean; size:LongWord; target:Pointer):LongWord; virtual; abstract;//Returns new Address published end; TOniDataDat = class(TOniData) private Fdat_file:TFileStream; Fraw_file:TFileStream; Fsep_file:TFileStream; Fdat_header:THeader; Fdat_filesmap:TFilesMap; Fdat_files:TFiles; Fdat_namedfilesmap:TNamedFilesMap; Fdat_extensionsmap:TExtensionsMap; FUnloadWhenUnused:Boolean; FDatOpened:Boolean; FRawOpened:Boolean; FSepOpened:Boolean; protected public property UnloadWhenUnused:Boolean read FUnloadWhenUnused write FUnloadWhenUnused; constructor Create(DatFilename:String; var Result:Boolean); override; procedure Close; override; function GetFileInfo(fileid:LongWord):TFileInfo; override; function GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray; override; function GetFilesCount:LongWord; override; function GetExtensionsList:TStringArray; override; function GetExtendedExtensionsList:TExtensionsMap; override; function LoadDatFile(fileid:LongWord):Tdata; override; procedure UpdateDatFile(fileid:LongWord; data:Tdata); override; procedure LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer); override; procedure UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer); override; procedure LoadRawOffset(loc_sep:Boolean; raw_addr,size:LongWord; target:Pointer); function GetRawList(fileid:LongWord):TRawList; override; procedure LoadRawFile(fileid,dat_offset:LongWord; target:Pointer); override; procedure UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer); override; procedure LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); override; procedure UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); override; function AppendRawFile(loc_sep:Boolean; size:LongWord; target:Pointer):LongWord; override;//Returns new Address published end; TOniDataADB = class(TOniData) private FDatabase:TABSDatabase; FQuery:TABSQuery; protected public constructor Create(OLDBFilename:String; var Result:Boolean); override; procedure Close; override; function GetFileInfo(fileid:LongWord):TFileInfo; override; function GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray; override; function GetFilesCount:LongWord; override; function GetExtensionsList:TStringArray; override; function GetExtendedExtensionsList:TExtensionsMap; override; function LoadDatFile(fileid:LongWord):Tdata; override; procedure UpdateDatFile(fileid:LongWord; data:Tdata); override; procedure LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer); override; procedure UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer); override; function GetRawList(fileid:LongWord):TRawList; override; procedure LoadRawFile(fileid,dat_offset:LongWord; target:Pointer); override; procedure UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer); override; procedure LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); override; procedure UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); override; published end; const ODB_None=-1; ODB_Dat=0; ODB_ADB=1; var OniDataConnection:TOniData; function CreateDataConnection(filename:String; backend:Integer):Boolean; procedure CloseDataConnection; implementation uses Unit2_Functions; (* Implementation of TOniData *) function TOniData.GetFileIDByName(name:String):Integer; var files:TStringArray; i: Integer; begin Result:=-1; files:=Self.GetFilesList('',name,false); if Length(files)>0 then for i:=0 to High(files) do if Pos(name,files[i])=Pos('-',files[i])+1 then begin // if MidStr(files[i],Pos('-',files[i])+1,Length(files[i])-Pos('-',files[i])-5)=name then begin Result:=Self.ExtractFileID(files[i]); Break; end; end; function TOniData.ExtractFileID(name:String):Integer; begin if name[5]='-' then Result:=HexToLong(MidStr(name,1,4)) else Result:=StrToInt(MidStr(name,1,5)); end; function TOniData.GetRawInfo(fileid,dat_offset:LongWord):TRawInfo; var i:LongWord; raw_list:TRawList; begin raw_list:=Self.GetRawList(fileid); Result.src_id:=0; Result.src_offset:=0; Result.raw_addr:=0; Result.raw_size:=0; for i:=0 to High(raw_list) do begin if raw_list[i].src_offset=dat_offset then begin Result.src_id:=fileid; Result.src_offset:=raw_list[i].src_offset; Result.raw_addr:=raw_list[i].raw_addr; Result.raw_size:=raw_list[i].raw_size; Result.loc_sep:=raw_list[i].loc_sep; Break; end; end; end; (* ================================================================================ Implementation of TOniDataDat *) constructor TOniDataDat.Create(DatFilename:String; var Result:Boolean); const header_ident1_pc:Array[0..$13] of Byte= ($1F,$27,$DC,$33,$DF,$BC,$03,$00,$31,$33,$52,$56,$40,$00,$14,$00,$10,$00,$08,$00); header_ident1_mac:Array[0..$13] of Byte= ($61,$30,$C1,$23,$DF,$BC,$03,$00,$31,$33,$52,$56,$40,$00,$14,$00,$10,$00,$08,$00); header_ident2:Array[0..$F] of Byte= ($99,$CF,$40,$00,$90,$4F,$63,$00,$F4,$55,$5F,$00,$90,$4F,$63,$00); var i:LongWord; header_pc,header_mac:Boolean; begin FUnloadWhenUnused:=True; FDatOpened:=False; FRawOpened:=False; if not FileExists(DatFilename) then begin ShowMessage('File doesn''t exist!!!'); Result:=False; Exit; end; FFileName:=DatFilename; Fdat_file:=TFileStream.Create(FFileName, fmOpenRead); Fdat_file.Read(Fdat_header,SizeOf(Fdat_header)); header_pc:=True; header_mac:=True; for i:=0 to High(Fdat_header.Ident) do begin FLevelInfo.Ident[i]:=Fdat_header.Ident[i]; if Fdat_header.Ident[i]<>header_ident1_pc[i] then begin header_pc:=False; end; if Fdat_header.Ident[i]<>header_ident1_mac[i] then begin header_mac:=False; end; end; if not (header_pc xor header_mac) then begin Result:=False; Exit; end else begin if (header_pc and not header_mac) then Fos_mac:=False else Fos_mac:=True; end; SetLength(Fdat_filesmap,Fdat_header.Files); SetLength(Fdat_files,Fdat_header.Files); for i:=0 to Fdat_header.Files-1 do Fdat_file.Read(Fdat_filesmap[i],SizeOf(Fdat_filesmap[i])); for i:=0 to Fdat_header.Files-1 do begin Fdat_files[i].Extension:=Fdat_filesmap[i].Extension; Fdat_files[i].Extension:=ReverseString(Fdat_files[i].Extension); Fdat_files[i].Size:=Fdat_filesmap[i].FileSize; Fdat_files[i].FileType:=Fdat_filesmap[i].FileType; Fdat_files[i].DatAddr:=Fdat_filesmap[i].DataAddr-8+Fdat_header.DataAddr; if (Fdat_filesmap[i].FileType and $01)=0 then begin Fdat_file.Seek(Fdat_filesmap[i].NameAddr+Fdat_header.NamesAddr,soFromBeginning); SetLength(Fdat_files[i].Name,100); Fdat_file.Read(Fdat_files[i].Name[1],100); Fdat_files[i].Name:=MidStr(Fdat_files[i].Name,1+4,Pos(#0,Fdat_files[i].Name)-1-4); end else begin Fdat_files[i].Name:=''; end; Fdat_files[i].FileName:=FormatNumber(i,5,'0')+'-'+Fdat_files[i].Name+'.'+Fdat_files[i].Extension; Fdat_files[i].FileNameHex:=IntToHex(i,4)+'-'+Fdat_files[i].Name+'.'+Fdat_files[i].Extension; end; Fdat_file.Seek($40+Fdat_header.Files*$14,soFromBeginning); SetLength(Fdat_namedfilesmap,Fdat_header.NamedFiles); for i:=0 to Fdat_header.NamedFiles-1 do Fdat_file.Read(Fdat_namedfilesmap[i],SizeOf(Fdat_namedfilesmap[i])); Fdat_file.Seek($40+Fdat_header.Files*$14+Fdat_header.NamedFiles*$8,soFromBeginning); SetLength(Fdat_extensionsmap,Fdat_header.Extensions); for i:=0 to Fdat_header.Extensions-1 do Fdat_file.Read(Fdat_extensionsmap[i],SizeOf(Fdat_extensionsmap[i])); Fdat_file.Seek(Fdat_files[0].DatAddr+7,soFromBeginning); Fdat_file.Read(FLevelInfo.LevelNumber,1); FLevelInfo.LevelNumber:=FLevelInfo.LevelNumber DIV 2; Fdat_file.Free; Result:=True; FBackend:=ODB_Dat; end; procedure TOniDataDat.Close; begin if not FUnloadWhenUnused and FDatOpened then Fdat_file.Free; if not FUnloadWhenUnused and FRawOpened then Fraw_file.Free; if not FUnloadWhenUnused and FSepOpened then Fsep_file.Free; Self.Free; end; function TOniDataDat.GetFileInfo(fileid:LongWord):TFileInfo; begin if fileid0) ) and ( (Length(pattern)=0) or (Pos(UpperCase(pattern),UpperCase(Fdat_files[i].Name))>0) ) then begin if (NoEmptyFiles=false) or ((Fdat_files[i].FileType and $02)=0) then begin SetLength(Result,Length(Result)+1); if AppSettings.FilenumbersAsHex then Result[High(Result)]:=Fdat_files[i].FileNameHex else Result[High(Result)]:=Fdat_files[i].FileName; end; end; end; end; function TOniDataDat.GetFilesCount:LongWord; begin Result:=Fdat_header.Files; end; function TOniDataDat.GetExtensionsList:TStringArray; var i:LongWord; begin SetLength(Result,Fdat_header.Extensions); for i:=0 to Fdat_header.Extensions-1 do begin with Fdat_extensionsmap[i] do begin Result[i]:=Extension[3]+Extension[2]+Extension[1]+Extension[0]+' ('+IntToStr(ExtCount)+')'; end; end; end; function TOniDataDat.GetExtendedExtensionsList:TExtensionsMap; var i:LongWord; begin SetLength(Result,Fdat_header.Extensions); for i:=0 to Fdat_header.Extensions-1 do begin Result[i]:=Fdat_extensionsmap[i]; end; end; function TOniDataDat.LoadDatFile(fileid:LongWord):Tdata; begin if fileidDBversion then begin ShowMessage('Database-file '+#13+#10+ '"'+OLDBFilename+'"'+#13+#10+ 'has wrong version. (Required: '+DBversion+'; found: '+ FQuery.FieldByName('value').AsString+')'); FQuery.Close; Result:=False; Exit; end; end; if FQuery.FieldByName('name').AsString='lvl' then begin FLevelInfo.LevelNumber:=StrToInt(FQuery.FieldByName('value').AsString); end; if FQuery.FieldByName('name').AsString='ident' then begin temps:=FQuery.FieldByName('value').AsString; for i:=0 to High(FLevelInfo.Ident) do begin j:=i*2+1; case temps[j] of '0'..'9': FLevelInfo.Ident[i]:=Ord(temps[j])-48; 'A'..'F': FLevelInfo.Ident[i]:=Ord(temps[j])-55; end; FLevelInfo.Ident[i]:=FLevelInfo.Ident[i]*16; case temps[j+1] of '0'..'9': FLevelInfo.Ident[i]:=FLevelInfo.Ident[i]+Ord(temps[j+1])-48; 'A'..'F': FLevelInfo.Ident[i]:=FLevelInfo.Ident[i]+Ord(temps[j+1])-55; end; end; end; if FQuery.FieldByName('name').AsString='ident' then begin temps:=FQuery.FieldByName('value').AsString; Fos_mac:=temps='MAC'; end; FQuery.Next; until FQuery.EoF; FQuery.Close; Result:=True; FBackend:=ODB_ADB; end; procedure TOniDataADB.Close; begin FDatabase.Close; FDatabase.Free; Self.Free; end; function TOniDataADB.GetFileInfo(fileid:LongWord):TFileInfo; begin if fileid0 then begin if Length(where)>0 then where:=where+' AND '; if Pos(',',ext)>0 then begin i:=1; where_ext:=''; while i0 then where_ext:=where_ext+' OR '; where_ext:=where_ext+'(extension="'+MidStr(ext,i,4)+'")'; i:=i+5; end; where:=where+'('+where_ext+')'; end else begin where:=where+'(extension="'+ext+'")'; end; end; if Length(pattern)>0 then begin if Length(where)>0 then where:=where+' AND '; where:=where+'(name LIKE "%'+pattern+'%")'; end; if NoEmptyFiles then begin if Length(where)>0 then where:=where+' AND '; where:=where+'(contenttype<>2)'; end; if Length(where)>0 then where:=' WHERE '+where; FQuery.SQL.Text:='SELECT id,name,extension FROM datfiles'+where+' ORDER BY id ASC;'; FQuery.Open; if FQuery.RecordCount>0 then begin FQuery.First; SetLength(Result,FQuery.RecordCount); i:=0; repeat Result[i]:=FormatNumber(FQuery.FieldByName('id').AsInteger,5,'0')+'-'+FQuery.FieldByName('name').AsString+'.'+FQuery.FieldByName('extension').AsString; Inc(i); FQuery.Next; until FQuery.EOF; end; FQuery.Close; end; function TOniDataADB.GetFilesCount:LongWord; begin FQuery.SQL.Text:='SELECT Count(*) AS cnumber FROM datfiles;'; FQuery.Open; if FQuery.RecordCount>0 then begin FQuery.First; Result:=FQuery.FieldByName('cnumber').AsInteger; end else Result:=0; FQuery.Close; end; function TOniDataADB.GetExtensionsList:TStringArray; var i:LongWord; begin SetLength(Result,0); FQuery.SQL.Text:='SELECT extension,count(extension) AS x FROM datfiles GROUP BY extension ORDER BY extension ASC;'; FQuery.Open; if FQuery.RecordCount>0 then begin SetLength(Result,FQuery.RecordCount); i:=0; repeat Result[i]:=FQuery.FieldByName('extension').AsString+' ('+IntToStr(FQuery.FieldByName('x').AsInteger)+')'; Inc(i); FQuery.Next; until FQuery.EOF; end; FQuery.Close; end; function TOniDataADB.GetExtendedExtensionsList:TExtensionsMap; var i,j:LongWord; temps:String; data:Tdata; begin SetLength(Result,0); FQuery.SQL.Text:='SELECT extension,ident FROM extlist ORDER BY extension ASC;'; FQuery.Open; if FQuery.RecordCount>0 then begin SetLength(Result,FQuery.RecordCount); i:=0; repeat temps:=FQuery.FieldByName('extension').AsString; for j:=0 to 3 do Result[i].Extension[j]:=temps[3-j]; data:=DecodeHexString(FQuery.FieldByName('ident').AsString); for j:=0 to 7 do Result[i].Ident[j]:=data[j]; Inc(i); FQuery.Next; until FQuery.EOF; end; FQuery.Close; end; function TOniDataADB.LoadDatFile(fileid:LongWord):Tdata; var mem:TStream; begin if fileid0 then begin mem:=FQuery.CreateBlobStream(FQuery.FieldByName('data'),bmRead); SetLength(Result,mem.Size); mem.Seek(0,soFromBeginning); mem.Read(Result[0],mem.Size); mem.Free; end; FQuery.Close; end; end; procedure TOniDataADB.UpdateDatFile(fileid:LongWord; data:Tdata); var MimeCoder: TStringFormat_MIME64; mem:TMemoryStream; begin if fileid0 THEN BEGIN mem:=FQuery.CreateBlobStream(FQuery.FieldByName('data'),bmRead); mem.Seek(offset,soFromBeginning); mem.Read(target^,size); mem.Free; END; FQuery.Close; END; END; procedure TOniDataADB.UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer); var MimeCoder: TStringFormat_MIME64; mem:TMemoryStream; data:Tdata; begin if fileid0 then begin FQuery.First; SetLength(Result,FQuery.RecordCount); i:=0; repeat Result[i].src_id:=fileid; Result[i].src_offset:=FQuery.FieldByName('src_link_offset').AsInteger; Result[i].raw_addr:=0; Result[i].raw_size:=FQuery.FieldByName('size').AsInteger; Inc(i); FQuery.Next; until FQuery.EOF; end; FQuery.Close; end; procedure TOniDataADB.LoadRawFile(fileid,dat_offset:LongWord; target:Pointer); var mem:TStream; begin if fileid0 then begin mem:=FQuery.CreateBlobStream(FQuery.FieldByName('data'),bmRead); mem.Seek(0,soFromBeginning); mem.Read(target^,mem.size); mem.Free; end; FQuery.Close; end; end; procedure TOniDataADB.UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer); var MimeCoder: TStringFormat_MIME64; mem:TMemoryStream; begin if fileid