fpspreadsheet: Improved reading of results of functions returning strings, booleans, or errors. Optional tests in test suite producing an error when Excel reads the test file.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3050 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-05-16 08:17:49 +00:00
parent e21231de03
commit 47d624ab46
6 changed files with 167 additions and 128 deletions

View File

@ -140,8 +140,7 @@
<Unit2> <Unit2>
<Filename Value="..\..\fpspreadsheet.pas"/> <Filename Value="..\..\fpspreadsheet.pas"/>
<UnitName Value="fpspreadsheet"/> <UnitName Value="fpspreadsheet"/>
<IsVisibleTab Value="True"/> <EditorIndex Value="3"/>
<EditorIndex Value="4"/>
<WindowIndex Value="0"/> <WindowIndex Value="0"/>
<TopLine Value="2655"/> <TopLine Value="2655"/>
<CursorPos X="3" Y="2680"/> <CursorPos X="3" Y="2680"/>
@ -151,10 +150,10 @@
<Unit3> <Unit3>
<Filename Value="..\..\fpspreadsheetgrid.pas"/> <Filename Value="..\..\fpspreadsheetgrid.pas"/>
<UnitName Value="fpspreadsheetgrid"/> <UnitName Value="fpspreadsheetgrid"/>
<EditorIndex Value="3"/> <EditorIndex Value="2"/>
<WindowIndex Value="0"/> <WindowIndex Value="0"/>
<TopLine Value="1774"/> <TopLine Value="1774"/>
<CursorPos X="26" Y="1785"/> <CursorPos X="23" Y="1783"/>
<UsageCount Value="100"/> <UsageCount Value="100"/>
<Loaded Value="True"/> <Loaded Value="True"/>
</Unit3> </Unit3>
@ -232,7 +231,7 @@
<Unit13> <Unit13>
<Filename Value="..\..\fpsutils.pas"/> <Filename Value="..\..\fpsutils.pas"/>
<UnitName Value="fpsutils"/> <UnitName Value="fpsutils"/>
<EditorIndex Value="9"/> <EditorIndex Value="8"/>
<WindowIndex Value="0"/> <WindowIndex Value="0"/>
<TopLine Value="37"/> <TopLine Value="37"/>
<CursorPos X="1" Y="21"/> <CursorPos X="1" Y="21"/>
@ -264,10 +263,11 @@
<Unit17> <Unit17>
<Filename Value="..\..\xlsbiff8.pas"/> <Filename Value="..\..\xlsbiff8.pas"/>
<UnitName Value="xlsbiff8"/> <UnitName Value="xlsbiff8"/>
<EditorIndex Value="6"/> <IsVisibleTab Value="True"/>
<EditorIndex Value="5"/>
<WindowIndex Value="0"/> <WindowIndex Value="0"/>
<TopLine Value="62"/> <TopLine Value="1727"/>
<CursorPos X="15" Y="90"/> <CursorPos X="1" Y="1744"/>
<UsageCount Value="84"/> <UsageCount Value="84"/>
<Loaded Value="True"/> <Loaded Value="True"/>
</Unit17> </Unit17>
@ -289,30 +289,30 @@
<Unit20> <Unit20>
<Filename Value="..\..\xlscommon.pas"/> <Filename Value="..\..\xlscommon.pas"/>
<UnitName Value="xlscommon"/> <UnitName Value="xlscommon"/>
<EditorIndex Value="5"/> <EditorIndex Value="4"/>
<WindowIndex Value="0"/> <WindowIndex Value="0"/>
<TopLine Value="588"/> <TopLine Value="974"/>
<CursorPos X="61" Y="592"/> <CursorPos X="21" Y="990"/>
<UsageCount Value="80"/> <UsageCount Value="80"/>
<Loaded Value="True"/> <Loaded Value="True"/>
</Unit20> </Unit20>
<Unit21> <Unit21>
<Filename Value="..\..\xlsbiff5.pas"/> <Filename Value="..\..\xlsbiff5.pas"/>
<UnitName Value="xlsbiff5"/> <UnitName Value="xlsbiff5"/>
<EditorIndex Value="7"/> <EditorIndex Value="6"/>
<WindowIndex Value="0"/> <WindowIndex Value="0"/>
<TopLine Value="1363"/> <TopLine Value="76"/>
<CursorPos X="1" Y="1364"/> <CursorPos X="49" Y="92"/>
<UsageCount Value="67"/> <UsageCount Value="67"/>
<Loaded Value="True"/> <Loaded Value="True"/>
</Unit21> </Unit21>
<Unit22> <Unit22>
<Filename Value="..\..\xlsbiff2.pas"/> <Filename Value="..\..\xlsbiff2.pas"/>
<UnitName Value="xlsbiff2"/> <UnitName Value="xlsbiff2"/>
<EditorIndex Value="8"/> <EditorIndex Value="7"/>
<WindowIndex Value="0"/> <WindowIndex Value="0"/>
<TopLine Value="664"/> <TopLine Value="548"/>
<CursorPos X="21" Y="677"/> <CursorPos X="1" Y="560"/>
<UsageCount Value="68"/> <UsageCount Value="68"/>
<Loaded Value="True"/> <Loaded Value="True"/>
</Unit22> </Unit22>
@ -372,12 +372,10 @@
</Unit29> </Unit29>
<Unit30> <Unit30>
<Filename Value="d:\lazarus-svn\lcl\include\control.inc"/> <Filename Value="d:\lazarus-svn\lcl\include\control.inc"/>
<EditorIndex Value="2"/>
<WindowIndex Value="0"/> <WindowIndex Value="0"/>
<TopLine Value="2696"/> <TopLine Value="2696"/>
<CursorPos X="23" Y="2712"/> <CursorPos X="23" Y="2712"/>
<UsageCount Value="10"/> <UsageCount Value="10"/>
<Loaded Value="True"/>
</Unit30> </Unit30>
<Unit31> <Unit31>
<Filename Value="..\..\fpspreadsheetchart.pas"/> <Filename Value="..\..\fpspreadsheetchart.pas"/>
@ -593,123 +591,123 @@
<JumpHistory Count="30" HistoryIndex="29"> <JumpHistory Count="30" HistoryIndex="29">
<Position1> <Position1>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="633" Column="1" TopLine="631"/> <Caret Line="346" Column="1" TopLine="336"/>
</Position1> </Position1>
<Position2> <Position2>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="638" Column="43" TopLine="619"/> <Caret Line="354" Column="1" TopLine="336"/>
</Position2> </Position2>
<Position3> <Position3>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="633" Column="43" TopLine="619"/> <Caret Line="346" Column="8" TopLine="336"/>
</Position3> </Position3>
<Position4> <Position4>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="195" Column="1" TopLine="168"/> <Caret Line="343" Column="1" TopLine="336"/>
</Position4> </Position4>
<Position5> <Position5>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="643" Column="25" TopLine="631"/> <Caret Line="346" Column="1" TopLine="336"/>
</Position5> </Position5>
<Position6> <Position6>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="640" Column="1" TopLine="631"/> <Caret Line="347" Column="1" TopLine="336"/>
</Position6> </Position6>
<Position7> <Position7>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="342" Column="3" TopLine="337"/> <Caret Line="348" Column="1" TopLine="336"/>
</Position7> </Position7>
<Position8> <Position8>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="343" Column="1" TopLine="336"/> <Caret Line="349" Column="1" TopLine="336"/>
</Position8> </Position8>
<Position9> <Position9>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="346" Column="1" TopLine="336"/> <Caret Line="350" Column="1" TopLine="336"/>
</Position9> </Position9>
<Position10> <Position10>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="354" Column="1" TopLine="336"/> <Caret Line="351" Column="1" TopLine="336"/>
</Position10> </Position10>
<Position11> <Position11>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="346" Column="8" TopLine="336"/> <Caret Line="354" Column="1" TopLine="336"/>
</Position11> </Position11>
<Position12> <Position12>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="343" Column="1" TopLine="336"/> <Caret Line="640" Column="1" TopLine="621"/>
</Position12> </Position12>
<Position13> <Position13>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="346" Column="1" TopLine="336"/> <Caret Line="641" Column="1" TopLine="621"/>
</Position13> </Position13>
<Position14> <Position14>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="347" Column="1" TopLine="336"/> <Caret Line="343" Column="1" TopLine="324"/>
</Position14> </Position14>
<Position15> <Position15>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="348" Column="1" TopLine="336"/> <Caret Line="632" Column="30" TopLine="621"/>
</Position15> </Position15>
<Position16> <Position16>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="349" Column="1" TopLine="336"/> <Caret Line="633" Column="30" TopLine="622"/>
</Position16> </Position16>
<Position17> <Position17>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="350" Column="1" TopLine="336"/> <Caret Line="634" Column="30" TopLine="623"/>
</Position17> </Position17>
<Position18> <Position18>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="351" Column="1" TopLine="336"/> <Caret Line="635" Column="30" TopLine="624"/>
</Position18> </Position18>
<Position19> <Position19>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="354" Column="1" TopLine="336"/> <Caret Line="636" Column="30" TopLine="625"/>
</Position19> </Position19>
<Position20> <Position20>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="640" Column="1" TopLine="621"/> <Caret Line="637" Column="30" TopLine="626"/>
</Position20> </Position20>
<Position21> <Position21>
<Filename Value="mainform.pas"/> <Filename Value="mainform.pas"/>
<Caret Line="641" Column="1" TopLine="621"/> <Caret Line="638" Column="30" TopLine="627"/>
</Position21> </Position21>
<Position22> <Position22>
<Filename Value="mainform.pas"/>
<Caret Line="343" Column="1" TopLine="324"/>
</Position22>
<Position23>
<Filename Value="mainform.pas"/>
<Caret Line="632" Column="30" TopLine="621"/>
</Position23>
<Position24>
<Filename Value="mainform.pas"/>
<Caret Line="633" Column="30" TopLine="622"/>
</Position24>
<Position25>
<Filename Value="mainform.pas"/>
<Caret Line="634" Column="30" TopLine="623"/>
</Position25>
<Position26>
<Filename Value="mainform.pas"/>
<Caret Line="635" Column="30" TopLine="624"/>
</Position26>
<Position27>
<Filename Value="mainform.pas"/>
<Caret Line="636" Column="30" TopLine="625"/>
</Position27>
<Position28>
<Filename Value="mainform.pas"/>
<Caret Line="637" Column="30" TopLine="626"/>
</Position28>
<Position29>
<Filename Value="mainform.pas"/>
<Caret Line="638" Column="30" TopLine="627"/>
</Position29>
<Position30>
<Filename Value="..\..\xlscommon.pas"/> <Filename Value="..\..\xlscommon.pas"/>
<Caret Line="592" Column="61" TopLine="588"/> <Caret Line="592" Column="61" TopLine="588"/>
</Position22>
<Position23>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="89" Column="48" TopLine="62"/>
</Position23>
<Position24>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1751" Column="16" TopLine="1743"/>
</Position24>
<Position25>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="1237" Column="67" TopLine="1222"/>
</Position25>
<Position26>
<Filename Value="..\..\xlsbiff2.pas"/>
<Caret Line="73" Column="48" TopLine="61"/>
</Position26>
<Position27>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="89" Column="29" TopLine="73"/>
</Position27>
<Position28>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="365" Column="16" TopLine="353"/>
</Position28>
<Position29>
<Filename Value="..\..\xlsbiff5.pas"/>
<Caret Line="1379" Column="1" TopLine="1363"/>
</Position29>
<Position30>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1754" Column="1" TopLine="1742"/>
</Position30> </Position30>
</JumpHistory> </JumpHistory>
</ProjectOptions> </ProjectOptions>

