fpspreadsheet: Fix reading/writing of cell error values in biff. Insert/delete unit tests with formulas are correct now. Fix crash in BIFFExplorer related to reading of formulas.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3582 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-09-19 19:44:35 +00:00
parent 4ed3b47628
commit b43fb99608
8 changed files with 65 additions and 229 deletions

View File

@ -2718,7 +2718,7 @@ begin
rtDateTime : Result := RPNNumber(FValue.ResDateTime, ANext);
rtBoolean : Result := RPNBool(FValue.ResBoolean, ANext);
rtFloat : Result := RPNNumber(FValue.ResFloat, ANext);
rtError : Result := RPNErr(ord(FValue.ResError), ANext);
rtError : Result := RPNErr(FValue.ResError, ANext);
end;
end;

View File

@ -1251,179 +1251,6 @@ var
'wheat' // $16
);
(*
{ Properties of formula elements }
type
{@@ Properties of formula elements:
@param Symbol Symbol used in the formula
@param MinParams Minimum count of parameters used in this function
@param MaxParams Maximum count of parameters used in this function
@param Func Function to be calculated }
TFEProp = record
Symbol: String;
MinParams, MaxParams: Byte;
Func: TsFormulaFunc;
end;
var
FEProps: array[TFEKind] of TFEProp = ( // functions marked by ( * )
{ Operands } // are only partially supported
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCell
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCellRef
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCellRange
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCellOffset
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCellNum
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCellInteger
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCellString
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCellBool
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCellErr
(Symbol:''; MinParams:Byte(-1); MaxParams:Byte(-1); Func:nil), // fekCellMissingArg
{ Basic operations }
(Symbol:'+'; MinParams:2; MaxParams:2; Func:fpsAdd), // fekAdd
(Symbol:'-'; MinParams:2; MaxParams:2; Func:fpsSub), // fekSub
(Symbol:'*'; MinParams:2; MaxParams:2; Func:fpsMul), // fekMul
(Symbol:'/'; MinParams:2; MaxParams:2; Func:fpsDiv), // fekDiv
(Symbol:'%'; MinParams:1; MaxParams:1; Func:fpsPercent), // fekPercent
(Symbol:'^'; MinParams:2; MaxParams:2; Func:fpsPower), // fekPower
(Symbol:'-'; MinParams:1; MaxParams:1; Func:fpsUMinus), // fekUMinus
(Symbol:'+'; MinParams:1; MaxParams:1; Func:fpsUPlus), // fekUPlus
(Symbol:'&'; MinParams:2; MaxParams:2; Func:fpsConcat), // fekConcat (string concatenation)
(Symbol:'='; MinParams:2; MaxParams:2; Func:fpsEqual), // fekEqual
(Symbol:'>'; MinParams:2; MaxParams:2; Func:fpsGreater), // fekGreater
(Symbol:'>='; MinParams:2; MaxParams:2; Func:fpsGreaterEqual), // fekGreaterEqual
(Symbol:'<'; MinParams:2; MaxParams:2; Func:fpsLess), // fekLess
(Symbol:'<='; MinParams:2; MaxParams:2; Func:fpsLessEqual), // fekLessEqual
(Symbol:'<>'; MinParams:2; MaxParams:2; Func:fpsNotEqual), // fekNotEqual
(Symbol:''; MinParams:1; MaxParams:1; Func:nil), // fekParen -- no need to calculate!
{ math }
(Symbol:'ABS'; MinParams:1; MaxParams:1; Func:fpsABS), // fekABS
(Symbol:'ACOS'; MinParams:1; MaxParams:1; Func:fpsACOS), // fekACOS
(Symbol:'ACOSH'; MinParams:1; MaxParams:1; Func:fpsACOSH), // fekACOSH
(Symbol:'ASIN'; MinParams:1; MaxParams:1; Func:fpsASIN), // fekASIN
(Symbol:'ASINH'; MinParams:1; MaxParams:1; Func:fpsASINH), // fekASINH
(Symbol:'ATAN'; MinParams:1; MaxParams:1; Func:fpsATAN), // fekATAN
(Symbol:'ATANH'; MinParams:1; MaxParams:1; Func:fpsATANH), // fekATANH,
(Symbol:'COS'; MinParams:1; MaxParams:1; Func:fpsCOS), // fekCOS
(Symbol:'COSH'; MinParams:1; MaxParams:1; Func:fpsCOSH), // fekCOSH
(Symbol:'DEGREES'; MinParams:1; MaxParams:1; Func:fpsDEGREES), // fekDEGREES
(Symbol:'EXP'; MinParams:1; MaxParams:1; Func:fpsEXP), // fekEXP
(Symbol:'INT'; MinParams:1; MaxParams:1; Func:fpsINT), // fekINT
(Symbol:'LN'; MinParams:1; MaxParams:1; Func:fpsLN), // fekLN
(Symbol:'LOG'; MinParams:1; MaxParams:2; Func:fpsLOG), // fekLOG,
(Symbol:'LOG10'; MinParams:1; MaxParams:1; Func:fpsLOG10), // fekLOG10
(Symbol:'PI'; MinParams:0; MaxParams:0; Func:fpsPI), // fekPI
(Symbol:'RADIANS'; MinParams:1; MaxParams:1; Func:fpsRADIANS), // fekRADIANS
(Symbol:'RAND'; MinParams:0; MaxParams:0; Func:fpsRAND), // fekRAND
(Symbol:'ROUND'; MinParams:2; MaxParams:2; Func:fpsROUND), // fekROUND,
(Symbol:'SIGN'; MinParams:1; MaxParams:1; Func:fpsSIGN), // fekSIGN
(Symbol:'SIN'; MinParams:1; MaxParams:1; Func:fpsSIN), // fekSIN
(Symbol:'SINH'; MinParams:1; MaxParams:1; Func:fpsSINH), // fekSINH
(Symbol:'SQRT'; MinParams:1; MaxParams:1; Func:fpsSQRT), // fekSQRT,
(Symbol:'TAN'; MinParams:1; MaxParams:1; Func:fpsTAN), // fekTAN
(Symbol:'TANH'; MinParams:1; MaxParams:1; Func:fpsTANH), // fekTANH,
{ date/time }
(Symbol:'DATE'; MinParams:3; MaxParams:3; Func:fpsDATE), // fekDATE
(Symbol:'DATEDIF'; MinParams:3; MaxParams:3; Func:fpsDATEDIF), // fekDATEDIF ( * )
(Symbol:'DATEVALUE'; MinParams:1; MaxParams:1; Func:fpsDATEVALUE), // fekDATEVALUE
(Symbol:'DAY'; MinParams:1; MaxParams:1; Func:fpsDAY), // fekDAY
(Symbol:'HOUR'; MinParams:1; MaxParams:1; Func:fpsHOUR), // fekHOUR
(Symbol:'MINUTE'; MinParams:1; MaxParams:1; Func:fpsMINUTE), // fekMINUTE
(Symbol:'MONTH'; MinParams:1; MaxParams:1; Func:fpsMONTH), // fekMONTH
(Symbol:'NOW'; MinParams:0; MaxParams:0; Func:fpsNOW), // fekNOW
(Symbol:'SECOND'; MinParams:1; MaxParams:1; Func:fpsSECOND), // fekSECOND
(Symbol:'TIME'; MinParams:3; MaxParams:3; Func:fpsTIME), // fekTIME
(Symbol:'TIMEVALUE'; MinParams:1; MaxParams:1; Func:fpsTIMEVALUE), // fekTIMEVALUE
(Symbol:'TODAY'; MinParams:0; MaxParams:0; Func:fpsTODAY), // fekTODAY
(Symbol:'WEEKDAY'; MinParams:1; MaxParams:2; Func:fpsWEEKDAY), // fekWEEKDAY
(Symbol:'YEAR'; MinParams:1; MaxParams:1; Func:fpsYEAR), // fekYEAR
{ statistical }
(Symbol:'AVEDEV'; MinParams:1; MaxParams:30; Func:fpsAVEDEV), // fekAVEDEV
(Symbol:'AVERAGE'; MinParams:1; MaxParams:30; Func:fpsAVERAGE), // fekAVERAGE
(Symbol:'BETADIST'; MinParams:3; MaxParams:5; Func:nil), // fekBETADIST
(Symbol:'BETAINV'; MinParams:3; MaxParams:5; Func:nil), // fekBETAINV
(Symbol:'BINOMDIST'; MinParams:4; MaxParams:4; Func:nil), // fekBINOMDIST
(Symbol:'CHIDIST'; MinParams:2; MaxParams:2; Func:nil), // fekCHIDIST
(Symbol:'CHIINV'; MinParams:2; MaxParams:2; Func:nil), // fekCHIINV
(Symbol:'COUNT'; MinParams:0; MaxParams:30; Func:fpsCOUNT), // fekCOUNT
(Symbol:'COUNTA'; MinParams:0; MaxParams:30; Func:fpsCOUNTA), // fekCOUNTA
(Symbol:'COUNTBLANK';MinParams:1; MaxParams:1; Func:fpsCOUNTBLANK), // fekCOUNTBLANK
(Symbol:'COUNTIF'; MinParams:2; MaxParams:2; Func:fpsCOUNTIF), // fekCOUNTIF
(Symbol:'MAX'; MinParams:1; MaxParams:30; Func:fpsMAX), // fekMAX
(Symbol:'MEDIAN'; MinParams:1; MaxParams:30; Func:nil), // fekMEDIAN
(Symbol:'MIN'; MinParams:1; MaxParams:30; Func:fpsMIN), // fekMIN
(Symbol:'PERMUT'; MinParams:2; MaxParams:2; Func:nil), // fekPERMUT
(Symbol:'POISSON'; MinParams:3; MaxParams:3; Func:nil), // fekPOISSON
(Symbol:'PRODUCT'; MinParams:0; MaxParams:30; Func:fpsPRODUCT), // fekPRODUCT
(Symbol:'STDEV'; MinParams:1; MaxParams:30; Func:fpsSTDEV), // fekSTDEV
(Symbol:'STDEVP'; MinParams:1; MaxParams:30; Func:fpsSTDEVP), // fekSTDEVP
(Symbol:'SUM'; MinParams:0; MaxParams:30; Func:fpsSUM), // fekSUM
(Symbol:'SUMIF'; MinParams:2; MaxParams:3; Func:fpsSUMIF), // fekSUMIF
(Symbol:'SUMSQ'; MinParams:0; MaxParams:30; Func:fpsSUMSQ), // fekSUMSQ
(Symbol:'VAR'; MinParams:1; MaxParams:30; Func:fpsVAR), // fekVAR
(Symbol:'VARP'; MinParams:1; MaxParams:30; Func:fpsVARP), // fekVARP
{ financial }
(Symbol:'FV'; MinParams:3; MaxParams:5; Func:nil), // fekFV
(Symbol:'NPER'; MinParams:3; MaxParams:5; Func:nil), // fekNPER
(Symbol:'PMT'; MinParams:3; MaxParams:5; Func:nil), // fekPMT
(Symbol:'PV'; MinParams:3; MaxParams:5; Func:nil), // fekPV
(Symbol:'RATE'; MinParams:3; MaxParams:6; Func:nil), // fekRATE
{ logical }
(Symbol:'AND'; MinParams:0; MaxParams:30; Func:fpsAND), // fekAND
(Symbol:'FALSE'; MinParams:0; MaxParams:0; Func:fpsFALSE), // fekFALSE
(Symbol:'IF'; MinParams:2; MaxParams:3; Func:fpsIF), // fekIF
(Symbol:'NOT'; MinParams:1; MaxParams:1; Func:fpsNOT), // fekNOT
(Symbol:'OR'; MinParams:1; MaxParams:30; Func:fpsOR), // fekOR
(Symbol:'TRUE'; MinParams:0; MaxParams:0; Func:fpsTRUE), // fekTRUE
{ string }
(Symbol:'CHAR'; MinParams:1; MaxParams:1; Func:fpsCHAR), // fekCHAR
(Symbol:'CODE'; MinParams:1; MaxParams:1; Func:fpsCODE), // fekCODE
(Symbol:'LEFT'; MinParams:1; MaxParams:2; Func:fpsLEFT), // fekLEFT
(Symbol:'LOWER'; MinParams:1; MaxParams:1; Func:fpsLOWER), // fekLOWER
(Symbol:'MID'; MinParams:3; MaxParams:3; Func:fpsMID), // fekMID
(Symbol:'PROPER'; MinParams:1; MaxParams:1; Func:nil), // fekPROPER
(Symbol:'REPLACE'; MinParams:4; MaxParams:4; Func:fpsREPLACE), // fekREPLACE
(Symbol:'RIGHT'; MinParams:1; MaxParams:2; Func:fpsRIGHT), // fekRIGHT
(Symbol:'SUBSTITUTE';MinParams:3; MaxParams:4; Func:fpsSUBSTITUTE), // fekSUBSTITUTE ( * )
(Symbol:'TRIM'; MinParams:1; MaxParams:1; Func:fpsTRIM), // fekTRIM
(Symbol:'UPPER'; MinParams:1; MaxParams:1; Func:fpsUPPER), // fekUPPER
{ lookup/reference }
(Symbol:'COLUMN'; MinParams:0; MaxParams:1; Func:fpsCOLUMN), // fekCOLUMN
(Symbol:'COLUMNS'; MinParams:1; MaxParams:1; Func:fpsCOLUMNS), // fekCOLUMNS
(Symbol:'ROW'; MinParams:0; MaxParams:1; Func:fpsROW), // fekROW
(Symbol:'ROWS'; MinParams:1; MaxParams:1; Func:fpsROWS), // fekROWS
{ info }
(Symbol:'CELL'; MinParams:1; MaxParams:2; Func:fpsCELLINFO), // fekCELLINFO ( * )
(Symbol:'INFO'; MinParams:1; MaxParams:1; Func:fpsINFO), // fekINFO ( * )
(Symbol:'ISBLANK'; MinParams:1; MaxParams:1; Func:fpsISBLANK), // fekIsBLANK
(Symbol:'ISERR'; MinParams:1; MaxParams:1; Func:fpsISERR), // fekIsERR
(Symbol:'ISERROR'; MinParams:1; MaxParams:1; Func:fpsISERROR), // fekIsERROR
(Symbol:'ISLOGICAL'; MinParams:1; MaxParams:1; Func:fpsISLOGICAL), // fekIsLOGICAL
(Symbol:'ISNA'; MinParams:1; MaxParams:1; Func:fpsISNA), // fekIsNA
(Symbol:'ISNONTEXT'; MinParams:1; MaxParams:1; Func:fpsISNONTEXT), // fekIsNONTEXT
(Symbol:'ISNUMBER'; MinParams:1; MaxParams:1; Func:fpsISNUMBER), // fekIsNUMBER
(Symbol:'ISREF'; MinParams:1; MaxParams:1; Func:fpsISREF), // fekIsRef
(Symbol:'ISTEXT'; MinParams:1; MaxParams:1; Func:fpsISTEXT), // fekIsTEXT
(Symbol:'VALUE'; MinParams:1; MaxParams:1; Func:fpsVALUE), // fekValue
{ Other operations }
(Symbol:'SUM'; MinParams:1; MaxParams:1; Func:nil) // fekOpSUM (Unary sum operation). Note: CANNOT be used for summing sell contents; use fekSUM}
);
{@@
Registers a function used when calculating a formula.
This feature allows to extend the built-in functions directly available in
fpspreadsheet.
@param AFormulaKind Identifier of the formula element
@param AFunc Function to be executed when the identifier is met
in an rpn formula. The function declaration MUST
follow the structure given by TsFormulaFunc.
}
procedure RegisterFormulaFunc(AFormulaKind: TFEKind; AFunc: Pointer);
begin
FEProps[AFormulaKind].Func := TsFormulaFunc(AFunc);
end;
*)
{@@
Registers a new reader/writer pair for a given spreadsheet file format

View File

@ -38,7 +38,7 @@ function RPNCellRange(ARow, ACol, ARow2, ACol2: Integer; AFlags: TsRelFlags;
ANext: PRPNItem): PRPNItem; overload;
function RPNCellOffset(ARowOffset, AColOffset: Integer; AFlags: TsRelFlags;
ANext: PRPNItem): PRPNItem;
function RPNErr(AErrCode: Byte; ANext: PRPNItem): PRPNItem;
function RPNErr(AErrCode: TsErrorValue; ANext: PRPNItem): PRPNItem;
function RPNInteger(AValue: Word; ANext: PRPNItem): PRPNItem;
function RPNMissingArg(ANext: PRPNItem): PRPNItem;
function RPNNumber(AValue: Double; ANext: PRPNItem): PRPNItem;
@ -245,11 +245,11 @@ end;
@param ANext Pointer to the next RPN item in the list
@see TsErrorValue
}
function RPNErr(AErrCode: Byte; ANext: PRPNItem): PRPNItem;
function RPNErr(AErrCode: TsErrorValue; ANext: PRPNItem): PRPNItem;
begin
Result := NewRPNItem;
Result^.FE.ElementKind := fekErr;
Result^.FE.IntValue := AErrCode;
Result^.FE.IntValue := ord(AErrCode);
Result^.Next := ANext;
end;

