Mega Code Archive

 
Categories / Delphi / Examples
 

Header file format of interbase-firebird files

A simple class to get information about the disk structure of an interbase/firebird database. This simple class will allow you to specify an interbase/firebird database and it will retrive information about the database including Secondary files Page sizes On disk structure number Number of pages for each file etc To use it you can simply do this GDBInfo := TGDBInfo.Create('c:\something.gdb'); try for I := 0 to GDBInfo.Count - 1 do ShowMessage(GDBInfo[I].Filename); finally GDBInfo.Free; end; -------------------------------------------------------------------------------- unit GDBInfo; interface uses SysUtils, Classes; const cMAX_PAGE_SIZE = 32768; type SChar = Shortint; SShort = Smallint; UShort = Word; SLong = Longint; ULong = LongWord; TPag = packed record pag_type: SChar; pag_flags: SChar; pag_checksum: UShort; pag_generation: ULong; pag_seqno: ULong; pg_offset: ULong; end; THdr = packed record hdr_header: TPag; hdr_page_size: UShort; hdr_ods_version: UShort; hdr_pages: SLong; hdr_next_page: ULong; hdr_oldest_transaction: SLong; hdr_oldest_active: SLong; hdr_next_transaction: SLong; hdr_sequence: UShort; hdr_flags: UShort; hdr_creation_date: array[0..1] of SLong; hdr_attachment_id: SLong; hdr_shadow_count: SLong; hdr_implementation: SShort; hdr_ods_minor: UShort; hdr_ods_minor_original: UShort; hdr_end: UShort; hdr_page_buffers: ULong; hdr_bumped_transaction: SLong; hdr_oldest_snapshot: SLong; hdr_misc: array[0..3] of SLong; end; THdrPage = packed record fix_data: THdr; var_data: array[0..cMAX_PAGE_SIZE - 1 - SizeOf(THdr)] of Byte; end; //Not IB related EGDBError = class(Exception); PGDBFile = ^TGDBFileInfo; TGDBFileInfo = record Header: THdr; Filename: ShortString; ContinuationFile: ShortString; FirstLogicalPage: LongWord; LastLogicalPage: LongWord; TotalPages: LongWord; end; TGDBInfo = class private FList: TList; FFilename: string; procedure GetDBFiles; function GetItem(I: Integer): TGDBFileInfo; protected public constructor Create(const AFilename: string); destructor Destroy; override; function Count: Integer; property Items[I: Integer]: TGDBFileInfo read GetItem; default; end; implementation { TGDBInfo } function TGDBInfo.Count: Integer; begin Result := FList.Count; end; constructor TGDBInfo.Create(const AFilename: string); begin inherited Create; FList := TList.Create; FFilename := AFilename; GetDBFiles; end; destructor TGDBInfo.Destroy; var I: Integer; begin for I := Count - 1 downto 0 do begin FreeMem(FList[I]); FList.Delete(I); end; inherited; end; procedure TGDBInfo.GetDBFiles; var FS: TFileStream; HeaderPage: THdrPage; NewFile: PGDBFile; CurrentFilename: ShortString; FilenameSize: Byte; StartPage: LongWord; SourceDir: string; DataOffset: Integer; begin if not FileExists(FFilename) then raise EGDBError.Create('File does not exist - ' + FFilename); SourceDir := ExtractFilePath(FFilename); if SourceDir = '' then SourceDir := IncludeTrailingBackSlash(GetCurrentDir); StartPage := 0; CurrentFilename := SourceDir + ExtractFilename(FFilename); repeat FS := TFileStream.Create(CurrentFilename, fmOpenRead or fmShareDenyNone); try GetMem(NewFile, SizeOf(TGDBFileInfo)); FS.Read(HeaderPage, SizeOf(HeaderPage)); Move(HeaderPage, NewFile.Header, SizeOf(THdr)); DataOffset := 0; //Format of var_data is repeated //1 = Root file name //2 = Journal server //3 = Continuation file (this is the one we want) //4 = Last logical page //5 = Unlicensed accesses //6 = Sweep interval //7 = Replay logging file //11= Shared cache file while HeaderPage.var_data[DataOffset] <> 3 do begin if HeaderPage.var_data[DataOffset + 1] = 0 then Break; Inc(DataOffset, HeaderPage.var_data[DataOffset + 1] + 2); if DataOffset > HeaderPage.fix_data.hdr_page_size - SizeOf(HeaderPage.fix_data) then raise EGDBError.Create('Continuation'); end; FilenameSize := HeaderPage.var_data[DataOffset + 1]; NewFile.Filename := CurrentFileName; SetLength(NewFile.ContinuationFile, FilenameSize); if FilenameSize > 0 then Move(HeaderPage.var_data[DataOffset + 2], NewFile.ContinuationFile[1], FilenameSize); NewFile.FirstLogicalPage := StartPage; Move(HeaderPage.var_data[DataOffset + FilenameSize + 4], NewFile.LastLogicalPage, SizeOf(LongWord)); NewFile.TotalPages := NewFile.LastLogicalPage - NewFile.FirstLogicalPage; Inc(StartPage, NewFile.TotalPages); FList.Add(NewFile); CurrentFilename := NewFile.ContinuationFile; if CurrentFilename = '' then begin NewFile.LastLogicalPage := 0; NewFile.TotalPages := 0; Break; end; finally FS.Free; end; until False; end; function TGDBInfo.GetItem(I: Integer): TGDBFileInfo; begin Result := PGDBFile(FList[I])^; end; end.