View File

@ -1941,4 +1941,56 @@ begin
RPNFunc(fekSUBSTITUTE, 3, RPNFunc(fekSUBSTITUTE, 3,
nil)))))); nil))))));
Worksheet.WriteUTF8Text(Row, 2, 'He..o Wor.d!'); Worksheet.WriteUTF8Text(Row, 2, 'He..o Wor.d!');
inc(Row, 2);
Worksheet.WriteUTF8Text(Row, 0, 'Errors');
Worksheet.WriteUsedFormatting(Row, 0, [uffBold]);
// Division by 0
// These tests partly produce an error messsage when the file is read by Excel.
// In order to avoid confusion they are deactivated by default.
// Remove the comment below to see these tests.
(*
inc(Row);
Worksheet.WriteUTF8Text(Row, 0, '=1/0');
Worksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1,
RPNNumber(0,
RPNFunc(fekDiv,
nil)))));
Worksheet.WriteUTF8Text(Row, 2, 'Error #DIV/0!');
// Not enough operands for operation
inc(Row);
Worksheet.WriteUTF8Text(Row, 0, '=1/2 ("2" forgotten from formula)" ');
Worksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1,
// here we'd normally put "RPNFormula(2," - but we "forget" it...
RPNFunc(fekDiv,
nil))));
Worksheet.WriteUTF8Text(Row, 2, 'Error #N/A"');
// Too many operands given
inc(Row);
Worksheet.WriteUTF8Text(Row, 0, '=1/2 (too many operands)');
Worksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1,
RPNNumber(2,
RPNNumber(3, // This line is too much
RPNFunc(fekDiv,
nil))))));
Worksheet.WriteUTF8Text(Row, 2, 'Error #N/A!');
// Parameter count not specified
inc(Row);
Worksheet.WriteUTF8Text(Row, 0, '=SUM(1, 2) (parameter count not specified');
Worksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1,
RPNNumber(2,
RPNFunc(fekSum, // We "forget" to specify the number of arguments
nil)))));
Worksheet.WriteUTF8Text(Row, 2, 'Error #N/A');
*)
end; end;

