fpspreadsheet: Fix bug in formula parser when scanning of ods cell addresses (incorrect extraction of row index).

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6577 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2018-08-09 22:00:21 +00:00
parent db4fd514dc
commit ba5e4da9be
2 changed files with 90 additions and 81 deletions

View File

@ -953,7 +953,7 @@ end;
It has the structure [sheet1.C1R1:sheet2.C2R2] } It has the structure [sheet1.C1R1:sheet2.C2R2] }
function TsExpressionScanner.DoCellRangeODS: TsTokenType; function TsExpressionScanner.DoCellRangeODS: TsTokenType;
type type
TScannerStateODS = (ssSheet1, ssCol1, ssRow1, ssSheet2, ssCol2, ssRow2); TScannerStateODS = (ssInSheet1, ssInCol1, ssInRow1, ssInSheet2, ssInCol2, ssInRow2);
var var
C: Char; C: Char;
prevC: Char; prevC: Char;
@ -968,7 +968,7 @@ begin
FCellRange.Col2 := Cardinal(-1); FCellRange.Col2 := Cardinal(-1);
FFlags := rfAllRel; FFlags := rfAllRel;
state := ssSheet1; state := ssInSheet1;
FToken := ''; FToken := '';
C := NextPos; C := NextPos;
prevC := #0; prevC := #0;
@ -976,33 +976,33 @@ begin
case C of case C of
cNULL: ScanError(rsUnexpectedEndOfExpression); cNULL: ScanError(rsUnexpectedEndOfExpression);
'.': begin '.': begin
if (state = ssSheet1) then if (state = ssInSheet1) then
begin begin
FSheet1 := FToken; FSheet1 := FToken;
state := ssCol1; state := ssInCol1;
end else end else
if (state = ssSheet2) then if (state = ssInSheet2) then
begin begin
FSheet2 := FToken; FSheet2 := FToken;
state := ssCol2; state := ssInCol2;
end else end else
ScanError(rsIllegalODSCellRange); ScanError(rsIllegalODSCellRange);
FToken := ''; FToken := '';
val := 0; val := 0;
end; end;
':': if (state = ssRow1) then ':': if (state = ssInRow1) then
begin begin
FCellRange.Row1 := val-1; FCellRange.Row1 := val-1;
state := ssSheet2; state := ssInSheet2;
FToken := ''; FToken := '';
end else end else
ScanError(rsIllegalODSCellRange); ScanError(rsIllegalODSCellRange);
'$': case state of '$': case state of
ssCol1: if prevC = '.' then Exclude(FFlags, rfRelCol) else Exclude(FFlags, rfRelRow); ssInCol1: if prevC = '.' then Exclude(FFlags, rfRelCol) else Exclude(FFlags, rfRelRow);
ssCol2: if prevC = '.' then Exclude(FFlags, rfRelCol2) else Exclude(FFlags, rfRelRow2); ssInCol2: if prevC = '.' then Exclude(FFlags, rfRelCol2) else Exclude(FFlags, rfRelRow2);
end; end;
else else
if (state in [ssSheet1, ssSheet2]) then if (state in [ssInSheet1, ssInSheet2]) then
FToken := FToken + C FToken := FToken + C
else else
case C of case C of
@ -1011,16 +1011,21 @@ begin
'a'..'z': 'a'..'z':
val := val*10 + ord(C) - ord('a'); val := val*10 + ord(C) - ord('a');
'0'..'9': '0'..'9':
if state = ssCol1 then begin if state = ssInCol1 then begin
FCellRange.Col1 := val; FCellRange.Col1 := val;
val := ord(C) - ord('0'); val := (ord(C) - ord('0'));
state := ssRow1; state := ssInRow1;
end else end else
if state = ssCol2 then begin if state = ssInRow1 then
val := val*10 + (ord(C) - ord('0'))
else
if state = ssInCol2 then begin
FCellRange.Col2 := val; FCellRange.Col2 := val;
val := ord(C) - ord('0'); val := (ord(C) - ord('0'));
state := ssRow2; state := ssInRow2;
end; end else
if state = ssInRow2 then
val := val*10 + (ord(C) - ord('0'));
end; end;
end; end;
prevC := C; prevC := C;
@ -1029,9 +1034,9 @@ begin
if C <> ']' then if C <> ']' then
ScanError(Format(rsRightSquareBracketExpected, [FPos, C])); ScanError(Format(rsRightSquareBracketExpected, [FPos, C]));
case state of case state of
ssRow1: ssInRow1:
if val > 0 then FCellRange.Row1 := val - 1 else ScanError(rsIllegalODSCellRange); if val > 0 then FCellRange.Row1 := val - 1 else ScanError(rsIllegalODSCellRange);
ssRow2: ssInRow2:
if val > 0 then FCellRange.Row2 := val - 1 else ScanError(rsIllegalODSCellRange); if val > 0 then FCellRange.Row2 := val - 1 else ScanError(rsIllegalODSCellRange);
end; end;
if FCellRange.Col2 = Cardinal(-1) then Exclude(FFlags, rfRelCol2); if FCellRange.Col2 = Cardinal(-1) then Exclude(FFlags, rfRelCol2);

View File

@ -2463,8 +2463,10 @@ begin
hasFormula := false; hasFormula := false;
// Read formula results // Read formula results
if hasFormula then TsWorkbook(FWorkbook).LockFormulas;
// Prevent formulas from being erased when formula results are written to cells
TsWorkbook(FWorkbook).LockFormulas;
try
valueType := GetAttrValue(ACellNode, 'office:value-type'); valueType := GetAttrValue(ACellNode, 'office:value-type');
valueStr := GetAttrValue(ACellNode, 'office:value'); valueStr := GetAttrValue(ACellNode, 'office:value');
calcExtValueType := GetAttrValue(ACellNode, 'calcext:value-type'); calcExtValueType := GetAttrValue(ACellNode, 'calcext:value-type');
@ -2527,10 +2529,12 @@ begin
if (valueStr <> '') then if (valueStr <> '') then
TsWorksheet(FWorksheet).WriteText(cell, valueStr); TsWorksheet(FWorksheet).WriteText(cell, valueStr);
if hasFormula then TsWorkbook(FWorkbook).UnlockFormulas;
if FIsVirtualMode then if FIsVirtualMode then
TsWorkbook(Workbook).OnReadCellData(Workbook, ARow, ACol, cell); TsWorkbook(Workbook).OnReadCellData(Workbook, ARow, ACol, cell);
finally
TsWorkbook(FWorkbook).UnlockFormulas;
end;
end; end;
procedure TsSpreadOpenDocReader.ReadFromStream(AStream: TStream; procedure TsSpreadOpenDocReader.ReadFromStream(AStream: TStream;