diff --git a/components/fpspreadsheet/examples/excel2demo/excel2write.lpr b/components/fpspreadsheet/examples/excel2demo/excel2write.lpr
index 46a740151..c5a22ba7e 100644
--- a/components/fpspreadsheet/examples/excel2demo/excel2write.lpr
+++ b/components/fpspreadsheet/examples/excel2demo/excel2write.lpr
@@ -69,6 +69,13 @@ begin
MyRPNFormula[2].ElementKind := fekROUND;
MyWorksheet.WriteRPNFormula(0, 5, MyRPNFormula);
+ // Write a string formula to G1 = "A" & "B"
+ MyWorksheet.WriteRPNFormula(0, 6, CreateRPNFormula(
+ RPNString('A',
+ RPNSTring('B',
+ RPNFunc(fekConcat,
+ nil)))));
+
// Write some string cells
MyWorksheet.WriteUTF8Text(1, 0, 'First');
MyWorksheet.WriteFont(1, 0, 'Arial', 12, [fssBold, fssItalic, fssUnderline], scRed);
diff --git a/components/fpspreadsheet/examples/excel8demo/excel8write.lpr b/components/fpspreadsheet/examples/excel8demo/excel8write.lpr
index 037d1905a..526847711 100644
--- a/components/fpspreadsheet/examples/excel8demo/excel8write.lpr
+++ b/components/fpspreadsheet/examples/excel8demo/excel8write.lpr
@@ -156,7 +156,14 @@ begin
MyRPNFormula[1].ElementKind := fekABS;
MyWorksheet.WriteRPNFormula(0, 5, MyRPNFormula);
- r:= 10;
+ // Write a string formula to G1 = "A" & "B"
+ MyWorksheet.WriteRPNFormula(0, 6, CreateRPNFormula(
+ RPNString('A',
+ RPNSTring('B',
+ RPNFunc(fekConcat,
+ nil)))));
+
+ r := 10;
// Write current date/time to cells B11:B16
MyWorksheet.WriteUTF8Text(r, 0, 'nfShortDate');
MyWorksheet.WriteDateTime(r, 1, now, nfShortDate);
diff --git a/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi b/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi
index 8cd0a41f0..642efb5fc 100644
--- a/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi
+++ b/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi
@@ -126,7 +126,6 @@
-
@@ -143,9 +142,6 @@
-
-
-
@@ -266,9 +262,12 @@
-
-
+
+
+
+
+
@@ -291,8 +290,8 @@
-
-
+
+
@@ -301,18 +300,19 @@
-
-
+
+
+
-
-
+
+
@@ -574,123 +574,127 @@
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
+
+
+
+
diff --git a/components/fpspreadsheet/xlsbiff2.pas b/components/fpspreadsheet/xlsbiff2.pas
index 957028f52..a51c199eb 100755
--- a/components/fpspreadsheet/xlsbiff2.pas
+++ b/components/fpspreadsheet/xlsbiff2.pas
@@ -70,6 +70,7 @@ type
procedure ReadNumber(AStream: TStream); override;
procedure ReadRowColXF(AStream: TStream; out ARow, ACol: Cardinal; out AXF: Word); override;
procedure ReadRowInfo(AStream: TStream); override;
+ procedure ReadStringRecord(AStream: TStream; var AStringResult: String); override;
procedure ReadWindow2(AStream: TStream); override;
procedure ReadXF(AStream: TStream);
public
@@ -662,6 +663,30 @@ begin
end;
end;
+{ Reads a STRING record which contains the result of string formula. }
+procedure TsSpreadBIFF2Reader.ReadStringRecord(AStream: TStream;
+ var AStringResult: String);
+var
+ record_id: Word;
+ record_size: word;
+ len: Byte;
+ s: ansistring;
+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
+ len := AStream.ReadByte;
+ if len > 0 then begin
+ SetLength(s, Len);
+ AStream.ReadBuffer(s[1], len);
+ end else
+ s := '';
+ AStringResult := s;
+end;
+
{ Reads the WINDOW2 record containing information like "show grid lines",
"show sheet headers", "panes are frozen", etc. }
procedure TsSpreadBIFF2Reader.ReadWindow2(AStream: TStream);
diff --git a/components/fpspreadsheet/xlsbiff5.pas b/components/fpspreadsheet/xlsbiff5.pas
index df73fe1e7..2e63e35b2 100755
--- a/components/fpspreadsheet/xlsbiff5.pas
+++ b/components/fpspreadsheet/xlsbiff5.pas
@@ -89,6 +89,7 @@ type
procedure ReadWorksheet(AStream: TStream; AData: TsWorkbook);
procedure ReadBoundsheet(AStream: TStream);
procedure ReadRichString(AStream: TStream);
+ procedure ReadStringRecord(AStream: TStream; var AStringResult: String); override;
procedure ReadXF(AStream: TStream);
public
{ General reading methods }
@@ -1360,6 +1361,30 @@ begin
ApplyCellFormatting(ARow, ACol, XF);
end;
+{ Reads a STRING record which contains the result of string formula. }
+procedure TsSpreadBIFF5Reader.ReadStringRecord(AStream: TStream;
+ var AStringResult: String);
+var
+ record_id: Word;
+ record_size: word;
+ len: Word;
+ s: ansistring;
+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
+ len := WordLEToN(AStream.ReadWord);
+ if len > 0 then begin
+ SetLength(s, Len);
+ AStream.ReadBuffer(s[1], len);
+ end else
+ s := '';
+ AStringResult := s;
+end;
+
procedure TsSpreadBIFF5Reader.ReadFromFile(AFileName: string; AData: TsWorkbook);
var
MemStream: TMemoryStream;
diff --git a/components/fpspreadsheet/xlsbiff8.pas b/components/fpspreadsheet/xlsbiff8.pas
index bd73afa1d..727cd06ba 100755
--- a/components/fpspreadsheet/xlsbiff8.pas
+++ b/components/fpspreadsheet/xlsbiff8.pas
@@ -91,6 +91,8 @@ type
procedure ReadBlank(AStream: TStream); override;
procedure ReadLabel(AStream: TStream); override;
procedure ReadRichString(const AStream: TStream);
+ protected
+ procedure ReadStringRecord(AStream: TStream; var AStringResult: String); override;
public
destructor Destroy; override;
{ General reading methods }
@@ -1743,6 +1745,23 @@ begin
ApplyCellFormatting(ARow, ACol, XF);
end;
+procedure TsSpreadBIFF8Reader.ReadStringRecord(AStream: TStream;
+ var AStringResult: String);
+var
+ record_id: Word;
+ record_size: word;
+ p: Cardinal;
+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);
+ p := AStream.Position;
+
+ AStringResult := ReadWideString(AStream, false);
+ AStream.Position := p + record_size;
+end;
+
procedure TsSpreadBIFF8Reader.ReadXF(const AStream: TStream);
function FixLineStyle(dw: DWord): TsLineStyle;
diff --git a/components/fpspreadsheet/xlscommon.pas b/components/fpspreadsheet/xlscommon.pas
index 66cd7b6fe..871072dab 100644
--- a/components/fpspreadsheet/xlscommon.pas
+++ b/components/fpspreadsheet/xlscommon.pas
@@ -36,6 +36,7 @@ const
INT_EXCEL_ID_BLANK = $0201; // BIFF2: $0001
INT_EXCEL_ID_NUMBER = $0203; // BIFF2: $0003
INT_EXCEL_ID_LABEL = $0204; // BIFF2: $0004
+ INT_EXCEL_ID_STRING = $0207; // BIFF2: $0007;
INT_EXCEL_ID_ROW = $0208; // BIFF2: $0008
INT_EXCEL_ID_INDEX = $020B; // BIFF2: $000B
INT_EXCEL_ID_WINDOW2 = $023E; // BIFF2: $003E
@@ -417,6 +418,8 @@ type
procedure ReadRowColXF(AStream: TStream; out ARow, ACol: Cardinal; out AXF: Word); virtual;
// Read row info
procedure ReadRowInfo(AStream: TStream); virtual;
+ // Read STRING record (result of string formula)
+ procedure ReadStringRecord(AStream: TStream; var AResultString: String); virtual;
// Read WINDOW2 record (gridlines, sheet headers)
procedure ReadWindow2(AStream: TStream); virtual;
public
@@ -939,6 +942,7 @@ var
nf: TsNumberFormat;
nd: Word;
nfs: String;
+ resultStr: String;
begin
{ BIFF Record header }
@@ -969,7 +973,10 @@ begin
if (Data[6] = $FF) and (Data[7] = $FF) then
case Data[0] of
- 0: FWorksheet.WriteUTF8Text(ARow, ACol, '(String)');
+ 0: begin
+ ReadStringRecord(AStream, resultStr);
+ FWorksheet.WriteUTF8Text(ARow, ACol, resultStr);
+ end;
1: FWorksheet.WriteUTF8Text(ARow, ACol, '(Bool)');
2: FWorksheet.WriteUTF8Text(ARow, ACol, '(ERROR)');
3: FWorksheet.WriteUTF8Text(ARow, ACol, '(empty)');
@@ -1199,6 +1206,15 @@ begin
// changed manually.
end;
+{ Reads a STRING record. It immediately precedes a FORMULA record which has a
+ string result.
+ Returns here just a dummy string. Has to be overridden to read the real text. }
+procedure TsSpreadBIFFReader.ReadStringRecord(AStream: TStream;
+ var AResultString: String);
+begin
+ AResultString := '(STRING)';
+end;
+
{ Reads the WINDOW2 record containing information like "show grid lines",
"show sheet headers", "panes are frozen", etc.
The record structure is slightly different for BIFF5 and BIFF8, but we use