View File

@ -70,7 +70,7 @@ type
procedure ReadNumber(AStream: TStream); override; procedure ReadNumber(AStream: TStream); override;
procedure ReadRowColXF(AStream: TStream; out ARow, ACol: Cardinal; out AXF: Word); override; procedure ReadRowColXF(AStream: TStream; out ARow, ACol: Cardinal; out AXF: Word); override;
procedure ReadRowInfo(AStream: TStream); override; procedure ReadRowInfo(AStream: TStream); override;
procedure ReadStringRecord(AStream: TStream; var AStringResult: String); override; procedure ReadStringRecord(AStream: TStream); override;
procedure ReadWindow2(AStream: TStream); override; procedure ReadWindow2(AStream: TStream); override;
procedure ReadXF(AStream: TStream); procedure ReadXF(AStream: TStream);
public public
@ -405,6 +405,7 @@ begin
INT_EXCEL_ID_NUMBER : ReadNumber(AStream); INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
INT_EXCEL_ID_LABEL : ReadLabel(AStream); INT_EXCEL_ID_LABEL : ReadLabel(AStream);
INT_EXCEL_ID_FORMULA : ReadFormula(AStream); INT_EXCEL_ID_FORMULA : ReadFormula(AStream);
INT_EXCEL_ID_STRING : ReadStringRecord(AStream);
INT_EXCEL_ID_COLWIDTH : ReadColWidth(AStream); INT_EXCEL_ID_COLWIDTH : ReadColWidth(AStream);
INT_EXCEL_ID_ROW : ReadRowInfo(AStream); INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream); INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream);
@ -547,27 +548,22 @@ begin
end; end;
{ Reads a STRING record which contains the result of string formula. } { Reads a STRING record which contains the result of string formula. }
procedure TsSpreadBIFF2Reader.ReadStringRecord(AStream: TStream; procedure TsSpreadBIFF2Reader.ReadStringRecord(AStream: TStream);
var AStringResult: String);
var var
record_id: Word;
record_size: word;
len: Byte; len: Byte;
s: ansistring; s: ansistring;
begin begin
record_id := WordLEToN(AStream.ReadWord);
if record_id <> INT_EXCEL_ID_STRING then
raise Exception.Create('ReadStringRecord: wrong record found.');
record_size := WordLEToN(AStream.ReadWord);
// The string is a byte-string with 16 bit length // The string is a byte-string with 16 bit length
len := AStream.ReadByte; len := AStream.ReadByte;
if len > 0 then begin if len > 0 then begin
SetLength(s, Len); SetLength(s, Len);
AStream.ReadBuffer(s[1], len); AStream.ReadBuffer(s[1], len);
end else if (FIncompleteCell <> nil) and (s <> '') then begin
s := ''; FIncompleteCell^.UTF8StringValue := s;
AStringResult := s; FIncompleteCell^.ContentType := cctUTF8String;
end;
end;
FIncompleteCell := nil;
end; end;
{ Reads the WINDOW2 record containing information like "show grid lines", { Reads the WINDOW2 record containing information like "show grid lines",

View File

@ -89,7 +89,7 @@ type
procedure ReadWorksheet(AStream: TStream; AData: TsWorkbook); procedure ReadWorksheet(AStream: TStream; AData: TsWorkbook);
procedure ReadBoundsheet(AStream: TStream); procedure ReadBoundsheet(AStream: TStream);
procedure ReadRichString(AStream: TStream); procedure ReadRichString(AStream: TStream);
procedure ReadStringRecord(AStream: TStream; var AStringResult: String); override; procedure ReadStringRecord(AStream: TStream); override;
procedure ReadXF(AStream: TStream); procedure ReadXF(AStream: TStream);
public public
{ General reading methods } { General reading methods }
@ -1256,6 +1256,7 @@ begin
INT_EXCEL_ID_COLINFO : ReadColInfo(AStream); INT_EXCEL_ID_COLINFO : ReadColInfo(AStream);
INT_EXCEL_ID_ROW : ReadRowInfo(AStream); INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
INT_EXCEL_ID_FORMULA : ReadFormula(AStream); INT_EXCEL_ID_FORMULA : ReadFormula(AStream);
INT_EXCEL_ID_STRING : ReadStringRecord(AStream);
INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream); INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream);
INT_EXCEL_ID_PANE : ReadPane(AStream); INT_EXCEL_ID_PANE : ReadPane(AStream);
INT_EXCEL_ID_BOF : ; INT_EXCEL_ID_BOF : ;
@ -1362,27 +1363,22 @@ begin
end; end;
{ Reads a STRING record which contains the result of string formula. } { Reads a STRING record which contains the result of string formula. }
procedure TsSpreadBIFF5Reader.ReadStringRecord(AStream: TStream; procedure TsSpreadBIFF5Reader.ReadStringRecord(AStream: TStream);
var AStringResult: String);
var var
record_id: Word;
record_size: word;
len: Word; len: Word;
s: ansistring; s: ansistring;
begin begin
record_id := WordLEToN(AStream.ReadWord);
if record_id <> INT_EXCEL_ID_STRING then
raise Exception.Create('ReadStringRecord: wrong record found.');
record_size := WordLEToN(AStream.ReadWord);
// The string is a byte-string with 16 bit length // The string is a byte-string with 16 bit length
len := WordLEToN(AStream.ReadWord); len := WordLEToN(AStream.ReadWord);
if len > 0 then begin if len > 0 then begin
SetLength(s, Len); SetLength(s, Len);
AStream.ReadBuffer(s[1], len); AStream.ReadBuffer(s[1], len);
end else if (FIncompleteCell <> nil) and (s <> '') then begin
s := ''; FIncompleteCell^.UTF8StringValue := s;
AStringResult := s; FIncompleteCell^.ContentType := cctUTF8String;
end;
end;
FIncompleteCell := nil;
end; end;
procedure TsSpreadBIFF5Reader.ReadFromFile(AFileName: string; AData: TsWorkbook); procedure TsSpreadBIFF5Reader.ReadFromFile(AFileName: string; AData: TsWorkbook);