View File

@ -31,19 +31,6 @@
<OtherUnitFiles Value="mrumenu"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<IncludeAssertionCode Value="True"/>
</SyntaxOptions>
</Parsing>
<CodeGeneration>
<Checks>
<IOChecks Value="True"/>
<RangeChecks Value="True"/>
<OverflowChecks Value="True"/>
<StackChecks Value="True"/>
</Checks>
</CodeGeneration>
<Linking>
<Debugging>
<DebugInfoType Value="dsDwarf2Set"/>
@ -144,6 +131,7 @@
<Unit3>
<Filename Value="bebiffutils.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="beBIFFUtils"/>
</Unit3>
<Unit4>
<Filename Value="behtml.pas"/>

View File

@ -2286,7 +2286,7 @@ begin
b := FBuffer[FBufferIndex];
if FCurrRow = Row then begin
FDetails.Add('Error code:'#13);
FDetails.Add(Format('Code $%.2x --> "%s"', [b, b]));
FDetails.Add(Format('Code $%.2x --> "%s"', [b, GetErrorValueStr(TsErrorValue(b))]));
end;
ShowInRow(FCurrRow, FBufferIndex, numBytes, Format('$%.2x', [b]), 'Error code');
end;

View File

@ -483,7 +483,7 @@ begin
SollFormula := '#REF!';
SollLayout := '12345678|'+
'23456789|'+
'34568890|'+
'3456E890|'+ // "E" = error
// '45678901|'+
'56789012|'+
'67890123';
@ -585,19 +585,19 @@ begin
MyCell := MyWorksheet.FindCell(row, col);
if MyCell = nil then
actual := actual + ' '
else begin
else
case MyCell^.ContentType of
cctEmpty : actual := actual + ' ';
cctNumber: actual := actual + IntToStr(Round(Mycell^.NumberValue));
cctError : actual := actual + 'E';
end;
if HasFormula(MyCell) then begin
CheckEquals(
MyWorksheet.ReadFormulaAsString(MyCell),
InsDelTestData[ATestIndex].SollFormula,
'Formula mismatch, cell '+CellNotation(MyWorksheet, Row, Col)
);
end;
if HasFormula(MyCell) then
begin
CheckEquals(
MyWorksheet.ReadFormulaAsString(MyCell),
InsDelTestData[ATestIndex].SollFormula,
'Formula mismatch, cell '+CellNotation(MyWorksheet, Row, Col)
);
end;
end;
CheckEquals(actual, expected,

View File

@ -48,7 +48,6 @@
<Unit1>
<Filename Value="datetests.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="datetests"/>
</Unit1>
<Unit2>
<Filename Value="stringtests.pas"/>
@ -57,6 +56,7 @@
<Unit3>
<Filename Value="numberstests.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="numberstests"/>
</Unit3>
<Unit4>
<Filename Value="manualtests.pas"/>
@ -66,20 +66,20 @@
<Unit5>
<Filename Value="testsutility.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="testsutility"/>
</Unit5>
<Unit6>
<Filename Value="internaltests.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="internaltests"/>
</Unit6>
<Unit7>
<Filename Value="formattests.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="formattests"/>
</Unit7>
<Unit8>
<Filename Value="colortests.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="colortests"/>
</Unit8>
<Unit9>
<Filename Value="fonttests.pas"/>
@ -110,12 +110,10 @@
<Unit15>
<Filename Value="errortests.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="errortests"/>
</Unit15>
<Unit16>
<Filename Value="virtualmodetests.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="virtualmodetests"/>
</Unit16>
<Unit17>
<Filename Value="insertdeletetests.pas"/>

View File

@ -190,6 +190,11 @@ type
function ConvertDateTimeToExcelDateTime
(const ADateTime: TDateTime; ADateMode: TDateMode): Double;
// Converts the error byte read from cells or formulas to fps error value
function ConvertFromExcelError(AValue: Byte): TsErrorValue;
// Converts an fps error value to the byte code needed in xls files
function ConvertToExcelError(AValue: TsErrorValue): byte;
type
{ Contents of the XF record to be stored in the XFList of the reader }
TXFListData = class
@ -501,6 +506,31 @@ begin
end;
end;
function ConvertFromExcelError(AValue: Byte): TsErrorValue;
begin
case AValue of
ERR_INTERSECTION_EMPTY : Result := errEmptyIntersection; // #NULL!
ERR_DIVIDE_BY_ZERO : Result := errDivideByZero; // #DIV/0!
ERR_WRONG_TYPE_OF_OPERAND : Result := errWrongType; // #VALUE!
ERR_ILLEGAL_REFERENCE : Result := errIllegalRef; // #REF!
ERR_WRONG_NAME : Result := errWrongName; // #NAME?
ERR_OVERFLOW : Result := errOverflow; // #NUM!
ERR_ARG_ERROR : Result := errArgError; // #N/A!
end;
end;
function ConvertToExcelError(AValue: TsErrorValue): byte;
begin
case AValue of
errEmptyIntersection : Result := ERR_INTERSECTION_EMPTY; // #NULL!
errDivideByZero : Result := ERR_DIVIDE_BY_ZERO; // #DIV/0!
errWrongType : Result := ERR_WRONG_TYPE_OF_OPERAND; // #VALUE!
errIllegalRef : Result := ERR_ILLEGAL_REFERENCE; // #REF!
errWrongName : Result := ERR_WRONG_NAME; // #NAME?
errOverflow : Result := ERR_OVERFLOW; // #NUM!
errArgError : Result := ERR_ARG_ERROR; // #N/A;
end;
end;
{ TsBIFFNumFormatList }
@ -959,7 +989,8 @@ begin
AStream.ReadDWord;
{ Create cell }
if FIsVirtualMode then begin // "Virtual" cell
if FIsVirtualMode then // "Virtual" cell
begin
InitCell(ARow, ACol, FVirtualCell);
cell := @FVirtualCell;
end else
@ -975,21 +1006,14 @@ begin
FWorksheet.WriteBoolValue(cell, Data[2] = 1);
2: begin // Error value
case Data[2] of
ERR_INTERSECTION_EMPTY : err := errEmptyIntersection;
ERR_DIVIDE_BY_ZERO : err := errDivideByZero;
ERR_WRONG_TYPE_OF_OPERAND: err := errWrongType;
ERR_ILLEGAL_REFERENCE : err := errIllegalRef;
ERR_WRONG_NAME : err := errWrongName;
ERR_OVERFLOW : err := errOverflow;
ERR_ARG_ERROR : err := errArgError;
end;
err := ConvertFromExcelError(Data[2]);
FWorksheet.WriteErrorValue(cell, err);
end;
3: FWorksheet.WriteBlank(cell);
end
else begin
else
begin
{
if SizeOf(Double) <> 8 then
raise Exception.Create('Double is not 8 bytes');
@ -1007,7 +1031,8 @@ begin
end;
{ Formula token array }
if boReadFormulas in FWorkbook.Options then begin
if boReadFormulas in FWorkbook.Options then
begin
ok := ReadRPNTokenArray(AStream, cell);
if not ok then
FWorksheet.WriteErrorValue(cell, errFormulaNotSupported);
@ -1506,7 +1531,7 @@ begin
INT_EXCEL_TOKEN_TSTR:
rpnItem := RPNString(ReadString_8BitLen(AStream), rpnItem);
INT_EXCEL_TOKEN_TERR:
rpnItem := RPNErr(AStream.ReadByte, rpnItem);
rpnItem := RPNErr(ConvertFromExcelError(AStream.ReadByte), rpnItem);
INT_EXCEL_TOKEN_TBOOL:
rpnItem := RPNBool(AStream.ReadByte=1, rpnItem);
INT_EXCEL_TOKEN_TINT:
@ -2361,15 +2386,7 @@ begin
cctError:
begin
Data[0] := 2;
case ACell^.ErrorValue of
errEmptyIntersection: Data[1] := ERR_INTERSECTION_EMPTY;// #NULL!
errDivideByZero : Data[1] := ERR_DIVIDE_BY_ZERO; // #DIV/0!
errWrongType : Data[1] := ERR_WRONG_TYPE_OF_OPERAND; // #VALUE!
errIllegalRef : Data[1] := ERR_ILLEGAL_REFERENCE; // #REF!
errWrongName : Data[1] := ERR_WRONG_NAME; // #NAME?
errOverflow : Data[1] := ERR_OVERFLOW; // #NUM!
errArgError : Data[1] := ERR_ARG_ERROR; // #N/A;
end;
Data[1] := ConvertToExcelError(ACell^.ErrorValue);
Data[3] := $FFFF;
end;
end;
@ -2410,7 +2427,7 @@ procedure TsSpreadBIFFWriter.WriteRPNTokenArray(AStream: TStream;
var RPNLength: Word);
var
i: Integer;
n: Word;
w, n: Word;
dr, dc: Integer;
TokenArraySizePos: Int64;
FinalPos: Int64;
@ -2500,7 +2517,7 @@ begin
INT_EXCEL_TOKEN_TINT: { fekNum, but integer }
begin
AStream.WriteBuffer(AFormula[i].IntValue, 2);
AStream.WriteWord(WordToLE(AFormula[i].IntValue));
inc(RPNLength, 2);
end;
@ -2517,6 +2534,12 @@ begin
inc(RPNLength, 1);
end;
INT_EXCEL_TOKEN_TERR: { fekErr }
begin
AStream.WriteByte(ConvertToExcelError(TsErrorValue(AFormula[i].IntValue)));
inc(RPNLength, 1);
end;
// Functions with fixed parameter count
INT_EXCEL_TOKEN_FUNC_R, INT_EXCEL_TOKEN_FUNC_V, INT_EXCEL_TOKEN_FUNC_A:
begin