unit OniDataClass; interface uses Data, Classes, SysUtils, StrUtils, Dialogs, ABSDecUtil, ABSMain, DB, Windows; 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: Integer): TFileInfo; virtual; function GetFilesList(ext: String; pattern: String; NoEmptyFiles: Boolean; sort: TSortType): 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: Integer): TFileInfo; override; function GetFilesList(ext: String; pattern: String; NoEmptyFiles: Boolean; sort: TSortType): 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; Fdat_files: TFiles; Fdat_extensionsmap: TExtensionsMap; protected public constructor Create(OLDBFilename: String; var Result: Boolean); override; procedure Close; override; procedure UpdateListCache; // function GetDatLinks(srcid:LongWord):TDatLinks; function GetFileInfo(fileid: Integer): TFileInfo; override; function GetFilesList(ext: String; pattern: String; NoEmptyFiles: Boolean; sort: TSortType): TStringArray; override; function GetFilesCount: LongWord; override; function GetExtensionsList: TStringArray; override; function GetExtendedExtensionsList: TExtensionsMap; override; function GetNamedFilesMap: TNamedFilesMap; 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 DataConnections: array of TOniData; function CreateDataConnection(filename: String; backend: Integer): TOniData; function ConnectionExists(filename: String): TOniData; procedure CloseDataConnection(connection: TOniData); function GetEmptyFileInfo: TFileInfo; implementation uses DataStructures, Functions; (* Implementation of TOniData *) function TOniData.GetFileIDByName(Name: String): Integer; var files: TStringArray; i: Integer; begin Result := -1; files := Self.GetFilesList('', Name, False, stIDAsc); 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; if Length(raw_list) > 0 then begin 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; end; function TOniData.GetFileInfo(fileid: Integer): TFileInfo; begin Result.ID := -1; Result.FileName := ''; Result.FileNameHex := ''; Result.Extension := ''; Result.Name := ''; Result.Size := 0; Result.FileType := 0; Result.DatAddr := 0; Result.opened := False; 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_ident1_macbeta: array[0..$13] of Byte = ($81, $11, $8D, $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 header_pc := False; if Fdat_header.Ident[i] <> header_ident1_mac[i] then header_mac := False; 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].ID := i; 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: Integer): TFileInfo; begin if fileid = -1 then begin Result := inherited GetFileInfo(fileid); Exit; end; if fileid < Self.GetFilesCount then Result := Fdat_files[fileid] else Result.ID := -1; end; function TOniDataDat.GetFilesList(ext: String; pattern: String; NoEmptyFiles: Boolean; sort: TSortType): TStringArray; var i: LongWord; list: TStringList; id, name, extension: String; fields: TStrings; procedure getfields; begin fields.CommaText := StringReplace(AnsiQuotedStr(list.Strings[i], '"'), ';', '","', [rfReplaceAll]); if sort in [stIDAsc, stIDDesc] then begin id := fields.Strings[0]; name := fields.Strings[1]; extension := fields.Strings[2]; end; if sort in [stNameAsc, stNameDesc] then begin id := fields.Strings[1]; name := fields.Strings[0]; extension := fields.Strings[2]; end; if sort in [stExtAsc, stExtDesc] then begin id := fields.Strings[1]; name := fields.Strings[2]; extension := fields.Strings[0]; end; end; begin list := TStringList.Create; list.Sorted := True; for i := 0 to Fdat_header.Files - 1 do begin if ((Length(ext) = 0) or (Pos(Fdat_files[i].Extension, ext) > 0)) 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 if AppSettings.FilenumbersAsHex then id := IntToHex(Fdat_files[i].ID, 4) else id := FormatNumber(Fdat_files[i].ID, 5, '0'); name := Fdat_files[i].Name; extension := Fdat_files[i].Extension; case sort of stIDAsc, stIDDesc: list.Add(id + ';' + name + ';' + extension); stNameAsc, stNameDesc: list.Add(name + ';' + id + ';' + extension); stExtAsc, stExtDesc: list.Add(extension + ';' + id + ';' + name); end; end; end; end; SetLength(Result, list.Count); if Length(Result) > 0 then begin fields := TStringList.Create; if sort in [stIDAsc, stNameAsc, stExtAsc] then for i := 0 to list.Count - 1 do begin getfields; Result[i] := id + '-' + name + '.' + extension; end else for i := list.Count - 1 downto 0 do begin getfields; Result[list.Count - i - 1] := id + '-' + name + '.' + extension; end; fields.Free; end; list.Free; 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 fileid < Self.GetFilesCount then begin if FUnloadWhenUnused or not FDatOpened then Fdat_file := TFileStream.Create(FFileName, fmOpenReadWrite); Fdat_file.Seek(Fdat_files[fileid].DatAddr, soFromBeginning); SetLength(Result, Fdat_files[fileid].Size); Fdat_file.Read(Result[0], Fdat_files[fileid].Size); if UnloadWhenUnused then Fdat_file.Free else FDatOpened := True; end; end; procedure TOniDataDat.UpdateDatFile(fileid: LongWord; Data: Tdata); begin if fileid < Self.GetFilesCount then begin if FUnloadWhenUnused or not FDatOpened then Fdat_file := TFileStream.Create(FFileName, fmOpenReadWrite); Fdat_file.Seek(Fdat_files[fileid].DatAddr, soFromBeginning); Fdat_file.Write(Data[0], Length(Data)); if UnloadWhenUnused then Fdat_file.Free else FDatOpened := True; end; end; procedure TOniDataDat.LoadDatFilePart(fileid, offset, size: LongWord; target: Pointer); begin if fileid < Self.GetFilesCount then begin if FUnloadWhenUnused or not FDatOpened then Fdat_file := TFileStream.Create(FFileName, fmOpenReadWrite); Fdat_file.Seek(Fdat_files[fileid].DatAddr + offset, soFromBeginning); Fdat_file.Read(target^, size); if UnloadWhenUnused then Fdat_file.Free else FDatOpened := True; end; end; procedure TOniDataDat.UpdateDatFilePart(fileid, offset, size: LongWord; target: Pointer); begin if fileid < Self.GetFilesCount then begin if FUnloadWhenUnused or not FDatOpened then Fdat_file := TFileStream.Create(FFileName, fmOpenReadWrite); Fdat_file.Seek(Fdat_files[fileid].DatAddr + offset, soFromBeginning); Fdat_file.Write(target^, size); if UnloadWhenUnused then Fdat_file.Free else FDatOpened := True; end; end; function TOniDataDat.GetRawList(fileid: LongWord): TRawList; var i: LongWord; begin SetLength(Result, 0); for i := 0 to High(RawListHandlers) do if UpperCase(RawListHandlers[i].Ext) = UpperCase(Fdat_files[fileid].extension) then if RawListHandlers[i].needed then begin Result := RawListHandlers[i].Handler(Self, fileid); Break; end else Break; end; procedure TOniDataDat.LoadRawOffset(loc_sep: Boolean; raw_addr, size: LongWord; target: Pointer); begin if not loc_sep then begin if FUnloadWhenUnused or not FRawOpened then Fraw_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.raw'), fmOpenReadWrite); if raw_addr <= Fraw_file.Size then begin Fraw_file.Seek(raw_addr, soFromBeginning); Fraw_file.Read(target^, size); end; if UnloadWhenUnused then Fraw_file.Free else FRawOpened := True; end else begin if FUnloadWhenUnused or not FSepOpened then Fsep_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.sep'), fmOpenReadWrite); if raw_addr <= Fsep_file.Size then begin Fsep_file.Seek(raw_addr, soFromBeginning); Fsep_file.Read(target^, size); end; if UnloadWhenUnused then Fsep_file.Free else FSepOpened := True; end; end; procedure TOniDataDat.LoadRawFile(fileid, dat_offset: LongWord; target: Pointer); var raw_info: TRawInfo; begin if fileid < Self.GetFilesCount then begin raw_info := Self.GetRawInfo(fileid, dat_offset); if not raw_info.loc_sep then begin if FUnloadWhenUnused or not FRawOpened then Fraw_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.raw'), fmOpenReadWrite); Fraw_file.Seek(raw_info.raw_addr, soFromBeginning); Fraw_file.Read(target^, raw_info.raw_size); if UnloadWhenUnused then Fraw_file.Free else FRawOpened := True; end else begin if FUnloadWhenUnused or not FSepOpened then Fsep_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.sep'), fmOpenReadWrite); Fsep_file.Seek(raw_info.raw_addr, soFromBeginning); Fsep_file.Read(target^, raw_info.raw_size); if UnloadWhenUnused then Fsep_file.Free else FSepOpened := True; end; end; end; procedure TOniDataDat.UpdateRawFile(fileid, dat_offset: LongWord; size: LongWord; target: Pointer); var raw_info: TRawInfo; begin if fileid < Self.GetFilesCount then begin raw_info := Self.GetRawInfo(fileid, dat_offset); if not raw_info.loc_sep then begin if FUnloadWhenUnused or not FRawOpened then Fraw_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.raw'), fmOpenReadWrite); Fraw_file.Seek(raw_info.raw_addr, soFromBeginning); Fraw_file.Write(target^, raw_info.raw_size); if UnloadWhenUnused then Fraw_file.Free else FRawOpened := True; end else begin if FUnloadWhenUnused or not FSepOpened then Fsep_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.sep'), fmOpenReadWrite); Fsep_file.Seek(raw_info.raw_addr, soFromBeginning); Fsep_file.Write(target^, raw_info.raw_size); if UnloadWhenUnused then Fsep_file.Free else FSepOpened := True; end; end; end; procedure TOniDataDat.LoadRawFilePart(fileid, dat_offset: LongWord; offset, size: LongWord; target: Pointer); var raw_info: TRawInfo; Data: Tdata; mem: TMemoryStream; begin if fileid < Self.GetFilesCount then begin raw_info := Self.GetRawInfo(fileid, dat_offset); SetLength(Data, raw_info.raw_size); Self.LoadRawFile(fileid, dat_offset, @Data[0]); mem := TMemoryStream.Create; mem.Write(Data[offset], size); mem.Read(target^, size); mem.Free; end; end; procedure TOniDataDat.UpdateRawFilePart(fileid, dat_offset: LongWord; offset, size: LongWord; target: Pointer); var raw_info: TRawInfo; begin if fileid < Self.GetFilesCount then begin raw_info := Self.GetRawInfo(fileid, dat_offset); if not raw_info.loc_sep then begin if FUnloadWhenUnused or not FRawOpened then Fraw_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.raw'), fmOpenReadWrite); Fraw_file.Seek(raw_info.raw_addr + offset, soFromBeginning); Fraw_file.Write(target^, raw_info.raw_size); if UnloadWhenUnused then Fraw_file.Free else FRawOpened := True; end else begin if FUnloadWhenUnused or not FSepOpened then Fsep_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.sep'), fmOpenReadWrite); Fsep_file.Seek(raw_info.raw_addr + offset, soFromBeginning); Fsep_file.Write(target^, raw_info.raw_size); if UnloadWhenUnused then Fsep_file.Free else FSepOpened := True; end; end; end; function TOniDataDat.AppendRawFile(loc_sep: Boolean; size: LongWord; target: Pointer): LongWord; //Returns new Address begin if not loc_sep then begin if FUnloadWhenUnused or not FRawOpened then Fraw_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.raw'), fmOpenReadWrite); Result := Fraw_file.Size; Fraw_file.Seek(0, soFromEnd); Fraw_file.Write(target^, size); if UnloadWhenUnused then Fraw_file.Free else FRawOpened := True; end else begin if FUnloadWhenUnused or not FSepOpened then Fsep_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.sep'), fmOpenReadWrite); Result := Fsep_file.Size; Fsep_file.Seek(0, soFromEnd); Fsep_file.Write(target^, size); if UnloadWhenUnused then Fsep_file.Free else FSepOpened := True; end; end; (* ================================================================================ Implementation of TOniDataADB *) constructor TOniDataADB.Create(OLDBFilename: String; var Result: Boolean); var i, j: Byte; temps: String; begin if not FileExists(OLDBFilename) then begin ShowMessage('File doesn''t exist!!!'); Result := False; Exit; end; FFileName := OLDBFilename; FDatabase := TABSDatabase.Create(nil); FDatabase.DatabaseName := 'OLDBcon'; FDatabase.DatabaseFileName := OLDBFilename; FDatabase.Open; FQuery := TABSQuery.Create(FDatabase); FQuery.DatabaseName := 'OLDBcon'; FQuery.SQL.Text := 'SELECT [name],[value] FROM globals ORDER BY [name] ASC'; FQuery.Open; FQuery.First; repeat if FQuery.FieldByName('name').AsString = 'dbversion' then begin if FQuery.FieldByName('value').AsString <> DBversion 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; UpdateListCache; Result := True; FBackend := ODB_ADB; end; procedure TOniDataADB.Close; begin FDatabase.Close; FDatabase.Free; Self.Free; end; procedure TOniDataADB.UpdateListCache; var i: LongWord; temps: String; begin FQuery.SQL.Text := 'SELECT id,name,extension,[size],contenttype FROM datfiles ORDER BY id ASC;'; FQuery.Open; if FQuery.RecordCount > 0 then begin FQuery.First; SetLength(Fdat_files, FQuery.RecordCount); i := 0; repeat Fdat_files[i].ID := FQuery.FieldByName('id').AsInteger; Fdat_files[i].Name := FQuery.FieldByName('name').AsString; Fdat_files[i].Extension := FQuery.FieldByName('extension').AsString; Fdat_files[i].FileName := FormatNumber(Fdat_files[i].ID, 5, '0') + '-' + Fdat_files[i].Name + '.' + Fdat_files[0].Extension; Fdat_files[i].FileNameHex := IntToHex(Fdat_files[i].ID, 4) + '-' + Fdat_files[i].Name + '.' + Fdat_files[0].Extension; Fdat_files[i].Size := FQuery.FieldByName('size').AsInteger; Fdat_files[i].FileType := HexToLong(FQuery.FieldByName('contenttype').AsString); Fdat_files[i].DatAddr := 0; Fdat_files[i].opened := False; Inc(i); FQuery.Next; until FQuery.EOF; end; FQuery.Close; SetLength(Fdat_extensionsmap, 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(Fdat_extensionsmap, FQuery.RecordCount); i := 0; repeat temps := FQuery.FieldByName('extension').AsString[1]; Fdat_extensionsmap[i].Extension[3] := temps[1]; Fdat_extensionsmap[i].Extension[2] := temps[2]; Fdat_extensionsmap[i].Extension[1] := temps[3]; Fdat_extensionsmap[i].Extension[0] := temps[4]; Fdat_extensionsmap[i].ExtCount := FQuery.FieldByName('x').AsInteger; Inc(i); FQuery.Next; until FQuery.EOF; end; FQuery.Close; end; function TOniDataADB.GetFileInfo(fileid: Integer): TFileInfo; var i: Integer; begin if fileid = -1 then begin Result := inherited GetFileInfo(fileid); Exit; end; if fileid < Self.GetFilesCount then begin for i := 0 to High(Fdat_files) do if Fdat_files[i].ID = fileid then Break; if i < Length(Fdat_files) then Result := Fdat_files[i] else Result.ID := -1; end else begin Result.ID := -1; end; end; function TOniDataADB.GetFilesList(ext: String; pattern: String; NoEmptyFiles: Boolean; sort: TSortType): TStringArray; var i: LongWord; list: TStringList; id, name, extension: String; fields: TStrings; procedure getfields; begin fields.CommaText := StringReplace(AnsiQuotedStr(list.Strings[i], '"'), ';', '","', [rfReplaceAll]); if sort in [stIDAsc, stIDDesc] then begin id := fields.Strings[0]; name := fields.Strings[1]; extension := fields.Strings[2]; end; if sort in [stNameAsc, stNameDesc] then begin id := fields.Strings[1]; name := fields.Strings[0]; extension := fields.Strings[2]; end; if sort in [stExtAsc, stExtDesc] then begin id := fields.Strings[1]; name := fields.Strings[2]; extension := fields.Strings[0]; end; end; begin list := TStringList.Create; list.Sorted := True; for i := 0 to High(Fdat_files) do begin if ((Length(ext) = 0) or (Pos(Fdat_files[i].Extension, ext) > 0)) 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 if AppSettings.FilenumbersAsHex then id := IntToHex(Fdat_files[i].ID, 4) else id := FormatNumber(Fdat_files[i].ID, 5, '0'); name := Fdat_files[i].Name; extension := Fdat_files[i].Extension; case sort of stIDAsc, stIDDesc: list.Add(id + ';' + name + ';' + extension); stNameAsc, stNameDesc: list.Add(name + ';' + id + ';' + extension); stExtAsc, stExtDesc: list.Add(extension + ';' + id + ';' + name); end; end; end; end; SetLength(Result, list.Count); fields := TStringList.Create; if sort in [stIDAsc, stNameAsc, stExtAsc] then for i := 0 to list.Count - 1 do begin getfields; Result[i] := id + '-' + name + '.' + extension; end else for i := list.Count - 1 downto 0 do begin getfields; Result[list.Count - i - 1] := id + '-' + name + '.' + extension; end; list.Free; fields.Free; end; function TOniDataADB.GetFilesCount: LongWord; begin Result := Length(Fdat_files); end; function TOniDataADB.GetExtensionsList: TStringArray; var i: LongWord; begin SetLength(Result, Length(Fdat_extensionsmap)); for i := 0 to High(Result) do begin with Fdat_extensionsmap[i] do begin Result[i] := Extension[3] + Extension[2] + Extension[1] + Extension[0] + ' (' + IntToStr(ExtCount) + ')'; end; end; end; function TOniDataADB.GetExtendedExtensionsList: TExtensionsMap; var i, j: LongWord; temps: String; Data: Tdata; begin SetLength(Result, 0); FQuery.SQL.Text := 'SELECT ext,ident FROM extlist ORDER BY ext ASC;'; FQuery.Open; if FQuery.RecordCount > 0 then begin SetLength(Result, FQuery.RecordCount); i := 0; repeat temps := FQuery.FieldByName('ext').AsString; for j := 0 to 3 do Result[i].Extension[j] := temps[4 - 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.GetNamedFilesMap: TNamedFilesMap; var i: LongWord; temp: Integer; temps: String; temparray: array of record id: Integer; fullname: String[50]; end; begin SetLength(temparray, 0); FQuery.SQL.Text := 'SELECT id,(extension+name) AS xname FROM datfiles WHERE Length(name)>0 ORDER BY extension,name ASC;'; FQuery.Open; if FQuery.RecordCount > 0 then begin repeat temp := FQuery.FieldByName('id').AsInteger; temps := FQuery.FieldByName('xname').AsString; SetLength(temparray, Length(temparray) + 1); if Length(temparray) > 1 then begin for i := High(temparray) - 1 downto 0 do begin if StringSmaller(temps, temparray[i].fullname) then begin temparray[i + 1] := temparray[i]; if i = 0 then begin temparray[i].id := temp; temparray[i].fullname := temps; end; end else begin temparray[i + 1].id := temp; temparray[i + 1].fullname := temps; Break; end; end; end else begin temparray[0].id := temp; temparray[0].fullname := temps; end; FQuery.Next; until FQuery.EOF; end; FQuery.Close; SetLength(Result, Length(temparray)); for i := 0 to High(temparray) do begin Result[i].FileNumber := temparray[i].id; Result[i].blubb := 0; end; end; function TOniDataADB.LoadDatFile(fileid: LongWord): Tdata; var mem: TStream; begin if fileid < Self.GetFilesCount then begin FQuery.SQL.Text := 'SELECT data FROM datfiles WHERE id=' + IntToStr(fileid) + ';'; FQuery.Open; if FQuery.RecordCount > 0 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 fileid < Self.GetFilesCount then begin mimecoder := TStringFormat_MIME64.Create; mem := TMemoryStream.Create; mem.Write(Data[0], Length(Data)); mem.Seek(0, soFromBeginning); FQuery.SQL.Text := 'UPDATE datfiles SET data=MimeToBin("' + MimeCoder.StrTo(mem.Memory, mem.Size) + '"), size=' + IntToStr(mem.Size) + ' WHERE id=' + IntToStr(fileid) + ';'; FQuery.ExecSQL; mem.Free; mimecoder.Free; end; UpdateListCache; end; procedure TOniDataADB.LoadDatFilePart(fileid, offset, size: LongWord; target: Pointer); var mem: TStream; begin if fileid < Self.GetFilesCount then begin FQuery.SQL.Text := 'SELECT data FROM datfiles WHERE id=' + IntToStr(fileid) + ';'; FQuery.Open; if FQuery.RecordCount > 0 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 fileid < Self.GetFilesCount then begin Data := Self.LoadDatFile(fileid); mimecoder := TStringFormat_MIME64.Create; mem := TMemoryStream.Create; mem.Write(Data[0], Length(Data)); mem.Seek(offset, soFromBeginning); mem.Write(target^, size); mem.Seek(0, soFromBeginning); FQuery.SQL.Text := 'UPDATE datfiles SET data=MimeToBin("' + MimeCoder.StrTo(mem.Memory, mem.Size) + '") WHERE id=' + IntToStr(fileid) + ';'; FQuery.ExecSQL; mem.Free; mimecoder.Free; end; end; function TOniDataADB.GetRawList(fileid: LongWord): TRawList; var i: LongWord; begin SetLength(Result, 0); FQuery.SQL.Text := 'SELECT [src_link_offset],[size],[sep] FROM rawmap WHERE [src_id]=' + IntToStr(fileid) + ' ORDER BY src_link_offset ASC;'; FQuery.Open; if FQuery.RecordCount > 0 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; Result[i].loc_sep := FQuery.FieldByName('sep').AsBoolean; 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 fileid < Self.GetFilesCount then begin FQuery.SQL.Text := 'SELECT data FROM rawmap WHERE (src_id=' + IntToStr(fileid) + ') AND (src_link_offset=' + IntToStr(dat_offset) + ');'; FQuery.Open; if FQuery.RecordCount > 0 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 < Self.GetFilesCount then begin mimecoder := TStringFormat_MIME64.Create; mem := TMemoryStream.Create; mem.Write(target^, size); mem.Seek(0, soFromBeginning); FQuery.SQL.Text := 'UPDATE rawmap SET data=MimeToBin("' + MimeCoder.StrTo( mem.Memory, mem.Size) + '") WHERE (src_id=' + IntToStr(fileid) + ') AND (src_link_offset=' + IntToStr(dat_offset) + ');'; FQuery.ExecSQL; mem.Free; mimecoder.Free; end; end; procedure TOniDataADB.LoadRawFilePart(fileid, dat_offset: LongWord; offset, size: LongWord; target: Pointer); var Data: Tdata; mem: TMemoryStream; begin if fileid < Self.GetFilesCount then begin SetLength(Data, Self.GetRawInfo(fileid, dat_offset).raw_size); Self.LoadRawFile(fileid, dat_offset, @Data[0]); mem := TMemoryStream.Create; mem.Write(Data[offset], size); mem.Read(target^, size); mem.Free; end; end; procedure TOniDataADB.UpdateRawFilePart(fileid, dat_offset: LongWord; offset, size: LongWord; target: Pointer); var MimeCoder: TStringFormat_MIME64; mem: TMemoryStream; Data: Tdata; begin if fileid < Self.GetFilesCount then begin SetLength(Data, Self.GetRawInfo(fileid, offset).raw_size); Self.LoadRawFile(fileid, offset, @Data[0]); mimecoder := TStringFormat_MIME64.Create; mem := TMemoryStream.Create; mem.Write(Data[0], Length(Data)); mem.Seek(offset, soFromBeginning); mem.Write(target^, size); mem.Seek(0, soFromBeginning); FQuery.SQL.Text := 'UPDATE rawmap SET data=MimeToBin("' + MimeCoder.StrTo( mem.Memory, mem.Size) + '") WHERE (src_id=' + IntToStr(fileid) + ') AND (src_link_offset=' + IntToStr(dat_offset) + ');'; FQuery.ExecSQL; mem.Free; mimecoder.Free; end; end; function CreateDataConnection(filename: String; backend: Integer): TOniData; var answer: Boolean; i: Integer; begin if Length(DataConnections) > 0 then begin for i := 0 to High(DataConnections) do begin if ExtractFileName(DataConnections[i].FFileName) = ExtractFileName(filename) then begin if DataConnections[i].FFileName <> filename then begin Result := nil; ShowMessage('You can not open two files with the same name at a time.'); end else Result := DataConnections[i]; Exit; end; end; end; if not FileExists(filename) then begin ShowMessage('File "' + filename + '" does not exist!'); Result := nil; Exit; end; SetLength(DataConnections, Length(DataConnections) + 1); i := High(DataConnections); case backend of ODB_Dat: DataConnections[i] := TOniDataDat.Create(filename, answer); ODB_ADB: DataConnections[i] := TOniDataADB.Create(filename, answer); else ShowMessage('Unknown Backend'); Result := nil; Exit; end; if answer then begin Result := DataConnections[i]; // Result := True; end else begin ShowMessage('File not loaded'); DataConnections[i].Close; DataConnections[i].Free; DataConnections[i] := nil; SetLength(DataConnections, Length(DataConnections) - 1); Result := nil; end; end; function ConnectionExists(filename: String): TOniData; var i: Integer; begin Result := nil; if Length(DataConnections) > 0 then for i := 0 to High(DataConnections) do if DataConnections[i].FFileName = filename then begin Result := DataConnections[i]; Exit; end; end; procedure CloseDataConnection(connection: TOniData); var i: Integer; found: Boolean; begin if Assigned(connection) then begin found := False; for i := 0 to High(DataConnections) do begin if not found then begin if DataConnections[i] = connection then begin DataConnections[i].Close; // DataConnections[i].Free; DataConnections[i] := nil; found := True; end; end else begin DataConnections[i - 1] := DataConnections[i]; end; end; if found then SetLength(DataConnections, Length(DataConnections) - 1); end; end; function GetEmptyFileInfo: TFileInfo; begin Result.ID := -1; Result.FileName := ''; Result.FileNameHex := ''; Result.Extension := ''; Result.Name := ''; Result.Size := 0; Result.FileType := 0; Result.DatAddr := 0; Result.opened := False; end; end.