From 04e41843a26cd70fd300ceabc5a5ddaea59930f6 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Thu, 14 Aug 2014 22:18:04 +0000 Subject: [PATCH] fpspreadsheet: Show details on shared formulas in BIFFExplorer git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3484 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../reference/BIFFExplorer/BIFFExplorer.lpi | 1 + .../reference/BIFFExplorer/bebiffgrid.pas | 360 +++++++++++++++++- .../reference/BIFFExplorer/bebiffutils.pas | 2 +- 3 files changed, 357 insertions(+), 6 deletions(-) diff --git a/components/fpspreadsheet/reference/BIFFExplorer/BIFFExplorer.lpi b/components/fpspreadsheet/reference/BIFFExplorer/BIFFExplorer.lpi index ae8bd0e7a..011054dc2 100644 --- a/components/fpspreadsheet/reference/BIFFExplorer/BIFFExplorer.lpi +++ b/components/fpspreadsheet/reference/BIFFExplorer/BIFFExplorer.lpi @@ -164,6 +164,7 @@ + diff --git a/components/fpspreadsheet/reference/BIFFExplorer/bebiffgrid.pas b/components/fpspreadsheet/reference/BIFFExplorer/bebiffgrid.pas index 42edfec63..368358f7f 100644 --- a/components/fpspreadsheet/reference/BIFFExplorer/bebiffgrid.pas +++ b/components/fpspreadsheet/reference/BIFFExplorer/bebiffgrid.pas @@ -58,6 +58,7 @@ type procedure ShowFormat; procedure ShowFormatCount; procedure ShowFormula; + procedure ShowFormulaTokens(ATokenBytes: Integer); procedure ShowHeader; procedure ShowHideObj; procedure ShowInteger; @@ -91,6 +92,7 @@ type procedure ShowRK; procedure ShowRow; procedure ShowSelection; + procedure ShowSharedFormula; procedure ShowSheet; procedure ShowSheetPR; procedure ShowSST; @@ -396,6 +398,8 @@ begin ShowRK; $0293: ShowStyle; + $04BC: + ShowSharedFormula; $087C: ShowXFCRC; $087D: @@ -954,7 +958,7 @@ begin numBytes := 2; Move(FBuffer[FBufferIndex], w, numbytes); ShowInRow(FCurrRow, FBufferIndex, numbytes, IntToStr(WordLEToN(w)), - 'Index to XF record for default column formattingg'); + 'Index to XF record for default column formatting'); numBytes := 2; Move(FBuffer[FBufferIndex], w, numbytes); @@ -1932,10 +1936,10 @@ var dbl: double absolute q; bytearr: array[0..7] of byte absolute q; wordarr: array[0..3] of word absolute q; - s: String; +// s: String; tokenBytes: Integer; - firstTokenBufIdx: Integer; - token: Byte; +// firstTokenBufIdx: Integer; +// token: Byte; r,c, r2,c2: Integer; begin BeginUpdate; @@ -2137,6 +2141,8 @@ begin ShowInRow(FCurrRow, FBufferIndex, numBytes, IntToStr(tokenBytes), 'Size of formula data (in Bytes)'); + ShowFormulaTokens(tokenBytes); +(* // Tokens and parameters firstTokenBufIdx := FBufferIndex; while FBufferIndex < firstTokenBufIdx + tokenBytes do begin @@ -2352,12 +2358,299 @@ begin '(unknown)'); end; end; - +*) 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; +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, 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); + w := WordLEToN(w); + if Row = FCurrRow then begin + FDetails.Add('Encoded cell address (row):'#13); + FDetails.Add('Relative row index: ' + IntToStr(Smallint(w))); + end; + ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d', [SmallInt(w)]), + 'Relative row index'); + + numBytes := 2; + Move(FBuffer[FBufferIndex], w, numbytes); + w := WordLEToN(w); + b := Lo(w); + if Row = FCurrRow then + begin + FDetails.Add('Encoded cell address (column):'#13); + FDetails.Add('Relative column index: ' + IntToStr(ShortInt(b))); + end; + ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d', [ShortInt(b)]), + 'Relative column index'); + end else + begin + numBytes := 2; + Move(FBuffer[FBufferIndex], w, numBytes); + w := WordLEToN(w) and $3FFF; + if Row = FCurrRow then begin + FDetails.Add('Encoded cell address (row):'#13); + FDetails.Add('Relative row index: ' + IntToStr(Smallint(w))); + end; + ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d', [SmallInt(w)]), + 'Relative row index'); + + numBytes := 1; + b := FBuffer[FBufferIndex]; + if Row = FCurrRow then + begin + FDetails.Add('Encoded cell address (column):'#13); + FDetails.Add('Relative column index: ' + IntToStr(ShortInt(b))); + end; + ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('%d', [ShortInt(b)]), + 'Relative column index'); + end; + end; + else + ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [token]), + '(unknown token)'); + + end; // case + end; // while + +end; + procedure TBIFFGrid.ShowHeader; var numbytes: Integer; @@ -3660,6 +3953,63 @@ begin 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; diff --git a/components/fpspreadsheet/reference/BIFFExplorer/bebiffutils.pas b/components/fpspreadsheet/reference/BIFFExplorer/bebiffutils.pas index a9ef6eb42..86294ee83 100644 --- a/components/fpspreadsheet/reference/BIFFExplorer/bebiffutils.pas +++ b/components/fpspreadsheet/reference/BIFFExplorer/bebiffutils.pas @@ -386,7 +386,7 @@ begin $0409: Result := 'BOF'; $041E: Result := 'FORMAT: Number format'; $0443: Result := 'XF'; - $04BC: Result := 'SharedFormula'; + $04BC: Result := 'SHAREDFMLA: Shared formula'; $0800: Result := 'HLINKTOOLTOP: Hyperlink tooltip'; $0801: Result := 'WEBPUB: Web publish item'; $0802: Result := 'QSISXTAG: PivotTable and query table extensions';