View File

@ -86,7 +86,7 @@ type
procedure ReadLabelSST(const AStream: TStream); procedure ReadLabelSST(const AStream: TStream);
procedure ReadRichString(const AStream: TStream); procedure ReadRichString(const AStream: TStream);
procedure ReadSST(const AStream: TStream); procedure ReadSST(const AStream: TStream);
procedure ReadStringRecord(AStream: TStream; var AStringResult: String); override; procedure ReadStringRecord(AStream: TStream); override;
procedure ReadXF(const AStream: TStream); procedure ReadXF(const AStream: TStream);
public public
destructor Destroy; override; destructor Destroy; override;
@ -1462,6 +1462,7 @@ begin
INT_EXCEL_ID_NUMBER : ReadNumber(AStream); INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
INT_EXCEL_ID_LABEL : ReadLabel(AStream); INT_EXCEL_ID_LABEL : ReadLabel(AStream);
INT_EXCEL_ID_FORMULA : ReadFormula(AStream); INT_EXCEL_ID_FORMULA : ReadFormula(AStream);
INT_EXCEL_ID_STRING : ReadStringRecord(AStream);
//(RSTRING) This record stores a formatted text cell (Rich-Text). //(RSTRING) This record stores a formatted text cell (Rich-Text).
// In BIFF8 it is usually replaced by the LABELSST record. Excel still // In BIFF8 it is usually replaced by the LABELSST record. Excel still
// uses this record, if it copies formatted text cells to the clipboard. // uses this record, if it copies formatted text cells to the clipboard.
@ -1740,18 +1741,16 @@ begin
ApplyCellFormatting(ARow, ACol, XF); ApplyCellFormatting(ARow, ACol, XF);
end; end;
procedure TsSpreadBIFF8Reader.ReadStringRecord(AStream: TStream; procedure TsSpreadBIFF8Reader.ReadStringRecord(AStream: TStream);
var AStringResult: String);
var var
record_id: Word; s: String;
record_size: word;
begin begin
record_id := WordLEToN(AStream.ReadWord); s := ReadWideString(AStream, false);
if record_id <> INT_EXCEL_ID_STRING then if (FIncompleteCell <> nil) and (s <> '') then begin
raise Exception.Create('ReadStringRecord: wrong record found.'); FIncompleteCell^.UTF8StringValue := s;
record_size := WordLEToN(AStream.ReadWord); FIncompleteCell^.ContentType := cctUTF8String;
end;
AStringResult := ReadWideString(AStream, false); FIncompleteCell := nil;
end; end;
procedure TsSpreadBIFF8Reader.ReadXF(const AStream: TStream); procedure TsSpreadBIFF8Reader.ReadXF(const AStream: TStream);

