You've already forked lazarus-ccr
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5438 8e941d3f-bd1b-0410-a28a-d453659cc2b4
1528 lines
49 KiB
ObjectPascal
1528 lines
49 KiB
ObjectPascal
{*********************************************************}
|
|
{* FlashFiler: FF 2 file interface definition *}
|
|
{*********************************************************}
|
|
|
|
(* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is TurboPower FlashFiler
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* TurboPower Software
|
|
*
|
|
* Portions created by the Initial Developer are Copyright (C) 1996-2002
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* ***** END LICENSE BLOCK ***** *)
|
|
|
|
{$I ffdefine.inc}
|
|
|
|
unit ffFileInt;
|
|
|
|
interface
|
|
|
|
uses
|
|
Dialogs,
|
|
Classes,
|
|
FFLLBase,
|
|
FFSrBase,
|
|
FFTBDict;
|
|
|
|
type
|
|
TffBlockType = (btUnknown, btFileHeader, btIndexHeader, btData,
|
|
btIndex, btBLOB, btStream, btFree);
|
|
|
|
{===Interface declarations===========================================}
|
|
|
|
ICommonBlock = interface; { forward declaration }
|
|
TffFileInterface = class; { forward declaration }
|
|
TffGeneralFileInfo = class; { forward declaration }
|
|
|
|
{ Event declarations }
|
|
|
|
TffGetInfoEvent = procedure(var Info : TffGeneralFileInfo) of object;
|
|
{ This event is raised by a block when it needs to
|
|
obtain information about the file containing the block. }
|
|
|
|
TffReportErrorEvent = procedure(Block : ICommonBlock;
|
|
const ErrCode : Integer;
|
|
const ErrorStr : string) of object;
|
|
{ This event is raised when an error is encountered during verification
|
|
of a block. It may be raised during both verification & repair. ErrCode
|
|
is the type of error encountered (see unit FFREPCNST for specific error
|
|
codes) and ErrorStr is an informative string describing the error. }
|
|
|
|
TffReportFixEvent = procedure(Block : ICommonBlock;
|
|
const ErrCode : Integer;
|
|
const RepairStr : string) of object;
|
|
{ This event is raised when an error in a block is repaired. ErrCode is
|
|
the type of error encountered (see unit FFREPCNST for specific error
|
|
codes) and RepairStr is an informative string describing how the
|
|
error was fixed. }
|
|
|
|
TffReportRebuildProgressEvent = procedure(FileInterface : TffFileInterface;
|
|
Position, Maximum : Integer) of object;
|
|
{ This event should be raised by the file interface while it is packing
|
|
or reindexing the table. }
|
|
|
|
ICommonBlock = interface
|
|
['{D23CBB0D-375D-4125-9FE6-E543B651B665}']
|
|
{ Common interface to a file block. Other interfaces specific to block
|
|
types are defined below. }
|
|
|
|
procedure BeginUpdate;
|
|
{ Call this method prior to updating a file block. }
|
|
procedure EndUpdate;
|
|
{ Call this method to commit changes to a file block. }
|
|
|
|
function GetBlockNum : TffWord32;
|
|
function GetBlockType : TffBlockType;
|
|
function GetLSN : TffWord32;
|
|
function GetNextBlock : TffWord32;
|
|
function GetOnGetInfo : TffGetInfoEvent;
|
|
function GetOnReportError : TffReportErrorEvent;
|
|
function GetOnReportFix : TffReportFixEvent;
|
|
function GetRawData : PffBlock;
|
|
function GetSignature : Longint;
|
|
function GetThisBlock : TffWord32;
|
|
|
|
{ Property access }
|
|
function GetPropertyCell(const Row, Column : Integer) : string;
|
|
function GetPropertyColCaption(const Index : Integer) : string;
|
|
function GetPropertyColCount : Integer;
|
|
function GetPropertyColWidth(const Index : Integer) : Integer;
|
|
function GetPropertyRowCount : Integer;
|
|
|
|
{ Data access }
|
|
function GetDataCell(const Row, Column : Integer) : string;
|
|
function GetDataColCaption(const Index : Integer) : string;
|
|
function GetDataColCount : Integer;
|
|
function GetDataColWidth(const Index : Integer) : Integer;
|
|
function GetDataRowCount : Integer;
|
|
|
|
function MapBlockTypeToStr(const BlockType : TffBlockType) : string;
|
|
function MapFlagsToStr(const Flags : Byte) : string;
|
|
function MapSigToStr(const Signature : Longint) : string;
|
|
|
|
procedure SetLSN(const Value : TffWord32);
|
|
procedure SetNextBlock(const Value : TffWord32);
|
|
procedure SetOnGetInfo(Value : TffGetInfoEvent);
|
|
procedure SetOnReportError(Value : TffReportErrorEvent);
|
|
procedure SetOnReportFix(Value : TffReportFixEvent);
|
|
procedure SetSignature(const Value : Longint);
|
|
procedure SetThisBlock(const Value : TffWord32);
|
|
|
|
procedure Repair;
|
|
{ Call this method to have a block verify itself & repair any flaws it
|
|
can repair on its own. }
|
|
|
|
procedure Verify;
|
|
{ Call this method to have a block verify itself. }
|
|
|
|
{ Properties }
|
|
property BlockNum : TffWord32
|
|
read GetBlockNum;
|
|
|
|
property BlockType : TffBlockType
|
|
read GetBlockType;
|
|
|
|
property LSN : TffWord32
|
|
read GetLSN write SetLSN;
|
|
|
|
property NextBlock : TffWord32
|
|
read GetNextBlock write SetNextBlock;
|
|
|
|
property OnGetInfo : TffGetInfoEvent
|
|
read GetOnGetInfo write SetOnGetInfo;
|
|
{ This event is raised when a block needs to obtain information about its
|
|
parent file. }
|
|
|
|
property OnReportError : TffReportErrorEvent
|
|
read GetOnReportError write SetOnReportError;
|
|
{ This event is raised when an error is detected in the block. It may
|
|
be raised during both verification & repair. }
|
|
|
|
property OnReportFix : TffReportFixEvent
|
|
read GetOnReportFix write SetOnReportFix;
|
|
{ This event is raised when an error is fixed. It is raised only during
|
|
the repair of a file. }
|
|
|
|
property RawData : PffBlock
|
|
read GetRawData;
|
|
|
|
property Signature : Longint
|
|
read GetSignature write SetSignature;
|
|
|
|
property ThisBlock : TffWord32
|
|
read GetThisBlock write SetThisBlock;
|
|
|
|
{ Property access }
|
|
property PropertyCell[const Row, Column : Integer] : string
|
|
read GetPropertyCell;
|
|
{ Returns the contents of the specified cell in the property view for
|
|
this block. The Row and Column values are zero-based. }
|
|
|
|
property PropertyColCaption[const Index : Integer] : string
|
|
read GetPropertyColCaption;
|
|
{ Returns the suggested caption for the specified column. The Index
|
|
parameter is zero-based. }
|
|
|
|
property PropertyColCount : Integer
|
|
read GetPropertyColCount;
|
|
{ The number of columns in the property view for this block. }
|
|
|
|
property PropertyColWidth[const Index : Integer] : Integer
|
|
read GetPropertyColWidth;
|
|
{ Returns the suggested width for the specified column. The Index
|
|
parameter is zero-based. }
|
|
|
|
property PropertyRowCount : Integer
|
|
read GetPropertyRowCount;
|
|
{ The number of property rows in the view for this block. }
|
|
|
|
{ Data access }
|
|
property DataCell[const Row, Column : Integer] : string
|
|
read GetDataCell;
|
|
{ Returns the contents of the specified cell in the data view for this
|
|
block. The Row and Column values are zero-based. }
|
|
|
|
property DataColCaption[const Index : Integer] : string
|
|
read GetDataColCaption;
|
|
{ Returns the suggested caption for the specified column. The Index
|
|
parameter is zero-based. }
|
|
|
|
property DataColCount : Integer
|
|
read GetDataColCount;
|
|
{ The number of columns in the data view for this block. }
|
|
|
|
property DataColWidth[const Index : Integer] : Integer
|
|
read GetDataColWidth;
|
|
{ Returns the suggested width for the specified column. The Index
|
|
parameter is zero-based. }
|
|
|
|
property DataRowCount : Integer
|
|
read GetDataRowCount;
|
|
{ The number of data rows in the view for this block. }
|
|
|
|
end;
|
|
|
|
IFileHeaderBlock = interface(ICommonBlock)
|
|
['{51157301-A9FA-4CBB-90A7-8FA30E8C17B9}']
|
|
function GetAvailBlocks : Longint;
|
|
function GetBLOBCount : TffWord32;
|
|
function GetBlockSize : Longint;
|
|
function GetDataDictBlockNum : TffWord32;
|
|
function GetDeletedBLOBHead : TffInt64;
|
|
function GetDeletedBLOBTail : TffInt64;
|
|
function GetDeletedRecordCount : Longint;
|
|
function GetEncrypted : Longint;
|
|
function GetEstimatedUsedBlocks : TffWord32;
|
|
function GetFFVersion : Longint;
|
|
function GetFieldCount : Longint;
|
|
function GetFirstDataBlock : TffWord32;
|
|
function GetFirstDeletedRecord : TffInt64;
|
|
function GetFirstFreeBlock : TffWord32;
|
|
function GetHasSequentialIndex : Longint;
|
|
function GetIndexCount : Longint;
|
|
function GetIndexHeaderBlockNum : TffWord32;
|
|
function GetLastAutoIncValue : TffWord32;
|
|
function GetLastDataBlock : TffWord32;
|
|
function GetLog2BlockSize : TffWord32;
|
|
function GetRecLenPlusTrailer : Longint;
|
|
function GetRecordCount : Longint;
|
|
function GetRecordLength : Longint;
|
|
function GetRecordsPerBlock : Longint;
|
|
function GetUsedBlocks : TffWord32;
|
|
|
|
procedure SetFirstDataBlock(const Value : TffWord32);
|
|
procedure SetFirstFreeBlock(const Value : TffWord32);
|
|
procedure SetHasSequentialIndex(const Value : Longint);
|
|
procedure SetLastDataBlock(const Value : TffWord32);
|
|
procedure SetLog2BlockSize(const Value : TffWord32);
|
|
procedure SetUsedBlocks(const Value : TffWord32);
|
|
|
|
property AvailBlocks : Longint
|
|
read GetAvailBlocks;
|
|
{ The number of free blocks in the file. }
|
|
|
|
property BLOBCount : TffWord32
|
|
read GetBLOBCount;
|
|
{ The number of BLOBs in the table. }
|
|
|
|
property BlockSize : Longint
|
|
read GetBlockSize;
|
|
{ Size of blocks in bytes (e.g., 4k, 8k, 16k, 32k, 64k) }
|
|
|
|
property DataDictBlockNum : TffWord32
|
|
read GetDataDictBlockNum;
|
|
{ The block number of the data dictionary. If there is no data
|
|
dictionary then this property returns the value zero. }
|
|
|
|
property DeletedBLOBHead : TffInt64
|
|
read GetDeletedBLOBHead;
|
|
{ The file-relative offset of the first segment in the deleted BLOB
|
|
chain. }
|
|
|
|
property DeletedBLOBTail : TffInt64
|
|
read GetDeletedBLOBTail;
|
|
{ The file-relative offset of the last segment in the deleted BLOB
|
|
chain. }
|
|
|
|
property DeletedRecordCount : Longint
|
|
read GetDeletedRecordCount;
|
|
{ The number of deleted records in the table. }
|
|
|
|
property Encrypted : Longint
|
|
read GetEncrypted;
|
|
{ 0 = not encrypted, 1 = encrypted }
|
|
|
|
property EstimatedUsedBlocks : TffWord32
|
|
read GetEstimatedUsedBlocks;
|
|
{ For cases where the UsedBlocks counter is invalid, use this property
|
|
to estimate the number of used blocks in the file. }
|
|
|
|
property FFVersion : Longint
|
|
read GetFFVersion;
|
|
{ The version of FlashFiler with which this table was created. }
|
|
|
|
property FieldCount : Longint
|
|
read GetFieldCount;
|
|
{ The number of fields in a record. }
|
|
|
|
property FirstDataBlock : TffWord32
|
|
read GetFirstDataBlock write SetFirstDataBlock;
|
|
{ The first data block in the chain of data blocks. }
|
|
|
|
property FirstDeletedRecord : TffInt64
|
|
read GetFirstDeletedRecord;
|
|
{ The offset of the first record in the deleted record chain. }
|
|
|
|
property FirstFreeBlock : TffWord32
|
|
read GetFirstFreeBlock write SetFirstFreeBlock;
|
|
{ The block number of the first free block in the deleted block chain. }
|
|
|
|
property HasSequentialIndex : Longint
|
|
read GetHasSequentialIndex write SetHasSequentialIndex;
|
|
{ Identifies whether the table has a sequential index. A value of zero
|
|
means the table does not have a sequential index. A value of 1
|
|
means the table does have a sequential index. }
|
|
|
|
property IndexCount : Longint
|
|
read GetIndexCount;
|
|
{ The number of indexes in the table. }
|
|
|
|
property IndexHeaderBlockNum : TffWord32
|
|
read GetIndexHeaderBlockNum;
|
|
{ The block number of the index header. }
|
|
|
|
property LastAutoIncValue : TffWord32
|
|
read GetLastAutoIncValue;
|
|
{ The last autoincrement value assigned to a record in the table. }
|
|
|
|
property LastDataBlock : TffWord32
|
|
read GetLastDataBlock write SetLastDataBlock;
|
|
{ The last data block in the chain of data blocks. }
|
|
|
|
property Log2BlockSize : TffWord32
|
|
read GetLog2BlockSize write SetLog2BlockSize;
|
|
{ log base 2 of BlockSize (e.g., 12, 13, 14, 15, or 16) }
|
|
|
|
property RecordCount : Longint
|
|
read GetRecordCount;
|
|
{ The number of records in the table. }
|
|
|
|
property RecordLength : Longint
|
|
read GetRecordLength;
|
|
{ The length of the record in bytes. }
|
|
|
|
property RecordLengthPlusTrailer : Longint
|
|
read GetRecLenPlusTrailer;
|
|
{ The length of the record plus the deletion link. }
|
|
|
|
property RecordsPerBlock : Longint
|
|
read GetRecordsPerBlock;
|
|
{ The number of records per data block. }
|
|
|
|
property UsedBlocks : TffWord32
|
|
read GetUsedBlocks write SetUsedBlocks;
|
|
{ The number of blocks in the file. }
|
|
|
|
end;
|
|
|
|
TffGeneralFileInfo = class
|
|
protected
|
|
{ The following vars identify the BLOB fields in a record. }
|
|
FBLOBFldCount : Integer;
|
|
{ The number of BLOB fields found. }
|
|
FBLOBFlds : array[0..1023] of Integer;
|
|
{ Contains field number (zero-based) of each BLOB field. }
|
|
FBLOBFldName : array[0..1023] of string;
|
|
{ Contains field description for each BLOB field. Each element of the
|
|
array has a one-to-one correspondence with the same element in the
|
|
BLOBFlds array. }
|
|
|
|
{ The following vars identify key fields for error reporting purposes. }
|
|
FKeyFldCount : Integer;
|
|
{ The number of key fields found. }
|
|
FKeyFlds : array[0..127] of Integer;
|
|
{ Contains field number (zero-based) of each key field used to uniquely
|
|
identify a record. }
|
|
FKeyFldName : array[0..127] of string;
|
|
{ Contains field description for each key field used to uniquely identify
|
|
a record. Each element of the array has a one-to-one correspondence with
|
|
the same element in the KeyFlds array. }
|
|
FUniqueIndexName : string;
|
|
{ Name of the unique index used for the key fields. }
|
|
|
|
FBlockSize : Longint;
|
|
FDict : TffServerDataDict;
|
|
FLog2BlockSize : TffWord32;
|
|
FRecLenPlusTrailer : Longint;
|
|
FRecordCount : Longint;
|
|
FRecordsPerBlock : Longint;
|
|
|
|
procedure CalcKeyFields; virtual;
|
|
function GetBLOBFields(const Inx : Integer) : Integer;
|
|
function GetBLOBFieldNames(const Inx : Integer) : string;
|
|
function GetKeyFields(const Inx : Integer) : Integer;
|
|
function GetKeyFieldNames(const Inx : Integer) : string;
|
|
procedure IdentBLOBFields; virtual;
|
|
|
|
public
|
|
{ Methods }
|
|
constructor Create(Dict : TffServerDataDict;
|
|
FileHeaderBlock : IFileHeaderBlock); virtual;
|
|
destructor Destroy; override;
|
|
|
|
function KeyFieldValues(RecPtr : PffByteArray) : string; virtual;
|
|
|
|
{ Properties }
|
|
property BLOBFieldCount : Integer
|
|
read FBLOBFldCount;
|
|
{ The number of BLOB fields in a record. }
|
|
property BLOBFields[const Inx : Integer] : Integer
|
|
read GetBLOBFields;
|
|
{ Array of BLOB field numbers. Returns an integer that is a zero-based
|
|
index into the dictionary's list of fields. }
|
|
property BLOBFieldNames[const Inx : Integer] : string
|
|
read GetBLOBFieldNames;
|
|
{ Array of BLOB field names. The elements of this array have a one-to-one
|
|
correspondence with the BLOBFields array. }
|
|
property BlockSize : Longint
|
|
read FBlockSize;
|
|
{ The size in bytes of the file's blocks. }
|
|
property Dict : TffServerDataDict
|
|
read FDict;
|
|
{ The data dictionary associated with the table. }
|
|
property KeyFieldCount : Integer
|
|
read FKeyFldCount;
|
|
{ Returns the number of fields used to uniquely identify a record in
|
|
the table. }
|
|
property KeyFields[const Inx : Integer] : Integer
|
|
read GetKeyFields;
|
|
{ Array of key field numbers. Returns an integer that is a zero-based
|
|
index into the dictionary's list of fields. }
|
|
property KeyFieldNames[const Inx : Integer] : string
|
|
read GetKeyFieldNames;
|
|
{ Array of key field names. The elements of this array have a one-to-one
|
|
correspondence with the KeyFields array. }
|
|
property Log2BlockSize : TffWord32
|
|
read FLog2BlockSize;
|
|
{ Calculated value representative of the file's block size. }
|
|
property RecLenPlusTrailer : Longint
|
|
read FRecLenPlusTrailer;
|
|
{ Record length plus # of trailing bytes for null field flags. }
|
|
property RecordCount : Longint
|
|
read FRecordCount;
|
|
{ The # of records in the file. }
|
|
property RecordsPerBlock : Longint
|
|
read FRecordsPerBlock;
|
|
{ The maximum # of records per block. }
|
|
property UniqueIndexName : string
|
|
read FUniqueIndexName;
|
|
{ Returns the name of the unique index used to identify records in the
|
|
table. }
|
|
end;
|
|
|
|
IDataBlock = interface(ICommonBlock)
|
|
['{7580BD14-3A18-40D9-8091-390D0150DF25}']
|
|
function GetRecCount : Longint;
|
|
function GetRecLen : Longint;
|
|
function GetNextDataBlock : TffWord32;
|
|
function GetPrevDataBlock : TffWord32;
|
|
|
|
procedure SetNextDataBlock(const Value : TffWord32);
|
|
procedure SetPrevDataBlock(const Value : TffWord32);
|
|
procedure SetRecCount(const Value : Longint);
|
|
procedure SetRecLen(const Value : Longint);
|
|
|
|
property RecordCount : Longint
|
|
read GetRecCount write SetRecCount;
|
|
{ The maximum number of records in the block. }
|
|
property RecordLen : Longint
|
|
read GetRecLen write SetRecLen;
|
|
{ The length of each record. }
|
|
property NextDataBlock : TffWord32
|
|
read GetNextDataBlock write SetNextDataBlock;
|
|
{ The block # of the next data block. }
|
|
property PrevDataBlock : TffWord32
|
|
read GetPrevDataBlock write SetPrevDataBlock;
|
|
{ The block # of the previous data block. }
|
|
end;
|
|
|
|
IIndexBlock = interface(ICommonBlock)
|
|
['{88433E3F-F4AD-445C-841A-A409751E38FE}']
|
|
function GetIndexBlockType : Byte;
|
|
function GetIsLeafPage : Boolean;
|
|
function GetNodeLevel : Byte;
|
|
function GetKeysAreRefs : Boolean;
|
|
function GetIndexNum : Word;
|
|
function GetKeyLength : Word;
|
|
function GetKeyCount : Longint;
|
|
function GetMaxKeyCount : Longint;
|
|
function GetPrevPageRef : TffWord32;
|
|
|
|
property IndexBlockType : Byte
|
|
read GetIndexBlockType;
|
|
{ The type of index block. Header blocks have value 0, B-Tree pages
|
|
have value 1. }
|
|
property IsLeafPage : Boolean
|
|
read GetIsLeafPage;
|
|
{ Returns False if this is an internal B-Tree page or True if this is
|
|
a leaf B-Tree page. }
|
|
property NodeLevel : Byte
|
|
read GetNodeLevel;
|
|
{ Returns the node level. Leaves have value 1, increments. }
|
|
property KeysAreRefs : Boolean
|
|
read GetKeysAreRefs;
|
|
{ Returns the value True if the keys in the index are record reference
|
|
numbers. }
|
|
property IndexNum : Word
|
|
read GetIndexNum;
|
|
{ The index number with which the index page is associated. }
|
|
property KeyLength : Word
|
|
read GetKeyLength;
|
|
{ The length of each key. }
|
|
property KeyCount : Longint
|
|
read GetKeyCount;
|
|
{ The number of keys currently in the page. }
|
|
property MaxKeyCount : Longint
|
|
read GetMaxKeyCount;
|
|
{ The maximum number of keys that may be placed within the page. }
|
|
property PrevPageRef : TffWord32
|
|
read GetPrevPageRef;
|
|
{ Block number of the previous page. }
|
|
end;
|
|
|
|
IIndexHeaderBlock = interface(IIndexBlock)
|
|
['{B5B7D142-BB11-4325-8E2E-D4E3621A2FE3}']
|
|
end;
|
|
|
|
IBLOBBlock = interface(ICommonBlock)
|
|
['{D4D5737F-3295-47FC-A6BF-A5B00AE5F905}']
|
|
end;
|
|
|
|
IStreamBlock = interface(ICommonBlock)
|
|
['{648433B7-604C-49BC-87D0-338582B1B238}']
|
|
function GetNextStrmBlock : TffWord32;
|
|
function GetOwningStream : Longint;
|
|
function GetStreamLength : Longint;
|
|
function GetStreamType : Longint;
|
|
|
|
property NextStreamBlock : TffWord32
|
|
read GetNextStrmBlock;
|
|
{ Block number of the next stream block in the chain or ffc_W32NoValue. }
|
|
|
|
property OwningStream : Longint
|
|
read GetOwningStream;
|
|
{ Block number of the first block of the stream. }
|
|
|
|
property StreamLength : Longint
|
|
read GetStreamLength;
|
|
{ Returns the length of the stream. This value is filled only for the
|
|
first stream block. }
|
|
|
|
property StreamType : Longint
|
|
read GetStreamType;
|
|
{ For dictionary blocks, this will contain the value of constant
|
|
ffc_SigDictStream. If it is a user-defined stream, it will contain
|
|
some user-defined value. }
|
|
|
|
end;
|
|
|
|
{===Class declarations===============================================}
|
|
|
|
TffFileBlock = class; { forward declaration }
|
|
TffFileInterface = class
|
|
{ This abstract class defines the interface to a FlashFiler table. This
|
|
interface is used by TffRepair to open a table & retrieve blocks from
|
|
the table.
|
|
|
|
In the initialization section, specific instances of this class must use
|
|
the Register method to indicate their availability for specific FF table
|
|
versions. The Unregister method must be called during finalization to
|
|
deregister availability.
|
|
}
|
|
protected
|
|
FStartFFVersion : Longint;
|
|
FEndFFVersion : Longint;
|
|
FID : string;
|
|
FOutputVersion : Longint;
|
|
{ When a table is packed, the FF version that is to be assigned to the
|
|
table. }
|
|
FRebuildProgress : TffReportRebuildProgressEvent;
|
|
|
|
function GetDictBlockCount : Longint; virtual; abstract;
|
|
function GetDictBlocks(const Inx : Longint) : IStreamBlock; virtual; abstract;
|
|
function GetOnReportError : TffReportErrorEvent; virtual; abstract;
|
|
function GetOnReportFix : TffReportFixEvent; virtual; abstract;
|
|
|
|
procedure SetOnReportError(Value : TffReportErrorEvent); virtual; abstract;
|
|
procedure SetOnReportFix(Value : TffReportFixEvent); virtual; abstract;
|
|
procedure SetOutputVersion(const Value : Longint); virtual; abstract;
|
|
|
|
public
|
|
|
|
{ ========= Registration methods ========= }
|
|
class procedure Register(const ID : string); virtual;
|
|
{ Creates an instance of this object and adds it to the list of
|
|
registered file interfaces. }
|
|
|
|
class procedure Unregister;
|
|
{ Removes all instances of this class type from the list of
|
|
registered file interfaces. }
|
|
|
|
class function FindInterface(const FileName : string) : TffFileInterface;
|
|
{ Searchs the list of registered file interface for a file interface that
|
|
handles the specified FlashFiler table. }
|
|
|
|
procedure Initialize; virtual;
|
|
{ This method is called after the object is instantiated via the
|
|
Register class method. }
|
|
|
|
function Handles(const FileName : string) : Boolean; virtual;
|
|
{ This function is called by the FindInterface class function. This
|
|
function must determine whether the file interface handles the specified
|
|
FlashFiler table. The default implementation compares the file's version
|
|
against the value of the StartVersion and EndVersion properties. }
|
|
|
|
{ ========= Functionality methods ========= }
|
|
procedure Close; virtual; abstract;
|
|
{ Close the currently opened file. }
|
|
|
|
function GetBlock(const BlockNumber : Longint) : ICommonBlock; virtual; abstract;
|
|
{ Returns a specific block from the file. }
|
|
|
|
function GetFileHeaderBlock : IFileHeaderBlock; virtual; abstract;
|
|
{ Returns the file header block. }
|
|
|
|
function GetFileInfo : TffGeneralFileInfo; virtual; abstract;
|
|
{ Returns general file information that is made available to blocks. }
|
|
|
|
function GetIndexHeaderBlock : IIndexHeaderBlock; virtual; abstract;
|
|
{ Returns the index header block. }
|
|
|
|
procedure Open(const Filename : string); virtual; abstract;
|
|
{ Open a file for analysis. }
|
|
|
|
procedure Pack; virtual; abstract;
|
|
|
|
{ Properties }
|
|
property DictBlockCount : Longint
|
|
read GetDictBlockCount;
|
|
{ Returns the number of data dictionary blocks. }
|
|
|
|
property DictBlocks[const Inx : Longint] : IStreamBlock
|
|
read GetDictBlocks;
|
|
{ Returns the specified data dictionary block. }
|
|
|
|
property EndFFVersion : Longint
|
|
read FEndFFVersion;
|
|
{ The final version of FF this interface supports. }
|
|
|
|
property ID : string
|
|
read FID;
|
|
|
|
property OnRebuildProgress : TffReportRebuildProgressEvent
|
|
read FRebuildProgress write FRebuildProgress;
|
|
{ Event handler used to report progress of reindex or pack. }
|
|
|
|
property OnReportError : TffReportErrorEvent
|
|
read GetOnReportError write SetOnReportError;
|
|
{ This event is raised when an error is detected in the block. It may
|
|
be raised during both verification & repair. }
|
|
|
|
property OnReportFix : TffReportFixEvent
|
|
read GetOnReportFix write SetOnReportFix;
|
|
{ This event is raised when an error is fixed. It is raised only during
|
|
the repair of a file. }
|
|
|
|
property OutputVersion : Longint
|
|
read FOutputVersion write SetOutputVersion;
|
|
{ The FF version to be assigned to a table when the table is packed.
|
|
Defaults to the current FF version. }
|
|
|
|
property StartFFVersion : Longint
|
|
read FStartFFVersion;
|
|
{ The first version of FF this interface supports. }
|
|
|
|
end;
|
|
|
|
TffFileBlock = class(TInterfacedObject, ICommonBlock)
|
|
{ Base class representing a file block. Classes implementing an interface
|
|
supporting a specific type of block should inherit from this class &
|
|
the appropriate interface. }
|
|
protected
|
|
|
|
FBlock : PffBlock;
|
|
FBlockNum : TffWord32;
|
|
FBufMgr : TffBufferManager;
|
|
FFileInfo : PffFileInfo;
|
|
FOnGetInfo : TffGetInfoEvent;
|
|
FOnReportError : TffReportErrorEvent;
|
|
FOnReportFix : TffReportFixEvent;
|
|
FRelMethod : TffReleaseMethod;
|
|
FTI : PffTransInfo;
|
|
|
|
procedure DoReportError(const ErrCode : Integer;
|
|
args : array of const); virtual;
|
|
procedure DoReportFix(const ErrCode: Integer;
|
|
args : array of const); virtual;
|
|
function GetBlockNum : TffWord32;
|
|
function GetBlockType : TffBlockType; virtual;
|
|
function GetLSN : TffWord32; virtual;
|
|
function GetNextBlock : TffWord32; virtual;
|
|
function GetOnGetInfo : TffGetInfoEvent; virtual;
|
|
function GetOnReportError : TffReportErrorEvent; virtual;
|
|
function GetOnReportFix : TffReportFixEvent; virtual;
|
|
function GetRawData : PffBlock; virtual;
|
|
function GetSignature : Longint; virtual;
|
|
function GetThisBlock : TffWord32; virtual;
|
|
|
|
{ Property access }
|
|
function GetPropertyCell(const Row, Column : Integer) : string; virtual;
|
|
function GetPropertyColCaption(const Index : Integer) : string; virtual;
|
|
function GetPropertyColCount : Integer; virtual;
|
|
function GetPropertyColWidth(const Index : Integer) : Integer; virtual;
|
|
function GetPropertyRowCount : Integer; virtual;
|
|
|
|
{ Data access }
|
|
function GetDataCell(const Row, Column : Integer) : string; virtual;
|
|
function GetDataColCaption(const Index : Integer) : string; virtual;
|
|
function GetDataColCount : Integer; virtual;
|
|
function GetDataColWidth(const Index : Integer) : Integer; virtual;
|
|
function GetDataRowCount : Integer; virtual;
|
|
|
|
procedure SetLSN(const Value : TffWord32); virtual;
|
|
procedure SetNextBlock(const Value : TffWord32); virtual;
|
|
procedure SetOnGetInfo(Value : TffGetInfoEvent); virtual;
|
|
procedure SetOnReportError(Value : TffReportErrorEvent); virtual;
|
|
procedure SetOnReportFix(Value : TffReportFixEvent); virtual;
|
|
procedure SetSignature(const Value : Longint); virtual;
|
|
procedure SetThisBlock(const Value : TffWord32); virtual;
|
|
|
|
procedure VerifyRepair(const Repair : Boolean); virtual;
|
|
{ This method is used by both Verify & Repair. It carries out the actual
|
|
verification &, if specified, repairing of problems. }
|
|
public
|
|
|
|
constructor Create(BufMgr : TffBufferManager;
|
|
FileInfo : PffFileInfo;
|
|
TI : PffTransInfo;
|
|
const BlockNum : TffWord32); virtual;
|
|
destructor Destroy; override;
|
|
|
|
procedure BeginUpdate; virtual;
|
|
{ Call this method prior to updating a file block. }
|
|
procedure EndUpdate; virtual;
|
|
{ Call this method to commit changes to a file block. }
|
|
|
|
function MapBlockTypeToStr(const BlockType : TffBlockType) : string; virtual;
|
|
{ Use this to retrieve a text string representing the block type. }
|
|
|
|
function MapFlagsToStr(const Flags : Byte) : string;
|
|
{ Use this to retrieve a text string representing the flags for an
|
|
index. }
|
|
|
|
function MapSigToStr(const Signature : Longint) : string; virtual;
|
|
{ Use this to retrieve a text string representing the signature. }
|
|
|
|
procedure Repair; virtual;
|
|
{ Call this method to have a block verify itself & repair any flaws it
|
|
can repair on its own. }
|
|
|
|
procedure Verify; virtual;
|
|
{ Call this method to have a block verify itself. }
|
|
|
|
{ Properties }
|
|
property BlockNum : TffWord32
|
|
read GetBlockNum;
|
|
|
|
property BlockType : TffBlockType
|
|
read GetBlockType;
|
|
|
|
property LSN : TffWord32
|
|
read GetLSN write SetLSN;
|
|
|
|
property NextBlock : TffWord32
|
|
read GetNextBlock write SetNextBlock;
|
|
|
|
property OnGetInfo : TffGetInfoEvent
|
|
read GetOnGetInfo write SetOnGetInfo;
|
|
{ This event is raised by a TffFileBlock instance when it needs to
|
|
obtain information about the file containing the block. The parent file
|
|
interface must supply a handler for this event. }
|
|
|
|
property OnReportError : TffReportErrorEvent
|
|
read GetOnReportError write SetOnReportError;
|
|
{ This event is raised when an error is detected in the block. It may
|
|
be raised during both verification & repair. }
|
|
|
|
property OnReportFix : TffReportFixEvent
|
|
read GetOnReportFix write SetOnReportFix;
|
|
{ This event is raised when an error is fixed. It is raised only during
|
|
the repair of a file. }
|
|
|
|
property RawData : PffBlock
|
|
read GetRawData;
|
|
|
|
property Signature : Longint
|
|
read GetSignature write SetSignature;
|
|
|
|
property ThisBlock : TffWord32
|
|
read GetThisBlock write SetThisBlock;
|
|
end;
|
|
|
|
{ Utility functions }
|
|
function BooleanValue(const TrueStr, FalseStr : string;
|
|
const Value : Boolean) : string;
|
|
function FlagStr(const Flag : Byte; const ZeroStr, OneStr : string) : string;
|
|
function ByteToHex(const B : byte) : string;
|
|
procedure GenerateHexLines(Buf : pointer; BufLen : TffMemSize;
|
|
Strings: TStrings);
|
|
function Int64ToStr(const Value : TffInt64) : string;
|
|
function LongintToChars(const L : Longint) : string;
|
|
function LongintToHex(const L : Longint) : string;
|
|
function Mirror(const Value : string) : string;
|
|
function VersionToStr(const Version : Longint) : string;
|
|
function YesNoValue(const Value : Longint) : string;
|
|
|
|
const
|
|
ciFileBlockColumns = 2;
|
|
ciFileBlockRows = 5;
|
|
|
|
implementation
|
|
|
|
uses
|
|
FFRepCnst,
|
|
FFUtil,
|
|
SysUtils;
|
|
|
|
var
|
|
_FileInterfaces : TffPointerList;
|
|
|
|
{===Utility functions================================================}
|
|
function BooleanValue(const TrueStr, FalseStr : string;
|
|
const Value : Boolean) : string;
|
|
begin
|
|
if Value then
|
|
Result := TrueStr
|
|
else
|
|
Result := FalseStr;
|
|
end;
|
|
{--------}
|
|
function FlagStr(const Flag : Byte; const ZeroStr, OneStr : string) : string;
|
|
begin
|
|
if Flag = 0 then
|
|
Result := ZeroStr
|
|
else
|
|
Result := OneStr;
|
|
Result := Result + '(' + IntToStr(Flag) + ')';
|
|
end;
|
|
{--------}
|
|
function ByteToHex(const B : byte) : string;
|
|
const
|
|
HexChars : array [0..15] of AnsiChar = '0123456789abcdef';
|
|
begin
|
|
Result := HexChars[B shr 4] + HexChars[B and $F];
|
|
end;
|
|
{--------}
|
|
procedure GenerateHexLines(Buf : pointer; BufLen : TffMemSize;
|
|
Strings : TStrings);
|
|
const
|
|
HexPos : array [0..15] of byte =
|
|
(1, 3, 5, 7, 10, 12, 14, 16, 19, 21, 23, 25, 28, 30, 32, 34);
|
|
HexChar : array [0..15] of char = '0123456789ABCDEF';
|
|
var
|
|
B : PffByteArray absolute Buf;
|
|
ThisWidth,
|
|
i, j : integer;
|
|
Line : string[56];
|
|
Work : byte;
|
|
begin
|
|
Strings.Clear;
|
|
if (BufLen = 0) or (Buf = nil) then
|
|
Exit
|
|
else begin
|
|
for i := 0 to ((BufLen-1) shr 4) do begin
|
|
FillChar(Line, 56, ' ');
|
|
Line[0] := #55;
|
|
Line[38] := '['; Line[55] := ']';
|
|
if (BufLen >= 16) then
|
|
ThisWidth := 16
|
|
else
|
|
ThisWidth := BufLen;
|
|
for j := 0 to Pred(ThisWidth) do begin
|
|
Work := B^[(i shl 4) + j];
|
|
Line[HexPos[j]] := HexChar[Work shr 4];
|
|
Line[HexPos[j]+1] := HexChar[Work and $F];
|
|
if (Work < 32) then
|
|
Work := ord('.');
|
|
Line[39+j] := char(Work);
|
|
end;
|
|
Strings.Add(Line);
|
|
dec(BufLen, ThisWidth);
|
|
end;
|
|
end;
|
|
end;
|
|
{--------}
|
|
function Int64ToStr(const Value : TffInt64) : string;
|
|
begin
|
|
Result := IntToStr(Value.iHigh) + ':' + IntToStr(Value.iLow);
|
|
end;
|
|
{--------}
|
|
function LongintToChars(const L : Longint) : string;
|
|
var
|
|
Inx : Integer;
|
|
Val : Integer;
|
|
begin
|
|
Result := Char(L shr 24) +
|
|
Char((L shr 16) and $FF) +
|
|
Char((L shr 8) and $FF) +
|
|
Char(L and $FF);
|
|
|
|
{ Convert values 0 - 9 to corresponding digits. }
|
|
for Inx := 1 to 4 do begin
|
|
Val := Ord(Result[Inx]);
|
|
if Val < 10 then
|
|
Result[Inx] := Char(Val + 48);
|
|
end;
|
|
end;
|
|
{--------}
|
|
function LongintToHex(const L : Longint) : string;
|
|
begin
|
|
Result := ByteToHex(L shr 24) +
|
|
ByteToHex((L shr 16) and $FF) +
|
|
ByteToHex((L shr 8) and $FF) +
|
|
ByteToHex(L and $FF);
|
|
end;
|
|
{--------}
|
|
function Mirror(const Value : string) : string;
|
|
var
|
|
Inx : Integer;
|
|
Len : Integer;
|
|
begin
|
|
Len := Length(Value);
|
|
SetLength(Result, Len);
|
|
for Inx := 1 to Len do
|
|
Result[Len - Pred(Inx)] := Value[Inx];
|
|
end;
|
|
{--------}
|
|
function VersionToStr(const Version : Longint) : string;
|
|
begin
|
|
Result := Format('%5.4f', [Version / 10000.0]);
|
|
end;
|
|
{--------}
|
|
function YesNoValue(const Value : Longint) : string;
|
|
begin
|
|
if Value = 0 then
|
|
Result := 'No (0)'
|
|
else
|
|
Result := 'Yes (' + IntToStr(Value) + ')';
|
|
end;
|
|
{====================================================================}
|
|
|
|
{===TffGeneralFileInfo===============================================}
|
|
constructor TffGeneralFileInfo.Create(Dict : TffServerDataDict;
|
|
FileHeaderBlock : IFileHeaderBlock);
|
|
begin
|
|
inherited Create;
|
|
|
|
FDict := TffServerDataDict.Create(Dict.BlockSize);
|
|
FDict.Assign(Dict);
|
|
|
|
FBlockSize := FileHeaderBlock.BlockSize;
|
|
FLog2BlockSize := FileHeaderBlock.Log2BlockSize;
|
|
FRecLenPlusTrailer := FileHeaderBlock.RecordLengthPlusTrailer;
|
|
FRecordCount := FileHeaderBlock.RecordCount;
|
|
FRecordsPerBlock := FileHeaderBlock.RecordsPerBlock;
|
|
|
|
IdentBLOBFields;
|
|
CalcKeyFields;
|
|
end;
|
|
{--------}
|
|
destructor TffGeneralFileInfo.Destroy;
|
|
begin
|
|
FDict.Free;
|
|
inherited;
|
|
end;
|
|
{--------}
|
|
procedure TffGeneralFileInfo.CalcKeyFields;
|
|
var
|
|
Inx : Integer;
|
|
IndexDesc : PffIndexDescriptor;
|
|
begin
|
|
if FKeyFldCount = 0 then begin
|
|
{ Determine which fields will be used to uniquely identify each
|
|
record.
|
|
|
|
Strategy: Find the first unique index. If that is found, use its fields
|
|
to identify the record. If one is not found then use first 4 fields. }
|
|
|
|
FillChar(FKeyFlds, SizeOf(FKeyFlds), 0);
|
|
FKeyFldCount := 0;
|
|
IndexDesc := nil;
|
|
for Inx := 1 to Pred(FDict.IndexCount) do begin
|
|
{ Skip Sequential Access Index. }
|
|
if not FDict.IndexAllowDups[Inx] then begin
|
|
IndexDesc := FDict.IndexDescriptor[Inx];
|
|
Break;
|
|
end; { if }
|
|
end; { for }
|
|
|
|
if Assigned(IndexDesc) then begin
|
|
{ Records will be identified using a unique index. }
|
|
FUniqueIndexName := IndexDesc^.idName;
|
|
for Inx := 0 to Pred(IndexDesc^.idCount) do begin
|
|
FKeyFlds[Inx] := IndexDesc^.idFields[Inx];
|
|
FKeyFldName[Inx] := FDict.FieldName[FKeyFlds[Inx]];
|
|
end; { for }
|
|
FKeyFldCount := IndexDesc^.idCount;
|
|
end
|
|
else begin
|
|
FKeyFldCount := FFMinI(4, FDict.FieldCount);
|
|
FUniqueIndexName := 'No unique index. Records identified using fields 1 ' +
|
|
'through ' + IntToStr(FKeyFldCount) + ' of the table.';
|
|
for Inx := 0 to Pred(FKeyFldCount) do begin
|
|
FKeyFlds[Inx] := Inx;
|
|
FKeyFldName[Inx] := FDict.FieldDesc[Inx];
|
|
end; { for }
|
|
end; { if..else }
|
|
end; { if }
|
|
end;
|
|
{--------}
|
|
function TffGeneralFileInfo.GetBLOBFields(const Inx : Integer) : Integer;
|
|
begin
|
|
Result := FBLOBFlds[Inx];
|
|
end;
|
|
{--------}
|
|
function TffGeneralFileInfo.GetBLOBFieldNames(const Inx : Integer) : string;
|
|
begin
|
|
Result := FBLOBFldName[Inx];
|
|
end;
|
|
{--------}
|
|
function TffGeneralFileInfo.GetKeyFields(const Inx : Integer) : Integer;
|
|
begin
|
|
Result := FKeyFlds[Inx];
|
|
end;
|
|
{--------}
|
|
function TffGeneralFileInfo.GetKeyFieldNames(const Inx : Integer) : string;
|
|
begin
|
|
Result := FKeyFldName[Inx];
|
|
end;
|
|
{--------}
|
|
procedure TffGeneralFileInfo.IdentBLOBFields;
|
|
var
|
|
Inx : Integer;
|
|
begin
|
|
FillChar(FBLOBFlds, SizeOf(FBLOBFlds), 0);
|
|
FBLOBFldCount := 0;
|
|
for Inx := 0 to Pred(FDict.FieldCount) do begin
|
|
if FDict.FieldType[Inx] in [fftBLOB..fftBLOBTypedBin] then begin
|
|
FBLOBFlds[FBLOBFldCount] := Inx;
|
|
FBLOBFldName[FBLOBFldCount] := FDict.FieldName[Inx];
|
|
inc(FBLOBFldCount);
|
|
end; { if }
|
|
end; { for }
|
|
end;
|
|
{--------}
|
|
function TffGeneralFileInfo.KeyFieldValues(RecPtr : PffByteArray) : string;
|
|
var
|
|
Inx : Integer;
|
|
FieldValue : TffVCheckValue;
|
|
IsNull : Boolean;
|
|
begin
|
|
Result := '';
|
|
for Inx := 0 to Pred(FKeyFldCount) do begin
|
|
if Result <> '' then
|
|
Result := Result + '; ';
|
|
FillChar(FieldValue, SizeOf(FieldValue), 0);
|
|
FDict.GetRecordField(FKeyFlds[Inx], RecPtr, IsNull, @FieldValue);
|
|
if IsNull then
|
|
Result := Result + Format('%s: %s',
|
|
[FKeyFldName[Inx], '<null>'])
|
|
else
|
|
Result := Result + Format('%s: %s',
|
|
[FKeyFldName[Inx],
|
|
FFVCheckValToString
|
|
(FieldValue,
|
|
FDict.FieldType[FKeyFlds[Inx]])
|
|
]);
|
|
end; { for }
|
|
end;
|
|
{====================================================================}
|
|
|
|
{===TffFileInterface=================================================}
|
|
function TffFileInterface.Handles(const FileName : string) : Boolean;
|
|
var
|
|
CharsRead : Integer;
|
|
FileVersion : Longint;
|
|
Stream : TFileStream;
|
|
Block : TffBlock;
|
|
FileHeader : PffBlockHeaderFile;
|
|
begin
|
|
Result := False;
|
|
Stream := TFileStream.Create(FileName, fmOpenRead);
|
|
try
|
|
{ Read the file header. }
|
|
CharsRead := Stream.Read(Block, 4096);
|
|
if CharsRead = 4096 then begin
|
|
FileHeader := PffBlockHeaderFile(@Block);
|
|
if FileHeader^.bhfSignature = ffc_SigHeaderBlock then begin
|
|
{ Check the version. }
|
|
FileVersion := FileHeader^.bhfFFVersion;
|
|
Result := (FileVersion >= StartFFVersion) and (FileVersion <= EndFFVersion);
|
|
end;
|
|
end
|
|
else
|
|
raise Exception.CreateFmt('"%s" is not a FlashFiler table.', [FileName]);
|
|
finally
|
|
Stream.Free;
|
|
end;
|
|
end;
|
|
{--------}
|
|
class procedure TffFileInterface.Register(const ID : string);
|
|
var
|
|
FileInterface: TffFileInterface;
|
|
begin
|
|
FileInterface := Create;
|
|
try
|
|
FileInterface.Initialize;
|
|
_FileInterfaces.Append(FileInterface);
|
|
except
|
|
FileInterface.Free;
|
|
end;
|
|
FileInterface.FID := ID;
|
|
end;
|
|
{--------}
|
|
class procedure TffFileInterface.Unregister;
|
|
var
|
|
wInx : Integer;
|
|
begin
|
|
if _FileInterfaces = nil then
|
|
Exit;
|
|
{ Free every instance of this class. }
|
|
for wInx := Pred(_FileInterfaces.Count) downto 0 do
|
|
with TffFileInterface(_FileInterfaces.Pointers[wInx]) do
|
|
if (ClassType = Self) then begin
|
|
Free;
|
|
_FileInterfaces.RemoveAt(wInx);
|
|
end;
|
|
end;
|
|
{--------}
|
|
class function TffFileInterface.FindInterface(const FileName : string) : TffFileInterface;
|
|
var
|
|
wInx : Integer;
|
|
begin
|
|
Result := nil;
|
|
for wInx := 0 to Pred(_FileInterfaces.Count) do
|
|
with TffFileInterface(_FileInterfaces.Pointers[wInx]) do
|
|
if Handles(FileName) then begin
|
|
Result := _FileInterfaces.Pointers[wInx];
|
|
Break;
|
|
end;
|
|
end;
|
|
{--------}
|
|
procedure TffFileInterface.Initialize;
|
|
begin
|
|
{ Descendant classes may override this method for custom initialization. }
|
|
end;
|
|
{====================================================================}
|
|
|
|
{===TffFileBlock=====================================================}
|
|
constructor TffFileBlock.Create(BufMgr : TffBufferManager;
|
|
FileInfo : PffFileInfo;
|
|
TI : PffTransInfo;
|
|
const BlockNum : TffWord32);
|
|
begin
|
|
inherited Create;
|
|
FBufMgr := BufMgr;
|
|
FBlock := FBufMgr.GetBlock(FileInfo, BlockNum, TI, ffc_ReadOnly, FRelMethod);
|
|
FFileInfo := FileInfo;
|
|
FTI := TI;
|
|
FBlockNum := BlockNum;
|
|
end;
|
|
{--------}
|
|
destructor TffFileBlock.Destroy;
|
|
begin
|
|
try
|
|
if Assigned(FRelMethod) and Assigned(FBlock) then
|
|
FRelMethod(FBlock);
|
|
finally
|
|
inherited;
|
|
end;
|
|
end;
|
|
{--------}
|
|
procedure TffFileBlock.BeginUpdate;
|
|
begin
|
|
{ Do nothing }
|
|
end;
|
|
{--------}
|
|
procedure TffFileBlock.EndUpdate;
|
|
begin
|
|
{ Do nothing }
|
|
end;
|
|
{--------}
|
|
procedure TffFileBlock.DoReportError(const ErrCode : Integer;
|
|
args : array of const);
|
|
begin
|
|
if Assigned(FOnReportError) then
|
|
FOnReportError(Self, ErrCode,
|
|
Format(rcErrStr[ErrCode], args));
|
|
end;
|
|
{--------}
|
|
procedure TffFileBlock.DoReportFix(const ErrCode : Integer;
|
|
args : array of const);
|
|
begin
|
|
if Assigned(FOnReportError) then
|
|
FOnReportFix(Self, ErrCode,
|
|
Format(rcFixStr[ErrCode], args));
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetBlockNum : TffWord32;
|
|
begin
|
|
Result := FBlockNum;
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetBlockType : TffBlockType;
|
|
begin
|
|
case PffBlockCommonHeader(FBlock)^.bchSignature of
|
|
ffc_SigHeaderBlock : Result := btFileHeader;
|
|
ffc_SigDataBlock : Result := btData;
|
|
ffc_SigIndexBlock :
|
|
begin
|
|
if PffBlockHeaderIndex(FBlock)^.bhiBlockType = 0 then
|
|
Result := btIndexHeader
|
|
else
|
|
Result := btIndex;
|
|
end;
|
|
ffc_SigBLOBBlock : Result := btBLOB;
|
|
ffc_SigStreamBlock : Result := btStream;
|
|
ffc_SigFreeBlock : Result := btFree;
|
|
else
|
|
Result := btUnknown;
|
|
end; { case }
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetDataCell(const Row, Column : Integer) : string;
|
|
begin
|
|
Result := '';
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetDataColCaption(const Index : Integer) : string;
|
|
begin
|
|
Result := '';
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetDataColCount : Integer;
|
|
begin
|
|
Result := 0;
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetDataColWidth(const Index : Integer) : Integer;
|
|
begin
|
|
Result := 0;
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetDataRowCount : Integer;
|
|
begin
|
|
Result := 0;
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetLSN : TffWord32;
|
|
begin
|
|
Result := PffBlockCommonHeader(FBlock)^.bchLSN;
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetNextBlock : TffWord32;
|
|
begin
|
|
Result := PffBlockCommonHeader(FBlock)^.bchNextBlock;
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetOnGetInfo : TffGetInfoEvent;
|
|
begin
|
|
Result := FOnGetInfo;
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetOnReportError : TffReportErrorEvent;
|
|
begin
|
|
Result := FOnReportError;
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetOnReportFix : TffReportFixEvent;
|
|
begin
|
|
Result := FOnReportFix;
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetRawData : PffBlock;
|
|
begin
|
|
Result := FBlock;
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetSignature : Longint;
|
|
begin
|
|
Result := PffBlockCommonHeader(FBlock)^.bchSignature;
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetThisBlock : TffWord32;
|
|
begin
|
|
Result := PffBlockCommonHeader(FBlock)^.bchThisBlock;
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetPropertyCell(const Row, Column : Integer) : string;
|
|
begin
|
|
if Column > Pred(ciFileBlockColumns) then
|
|
raise Exception.CreateFmt
|
|
('Cannot ask for cell in column %d when there are only %d columns in the view',
|
|
[Column, ciFileBlockColumns]);
|
|
|
|
case Row of
|
|
0 : if Column = 0 then
|
|
Result := 'Block type'
|
|
else
|
|
Result := MapBlockTypeToStr(GetBlockType);
|
|
1 : if Column = 0 then
|
|
Result := 'Signature'
|
|
else
|
|
Result := MapSigToStr(GetSignature);
|
|
2 : if Column = 0 then
|
|
Result := 'This block'
|
|
else
|
|
Result := IntToStr(GetThisBlock);
|
|
3 : if Column = 0 then
|
|
Result := 'Next block'
|
|
else
|
|
Result := IntToStr(GetNextBlock);
|
|
4 : if Column = 0 then
|
|
Result := 'LSN'
|
|
else
|
|
Result := IntToStr(GetLSN);
|
|
else
|
|
raise Exception.CreateFmt
|
|
('Cannot ask for cell in row %d when there are only %d rows in the view',
|
|
[Row, ciFileBlockRows]);
|
|
end; { case }
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetPropertyColCaption(const Index : Integer) : string;
|
|
begin
|
|
case Index of
|
|
0 : Result := 'Property';
|
|
1 : Result := 'Value';
|
|
else
|
|
raise Exception.CreateFmt
|
|
('Cannot ask for caption %d when there are only %d columns in the view',
|
|
[Index, ciFileBlockColumns]);
|
|
end; { case }
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetPropertyColCount : Integer;
|
|
begin
|
|
Result := ciFileBlockColumns;
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetPropertyColWidth(const Index : Integer) : Integer;
|
|
begin
|
|
case Index of
|
|
0 : Result := 150;
|
|
1 : Result := 150;
|
|
else
|
|
raise Exception.CreateFmt
|
|
('Cannot ask for width %d when there are only %d columns in the view',
|
|
[Index, ciFileBlockColumns]);
|
|
end; { case }
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.GetPropertyRowCount : Integer;
|
|
begin
|
|
Result := ciFileBlockRows;
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.MapBlockTypeToStr(const BlockType : TffBlockType) : string;
|
|
begin
|
|
case BlockType of
|
|
btUnknown : Result := 'Unknown';
|
|
btFileHeader : Result := 'File header';
|
|
btIndexHeader : Result := 'Index header';
|
|
btData : Result := 'Data';
|
|
btIndex : Result := 'Index';
|
|
btBLOB : Result := 'BLOB';
|
|
btStream : Result := 'Stream';
|
|
btFree : Result := 'Free';
|
|
end; { case }
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.MapFlagsToStr(const Flags : Byte) : string;
|
|
var
|
|
FlagSet : Boolean;
|
|
begin
|
|
FlagSet := False;
|
|
Result := IntToStr(Flags);
|
|
if Flags > 0 then begin
|
|
Result := Result + ' [';
|
|
if (Flags and ffc_InxFlagAllowDups) <> 0 then begin
|
|
Result := Result + ' Allow dups';
|
|
FlagSet := True;
|
|
end;
|
|
|
|
if (Flags and ffc_InxFlagKeysAreRefs) <> 0 then begin
|
|
if FlagSet then
|
|
Result := Result + ', ';
|
|
Result := Result + 'Keys are refs'
|
|
end; { if }
|
|
Result := Result + ']';
|
|
end; { if }
|
|
end;
|
|
{--------}
|
|
function TffFileBlock.MapSigToStr(const Signature : Longint) : string;
|
|
begin
|
|
Result := Mirror(LongintToChars(Signature)) + ' (' +
|
|
LongintToHex(Signature) + ')';
|
|
end;
|
|
{--------}
|
|
procedure TffFileBlock.Repair;
|
|
begin
|
|
try
|
|
VerifyRepair(True);
|
|
except
|
|
on E:Exception do
|
|
ShowMessage(E.Message);
|
|
end;
|
|
end;
|
|
{--------}
|
|
procedure TffFileBlock.SetLSN(const Value : TffWord32);
|
|
begin
|
|
PffBlockCommonHeader(FBlock)^.bchLSN := Value;
|
|
end;
|
|
{--------}
|
|
procedure TffFileBlock.SetNextBlock(const Value : TffWord32);
|
|
begin
|
|
PffBlockCommonHeader(FBlock)^.bchNextBlock := Value;
|
|
end;
|
|
{--------}
|
|
procedure TffFileBlock.SetOnGetInfo(Value : TffGetInfoEvent);
|
|
begin
|
|
FOnGetInfo := Value;
|
|
end;
|
|
{--------}
|
|
procedure TffFileBlock.SetOnReportError(Value : TffReportErrorEvent);
|
|
begin
|
|
FOnReportError := Value;
|
|
end;
|
|
{--------}
|
|
procedure TffFileBlock.SetOnReportFix(Value : TffReportFixEvent);
|
|
begin
|
|
FOnReportFix := Value;
|
|
end;
|
|
{--------}
|
|
procedure TffFileBlock.SetSignature(const Value : Longint);
|
|
begin
|
|
PffBlockCommonHeader(FBlock)^.bchSignature := Value;
|
|
end;
|
|
{--------}
|
|
procedure TffFileBlock.SetThisBlock(const Value : TffWord32);
|
|
begin
|
|
PffBlockCommonHeader(FBlock)^.bchThisBlock := Value;
|
|
end;
|
|
{--------}
|
|
procedure TffFileBlock.Verify;
|
|
begin
|
|
VerifyRepair(False);
|
|
end;
|
|
{--------}
|
|
procedure TffFileBlock.VerifyRepair(const Repair : Boolean);
|
|
var
|
|
Block : PffBlock;
|
|
RelMethod : TffReleaseMethod;
|
|
Modified : Boolean;
|
|
begin
|
|
Modified := False;
|
|
try
|
|
{ Verify the block type. }
|
|
if BlockType = btUnknown then begin
|
|
DoReportError(rciUnknownBlockType,
|
|
[PffBlockCommonHeader(FBlock)^.bchSignature]);
|
|
if Repair then begin
|
|
BeginUpdate;
|
|
Modified := True;
|
|
{ Mark this as a free block. }
|
|
PffBlockCommonHeader(FBlock)^.bchSignature := ffc_SigFreeBlock;
|
|
DoReportFix(rciUnknownBlockType,
|
|
[BlockNum]);
|
|
end;
|
|
end;
|
|
|
|
{ Can't do much with the LSN. }
|
|
|
|
{ Verify the next block is a valid block. }
|
|
if NextBlock <> ffc_W32NoValue then
|
|
try
|
|
Block := FBufMgr.GetBlock(FFileInfo, NextBlock, FTI, ffc_ReadOnly,
|
|
RelMethod);
|
|
RelMethod(Block);
|
|
except
|
|
DoReportError(rciInvalidBlockRefNext, [NextBlock]);
|
|
end;
|
|
|
|
{ Verify ThisBlock matches this block number. }
|
|
if ThisBlock <> FBlockNum then begin
|
|
DoReportError(rciInvalidThisBlock, [FBlockNum, ThisBlock]);
|
|
if Repair then begin
|
|
BeginUpdate;
|
|
Modified := True;
|
|
ThisBlock := FBlockNum;
|
|
DoReportFix(rciInvalidThisBlock, [FBlockNum]);
|
|
end;
|
|
end;
|
|
finally
|
|
if Modified then
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
{====================================================================}
|
|
|
|
|
|
initialization
|
|
_FileInterfaces := TffPointerList.Create;
|
|
|
|
finalization
|
|
|
|
_FileInterfaces.Free;
|
|
{ Assumption: Units registering comparator classes will also unregister
|
|
them. }
|
|
_FileInterfaces := nil;
|
|
|
|
end.
|