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
This commit is contained in:
wp_xxyyzz
2018-05-09 21:38:24 +00:00
parent bfb8cff66e
commit 74c64b7258
5 changed files with 58 additions and 50 deletions

View File

@ -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

View File

@ -176,6 +176,9 @@ procedure InitBiff2Limitations(out ALimitations: TsSpreadsheetFormatLimitations)
implementation
uses
{$IFDEF FPSpreadDebug}
LazLogger,
{$ENDIF}
Math,
fpsStrings, fpsReaderWriter, fpsPalette, fpsNumFormat;

View File

@ -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 }

View File

@ -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 }

View File

@ -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