View File

@ -362,6 +362,7 @@ type
FDateMode: TDateMode; FDateMode: TDateMode;
FPaletteFound: Boolean; FPaletteFound: Boolean;
FXFList: TFPList; // of TXFListData FXFList: TFPList; // of TXFListData
FIncompleteCell: PCell;
procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Word); virtual; procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Word); virtual;
procedure CreateNumFormatList; override; procedure CreateNumFormatList; override;
// Extracts a number out of an RK value // Extracts a number out of an RK value
@ -402,7 +403,7 @@ type
// Read row info // Read row info
procedure ReadRowInfo(AStream: TStream); virtual; procedure ReadRowInfo(AStream: TStream); virtual;
// Read STRING record (result of string formula) // Read STRING record (result of string formula)
procedure ReadStringRecord(AStream: TStream; var AResultString: String); virtual; procedure ReadStringRecord(AStream: TStream); virtual;
// Read WINDOW2 record (gridlines, sheet headers) // Read WINDOW2 record (gridlines, sheet headers)
procedure ReadWindow2(AStream: TStream); virtual; procedure ReadWindow2(AStream: TStream); virtual;
public public
@ -981,19 +982,17 @@ begin
//RPN data not used by now //RPN data not used by now
AStream.Position := AStream.Position + FormulaSize; AStream.Position := AStream.Position + FormulaSize;
(*
// Now determine the type of the formula result // Now determine the type of the formula result
if (Data[6] = $FF) and (Data[7] = $FF) then if (Data[6] = $FF) and (Data[7] = $FF) then
case Data[0] of case Data[0] of
0: begin 0: // String -> Value is found in next record (STRING)
ReadStringRecord(AStream, resultStr); FIncompleteCell := FWorksheet.GetCell(ARow, ACol);
if resultStr = '' then
FWorksheet.WriteBlank(ARow, ACol) 1: // Boolean value
else FWorksheet.WriteBoolValue(ARow, ACol, Data[2] = 1);
FWorksheet.WriteUTF8Text(ARow, ACol, resultStr);
end; 2: begin // Error value
1: FWorksheet.WriteBoolValue(ARow, ACol, Data[2] = 1);
2: begin
case Data[2] of case Data[2] of
ERR_INTERSECTION_EMPTY : err := errEmptyIntersection; ERR_INTERSECTION_EMPTY : err := errEmptyIntersection;
ERR_DIVIDE_BY_ZERO : err := errDivideByZero; ERR_DIVIDE_BY_ZERO : err := errDivideByZero;
@ -1007,20 +1006,20 @@ begin
end; end;
3: FWorksheet.WriteBlank(ARow, ACol); 3: FWorksheet.WriteBlank(ARow, ACol);
end end
else begin *) else begin
if SizeOf(Double) <> 8 then if SizeOf(Double) <> 8 then
raise Exception.Create('Double is not 8 bytes'); raise Exception.Create('Double is not 8 bytes');
// Result is a number or a date/time // Result is a number or a date/time
Move(Data[0], ResultFormula, SizeOf(Data)); Move(Data[0], ResultFormula, SizeOf(Data));
{Find out what cell type, set content type and value} {Find out what cell type, set content type and value}
ExtractNumberFormat(XF, nf, nd, nfs); ExtractNumberFormat(XF, nf, nd, nfs);
if IsDateTime(ResultFormula, nf, dt) then if IsDateTime(ResultFormula, nf, dt) then
FWorksheet.WriteDateTime(ARow, ACol, dt, nf, nfs) FWorksheet.WriteDateTime(ARow, ACol, dt, nf, nfs)
else else
FWorksheet.WriteNumber(ARow, ACol, ResultFormula, nf, nd); FWorksheet.WriteNumber(ARow, ACol, ResultFormula, nf, nd);
// end; end;
{Add attributes} {Add attributes}
ApplyCellFormatting(ARow, ACol, XF); ApplyCellFormatting(ARow, ACol, XF);
@ -1233,12 +1232,11 @@ begin
end; end;
{ Reads a STRING record. It immediately precedes a FORMULA record which has a { Reads a STRING record. It immediately precedes a FORMULA record which has a
string result. string result. The read value is applied to the FIncompleteCell.
Returns here just a dummy string. Has to be overridden to read the real text. } Must be overridden because the implementation depends on BIFF version. }
procedure TsSpreadBIFFReader.ReadStringRecord(AStream: TStream; procedure TsSpreadBIFFReader.ReadStringRecord(AStream: TStream);
var AResultString: String);
begin begin
AResultString := '(STRING)'; //
end; end;
{ Reads the WINDOW2 record containing information like "show grid lines", { Reads the WINDOW2 record containing information like "show grid lines",