From 74c64b7258887fc2f2ff64795ce5778bb7ea17e2 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Wed, 9 May 2018 21:38:24 +0000 Subject: [PATCH] fpspreadsheet/formulas with 3d references: Implement BIFF5 reader for 3d references. Some DebugLn insertions for better debugging (triggered by define FPSpreadDebug). git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6400 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../source/common/fpsopendocument.pas | 51 ++++--------------- .../fpspreadsheet/source/common/xlsbiff2.pas | 3 ++ .../fpspreadsheet/source/common/xlsbiff5.pas | 39 ++++++++++++-- .../fpspreadsheet/source/common/xlsbiff8.pas | 12 +++-- .../fpspreadsheet/source/common/xlscommon.pas | 3 ++ 5 files changed, 58 insertions(+), 50 deletions(-) diff --git a/components/fpspreadsheet/source/common/fpsopendocument.pas b/components/fpspreadsheet/source/common/fpsopendocument.pas index 5ab3e7886..0b2ffc437 100644 --- a/components/fpspreadsheet/source/common/fpsopendocument.pas +++ b/components/fpspreadsheet/source/common/fpsopendocument.pas @@ -34,9 +34,6 @@ unit fpsopendocument; interface uses - {$IFDEF FPSpreadDebug} - LazLogger, - {$ENDIF} Classes, SysUtils, laz2_xmlread, laz2_DOM, avglvltree, math, dateutils, contnrs, @@ -293,6 +290,9 @@ var implementation uses + {$IFDEF FPSpreadDebug} + LazLogger, + {$ENDIF} StrUtils, Variants, LazFileUtils, URIParser, LazUTF8, {$IFDEF FPS_VARISBOOL} fpsPatches, @@ -2390,7 +2390,7 @@ var ns: String; begin {$IFDEF FPSpreadDebug} - DebugLn(Format('ReadFormula: ARow=%d, ACol=%d, AStyleIndex=%d', [ARow, ACol, AStyleIndex])); + DebugLn(Format('[ReadFormula] ARow=%d, ACol=%d, AStyleIndex=%d', [ARow, ACol, AStyleIndex])); {$ENDIF} // Create cell and apply format @@ -2416,7 +2416,7 @@ begin if formula <> '' then begin // Formulas written by Spread begin with 'of:=', by Excel with 'msof:='. - // Remove that. And both use different list separators + // Remove that. And both use different list separators. p := pos('=', formula); ns := Copy(formula, 1, p-2); case ns of @@ -2425,36 +2425,7 @@ begin end; Delete(formula, 1, p); end; - (* - if not (boIgnoreFormulas in FWorkbook.Options) then - begin - // ... convert to Excel "A1" dialect used by fps by defailt - parser := TsSpreadsheetParser.Create(FWorksheet); - try - try - parser.Dialect := fdOpenDocument; - parser.LocalizedExpression[FPointSeparatorSettings] := formula; - parser.Dialect := fdExcelA1; - formula := parser.Expression; - except - on E:EExprParser do - begin - Workbook.AddErrorMsg(E.Message); - formula := ''; - if (boAbortReadOnFormulaError in Workbook.Options) then raise; - end; - on E:ECalcEngine do - begin - Workbook.AddErrorMsg(E.Message); - formula := ''; - if (boAbortReadOnFormulaError in Workbook.Options) then raise; - end; - end; - finally - parser.Free; - end; - end; - *) + // ... and store in cell's FormulaValue field. cell^.FormulaValue := formula; // Note: This formula is still in OpenDocument dialect. Conversion to @@ -2464,10 +2435,6 @@ begin {$IFDEF FPSpreadDebug} DebugLn(' Formula found: ' + formula); - (* - if SameText(formula, 'IsText({.B1])') then - formula := formula + ''; - *) {$ENDIF} end; @@ -3535,11 +3502,11 @@ var s: String; colsSpanned, rowsSpanned: Integer; begin - {$IFDEF FPSpreadDebug} - DebugLn(Format('ReadCell: ARow=%d, ACol=%d, AFormatIndex=%d', + {$IFDEF FPSpreadDebug} + DebugLn(Format('[ReadCell] ARow=%d, ACol=%d, AFormatIndex=%d', [ARow, ACol, AFormatIndex]) ); - {$ENDIF} + {$ENDIF} // Workaround for Excel files converted to ods by Calc: These files are // expanded to fill the entire max worksheet. They also have single empty diff --git a/components/fpspreadsheet/source/common/xlsbiff2.pas b/components/fpspreadsheet/source/common/xlsbiff2.pas index 1338a77ad..6e146eecb 100644 --- a/components/fpspreadsheet/source/common/xlsbiff2.pas +++ b/components/fpspreadsheet/source/common/xlsbiff2.pas @@ -176,6 +176,9 @@ procedure InitBiff2Limitations(out ALimitations: TsSpreadsheetFormatLimitations) implementation uses + {$IFDEF FPSpreadDebug} + LazLogger, + {$ENDIF} Math, fpsStrings, fpsReaderWriter, fpsPalette, fpsNumFormat; diff --git a/components/fpspreadsheet/source/common/xlsbiff5.pas b/components/fpspreadsheet/source/common/xlsbiff5.pas index 179bd142a..5a0434350 100644 --- a/components/fpspreadsheet/source/common/xlsbiff5.pas +++ b/components/fpspreadsheet/source/common/xlsbiff5.pas @@ -53,7 +53,6 @@ unit xlsbiff5; {$endif} {$define USE_NEW_OLE} -{.$define FPSPREADDEBUG} //define to print out debug info to console. Used to be XLSDEBUG; interface @@ -81,6 +80,7 @@ type procedure ReadFORMAT(AStream: TStream); override; procedure ReadLABEL(AStream: TStream); override; function ReadRPNCellRange3D(AStream: TStream; var ARPNItem: PRPNItem): Boolean; override; + procedure ReadRPNSheetIndex(AStream: TStream; out ASheet1, ASheet2: Integer); override; procedure ReadRSTRING(AStream: TStream); procedure ReadStandardWidth(AStream: TStream; ASheet: TsWorksheet); procedure ReadStringRecord(AStream: TStream); override; @@ -218,6 +218,9 @@ var implementation uses + {$IFDEF FPSpreadDebug} + LazLogger, + {$ENDIF} Math, fpsStrings, fpsReaderWriter, fpsStreams, fpsPalette, fpsNumFormat, xlsconst; @@ -599,7 +602,7 @@ begin (* $0225: ; //(DEFAULTROWHEIGHT) This record specifies the default height and default flags for rows that do not have a corresponding ROW record. $023E: ; //(WINDOW2) This record contains the range address of the used area in the current sheet. else - WriteLn(format('Record type: %.4X Record Size: %.4X',[RecordType,RecordSize])); + DebugLn(format('Record type: %.4X Record Size: %.4X',[RecordType,RecordSize])); end; {$ENDIF} end; @@ -647,6 +650,34 @@ begin ARPNItem := RPNCellRange3D(sheetIndex1, r1, c1, sheetIndex2, r2, c2, flags, ARPNItem); end; +procedure TsSpreadBIFF5Reader.ReadRPNSheetIndex(AStream: TStream; + out ASheet1, ASheet2: Integer); +var + idx: Int16; +begin + // One-based index to EXTERNSHEET record. Negative to indicate a 3D reference. + // Positive to indicate an external reference + idx := WordLEToN(AStream.ReadWord); + + // We don't support external references at the moment. + if idx > 0 then begin + ASheet1 := -1; + ASheet1 := -1; + exit; + end; + + // Skip 8 unused bytes + AStream.Position := AStream.Position + 8; + + // Zero-based index to first referenced sheet (-1 = deleted sheet) + idx := WordLEToN(AStream.ReadWord); + ASheet1 := idx; + + // Zero-based index to last referenced sheet (-1 = deleted sheet) + idx := WordLEToN(AStream.ReadWord); + ASheet2 := idx; +end; + procedure TsSpreadBIFF5Reader.ReadRSTRING(AStream: TStream); var L, i: Word; @@ -1022,8 +1053,8 @@ begin { Character set } lCodepage := AStream.ReadByte(); - {$ifdef FPSPREADDEBUG} - WriteLn('Reading Font Codepage='+IntToStr(lCodepage)); + {$ifdef FPSpreadDebug} + DebugLn('Reading Font Codepage = ' + IntToStr(lCodepage)); {$endif} { Not used } diff --git a/components/fpspreadsheet/source/common/xlsbiff8.pas b/components/fpspreadsheet/source/common/xlsbiff8.pas index 45736efdc..a53deb05d 100644 --- a/components/fpspreadsheet/source/common/xlsbiff8.pas +++ b/components/fpspreadsheet/source/common/xlsbiff8.pas @@ -50,7 +50,6 @@ unit xlsbiff8; // The new OLE code is much better, so always use it {$define USE_NEW_OLE} -{.$define FPSPREADDEBUG} //define to print out debug info to console. Used to be XLSDEBUG; interface @@ -318,6 +317,9 @@ procedure InitBIFF8Limitations(out ALimitations: TsSpreadsheetFormatLimitations) implementation uses + {$IFDEF FPSpreadDebug} + LazLogger, + {$ENDIF} Math, lconvencoding, LazFileUtils, URIParser, fpsStrings, {%H-}fpsPatches, fpsStreams, fpsReaderWriter, fpsPalette, fpsNumFormat, fpsExprParser, xlsEscher; @@ -930,7 +932,9 @@ begin PendingRecordSize := RecordSize; // For debugging to find out in which record a crash happens: -// WriteLn(Format('Stream.Pos: %d, RecordType: $%.04x, RecordSize: %d', [AStream.Position-4, RecordType, RecordSize])); + {$IFDEF FPSpreadDebug} + DebugLn(Format('[ReadWorksheet] Stream.Pos: %d, RecordType: $%.04x, RecordSize: %d', [AStream.Position-4, RecordType, RecordSize])); + {$ENDIF} CurStreamPos := AStream.Position; @@ -2009,8 +2013,8 @@ begin { Character set } lCodepage := AStream.ReadByte(); - {$ifdef FPSPREADDEBUG} - WriteLn('Reading Font Codepage='+IntToStr(lCodepage)); + {$ifdef FPSpreadDebug} + DebugLn('Reading Font Codepage='+IntToStr(lCodepage)); {$endif} { Not used } diff --git a/components/fpspreadsheet/source/common/xlscommon.pas b/components/fpspreadsheet/source/common/xlscommon.pas index 8913dfd3f..53c17b58d 100644 --- a/components/fpspreadsheet/source/common/xlscommon.pas +++ b/components/fpspreadsheet/source/common/xlscommon.pas @@ -1622,6 +1622,9 @@ end; NOTE: A character #03 is prepended to the sheet name if the EXTERNSHEET stores a reference to one of the own sheets. + + NOTE: The string length field is decreased by 1, if the EXTERNSHEET stores + a reference to one of the own sheets (first character is #03). -------------------------------------------------------------------------------} procedure TsSpreadBIFFReader.ReadExternSheet(AStream: TStream); var