From c3f5600c0dd48d538dfec2038aecae342cdf555e Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Wed, 14 May 2014 16:30:33 +0000 Subject: [PATCH] fpspreadsheet: Read results of formulas that return strings git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3045 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../examples/excel2demo/excel2write.lpr | 7 + .../examples/excel8demo/excel8write.lpr | 9 +- .../examples/fpsgrid/fpsgrid.lpi | 138 +++++++++--------- components/fpspreadsheet/xlsbiff2.pas | 25 ++++ components/fpspreadsheet/xlsbiff5.pas | 25 ++++ components/fpspreadsheet/xlsbiff8.pas | 19 +++ components/fpspreadsheet/xlscommon.pas | 18 ++- 7 files changed, 172 insertions(+), 69 deletions(-) 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