fpspreadsheet: Fix crash of unit test. Still some number format detection issues.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3046 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-05-14 23:17:46 +00:00
parent c3f5600c0d
commit 283a28fabd
11 changed files with 257 additions and 257 deletions

View File

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

View File

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

View File

@ -149,8 +149,8 @@
<UnitName Value="fpspreadsheetgrid"/>
<EditorIndex Value="2"/>
<WindowIndex Value="0"/>
<TopLine Value="83"/>
<CursorPos X="15" Y="96"/>
<TopLine Value="525"/>
<CursorPos X="30" Y="533"/>
<UsageCount Value="100"/>
<Loaded Value="True"/>
</Unit3>
@ -220,15 +220,18 @@
<Unit12>
<Filename Value="d:\lazarus-svn\lcl\grids.pas"/>
<UnitName Value="Grids"/>
<IsVisibleTab Value="True"/>
<EditorIndex Value="6"/>
<WindowIndex Value="0"/>
<TopLine Value="2464"/>
<CursorPos X="1" Y="2495"/>
<TopLine Value="4852"/>
<CursorPos X="16" Y="4884"/>
<UsageCount Value="48"/>
<Loaded Value="True"/>
</Unit12>
<Unit13>
<Filename Value="..\..\fpsutils.pas"/>
<UnitName Value="fpsutils"/>
<EditorIndex Value="8"/>
<EditorIndex Value="9"/>
<WindowIndex Value="0"/>
<TopLine Value="614"/>
<CursorPos X="23" Y="621"/>
@ -263,7 +266,7 @@
<EditorIndex Value="5"/>
<WindowIndex Value="0"/>
<TopLine Value="1747"/>
<CursorPos X="1" Y="1764"/>
<CursorPos X="25" Y="1779"/>
<UsageCount Value="78"/>
<Bookmarks Count="1">
<Item0 X="1" Y="1761" ID="1"/>
@ -298,7 +301,7 @@
<Unit21>
<Filename Value="..\..\xlsbiff5.pas"/>
<UnitName Value="xlsbiff5"/>
<EditorIndex Value="6"/>
<EditorIndex Value="7"/>
<WindowIndex Value="0"/>
<TopLine Value="1363"/>
<CursorPos X="1" Y="1364"/>
@ -308,11 +311,10 @@
<Unit22>
<Filename Value="..\..\xlsbiff2.pas"/>
<UnitName Value="xlsbiff2"/>
<IsVisibleTab Value="True"/>
<EditorIndex Value="7"/>
<EditorIndex Value="8"/>
<WindowIndex Value="0"/>
<TopLine Value="664"/>
<CursorPos X="30" Y="687"/>
<CursorPos X="21" Y="677"/>
<UsageCount Value="62"/>
<Loaded Value="True"/>
</Unit22>
@ -577,47 +579,47 @@
<JumpHistory Count="30" HistoryIndex="29">
<Position1>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1755" Column="19" TopLine="1715"/>
<Caret Line="1753" Column="1" TopLine="1738"/>
</Position1>
<Position2>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1964" Column="1" TopLine="1924"/>
<Caret Line="1968" Column="1" TopLine="1928"/>
</Position2>
<Position3>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="1210" Column="81" TopLine="1176"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1" Column="1" TopLine="1"/>
</Position3>
<Position4>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="1959" Column="1" TopLine="1919"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="80" Column="21" TopLine="47"/>
</Position4>
<Position5>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="41" Column="1" TopLine="41"/>
<Caret Line="1760" Column="1" TopLine="1744"/>
</Position5>
<Position6>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1753" Column="1" TopLine="1738"/>
<Caret Line="95" Column="22" TopLine="75"/>
</Position6>
<Position7>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1968" Column="1" TopLine="1928"/>
<Caret Line="1" Column="1" TopLine="1"/>
</Position7>
<Position8>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1" Column="1" TopLine="1"/>
<Caret Line="1524" Column="37" TopLine="1516"/>
</Position8>
<Position9>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="80" Column="21" TopLine="47"/>
<Caret Line="1649" Column="21" TopLine="1622"/>
</Position9>
<Position10>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1760" Column="1" TopLine="1744"/>
<Caret Line="1527" Column="3" TopLine="1524"/>
</Position10>
<Position11>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="95" Column="22" TopLine="75"/>
<Caret Line="1758" Column="3" TopLine="1733"/>
</Position11>
<Position12>
<Filename Value="..\..\xlsbiff8.pas"/>
@ -625,75 +627,75 @@
</Position12>
<Position13>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1524" Column="37" TopLine="1516"/>
<Caret Line="51" Column="19" TopLine="18"/>
</Position13>
<Position14>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1649" Column="21" TopLine="1622"/>
<Caret Line="57" Column="11" TopLine="24"/>
</Position14>
<Position15>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1527" Column="3" TopLine="1524"/>
<Caret Line="67" Column="13" TopLine="34"/>
</Position15>
<Position16>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1758" Column="3" TopLine="1733"/>
<Caret Line="1394" Column="3" TopLine="1388"/>
</Position16>
<Position17>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1" Column="1" TopLine="1"/>
<Caret Line="1761" Column="3" TopLine="1738"/>
</Position17>
<Position18>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="51" Column="19" TopLine="18"/>
<Caret Line="95" Column="75" TopLine="76"/>
</Position18>
<Position19>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="57" Column="11" TopLine="24"/>
<Caret Line="1749" Column="8" TopLine="1747"/>
</Position19>
<Position20>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="67" Column="13" TopLine="34"/>
<Caret Line="95" Column="55" TopLine="95"/>
</Position20>
<Position21>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1394" Column="3" TopLine="1388"/>
<Caret Line="1748" Column="49" TopLine="1733"/>
</Position21>
<Position22>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1761" Column="3" TopLine="1738"/>
<Caret Line="95" Column="55" TopLine="95"/>
</Position22>
<Position23>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="95" Column="75" TopLine="76"/>
<Caret Line="1749" Column="8" TopLine="1747"/>
</Position23>
<Position24>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1749" Column="8" TopLine="1747"/>
</Position24>
<Position25>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="95" Column="55" TopLine="95"/>
</Position25>
<Position26>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1748" Column="49" TopLine="1733"/>
</Position26>
<Position27>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="95" Column="55" TopLine="95"/>
</Position27>
<Position28>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1749" Column="8" TopLine="1747"/>
</Position28>
<Position29>
<Filename Value="..\..\xlsbiff5.pas"/>
<Caret Line="1370" Column="1" TopLine="1358"/>
</Position29>
<Position30>
</Position24>
<Position25>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="39" Column="3" TopLine="10"/>
</Position25>
<Position26>
<Filename Value="..\..\xlsbiff2.pas"/>
<Caret Line="677" Column="21" TopLine="664"/>
</Position26>
<Position27>
<Filename Value="..\..\fpspreadsheetgrid.pas"/>
<Caret Line="524" Column="27" TopLine="524"/>
</Position27>
<Position28>
<Filename Value="..\..\fpspreadsheetgrid.pas"/>
<Caret Line="1" Column="1" TopLine="1"/>
</Position28>
<Position29>
<Filename Value="..\..\fpspreadsheetgrid.pas"/>
<Caret Line="1787" Column="3" TopLine="1779"/>
</Position29>
<Position30>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1779" Column="25" TopLine="1747"/>
</Position30>
</JumpHistory>
</ProjectOptions>
@ -723,6 +725,15 @@
</Other>
</CompilerOptions>
<Debugging>
<BreakPoints Count="1">
<Item1>
<Kind Value="bpkSource"/>
<WatchScope Value="wpsLocal"/>
<WatchKind Value="wpkWrite"/>
<Source Value="..\..\fpspreadsheetgrid.pas"/>
<Line Value="1790"/>
</Item1>
</BreakPoints>
<Watches Count="2">
<Item1>
<Expression Value="acol"/>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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