You've already forked lazarus-ccr
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3582 8e941d3f-bd1b-0410-a28a-d453659cc2b4
5217 lines
186 KiB
ObjectPascal
5217 lines
186 KiB
ObjectPascal
unit beBIFFGrid;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, Controls, Grids, fpspreadsheet;
|
|
|
|
type
|
|
TBIFFBuffer = array of byte;
|
|
|
|
TBIFFDetailsEvent = procedure(Sender: TObject; ADetails: TStrings) of object;
|
|
|
|
TBIFFGrid = class(TStringGrid)
|
|
private
|
|
FRecType: Word;
|
|
FBuffer: TBIFFBuffer;
|
|
FBufferIndex: LongWord;
|
|
FFormat: TsSpreadsheetFormat;
|
|
FCurrRow: Integer;
|
|
FDetails: TStrings;
|
|
FOnDetails: TBIFFDetailsEvent;
|
|
function GetStringType: String;
|
|
|
|
procedure ShowBackup;
|
|
procedure ShowBlankCell;
|
|
procedure ShowBOF;
|
|
procedure ShowBookBool;
|
|
procedure ShowBottomMargin;
|
|
procedure ShowCalcCount;
|
|
procedure ShowCalcMode;
|
|
procedure ShowCellAddress;
|
|
procedure ShowCellAddressRange;
|
|
procedure ShowClrtClient;
|
|
procedure ShowCodePage;
|
|
procedure ShowColInfo;
|
|
procedure ShowColWidth;
|
|
procedure ShowCountry;
|
|
procedure ShowDateMode;
|
|
procedure ShowDBCell;
|
|
procedure ShowDefColWidth;
|
|
procedure ShowDefinedName;
|
|
procedure ShowDefRowHeight;
|
|
procedure ShowDelta;
|
|
procedure ShowDimensions;
|
|
procedure ShowDSF;
|
|
procedure ShowEOF;
|
|
procedure ShowExcel9File;
|
|
procedure ShowExternalBook;
|
|
procedure ShowExternCount;
|
|
procedure ShowExternSheet;
|
|
procedure ShowFileSharing;
|
|
procedure ShowFnGroupCount;
|
|
procedure ShowFont;
|
|
procedure ShowFontColor;
|
|
procedure ShowFooter;
|
|
procedure ShowFormat;
|
|
procedure ShowFormatCount;
|
|
procedure ShowFormula;
|
|
procedure ShowFormulaTokens(ATokenBytes: Integer);
|
|
procedure ShowGCW;
|
|
procedure ShowHeader;
|
|
procedure ShowHideObj;
|
|
procedure ShowInteger;
|
|
procedure ShowInterfaceEnd;
|
|
procedure ShowInterfaceHdr;
|
|
procedure ShowIteration;
|
|
procedure ShowIXFE;
|
|
procedure ShowLabelCell;
|
|
procedure ShowLabelSSTCell;
|
|
procedure ShowLeftMargin;
|
|
procedure ShowMergedCells;
|
|
procedure ShowMMS;
|
|
procedure ShowMulBlank;
|
|
procedure ShowMulRK;
|
|
procedure ShowNote;
|
|
procedure ShowNumberCell;
|
|
procedure ShowObj;
|
|
procedure ShowPageSetup;
|
|
procedure ShowPalette;
|
|
procedure ShowPane;
|
|
procedure ShowPassword;
|
|
procedure ShowPrecision;
|
|
procedure ShowPrintGridLines;
|
|
procedure ShowPrintHeaders;
|
|
procedure ShowProt4Rev;
|
|
procedure ShowProt4RevPass;
|
|
procedure ShowProtect;
|
|
procedure ShowRecalc;
|
|
procedure ShowRefMode;
|
|
procedure ShowRefreshAll;
|
|
procedure ShowRightMargin;
|
|
procedure ShowRK;
|
|
procedure ShowRow;
|
|
procedure ShowSelection;
|
|
procedure ShowSharedFormula;
|
|
procedure ShowSheet;
|
|
procedure ShowSheetPR;
|
|
procedure ShowSST;
|
|
procedure ShowStandardWidth;
|
|
procedure ShowString;
|
|
procedure ShowStyle;
|
|
procedure ShowStyleExt;
|
|
procedure ShowTabID;
|
|
procedure ShowTopMargin;
|
|
procedure ShowWindow1;
|
|
procedure ShowWindow2;
|
|
procedure ShowWindowProtect;
|
|
procedure ShowWriteAccess;
|
|
procedure ShowWriteProt;
|
|
procedure ShowXF;
|
|
procedure ShowXFCRC;
|
|
procedure ShowXFEXT;
|
|
|
|
protected
|
|
procedure Click; override;
|
|
procedure DoExtractDetails;
|
|
function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; override;
|
|
function DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; override;
|
|
procedure ExtractString(ABufIndex: Integer; ALenBytes: Byte; AUnicode: Boolean;
|
|
out AString: String; out ANumBytes: Integer; IgnoreCompressedFlag: Boolean = false);
|
|
procedure PopulateGrid;
|
|
procedure ShowInRow(var ARow: Integer; var AOffs: LongWord; ASize: Word; AValue,ADescr: String);
|
|
procedure ShowRowColData(var ABufIndex: LongWord);
|
|
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure SetRecordType(ARecType: Word; ABuffer: TBIFFBuffer; AFormat: TsSpreadsheetFormat);
|
|
|
|
published
|
|
property OnDetails: TBIFFDetailsEvent read FOnDetails write FOnDetails;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
StrUtils, Math,
|
|
fpsutils,
|
|
beBIFFUtils;
|
|
|
|
const
|
|
ABS_REL: array[boolean] of string = ('abs', 'rel');
|
|
|
|
constructor TBIFFGrid.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
ColCount := 4;
|
|
FixedCols := 0;
|
|
RowCount := 2;
|
|
Cells[0, 0] := 'Offset';
|
|
Cells[1, 0] := 'Size';
|
|
Cells[2, 0] := 'Value';
|
|
Cells[3, 0] := 'Description';
|
|
ColWidths[0] := 60;
|
|
ColWidths[1] := 60;
|
|
ColWidths[2] := 120;
|
|
ColWidths[3] := 350;
|
|
Options := Options + [goThumbTracking, goColSizing, goTruncCellHints, goCellHints] - [goVertLine];
|
|
FDetails := TStringList.Create;
|
|
end;
|
|
|
|
|
|
destructor TBIFFGrid.Destroy;
|
|
begin
|
|
FDetails.Free;
|
|
inherited;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.Click;
|
|
begin
|
|
inherited;
|
|
if (FBuffer <> nil) then
|
|
DoExtractDetails;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.DoExtractDetails;
|
|
begin
|
|
if Assigned(FOnDetails) then begin
|
|
PopulateGrid;
|
|
FOnDetails(self, FDetails);
|
|
end;
|
|
end;
|
|
|
|
function TBIFFGrid.DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint
|
|
): Boolean;
|
|
begin
|
|
Result := inherited;
|
|
Click;
|
|
end;
|
|
|
|
function TBIFFGrid.DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint
|
|
): Boolean;
|
|
begin
|
|
Result := inherited;
|
|
Click;
|
|
end;
|
|
|
|
procedure TBIFFGrid.ExtractString(ABufIndex: Integer; ALenBytes: Byte; AUnicode: Boolean;
|
|
out AString: String; out ANumBytes: Integer; IgnoreCompressedFlag: Boolean = false);
|
|
var
|
|
ls: Integer;
|
|
sa: ansiString;
|
|
sw: WideString;
|
|
w: Word;
|
|
optn: Byte;
|
|
begin
|
|
if Length(FBuffer) = 0 then begin
|
|
AString := '';
|
|
ANumBytes := 0;
|
|
exit;
|
|
end;
|
|
if ALenBytes = 1 then
|
|
ls := FBuffer[ABufIndex]
|
|
else begin
|
|
Move(FBuffer[ABufIndex], w, 2);
|
|
ls := WordLEToN(w);
|
|
end;
|
|
if AUnicode then begin
|
|
optn := FBuffer[ABufIndex + ALenBytes];
|
|
if (optn and $01 = 0) and (not IgnoreCompressedFlag)
|
|
then begin // compressed --> 1 byte per character
|
|
SetLength(sa, ls);
|
|
ANumbytes := ls*SizeOf(AnsiChar) + ALenBytes + 1;
|
|
Move(FBuffer[ABufIndex + ALenBytes + 1], sa[1], ls*SizeOf(AnsiChar));
|
|
AString := sa;
|
|
end else begin
|
|
SetLength(sw, ls);
|
|
ANumBytes := ls*SizeOf(WideChar) + ALenBytes + 1;
|
|
Move(FBuffer[ABufIndex + ALenBytes + 1], sw[1], ls*SizeOf(WideChar));
|
|
AString := UTF8Encode(WideStringLEToN(sw));
|
|
end;
|
|
end else begin
|
|
SetLength(sa, ls);
|
|
ANumBytes := ls*SizeOf(AnsiChar) + ALenBytes;
|
|
Move(FBuffer[ABufIndex + ALenBytes], sa[1], ls*SizeOf(AnsiChar));
|
|
AString := AnsiToUTF8(sa);
|
|
end;
|
|
end;
|
|
|
|
|
|
function TBIFFGrid.GetStringType: String;
|
|
begin
|
|
case FFormat of
|
|
sfExcel2: Result := 'Byte';
|
|
sfExcel5: Result := 'Byte';
|
|
sfExcel8: Result := 'Unicode';
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.PopulateGrid;
|
|
begin
|
|
FBufferIndex := 0;
|
|
FCurrRow := FixedRows;
|
|
FDetails.Clear;
|
|
case FRecType of
|
|
$0000, $0200:
|
|
ShowDimensions;
|
|
$0001, $0201:
|
|
ShowBlankCell;
|
|
$0002:
|
|
ShowInteger;
|
|
$0003, $0203:
|
|
ShowNumberCell;
|
|
$0004, $0204:
|
|
ShowLabelCell;
|
|
$0006:
|
|
ShowFormula;
|
|
$0007, $0207:
|
|
ShowString;
|
|
$0008, $0208:
|
|
ShowRow;
|
|
$0009, $0209, $0409, $0809:
|
|
ShowBOF;
|
|
$000A:
|
|
ShowEOF;
|
|
$000C:
|
|
ShowCalcCount;
|
|
$000D:
|
|
ShowCalcMode;
|
|
$000E:
|
|
ShowPrecision;
|
|
$000F:
|
|
ShowRefMode;
|
|
$0010:
|
|
ShowDelta;
|
|
$0011:
|
|
ShowIteration;
|
|
$0012:
|
|
ShowProtect;
|
|
$0013:
|
|
ShowPassword;
|
|
$0014:
|
|
ShowHeader;
|
|
$0015:
|
|
ShowFooter;
|
|
$0016:
|
|
ShowExternCount;
|
|
$0017:
|
|
ShowExternSheet;
|
|
$0018, $0218:
|
|
ShowDefinedName;
|
|
$0019:
|
|
ShowWindowProtect;
|
|
$001C:
|
|
ShowNote;
|
|
$001D:
|
|
ShowSelection;
|
|
$001E, $041E:
|
|
ShowFormat;
|
|
$001F:
|
|
ShowFormatCount;
|
|
$0022:
|
|
ShowDateMode;
|
|
$0024:
|
|
ShowColWidth;
|
|
$0025, $0225:
|
|
ShowDefRowHeight;
|
|
$0026:
|
|
ShowLeftMargin;
|
|
$0027:
|
|
ShowRightMargin;
|
|
$0028:
|
|
ShowTopMargin;
|
|
$0029:
|
|
ShowBottomMargin;
|
|
$002A:
|
|
ShowPrintHeaders;
|
|
$002B:
|
|
ShowPrintGridLines;
|
|
$0031:
|
|
ShowFont;
|
|
$003D:
|
|
ShowWindow1;
|
|
$003E, $023E:
|
|
ShowWindow2;
|
|
$0040:
|
|
ShowBackup;
|
|
$0041:
|
|
ShowPane;
|
|
$0042:
|
|
ShowCodePage;
|
|
$0043:
|
|
ShowXF;
|
|
$0044:
|
|
ShowIXFE;
|
|
$0045:
|
|
ShowFontColor;
|
|
$0055:
|
|
ShowDefColWidth;
|
|
$005B:
|
|
ShowFileSharing;
|
|
$005C:
|
|
ShowWriteAccess;
|
|
$005D:
|
|
ShowObj;
|
|
$005F:
|
|
ShowRecalc;
|
|
$007D:
|
|
ShowColInfo;
|
|
$0081:
|
|
ShowSheetPR;
|
|
$0085:
|
|
ShowSheet;
|
|
$0086:
|
|
ShowWriteProt;
|
|
$008C:
|
|
ShowCountry;
|
|
$008D:
|
|
ShowHideObj;
|
|
$0092:
|
|
ShowPalette;
|
|
$099:
|
|
ShowStandardWidth;
|
|
$00A1:
|
|
ShowPageSetup;
|
|
$00AB:
|
|
ShowGCW;
|
|
$00C1:
|
|
ShowMMS;
|
|
$009C:
|
|
ShowFnGroupCount;
|
|
$00BE:
|
|
ShowMulBlank;
|
|
$00BD:
|
|
ShowMulRK;
|
|
$00D7:
|
|
ShowDBCell;
|
|
$00DA:
|
|
ShowBookBool;
|
|
$00E0:
|
|
ShowXF;
|
|
$00E1:
|
|
ShowInterfaceHdr;
|
|
$00E2:
|
|
ShowInterfaceEnd;
|
|
$00E5:
|
|
ShowMergedCells;
|
|
$00FC:
|
|
ShowSST;
|
|
$00FD:
|
|
ShowLabelSSTCell;
|
|
$013D:
|
|
ShowTabID;
|
|
$0161:
|
|
ShowDSF;
|
|
$01AE:
|
|
ShowExternalBook;
|
|
$01AF:
|
|
ShowProt4Rev;
|
|
$01B7:
|
|
ShowRefreshAll;
|
|
$01BC:
|
|
ShowProt4RevPass;
|
|
$01C0:
|
|
ShowExcel9File;
|
|
$027E:
|
|
ShowRK;
|
|
$0293:
|
|
ShowStyle;
|
|
$04BC:
|
|
ShowSharedFormula;
|
|
$087C:
|
|
ShowXFCRC;
|
|
$087D:
|
|
ShowXFEXT;
|
|
$0892:
|
|
ShowStyleExt;
|
|
$105C:
|
|
ShowClrtClient;
|
|
else
|
|
RowCount := 2;
|
|
Rows[1].Clear;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.SetRecordType(ARecType: Word; ABuffer: TBIFFBuffer;
|
|
AFormat: TsSpreadsheetFormat);
|
|
begin
|
|
FFormat := AFormat;
|
|
FRecType := ARecType;
|
|
SetLength(FBuffer, Length(ABuffer));
|
|
if Length(FBuffer) > 0 then
|
|
Move(ABuffer[0], FBuffer[0], Length(FBuffer));
|
|
PopulateGrid;
|
|
if Assigned(FOnDetails) then FOnDetails(self, FDetails);
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowBackup;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Save backup copy of workbook:'#13);
|
|
if w = 0
|
|
then FDetails.Add('0 = no backup')
|
|
else FDetails.Add('1 = backup copy is saved when workbook is saved');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.4x', [w]),
|
|
'Save backup copy of workbook');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowBlankCell;
|
|
var
|
|
numBytes: Integer;
|
|
b: Byte = 0;
|
|
w: Word = 0;
|
|
dbl: Double;
|
|
begin
|
|
RowCount := IfThen(FFormat = sfExcel2, FixedRows + 5, FixedRows + 3);
|
|
// Offset 0: Row & Offset 2: Column
|
|
ShowRowColData(FBufferIndex);
|
|
|
|
// Offset 4: Cell attributes (BIFF2) or XF record index (> BIFF2)
|
|
if FFormat = sfExcel2 then begin
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Cell protection and XF index:'#13);
|
|
FDetails.Add(Format('Bits 5-0 = %d: XF Index', [b and $3F]));
|
|
case b and $40 of
|
|
0: FDetails.Add('Bit 6 = 0: Cell is NOT locked.');
|
|
1: FDetails.Add('Bit 6 = 1: Cell is locked.');
|
|
end;
|
|
case b and $80 of
|
|
0: FDetails.Add('Bit 7 = 0: Formula is NOT hidden.');
|
|
1: FDetails.Add('Bit 7 = 1: Formula is hidden.');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.2x)', [b, b]),
|
|
'Cell protection and XF index');
|
|
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Indexes to format and font records:'#13);
|
|
FDetails.Add(Format('Bits 5-0 = %d: Index to FORMAT record', [b and $3f]));
|
|
FDetails.Add(Format('Bits 7-6 = %d: Index to FONT record', [(b and $C0) shr 6]));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.2x)', [b, b]),
|
|
'Indexes of format and font records');
|
|
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Cell style:'#13);
|
|
case b and $07 of
|
|
0: FDetails.Add('Bits 2-0 = 0: Horizontal alignment is GENERAL');
|
|
1: FDetails.Add('Bits 2-0 = 1: Horizontal alignment is LEFT');
|
|
2: FDetails.Add('Bits 2-0 = 2: Horizontal alignment is CENTERED');
|
|
3: FDetails.Add('Bits 2-0 = 3: Horizontal alignment is RIGHT');
|
|
4: FDetails.Add('Bits 2-0 = 4: Horizontal alignment is FILLED');
|
|
end;
|
|
if b and $08 = 0
|
|
then FDetails.Add('Bit 3 = 0: Cell has NO left border')
|
|
else FDetails.Add('Bit 3 = 1: Cell has left black border');
|
|
if b and $10 = 0
|
|
then FDetails.Add('Bit 4 = 0: Cell has NO right border')
|
|
else FDetails.Add('Bit 4 = 1: Cell has right black border');
|
|
if b and $20 = 0
|
|
then FDetails.Add('Bit 5 = 0: Cell has NO top border')
|
|
else FDetails.Add('Bit 5 = 1: Cell has top black border');
|
|
if b and $40 = 0
|
|
then FDetails.Add('Bit 6 = 0: Cell has NO bottom border')
|
|
else FDetails.Add('Bit 6 = 1: Cell has bottom black border');
|
|
if b and $80 = 0
|
|
then FDetails.Add('Bit 7 = 0: Cell has NO shaded background')
|
|
else FDetails.Add('Bit 7 = 1: Cell has shaded background');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('%d ($%.2x)', [b,b]),
|
|
'Cell style');
|
|
end else
|
|
begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrROw, FBufferIndex, numBytes, Format('%d ($%.4x)', [w, w]),
|
|
'Index of XF record');
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowBOF;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
s: String;
|
|
begin
|
|
case FFormat of
|
|
sfExcel2: RowCount := FixedRows + 2;
|
|
{ //Excel3 & 4 not supported by fpspreadsheet
|
|
sfExcel3, sfExcel4: RowCount := FixedRows + 3;
|
|
}
|
|
sfExcel5: RowCount := FixedRows + 4;
|
|
sfExcel8: RowCount := FixedRows + 6;
|
|
end;
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('BIFF version:'#13);
|
|
case FRecType of
|
|
$0009,
|
|
$0209,
|
|
$0409: FDetails.Add('not used');
|
|
$0809: case FFormat of
|
|
sfExcel5: FDetails.Add('$0500 = BIFF5');
|
|
sfExcel8: FDetails.Add('$0600 = BIFF8');
|
|
end;
|
|
else case w of
|
|
$0000: FDetails.Add('$0000 = BIFF5');
|
|
$0200: FDetails.Add('$0200 = BIFF2');
|
|
$0300: FDetails.Add('$0300 = BIFF3');
|
|
$0400: FDetails.Add('$0400 = BIFF4');
|
|
$0500: FDetails.Add('$0500 = BIFF5');
|
|
$0600: FDetails.Add('$0600 = BIFF8');
|
|
end;
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.4x', [w]),
|
|
'BIFF version');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
s := '$0010=Sheet, $0020=Chart, $0040=Macro sheet';
|
|
if FFormat > sfExcel2 then
|
|
s := '$0005=WB globals, $0006=VB module, ' + s + ', $0100=Workspace';
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Type of data:'#13);
|
|
FDetails.Add(Format('$%.4x = %s', [w, BofName(w)]));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.4x', [w]),
|
|
Format('Type of data (%s)', [s]));
|
|
|
|
if FFormat > sfExcel2 then begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
{ Excel3/4 not supported in fpSpreadsheet
|
|
if FFormat in [sfExcel3, sfExcel4] then
|
|
ShowInRow(FCurrRow, FBUfferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'not used')
|
|
else}
|
|
begin
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Build identifier (must not be zero)');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Build year (must not be zero)');
|
|
end;
|
|
end;
|
|
|
|
if FFormat = sfExcel8 then begin
|
|
numBytes := 4;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'File history flags');
|
|
|
|
numBytes :=4;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Lowest Excel version that can read all records of this file');
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowBookBool;
|
|
var
|
|
numbytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Some properties assosciated with notebook:'#13);
|
|
if w and $0001 = 0
|
|
then FDetails.Add('Bit 0 = 0: External link values are saved.')
|
|
else FDetails.Add('Bit 0 = 1: External link values are NOT saved.');
|
|
FDetails.Add('Bit 1: to be ignored');
|
|
if w and $0004 = 0
|
|
then FDetails.Add('Bit 2 = 0: Workbook does not have a mail envelope')
|
|
else FDetails.Add('Bit 2 = 1: Workbook has a mail envelope');
|
|
if w and $0008 = 0
|
|
then FDetails.Add('Bit 3 = 0: Mail envelope is NOT visible.')
|
|
else FDetails.Add('Bit 3 = 1: Mail envelope is visible.');
|
|
if w and $0010 = 0
|
|
then FDetails.Add('Bit 4 = 0: Mail envelope has NOT been initialized.')
|
|
else FDetails.Add('Bit 4 = 1: Mail envelope has been initialized.');
|
|
case (w and $0060) shr 5 of
|
|
0: FDetails.Add('Bits 5-6 (Update external links) = 0: Prompt user to update');
|
|
1: FDetails.Add('Bits 5-6 (Update external linls) = 1: Do not update, and do not prompt user.');
|
|
2: FDetails.Add('Bits 5-6 (Update external links) = 2: Silently update external links.');
|
|
end;
|
|
FDetails.Add('Bit 7: undefined, must be ignored');
|
|
if w and $0100 = 0
|
|
then FDetails.Add('Bit 8 = 0: Do not hide borders of tables that do not contain the active cell')
|
|
else FDetails.Add('Bit 8 = 1: Hide borders of tables that do not contain the active cell');
|
|
FDetails.Add('Bits 9-15: MUST BE zero, MUST be ignored');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.4x', [w]),
|
|
'Specifies some properties assosciated with a workbook');
|
|
end;
|
|
|
|
procedure TBIFFGrid.ShowBottomMargin;
|
|
var
|
|
numBytes: Integer;
|
|
dbl: Double;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 8;
|
|
Move(FBuffer[FBufferIndex], dbl, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, FloatToStr(dbl),
|
|
'Bottom page margin in inches (IEEE 754 floating-point value, 64-bit double precision)');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowCalcCount;
|
|
var
|
|
numBytes: Word;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'Maximum number of iterations allowed in circular references');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowCalcMode;
|
|
var
|
|
numBytes: Word;
|
|
w: word;
|
|
s: String;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if w = $FFFF then
|
|
s := '–1 = automatically except for multiple table operations'
|
|
else if w = 0 then
|
|
s := '0 = manually'
|
|
else if w = 1 then
|
|
s := '1 = automatically (default)';
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.4x)', [w, w]), s);
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowCellAddress;
|
|
{ Note: The bitmask assignment to relative column/row is reversed in relation
|
|
to OpenOffice documentation in order to match with Excel files. }
|
|
var
|
|
numBytes: Word;
|
|
b: Byte;
|
|
w: Word;
|
|
r,c: Integer;
|
|
s: String;
|
|
begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes); // row --> w
|
|
r := WordLEToN(w);
|
|
if FFormat = sfExcel8 then begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex+2], w, numBytes); // column --w1
|
|
c := WordLEToN(w);
|
|
if FCurrRow = Row then begin
|
|
FDetails.Add('RowIndex information:'#13);
|
|
FDetails.Add(Format('RowIndex = %d (%s)', [r, ABS_REL[c and $4000 <> 0]]));
|
|
end;
|
|
s := Format('%d ($%.4x)', [r, r]);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, s, 'Row index');
|
|
if FCurrRow = Row then begin
|
|
FDetails.Add('ColIndex information:'#13);
|
|
FDetails.Add(Format('Bits 0-13: ColIndex = %d (%s)', [c and $3FFF, ABS_REL[c and $8000 <> 0]]));
|
|
if c and $4000 = 0
|
|
then FDetails.Add('Bit 14=0: absolute column index')
|
|
else FDetails.Add('Bit 14=1: relative column index');
|
|
if c and $8000 = 0
|
|
then FDetails.Add('Bit 15=0: absolute row index')
|
|
else FDetails.Add('Bit 15=1: relative row index');
|
|
end;
|
|
s := Format('%d ($%.4x)', [c, c]);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s, 'Column index');
|
|
end else
|
|
begin
|
|
numbytes := 1;
|
|
Move(FBuffer[FBufferIndex+2], b, numBytes);
|
|
c := b;
|
|
if FCurrRow = Row then begin
|
|
FDetails.Add('RowIndex information:'#13);
|
|
FDetails.Add(Format('Bits 0-13: RowIndex = %d (%s)', [r and $3FFF, ABS_REL[r and $4000 <> 0]]));
|
|
if r and $4000 = 0
|
|
then FDetails.Add('Bit 14=0: absolute column index')
|
|
else FDetails.Add('Bit 14=1: relative column index');
|
|
if r and $8000 = 0
|
|
then FDetails.Add('Bit 15=0: absolute row index')
|
|
else FDetails.Add('Bit 15=1: relative row index');
|
|
end;
|
|
//s := Format('$%.4x (%d, %s)', [r, r and $3FFF, ABS_REL[r and $4000 <> 0]]);
|
|
s := Format('%d ($%.4x)', [r, r]);
|
|
ShowInRow(FCurrRow, FBufferIndex, 2, s, 'Row index');
|
|
if FCurrRow = Row then begin
|
|
FDetails.Add('ColIndex information:'#13);
|
|
FDetails.Add(Format('ColIndex = %d (%s)', [c, ABS_REL[r and $8000 <> 0]]));
|
|
end;
|
|
//s := Format('$%.2x (%d, %s)', [c, c, ABS_REL[r and $8000 <> 0]]);
|
|
s := Format('%d ($%.4x)', [c, c]);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s, 'Column index');
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowCellAddressRange;
|
|
{ Note: The bitmask assignment to relative column/row is reversed in relation
|
|
to OpenOffice documentation in order to match with Excel files. }
|
|
var
|
|
numbytes: Word;
|
|
b: Byte;
|
|
w: Word;
|
|
r, c, r2, c2: Integer;
|
|
s: String;
|
|
begin
|
|
if FFormat = sfExcel8 then begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
r := WordLEToN(w);
|
|
if FCurrRow = Row then begin
|
|
FDetails.Add('RowIndex information:'#13);
|
|
FDetails.Add(Format('RowIndex = %d (%s)', [r, ABS_REL[c and $4000 <> 0]]));
|
|
end;
|
|
s := Format('%d ($%.4x)', [r, r]);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, s, 'First row index');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
r2 := WordLEToN(w);
|
|
if FCurrRow = Row then begin
|
|
FDetails.Add('RowIndex information:'#13);
|
|
FDetails.Add(Format('RowIndex = %d (%s)', [r2, ABS_REL[c and $4000 <> 0]]));
|
|
end;
|
|
s := Format('%d ($%.4x)', [r2, r2]);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, s, 'Last row index');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numBytes); // column
|
|
c := WordLEToN(w);
|
|
Move(FBuffer[FBufferIndex+2], w, numBytes);
|
|
c2 := WordLEToN(w);
|
|
|
|
if FCurrRow = Row then begin
|
|
FDetails.Add('ColIndex information:'#13);
|
|
FDetails.Add(Format('Bits 0-13: ColIndex = %d (%s)', [c and $3FFF, ABS_REL[c and $8000 <> 0]]));
|
|
if c and $4000 = 0
|
|
then FDetails.Add('Bit 14=0: absolute column index')
|
|
else FDetails.Add('Bit 14=1: relative column index');
|
|
if c and $8000 = 0
|
|
then FDetails.Add('Bit 15=0: absolute row index')
|
|
else FDetails.Add('Bit 15=1: relative row index');
|
|
end;
|
|
s := Format('%d ($%.4x)', [c, c]);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s, 'First column index');
|
|
|
|
if FCurrRow = Row then
|
|
begin
|
|
FDetails.Add('ColIndex information:'#13);
|
|
FDetails.Add(Format('Bits 0-13: ColIndex = %d (%s)', [c2 and $3FFF, ABS_REL[c2 and $8000 <> 0]]));
|
|
if c2 and $4000 = 0
|
|
then FDetails.Add('Bit 14=0: absolute column index')
|
|
else FDetails.Add('Bit 14=1: relative column index');
|
|
if c2 and $8000 = 0
|
|
then FDetails.Add('Bit 15=0: absolute row index')
|
|
else FDetails.Add('Bit 15=1: relative row index');
|
|
end;
|
|
s := Format('%d ($%.4x)', [c2, c2]);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s, 'Last column index');
|
|
end
|
|
else
|
|
begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
r := WordLEToN(w);
|
|
Move(FBuffer[FBufferIndex+2], w, numBytes);
|
|
r2 := WordLEToN(w);
|
|
|
|
numbytes := 1;
|
|
c := FBuffer[FBufferIndex+4];
|
|
c2 := FBuffer[FBufferIndex+5];
|
|
|
|
if FCurrRow = Row then
|
|
begin
|
|
FDetails.Add('RowIndex information:'#13);
|
|
FDetails.Add(Format('Bits 0-13: RowIndex = %d (%s)', [r and $3FFF, ABS_REL[r and $4000 <> 0]]));
|
|
if r and $4000 = 0
|
|
then FDetails.Add('Bit 14=0: absolute column index')
|
|
else FDetails.Add('Bit 14=1: relative column index');
|
|
if r and $8000 = 0
|
|
then FDetails.Add('Bit 15=0: absolute row index')
|
|
else FDetails.Add('Bit 15=1: relative row index');
|
|
end;
|
|
s := Format('%d ($%.4x)', [r, r]);
|
|
ShowInRow(FCurrRow, FBufferIndex, 2, s, 'First row index');
|
|
|
|
if FCurrRow = Row then
|
|
begin
|
|
FDetails.Add('RowIndex information:'#13);
|
|
FDetails.Add(Format('Bits 0-13: RowIndex = %d (%s)', [r2 and $3FFF, ABS_REL[r2 and $4000 <> 0]]));
|
|
if r2 and $4000 = 0
|
|
then FDetails.Add('Bit 14=0: absolute column index')
|
|
else FDetails.Add('Bit 14=1: relative column index');
|
|
if r2 and $8000 = 0
|
|
then FDetails.Add('Bit 15=0: absolute row index')
|
|
else FDetails.Add('Bit 15=1: relative row index');
|
|
end;
|
|
s := Format('%d ($%.4x)', [r2, r2]);
|
|
ShowInRow(FCurrRow, FBufferIndex, 2, s, 'Last row index');
|
|
|
|
if FCurrRow = Row then
|
|
begin
|
|
FDetails.Add('ColIndex information:'#13);
|
|
FDetails.Add(Format('ColIndex = %d (%s)', [c, ABS_REL[r and $8000 <> 0]]));
|
|
end;
|
|
s := Format('%d ($%.4x)', [c, c]);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s, 'First column index');
|
|
|
|
if FCurrRow = Row then
|
|
begin
|
|
FDetails.Add('ColIndex information:'#13);
|
|
FDetails.Add(Format('ColIndex = %d (%s)', [c2, ABS_REL[r2 and $8000 <> 0]]));
|
|
end;
|
|
s := Format('%d ($%.4x)', [c2, c2]);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s, 'Last column index');
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowClrtClient;
|
|
var
|
|
w: Word;
|
|
dw: DWord;
|
|
numbytes: Word;
|
|
begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
|
|
RowCount := FixedRows + w + 1;
|
|
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w), 'Number of colors (must be 3)');
|
|
|
|
numBytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numbytes);
|
|
dw := DWordLEToN(dw);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.8x', [dw]),
|
|
'Foreground color (system window text color)');
|
|
Move(FBuffer[FBufferIndex], dw, numbytes);
|
|
dw := DWordLEToN(dw);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.8x', [dw]),
|
|
'Background color (system window color)');
|
|
Move(FBuffer[FBufferIndex], dw, numbytes);
|
|
dw := DWordLEToN(dw);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.8x', [dw]), '???');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowCodePage;
|
|
var
|
|
numBytes: Word;
|
|
w: Word;
|
|
s: String;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
s := CodePageName(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Code page:'#13);
|
|
FDetails.Add(Format('$%.04x = %s', [w, s]));
|
|
end;
|
|
if s <> '' then s := 'Code page identifier (' + s + ')' else s := 'Code page identifier';
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.4x)', [w, w]), s);
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowColInfo;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
if FFormat = sfExcel2 then
|
|
exit;
|
|
|
|
RowCount := FixedRows + 5;
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index of first column in range');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index of last column in range');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d (%f characters)', [w, w/256]),
|
|
'Width of the columns in 1/256 of the width of the zero character, using default font (first FONT record in the file)');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Index to XF record for default column formatting');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Column options:'#13);
|
|
if w and $0001 = 0
|
|
then FDetails.Add('Bit $0001 = 0: Columns are NOT hidden')
|
|
else FDetails.Add('Bit $0001 = 1: Columns are hidden');
|
|
FDetails.Add(Format('Bits $0700 = %d: Outline level of the columns (0 = no outline)', [(w and $0700) shr 8]));
|
|
if w and $1000 = 0
|
|
then FDetails.Add('Bit $1000 = 0: Columns are NOT collapsed')
|
|
else FDetails.Add('Bit $1000 = 1: Columns are collapsed');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(w), 'Option flags');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowColWidth;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
b: Byte;
|
|
begin
|
|
if FFormat <> sfExcel2 then
|
|
exit;
|
|
|
|
RowCount := FixedRows + 3;
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b),
|
|
'Index of first column');
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b),
|
|
'Index of last column');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Width of the columns in 1/256 of the width of the zero character, using default font (first FONT record in the file)');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowCountry;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 2;
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Windows country identifier for UI language of Excel');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Windows country identifier of system regional settings');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowDateMode;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'0 = Base date is 1899-Dec-31, 1 = Base date is 1904-Jan-01');
|
|
end;
|
|
|
|
procedure TBIFFGrid.ShowDBCell;
|
|
var
|
|
i, n: Integer;
|
|
dw: DWord;
|
|
w: Word;
|
|
numBytes: Integer;
|
|
begin
|
|
if FFormat < sfExcel5 then exit;
|
|
|
|
n := (Length(FBuffer) - 4) div 2;
|
|
RowCount := FixedRows + 1 + n;
|
|
|
|
numBytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(DWordLEToN(dw)),
|
|
'Relative offset to first ROW record in the Row Block');
|
|
|
|
numBytes := 2;
|
|
for i:=1 to n do begin
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Relative offsets to calculate stream position of the first cell record in row');
|
|
end;
|
|
end;
|
|
|
|
procedure TBIFFGrid.ShowDefColWidth;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Column width in characters, using the width of the zero character from default '+
|
|
'font (first FONT record in the file) + some extra space.');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowDefinedName;
|
|
var
|
|
numBytes: Integer;
|
|
b: Byte;
|
|
w: Word;
|
|
isFuncMacro: Boolean;
|
|
lenName: Word;
|
|
ansistr: AnsiString;
|
|
widestr: WideString;
|
|
s: String;
|
|
macro: Boolean;
|
|
formulaSize: Word;
|
|
firstTokenBufIdx: Integer;
|
|
token: Byte;
|
|
r,c, r2,c2: Integer;
|
|
begin
|
|
BeginUpdate;
|
|
RowCount := FixedRows + 1000;
|
|
// Brute force simplification because of unknown row count at this point
|
|
// Will be reduced at the end.
|
|
|
|
if FFormat = sfExcel2 then
|
|
begin
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
isFuncMacro := b and $02 <> 0;
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Option flags:'#13);
|
|
if b and $02 = 0 then
|
|
FDetails.Add('Bit $02 = 0: NO function macro or command macro')
|
|
else
|
|
FDetails.Add('Bit $02 = 1: Function macro or command macro');
|
|
if b and $04 = 0 then
|
|
FDetails.Add('Bit $04 = 0: NO Complex function (array formula or user defined)')
|
|
else
|
|
FDetails.Add('Bit $04 = 1: Complex function (array formula or user defined)');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [b]),
|
|
'Option flags');
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
if isFuncMacro then
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b),
|
|
'$01 = Function macro, $02 = Command macro')
|
|
else
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b),
|
|
'unknown');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.4x)', [w, w]),
|
|
'Keyboard shortcut (only for command macro names)');
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b),
|
|
'Length of the name (character count)');
|
|
lenName := b;
|
|
|
|
numbytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBUfferIndex, numBytes, IntToStr(b),
|
|
'Size of the formula data');
|
|
formulaSize := b;
|
|
end
|
|
else
|
|
begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
macro := (w and $0008 <> 0);
|
|
FDetails.Add('Option flags:'#13);
|
|
if w and $0001 = 0
|
|
then FDetails.Add('Bit $0001 (flag name "hidden") = 0: Visible')
|
|
else FDetails.Add('Bit $0001 (flag name "hidden")= 1: Hidden');
|
|
if w and $0002 = 0
|
|
then FDetails.Add('Bit §0002 (flag name "func") = 0: Command macro')
|
|
else FDetails.Add('Bit $0002 (flag name "func") = 1: Function macro');
|
|
if w and $0004 = 0
|
|
then FDetails.Add('Bit $0004 (flag name "vbasic") = 0: Sheet macro')
|
|
else FDetails.Add('Bit $0004 (flag name "vbasic") = 1: Visual basic macro');
|
|
if w and $0008 = 0
|
|
then FDetails.Add('Bit $0008 (flag name "macro") = 0: Standard name')
|
|
else FDetails.Add('Bit $0008 (flag name "macro") = 1: Macro name');
|
|
if w and $0010 = 0
|
|
then FDetails.Add('Bit $0010 (flag name "complex") = 0: Simple formula')
|
|
else FDetails.Add('Bit $0010 (flag name "complex") = 1: Complex formula (array formula or user defined)');
|
|
if w and $0020 = 0
|
|
then FDetails.Add('Bit $0020 (flag name "builtin") = 0: User-defined name')
|
|
else FDetails.Add('Bit $0020 (flag name "builtin") = 1: Built-in name');
|
|
case (w and $0FC0) shr 6 of
|
|
0: if macro then
|
|
FDetails.Add('Bit $0FC0 = 0: --- forbidden value, must be > 0 ---')
|
|
else
|
|
FDetails.Add('Bit $0FC0 (flag name "funcgroup") = 0: not used (requires "macro" = 1)');
|
|
1: FDetails.Add('Bit $0FC0 (flag name "funcgroup") = 1: financial');
|
|
2: FDetails.Add('Bit $0FC0 (flag name "funcgroup") = 2: date & time');
|
|
3: FDetails.Add('Bit $0FC0 (flag name "funcgroup") = 3: math & trig');
|
|
4: FDetails.Add('Bit $0FC0 (flag name "funcgroup") = 4: statistical');
|
|
5: FDetails.Add('Bit $0FC0 (flag name "funcgroup") = 5: lookup & reference');
|
|
6: FDetails.Add('Bit $0FC0 (flag name "funcgroup") = 6: database');
|
|
7: FDetails.Add('Bit $0FC0 (flag name "funcgroup") = 7: text');
|
|
8: FDetails.Add('Bit $0FC0 (flag name "funcgroup") = 8: logical');
|
|
9: FDetails.Add('Bit $0FC0 (flag name "funcgroup") = 9: information');
|
|
10: FDetails.Add('Bit $0FC0 (flag name "funcgroup") = 10: commands');
|
|
11: FDetails.Add('Bit $0FC0 (flag name "funcgroup") = 11: customizing');
|
|
12: FDetails.Add('Bit $0FC0 (flag name "funcgroup") = 12: macro control');
|
|
13: FDetails.Add('Bit $0FC0 (flag name "funcgroup") = 13: dde/external');
|
|
14: FDetails.Add('Bit $0FC0 (flag name "funcgroup") = 14: user defined');
|
|
end;
|
|
if w and $1000 = 0
|
|
then FDetails.Add('Bit $1000 (flag name "binary") = 0: formula definition')
|
|
else FDetails.add('Bit $1000 (flag name "binary") = 1: binary data (BIFF5-BIFF8)');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.4x)', [w, w]),
|
|
'Option flags');
|
|
|
|
numbytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInrow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.2x)', [b, b]),
|
|
'Keyboard shortcurt (only for command macro names)');
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(b),
|
|
'Length of the name (character count)');
|
|
lenName := b;
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'Size of the formula data');
|
|
formulaSize := w;
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if FFormat = sfExcel5 then
|
|
ShowInRow(FCurrRow, FBufferIndex, NumBytes, IntToStr(w),
|
|
'0 = Global name, otherwise index to EXTERNSHEET record (one-based)')
|
|
else
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'not used');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, NumBytes, IntToStr(w),
|
|
'0 = Global name, otherwise index to sheet (one-based)');
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, nuMbytes, IntToStr(b),
|
|
'Length of the menu text (character count)');
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, nuMbytes, IntToStr(b),
|
|
'Length of the description text (character count)');
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, nuMbytes, IntToStr(b),
|
|
'Length of the help topic text (character count)');
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, nuMbytes, IntToStr(b),
|
|
'Length of the status bar text (character count)');
|
|
|
|
if FFormat = sfExcel5 then begin
|
|
numBytes := lenName * sizeOf(ansiChar);
|
|
SetLength(ansiStr, lenName);
|
|
Move(FBuffer[FBufferIndex], ansiStr[1], numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, ansiStr,
|
|
'Character array of the name');
|
|
end else begin
|
|
|
|
if (FBuffer[FBufferIndex] and $01 = 0) //and (not IgnoreCompressedFlag)
|
|
then begin // compressed --> 1 byte per character
|
|
SetLength(ansiStr, lenName);
|
|
numbytes := lenName*SizeOf(ansiChar) + 1;
|
|
Move(FBuffer[FBufferIndex + 1], ansiStr[1], lenName*SizeOf(AnsiChar));
|
|
s := AnsiToUTF8(ansiStr);
|
|
end else begin
|
|
SetLength(wideStr, lenName);
|
|
numBytes := lenName*SizeOf(WideChar) + 1;
|
|
Move(FBuffer[FBufferIndex + 1], wideStr[1], lenName*SizeOf(WideChar));
|
|
s := UTF8Encode(WideStringLEToN(wideStr));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, s,
|
|
'Name (Unicode string without length field)');
|
|
end;
|
|
end;
|
|
|
|
firstTokenBufIdx := FBufferIndex;
|
|
while FBufferIndex < firstTokenBufIdx + formulaSize do begin
|
|
token := FBuffer[FBufferIndex];
|
|
numBytes := 1;
|
|
case token of
|
|
$3A, $3B, $5A, $5B, $7A, $7B:
|
|
begin
|
|
case token of
|
|
$3A: s := 'Token tRef3dR for "3D or external reference to a cell" (R = Reference)';
|
|
$5A: s := 'Token tRef3dV for "3D or external reference to a cell" (V = Value)';
|
|
$7A: s := 'Token tRef3dA for "3D or external reference to a cell" (A = Area)';
|
|
$3B: s := 'Token tArea3dR for "3D or external reference to a cell range" (R = Reference)';
|
|
$5B: s := 'Token tArea3dV for "3D or external reference to a cell range" (V = Value)';
|
|
$7B: s := 'Token tArea3dA for "3D or external reference to a cell range" (A = Area)';
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.2x', [token]), s);
|
|
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if FFormat = sfExcel5 then begin
|
|
if w and $8000 <> 0 then begin // negative value --> 3D reference
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(SmallInt(w)),
|
|
'3D reference, 1-based index to EXTERNSHEET record');
|
|
numBytes := 8;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, '', 'Not used');
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index to first referenced sheet ($FFFF = deleted sheet)');
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index to last referenced sheet ($FFFF = deleted sheet)');
|
|
end else
|
|
begin
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'External reference, 1-based index to EXTERNSHEET record');
|
|
numBytes := 12;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, '', 'Not used');
|
|
end;
|
|
end else
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'Index to REF entry in EXTERNSHEET record');
|
|
|
|
if token in [$3A, $5A, $7A] then
|
|
ShowCellAddress // Cell address
|
|
else
|
|
ShowCellAddressRange; // Cell range
|
|
end;
|
|
|
|
else
|
|
numBytes := 1;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'(unknown token)');
|
|
end; // case
|
|
end; // while
|
|
|
|
RowCount := FCurrRow;
|
|
EndUpdate(true);
|
|
end;
|
|
|
|
procedure TBIFFGrid.ShowDefRowHeight;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + IfThen(FFormat = sfExcel2, 1, 2);
|
|
|
|
if FFormat = sfExcel2 then begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Default height for unused rows:'#13);
|
|
FDetails.Add(Format(
|
|
'Bits $7FFF = %d: Default height for unused rows, in twips = 1/20 of a point',
|
|
[w and $7FFF]));
|
|
if w and $8000 = 0 then
|
|
FDetails.Add('Bit $8000 = 0: Row height changed manually')
|
|
else
|
|
FDetails.Add('Bit $8000 = 1: Row height not changed manually');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.4x)', [w, w]),
|
|
'Default height for unused rows, in twips = 1/20 of a point');
|
|
end else begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Option flags:'#13);
|
|
if w and $0001 = 0
|
|
then FDetails.Add('Bit $0001 = 0: Row height and default font height do match')
|
|
else FDetails.Add('Bit $0001 = 1: Row height and default font height do not match');
|
|
if w and $0002 = 0
|
|
then FDetails.Add('Bit $0002 = 0: Row is visible')
|
|
else FDetails.Add('Bit $0002 = 1: Row is hidden');
|
|
if w and $0004 = 0
|
|
then FDetails.Add('Bit $0004 = 0: No additional space above the row')
|
|
else FDetails.Add('Bit $0004 = 1: Additional space above the row');
|
|
if w and $0008 = 0
|
|
then FDetails.Add('Bit $0008 = 0: No additional space below the row')
|
|
else FDetails.Add('Bit $0008 = 1: Additional space below the row');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.4x', [WordLEToN(w)]),
|
|
'Option flags');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Default height for unused rows, in twips = 1/20 of a point');
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowDelta;
|
|
var
|
|
numBytes: Integer;
|
|
dbl: Double;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 8;
|
|
Move(FBuffer[FBufferIndex], dbl, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, FloatToStr(dbl),
|
|
'Maximum change in iteration (IEEE 754 floating-point value, 64-bit double precision)');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowDimensions;
|
|
var
|
|
numBytes: Integer;
|
|
dw: DWord;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + IfThen(FFormat = sfExcel2, 4, 5);
|
|
|
|
if FFormat = sfExcel8 then begin
|
|
numBytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(DWordLEToN(dw)),
|
|
'Index to first used row');
|
|
|
|
Move(FBuffer[FBufferIndex], dw, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(DWordLEToN(dw)),
|
|
'Index to last used row, increased by 1');
|
|
end else begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index to first used row');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index to last used row, increased by 1');
|
|
end;
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index to first used column');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index to last used column, increased by 1');
|
|
|
|
if FFormat <> sfExcel2 then begin
|
|
numBytes := 2;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, '',
|
|
'(not used)');
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowDSF;
|
|
var
|
|
w: Word;
|
|
numbytes: Integer;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(w), 'Reserved, MUST be ignored');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowEOF;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
ShowInRow(FCurrRow, FBufferIndex, 0, '', '(no content)');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowExcel9File;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
ShowInRow(FCurrRow, FBufferIndex, 0, '', 'Optional and unused');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowExternalBook;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
wideStr: WideString;
|
|
ansiStr: AnsiString;
|
|
s: String;
|
|
i, n: Integer;
|
|
begin
|
|
BeginUpdate;
|
|
RowCount := FixedRows + 1000;
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
n := WordLEToN(w);
|
|
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(n),
|
|
'Number of sheet names / number of sheets');
|
|
|
|
if Length(FBuffer) - FBufferIndex = 2 then begin
|
|
SetLength(ansiStr, 1);
|
|
Move(FBuffer[FBufferIndex], ansiStr[1], 1);
|
|
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s,
|
|
'(relict of BIFF5)');
|
|
end else begin
|
|
ExtractString(FBufferIndex, 2, true, s, numBytes);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Encoded URL without sheet name:'#13);
|
|
case s[1] of
|
|
#0: FDetails.Add('First character = #00: Reference relative to current sheet');
|
|
#1: FDetails.Add('First character = #01: Encoded URL follows');
|
|
#2: if FFormat = sfExcel8 then
|
|
FDetails.Add('First character = #02: Reference to a sheet in own document; sheet name follows')
|
|
else
|
|
FDetails.Add('First character = #02: Reference to the corrent sheet (nothing will follow)');
|
|
#3: if FFormat = sfExcel5 then
|
|
FDetails.Add('First character = #03: Reference to a sheet in own document; sheet name follows')
|
|
else
|
|
FDetails.Add('First character = #03: not used');
|
|
#4: if FFormat = sfExcel5 then
|
|
FDetails.ADd('First character = #03: Reference to the own workbook, sheet is unspecified (nothing will follow)')
|
|
else
|
|
FDetails.Add('First character = #03: not used');
|
|
end;
|
|
end;
|
|
if s[1] in [#0, #1, #2, #3, #4] then Delete(s, 1, 1);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s,
|
|
'Encoded URL without sheet name (Unicode string, 16-bit string length)');
|
|
|
|
for i:=0 to n-1 do begin
|
|
ExtractString(FBufferIndex, 2, true, s, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s,
|
|
'Sheet name (Unicode string with 16-bit string length)');
|
|
end;
|
|
end;
|
|
|
|
RowCount := FCurrRow;
|
|
EndUpdate(true);
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowExternCount;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Number of following EXTERNSHEET records');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowExternSheet;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
s: String;
|
|
nREF: Integer;
|
|
i: Integer;
|
|
len: Byte;
|
|
ansiStr: AnsiString;
|
|
begin
|
|
if FFormat <= sfExcel5 then begin
|
|
RowCount := FixedRows + 1;
|
|
len := FBuffer[0];
|
|
if FBuffer[1] = $03 then inc(len);
|
|
numBytes := len*SizeOf(AnsiChar) + 1;
|
|
SetLength(ansiStr, len);
|
|
Move(FBuffer[1], ansiStr[1], len*SizeOf(AnsiChar));
|
|
s := AnsiToUTF8(ansiStr);
|
|
if FCurrRow = Row then begin
|
|
FDetails.Add('Encoded document and sheet name:'#13);
|
|
if s[1] = #03 then begin
|
|
FDetails.Add('First character = $03: EXTERNSHEET stores a reference to one of the own sheets');
|
|
FDetails.Add('Document name: ' + Copy(s, 2, Length(s)));
|
|
end else
|
|
if (s[1] = ':') and (Length(s) = 1) then begin
|
|
FDetails.Add('Special EXTERNSHEET record for an add-in function. EXTERNName record with the name of the function follows.');
|
|
end else
|
|
FDetails.Add('Document name: ' + s);
|
|
end;
|
|
if s[1] = #03 then
|
|
Delete(s, 1, 1);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s,
|
|
'Encoded document and sheet name (Byte string, 8-bit string length)');
|
|
end else begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
nREF := WordLEToN(w);
|
|
|
|
RowCount := FixedRows + 1 + nREF*3;
|
|
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(nREF),
|
|
'Number of following REF structures');
|
|
|
|
for i:=1 to nREF do begin
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
Format('REF #%d: Index to EXTERNALBOOK record', [i]));
|
|
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
Format('REF #%d: Index to first sheet in EXTERNALBOOK sheet list', [i]));
|
|
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
Format('REF #%d: Index to last sheet in EXTERNALBOOK sheet list', [i]));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowFileSharing;
|
|
var
|
|
numbytes: Integer;
|
|
w: Word;
|
|
s: String;
|
|
begin
|
|
RowCount := FixedRows + 3;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Recommend read-only state when loading the file:'#13);
|
|
if w = 0 then FDetails.Add('0 = no') else FDetails.Add('1 = yes');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'Recommend read-only state when loading the file');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.4x', [w]),
|
|
'Hash value calculated from the read-only password');
|
|
|
|
ExtractString(FBufferIndex, IfThen(FFormat=sfExcel8, 2, 1), FFormat=sfExcel8,
|
|
s, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, s,
|
|
'User name of the file creator' + IfThen(FFormat = sfExcel8,
|
|
' (Unicode string, 16-bit string length)',
|
|
' (byte string, 8-bit string length)'
|
|
));
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowFnGroupCount;
|
|
var
|
|
numbytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Number of built-in function categories:'#13);
|
|
case w of
|
|
$000E:
|
|
FDetails.Add(
|
|
'There are 14 built-in function categories in the workbook.'#13+
|
|
'This implies that the file was last saved by a specific version of the application.'#13+
|
|
'The following 9 built-in function categories are visible to the end-user:'#13+
|
|
' Financial'#13+
|
|
' Date & Time'#13+
|
|
' Math & Trig'#13+
|
|
' Statistical'#13+
|
|
' Lookup & Reference'#13+
|
|
' Database'#13+
|
|
' Text'#13+
|
|
' Logical'#13+
|
|
' Information'#13+
|
|
'The following 5 built-in function categories are not visible to the end-user:'#13+
|
|
' UserDefined'#13+
|
|
' Commands'#13+
|
|
' Customize'#13+
|
|
' MacroControl'#13+
|
|
' DDEExternal'
|
|
);
|
|
$0010:
|
|
FDetails.Add(
|
|
'There are 16 built-in function categories in the workbook.'#13+
|
|
'This implies that the file was last saved by a specific version of the application'#13+
|
|
'The following 11 built-in function categories are visible to the end-user:'#13+
|
|
' Financial'#13+
|
|
' Date & time'#13+
|
|
' Math & Trig'#13+
|
|
' Statistical'#13+
|
|
' Lookup & Reference'+
|
|
' Database'#13+
|
|
' Text'#13+
|
|
' Logical'#13+
|
|
' Information'#13+
|
|
' Engineering'#13+
|
|
' Cube'#13+
|
|
'The following 5 built-in function categories are not visible to the end-user:'#13+
|
|
' UserDefined'#13+
|
|
' Commands'#13+
|
|
' Customize'#13+
|
|
' MacroControl'#13+
|
|
' DDEExternal'
|
|
);
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(w),
|
|
'Number of built-in function categories');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowFont;
|
|
var
|
|
numbytes: Integer;
|
|
w: Word;
|
|
b: Byte;
|
|
s: String;
|
|
begin
|
|
RowCount := IfThen(FFormat = sfExcel2, 3, 10) + FixedRows;
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(w),
|
|
'Font height in twips (=1/20 point)');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Option flags:'#13);
|
|
if w and $0001 = 0
|
|
then FDetails.Add('Bit $0001 = 0: not bold')
|
|
else FDetails.Add('Bit $0001 = 1: bold (redundant in BIFF5-BIFF8)');
|
|
if w and $0002 = 0
|
|
then FDetails.Add('Bit $0002 = 0: not italic')
|
|
else FDetails.Add('Bit $0002 = 1: italic');
|
|
if w and $0004 = 0
|
|
then FDetails.Add('Bit $0004 = 0: not underlined')
|
|
else FDetails.Add('Bit $0004 = 1: underlined (redundant in BIFF5-BIFF8)');
|
|
if w and $0008 = 0
|
|
then FDetails.Add('Bit $0008 = 0: not struck out')
|
|
else FDetails.Add('Bit $0008 = 1: struck out');
|
|
if w and $0010 = 0
|
|
then FDetails.Add('Bit $0010 = 0: not outlined')
|
|
else FDetails.Add('Bit $0010 = 1: outlined');
|
|
if w and $0020 = 0
|
|
then FDetails.Add('Bit $0020 = 0: not shadowed')
|
|
else FDetails.Add('Bit $0020 = 1: shadowed');
|
|
if w and $0040 = 0
|
|
then FDetails.Add('Bit $0040 = 0: not condensed')
|
|
else FDetails.Add('Bit $0040 = 1: condensed');
|
|
if w and $0080 = 0
|
|
then FDetails.Add('Bit $0080 = 0: not extended')
|
|
else FDetails.Add('Bit $0080 = 1: extended');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.4x)', [w, w]),
|
|
'Option flags');
|
|
|
|
if FFormat <> sfExcel2 then begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(2), 'Color index');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.4x)', [w,w]),
|
|
'Font weight (400=normal, 700=bold)');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Escapement:'#13);
|
|
case w of
|
|
0: FDetails.Add('0 = none');
|
|
1: FDetails.Add('1 = superscript');
|
|
2: FDetails.Add('2 = subscript');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.4x', [w]),
|
|
'Escapement ($00=none, $01=superscript, $02=subscript)');
|
|
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Underline type:'#13);
|
|
case b of
|
|
$00: FDetails.Add('$00 = no underline');
|
|
$01: FDetails.Add('$01 = single underline');
|
|
$02: FDetails.Add('$02 = double underline');
|
|
$21: FDetails.Add('$21 = single accounting');
|
|
$22: FDetails.Add('$22 = double accounting');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [b]),
|
|
'Underline type ($00=none, $01=single, $02=double, ...)');
|
|
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Font family:'#13);
|
|
case b of
|
|
$00: FDetails.Add('$00 = None (unknown or don''t care)');
|
|
$01: FDetails.Add('$01 = Roman (variable width, serifed)');
|
|
$02: FDetails.Add('$02 = Swiss (variable width, sans-serifed)');
|
|
$03: FDetails.Add('$03 = Modern (fixed width, serifed or sans-serifed)');
|
|
$04: FDetails.Add('$04 = Script (cursive)');
|
|
$05: FDetails.Add('$05 = Decorative (specialised, for example Old English, Fraktur)');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%.2x', [b]),
|
|
'Font family');
|
|
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
case b of
|
|
$00: s := 'ANSI Latin';
|
|
$01: s := 'System default';
|
|
$02: s := 'Symbol';
|
|
$4D: s := 'Apple Roman';
|
|
$80: s := 'ANSI Japanese Shift-JIS';
|
|
$81: s := 'ANSI Korean (Hangul)';
|
|
$82: s := 'ANSI Korean (Johab)';
|
|
$86: s := 'ANSI Chinese Simplified GBK';
|
|
$88: s := 'ANSI Chinese Traditional BIG5';
|
|
$A1: s := 'ANSI Greek';
|
|
$A2: s := 'ANSI Turkish';
|
|
$A3: s := 'ANSI Vietnamese';
|
|
$B1: s := 'ANSI Hebrew';
|
|
$B2: s := 'ANSI Arabic';
|
|
$BA: s := 'ANSI Baltic';
|
|
$CC: s := 'ANSI Cyrillic';
|
|
$DE: s := 'ANSI Thai';
|
|
$EE: s := 'ANSI Latin II (Central European)'; // East Europe in MS docs!
|
|
$FF: s := 'OEM Latin I';
|
|
else s := '';
|
|
end;
|
|
if s <> '' then s := Format('$%.2x: %s', [b, s]) else s := Format('$%.2x', [b]);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s,
|
|
'Character set');
|
|
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, '', 'Not used');
|
|
end;
|
|
|
|
ExtractString(FBufferIndex, 1, FFormat=sfExcel8, s, numbytes);
|
|
if FFormat = sfExcel8 then
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, s, 'Font name (unicode string, 8-bit string length)')
|
|
else
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, s, 'Font name (byte string, 8-bit string length)');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowFontColor;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
s: String;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
NumBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
case w of
|
|
$0000: s := 'EGA Black (rgb = $000000)';
|
|
$0001: s := 'EGA White (rgb = $FFFFFF)';
|
|
$0002: s := 'EGA Red (rgb = $0000FF)';
|
|
$0003: s := 'EGA Green (rgb = $00FF00)';
|
|
$0004: s := 'EGA Blue (rgb = $FF0000)';
|
|
$0005: s := 'EGA Yellow (rgb = $00FFFF)';
|
|
$0006: s := 'EGA Magenta (rgb = $FF00FF)';
|
|
$0007: s := 'EGA Cyan (rgb = $FFFF00)';
|
|
$7FFF: s := 'Automatic (system window text colour)';
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.04x)', [w, w]),
|
|
Format('Font color index into preceding FONT record (%s)', [s]));
|
|
end;
|
|
|
|
procedure TBIFFGrid.ShowFooter;
|
|
var
|
|
numbytes: Integer;
|
|
s: String;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
ExtractString(FBufferIndex, IfThen(FFormat=sfExcel8, 2, 1), FFormat=sfExcel8,
|
|
s, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, s,
|
|
'Page footer string' + IfThen(FFormat = sfExcel8,
|
|
' (Unicode string, 16-bit string length)',
|
|
' (byte string, 8-bit string length)'
|
|
));
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowFormat;
|
|
var
|
|
numBytes: Integer;
|
|
w: word;
|
|
b: Byte;
|
|
s: String;
|
|
begin
|
|
RowCount := IfThen(FFormat = sfExcel2, FixedRows + 1, FixedRows + 2);
|
|
if FFormat <> sfExcel2 then begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(w),
|
|
'FormatIndex used in other records');
|
|
end;
|
|
b := IfThen(FFormat=sfExcel8, 2, 1);
|
|
ExtractString(FBufferIndex, b, (FFormat=sfExcel8), s, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s,
|
|
Format('Number format string (%s string, %d-bit string length)', [GetStringType, b*8]));
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowFormatCount;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
if FFormat = sfExcel2 then begin
|
|
RowCount := 1 + FixedRows;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Number of FORMAT records');
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowFormula;
|
|
var
|
|
numBytes: Integer;
|
|
b: Byte;
|
|
w: Word;
|
|
q: QWord;
|
|
dbl: double absolute q;
|
|
bytearr: array[0..7] of byte absolute q;
|
|
wordarr: array[0..3] of word absolute q;
|
|
// s: String;
|
|
tokenBytes: Integer;
|
|
// firstTokenBufIdx: Integer;
|
|
// token: Byte;
|
|
r,c, r2,c2: Integer;
|
|
begin
|
|
BeginUpdate;
|
|
RowCount := FixedRows + 1000;
|
|
// Brute force simplification because of unknown row count at this point
|
|
// Will be reduced at the end.
|
|
|
|
// Offset 0 = Row, Offset 2 = Column
|
|
ShowRowColData(FBufferIndex);
|
|
// Offset 4 = Cell attributes (BIFF2) or XF ecord index (> BIFF2)
|
|
if FFormat = sfExcel2 then begin
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Cell protection and XF index:'#13);
|
|
FDetails.Add(Format('Bits 5-0 = %d: XF Index', [b and $3F]));
|
|
case b and $40 of
|
|
0: FDetails.Add('Bit 6 = 0: Cell is NOT locked.');
|
|
1: FDetails.Add('Bit 6 = 1: Cell is locked.');
|
|
end;
|
|
case b and $80 of
|
|
0: FDetails.Add('Bit 7 = 0: Formula is NOT hidden.');
|
|
1: FDetails.Add('Bit 7 = 1: Formula is hidden.');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.2x)', [b,b]),
|
|
'Cell protection and XF index');
|
|
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Indexes to format and font records:'#13);
|
|
FDetails.Add(Format('Bits 5-0 = %d: Index to FORMAT record', [b and $3f]));
|
|
FDetails.Add(Format('Bits 7-6 = %d: Index to FONT record', [(b and $C0) shr 6]));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.2x)', [b,b]),
|
|
'Indexes of format and font records');
|
|
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Cell style:'#13);
|
|
case b and $07 of
|
|
0: FDetails.Add('Bits 2-0 = 0: Horizontal alignment is GENERAL');
|
|
1: FDetails.Add('Bits 2-0 = 1: Horizontal alignment is LEFT');
|
|
2: FDetails.Add('Bits 2-0 = 2: Horizontal alignment is CENTERED');
|
|
3: FDetails.Add('Bits 2-0 = 3: Horizontal alignment is RIGHT');
|
|
4: FDetails.Add('Bits 2-0 = 4: Horizontal alignment is FILLED');
|
|
end;
|
|
if b and $08 = 0
|
|
then FDetails.Add('Bit 3 = 0: Cell has NO left border')
|
|
else FDetails.Add('Bit 3 = 1: Cell has left black border');
|
|
if b and $10 = 0
|
|
then FDetails.Add('Bit 4 = 0: Cell has NO right border')
|
|
else FDetails.Add('Bit 4 = 1: Cell has right black border');
|
|
if b and $20 = 0
|
|
then FDetails.Add('Bit 5 = 0: Cell has NO top border')
|
|
else FDetails.Add('Bit 5 = 1: Cell has top black border');
|
|
if b and $40 = 0
|
|
then FDetails.Add('Bit 6 = 0: Cell has NO bottom border')
|
|
else FDetails.Add('Bit 6 = 1: Cell has bottom black border');
|
|
if b and $80 = 0
|
|
then FDetails.Add('Bit 7 = 0: Cell has NO shaded background')
|
|
else FDetails.Add('Bit 7 = 1: Cell has shaded background');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('%d ($%.2x)', [b,b]),
|
|
'Cell style');
|
|
end else begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrROw, FBufferIndex, numBytes, Format('%d ($%.4x)', [w, w]),
|
|
'Index of XF record');
|
|
end;
|
|
|
|
// Offset 6: Result of formula
|
|
numBytes := 8;
|
|
Move(FBuffer[FBufferIndex], q, numBytes);
|
|
if wordarr[3] <> $FFFF then begin
|
|
if FCurrRow = Row then begin
|
|
FDetails.Add('Formula result:'#13);
|
|
FDetails.Add(Format('Bytes 0-7: $%.15x --> IEEE 764 floating-point value, 64-bit double precision'#13+
|
|
' = %g', [q, dbl]));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, FloatToStr(dbl),
|
|
'Result of formula (IEEE 764 floating-point value, 64-bit double precision)');
|
|
end else begin
|
|
case bytearr[0] of
|
|
0: begin // String result
|
|
if FCurrRow = Row then begin
|
|
FDetails.Add('Formula result:'#13);
|
|
FDetails.Add('Byte 0 = 0 --> Result is string, follows in STRING record');
|
|
FDetails.Add('Byte 1-5: Not used');
|
|
FDetails.Add('Byte 6&7: $FFFF --> no floating point number');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.16x', [q]),
|
|
'Result is a string, follows in STRING record');
|
|
end;
|
|
1: begin // BOOL result
|
|
if FCurrRow = Row then begin
|
|
FDetails.Add('Formula result:'#13);
|
|
FDetails.Add('Byte 0 = 1 --> Result is BOOLEAN');
|
|
FDetails.Add('Byte 1: Not used');
|
|
if bytearr[2] = 0
|
|
then FDetails.Add('Byte 2 = 0 --> FALSE')
|
|
else FDetails.Add('Byte 2 = 1 --> TRUE');
|
|
FDetails.Add('Bytes 3-5: Not used');
|
|
FDetails.Add('Bytes 6&7: $FFFF --> no floating point number');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.16x', [q]),
|
|
'Result is BOOLEAN');
|
|
end;
|
|
2: begin // ERROR result
|
|
if FCurrRow = Row then begin
|
|
FDetails.Add('Formula result:'#13);
|
|
FDetails.Add('Byte 0 = 2 --> Result is an ERROR value');
|
|
FDetails.Add('Byte 1: Not used');
|
|
case bytearr[2] of
|
|
$00: FDetails.Add('Byte 2 = $00 --> #NULL! Intersection of two cell ranges is empty');
|
|
$07: FDetails.Add('Byte 2 = $07 --> #DIV/0! Division by zero');
|
|
$0F: FDetails.Add('Byte 2 = $0F --> #VALUE! Wrong type of operand');
|
|
$17: FDetails.Add('Byte 2 = $17 --> #REF! Illegal or deleted cell reference');
|
|
$1D: FDetails.Add('Byte 2 = $1D --> #NAME? Wrong function or range name');
|
|
$24: FDetails.Add('Byte 2 = $24 --> #NUM! Value range overflow');
|
|
$2A: FDetails.Add('Byte 2 = $2A --> #N/A Argument or function not available');
|
|
end;
|
|
FDetails.Add('Bytes 6&7: $FFFF --> no floating point number');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.16x', [q]),
|
|
'Result is an ERROR value');
|
|
end;
|
|
3: begin // EMPTY cell
|
|
if FCurrRow = Row then begin
|
|
FDetails.Add('Formula result:'#13);
|
|
FDetails.Add('Byte 0 = 3 --> Result is an empty cell, for example an empty string');
|
|
FDetails.Add('Byte 1-5: Not used');
|
|
FDetails.Add('Bytes 6&7: $FFFF --> no floating point number');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.16x', [q]),
|
|
'Result is an EMPTY cell (empty string)');
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// Option flags
|
|
if FFormat = sfExcel2 then begin
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Option flags:'#13);
|
|
case b of
|
|
0: FDetails.Add('0 = Do not recalculate');
|
|
1: FDetails.Add('1 = Recalculate always');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(b), 'Option flags');
|
|
end else begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Option flags:'#13);
|
|
if w and $0001 = 0
|
|
then FDetails.Add('Bit $0001 = 0: Do not recalculate')
|
|
else FDetails.Add('Bit $0001 = 1: Recalculate always');
|
|
FDetails.Add('Bit $0002: Reserved - MUST be zero, MUST be ignored');
|
|
if w and $0004 = 0
|
|
then FDetails.Add('Bit $0004 = 0: Cell does NOT have a fill alignment or a center-across-selection alignment.')
|
|
else FDetails.Add('Bit $0004 = 1: Cell has either a fill alignment or a center-across-selection alignment.');
|
|
if w and $0008 = 0
|
|
then FDetails.Add('Bit $0008 = 0: Formula is NOT part of a shared formula')
|
|
else FDetails.Add('Bit $0008 = 1: Formula is part of a shared formula');
|
|
FDetails.Add('Bit $0010: Reserved - MUST be zero, MUST be ignored');
|
|
if w and $0020 = 0
|
|
then FDetails.Add('Bit $0020 = 0: Formula is NOT excluded from formula error checking')
|
|
else FDetails.Add('Bit $0020 = 1: Formula is excluded from formula error checking');
|
|
FDetails.Add('Bits $FC00: Reserved - MUST be zero, MUST be ignored');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.4x', [w]),
|
|
'Option flags');
|
|
end;
|
|
|
|
// Not used
|
|
if (FFormat >= sfExcel5) then begin
|
|
numBytes := 4;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, '', '(not used');
|
|
end;
|
|
|
|
// Size of Token array (in Bytes)
|
|
if FFormat = sfExcel2 then begin
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
tokenBytes := b;
|
|
end else begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
tokenBytes := WordLEToN(w);
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(tokenBytes),
|
|
'Size of formula data (in Bytes)');
|
|
|
|
ShowFormulaTokens(tokenBytes);
|
|
|
|
RowCount := FCurrRow;
|
|
EndUpdate(true);
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowFormulaTokens(ATokenBytes: Integer);
|
|
var
|
|
numBytes: Integer;
|
|
b: Byte;
|
|
w: Word;
|
|
s: String;
|
|
dbl: Double;
|
|
firstTokenBufIndex: Integer;
|
|
token: Byte;
|
|
r, c: Word;
|
|
begin
|
|
// Tokens and parameters
|
|
firstTokenBufIndex := FBufferIndex;
|
|
while FBufferIndex < firstTokenBufIndex + ATokenBytes do begin
|
|
token := FBuffer[FBufferIndex];
|
|
numBytes := 1;
|
|
case token of
|
|
$01: begin
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.2x', [token]),
|
|
'Token for "Cell is part of shared formula"');
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Index to row of first FORMULA record in the formula range');
|
|
if FFormat = sfExcel2 then begin
|
|
numbytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(b),
|
|
'Index to column of first FORMULA record in the formula range');
|
|
end else begin
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Index to column of first FORMULA record in the formula range');
|
|
end;
|
|
end;
|
|
$02: begin
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.2x', [token]),
|
|
'Token for "Cell is part of a multiple operations table"');
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Index to first row of the table range');
|
|
if FFormat = sfExcel2 then begin
|
|
numbytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(b),
|
|
'Index to first column of the table range');
|
|
end else begin
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Index to first column of the table range');
|
|
end;
|
|
end;
|
|
$03: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token "+" (add)');
|
|
$04: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token "-" (subtract)');
|
|
$05: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token "*" (multiply)');
|
|
$06: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token "/" (divide)');
|
|
$07: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token "^" (power)');
|
|
$08: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token "&" (concat)');
|
|
$09: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token "<" (less than)');
|
|
$0A: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token "<=" (less equal)');
|
|
$0B: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token "=" (equal)');
|
|
$0C: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token ">=" (greater equal)');
|
|
$0D: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token ">" (greater than)');
|
|
$0E: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token "<>" (not equal)');
|
|
$0F: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token " " (intersect)');
|
|
$10: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token "list character"');
|
|
$11: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token ":" (range)');
|
|
$12: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token "+" (unary plus)');
|
|
$13: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token "-" (unary minus)');
|
|
$14: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token "%" (percent)');
|
|
$15: ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.2x', [token]),
|
|
'Token "()" (operator in parenthesis)');
|
|
$16: ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token "missing argument"');
|
|
$17: begin
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token tSTR (Label)');
|
|
ExtractString(FBufferIndex, 1, (FFormat = sfExcel8), s, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s, 'String value');
|
|
end;
|
|
$1C: begin
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token tERR (Error)');
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
if FCurrRow = Row then begin
|
|
FDetails.Add('Error code:'#13);
|
|
FDetails.Add(Format('Code $%.2x --> "%s"', [b, GetErrorValueStr(TsErrorValue(b))]));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [b]), 'Error code');
|
|
end;
|
|
$1D: begin
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token tBOOL');
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b),
|
|
'0=FALSE, 1=TRUE');
|
|
end;
|
|
$1E: begin
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token tINT (Integer)');
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Integer value');
|
|
end;
|
|
$1F: begin
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token tNUM (Number)');
|
|
numBytes := 8;
|
|
Move(FBuffer[FBufferIndex], dbl, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%g', [dbl]), //FloatToStr(dbl),
|
|
'IEEE 754 floating-point value');
|
|
end;
|
|
$20, $40, $60:
|
|
begin
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token tARRAY');
|
|
if FFormat = sfExcel2 then numBytes := 6 else numBytes := 7;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, '', '(not used)');
|
|
end;
|
|
$21, $41, $61:
|
|
begin
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token tFUNC (Function with fixed argument count)');
|
|
if FFormat = sfExcel2 then begin
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
s := Format('Index of function (%s)', [SheetFuncName(b)]);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b), s);
|
|
end else begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
s := Format('Index of function (%s)', [SheetFuncName(w)]);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w), s);
|
|
end;
|
|
end;
|
|
$22, $42, $62:
|
|
begin
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token tFUNCVAR (Function with variable argument count)');
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b),
|
|
'Number of arguments');
|
|
if FFormat = sfExcel2 then begin
|
|
numBytes := 1;
|
|
s := Format('Index of built-in function (%s)', [SheetFuncName(b)]);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b), s);
|
|
end else begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
s := Format('Index of built-in function (%s)', [SheetFuncName(w)]);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w), s);
|
|
end;
|
|
end;
|
|
$23, $43, $63:
|
|
begin
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'Token tNAME');
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
case FFormat of
|
|
sfExcel2: s := 'DEFINEDNAME or EXTERNALNAME record';
|
|
sfExcel5: s := 'DEFINEDNAME record in Global Link Table';
|
|
sfExcel8: s := 'DEFINEDNAME record in Link Table';
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'1-based index to '+s);
|
|
case FFormat of
|
|
sfExcel2: numBytes := 5;
|
|
sfExcel5: numBytes := 12;
|
|
sfExcel8: numBytes := 2;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, '', '(not used)');
|
|
end;
|
|
$24, $44, $64:
|
|
begin
|
|
case token of
|
|
$24: s := 'reference';
|
|
$44: s := 'value';
|
|
$64: s := 'array';
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
Format('Token tREF (Cell %s)', [s]));
|
|
ShowCellAddress;
|
|
end;
|
|
$25, $45, $65:
|
|
begin
|
|
case token of
|
|
$25: s := 'reference';
|
|
$45: s := 'value';
|
|
$65: s := 'array';
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
Format('Token tAREA (Cell range %s)', [s]));
|
|
ShowCellAddressRange;
|
|
end;
|
|
$2C, $4C, $6C:
|
|
begin
|
|
case token of
|
|
$2C: s := 'reference';
|
|
$4C: s := 'value';
|
|
$6C: s := 'array';
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
Format('Token tREFN (Relative reference to cell %s in same sheet)', [s]));
|
|
|
|
// Encoded relative cell address
|
|
if FFormat = sfExcel8 then
|
|
begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes); // row
|
|
r := WordLEToN(w);
|
|
Move(FBuffer[FBufferIndex+2], w, numBytes); // column with flags
|
|
c := WordLEToN(w);
|
|
|
|
{ Note: The bitmask assignment to relative column/row is reversed in relation
|
|
to OpenOffice documentation in order to match with Excel files. }
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Encoded cell address (row):'#13);
|
|
if c and $8000 = 0 then
|
|
begin
|
|
FDetails.Add('Row index is ABSOLUTE (see Encoded column index)');
|
|
FDetails.Add('Absolute row index: ' + IntToStr(r));
|
|
end else
|
|
begin
|
|
FDetails.Add('Row index is RELATIVE (see Encoded column index)');
|
|
FDetails.Add('Relative row index: ' + IntToStr(Smallint(r)));
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.4x)', [r, r]),
|
|
'Encoded row index');
|
|
|
|
// Bit mask $4000 --> column
|
|
// Bit mask $8000 --> row
|
|
if Row = FCurrRow then
|
|
begin
|
|
FDetails.Add('Encoded cell address (column):'#13);
|
|
if c and $4000 = 0
|
|
then FDetails.Add('Bit 14=0: Column index is ABSOLUTE')
|
|
else FDetails.Add('Bit 14=1: Column index is RELATIVE');
|
|
if c and $8000 = 0
|
|
then FDetails.Add('Bit 15=0: Row index is ABSOLUTE')
|
|
else FDetails.Add('Bit 15=1: Row index is RELATIVE');
|
|
FDetails.Add('');
|
|
if c and $4000 = 0
|
|
then FDetails.Add('Absolute column index: ' + IntToStr(Lo(c)))
|
|
else FDetails.Add('Relative column index: ' + IntToStr(ShortInt(Lo(c))));
|
|
end;
|
|
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.4x)', [c, c]),
|
|
'Encoded column index');
|
|
end
|
|
else
|
|
// Excel5 (Excel2 does not support shared formulas)
|
|
begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
r := w and $3FFF;
|
|
b := FBuffer[FBufferIndex+2];
|
|
c := b;
|
|
|
|
// Bit mask $4000 --> column
|
|
// Bit mask $8000 --> row
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Encoded cell address (row):'#13);
|
|
if w and $4000 = 0
|
|
then FDetails.Add('Bit 14=0: Column index is ABSOLUTE')
|
|
else FDetails.Add('Bit 14=0: Column index is RELATIVE');
|
|
if w and $8000 = 0
|
|
then FDetails.Add('Bit 15=0: Row index is ABSOLUTE')
|
|
else FDetails.Add('Bit 15=1: Row index is RELATIVE');
|
|
FDetails.Add('');
|
|
if w and $8000 = 0
|
|
then FDetails.Add('Absolute row index: ' + IntToStr(r))
|
|
else FDetails.Add('Relative row index: ' + IntToStr(Smallint(r)));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.4x)', [w, w]),
|
|
'Encoded row index');
|
|
|
|
if Row = FCurrRow then
|
|
begin
|
|
FDetails.Add('Encoded cell address (column):'#13);
|
|
if w and $4000 = 0 then begin
|
|
FDetails.Add('Column index is ABSOLUTE (see Encoded row index)');
|
|
FDetails.Add('Absolute column index: ' + IntToStr(c));
|
|
end else begin
|
|
FDetails.Add('Column index is RELATIVE (see Encoded row index)');
|
|
FDetails.Add('Relative column index: ' + IntToStr(ShortInt(c)));
|
|
end;
|
|
end;
|
|
numBytes := 1;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.2x)', [b, b]),
|
|
'Encoded column index');
|
|
end;
|
|
end;
|
|
|
|
else
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]),
|
|
'(unknown token)');
|
|
|
|
end; // case
|
|
end; // while
|
|
|
|
end;
|
|
|
|
procedure TBIFFGrid.ShowGCW;
|
|
var
|
|
numBytes: Integer;
|
|
b: Byte;
|
|
w: Word;
|
|
i,j: Integer;
|
|
bit: Byte;
|
|
begin
|
|
RowCount := FixedRows + 33;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'Size of Global Column Width bit field (1 bit per column), must be 32');
|
|
|
|
numBytes := 1;
|
|
for i:= 0 to w-1 do begin
|
|
b := FBuffer[FBufferIndex];
|
|
if FCurrRow = Row then begin
|
|
FDetails.Add(Format('GCW (Global column width) record, byte #%d:'#13, [i]));
|
|
bit := 1;
|
|
for j:=0 to 7 do begin
|
|
if b and bit = 0
|
|
then FDetails.Add(Format('Bit $%.2x=0: Column %d uses width of COLWIDTH record.', [bit, j+i*8]))
|
|
else FDetails.Add(Format('Bit $%.2x=1: Column %d uses width of STANDARDWIDTH record '+
|
|
'(or, if not available, DEFCOLWIDTH record)', [bit, j+i*8]));
|
|
bit := bit * 2;
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [b]),
|
|
Format('Widths of columns %d-%d', [i*8, i*8+7]));
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowHeader;
|
|
var
|
|
numbytes: Integer;
|
|
s: String;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
ExtractString(FBufferIndex, IfThen(FFormat=sfExcel8, 2, 1), FFormat=sfExcel8,
|
|
s, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, s,
|
|
'Page header string' + IfThen(FFormat = sfExcel8,
|
|
' (Unicode string, 16-bit string length)',
|
|
' (byte string, 8-bit string length)'
|
|
));
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowHideObj;
|
|
var
|
|
numBytes: word;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Viewing mode for objects:'#13);
|
|
case w of
|
|
0: FDetails.Add('0 = Show all objects');
|
|
1: FDetails.Add('1 = Show placeholders');
|
|
2: FDetails.Add('2 = Do not show objects');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'Viewing mode for objects');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowInRow(var ARow: Integer; var AOffs: LongWord;
|
|
ASize: Word; AValue,ADescr: String);
|
|
begin
|
|
Cells[0, ARow] := IntToStr(AOffs);
|
|
Cells[1, ARow] := IntToStr(ASize);
|
|
Cells[2, ARow] := AValue;
|
|
Cells[3, ARow] := ADescr;
|
|
inc(ARow);
|
|
inc(AOffs, ASize);
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowInteger;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
b: Byte;
|
|
begin
|
|
// BIFF2 only
|
|
if (FFormat <> sfExcel2) then
|
|
exit;
|
|
|
|
RowCount := FixedRows + 5;
|
|
ShowRowColData(FBufferIndex);
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Cell protection and XF index:'#13);
|
|
FDetails.Add(Format('Bits 5-0 = %d: XF Index', [b and $3F]));
|
|
case b and $40 of
|
|
0: FDetails.Add('Bit 6 = 0: Cell is NOT locked.');
|
|
1: FDetails.Add('Bit 6 = 1: Cell is locked.');
|
|
end;
|
|
case b and $80 of
|
|
0: FDetails.Add('Bit 7 = 0: Formula is NOT hidden.');
|
|
1: FDetails.Add('Bit 7 = 1: Formula is hidden.');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.2x)', [b,b]),
|
|
'Cell protection and XF index');
|
|
|
|
b := FBuffer[FBufferIndex];
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Indexes to format and font records:'#13);
|
|
FDetails.Add(Format('Bits 5-0 = %d: Index to FORMAT record', [b and $3f]));
|
|
FDetails.Add(Format('Bits 7-6 = %d: Index to FONT record', [(b and $C0) shr 6]));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.2x)', [b,b]),
|
|
'Indexes of format and font records');
|
|
|
|
b := FBuffer[FBufferIndex];
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Cell style:'#13);
|
|
case b and $07 of
|
|
0: FDetails.Add('Bits 2-0 = 0: Horizontal alignment is GENERAL');
|
|
1: FDetails.Add('Bits 2-0 = 1: Horizontal alignment is LEFT');
|
|
2: FDetails.Add('Bits 2-0 = 2: Horizontal alignment is CENTERED');
|
|
3: FDetails.Add('Bits 2-0 = 3: Horizontal alignment is RIGHT');
|
|
4: FDetails.Add('Bits 2-0 = 4: Horizontal alignment is FILLED');
|
|
end;
|
|
if b and $08 = 0
|
|
then FDetails.Add('Bit 3 = 0: Cell has NO left border')
|
|
else FDetails.Add('Bit 3 = 1: Cell has left black border');
|
|
if b and $10 = 0
|
|
then FDetails.Add('Bit 4 = 0: Cell has NO right border')
|
|
else FDetails.Add('Bit 4 = 1: Cell has right black border');
|
|
if b and $20 = 0
|
|
then FDetails.Add('Bit 5 = 0: Cell has NO top border')
|
|
else FDetails.Add('Bit 5 = 1: Cell has top black border');
|
|
if b and $40 = 0
|
|
then FDetails.Add('Bit 6 = 0: Cell has NO bottom border')
|
|
else FDetails.Add('Bit 6 = 1: Cell has bottom black border');
|
|
if b and $80 = 0
|
|
then FDetails.Add('Bit 7 = 0: Cell has NO shaded background')
|
|
else FDetails.Add('Bit 7 = 1: Cell has shaded background');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('%d ($%.2x)', [b,b]),
|
|
'Cell style');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Unsigned 16-bit integer cell value');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowInterfaceEnd;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
ShowInRow(FCurrRow, FBufferIndex, 0, '', 'End of Globals Substream');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowInterfaceHdr;
|
|
var
|
|
numbytes: Integer;
|
|
w: Word;
|
|
begin
|
|
if FFormat < sfExcel8 then begin
|
|
RowCount := FixedRows;
|
|
exit;
|
|
end;
|
|
|
|
RowCount := FixedRows + 1;
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Code page of user interface:'#13);
|
|
FDetails.Add(Format('$%.4x = %s', [w, CodePageName(w)]));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('%d ($%.4x)', [w, w]),
|
|
'Begin of Globals Substream, code page of user interface');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowIteration;
|
|
var
|
|
numBytes: Integer;
|
|
w: word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Iterations:'#13);
|
|
case w of
|
|
0: FDetails.Add('0 = Iterations off');
|
|
1: FDetails.Add('1 = Iterations on');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w), 'Iterations on/off');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowIXFE;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index to XF record');
|
|
end;
|
|
|
|
procedure TBIFFGrid.ShowLabelCell;
|
|
var
|
|
numBytes: Integer;
|
|
b: Byte;
|
|
w: Word;
|
|
s: String;
|
|
begin
|
|
RowCount := IfThen(FFormat = sfExcel2, FixedRows + 6, FixedRows + 4);
|
|
ShowRowColData(FBufferIndex);
|
|
if (FFormat = sfExcel2) then begin
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Cell protection and XF index:'#13);
|
|
FDetails.Add(Format('Bits 5-0 = %d: XF Index', [b and $3F]));
|
|
case b and $40 of
|
|
0: FDetails.Add('Bit 6 = 0: Cell is NOT locked.');
|
|
1: FDetails.Add('Bit 6 = 1: Cell is locked.');
|
|
end;
|
|
case b and $80 of
|
|
0: FDetails.Add('Bit 7 = 0: Formula is NOT hidden.');
|
|
1: FDetails.Add('Bit 7 = 1: Formula is hidden.');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.2x)', [b,b]),
|
|
'Cell protection and XF index');
|
|
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Indexes to format and font records:'#13);
|
|
FDetails.Add(Format('Bits 5-0 = %d: Index to FORMAT record', [b and $3f]));
|
|
FDetails.Add(Format('Bits 7-6 = %d: Index to FONT record', [(b and $C0) shr 6]));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.2x)', [b,b]),
|
|
'Indexes of format and font records');
|
|
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Cell style:'#13);
|
|
case b and $07 of
|
|
0: FDetails.Add('Bits 2-0 = 0: Horizontal alignment is GENERAL');
|
|
1: FDetails.Add('Bits 2-0 = 1: Horizontal alignment is LEFT');
|
|
2: FDetails.Add('Bits 2-0 = 2: Horizontal alignment is CENTERED');
|
|
3: FDetails.Add('Bits 2-0 = 3: Horizontal alignment is RIGHT');
|
|
4: FDetails.Add('Bits 2-0 = 4: Horizontal alignment is FILLED');
|
|
end;
|
|
if b and $08 = 0
|
|
then FDetails.Add('Bit 3 = 0: Cell has NO left border')
|
|
else FDetails.Add('Bit 3 = 1: Cell has left black border');
|
|
if b and $10 = 0
|
|
then FDetails.Add('Bit 4 = 0: Cell has NO right border')
|
|
else FDetails.Add('Bit 4 = 1: Cell has right black border');
|
|
if b and $20 = 0
|
|
then FDetails.Add('Bit 5 = 0: Cell has NO top border')
|
|
else FDetails.Add('Bit 5 = 1: Cell has top black border');
|
|
if b and $40 = 0
|
|
then FDetails.Add('Bit 6 = 0: Cell has NO bottom border')
|
|
else FDetails.Add('Bit 6 = 1: Cell has bottom black border');
|
|
if b and $80 = 0
|
|
then FDetails.Add('Bit 7 = 0: Cell has NO shaded background')
|
|
else FDetails.Add('Bit 7 = 1: Cell has shaded background');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('%d ($%.2x)', [b,b]),
|
|
'Cell style');
|
|
end else begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.4x)', [w, w]),
|
|
'Index of XF record');
|
|
end;
|
|
|
|
b := IfThen(FFormat=sfExcel2, 1, 2);
|
|
ExtractString(FBufferIndex, b, (FFormat = sfExcel8), s, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s,
|
|
Format('%s string, %d-bit string length', [GetStringType, b*8]));
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowLabelSSTCell;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
dw: DWord;
|
|
begin
|
|
RowCount := FixedRows + 4;
|
|
ShowRowColData(FBufferIndex);
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.4x)', [w, w]),
|
|
'Index of XF record');
|
|
|
|
numBytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numBytes);
|
|
dw := DWordLEToN(dw);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(dw),
|
|
'Index into SST record (shared string table)');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowLeftMargin;
|
|
var
|
|
numBytes: Integer;
|
|
dbl: Double;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 8;
|
|
Move(FBuffer[FBufferIndex], dbl, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, FloatToStr(dbl),
|
|
'Left page margin in inches (IEEE 754 floating-point value, 64-bit double precision)');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowMergedCells;
|
|
var
|
|
w: Word;
|
|
numBytes: Integer;
|
|
i, n: Integer;
|
|
begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
n := WordLEToN(w); // count of merged ranges in this record
|
|
|
|
RowCount := FixedRows + 1 + n*4;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(n),
|
|
'Count of merged ranges in this record');
|
|
|
|
for i:=1 to n do begin
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(w),
|
|
Format('Merged range #%d: First row = %d', [i, w]));
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(w),
|
|
Format('Merged range #%d: Last row = %d', [i, w]));
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(w),
|
|
Format('Merged range #%d: First column = %d', [i, w]));
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(w),
|
|
Format('Merged range #%d: Last column = %d', [i, w]));
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowMMS;
|
|
var
|
|
w: Word;
|
|
numbytes: Integer;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(w), 'Reserved, MUST be ignored');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowMulBlank;
|
|
var
|
|
w: Word;
|
|
numbytes: Integer;
|
|
i, nc: Integer;
|
|
begin
|
|
nc := (Length(FBuffer) - 6) div 2;
|
|
RowCount := FixedRows + 3 + nc;
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Index to row');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Index to first column');
|
|
|
|
for i:=0 to nc-1 do begin
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
Format('Index to XF record #%d', [i]));
|
|
end;
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Index to last column');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowMulRK;
|
|
var
|
|
w: Word;
|
|
numBytes: Integer;
|
|
i, nc: Integer;
|
|
dw: DWord;
|
|
encint: DWord;
|
|
encdbl: QWord;
|
|
dbl: Double absolute encdbl;
|
|
s: String;
|
|
begin
|
|
nc := (Length(FBuffer) - 6) div 6;
|
|
RowCount := FixedRows + 3 + nc*2;
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Index to row');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Index to first column');
|
|
|
|
for i:=0 to nc-1 do begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
Format('Index to XF record #%d', [i]));
|
|
|
|
numBytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numbytes);
|
|
dw := DWordLEToN(dw);
|
|
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('RK Value:'#13);
|
|
if dw and $00000001 = 0
|
|
then FDetails.Add('Bit 0 = 0: Value not changed')
|
|
else FDetails.Add('Bit 0 = 1: Encoded value is multiplied by 100.');
|
|
if dw and $00000002 = 0
|
|
then FDetails.Add('Bit 1 = 0: Floating point value')
|
|
else FDetails.Add('Bit 1 = 1: Signed integer value');
|
|
if dw and $00000002 = 0 then begin
|
|
encdbl := (QWord(dw) and QWord($FFFFFFFFFFFFFFFC)) shl 32;
|
|
if dw and $00000001 = 1 then
|
|
s := Format('%.2f', [dbl*0.01])
|
|
else
|
|
s := Format('%.0f', [dbl]);
|
|
end
|
|
else begin
|
|
s := Format('$%.16x', [-59000000]);
|
|
encint := ((dw and DWord($FFFFFFFC)) shr 2) or (dw and DWord($C0000000));
|
|
// "arithmetic shift" = replace left-most bits by original bits
|
|
if dw and $00000001 = 1 then
|
|
s := FloatToStr(encint*0.01)
|
|
else
|
|
s := IntToStr(encint);
|
|
end;
|
|
FDetails.Add('Bits 31-2: Encoded value ' + s);
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes,
|
|
Format('$%.8x', [dw]),
|
|
Format('RK value #%d', [i])
|
|
);
|
|
end;
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Index to last column');
|
|
end;
|
|
|
|
procedure TBIFFGrid.ShowNote;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word = 0;
|
|
s: String;
|
|
begin
|
|
RowCount := IfThen(FFormat = sfExcel8, 6, 4);
|
|
|
|
// Offset 0: Row and Col index
|
|
ShowRowColData(FBufferIndex);
|
|
|
|
if FFormat = sfExcel8 then begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Comment flags:'#13);
|
|
if (w and $0002 <> 0)
|
|
then FDetails.Add('Bit 1=1: Comment is shown at all times')
|
|
else FDetails.Add('Bit 1=0: Comment is not shown at all tiems');
|
|
if (w and $0080 <> 0)
|
|
then FDetails.Add('Bit 7=1: Row with comment is hidden')
|
|
else FDetails.Add('Bit 7=0: Row with comment is visible');
|
|
if (w and $0100 <> 0)
|
|
then FDetails.Add('Bit 8=1: Column with comment is hidden')
|
|
else FDetails.Add('Bit 8=0: Column with comment is visible');
|
|
FDetails.Add('All other bits are reserved and must be ignored.');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.4x)', [w, w]),
|
|
'Flags');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w), 'Object ID');
|
|
|
|
ExtractString(FBufferIndex, IfThen(FFormat=sfExcel8, 2, 1), FFormat=sfExcel8,
|
|
s, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s, 'Author');
|
|
end else begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'Total length of comment');
|
|
|
|
numBytes := Min(Length(FBuffer) - FBufferIndex, 2048);
|
|
SetLength(s, numBytes);
|
|
Move(FBuffer[FBufferIndex], s[1], numBytes);
|
|
SetLength(s, Length(s));
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s, 'Comment text');
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowNumberCell;
|
|
var
|
|
numBytes: Integer;
|
|
b: Byte = 0;
|
|
w: Word = 0;
|
|
dbl: Double;
|
|
begin
|
|
RowCount := IfThen(FFormat = sfExcel2, FixedRows + 6, FixedRows + 4);
|
|
// Offset 0: Row & Offsset 2: Column
|
|
ShowRowColData(FBufferIndex);
|
|
// Offset 4: Cell attributes (BIFF2) or XF ecord index (> BIFF2)
|
|
if FFormat = sfExcel2 then begin
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Cell protection and XF index:'#13);
|
|
FDetails.Add(Format('Bits 5-0 = %d: XF Index', [b and $3F]));
|
|
case b and $40 of
|
|
0: FDetails.Add('Bit 6 = 0: Cell is NOT locked.');
|
|
1: FDetails.Add('Bit 6 = 1: Cell is locked.');
|
|
end;
|
|
case b and $80 of
|
|
0: FDetails.Add('Bit 7 = 0: Formula is NOT hidden.');
|
|
1: FDetails.Add('Bit 7 = 1: Formula is hidden.');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.2x)', [b,b]),
|
|
'Cell protection and XF index');
|
|
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Indexes to format and font records:'#13);
|
|
FDetails.Add(Format('Bits 5-0 = %d: Index to FORMAT record', [b and $3f]));
|
|
FDetails.Add(Format('Bits 7-6 = %d: Index to FONT record', [(b and $C0) shr 6]));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.2x)', [b,b]),
|
|
'Indexes of format and font records');
|
|
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Cell style:'#13);
|
|
case b and $07 of
|
|
0: FDetails.Add('Bits 2-0 = 0: Horizontal alignment is GENERAL');
|
|
1: FDetails.Add('Bits 2-0 = 1: Horizontal alignment is LEFT');
|
|
2: FDetails.Add('Bits 2-0 = 2: Horizontal alignment is CENTERED');
|
|
3: FDetails.Add('Bits 2-0 = 3: Horizontal alignment is RIGHT');
|
|
4: FDetails.Add('Bits 2-0 = 4: Horizontal alignment is FILLED');
|
|
end;
|
|
if b and $08 = 0
|
|
then FDetails.Add('Bit 3 = 0: Cell has NO left border')
|
|
else FDetails.Add('Bit 3 = 1: Cell has left black border');
|
|
if b and $10 = 0
|
|
then FDetails.Add('Bit 4 = 0: Cell has NO right border')
|
|
else FDetails.Add('Bit 4 = 1: Cell has right black border');
|
|
if b and $20 = 0
|
|
then FDetails.Add('Bit 5 = 0: Cell has NO top border')
|
|
else FDetails.Add('Bit 5 = 1: Cell has top black border');
|
|
if b and $40 = 0
|
|
then FDetails.Add('Bit 6 = 0: Cell has NO bottom border')
|
|
else FDetails.Add('Bit 6 = 1: Cell has bottom black border');
|
|
if b and $80 = 0
|
|
then FDetails.Add('Bit 7 = 0: Cell has NO shaded background')
|
|
else FDetails.Add('Bit 7 = 1: Cell has shaded background');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('%d ($%.2x)', [b,b]),
|
|
'Cell style');
|
|
end else begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrROw, FBufferIndex, numBytes, Format('%d ($%.4x)', [w, w]),
|
|
'Index of XF record');
|
|
end;
|
|
// Offset 6: Double value
|
|
numBytes := 8;
|
|
Move(FBuffer[FBufferIndex], dbl, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%g', [dbl]), //FloatToStr(dbl),
|
|
'IEEE 764 floating-point value');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowObj;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 5;
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.04x', [WordLEToN(w)]),
|
|
'ft (must be $15)');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.04x', [WordLEToN(w)]),
|
|
'cb (must be $12)');
|
|
|
|
numBytes := 2;
|
|
w := WordLEToN(w);
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Object type:'#13);
|
|
case w of
|
|
$00: FDetails.Add('$00 = Group');
|
|
$01: FDetails.Add('$01 = Line');
|
|
$02: FDetails.Add('$02 = Rectangle');
|
|
$03: FDetails.Add('$03 = Oval');
|
|
$04: FDetails.Add('$04 = Arc');
|
|
$05: FDetails.Add('$05 = Chart');
|
|
$06: FDetails.Add('$06 = Text');
|
|
$07: FDetails.Add('$07 = Button');
|
|
$08: FDetails.Add('$08 = Picture');
|
|
$09: FDetails.Add('$09 = Polygon');
|
|
$0B: FDetails.Add('$0B = Checkbox');
|
|
$0C: FDetails.Add('$0C = Radio button');
|
|
$0D: FDetails.Add('$0D = Edit box');
|
|
$0E: FDetails.Add('$0E = Label');
|
|
$0F: FDetails.Add('$0F = Dialog box');
|
|
$10: FDetails.Add('$10 = Spin control');
|
|
$11: FDetails.Add('$11 = Scrollbar');
|
|
$12: FDetails.Add('$12 = List');
|
|
$13: FDetails.Add('$13 = Group box');
|
|
$14: FDetails.ADd('$14 = Dropdown list');
|
|
$19: FDetails.Add('$19 = Note');
|
|
$1E: FDetails.Add('$1E = OfficeArt object');
|
|
else FDetails.Add(IntToStr(w) + ' = (unknown object)');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.04x', [w]),
|
|
'Object type (ot)');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.04x', [WordLEToN(w)]),
|
|
'Object ID');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Object flags:'#13);
|
|
if w and $0001 <> 0
|
|
then FDetails.Add('Bit $0001 = 1: Object is locked')
|
|
else FDetails.Add('Bit $0001 = 0: Object is NOT locked');
|
|
if w and $0002 <> 0
|
|
then FDetails.Add('Bit $0002 = 1: Reserved - must be zero!!!d')
|
|
else FDetails.Add('Bit $0002 = 0: Reserved - must be zero');
|
|
if w and $0004 <> 0
|
|
then FDetails.Add('Bit $0004 = 1: Application is expected to choose object size')
|
|
else FDetails.Add('Bit $0004 = 0: Application is NOT expected to choose object size');
|
|
if w and $0008 <> 0
|
|
then FDetails.Add('Bit $0008 = 1: Is a chart that is expected to be published when sheet is published')
|
|
else FDetails.Add('Bit $0008 = 0: Is NOT a chart that is expected to be published when sheet is published');
|
|
if w and $0010 <> 0
|
|
then FDetails.Add('Bit $0010 = 1: Image of this object is intended to be included when printing')
|
|
else FDetails.Add('Bit $0010 = 0: Image of this object is NOT intended to be included when printing');
|
|
FDetails.Add('Bit $0020 : unused');
|
|
FDetails.Add('Bit $0040 : unused');
|
|
if w and $0080 <> 0
|
|
then FDetails.Add('Bit $0080 = 1: Object is disabled')
|
|
else FDetails.ADd('Bit $0080 = 0: Object is NOT disabled');
|
|
if w and $0100 <> 0
|
|
then FDetails.Add('Bit $0100 = 1: is an auxiliary object that can only be automatically inserted by the application')
|
|
else FDetails.Add('Bit $0100 = 0: is NOT an auxiliary object that can only be automatically inserted by the application');
|
|
if w and $0200 <> 0
|
|
then FDetails.Add('Bit $0200 = 1: is expected to be updated on load to reflect the values in the range associated with the object')
|
|
else FDetails.Add('Bit $0200 = 0: is NOT expected to be updated on load to reflect the values in the range associated with the object');
|
|
FDetails.Add('Bit $0400 : unused');
|
|
FDetails.Add('Bit $0800 : unused');
|
|
if w and $1000 <> 0
|
|
then FDetails.Add('Bit $1000 = 1: is expected to be updated whenever the value of a cell in the range associated with the object changes')
|
|
else FDetails.Add('Bit $1000 = 0: is NOT expected to be updated whenever the value of a cell in the range associated with the object changes');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.04x', [w]),
|
|
'Flags');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowPageSetup;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
s: String;
|
|
dbl: Double;
|
|
begin
|
|
if FFormat in [sfExcel5, sfExcel8] then RowCount := FixedRows + 11
|
|
else RowCount := FixedRows + 6;
|
|
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Paper size:'#13);
|
|
FDetails.Add(Format('%d - %s', [w, PaperSizeName(w)]));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w), 'Paper size');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w), 'Scaling factor in percent');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLETON(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w), 'Start page number');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLETON(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'Fit worksheet width to this number of pages (0 = use as many as needed)');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLETON(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'Fit worksheet height to this number of pages (0 = use as many as needed)');
|
|
|
|
{ Excel4 not supported in fpspreadsheet }
|
|
{
|
|
if FFormat = sfExcel4 then begin
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLETON(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Option flags:'#13);
|
|
if w and $0001 = 0
|
|
then FDetails.Add('Bit $0001 = 0: Print pages in columns')
|
|
else FDetails.Add('Bit $0001 = 1: Print pages in rows');
|
|
if w and $0002 = 0
|
|
then FDetails.add('Bit $0002 = 0: Landscape')
|
|
else FDetails.Add('Bit $0002 = 1: Portrait');
|
|
if w and $0004 = 0
|
|
then FDetails.Add('Bit $0004 = 0: Paper size, scaling factor, and paper orientation ' +
|
|
'(portrait/landscape) ARE initialised')
|
|
else FDetails.Add('Bit $0004 = 1: Paper size, scaling factor, and paper orientation ' +
|
|
'(portrait/landscape) are NOT initialised');
|
|
if w and $0008 = 0
|
|
then FDetails.Add('Bit $0008 = 0: Print colored')
|
|
else FDetails.add('Bit $0008 = 1: Print black and white');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.4x (%d)', [w, w]),
|
|
'Option flags');
|
|
end else }
|
|
if (FFormat in [sfExcel5, sfExcel8]) then begin
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Option flags:'#13);
|
|
if w and $0001 = 0
|
|
then FDetails.Add('Bit $0001 = 0: Print pages in columns')
|
|
else FDetails.Add('Bit $0001 = 1: Print pages in rows');
|
|
if w and $0002 = 0
|
|
then FDetails.add('Bit $0002 = 0: Landscape')
|
|
else FDetails.Add('Bit $0002 = 1: Portrait');
|
|
if w and $0004 = 0
|
|
then FDetails.Add('Bit $0004 = 0: Paper size, scaling factor, and paper orientation ' +
|
|
'(portrait/landscape) ARE initialised')
|
|
else FDetails.Add('Bit $0004 = 1: Paper size, scaling factor, and paper orientation ' +
|
|
'(portrait/landscape) are NOT initialised');
|
|
if w and $0008 = 0
|
|
then FDetails.Add('Bit $0008 = 0: Print colored')
|
|
else FDetails.add('Bit $0008 = 1: Print black and white');
|
|
if w and $0010 = 0
|
|
then FDetails.Add('Bit $0010 = 0: Default print quality')
|
|
else FDetails.Add('Bit $0010 = 1: Draft quality');
|
|
if w and $0020 = 0
|
|
then FDetails.Add('Bit $0020 = 0: Do NOT print cell notes')
|
|
else FDetails.Add('Bit $0020 = 0: Print cell notes');
|
|
if w and $0040 = 0
|
|
then FDetails.Add('Bit $0040 = 0: Use paper orientation (portrait/landscape) flag abov')
|
|
else FDetails.Add('Bit $0040 = 1: Use default paper orientation (landscape for chart sheets, portrait otherwise)');
|
|
if w and $0080 = 0
|
|
then FDetails.Add('Bit $0080 = 0: Automatic page numbers')
|
|
else FDetails.Add('Bit $0080 = 1: Use start page number above');
|
|
if w and $0200 = 0
|
|
then FDetails.Add('Bit $0200 = 0: Print notes as displayed')
|
|
else FDetails.Add('Bit $0200 = 1: Print notes at end of sheet');
|
|
case (w and $0C00) shr 10 of
|
|
0: FDetails.Add('Bit $0C00 = 0: Print errors as displayed');
|
|
1: FDetails.add('Bit $0C00 = 1: Do not print errors');
|
|
2: FDetails.Add('Bit $0C00 = 2: Print errors as "--"');
|
|
3: FDetails.Add('Bit $0C00 = 4: Print errors as "#N/A"');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.4x (%d)', [w, w]),
|
|
'Option flags');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w), 'Print resolution in dpi');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w), 'Vertical print resolution in dpi');
|
|
|
|
numBytes := 8;
|
|
Move(FBuffer[FBufferIndex], dbl, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, FloatToStr(dbl), 'Header margin');
|
|
|
|
Move(FBuffer[FBufferIndex], dbl, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, FloatToStr(dbl), 'Footer margin');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w), 'Number of copies to print');
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TBIFFGrid.ShowPalette;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
dw: DWord;
|
|
npal: Integer;
|
|
i: Integer;
|
|
s: String;
|
|
begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
npal := WordLEToN(w);
|
|
|
|
RowCount := FixedRows + 1 + npal;
|
|
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(npal),
|
|
'Number of palette colors');
|
|
|
|
for i := 0 to npal-1 do begin
|
|
numbytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numBytes);
|
|
dw := DWordLEToN(dw);
|
|
s := Format('Palette color, index #%d ($%.2x)',[i, i]);
|
|
case i of
|
|
$00..$07: ;
|
|
$08..$3F: s := s + ', user-defined palette';
|
|
$40 : s := s + ', system window text color for border lines';
|
|
$41 : s := s + ', system window background color for pattern background';
|
|
$43 : s := s + ', system face color (dialogue background color)';
|
|
$4D : s := s + ', system window text colour for chart border lines';
|
|
$4E : s := s + ', system window background color for chart areas';
|
|
$4F : s := s + ', automatic color for chart border lines (seems to be always Black)';
|
|
$50 : s := s + ', system tool tip background color (used in note objects)';
|
|
$51 : s := s + ', system tool tip text color (used in note objects)';
|
|
$7FFF : s := s + ', system window text color for fonts';
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.8x', [dw]), s);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowPane;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
b: Byte;
|
|
begin
|
|
RowCount := FixedRows + IfThen(FFormat < sfExcel5, 5, 6);
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Position of vertical split (twips or columns (if frozen))');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBUfferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Position of horizontal split (twips or rows (if frozen))');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBUfferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index to first visible row in bottom pane(s)');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBUfferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index to first visible column in right pane(s)');
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBUfferIndex, numBytes, IntToStr(b),
|
|
'Identifier of pane with active cell cursor');
|
|
|
|
if FFormat >= sfExcel5 then begin
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBUfferIndex, numBytes, IntToStr(b), 'not used');
|
|
end;
|
|
end;
|
|
|
|
procedure TBIFFGrid.ShowPassword;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Password verifier for sheet or workbook:'#13);
|
|
if w = 0
|
|
then FDetails.Add('0 = No password')
|
|
else FDetails.Add(Format('$%.4x = Password verifier', [w]));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'Password verifier for sheet or workbook');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowPrecision;
|
|
var
|
|
numbytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Precision-as-displayed mode:'#13);
|
|
if w = 0
|
|
then FDetails.Add('0 = Precision-as-displayed mode selected')
|
|
else FDetails.Add('1 = Precision-as-displayed mode NOT selected');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'Precision-as-displayed mode');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowPrintGridLines;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Print sheet grid lines:'#13);
|
|
if w = 0
|
|
then FDetails.Add('0 = Do not print sheet grid lines')
|
|
else FDetails.Add('1 = Print sheet grid lines');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'Print sheet grid lines');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowPrintHeaders;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Print row/column headers');
|
|
FDetails.Add('(the area with row numbers and column letters):'#13);
|
|
if w = 0
|
|
then FDetails.Add('0 = Do not print row/column headers')
|
|
else FDetails.Add('1 = Print row/column headers');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'Print row/column headers');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowProt4Rev;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Removal of the shared workbook''s revision logs:'#13);
|
|
if w = 0
|
|
then FDetails.Add('0 = Removal of the shared workbook''s revision logs is allowed.')
|
|
else FDetails.Add('1 = Removal of the shared workbook''s revision logs is NOT allowed.');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'Removal of the shared workbook''s revision logs');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowProt4RevPass;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Password verifier needed to change the PROT4REV record:'#13);
|
|
if w = 0
|
|
then FDetails.Add('0 = No password.')
|
|
else FDetails.Add(Format('$%.04x = Password verifier.', [w]));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.4x)', [w,w]),
|
|
'Password verifier needed to change the PROT4REV record');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowProtect;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Protection state of the workbook:'#13);
|
|
if w = 0
|
|
then FDetails.Add('0 = Workbook is NOT protected.')
|
|
else FDetails.Add('1 = Workbook is protected.');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.4x', [w]),
|
|
'Protection state of the workbook');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowRecalc;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('"Recalculate before save" option:'#13);
|
|
if w = 0
|
|
then FDetails.Add('0 = Do not recalculate')
|
|
else FDetails.Add('1 = Recalculate before saving the document');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w),
|
|
'Recalculate before saving');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowRefMode;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FbufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Cell reference mode:'#13);
|
|
if w = 0
|
|
then FDetails.Add('0 = RC mode (i.e. cell address shown as "R(1)C(-1)"')
|
|
else FDetails.Add('1 = A1 mode (i.e. cell address shown as "B1")');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(w),
|
|
'Cell reference mode');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowRefreshAll;
|
|
var
|
|
numbytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('RefreshAll record:'#13);
|
|
if w = 0
|
|
then FDetails.Add('0 = Do not force refresh of external data ranges, PivotTables and XML maps on workbook load.')
|
|
else FDetails.Add('1 = Force refresh of external data ranges, PivotTables and XML maps on workbook load.');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('%d ($%.4x)', [w, w]),
|
|
'Force refresh of external data ranges, Pivot tables and XML maps on workbook load');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowRightMargin;
|
|
var
|
|
numBytes: Integer;
|
|
dbl: Double;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 8;
|
|
Move(FBuffer[FBufferIndex], dbl, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, FloatToStr(dbl),
|
|
'Right page margin in inches (IEEE 754 floating-point value, 64-bit double precision)');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowRK;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
dw: DWord;
|
|
encint: DWord;
|
|
encdbl: QWord;
|
|
dbl: Double absolute encdbl;
|
|
s: String;
|
|
begin
|
|
RowCount := FixedRows + 4;
|
|
|
|
ShowRowColData(FBufferIndex);
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index to XF record');
|
|
|
|
numBytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numBytes);
|
|
dw := DWordLEToN(dw);
|
|
|
|
if dw and $00000002 = 0 then begin
|
|
encdbl := (QWord(dw) and QWord($FFFFFFFFFFFFFFFC)) shl 32;
|
|
if dw and $00000001 = 1 then
|
|
s := Format('%.2f', [dbl*0.01])
|
|
else
|
|
s := Format('%.0f', [dbl]);
|
|
end
|
|
else begin
|
|
s := Format('$%.16x', [-59000000]);
|
|
encint := ((dw and DWord($FFFFFFFC)) shr 2) or (dw and DWord($C0000000));
|
|
// "arithmetic shift" = replace left-most bits by original bits
|
|
if dw and $00000001 = 1 then
|
|
s := FloatToStr(encint*0.01)
|
|
else
|
|
s := IntToStr(encint);
|
|
end;
|
|
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('RK Value:'#13);
|
|
if dw and $00000001 = 0
|
|
then FDetails.Add('Bit 0 = 0: Value not changed')
|
|
else FDetails.Add('Bit 0 = 1: Encoded value is multiplied by 100.');
|
|
if dw and $00000002 = 0
|
|
then FDetails.Add('Bit 1 = 0: Floating point value')
|
|
else FDetails.Add('Bit 1 = 1: Signed integer value');
|
|
FDetails.Add('Bits 31-2: Encoded value ' + s);
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes,
|
|
Format('$%.8x', [QWord(dw)]), 'RK value ['+s+']');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowRow;
|
|
var
|
|
numBytes: Integer;
|
|
dw: DWord;
|
|
w: Word;
|
|
b: Byte;
|
|
begin
|
|
RowCount := FixedRows + IfThen(FFormat = sfExcel2, 10, 7);
|
|
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index of this row');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index to column of the first cell which is described by a cell record');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index to column of the last cell which is described by a cell record, increased by 1');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Row height:'#13);
|
|
FDetails.Add(Format('Bits 14-0 = %d: Row height in twips (1/20 pt) --> %.1f-pt',
|
|
[w and $7FFF, (w and $7FFF)/20.0])
|
|
);
|
|
if w and $8000 = 0
|
|
then FDetails.Add('Bit 15 = 0: Row has custom height')
|
|
else FDetails.Add('Bit 15 = 1: Row has default height');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.4x', [w]),
|
|
'Bits 14-0: Height of row in twips (1/20 pt), Bit 15: Row has default height');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, '', '(not used)');
|
|
|
|
if FFormat = sfExcel2 then begin
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b),
|
|
'0=No defaults written, 1=Default row attribute field and XF index occur below');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Relative offset to calculate stream position of the first cell record for this row');
|
|
|
|
if b = 1 then begin
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b),
|
|
'Cell protection and XF index');
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b),
|
|
'Indexes to FORMAT and FONT records');
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b),
|
|
'Cell style');
|
|
end;
|
|
end
|
|
else begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, '',
|
|
'In BIFF5-BIFF8 this field is not used anymore, but the DBCELL record instead.');
|
|
|
|
numBytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numbytes);
|
|
dw := DWordLEToN(dw);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Option flags and default row formatting:'#13);
|
|
FDetails.Add(Format('Bits 0-2 = %d: Outline level of the row', [dw and $00000007]));
|
|
if dw and $00000010 = 0
|
|
then FDetails.Add('Bit 4 = 0: Outline group does not start or end here and is not collapsed')
|
|
else FDetails.Add('Bit 4 = 1: Outline group starts or ends here and is collapsed');
|
|
if dw and $00000020 = 0
|
|
then FDetails.Add('Bit 5 = 0: Row is NOT hidden')
|
|
else FDetails.Add('Bit 5 = 1: Row is hidden');
|
|
if dw and $00000040 = 0
|
|
then FDetails.Add('Bit 6 = 0: Row height and default font height do match.')
|
|
else FDetails.Add('Bit 6 = 1: Row height and default font height do NOT match.');
|
|
if dw and $00000080 = 0
|
|
then FDetails.Add('Bit 7 = 0: Row does NOT have explicit default format.')
|
|
else FDetails.Add('Bit 7 = 1: Row has explicit default format.');
|
|
FDetails.Add('Bit 8 = 1: Is always 1');
|
|
FDetails.Add(Format('Bits 16-27 = %d: Index to default XF record', [(dw and $0FFF0000) shr 16]));
|
|
if dw and $10000000 = 0
|
|
then FDetails.Add('Bit 28 = 0: No additional space above the row.')
|
|
else FDetails.Add('Bit 28 = 1: Additional space above the row.');
|
|
if dw and $20000000 = 0
|
|
then FDetails.Add('Bit 29 = 0: No additional space below the row.')
|
|
else FDetails.Add('Bit 29 = 1: Additional space below the row.');
|
|
if dw and $40000000 = 0
|
|
then FDetails.Add('Bit 30 = 0: D0 NOT show phonetic text for all cells in the row.')
|
|
else FDetails.Add('Bit 30 = 1: Show phonetic text for all cells in the row.');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.8x', [dw]),
|
|
'Option flags and default row formatting');
|
|
end;
|
|
end;
|
|
|
|
procedure TBIFFGrid.ShowRowColData(var ABufIndex: LongWord);
|
|
var
|
|
w: Word;
|
|
numBytes: Integer;
|
|
begin
|
|
// Row
|
|
numBytes := 2;
|
|
Move(FBuffer[ABufIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, ABufIndex, numBytes, IntToStr(WordLEToN(w)), 'Index to row');
|
|
// Column
|
|
numBytes := 2;
|
|
Move(FBuffer[ABufIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, ABufIndex, numBytes, IntToStr(WordLEToN(w)), 'Index to column');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowSelection;
|
|
var
|
|
numBytes: Integer;
|
|
w: word;
|
|
b: Byte;
|
|
i, n: Integer;
|
|
begin
|
|
Move(FBuffer[FBufferIndex+7], w, 2);
|
|
n := WordLEToN(w);
|
|
|
|
RowCount := FixedRows + 5 + n*4;
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b), 'Pane identifier (see PANE record)');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index to row of the active cell');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index to column of the active cell');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index into the following cell range list to the entry that contains the active cell');
|
|
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(n),
|
|
'Number of following cell range addresses');
|
|
|
|
numbytes := 2;
|
|
for i:=1 to n do begin
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)), 'Index to first row');
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)), 'Index to last row');
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b), 'Index to first column');
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b), 'Index to last column');
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowSharedFormula;
|
|
var
|
|
numBytes: Integer;
|
|
b: Byte;
|
|
w: Word;
|
|
tokenBytes: Integer;
|
|
begin
|
|
BeginUpdate;
|
|
RowCount := FixedRows + 1000;
|
|
// Brute force simplification because of unknown row count at this point
|
|
// Will be reduced at the end.
|
|
|
|
// Index to first row
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)), 'Index to first row');
|
|
|
|
// Index to last row
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)), 'Index to last row');
|
|
|
|
// Index to first column
|
|
numBytes := 1; // 8-bit also for BIFF8!
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b), 'Index to first column');
|
|
|
|
// Index to last column
|
|
numBytes := 1; // 8-bit also for BIFF8!
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b), 'Index to last column');
|
|
|
|
// Not used
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b), 'Not used');
|
|
|
|
// Number of existing FORMULA records for this shared formula
|
|
numBytes := 1;
|
|
Move(FBuffer[FBufferIndex], b, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b), 'Number of FORMULA records in shared formula');
|
|
|
|
// Size of Token array (in Bytes)
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
tokenBytes := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(tokenBytes),
|
|
'Size of formula data (in Bytes)');
|
|
|
|
// Formula tokens
|
|
ShowFormulaTokens(tokenBytes);
|
|
|
|
RowCount := FCurrRow;
|
|
EndUpdate(true);
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowSheet;
|
|
var
|
|
numBytes: Integer;
|
|
dw: DWord;
|
|
b: Byte;
|
|
s: String;
|
|
begin
|
|
RowCount := FixedRows + 4;
|
|
|
|
numBytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numBytes);
|
|
dw := DWordLEToN(dw);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.8x)', [dw, dw]),
|
|
'Absolute stream position of BOF record of sheet represented by this record.');
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(b),
|
|
'Sheet state (0=visible, 1=hidden, 2="very" hidden)');
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [b]),
|
|
'Sheet type ($00=worksheet, $02=Chart, $06=VB module)');
|
|
|
|
ExtractString(FBufferIndex, 1, (FFormat = sfExcel8), s, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s, IfThen(FFormat=sfExcel8,
|
|
'Sheet name (unicode string, 8-bit string length)',
|
|
'Sheet name (byte string, 8-bit string length)')
|
|
);
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowSheetPR;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Option flags:'#13);
|
|
if w and $0001 = 0
|
|
then FDetails.Add('Bit $0001 = 0: Do not show automatic page breaks')
|
|
else FDetails.Add('Bit $0001 = 1: Show automatic page breaks');
|
|
if w and $0010 = 0
|
|
then FDetails.Add('Bit $0010 = 0: Standard sheet')
|
|
else FDetails.Add('Bit $0010 = 1: Dialog sheet (BIFF5-BIFF8)');
|
|
if w and $0020 = 0
|
|
then FDetails.Add('Bit $0020 = 0: No automatic styles in outlines')
|
|
else FDetails.Add('Bit $0020 = 1: Apply automatic styles to outlines');
|
|
if w and $0040 = 0
|
|
then FDetails.Add('Bit $0040 = 0: Outline buttons above outline group')
|
|
else FDetails.Add('Bit $0040 = 1: Outline buttons below outline group');
|
|
if w and $0080 = 0
|
|
then FDetails.Add('Bit $0080 = 0: Outline buttons left of outline group')
|
|
else FDetails.Add('Bit $0080 = 1: Outline buttons right of outline group');
|
|
if w and $0100 = 0
|
|
then FDetails.Add('Bit $0100 = 0: Scale printout in percent')
|
|
else FDetails.Add('Bit $0100 = 1: Fit printout to number of pages');
|
|
if w and $0200 = 0
|
|
then FDetails.Add('Bit $0200 = 0: Save external linked values (BIFF3-BIFF4 only)')
|
|
else FDetails.Add('Bit $0200 = 1: Do NOT save external linked values (BIFF3-BIFF4 only)');
|
|
if w and $0400 = 0
|
|
then FDetails.Add('Bit $0400 = 0: Do not show row outline symbols')
|
|
else FDetails.Add('Bit $0400 = 1: Show row outline symbols');
|
|
if w and $0800 = 0
|
|
then FDetails.Add('Bit $0800 = 0: Do not show column outline symbols')
|
|
else FDetails.Add('Bit $0800 = 1: Show column outline symbols');
|
|
case (w and $3000) shr 12 of
|
|
0: FDetails.Add('Bits $3000 = $0000: Arrange windows tiled');
|
|
1: FDetails.Add('Bits $3000 = $1000: Arrange windows horizontal');
|
|
2: FDetails.Add('Bits $3000 = $2000: Arrange windows vertical');
|
|
3: FDetails.Add('Bits $3000 = $3000: Arrange windows cascaded');
|
|
end;
|
|
if w and $4000 = 0
|
|
then FDetails.Add('Bits $4000 = 0: Excel like expression evaluation (BIFF4-BIFF8 only)')
|
|
else FDetails.Add('Bits $4000 = 1: Lotus like expression evaluation (BIFF4-BIFF8 only)');
|
|
if w and $8000 = 0
|
|
then FDetails.Add('Bits $8000 = 0: Excel like formula editing (BIFF4-BIFF8 only)')
|
|
else FDetails.Add('Bits $8000 = 1: Lotus like formula editing (BIFF4-BIFF8 only)');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.4x (%d)', [w, w]),
|
|
'Option flags');
|
|
end;
|
|
|
|
procedure TBIFFGrid.ShowSST;
|
|
var
|
|
numBytes: Integer;
|
|
s: String;
|
|
total1, total2: DWord;
|
|
i: Integer;
|
|
begin
|
|
numBytes := 4;
|
|
Move(FBuffer[FBufferIndex], total1, numBytes);
|
|
Move(FBuffer[FBufferIndex+4], total2, numBytes);
|
|
total1 := DWordLEToN(total1);
|
|
total2 := DWordLEToN(total2);
|
|
|
|
RowCount := FixedRows + 2 + total2;
|
|
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(total1),
|
|
'Total number of shared strings in the workbook');
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(total2),
|
|
'Number of following strings');
|
|
|
|
for i:=1 to total2 do begin
|
|
ExtractString(FBufferIndex, 2, true, s, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s, Format('Shared string #%d', [i]));
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowStandardWidth;
|
|
var
|
|
w: Word;
|
|
numBytes: Integer;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d (%f characters)', [w, w/256]),
|
|
'Default column width (overrides DFCOLWIDTH, in 1/256 of "0" width)');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowString;
|
|
var
|
|
numBytes: Integer;
|
|
s: String;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
case FFormat of
|
|
sfExcel2:
|
|
begin
|
|
ExtractString(FBufferIndex, 1, false, s, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s, 'Byte string, 8-bit string length');
|
|
end;
|
|
sfExcel5:
|
|
begin
|
|
ExtractString(FBufferIndex, 2, false, s, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s, 'Byte string, 16-bit string length');
|
|
end;
|
|
sfExcel8:
|
|
begin
|
|
ExtractString(FBufferIndex, 2, true, s, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s, 'Unicode string, 16-bit string length');
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowStyle;
|
|
var
|
|
numBytes: Integer;
|
|
b: Byte;
|
|
w: Word;
|
|
s: String;
|
|
isRowLevel: Boolean;
|
|
isColLevel: Boolean;
|
|
begin
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
if w and $8000 = 0 then
|
|
RowCount := FixedRows + 2
|
|
else
|
|
RowCount := FixedRows + 3;
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Style:'#13);
|
|
FDetails.Add(Format('Bits 0-11 = %d: Index to style XF record', [w and $0FFFF]));
|
|
if w and $8000 = 0
|
|
then FDetails.Add('Bit 15 = 0: user-defined style')
|
|
else FDetails.Add('Bit 15 = 1: built-in style');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.4x', [w]), 'Style index and type');
|
|
|
|
if w and $8000 = 0 then begin
|
|
if FFormat = sfExcel8 then begin
|
|
ExtractString(FBufferIndex, 2, true, s, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s, 'Style name (Unicode string, 16-bit string length)');
|
|
end else begin
|
|
ExtractString(FBufferIndex, 1, false, s, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, s, 'Style name (Byte string, 8-bit string length)');
|
|
end;
|
|
end else begin
|
|
numbytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
isRowLevel := (b = 1);
|
|
isColLevel := (b = 2);
|
|
if FCurrRow = Row then begin
|
|
FDetails.Add('Identifier for built-in cell style:'#13);
|
|
case b of
|
|
0: FDetails.Add('0 = normal');
|
|
1: FDetails.Add('1 = RowLevel (see next field)');
|
|
2: FDetails.Add('2 = ColLevel (see next field)');
|
|
3: FDetails.Add('3 = Comma');
|
|
4: FDetails.Add('4 = Currency');
|
|
5: FDetails.Add('5 = Percent');
|
|
6: FDetails.Add('6 = Comma [0]');
|
|
7: FDetails.Add('7 = Currency [0]');
|
|
8: FDetails.Add('8 = Hyperlink');
|
|
9: FDetails.Add('9 = Followed hyperlink');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b),
|
|
'Identifier for built-in cell style');
|
|
|
|
b := FBuffer[FBufferIndex];
|
|
if FCurrRow = Row then begin
|
|
FDetails.Add('Level for RowLevel or ColLevel style (zero-based):'#13);
|
|
if b = $FF then
|
|
FDetails.Add('$FF = no RowLevel or ColLevel style')
|
|
else
|
|
if isRowLevel then
|
|
FDetails.Add('RowLevel = ' + IntToStr(b))
|
|
else if isColLevel then
|
|
FDetails.Add('ColLevel = ' + IntToStr(b));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(b),
|
|
'Level for RowLevel or ColLevel style (if available)');
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowStyleExt;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
b: Byte;
|
|
bs: Byte;
|
|
s: String;
|
|
begin
|
|
RowCount := FixedRows + 11;
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.4x', [wordLEToN(w)]),
|
|
'Future record type');
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Attributes:'#13);
|
|
if w and $0001 = 0
|
|
then FDetails.Add('Bit 0 = 0: The containing record does not specify a range of cells.')
|
|
else FDetails.Add('Bit 0 = 1: The containing record specifies a range of cells.');
|
|
FDetails.Add('Bit 1: specifies wether to alert the user of possible problems '+
|
|
'when saving the file whithout having reckognized this record.');
|
|
FDetails.Add('Bits 2-15: reserved (MUST be zero, MUST be ignored)');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.4x', [w]),
|
|
'Attributes');
|
|
numbytes := 8;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, '', 'Reserved');
|
|
|
|
numbytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Flags:'#13);
|
|
if b and $01 = 0
|
|
then FDetails.Add('Bit 0 = 0: no built-in style')
|
|
else FDetails.Add('Bit 0 = 1: built-in style');
|
|
if b and $02 = 0
|
|
then FDetails.Add('Bit 1 = 0: NOT hidden')
|
|
else FDetails.Add('Bit 1 = 1: hidden (i.e. is displayed in user interface)');
|
|
FDetails.Add('Bit 2: specifies whether the built-in cell style was modified '+
|
|
'by the user and thus has a custom definition.');
|
|
FDetails.Add('Bit 3-7: Reserved');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [b]), 'Flags');
|
|
|
|
numbytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Category:'#13);
|
|
case b of
|
|
0: FDetails.Add('Bits 0-7 = 0: Custom style');
|
|
1: FDetails.Add('Bits 0-7 = 1: Good, bad, neutral style');
|
|
2: FDetails.Add('Bits 0-7 = 2: Data model style');
|
|
3: FDetails.Add('Bits 0-7 = 3: Title and heading style');
|
|
4: FDetails.Add('Bits 0-7 = 4: Themed cell style');
|
|
5: FDetails.Add('Bits 0-7 = 5: Number format style');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [b]), 'Category');
|
|
|
|
numbytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Built-in style:'#13);
|
|
FDetails.Add('An unsigned integer that specifies the type of the built-in cell style.');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [b]), 'Built-in style');
|
|
bs := b;
|
|
|
|
numbytes := 1;
|
|
b := FBuffer[FBufferindex];
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Outline depth level:'#13);
|
|
FDetails.Add('An unsigned integer that specifies the depth level of row/column automatic outlining.');
|
|
if (bs in [1, 2]) then
|
|
FDetails.Add(Format('Bits 0-7 = %d: Outline level is %d', [b, b+1]))
|
|
else
|
|
FDetails.Add(Format('Bits 0-7 = $%.2x: MUST be $FF, MUST be ignoried', [b]));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.2x', [b]), 'Outline depth level');
|
|
|
|
ExtractString(FBufferIndex, 1, true, s, numBytes, true);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, s, 'Name of the style name to extend (Unicode string, 8-bit string length)');
|
|
|
|
numbytes := 2;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, '', 'XFProps (reserved)');
|
|
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(w), 'Count of XFProp structures to follow in array');
|
|
|
|
|
|
end;
|
|
|
|
|
|
procedure TBiffGrid.ShowTabID;
|
|
var
|
|
numbytes: Integer;
|
|
w: word;
|
|
i, n: Integer;
|
|
begin
|
|
numbytes := 2;
|
|
n := Length(FBuffer) div numbytes;
|
|
RowCount := FixedRows + n;
|
|
for i := 1 to n do begin
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('%d ($%.4x)', [w, w]),
|
|
'Unique sheet identifier');
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowTopMargin;
|
|
var
|
|
numBytes: Integer;
|
|
dbl: Double;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 8;
|
|
Move(FBuffer[FBufferIndex], dbl, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, FloatToStr(dbl),
|
|
'Top page margin in inches (IEEE 754 floating-point value, 64-bit double precision)');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowWindow1;
|
|
var
|
|
numBytes: Word;
|
|
b: Byte;
|
|
w: word;
|
|
begin
|
|
RowCount := FixedRows + IfThen(FFormat < sfExcel5, 5, 9);
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Horizontal position of the document window (in twips = 1/20 pt)');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Vertical position of the document window (in twips = 1/20 pt)');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Width of the document window (in twips = 1/20 pt)');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Height of the document window (in twips = 1/20 pt)');
|
|
|
|
if FFormat < sfExcel5 then begin
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(b)),
|
|
'0 = Window is visible; 1 = window is hidden');
|
|
end else begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Option flags:');
|
|
if w and $0001 = 0
|
|
then FDetails.Add('Bit $0001 = 0: Window is visible')
|
|
else FDetails.Add('Bit $0001 = 1: Window is hidden');
|
|
if w and $0002 = 0
|
|
then FDetails.Add('Bit $0002 = 0: Window is open')
|
|
else FDetails.Add('Bit $0002 = 1: Window is minimized');
|
|
if w and $0008 = 0
|
|
then FDetails.Add('Bit $0008 = 0: Horizontal scrollbar hidden')
|
|
else FDetails.Add('Bit $0008 = 1: Horizontal scrollbar visible');
|
|
if w and $0010 = 0
|
|
then FDetails.Add('Bit $0010 = 0: Vertical scrollbar hidden')
|
|
else FDetails.Add('Bit $0010 = 1: Vertical scrollbar visible');
|
|
if w and $0020 = 0
|
|
then FDetails.Add('Bit $0020 = 0: Worksheet tab bar hidden')
|
|
else FDetails.Add('Bit $0020 = 1: Worksheet tab bar visible');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('%d ($%.4x)', [w, w]),
|
|
'Option flags');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Index to active (displayed) worksheet');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Index of first visible tab in the worksheet tab bar');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Number of selected worksheets (highlighted in the worksheet tab bar)');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Width of worksheet tab bar (in 1/1000 of window width). '+
|
|
'The remaining space is used by the horizontal scrollbar.');
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowWindow2;
|
|
var
|
|
numBytes: Word;
|
|
b: Byte;
|
|
w: word;
|
|
dw : DWord;
|
|
begin
|
|
if FFormat = sfExcel2 then begin
|
|
RowCount := FixedRows + 9;
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(b),
|
|
'0 = Show formula results; 1 = Show formulas');
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(b),
|
|
'0 = Do not show grid lines; 1 = Show grid lines');
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(b),
|
|
'0 = Do not show sheet headers; 1 = Show sheet headers');
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(b),
|
|
'0 = Panes are not frozen; 1 = Panes are frozen');
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(b),
|
|
'0 = Show zero values as empty cells; 1 = Show zero values');
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Index to first visible row');
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Index to first visible column');
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(b),
|
|
'0 = Use manual grid line colour (below); 1 = Use automatic grid line colour');
|
|
numbytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.8x', [DWordLEToN(dw)]),
|
|
'Grid line RGB color');
|
|
end else begin
|
|
RowCount := FixedRows + IfThen(FFormat = sfExcel5, 4, 8);
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Option flags:');
|
|
if w and $0001 = 0
|
|
then FDetails.Add('Bit $0001 = 0: Show formula results')
|
|
else FDetails.Add('Bit $0001 = 1: Show formulas');
|
|
if w and $0002 = 0
|
|
then FDetails.Add('Bit $0002 = 0: Do not show grid lines')
|
|
else FDetails.Add('Bit $0002 = 1: Show grid lines');
|
|
if w and $0004 = 0
|
|
then FDetails.Add('Bit $0004 = 0: Do not show sheet headers')
|
|
else FDetails.Add('Bit $0004 = 1: Show sheet headers');
|
|
if w and $0008 = 0
|
|
then FDetails.Add('Bit $0008 = 0: Panes are not frozen')
|
|
else FDetails.Add('Bit $0008 = 1: Panes are frozen');
|
|
if w and $0010 = 0
|
|
then FDetails.Add('Bit $0010 = 0: Show zero values as empty cells')
|
|
else FDetails.Add('Bit $0010 = 1: Show zero values');
|
|
if w and $0020 = 0
|
|
then FDetails.Add('Bit $0020 = 0: Manual grid line color')
|
|
else FDetails.Add('Bit $0020 = 1: Automatic grid line color');
|
|
if w and $0040 = 0
|
|
then FDetails.Add('Bit $0040 = 0: Columns from left to right')
|
|
else FDetails.Add('Bit $0040 = 1: Columns from right to left');
|
|
if w and $0080 = 0
|
|
then FDetails.Add('Bit $0080 = 0: Do not show outline symbols')
|
|
else FDetails.Add('Bit $0080 = 1: Show outline symbols');
|
|
if w and $0100 = 0
|
|
then FDetails.Add('Bit $0100 = 0: Keep splits if pane freeze is removed')
|
|
else FDetails.Add('Bit $0100 = 1: Remove splits if pane freeze is removed');
|
|
if w and $0200 = 0
|
|
then FDetails.Add('Bit $0200 = 0: Sheet not selected')
|
|
else FDetails.Add('Bit $0200 = 1: Sheet selected');
|
|
if w and $0400 = 0
|
|
then FDetails.Add('Bit $0400 = 0: Sheet not active')
|
|
else FDetails.Add('Bit $0400 = 1: Sheet active');
|
|
if w and $0800 = 0
|
|
then FDetails.Add('Bit $0800 = 0: Show in normal view')
|
|
else FDetails.Add('Bit $0800 = 1: Show in page break preview');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('%d ($%.4x)', [w, w]),
|
|
'Option flags');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Index to first visible row');
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Index to first visible column');
|
|
|
|
if FFormat =sfExcel5 then begin
|
|
numbytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.8x', [DWordLEToN(dw)]),
|
|
'Grid line RGB color');
|
|
end else begin
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Color index of grid line color');
|
|
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, '', 'Not used');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Cached magnification factor in page break preview (in percent); 0 = Default (60%)');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)),
|
|
'Cached magnification factor in normal view (in percent); 0 = Default (100%)');
|
|
|
|
numBytes := 4;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, '', 'Not used');
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowWindowProtect;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Protection state of workbook windows:'#13);
|
|
if w = 0
|
|
then FDetails.Add('0 = The workbook windows can be resized or moved and the window state can be changed.')
|
|
else FDetails.Add('1 = The workbook windows cannot be resized or moved and the window state cannot be changed.');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.4x', [w]),
|
|
'Protection state of the workbook windows');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowWriteAccess;
|
|
var
|
|
numbytes: Integer;
|
|
s: String;
|
|
begin
|
|
RowCount := FixedRows + 1;
|
|
ExtractString(FBufferIndex, IfThen(FFormat=sfExcel8, 2, 1), FFormat=sfExcel8, s, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, s, 'User name (i.e., the name that you type when you install Microsoft Excel');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowWriteProt;
|
|
begin
|
|
RowCount := FixedRows + 2;
|
|
ShowInRow(FCurrRow, FBufferIndex, 0, '', 'Write protect: if present file is write-protected');
|
|
ShowInRow(FCurrRow, FBufferIndex, 0, '', 'Write protection password is in FILESHARING record');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowXF;
|
|
var
|
|
numBytes: Word;
|
|
b: Byte;
|
|
w: word;
|
|
dw : DWord;
|
|
begin
|
|
if FFormat = sfExcel2 then begin
|
|
RowCount := FixedRows + 4;
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(b),
|
|
'Index to font record');
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, '',
|
|
'(not used)');
|
|
|
|
b := FBuffer[FBufferIndex];
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Number format and cell flags:'#13);
|
|
FDetails.Add(Format('Bits 0-5 = %d: Index to FORMAT record', [b and $3F]));
|
|
if b and $40 = 0
|
|
then FDetails.Add('Bit 6 = 0: Cell is not locked')
|
|
else FDetails.Add('Bit 6 = 1: Cell is locked');
|
|
if b and $80 = 0
|
|
then FDetails.Add('Bit 7 = 0: Formula is not hidden')
|
|
else FDetails.Add('Bit 7 = 1: Formula is hidden');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d ($%.2x)', [b, b]),
|
|
'Number format and cell flags');
|
|
|
|
b := FBuffer[FBufferIndex];
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Horizontal alignment, border style and background:'#13);
|
|
case b and $07 of
|
|
0: FDetails.Add('Bits $07 = 0: Horizontal alignment "General"');
|
|
1: FDetails.Add('Bits $07 = 1: Horizontal alignment "Left"');
|
|
2: FDetails.Add('Bits $07 = 2: Horizontal alignemnt "Centered"');
|
|
3: FDetails.Add('Bits $07 = 3: Horizontal alignment "Right"');
|
|
4: FDetails.Add('Bits $07 = 4: Horizontal alignment "Filled"');
|
|
5: FDetails.Add('Bits $07 = 5: Horizontal alignment "Justified"');
|
|
6: FDetails.Add('Bits $07 = 6: Horizontal alignment "Centred across selection"');
|
|
7: FDetails.Add('Bits $07 = 7: Horizontal alignment "Distributed"');
|
|
end;
|
|
if b and $08 = 0
|
|
then FDetails.Add('Bit $08 = 0: Cell has no left border')
|
|
else FDetails.Add('Bit $08 = 1: Cell has left black border');
|
|
if b and $10 = 0
|
|
then FDetails.Add('Bit $10 = 0: Cell has no right border')
|
|
else FDetails.Add('Bit $10 = 1: Cell has right black border');
|
|
if b and $20 = 0
|
|
then FDetails.Add('Bit $20 = 0: Cell has no top border')
|
|
else FDetails.Add('Bit $20 = 1: Cell has top black border');
|
|
if b and $40 = 0
|
|
then FDetails.Add('Bit $40 = 0: Cell has no bottom border')
|
|
else FDetails.Add('Bit $40 = 1: Cell has bottom black border');
|
|
if b and $80 = 0
|
|
then FDetails.Add('Bit $80 = 0: Cell has no shaded background')
|
|
else FDetails.Add('Bit $80 = 1: Cell has shaded background');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [b]),
|
|
'Horizontal alignment, border style, and background');
|
|
end
|
|
else
|
|
begin // XF (BIFF5 and BIFF8)
|
|
RowCount := FixedRows + IfThen(FFormat=sfExcel5, 7, 10);
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index to font record');
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(WordLEToN(w)),
|
|
'Index to format record');
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('XFType, cell protection, parent style XF:'#13);
|
|
if w and $0001 = 0
|
|
then FDetails.Add('Bit $0001 = 0: Cell is not locked')
|
|
else FDetails.Add('Bit $0001 = 1: Cell is locked');
|
|
if w and $0002 = 0
|
|
then FDetails.Add('Bit $0002 = 0: Formula is not hidden')
|
|
else FDetails.Add('Bit $0002 = 1: Formula is hidden');
|
|
if w and $0004 = 0
|
|
then FDetails.Add('Bit $0004 = 0: Cell XF')
|
|
else FDetails.Add('Bit $0004 = 1: Style XF');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.4x', [w]),
|
|
'XFType, cell protection, parent style XF');
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Alignment and text break:'#13);
|
|
case b and $03 of
|
|
0: FDetails.Add('Bits 0-2 = 0: Horizontal alignment "General"');
|
|
1: FDetails.Add('Bits 0-2 = 1: Horizontal alignment "Left"');
|
|
2: FDetails.Add('Bits 0-2 = 2: Horizontal alignemnt "Centered"');
|
|
3: FDetails.Add('Bits 0-2 = 3: Horizontal alignment "Right"');
|
|
4: FDetails.Add('Bits 0-2 = 4: Horizontal alignment "Filled"');
|
|
5: FDetails.Add('Bits 0-2 = 5: Horizontal alignment "Justified"');
|
|
6: FDetails.Add('Bits 0-2 = 6: Horizontal alignment "Centred across selection"');
|
|
7: if FFormat = sfExcel8 then
|
|
FDetails.Add('Bits 0-2 = 7: Horizontal alignment "Distributed"');
|
|
end;
|
|
if b and $08 = 0
|
|
then FDetails.Add('Bit 3 = 0: Text is not wrapped.')
|
|
else FDetails.Add('Bit 3 = 1: Text is wrapped at right border.');
|
|
case (b and $70) shr 4 of
|
|
0: FDetails.Add('Bits 4-6 = 0: Vertical alignment "Top"');
|
|
1: FDetails.Add('Bits 4-6 = 1: Vertical alignment "Centered"');
|
|
2: FDetails.Add('Bits 4-6 = 2: Vertical alignment "Bottom"');
|
|
3: FDetails.Add('Bits 4-6 = 3: Vertical alignment "Justified"');
|
|
4: if FFormat = sfExcel8 then
|
|
FDetails.Add('Bits 4-6 = 4: Vertical alignment "Distributed"');
|
|
end;
|
|
if FFormat = sfExcel8 then begin
|
|
if b and $80 = 0
|
|
then FDetails.Add('Bit 3 = 0: Don''t justify last line in justified or distibuted text')
|
|
else FDetails.Add('Bit 3 = 1: Justify last line in justified or distibuted text');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [b]),
|
|
'Alignment and text break');
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
if FFormat = sfExcel5 then begin
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Text orientation and flags for used attribute groups:'#13);
|
|
case (b and $03) of
|
|
0: FDetails.Add('Bits $03 = 0: not rotated');
|
|
1: FDetails.Add('Bits $03 = 1: not rotated, letters stacked top-to-bottom');
|
|
2: FDetails.Add('Bits $03 = 2: text rotated 90° counter-clockwise');
|
|
3: FDetails.Add('Bits $03 = 3: text rotated 90° clockwise');
|
|
end;
|
|
if b and $04 = 0
|
|
then FDetails.Add('Bit $04 = 0: No flag for number format')
|
|
else FDetails.Add('Bit $04 = 1: Flag for number format');
|
|
if b and $08 = 0
|
|
then FDetails.Add('Bit $08 = 0: No flag for font')
|
|
else FDetails.Add('Bit $08 = 2: Flag for font');
|
|
if b and $10 = 0
|
|
then FDetails.Add('Bit $10 = 0: No flag for hor/vert alignment, text wrap, indentation, orientation, rotation, and text direction')
|
|
else FDetails.Add('Bit $10 = 1: Flag for hor/vert alignment, text wrap, indentation, orientation, rotation, and text direction');
|
|
if b and $20 = 0
|
|
then FDetails.Add('Bit $20 = 0: No flag for border lines')
|
|
else FDetails.Add('Bit $20 = 1: Flag for border lines');
|
|
if b and $40 = 0
|
|
then FDetails.Add('Bit $40 = 0: No flag for background area style')
|
|
else FDetails.Add('Bit $40 = 1: Flag for background area style');
|
|
if b and $80 = 0
|
|
then FDetails.Add('Bit $80 = 0: No flag for cell protection (cell locked and formula hidden)')
|
|
else FDetails.Add('Bit $80 = 1: Flag for cell protection (cell locked and formula hidden)');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.2x', [b]),
|
|
'Text orientation and flags for used attribute groups');
|
|
end else
|
|
begin // sfExcel8
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Text rotation angle:'#13);
|
|
if b = 0 then
|
|
FDetails.Add('not rotated')
|
|
else if b <= 90 then
|
|
FDetails.Add(Format('%d degrees counter-clockwise', [b]))
|
|
else if b <= 180 then
|
|
FDetails.Add(Format('%d degrees clockwize', [b-90]))
|
|
else if b = 255 then
|
|
FDetails.Add('not rotated, letters stacked top-to-bottom');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(b), 'Text rotation angle');
|
|
end;
|
|
|
|
if FFormat = sfExcel8 then begin
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Indentation, shrink to cell size, and text direction:'#13);
|
|
FDetails.Add(Format('Bits 0-3: Indent level = %d', [b and $0F]));
|
|
if b and $10 = 0
|
|
then FDetails.Add('Bit $10 = 0: Don''t shrink content to fit into cell')
|
|
else FDetails.Add('Bit $10 = 1: Shrink content to fit into cell');
|
|
if b and $20 = 0
|
|
then FDetails.Add('Bit $20 = 0: Merge Cell option is OFF')
|
|
else FDetails.Add('Bit $20 = 1: Merge Cell option is ON');
|
|
case (b and $C0) shr 6 of
|
|
0: FDetails.Add('Bits 6-7 = 0: Text direction according to context');
|
|
1: FDetails.Add('Bits 6-7 = 1: Text direction left-to-right');
|
|
2: FDetails.Add('Bits 6-7 = 2: Text direction right-to-left');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [b]),
|
|
'Indentation, shrink to cell size, and text direction');
|
|
|
|
numBytes := 1;
|
|
b := FBuffer[FBufferIndex];
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Flags for used attribute groups:'#13);
|
|
if b and $04 = 0
|
|
then FDetails.Add('Bit $04 = 0: No flag for number format')
|
|
else FDetails.Add('Bit $04 = 1: Flag for number format');
|
|
if b and $08 = 0
|
|
then FDetails.Add('Bit $08 = 0: No flag for font')
|
|
else FDetails.Add('Bit $08 = 2: Flag for font');
|
|
if b and $10 = 0
|
|
then FDetails.Add('Bit $10 = 0: No flag for hor/vert alignment, text wrap, indentation, orientation, rotation, and text direction')
|
|
else FDetails.Add('Bit $10 = 1: Flag for hor/vert alignment, text wrap, indentation, orientation, rotation, and text direction');
|
|
if b and $20 = 0
|
|
then FDetails.Add('Bit $20 = 0: No flag for border lines')
|
|
else FDetails.Add('Bit $20 = 1: Flag for border lines');
|
|
if b and $40 = 0
|
|
then FDetails.Add('Bit $40 = 0: No flag for background area style')
|
|
else FDetails.Add('Bit $40 = 1: Flag for background area style');
|
|
if b and $80 = 0
|
|
then FDetails.Add('Bit $80 = 0: No flag for cell protection (cell locked and formula hidden)')
|
|
else FDetails.Add('Bit $80 = 1: Flag for cell protection (cell locked and formula hidden)');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.2x', [b]),
|
|
'Flags for used attribute groups');
|
|
|
|
numBytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numbytes);
|
|
dw := DWordLEToN(dw);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Cell border lines and background area:'#13);
|
|
case dw and $0000000F of
|
|
$0000: FDetails.Add('Bits 0-3 = 0: Left border = No line');
|
|
$0001: FDetails.Add('Bits 0-3 = 1: Left border = thin solid line');
|
|
$0002: FDetails.Add('Bits 0-3 = 2: Left border = medium solid line');
|
|
$0003: FDetails.Add('Bits 0-3 = 3: Left border = dashed line');
|
|
$0004: FDetails.Add('Bits 0-3 = 4: Left border = dotted line');
|
|
$0005: FDetails.Add('Bits 0-3 = 5: Left border = thick solid line');
|
|
$0006: FDetails.Add('Bits 0-3 = 6: Left border = double solid line');
|
|
$0007: FDetails.Add('Bits 0-3 = 7: Left border = hair line');
|
|
$0008: FDetails.Add('Bits 0-3 = 8: Left border = medium dashed');
|
|
$0009: FDetails.Add('Bits 0-3 = 9: Left border = thin dash-dotted');
|
|
$000A: FDetails.Add('Bits 0-3 = 10: Left border = medium dash-dotted');
|
|
$000B: FDetails.Add('Bits 0-3 = 11: Left border = thin dash-dot-dotted');
|
|
$000C: FDetails.Add('Bits 0-3 = 12: Left border = medium dash-dot-dotted');
|
|
$000D: FDetails.Add('Bits 0-3 = 13: Left border = slanted medium dash-dotted');
|
|
end;
|
|
case dw and $000000F0 of
|
|
$0000: FDetails.Add('Bits 4-7 = 0: Right border = No line');
|
|
$0010: FDetails.Add('Bits 4-7 = 1: Right border = thin solid line');
|
|
$0020: FDetails.Add('Bits 4-7 = 2: Right border = medium solid line');
|
|
$0030: FDetails.Add('Bits 4-7 = 3: Right border = dashed line');
|
|
$0040: FDetails.Add('Bits 4-7 = 4: Right border = dotted line');
|
|
$0050: FDetails.Add('Bits 4-7 = 5: Right border = thick solid line');
|
|
$0060: FDetails.Add('Bits 4-7 = 6: Right border = double solid line');
|
|
$0070: FDetails.Add('Bits 4-7 = 7: Right border = hair line');
|
|
$0080: FDetails.Add('Bits 4-7 = 8: Right border = medium dashed');
|
|
$0090: FDetails.Add('Bits 4-7 = 9: Right border = thin dash-dotted');
|
|
$00A0: FDetails.Add('Bits 4-7 = 10: Right border = medium dash-dotted');
|
|
$00B0: FDetails.Add('Bits 4-7 = 11: Right border = thin dash-dot-dotted');
|
|
$00C0: FDetails.Add('Bits 4-7 = 12: Right border = medium dash-dot-dotted');
|
|
$00D0: FDetails.Add('Bits 4-7 = 13: Right border = slanted medium dash-dotted');
|
|
end;
|
|
case dw and $00000F00 of
|
|
$0000: FDetails.Add('Bits 8-11 = 0: Top border = No line');
|
|
$0100: FDetails.Add('Bits 8-11 = 1: Top border = thin solid line');
|
|
$0200: FDetails.Add('Bits 8-11 = 2: Top border = medium solid line');
|
|
$0300: FDetails.Add('Bits 8-11 = 3: Top border = dashed line');
|
|
$0400: FDetails.Add('Bits 8-11 = 4: Top border = dotted line');
|
|
$0500: FDetails.Add('Bits 8-11 = 5: Top border = thick solid line');
|
|
$0600: FDetails.Add('Bits 8-11 = 6: Top border = double solid line');
|
|
$0700: FDetails.Add('Bits 8-11 = 7: Top border = hair line');
|
|
$0800: FDetails.Add('Bits 8-11 = 8: Top border = medium dashed');
|
|
$0900: FDetails.Add('Bits 8-11 = 9: Top border = thin dash-dotted');
|
|
$0A00: FDetails.Add('Bits 8-11 = 10: Top border = medium dash-dotted');
|
|
$0B00: FDetails.Add('Bits 8-11 = 11: Top border = thin dash-dot-dotted');
|
|
$0C00: FDetails.Add('Bits 8-11 = 12: Top border = medium dash-dot-dotted');
|
|
$0D00: FDetails.Add('Bits 8-11 = 13: Top border = slanted medium dash-dotted');
|
|
end;
|
|
case dw and $0000F000 of
|
|
$0000: FDetails.Add('Bits 12-15 = 0: Bottom border = No line');
|
|
$1000: FDetails.Add('Bits 12-15 = 1: Bottom border = thin solid line');
|
|
$2000: FDetails.Add('Bits 12-15 = 2: Bottom border = medium solid line');
|
|
$3000: FDetails.Add('Bits 12-15 = 3: Bottom border = dashed line');
|
|
$4000: FDetails.Add('Bits 12-15 = 4: Bottom border = dotted line');
|
|
$5000: FDetails.Add('Bits 12-15 = 5: Bottom border = thick solid line');
|
|
$6000: FDetails.Add('Bits 12-15 = 6: Bottom border = double solid line');
|
|
$7000: FDetails.Add('Bits 12-15 = 7: Bottom border = hair line');
|
|
$8000: FDetails.Add('Bits 12-15 = 8: Bottom border = medium dashed');
|
|
$9000: FDetails.Add('Bits 12-15 = 9: Bottom border = thin dash-dotted');
|
|
$A000: FDetails.Add('Bits 12-15 = 10: Bottom border = medium dash-dotted');
|
|
$B000: FDetails.Add('Bits 12-15 = 11: Bottom border = thin dash-dot-dotted');
|
|
$C000: FDetails.Add('Bits 12-15 = 12: Bottom border = medium dash-dot-dotted');
|
|
$D000: FDetails.Add('Bits 12-15 = 13: Bottom border = slanted medium dash-dotted');
|
|
end;
|
|
FDetails.Add(Format('Bits 16-22 = %d: Color index for left line color', [(dw and $007F0000) shr 16]));
|
|
FDetails.Add(Format('Bits 23-29 = %d: Color index for right line color', [(dw and $3F800000) shr 23]));
|
|
if dw and $40000000 = 0
|
|
then FDetails.Add('Bit 30 = 0: No diagonal line from top left to right bottom')
|
|
else FDetails.Add('Bit 30 = 1: Diagonal line from top left to right bottom');
|
|
if dw and $80000000 = 0
|
|
then FDetails.Add('Bit 31 = 0: No diagonal line from bottom left to right top')
|
|
else FDetails.Add('Bit 31 = 1: Diagonal line from bottom left to right top');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.8x', [dw]),
|
|
'Cell border lines and background area');
|
|
|
|
numBytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numbytes);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Cell border lines and background area (cont''d):'#13);
|
|
FDetails.Add(Format('Bits 0-6 = %d: Color index for top line color', [(dw and $0000007F)]));
|
|
FDetails.Add(Format('Bits 7-13 = %d: Color index for bottom line color', [(dw and $00003F80) shr 7]));
|
|
FDetails.Add(Format('Bits 14-20 = %d: Color index for diagonal line color', [(dw and $001FC000) shr 14]));
|
|
case dw and $01E00000 shr 17 of
|
|
$0: FDetails.Add('Bits 21-24 = 0: Diagonal line style = No line');
|
|
$1: FDetails.Add('Bits 21-24 = 1: Diagonal line style = thin solid line');
|
|
$2: FDetails.Add('Bits 21-24 = 2: Diagonal line style = medium solid line');
|
|
$3: FDetails.Add('Bits 21-24 = 3: Diagonal line style = dashed line');
|
|
$4: FDetails.Add('Bits 21-24 = 4: Diagonal line style = dotted line');
|
|
$5: FDetails.Add('Bits 21-24 = 5: Diagonal line style = thick solid line');
|
|
$6: FDetails.Add('Bits 21-24 = 6: Diagonal line style = double solid line');
|
|
$7: FDetails.Add('Bits 21-24 = 7: Diagonal line style = hair line');
|
|
$8: FDetails.Add('Bits 21-24 = 8: Diagonal line style = medium dashed');
|
|
$9: FDetails.Add('Bits 21-24 = 9: Diagonal line style = thin dash-dotted');
|
|
$A: FDetails.Add('Bits 21-24 = 10: Diagonal line style = medium dash-dotted');
|
|
$B: FDetails.Add('Bits 21-24 = 11: Diagonal line style = thin dash-dot-dotted');
|
|
$C: FDetails.Add('Bits 21-24 = 12: Diagonal line style = medium dash-dot-dotted');
|
|
$D: FDetails.Add('Bits 21-24 = 13: Diagonal line style = slanted medium dash-dotted');
|
|
end;
|
|
case (dw and $FC000000) shr 26 of
|
|
$00: FDetails.Add('Bits 26-31 = 0: Fill pattern = No fill');
|
|
$01: FDetails.Add('Bits 26-31 = 1: Fill pattern = solid fill');
|
|
$02: FDetails.Add('Bits 26-31 = 2: Fill pattern = medium fill');
|
|
$03: FDetails.Add('Bits 26-31 = 3: Fill pattern = dense fill');
|
|
$04: FDetails.Add('Bits 26-31 = 4: Fill pattern = sparse fill');
|
|
$05: FDetails.Add('Bits 26-31 = 5: Fill pattern = horizontal fill');
|
|
$06: FDetails.Add('Bits 26-31 = 6: Fill pattern = vertical fill');
|
|
$07: FDetails.Add('Bits 26-31 = 7: Fill pattern = backslash fill');
|
|
$08: FDetails.Add('Bits 26-31 = 8: Fill pattern = slash fill');
|
|
$09: FDetails.Add('Bits 26-31 = 9: Fill pattern = coarse medium fill');
|
|
$0A: FDetails.Add('Bits 26-31 = 10: Fill pattern = coarse medium horiz fill');
|
|
$0B: FDetails.Add('Bits 26-31 = 11: Fill pattern = sparse horizontal fill');
|
|
$0C: FDetails.Add('Bits 26-31 = 12: Fill pattern = sparse vertical fill');
|
|
$0D: FDetails.Add('Bits 26-31 = 13: Fill pattern = sparse backslash fill');
|
|
$0E: FDetails.Add('Bits 26-31 = 14: Fill pattern = sparse slash fill');
|
|
$0F: FDetails.Add('Bits 26-31 = 15: Fill pattern = cross fill');
|
|
$10: FDetails.Add('Bits 26-31 = 16: Fill pattern = dense backslash fill');
|
|
$11: FDetails.Add('Bits 26-31 = 17: Fill pattern = very sparse fill');
|
|
$12: FDetails.Add('Bits 26-31 = 18: Fill pattern = extremely sparse fill');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.8x', [dw]),
|
|
'Cell border lines and background area (cont''d)');
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Cell border lines and background area (cont''d):'#13);
|
|
FDetails.Add(Format('Bits 0-6 = %d: Color index for pattern color', [(w and $007F)]));
|
|
FDetails.Add(Format('Bits 7-13 = %d: Color index for pattern background color', [(w and $3F80) shr 7]));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.4x', [w]),
|
|
'Cell border lines and background area (cont''d)');
|
|
end;
|
|
|
|
if FFormat = sfExcel5 then begin
|
|
numBytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numBytes);
|
|
dw := DWordLEToN(dw);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Cell border lines and background area:'#13);
|
|
FDetails.Add(Format('Bits 0-6 = %d: Color index for pattern color', [(dw and $007F)]));
|
|
FDetails.Add(Format('Bits 7-13 = %d: Color index for pattern background color', [(dw and $3F80) shr 7]));
|
|
case (dw and $003F0000) shr 16 of
|
|
$00: FDetails.Add('Bits 16-21 = 0: Fill pattern = No fill');
|
|
$01: FDetails.Add('Bits 16-21 = 1: Fill pattern = solid fill');
|
|
$02: FDetails.Add('Bits 16-21 = 2: Fill pattern = medium fill');
|
|
$03: FDetails.Add('Bits 16-21 = 3: Fill pattern = dense fill');
|
|
$04: FDetails.Add('Bits 16-21 = 4: Fill pattern = sparse fill');
|
|
$05: FDetails.Add('Bits 16-21 = 5: Fill pattern = horizontal fill');
|
|
$06: FDetails.Add('Bits 16-21 = 6: Fill pattern = vertical fill');
|
|
$07: FDetails.Add('Bits 16-21 = 7: Fill pattern = backslash fill');
|
|
$08: FDetails.Add('Bits 16-21 = 8: Fill pattern = slash fill');
|
|
$09: FDetails.Add('Bits 16-21 = 9: Fill pattern = coarse medium fill');
|
|
$0A: FDetails.Add('Bits 16-21 = 10: Fill pattern = coarse medium horiz fill');
|
|
$0B: FDetails.Add('Bits 16-21 = 11: Fill pattern = sparse horizontal fill');
|
|
$0C: FDetails.Add('Bits 16-21 = 12: Fill pattern = sparse vertical fill');
|
|
$0D: FDetails.Add('Bits 16-21 = 13: Fill pattern = sparse backslash fill');
|
|
$0E: FDetails.Add('Bits 16-21 = 14: Fill pattern = sparse slash fill');
|
|
$0F: FDetails.Add('Bits 16-21 = 15: Fill pattern = cross fill');
|
|
$10: FDetails.Add('Bits 16-21 = 16: Fill pattern = dense backslash fill');
|
|
$11: FDetails.Add('Bits 16-21 = 17: Fill pattern = very sparse fill');
|
|
$12: FDetails.Add('Bits 16-21 = 18: Fill pattern = extremely sparse fill');
|
|
end;
|
|
case dw and $01C00000 shr 22 of
|
|
$0: FDetails.Add('Bits 22-24 = 0: Bottom line style = No line');
|
|
$1: FDetails.Add('Bits 22-24 = 1: Bottom line style = thin solid line');
|
|
$2: FDetails.Add('Bits 22-24 = 2: Bottom line style = medium solid line');
|
|
$3: FDetails.Add('Bits 22-24 = 3: Bottom line style = dashed line');
|
|
$4: FDetails.Add('Bits 22-24 = 4: Bottom line style = dotted line');
|
|
$5: FDetails.Add('Bits 22-24 = 5: Bottom line style = thick solid line');
|
|
$6: FDetails.Add('Bits 22-24 = 6: Bottom line style = double solid line');
|
|
$7: FDetails.Add('Bits 22-24 = 7: Bottom line style = hair line');
|
|
end;
|
|
FDetails.Add(Format('Bits 25-31 = %d: Color index for bottom line color', [(dw and $FE000000) shr 25]));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.8x', [dw]),
|
|
'Cell border lines & background area');
|
|
|
|
numBytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numBytes);
|
|
dw := DWOrdLEToN(dw);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Cell border lines (cont''d):'#13);
|
|
case dw and $00000007 of
|
|
$00: FDetails.Add('Bits 0-2 = 0: Top border = No line');
|
|
$01: FDetails.Add('Bits 0-2 = 1: Top border = thin solid line');
|
|
$02: FDetails.Add('Bits 0-2 = 2: Top border = medium solid line');
|
|
$03: FDetails.Add('Bits 0-2 = 3: Top border = dashed line');
|
|
$04: FDetails.Add('Bits 0-2 = 4: Top border = dotted line');
|
|
$05: FDetails.Add('Bits 0-2 = 5: Top border = thick solid line');
|
|
$06: FDetails.Add('Bits 0-2 = 6: Top border = double solid line');
|
|
$07: FDetails.Add('Bits 0-2 = 7: Top border = hair line');
|
|
end;
|
|
case (dw and $00000038) shr 3 of
|
|
$0000: FDetails.Add('Bits 3-5 = 0: Left border = No line');
|
|
$0001: FDetails.Add('Bits 3-5 = 1: Left border = thin solid line');
|
|
$0002: FDetails.Add('Bits 3-5 = 2: Left border = medium solid line');
|
|
$0003: FDetails.Add('Bits 3-5 = 3: Left border = dashed line');
|
|
$0004: FDetails.Add('Bits 3-5 = 4: Left border = dotted line');
|
|
$0005: FDetails.Add('Bits 3-5 = 5: Left border = thick solid line');
|
|
$0006: FDetails.Add('Bits 3-5 = 6: Left border = double solid line');
|
|
$0007: FDetails.Add('Bits 3-5 = 7: Left border = hair line');
|
|
end;
|
|
case (dw and $000001C0) shr 6 of
|
|
$0000: FDetails.Add('Bits 6-8 = 0: Right border = No line');
|
|
$0010: FDetails.Add('Bits 6-8 = 1: Right border = thin solid line');
|
|
$0020: FDetails.Add('Bits 6-8 = 2: Right border = medium solid line');
|
|
$0030: FDetails.Add('Bits 6-8 = 3: Right border = dashed line');
|
|
$0040: FDetails.Add('Bits 6-8 = 4: Right border = dotted line');
|
|
$0050: FDetails.Add('Bits 6-8 = 5: Right border = thick solid line');
|
|
$0060: FDetails.Add('Bits 6-8 = 6: Right border = double solid line');
|
|
$0070: FDetails.Add('Bits 6-8 = 7: Right border = hair line');
|
|
end;
|
|
FDetails.Add(Format('Bits 9-15 = %d: Color index for top line color', [(dw and $0000FE00) shr 7]));
|
|
FDetails.Add(Format('Bits 16-22 = %d: Color index for left line color', [(dw and $007F0000) shr 16]));
|
|
FDetails.Add(Format('Bits 23-29 = %d: Color index for right line color', [(dw and $3F800000) shr 23]));
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.8x', [dw]),
|
|
'Cell border lines (cont''d)');
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowXFCRC;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
dw: DWord;
|
|
begin
|
|
RowCount := FixedRows + 7;
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.4x', [wordLEToN(w)]),
|
|
'Future record type');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Attributes:'#13);
|
|
if w and $0001 = 0
|
|
then FDetails.Add('Bit 0 = 0: The containing record does not specify a range of cells.')
|
|
else FDetails.Add('Bit 0 = 1: The containing record specifies a range of cells.');
|
|
FDetails.Add('Bit 1: specifies wether to alert the user of possible problems '+
|
|
'when saving the file whithout having reckognized this record.');
|
|
FDetails.Add('Bits 2-15: reserved (MUST be zero, MUST be ignored)');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.4x', [w]),
|
|
'Attributes');
|
|
|
|
numbytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(DWordLEToN(dw)), 'Reserved');
|
|
Move(FBuffer[FBufferIndex], dw, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(DWordLEToN(dw)), 'Reserved');
|
|
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.4x', [w]), 'Reserved');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(w),
|
|
'Count of XF records');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('%d ($%.4x)', [w,w]),
|
|
'Checksum of XF records');
|
|
end;
|
|
|
|
|
|
procedure TBIFFGrid.ShowXFEXT;
|
|
var
|
|
numBytes: Integer;
|
|
w: Word;
|
|
dw: DWord;
|
|
i, n: Integer;
|
|
et: Word;
|
|
es: Word;
|
|
ct: Word;
|
|
buffidx: Cardinal;
|
|
s: String;
|
|
begin
|
|
BeginUpdate;
|
|
|
|
RowCount := FixedRows + 100;
|
|
|
|
numBytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numBytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.4x', [wordLEToN(w)]),
|
|
'Future record type');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Attributes:'#13);
|
|
if w and $0001 = 0
|
|
then FDetails.Add('Bit 0 = 0: The containing record does not specify a range of cells.')
|
|
else FDetails.Add('Bit 0 = 1: The containing record specifies a range of cells.');
|
|
FDetails.Add('Bit 1: specifies wether to alert the user of possible problems '+
|
|
'when saving the file whithout having reckognized this record.');
|
|
FDetails.Add('Bits 2-15: reserved (MUST be zero, MUST be ignored)');
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.4x', [w]),
|
|
'Attributes');
|
|
|
|
numbytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(DWordLEToN(dw)), 'Reserved');
|
|
Move(FBuffer[FBufferIndex], dw, numbytes);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(DWordLEToN(dw)), 'Reserved');
|
|
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.4x', [w]), 'Reserved');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('%d ($%.4x)', [w,w]),
|
|
'XF index');
|
|
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('$%.4x', [w]), 'Reserved');
|
|
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(w),
|
|
'Number of extension properties');
|
|
n := w;
|
|
|
|
for i:=1 to n do begin
|
|
buffidx := FBufferIndex;
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], et, numbytes);
|
|
et := WordLEToN(et);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Type:'#13);
|
|
case et of
|
|
$04: FDetails.Add('Full color extension that specifies the cell interior foreground color.');
|
|
$05: FDetails.Add('Full color extension that specifies the cell interior background color.');
|
|
$06: FDetails.Add('Gradient extension that specifies a cell interior gradient fill.');
|
|
$07: FDetails.Add('Full color extension that specifies the top cell border color.');
|
|
$08: FDetails.Add('Full color extension that specifies the bottom cell border color.');
|
|
$09: FDetails.Add('Full color extension that specifies the left cell border color.');
|
|
$0A: FDetails.Add('Full color extension that specifies the right cell border color.');
|
|
$0B: FDetails.Add('Full color extension that specifies the diagonal cell border color.');
|
|
$0D: FDetails.Add('Full color extension that specifies the cell text color.');
|
|
$0E: FDetails.Add('2-byte unsigned integer that specifies a font scheme.');
|
|
$0F: FDetails.Add('2-byte unsigned integer that specifies the text indentation level (MUST be <= 250).');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('%d ($%.4x)', [et, et]),
|
|
Format('Extension property #%d: Type', [i]));
|
|
Move(FBuffer[FBufferIndex], es, numbytes);
|
|
es := WordLEToN(es);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(es),
|
|
Format('Extension property #%d: Data size', [i]));
|
|
|
|
case et of
|
|
$04, $05, $07..$0D: // FullColorExt
|
|
begin
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], ct, numbytes);
|
|
ct := WordLEToN(ct);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Full color extension - Color type:'#13);
|
|
case ct of
|
|
0: FDetails.Add('0 - Automatic color');
|
|
1: FDetails.Add('1 - Indexed color');
|
|
2: FDetails.Add('2 - RGB color');
|
|
3: FDetails.Add('3 - Theme color');
|
|
4: FDetails.Add('4 - Color not set');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(ct),
|
|
Format('Extension property #%d (Full color extension): Color type', [i]));
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(integer(w)),
|
|
Format('Extension property #%d (Full color extension): Color tint', [i]));
|
|
numbytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numbytes);
|
|
dw := DWordLEToN(dw);
|
|
case ct of
|
|
0: s := '(dummy - MUST be 0)';
|
|
1: s := '(index)';
|
|
2: s := '(RGB value)';
|
|
3: s := '(theme)';
|
|
else s := '';
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('%d ($%.8x)', [QWord(dw), QWord(dw)]),
|
|
Format('Extension property #%d (Full color extension): value %s', [i, s]));
|
|
numbytes := 4;
|
|
Move(FBuffer[FBufferIndex], dw, numbytes);
|
|
dw := DWordLEToN(dw);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('%d ($%.8x)', [QWord(dw), QWord(dw)]),
|
|
Format('Extension property #%d (Full color extension): Reserved', [i]));
|
|
Move(FBuffer[FBufferIndex], dw, numbytes);
|
|
dw := DWordLEToN(dw);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('%d ($%.8x)', [QWord(dw), QWord(dw)]),
|
|
Format('Extension property #%d (Full color extension): Reserved', [i]));
|
|
end;
|
|
|
|
$06: // Gradient
|
|
begin
|
|
ShowInRow(FCurrRow, FBufferIndex, es, '(var)',
|
|
Format('Extension property #%d (Gradient): - not interpreted here -', [i]));
|
|
end;
|
|
|
|
$0E: // Font scheme
|
|
begin
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
if Row = FCurrRow then begin
|
|
FDetails.Add('Font scheme:'#13);
|
|
case w of
|
|
0: FDetails.Add('0 - No font scheme');
|
|
1: FDetails.Add('1 - Major scheme');
|
|
2: FDetails.Add('2 - Minor scheme');
|
|
3: FDetails.Add('3 - Ninched scheme');
|
|
end;
|
|
end;
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, Format('%d ($%.4x)', [w,w]),
|
|
Format('Extension property #%d Font scheme', [i]));
|
|
end;
|
|
|
|
$0F: // Text indentation level
|
|
begin
|
|
numbytes := 2;
|
|
Move(FBuffer[FBufferIndex], w, numbytes);
|
|
w := WordLEToN(w);
|
|
ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(w),
|
|
Format('Extension property #%d Text indentation level', [i]));
|
|
end;
|
|
end;
|
|
FBufferIndex := buffidx + es;
|
|
end;
|
|
RowCount := FCurrRow;
|
|
|
|
EndUpdate(true);
|
|
end;
|
|
|
|
|
|
end.
|
|
|