You've already forked lazarus-ccr
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:
@ -953,7 +953,7 @@ end;
|
||||
It has the structure [sheet1.C1R1:sheet2.C2R2] }
|
||||
function TsExpressionScanner.DoCellRangeODS: TsTokenType;
|
||||
type
|
||||
TScannerStateODS = (ssSheet1, ssCol1, ssRow1, ssSheet2, ssCol2, ssRow2);
|
||||
TScannerStateODS = (ssInSheet1, ssInCol1, ssInRow1, ssInSheet2, ssInCol2, ssInRow2);
|
||||
var
|
||||
C: Char;
|
||||
prevC: Char;
|
||||
@ -968,7 +968,7 @@ begin
|
||||
FCellRange.Col2 := Cardinal(-1);
|
||||
FFlags := rfAllRel;
|
||||
|
||||
state := ssSheet1;
|
||||
state := ssInSheet1;
|
||||
FToken := '';
|
||||
C := NextPos;
|
||||
prevC := #0;
|
||||
@ -976,33 +976,33 @@ begin
|
||||
case C of
|
||||
cNULL: ScanError(rsUnexpectedEndOfExpression);
|
||||
'.': begin
|
||||
if (state = ssSheet1) then
|
||||
if (state = ssInSheet1) then
|
||||
begin
|
||||
FSheet1 := FToken;
|
||||
state := ssCol1;
|
||||
state := ssInCol1;
|
||||
end else
|
||||
if (state = ssSheet2) then
|
||||
if (state = ssInSheet2) then
|
||||
begin
|
||||
FSheet2 := FToken;
|
||||
state := ssCol2;
|
||||
state := ssInCol2;
|
||||
end else
|
||||
ScanError(rsIllegalODSCellRange);
|
||||
FToken := '';
|
||||
val := 0;
|
||||
end;
|
||||
':': if (state = ssRow1) then
|
||||
':': if (state = ssInRow1) then
|
||||
begin
|
||||
FCellRange.Row1 := val-1;
|
||||
state := ssSheet2;
|
||||
state := ssInSheet2;
|
||||
FToken := '';
|
||||
end else
|
||||
ScanError(rsIllegalODSCellRange);
|
||||
'$': case state of
|
||||
ssCol1: if prevC = '.' then Exclude(FFlags, rfRelCol) else Exclude(FFlags, rfRelRow);
|
||||
ssCol2: if prevC = '.' then Exclude(FFlags, rfRelCol2) else Exclude(FFlags, rfRelRow2);
|
||||
ssInCol1: if prevC = '.' then Exclude(FFlags, rfRelCol) else Exclude(FFlags, rfRelRow);
|
||||
ssInCol2: if prevC = '.' then Exclude(FFlags, rfRelCol2) else Exclude(FFlags, rfRelRow2);
|
||||
end;
|
||||
else
|
||||
if (state in [ssSheet1, ssSheet2]) then
|
||||
if (state in [ssInSheet1, ssInSheet2]) then
|
||||
FToken := FToken + C
|
||||
else
|
||||
case C of
|
||||
@ -1011,16 +1011,21 @@ begin
|
||||
'a'..'z':
|
||||
val := val*10 + ord(C) - ord('a');
|
||||
'0'..'9':
|
||||
if state = ssCol1 then begin
|
||||
if state = ssInCol1 then begin
|
||||
FCellRange.Col1 := val;
|
||||
val := ord(C) - ord('0');
|
||||
state := ssRow1;
|
||||
val := (ord(C) - ord('0'));
|
||||
state := ssInRow1;
|
||||
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;
|
||||
val := ord(C) - ord('0');
|
||||
state := ssRow2;
|
||||
end;
|
||||
val := (ord(C) - ord('0'));
|
||||
state := ssInRow2;
|
||||
end else
|
||||
if state = ssInRow2 then
|
||||
val := val*10 + (ord(C) - ord('0'));
|
||||
end;
|
||||
end;
|
||||
prevC := C;
|
||||
@ -1029,9 +1034,9 @@ begin
|
||||
if C <> ']' then
|
||||
ScanError(Format(rsRightSquareBracketExpected, [FPos, C]));
|
||||
case state of
|
||||
ssRow1:
|
||||
ssInRow1:
|
||||
if val > 0 then FCellRange.Row1 := val - 1 else ScanError(rsIllegalODSCellRange);
|
||||
ssRow2:
|
||||
ssInRow2:
|
||||
if val > 0 then FCellRange.Row2 := val - 1 else ScanError(rsIllegalODSCellRange);
|
||||
end;
|
||||
if FCellRange.Col2 = Cardinal(-1) then Exclude(FFlags, rfRelCol2);
|
||||
|
@ -2463,74 +2463,78 @@ begin
|
||||
hasFormula := false;
|
||||
|
||||
// Read formula results
|
||||
if hasFormula then TsWorkbook(FWorkbook).LockFormulas;
|
||||
|
||||
valueType := GetAttrValue(ACellNode, 'office:value-type');
|
||||
valueStr := GetAttrValue(ACellNode, 'office:value');
|
||||
calcExtValueType := GetAttrValue(ACellNode, 'calcext:value-type');
|
||||
// ODS wants a 0 in the NumberValue field in case of an error. If there is
|
||||
// no error, this value will be corrected below.
|
||||
cell^.NumberValue := 0.0;
|
||||
// (a) number value
|
||||
if (valueType = 'float') then
|
||||
begin
|
||||
if UpperCase(valueStr) = '1.#INF' then
|
||||
TsWorksheet(FWorksheet).WriteNumber(cell, 1.0/0.0)
|
||||
else
|
||||
// Prevent formulas from being erased when formula results are written to cells
|
||||
TsWorkbook(FWorkbook).LockFormulas;
|
||||
try
|
||||
valueType := GetAttrValue(ACellNode, 'office:value-type');
|
||||
valueStr := GetAttrValue(ACellNode, 'office:value');
|
||||
calcExtValueType := GetAttrValue(ACellNode, 'calcext:value-type');
|
||||
// ODS wants a 0 in the NumberValue field in case of an error. If there is
|
||||
// no error, this value will be corrected below.
|
||||
cell^.NumberValue := 0.0;
|
||||
// (a) number value
|
||||
if (valueType = 'float') then
|
||||
begin
|
||||
floatValue := StrToFloat(valueStr, FPointSeparatorSettings);
|
||||
TsWorksheet(FWorksheet).WriteNumber(cell, floatValue);
|
||||
end;
|
||||
if IsDateTimeFormat(fmt^.NumberFormat) then
|
||||
begin
|
||||
cell^.ContentType := cctDateTime;
|
||||
// No datemode correction for intervals and for time-only values
|
||||
if (fmt^.NumberFormat = nfTimeInterval) or (cell^.NumberValue < 1) then
|
||||
cell^.DateTimeValue := cell^.NumberValue
|
||||
if UpperCase(valueStr) = '1.#INF' then
|
||||
TsWorksheet(FWorksheet).WriteNumber(cell, 1.0/0.0)
|
||||
else
|
||||
case FDateMode of
|
||||
dmODS1899: cell^.DateTimeValue := cell^.NumberValue + DATEMODE_1899_BASE;
|
||||
dmODS1900: cell^.DateTimeValue := cell^.NumberValue + DATEMODE_1900_BASE;
|
||||
dmODS1904: cell^.DateTimeValue := cell^.NumberValue + DATEMODE_1904_BASE;
|
||||
end;
|
||||
end;
|
||||
end else
|
||||
// (b) Date/time value
|
||||
if (valueType = 'date') or (valueType = 'time') then
|
||||
begin
|
||||
floatValue := ExtractDateTimeFromNode(ACellNode, fmt^.NumberFormat, fmt^.NumberFormatStr);
|
||||
TsWorksheet(FWorkSheet).WriteDateTime(cell, floatValue);
|
||||
end else
|
||||
// (c) text
|
||||
if (valueType = 'string') and (calcextValueType <> 'error') then
|
||||
begin
|
||||
node := ACellNode.FindNode('text:p');
|
||||
if (node <> nil) and (node.FirstChild <> nil) then
|
||||
begin
|
||||
floatValue := StrToFloat(valueStr, FPointSeparatorSettings);
|
||||
TsWorksheet(FWorksheet).WriteNumber(cell, floatValue);
|
||||
end;
|
||||
if IsDateTimeFormat(fmt^.NumberFormat) then
|
||||
begin
|
||||
cell^.ContentType := cctDateTime;
|
||||
// No datemode correction for intervals and for time-only values
|
||||
if (fmt^.NumberFormat = nfTimeInterval) or (cell^.NumberValue < 1) then
|
||||
cell^.DateTimeValue := cell^.NumberValue
|
||||
else
|
||||
case FDateMode of
|
||||
dmODS1899: cell^.DateTimeValue := cell^.NumberValue + DATEMODE_1899_BASE;
|
||||
dmODS1900: cell^.DateTimeValue := cell^.NumberValue + DATEMODE_1900_BASE;
|
||||
dmODS1904: cell^.DateTimeValue := cell^.NumberValue + DATEMODE_1904_BASE;
|
||||
end;
|
||||
end;
|
||||
end else
|
||||
// (b) Date/time value
|
||||
if (valueType = 'date') or (valueType = 'time') then
|
||||
begin
|
||||
valueStr := node.FirstChild.Nodevalue;
|
||||
floatValue := ExtractDateTimeFromNode(ACellNode, fmt^.NumberFormat, fmt^.NumberFormatStr);
|
||||
TsWorksheet(FWorkSheet).WriteDateTime(cell, floatValue);
|
||||
end else
|
||||
// (c) text
|
||||
if (valueType = 'string') and (calcextValueType <> 'error') then
|
||||
begin
|
||||
node := ACellNode.FindNode('text:p');
|
||||
if (node <> nil) and (node.FirstChild <> nil) then
|
||||
begin
|
||||
valueStr := node.FirstChild.Nodevalue;
|
||||
TsWorksheet(FWorksheet).WriteText(cell, valueStr);
|
||||
end;
|
||||
end else
|
||||
// (d) boolean
|
||||
if (valuetype = 'boolean') then
|
||||
begin
|
||||
boolValue := ExtractBoolFromNode(ACellNode);
|
||||
TsWorksheet(FWorksheet).WriteBoolValue(cell, boolValue);
|
||||
end else
|
||||
if (calcextValuetype = 'error') then
|
||||
begin
|
||||
if ExtractErrorFromNode(ACellNode, errorValue) then
|
||||
TsWorksheet(FWorksheet).WriteErrorValue(cell, errorValue) else
|
||||
TsWorksheet(FWorksheet).WriteText(cell, 'ERROR');
|
||||
end else
|
||||
// (e) Text
|
||||
if (valueStr <> '') then
|
||||
TsWorksheet(FWorksheet).WriteText(cell, valueStr);
|
||||
end;
|
||||
end else
|
||||
// (d) boolean
|
||||
if (valuetype = 'boolean') then
|
||||
begin
|
||||
boolValue := ExtractBoolFromNode(ACellNode);
|
||||
TsWorksheet(FWorksheet).WriteBoolValue(cell, boolValue);
|
||||
end else
|
||||
if (calcextValuetype = 'error') then
|
||||
begin
|
||||
if ExtractErrorFromNode(ACellNode, errorValue) then
|
||||
TsWorksheet(FWorksheet).WriteErrorValue(cell, errorValue) else
|
||||
TsWorksheet(FWorksheet).WriteText(cell, 'ERROR');
|
||||
end else
|
||||
// (e) Text
|
||||
if (valueStr <> '') then
|
||||
TsWorksheet(FWorksheet).WriteText(cell, valueStr);
|
||||
|
||||
if hasFormula then TsWorkbook(FWorkbook).UnlockFormulas;
|
||||
if FIsVirtualMode then
|
||||
TsWorkbook(Workbook).OnReadCellData(Workbook, ARow, ACol, cell);
|
||||
|
||||
if FIsVirtualMode then
|
||||
TsWorkbook(Workbook).OnReadCellData(Workbook, ARow, ACol, cell);
|
||||
finally
|
||||
TsWorkbook(FWorkbook).UnlockFormulas;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TsSpreadOpenDocReader.ReadFromStream(AStream: TStream;
|
||||
|
Reference in New Issue
Block a user