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] }
|
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);
|
||||||
|
@ -2463,74 +2463,78 @@ begin
|
|||||||
hasFormula := false;
|
hasFormula := false;
|
||||||
|
|
||||||
// Read formula results
|
// Read formula results
|
||||||
if hasFormula then TsWorkbook(FWorkbook).LockFormulas;
|
|
||||||
|
|
||||||
valueType := GetAttrValue(ACellNode, 'office:value-type');
|
// Prevent formulas from being erased when formula results are written to cells
|
||||||
valueStr := GetAttrValue(ACellNode, 'office:value');
|
TsWorkbook(FWorkbook).LockFormulas;
|
||||||
calcExtValueType := GetAttrValue(ACellNode, 'calcext:value-type');
|
try
|
||||||
// ODS wants a 0 in the NumberValue field in case of an error. If there is
|
valueType := GetAttrValue(ACellNode, 'office:value-type');
|
||||||
// no error, this value will be corrected below.
|
valueStr := GetAttrValue(ACellNode, 'office:value');
|
||||||
cell^.NumberValue := 0.0;
|
calcExtValueType := GetAttrValue(ACellNode, 'calcext:value-type');
|
||||||
// (a) number value
|
// ODS wants a 0 in the NumberValue field in case of an error. If there is
|
||||||
if (valueType = 'float') then
|
// no error, this value will be corrected below.
|
||||||
begin
|
cell^.NumberValue := 0.0;
|
||||||
if UpperCase(valueStr) = '1.#INF' then
|
// (a) number value
|
||||||
TsWorksheet(FWorksheet).WriteNumber(cell, 1.0/0.0)
|
if (valueType = 'float') then
|
||||||
else
|
|
||||||
begin
|
begin
|
||||||
floatValue := StrToFloat(valueStr, FPointSeparatorSettings);
|
if UpperCase(valueStr) = '1.#INF' then
|
||||||
TsWorksheet(FWorksheet).WriteNumber(cell, floatValue);
|
TsWorksheet(FWorksheet).WriteNumber(cell, 1.0/0.0)
|
||||||
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
|
else
|
||||||
case FDateMode of
|
begin
|
||||||
dmODS1899: cell^.DateTimeValue := cell^.NumberValue + DATEMODE_1899_BASE;
|
floatValue := StrToFloat(valueStr, FPointSeparatorSettings);
|
||||||
dmODS1900: cell^.DateTimeValue := cell^.NumberValue + DATEMODE_1900_BASE;
|
TsWorksheet(FWorksheet).WriteNumber(cell, floatValue);
|
||||||
dmODS1904: cell^.DateTimeValue := cell^.NumberValue + DATEMODE_1904_BASE;
|
end;
|
||||||
end;
|
if IsDateTimeFormat(fmt^.NumberFormat) then
|
||||||
end;
|
begin
|
||||||
end else
|
cell^.ContentType := cctDateTime;
|
||||||
// (b) Date/time value
|
// No datemode correction for intervals and for time-only values
|
||||||
if (valueType = 'date') or (valueType = 'time') then
|
if (fmt^.NumberFormat = nfTimeInterval) or (cell^.NumberValue < 1) then
|
||||||
begin
|
cell^.DateTimeValue := cell^.NumberValue
|
||||||
floatValue := ExtractDateTimeFromNode(ACellNode, fmt^.NumberFormat, fmt^.NumberFormatStr);
|
else
|
||||||
TsWorksheet(FWorkSheet).WriteDateTime(cell, floatValue);
|
case FDateMode of
|
||||||
end else
|
dmODS1899: cell^.DateTimeValue := cell^.NumberValue + DATEMODE_1899_BASE;
|
||||||
// (c) text
|
dmODS1900: cell^.DateTimeValue := cell^.NumberValue + DATEMODE_1900_BASE;
|
||||||
if (valueType = 'string') and (calcextValueType <> 'error') then
|
dmODS1904: cell^.DateTimeValue := cell^.NumberValue + DATEMODE_1904_BASE;
|
||||||
begin
|
end;
|
||||||
node := ACellNode.FindNode('text:p');
|
end;
|
||||||
if (node <> nil) and (node.FirstChild <> nil) then
|
end else
|
||||||
|
// (b) Date/time value
|
||||||
|
if (valueType = 'date') or (valueType = 'time') then
|
||||||
begin
|
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);
|
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
|
finally
|
||||||
TsWorkbook(Workbook).OnReadCellData(Workbook, ARow, ACol, cell);
|
TsWorkbook(FWorkbook).UnlockFormulas;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsSpreadOpenDocReader.ReadFromStream(AStream: TStream;
|
procedure TsSpreadOpenDocReader.ReadFromStream(AStream: TStream;
|
||||||
|
Reference in New Issue
Block a user