diff --git a/components/fpspreadsheet/examples/excel2demo/excel2read.lpr b/components/fpspreadsheet/examples/excel2demo/excel2read.lpr
index 2bad7981b..fd56de91d 100644
--- a/components/fpspreadsheet/examples/excel2demo/excel2read.lpr
+++ b/components/fpspreadsheet/examples/excel2demo/excel2read.lpr
@@ -42,7 +42,6 @@ begin
WriteLn('Row: ', CurCell^.Row, ' Col: ', CurCell^.Col, ' Value: ',
UTF8ToAnsi(MyWorkSheet.ReadAsUTF8Text(CurCell^.Row, CurCell^.Col))
);
- WriteLn(MyWorkbook.GetFont(CurCell^.FontIndex).Size-11);
CurCell := MyWorkSheet.GetNextCell();
end;
diff --git a/components/fpspreadsheet/examples/excel8demo/excel8write.lpr b/components/fpspreadsheet/examples/excel8demo/excel8write.lpr
index 526847711..f51763f6b 100644
--- a/components/fpspreadsheet/examples/excel8demo/excel8write.lpr
+++ b/components/fpspreadsheet/examples/excel8demo/excel8write.lpr
@@ -75,6 +75,7 @@ begin
MyWorksheet.WriteBorderLineStyle(5, 5, cbNorth, lsThick);
// F7, top border only, but different color
+ MyWorksheet.WriteBorders(6, 5, [cbNorth]);
MyWorksheet.WriteBorderColor(6, 5, cbNorth, scGreen);
MyWorksheet.WriteUTF8Text(6, 5, 'top border green or red?');
// Excel shows it to be red --> the upper border wins
@@ -200,6 +201,10 @@ begin
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, mm:ss.zzz');
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'mm:ss.zzz');
+ // NOTE: The upper option "MSZ" = "mm:ss.z" should result only in 1 decimal.
+ // This is true for writing, but in reading always 3 decimals are displayed.
+ // This is due to fpc's SysUtile.FormatDateTime which does not distinguish
+ // both cases.
// Write formatted numbers
number := 12345.67890123456789;
diff --git a/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi b/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi
index 642efb5fc..3d7ebb480 100644
--- a/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi
+++ b/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi
@@ -149,8 +149,8 @@
-
-
+
+
@@ -220,15 +220,18 @@
+
+
-
-
+
+
+
-
+
@@ -263,7 +266,7 @@
-
+
@@ -298,7 +301,7 @@
-
+
@@ -308,11 +311,10 @@
-
-
+
-
+
@@ -577,47 +579,47 @@
-
+
-
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -625,75 +627,75 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -723,6 +725,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/components/fpspreadsheet/fpsopendocument.pas b/components/fpspreadsheet/fpsopendocument.pas
index 4abd8dc51..3059d6020 100755
--- a/components/fpspreadsheet/fpsopendocument.pas
+++ b/components/fpspreadsheet/fpsopendocument.pas
@@ -46,6 +46,14 @@ type
dm1904 {e.g. Quattro Pro,Mac Excel compatibility}
);
+ { TsSpreadOpenDocNumFormatList }
+ TsSpreadOpenDocNumFormatList = class(TsCustomNumFormatList)
+ protected
+ procedure AddBuiltinFormats; override;
+ public
+// function FormatStringForWriting(AIndex: Integer): String; override;
+ end;
+
{ TsSpreadOpenDocReader }
TsSpreadOpenDocReader = class(TsCustomSpreadReader)
@@ -58,6 +66,7 @@ type
// Figures out what the base year for times in this file (dates are unambiguous)
procedure ReadDateMode(SpreadSheetNode: TDOMNode);
protected
+ procedure CreateNumFormatList; override;
{ Record writing methods }
procedure ReadFormula(ARow : Word; ACol : Word; ACellNode: TDOMNode);
procedure ReadLabel(ARow : Word; ACol : Word; ACellNode: TDOMNode);
@@ -79,6 +88,8 @@ type
// Streams with the contents of files
FSMeta, FSSettings, FSStyles, FSContent, FSMimetype: TStringStream;
FSMetaInfManifest: TStringStream;
+ // Helpers
+ procedure CreateNumFormatList; override;
// Routines to write those files
procedure WriteMimetype;
procedure WriteMetaInfManifest;
@@ -159,8 +170,23 @@ const
DATEMODE_1904_BASE=1462; //1/1/1904 in FPC TDateTime
+{ TsSpreadOpenDocNumFormatList }
+
+procedure TsSpreadOpenDocNumFormatList.AddBuiltinFormats;
+begin
+ // to be filled later...
+end;
+
{ TsSpreadOpenDocReader }
+{ Creates the correct version of the number format list.
+ It is for ods file formats. }
+procedure TsSpreadOpenDocReader.CreateNumFormatList;
+begin
+ FreeAndNil(FNumFormatList);
+ FNumFormatList := TsSpreadOpenDocNumFormatList.Create;
+end;
+
function TsSpreadOpenDocReader.GetAttrValue(ANode : TDOMNode; AAttrName : string) : string;
var
i : integer;
@@ -442,6 +468,12 @@ end;
{ TsSpreadOpenDocWriter }
+procedure TsSpreadOpenDocWriter.CreateNumFormatList;
+begin
+ FreeAndNil(FNumFormatList);
+ FNumFormatList := TsSpreadOpenDocNumFormatList.Create;
+end;
+
procedure TsSpreadOpenDocWriter.WriteMimetype;
begin
FMimetype := 'application/vnd.oasis.opendocument.spreadsheet';
diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas
index 5684e9eb7..463497639 100755
--- a/components/fpspreadsheet/fpspreadsheet.pas
+++ b/components/fpspreadsheet/fpspreadsheet.pas
@@ -125,7 +125,18 @@ type
{@@ Describes the type of content of a cell on a TsWorksheet }
TCellContentType = (cctEmpty, cctFormula, cctRPNFormula, cctNumber,
- cctUTF8String, cctDateTime);
+ cctUTF8String, cctDateTime, cctBool, cctError);
+
+ {@@ Error code values }
+ TErrorValue = (
+ errEmptyIntersection, // #NULL!
+ errDivideByZero, // #DIV/0!
+ errWrongType, // #VALUE!
+ errIllegalRef, // #REF!
+ errWrongName, // #NAME?
+ errOverflow, // #NUM!
+ errArgNotAvail // #N/A
+ );
{@@ List of possible formatting fields }
TsUsedFormattingField = (uffTextRotation, uffFont, uffBold, uffBorder,
@@ -278,6 +289,8 @@ type
NumberValue: double;
UTF8StringValue: ansistring;
DateTimeValue: TDateTime;
+ BoolValue: Boolean;
+ StatusValue: Byte;
{ Formatting fields }
UsedFormattingFields: TsUsedFormattingFields;
FontIndex: Integer;
@@ -369,8 +382,10 @@ type
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double;
AFormatString: String); overload;
procedure WriteBlank(ARow, ACol: Cardinal);
+ procedure WriteBoolValue(ARow, ACol: Cardinal; AValue: Boolean);
procedure WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = '');
+ procedure WriteErrorValue(ARow, ACol: Cardinal; AValue: TErrorValue);
procedure WriteFormula(ARow, ACol: Cardinal; AFormula: TsFormula);
procedure WriteRPNFormula(ARow, ACol: Cardinal; AFormula: TsRPNFormula);
{ Writing of cell attributes }
@@ -688,6 +703,15 @@ resourcestring
lpNoValidSpreadsheetFile = '"%s" is not a valid spreadsheet file';
lpUnknownSpreadsheetFormat = 'unknown format';
lpInvalidFontIndex = 'Invalid font index';
+ lpTRUE = 'TRUE';
+ lpFALSE = 'FALSE';
+ lpErrEmptyIntersection = '#NULL!';
+ lpErrDivideByZero = '#DIV/0!';
+ lpErrWrongType = '#VALUE!';
+ lpErrIllegalRef = '#REF!';
+ lpErrWrongName = '#NAME?';
+ lpErrOverflow = '#NUM!';
+ lpErrArgNotAvail = '#N/A';
var
{@@
@@ -1173,6 +1197,18 @@ begin
Result := UTF8StringValue;
cctDateTime:
Result := DateTimeToStrNoNaN(DateTimeValue, NumberFormat, NumberFormatStr, NumberDecimals);
+ cctBool:
+ Result := IfThen(BoolValue, lpTRUE, lpFALSE);
+ cctError:
+ case TErrorValue(StatusValue and $0F) of
+ errEmptyIntersection: Result := lpErrEmptyIntersection;
+ errDivideByZero : Result := lpErrDivideByZero;
+ errWrongType : Result := lpErrWrongType;
+ errIllegalRef : Result := lpErrIllegalRef;
+ errWrongName : Result := lpErrWrongName;
+ errOverflow : Result := lpErrOverflow;
+ errArgNotAvail : Result := lpErrArgNotAvail;
+ end;
else
Result := '';
end;
@@ -1382,6 +1418,23 @@ begin
ChangedCell(ARow, ACol);
end;
+{@@
+ Writes as boolean cell
+
+ @param ARow The row of the cell
+ @param ACol The column of the cell
+ @param AValue The boolean value
+}
+procedure TsWorksheet.WriteBoolValue(ARow, ACol: Cardinal; AValue: Boolean);
+var
+ ACell: PCell;
+begin
+ ACell := GetCell(ARow, ACol);
+ ACell^.ContentType := cctBool;
+ ACell^.BoolValue := AValue;
+ ChangedCell(ARow, ACol);
+end;
+
{@@
Writes a date/time value to a determined cell
@@ -1446,6 +1499,23 @@ begin
ChangedCell(ARow, ACol);
end;
+{@@
+ Writes a cell with an error.
+
+ @param ARow The row of the cell
+ @param ACol The column of the cell
+ @param AValue The error code value
+}
+procedure TsWorksheet.WriteErrorValue(ARow, ACol: Cardinal; AValue: TErrorValue);
+var
+ ACell: PCell;
+begin
+ ACell := GetCell(ARow, ACol);
+ ACell^.ContentType := cctError;
+ ACell^.StatusValue := (ACell^.StatusValue and $F0) or ord(AValue);
+ ChangedCell(ARow, ACol);
+end;
+
{@@
Writes a formula to a determined cell
@@ -2553,8 +2623,12 @@ begin
ANumFormat := nfShortDateTime
else if isDate then
ANumFormat := SHORT_LONG_DATE[isLongDate]
- else if isTime then
- ANumFormat := AMPM_SHORT_LONG_TIME[isAMPM, isLongTime]
+ else if isTime then begin
+ if (ADecimals > 0) and (not isAMPM) then
+ ANumFormat := nfFmtDateTime
+ else
+ ANumFormat := AMPM_SHORT_LONG_TIME[isAMPM, isLongTime]
+ end
else if AFormatString <> '' then
ANumFormat := nfCustom;
end;
diff --git a/components/fpspreadsheet/tests/formattests.pas b/components/fpspreadsheet/tests/formattests.pas
index c0406372d..7150d29f1 100644
--- a/components/fpspreadsheet/tests/formattests.pas
+++ b/components/fpspreadsheet/tests/formattests.pas
@@ -189,7 +189,7 @@ begin
SollDateTimeStrings[i, 6] := FormatDateTime('dd/mmm', SollDateTimes[i]);
SollDateTimeStrings[i, 7] := FormatDateTime('mmm/yy', SollDateTimes[i]);
SollDateTimeStrings[i, 8] := FormatDateTime('nn:ss', SollDateTimes[i]);
- SollDateTimeStrings[i, 9] := TimeIntervalToString(SollDateTimes[i]);
+ SollDateTimeStrings[i, 9] := FormatDateTime('[h]:mm:ss', SollDateTimes[i]);
end;
// Column width
diff --git a/components/fpspreadsheet/tests/stringtests.pas b/components/fpspreadsheet/tests/stringtests.pas
index da6b7fe89..b13d2c51c 100644
--- a/components/fpspreadsheet/tests/stringtests.pas
+++ b/components/fpspreadsheet/tests/stringtests.pas
@@ -25,7 +25,7 @@ uses
// Not using lazarus package as the user may be working with multiple versions
// Instead, add .. to unit search path
Classes, SysUtils, fpcunit, testutils, testregistry,
- fpsallformats, fpspreadsheet, xlsbiff8 {and a project requirement for lclbase for utf8 handling},
+ fpsallformats, fpsutils, fpspreadsheet, xlsbiff8 {and a project requirement for lclbase for utf8 handling},
testsutility;
var
diff --git a/components/fpspreadsheet/tests/testbiff8.xls b/components/fpspreadsheet/tests/testbiff8.xls
index 5093f294b..a3c729c5e 100644
Binary files a/components/fpspreadsheet/tests/testbiff8.xls and b/components/fpspreadsheet/tests/testbiff8.xls differ
diff --git a/components/fpspreadsheet/xlsbiff2.pas b/components/fpspreadsheet/xlsbiff2.pas
index a51c199eb..19d4c325f 100755
--- a/components/fpspreadsheet/xlsbiff2.pas
+++ b/components/fpspreadsheet/xlsbiff2.pas
@@ -130,37 +130,6 @@ var
$00FFFF // $07: cyan
);
-(*
-{ These are the built-in number formats of BIFF2. They are not stored in
- the file. Note that, compared to the BUFF5+ built-in formats, two formats
- are missing and the indexes are offset by 2 after #11.
- It seems that BIFF2 can handle only these 21 formats. The other formats
- available in fpspreadsheet are mapped to these 21 formats such that least
- destruction is made. }
- NUMFORMAT_BIFF2: array[0..20] of string = (
- 'General', // 0
- '0',
- '0.00',
- '#,##0',
- '#,##0.00',
- '"$"#,##0_);("$"#,##0)', // 5
- '"$"#,##0_);[Red]("$"#,##0)',
- '"$"#,##0.00_);("$"#,##0.00)',
- '"$"#,##0.00_);[Red]("$"#,##0.00)',
- '0%',
- '0.00%', // 10
- '0.00E+00',
- 'M/D/YY',
- 'D-MMM-YY',
- 'D-MMM',
- 'MMM-YY', // 15
- 'h:mm AM/PM',
- 'h:mm:ss AM/PM',
- 'h:mm',
- 'h:mm:ss',
- 'M/D/YY h:mm' // 20
- );
-*)
implementation
@@ -193,36 +162,7 @@ const
INT_EXCEL_SHEET = $0010;
INT_EXCEL_CHART = $0020;
INT_EXCEL_MACRO_SHEET = $0040;
- (*
- { FORMAT record constants for BIFF2 }
- // Subset of the built-in formats for US Excel,
- // including those needed for date/time output
- FORMAT_GENERAL = 0; //general/default format
- FORMAT_FIXED_0_DECIMALS = 1; //fixed, 0 decimals
- FORMAT_FIXED_2_DECIMALS = 2; //fixed, 2 decimals
- FORMAT_FIXED_THOUSANDS_0_DECIMALS = 3; //fixed, w/ thousand separator, 0 decs
- FORMAT_FIXED_THOUSANDS_2_DECIMALS = 4; //fixed, w/ thousand separator, 2 decs
- FORMAT_CURRENCY_0_DECIMALS = 5; //currency (with currency symbol), 0 decs
- FORMAT_CURRENCY_2_DECIMALS = 7; //currency (with currency symbol), 2 decs
- FORMAT_PERCENT_0_DECIMALS = 9; //percent, 0 decimals
- FORMAT_PERCENT_2_DECIMALS = 10; //percent, 2 decimals
- FORMAT_EXP_2_DECIMALS = 11; //exponent, 2 decimals
- FORMAT_SCI_1_DECIMAL = 11; //scientific, 1 decimal -- not present in BIFF2 -- mapped to EXP_2_DECIMALS
- FORMAT_SHORT_DATE = 12; //short date
- FORMAT_DATE_DM = 14; //date D-MMM
- FORMAT_DATE_MY = 15; //date MMM-YYYY
- FORMAT_SHORT_TIME_AM = 16; //short time H:MM with AM
- FORMAT_LONG_TIME_AM = 17; //long time H:MM:SS with AM
- FORMAT_SHORT_TIME = 18; //short time H:MM
- FORMAT_LONG_TIME = 19; //long time H:MM:SS
- FORMAT_SHORT_DATETIME = 20; //short date+time
- { The next three formats are not available in BIFF2. They should not be used
- when a file is to be saved in BIFF2. If it IS saved as BIFF2 the formats
- are mapped to FORMAT_LONG_TIME}
- FORMAT_TIME_MS = 19; //time MM:SS
- FORMAT_TIME_MSZ = 19; //time MM:SS.0
- FORMAT_TIME_INTERVAL = 19; //time [hh]:mm:ss, hh can be >24
- *)
+
{ TsBIFF2NumFormatList }
@@ -351,74 +291,19 @@ end;
procedure TsSpreadBIFF2Reader.ExtractNumberFormat(AXFIndex: WORD;
out ANumberFormat: TsNumberFormat; out ADecimals: Word;
out ANumberFormatStr: String);
-const
- NOT_USED = nfGeneral;
- fmts: array[1..20] of TsNumberFormat = (
- nfFixed, nfFixed, nfFixedTh, nfFixedTh, nfFixedTh, // 1..5
- nfFixedTh, nfFixedTh, nfFixedTh, nfPercentage, nfPercentage, // 6..10
- nfExp, nfShortDate, nfShortDate, nfFmtDateTime, nfFmtDateTime, // 11..15
- nfShortTimeAM, nfLongTimeAM, nfShortTime, nfLongTime, nfShortDateTime// 16..20
- );
- decs: array[1..20] of word = (
- 0, 2, 0, 2, 0, 0, 2, 2, 0, 2, // 1..10
- 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 11..20
- );
var
lNumFormatData: TsNumFormatData;
- lXFData: TXFListData;
- isAMPM: Boolean;
- isLongTime: Boolean;
- isMilliSec: Boolean;
- t,d: Boolean;
begin
- ANumberFormat := nfGeneral;
- ANumberFormatStr := '';
- ADecimals := 0;
- (*
lNumFormatData := FindNumFormatDataForCell(AXFIndex);
- if lNumFormatData = nil then begin
- // no custom format, so first test for default formats
- lXFData := TXFListData (FXFList.Items[AXFIndex]);
- if (lXFData.FormatIndex > 0) and (lXFData.FormatIndex <= 20) then begin
- ANumberFormat := fmts[lXFData.FormatIndex];
- ADecimals := decs[lXFData.FormatIndex];
- end;
- end else
- // The next is copied from xlscommon - I think it's not necessary here
- if IsPercentNumberFormat(lNumFormatData.FormatString, ADecimals) then
- ANumberFormat := nfPercentage
- else
- if IsExpNumberFormat(lNumFormatData.Formatstring, ADecimals) then
- ANumberFormat := nfExp
- else
- if IsThousandSepNumberFormat(lNumFormatData.FormatString, ADecimals) then
- ANumberFormat := nfFixedTh
- else
- if IsFixedNumberFormat(lNumFormatData.FormatString, ADecimals) then
- ANumberFormat := nfFixed
- else begin
- t := IsTimeFormat(lNumFormatData.FormatString, isLongTime, isAMPM, isMilliSec);
- d := IsDateFormat(lNumFormatData.FormatString, isLongDate);
- if d and t then
- ANumberFormat := nfShortDateTime
- else
- if d then
- ANumberFormat := nfShortDate
- else
- if t then begin
- if isAMPM then begin
- if isLongTime then
- ANumberFormat := nfLongTimeAM
- else
- ANumberFormat := nfShortTimeAM;
- end else begin
- if isLongTime then
- ANumberFormat := nfLongTime
- else
- ANumberFormat := nfShortTime;
- end;
- end;
- end; *)
+ if lNumFormatData <> nil then begin
+ ANumberFormat := lNumFormatData.NumFormat;
+ ANumberFormatStr := lNumFormatData.FormatString;
+ ADecimals := lNumFormatData.Decimals;
+ end else begin
+ ANumberFormat := nfGeneral;
+ ANumberFormatStr := '';
+ ADecimals := 0;
+ end;
end;
procedure TsSpreadBIFF2Reader.ReadBlank(AStream: TStream);
@@ -513,22 +398,20 @@ begin
CurStreamPos := AStream.Position;
case RecordType of
-
- INT_EXCEL_ID_BLANK : ReadBlank(AStream);
- INT_EXCEL_ID_FONT : ReadFont(AStream);
- INT_EXCEL_ID_FONTCOLOR : ReadFontColor(AStream);
- INT_EXCEL_ID_INTEGER : ReadInteger(AStream);
- INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
- INT_EXCEL_ID_LABEL : ReadLabel(AStream);
- INT_EXCEL_ID_FORMULA : ReadFormula(AStream);
- INT_EXCEL_ID_COLWIDTH : ReadColWidth(AStream);
- INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
- INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream);
- INT_EXCEL_ID_PANE : ReadPane(AStream);
- INT_EXCEL_ID_XF : ReadXF(AStream);
- INT_EXCEL_ID_BOF : ;
- INT_EXCEL_ID_EOF : BIFF2EOF := True;
-
+ INT_EXCEL_ID_BLANK : ReadBlank(AStream);
+ INT_EXCEL_ID_FONT : ReadFont(AStream);
+ INT_EXCEL_ID_FONTCOLOR : ReadFontColor(AStream);
+ INT_EXCEL_ID_INTEGER : ReadInteger(AStream);
+ INT_EXCEL_ID_NUMBER : ReadNumber(AStream);
+ INT_EXCEL_ID_LABEL : ReadLabel(AStream);
+ INT_EXCEL_ID_FORMULA : ReadFormula(AStream);
+ INT_EXCEL_ID_COLWIDTH : ReadColWidth(AStream);
+ INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
+ INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream);
+ INT_EXCEL_ID_PANE : ReadPane(AStream);
+ INT_EXCEL_ID_XF : ReadXF(AStream);
+ INT_EXCEL_ID_BOF : ;
+ INT_EXCEL_ID_EOF : BIFF2EOF := True;
else
// nothing
end;
diff --git a/components/fpspreadsheet/xlsbiff8.pas b/components/fpspreadsheet/xlsbiff8.pas
index 727cd06ba..9c51dc89c 100755
--- a/components/fpspreadsheet/xlsbiff8.pas
+++ b/components/fpspreadsheet/xlsbiff8.pas
@@ -78,21 +78,16 @@ type
procedure ReadWorksheet(AStream: TStream; AData: TsWorkbook);
procedure ReadBoundsheet(AStream: TStream);
function ReadString(const AStream: TStream; const ALength: WORD): UTF8String;
- procedure ReadSST(const AStream: TStream);
- procedure ReadLabelSST(const AStream: TStream);
- // Read XF record
- procedure ReadXF(const AStream: TStream);
- // Workbook Globals records
- // procedure ReadCodepage in xlscommon
- // procedure ReadDateMode in xlscommon
+ protected
+ procedure ReadBlank(AStream: TStream); override;
procedure ReadFont(const AStream: TStream);
procedure ReadFormat(AStream: TStream); override;
- { Record reading methods }
- procedure ReadBlank(AStream: TStream); override;
procedure ReadLabel(AStream: TStream); override;
+ procedure ReadLabelSST(const AStream: TStream);
procedure ReadRichString(const AStream: TStream);
- protected
+ procedure ReadSST(const AStream: TStream);
procedure ReadStringRecord(AStream: TStream; var AStringResult: String); override;
+ procedure ReadXF(const AStream: TStream);
public
destructor Destroy; override;
{ General reading methods }
@@ -1750,16 +1745,13 @@ procedure TsSpreadBIFF8Reader.ReadStringRecord(AStream: TStream;
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);
diff --git a/components/fpspreadsheet/xlscommon.pas b/components/fpspreadsheet/xlscommon.pas
index 871072dab..df8c00827 100644
--- a/components/fpspreadsheet/xlscommon.pas
+++ b/components/fpspreadsheet/xlscommon.pas
@@ -237,33 +237,6 @@ const
{ DATEMODE record, 5.28 }
DATEMODE_1900_BASE=1; //1/1/1900 minus 1 day in FPC TDateTime
DATEMODE_1904_BASE=1462; //1/1/1904 in FPC TDateTime
- (*
- { FORMAT record constants for BIFF5-BIFF8}
- // Subset of the built-in formats for US Excel,
- // including those needed for date/time output
- FORMAT_GENERAL = 0; //general/default format
- FORMAT_FIXED_0_DECIMALS = 1; //fixed, 0 decimals
- FORMAT_FIXED_2_DECIMALS = 2; //fixed, 2 decimals
- FORMAT_FIXED_THOUSANDS_0_DECIMALS = 3; //fixed, w/ thousand separator, 0 decs
- FORMAT_FIXED_THOUSANDS_2_DECIMALS = 4; //fixed, w/ thousand separator, 2 decs
- FORMAT_CURRENCY_0_DECIMALS = 5; //currency (with currency symbol), 0 decs
- FORMAT_CURRENCY_2_DECIMALS = 7; //currency (with currency symbol), 2 decs
- FORMAT_PERCENT_0_DECIMALS = 9; //percent, 0 decimals
- FORMAT_PERCENT_2_DECIMALS = 10; //percent, 2 decimals
- FORMAT_EXP_2_DECIMALS = 11; //exponent, 2 decimals
- FORMAT_SHORT_DATE = 14; //short date
- FORMAT_DATE_DM = 16; //date D-MMM
- FORMAT_DATE_MY = 17; //date MMM-YYYY
- FORMAT_SHORT_TIME_AM = 18; //short time H:MM with AM
- FORMAT_LONG_TIME_AM = 19; //long time H:MM:SS with AM
- FORMAT_SHORT_TIME = 20; //short time H:MM
- FORMAT_LONG_TIME = 21; //long time H:MM:SS
- FORMAT_SHORT_DATETIME = 22; //short date+time
- FORMAT_TIME_MS = 45; //time MM:SS
- FORMAT_TIME_INTERVAL = 46; //time [hh]:mm:ss, hh can be >24
- FORMAT_TIME_MSZ = 47; //time MM:SS.0
- FORMAT_SCI_1_DECIMAL = 48; //scientific, 1 decimal
- *)
{ WINDOW1 record constants - BIFF5-BIFF8 }
MASK_WINDOW1_OPTION_WINDOW_HIDDEN = $0001;
@@ -336,6 +309,14 @@ const
MASK_XF_VERT_ALIGN_BOTTOM = $20;
MASK_XF_VERT_ALIGN_JUSTIFIED = $30;
+ { Error codes }
+ ERR_INTERSECTION_EMPTY = $00; // #NULL!
+ ERR_DIVIDE_BY_ZERO = $07; // #DIV/0!
+ ERR_WRONG_TYPE_OF_OPERAND = $0F; // #VALUE!
+ ERR_ILLEGAL_REFERENCE = $17; // #REF!
+ ERR_WRONG_NAME = $1D; // #NAME?
+ ERR_OVERFLOW = $24; // #NUM!
+ ERR_NOT_AVAILABLE = $2A; // #N/A
type
TDateMode=(dm1900,dm1904); //DATEMODE values, 5.28
@@ -943,6 +924,7 @@ var
nd: Word;
nfs: String;
resultStr: String;
+ err: TErrorValue;
begin
{ BIFF Record header }
@@ -970,18 +952,33 @@ begin
//RPN data not used by now
AStream.Position := AStream.Position + FormulaSize;
-
+ (*
+ // Now determine the type of the formula result
if (Data[6] = $FF) and (Data[7] = $FF) then
case Data[0] of
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)');
+ if resultStr = '' then
+ FWorksheet.WriteBlank(ARow, ACol)
+ else
+ FWorksheet.WriteUTF8Text(ARow, ACol, resultStr);
+ end;
+ 1: FWorksheet.WriteBoolValue(ARow, ACol, Data[2] = 1);
+ 2: begin
+ case Data[2] of
+ ERR_INTERSECTION_EMPTY : err := errEmptyIntersection;
+ ERR_DIVIDE_BY_ZERO : err := errDivideByZero;
+ ERR_WRONG_TYPE_OF_OPERAND: err := errWrongType;
+ ERR_ILLEGAL_REFERENCE : err := errIllegalRef;
+ ERR_WRONG_NAME : err := errWrongName;
+ ERR_OVERFLOW : err := errOverflow;
+ ERR_NOT_AVAILABLE : err := errArgNotAvail;
+ end;
+ FWorksheet.WriteErrorValue(ARow, ACol, err);
+ end;
+ 3: FWorksheet.WriteBlank(ARow, ACol);
end
- else begin
+ else begin *)
if SizeOf(Double) <> 8 then
raise Exception.Create('Double is not 8 bytes');
@@ -994,7 +991,7 @@ begin
FWorksheet.WriteDateTime(ARow, ACol, dt, nf, nfs)
else
FWorksheet.WriteNumber(ARow, ACol, ResultFormula, nf, nd);
- end;
+// end;
{Add attributes}
ApplyCellFormatting(ARow, ACol, XF);
@@ -1076,7 +1073,7 @@ var
nd: word;
nfs: String;
begin
- ReadRowColXF(AStream,ARow,ACol,XF);
+ ReadRowColXF(AStream, ARow, ACol, XF);
{ IEE 754 floating-point value }
AStream.ReadBuffer(value, 8);
@@ -1609,14 +1606,21 @@ end;
procedure TsSpreadBIFFWriter.WriteFormats(AStream: TStream);
var
i: Integer;
+
+ item: TsNumFormatData;
+
begin
ListAllNumFormats;
+
+ item := NumFormatList[20];
+
i := NumFormatList.Find(NumFormatList.FirstFormatIndexInFile);
- while i < NumFormatList.Count do begin
- if NumFormatList[i] <> nil then
- WriteFormat(AStream, NumFormatList[i], i);
- inc(i);
- end;
+ if i > -1 then
+ while i < NumFormatList.Count do begin
+ if NumFormatList[i] <> nil then
+ WriteFormat(AStream, NumFormatList[i], i);
+ inc(i);
+ end;
end;
{ Writes a 64-bit floating point NUMBER record.