diff --git a/components/fpspreadsheet/fpsopendocument.pas b/components/fpspreadsheet/fpsopendocument.pas
index b7055fe75..951e10e3d 100755
--- a/components/fpspreadsheet/fpsopendocument.pas
+++ b/components/fpspreadsheet/fpsopendocument.pas
@@ -2939,6 +2939,8 @@ var
begin
// some abbreviations...
defFontSize := Workbook.GetFont(0).Size;
+ GetSheetDimensions(ASheet, firstRow, lastRow, firstCol, lastCol);
+ {
firstCol := ASheet.GetFirstColIndex;
firstRow := ASheet.GetFirstRowIndex;
lastCol := ASheet.GetLastColIndex;
@@ -2946,6 +2948,7 @@ begin
// avoid arithmetic overflow in case of empty worksheet
if (firstCol = $FFFFFFFF) and (lastCol = 0) then firstCol := 0;
if (FirstRow = $FFFFFFFF) and (lastRow = 0) then firstRow := 0;
+ }
emptyRowsAbove := firstRow > 0;
// Now loop through all rows
@@ -3103,8 +3106,8 @@ begin
FPointSeparatorSettings.DecimalSeparator:='.';
// http://en.wikipedia.org/wiki/List_of_spreadsheet_software#Specifications
- FLimitations.MaxCols := 1024;
- FLimitations.MaxRows := 1048576;
+ FLimitations.MaxColCount := 1024;
+ FLimitations.MaxRowCount := 1048576;
end;
destructor TsSpreadOpenDocWriter.Destroy;
diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas
index 17c7af044..327f3af4e 100755
--- a/components/fpspreadsheet/fpspreadsheet.pas
+++ b/components/fpspreadsheet/fpspreadsheet.pas
@@ -26,8 +26,8 @@ type
{@@ Record collection limitations of a particular file format }
TsSpreadsheetFormatLimitations = record
- MaxRows: Cardinal;
- MaxCols: Cardinal;
+ MaxRowCount: Cardinal;
+ MaxColCount: Cardinal;
end;
const
@@ -6173,8 +6173,8 @@ constructor TsCustomSpreadWriter.Create(AWorkbook: TsWorkbook);
begin
inherited Create(AWorkbook);
{ A good starting point valid for many formats... }
- FLimitations.MaxCols := 256;
- FLimitations.MaxRows := 65536;
+ FLimitations.MaxColCount := 256;
+ FLimitations.MaxRowCount := 65536;
end;
{@@
@@ -6265,7 +6265,8 @@ end;
{@@
Determines the size of the worksheet to be written. VirtualMode is respected.
- Is called when the writer needs the size for output.
+ Is called when the writer needs the size for output. Column and row count
+ limitations are repsected as well.
@param AWorksheet Worksheet to be written
@param AFirsRow Index of first row to be written
@@ -6276,15 +6277,26 @@ end;
procedure TsCustomSpreadWriter.GetSheetDimensions(AWorksheet: TsWorksheet;
out AFirstRow, ALastRow, AFirstCol, ALastCol: Cardinal);
begin
- AFirstRow := 0;
- AFirstCol := 0;
if (boVirtualMode in AWorksheet.Workbook.Options) then begin
+ AFirstRow := 0;
+ AFirstCol := 0;
ALastRow := AWorksheet.Workbook.VirtualRowCount-1;
ALastCol := AWorksheet.Workbook.VirtualColCount-1;
end else begin
+ Workbook.UpdateCaches;
+ AFirstRow := AWorksheet.GetFirstRowIndex;
+ AFirstCol := AWorksheet.GetFirstColIndex;
ALastRow := AWorksheet.GetLastRowIndex;
ALastCol := AWorksheet.GetLastColIndex;
end;
+ if AFirstCol >= Limitations.MaxColCount then
+ AFirstCol := Limitations.MaxColCount-1;
+ if AFirstRow >= Limitations.MaxRowCount then
+ AFirstRow := Limitations.MaxRowCount-1;
+ if ALastCol >= Limitations.MaxColCount then
+ ALastCol := Limitations.MaxColCount-1;
+ if ALastRow >= Limitations.MaxRowCount then
+ ALastRow := Limitations.MaxRowCount-1;
end;
{@@
@@ -6307,10 +6319,10 @@ var
lastCol, lastRow: Cardinal;
begin
Workbook.GetLastRowColIndex(lastRow, lastCol);
- if lastRow >= FLimitations.MaxRows then
- Workbook.AddErrorMsg(lpMaxRowsExceeded, [lastRow+1, FLimitations.MaxRows]);
- if lastCol >= FLimitations.MaxCols then
- Workbook.AddErrorMsg(lpMaxColsExceeded, [lastCol+1, FLimitations.MaxCols]);
+ if lastRow >= FLimitations.MaxRowCount then
+ Workbook.AddErrorMsg(lpMaxRowsExceeded, [lastRow+1, FLimitations.MaxRowCount]);
+ if lastCol >= FLimitations.MaxColCount then
+ Workbook.AddErrorMsg(lpMaxColsExceeded, [lastCol+1, FLimitations.MaxColCount]);
end;
diff --git a/components/fpspreadsheet/tests/errortests.pas b/components/fpspreadsheet/tests/errortests.pas
index 2e5840251..4a441610d 100644
--- a/components/fpspreadsheet/tests/errortests.pas
+++ b/components/fpspreadsheet/tests/errortests.pas
@@ -30,7 +30,6 @@ type
procedure TestWriteErrorMessages_BIFF8;
procedure TestWriteErrorMessages_ODS;
procedure TestWriteErrorMessages_OOXML;
-
end;
implementation
@@ -62,10 +61,14 @@ var
row, col: Cardinal;
row1, row2: Cardinal;
col1, col2: Cardinal;
+ formula: TsFormula;
s: String;
TempFile: String;
ErrList: TStringList;
begin
+ formula.FormulaStr := '=A1';
+ formula.DoubleValue := 0.0;
+
ErrList := TStringList.Create;
try
// Test 1: Too many rows
@@ -78,7 +81,8 @@ begin
MyWorksheet.WriteBlank(row, 0);
MyWorksheet.WriteNumber(row, 1, 1.0);
MyWorksheet.WriteUTF8Text(row, 2, 'A');
- MyWorksheet.WriteRPNFormula(row, 3, CreateRPNFormula(
+ MyWorksheet.WriteFormula(Row, 3, formula);
+ MyWorksheet.WriteRPNFormula(row, 4, CreateRPNFormula(
RPNCellValue('A1', nil)));
end;
TempFile:=NewTempFile;
@@ -97,10 +101,11 @@ begin
col1 := MAX_COL_COUNT[TTestFormat(AFormat)] - 5;
col2 := MAX_COL_COUNT[TTestFormat(AFormat)] + 5;
for col := col1 to col2 do begin
- MyWorksheet.WriteBlank(row, 0);
- MyWorksheet.WriteNumber(row, 1, 1.0);
- MyWorksheet.WriteUTF8Text(row, 2, 'A');
- MyWorksheet.WriteRPNFormula(row, 3, CreateRPNFormula(
+ MyWorksheet.WriteBlank(0, col);
+ MyWorksheet.WriteNumber(1, col, 1.0);
+ MyWorksheet.WriteUTF8Text(2, col, 'A');
+ MyWorksheet.WriteFormula(3, col, formula);
+ MyWorksheet.WriteRPNFormula(4, col, CreateRPNFormula(
RPNCellValue('A1', nil)));
end;
TempFile:=NewTempFile;
diff --git a/components/fpspreadsheet/tests/spreadtestgui.lpi b/components/fpspreadsheet/tests/spreadtestgui.lpi
index 85297ef2b..e4dc9f4dd 100644
--- a/components/fpspreadsheet/tests/spreadtestgui.lpi
+++ b/components/fpspreadsheet/tests/spreadtestgui.lpi
@@ -48,7 +48,6 @@
-
@@ -63,7 +62,6 @@
-
@@ -78,7 +76,6 @@
-
@@ -91,7 +88,6 @@
-
@@ -100,17 +96,14 @@
-
-
-
diff --git a/components/fpspreadsheet/xlsbiff2.pas b/components/fpspreadsheet/xlsbiff2.pas
index e857e1afb..aa51f57b8 100755
--- a/components/fpspreadsheet/xlsbiff2.pas
+++ b/components/fpspreadsheet/xlsbiff2.pas
@@ -1502,7 +1502,7 @@ var
s: ansistring;
xf: Word;
begin
- if (ARow >= FLimitations.MaxRows) or (ACol >= FLimitations.MaxCols) then
+ if (ARow >= FLimitations.MaxRowCount) or (ACol >= FLimitations.MaxColCount) then
exit;
RPNLength := 0;
@@ -1608,7 +1608,7 @@ var
xf: Word;
rec: TBlankRecord;
begin
- if (ARow >= FLimitations.MaxRows) or (ACol >= FLimitations.MaxCols) then
+ if (ARow >= FLimitations.MaxRowCount) or (ACol >= FLimitations.MaxColCount) then
exit;
xf := FindXFIndex(ACell);
@@ -1667,7 +1667,7 @@ var
var
xf: Word;
begin
- if (ARow >= FLimitations.MaxRows) or (ACol >= FLimitations.MaxCols) then
+ if (ARow >= FLimitations.MaxRowCount) or (ACol >= FLimitations.MaxColCount) then
exit;
if AValue = '' then Exit; // Writing an empty text doesn't work
@@ -1730,7 +1730,7 @@ var
xf: Word;
rec: TBIFF2NumberRecord;
begin
- if (ARow >= FLimitations.MaxRows) or (ACol >= FLimitations.MaxCols) then
+ if (ARow >= FLimitations.MaxRowCount) or (ACol >= FLimitations.MaxColCount) then
exit;
xf := FindXFIndex(ACell);
@@ -1763,8 +1763,8 @@ var
w: Word;
h: Single;
begin
- if (ARowIndex >= FLimitations.MaxRows) or (AFirstColIndex >= FLimitations.MaxCols)
- or (ALastColIndex >= FLimitations.MaxCols)
+ if (ARowIndex >= FLimitations.MaxRowCount) or (AFirstColIndex >= FLimitations.MaxColCount)
+ or (ALastColIndex >= FLimitations.MaxColCount)
then
exit;
diff --git a/components/fpspreadsheet/xlsbiff5.pas b/components/fpspreadsheet/xlsbiff5.pas
index 03ab855f2..9ff85c300 100755
--- a/components/fpspreadsheet/xlsbiff5.pas
+++ b/components/fpspreadsheet/xlsbiff5.pas
@@ -307,6 +307,16 @@ const
);
type
+ TBIFF5DimensionsRecord = packed record
+ RecordID: Word;
+ RecordSize: Word;
+ FirstRow: Word;
+ LastRowPlus1: Word;
+ FirstCol: Word;
+ LastColPlus1: Word;
+ NotUsed: Word;
+ end;
+
TBIFF5LabelRecord = packed record
RecordID: Word;
RecordSize: Word;
@@ -431,7 +441,7 @@ begin
WriteWindow2(AStream, sheet);
WritePane(AStream, sheet, true, pane); // true for "is BIFF5 or BIFF8"
WriteSelection(AStream, sheet, pane);
- WriteRows(AStream, sheet);
+ //WriteRows(AStream, sheet);
if (boVirtualMode in Workbook.Options) then
WriteVirtualCells(AStream)
@@ -551,8 +561,27 @@ end;
}
procedure TsSpreadBIFF5Writer.WriteDimensions(AStream: TStream; AWorksheet: TsWorksheet);
var
- lLastCol, lLastRow: Word;
+ rec: TBIFF5DimensionsRecord;
+ firstCol, lastCol, firstRow, lastRow: Cardinal;
+ lLastRow, lLastCol: Word;
begin
+ { Determine sheet size }
+ GetSheetDimensions(AWorksheet, firstRow, lastRow, firstCol, lastCol);
+
+ { Setup BIFF record }
+ rec.RecordID := WordToLE(INT_EXCEL_ID_DIMENSIONS);
+ rec.RecordSize := WordToLE(10);
+ rec.FirstRow := WordToLE(firstRow);
+ rec.LastRowPlus1 := WordToLE(lastRow+1);
+ rec.FirstCol := WordToLe(firstCol);
+ rec.LastColPlus1 := WordToLE(lastCol+1);
+ rec.NotUsed := 0;
+
+ { Write BIFF record }
+ AStream.WriteBuffer(rec, SizeOf(rec));
+
+ (*
+
{ BIFF Record header }
AStream.WriteWord(WordToLE(INT_EXCEL_ID_DIMENSIONS));
AStream.WriteWord(WordToLE(10));
@@ -573,6 +602,7 @@ begin
{ Not used }
AStream.WriteWord(0);
+ *)
end;
{*******************************************************************
@@ -951,7 +981,7 @@ var
rec: TBIFF5LabelRecord;
buf: array of byte;
begin
- if (ARow >= FLimitations.MaxRows) or (ACol >= FLimitations.MaxCols) then
+ if (ARow >= FLimitations.MaxRowCount) or (ACol >= FLimitations.MaxColCount) then
exit;
case WorkBookEncoding of
diff --git a/components/fpspreadsheet/xlsbiff8.pas b/components/fpspreadsheet/xlsbiff8.pas
index 07484e6a7..2a31c3f03 100755
--- a/components/fpspreadsheet/xlsbiff8.pas
+++ b/components/fpspreadsheet/xlsbiff8.pas
@@ -34,9 +34,11 @@ EOF
The row and column numbering in BIFF files is zero-based.
Excel file format specification obtained from:
-
http://sc.openoffice.org/excelfileformat.pdf
+see also:
+http://office.microsoft.com/en-us/excel-help/excel-specifications-and-limits-HP005199291.aspx
+
AUTHORS: Felipe Monteiro de Carvalho
Jose Mejuto
}
@@ -280,6 +282,16 @@ const
);
type
+ TBIFF8DimensionsRecord = packed record
+ RecordID: Word;
+ RecordSize: Word;
+ FirstRow: DWord;
+ LastRowPlus1: DWord;
+ FirstCol: Word;
+ LastColPlus1: Word;
+ NotUsed: Word;
+ end;
+
TBIFF8LabelRecord = packed record
RecordID: Word;
RecordSize: Word;
@@ -578,7 +590,24 @@ end;
procedure TsSpreadBIFF8Writer.WriteDimensions(AStream: TStream; AWorksheet: TsWorksheet);
var
firstRow, lastRow, firstCol, lastCol: Cardinal;
+ rec: TBIFF8DimensionsRecord;
begin
+ { Determine sheet size }
+ GetSheetDimensions(AWorksheet, firstRow, lastRow, firstCol, lastCol);
+
+ { Populate BIFF record }
+ rec.RecordID := WordToLE(INT_EXCEL_ID_DIMENSIONS);
+ rec.RecordSize := WordToLE(14);
+ rec.FirstRow := DWordToLE(firstRow);
+ rec.LastRowPlus1 := DWordToLE(lastRow+1);
+ rec.FirstCol := WordToLE(firstCol);
+ rec.LastColPlus1 := WordToLE(lastCol+1);
+ rec.NotUsed := 0;
+
+ { Write BIFF record to stream }
+ AStream.WriteBuffer(rec, SizeOf(rec));
+
+ (*
{ BIFF Record header }
AStream.WriteWord(WordToLE(INT_EXCEL_ID_DIMENSIONS));
AStream.WriteWord(WordToLE(14));
@@ -600,6 +629,7 @@ begin
{ Not used }
AStream.WriteWord(WordToLE(0));
+ *)
end;
{*******************************************************************
@@ -996,7 +1026,7 @@ var
rec: TBIFF8LabelRecord;
buf: array of byte;
begin
- if (ARow >= FLimitations.MaxRows) or (ACol >= FLimitations.MaxCols) then
+ if (ARow >= FLimitations.MaxRowCount) or (ACol >= FLimitations.MaxColCount) then
exit;
WideValue := UTF8Decode(AValue); //to UTF16
diff --git a/components/fpspreadsheet/xlscommon.pas b/components/fpspreadsheet/xlscommon.pas
index 527854484..bdff0d1db 100644
--- a/components/fpspreadsheet/xlscommon.pas
+++ b/components/fpspreadsheet/xlscommon.pas
@@ -1852,7 +1852,7 @@ procedure TsSpreadBIFFWriter.WriteBlank(AStream: TStream;
var
rec: TBIFF58BlankRecord;
begin
- if (ARow >= FLimitations.MaxRows) or (ACol >= FLimitations.MaxCols) then
+ if (ARow >= FLimitations.MaxRowCount) or (ACol >= FLimitations.MaxColCount) then
exit;
{ BIFF record header }
@@ -1925,7 +1925,7 @@ var
w: Integer;
begin
if Assigned(ACol) then begin
- if (ACol^.Col >= FLimitations.MaxCols) then
+ if (ACol^.Col >= FLimitations.MaxColCount) then
exit;
{ BIFF record header }
@@ -2041,7 +2041,7 @@ procedure TsSpreadBIFFWriter.WriteNumber(AStream: TStream;
var
rec: TBIFF58NumberRecord;
begin
- if (ARow >= FLimitations.MaxRows) or (ACol >= FLimitations.MaxCols) then
+ if (ARow >= FLimitations.MaxRowCount) or (ACol >= FLimitations.MaxColCount) then
exit;
{ BIFF Record header }
@@ -2269,7 +2269,7 @@ var
RPNLength: Word;
RecordSizePos, FinalPos: Int64;
begin
- if (ARow >= FLimitations.MaxRows) or (ACol >= FLimitations.MaxCols) then
+ if (ARow >= FLimitations.MaxRowCount) or (ACol >= FLimitations.MaxColCount) then
exit;
{ BIFF Record header }
@@ -2494,9 +2494,9 @@ var
rowheight: Word;
h: Single;
begin
- if (ARowIndex >= FLimitations.MaxRows) or
- (AFirstColIndex >= FLimitations.MaxCols) or
- (ALastColIndex >= FLimitations.MaxCols)
+ if (ARowIndex >= FLimitations.MaxRowCount) or
+ (AFirstColIndex >= FLimitations.MaxColCount) or
+ (ALastColIndex >= FLimitations.MaxColCount)
then
exit;
diff --git a/components/fpspreadsheet/xlsxooxml.pas b/components/fpspreadsheet/xlsxooxml.pas
index 2aa118f1c..4694ca6ae 100755
--- a/components/fpspreadsheet/xlsxooxml.pas
+++ b/components/fpspreadsheet/xlsxooxml.pas
@@ -1857,9 +1857,11 @@ begin
AppendToStream(AStream,
'');
+ GetSheetDimensions(AWorksheet, r1, r2, c1, c2);
+
if (boVirtualMode in Workbook.Options) and Assigned(Workbook.OnWriteCellData)
then begin
- for r := 0 to Workbook.VirtualRowCount-1 do begin
+ for r := 0 to r2 do begin
row := AWorksheet.FindRow(r);
if row <> nil then
rh := Format(' ht="%g" customHeight="1"', [
@@ -1868,7 +1870,7 @@ begin
rh := '';
AppendToStream(AStream, Format(
'', [r+1, Workbook.VirtualColCount, rh]));
- for c := 0 to Workbook.VirtualColCount-1 do begin
+ for c := 0 to c2 do begin
InitCell(lCell);
value := varNull;
styleCell := nil;
@@ -1905,6 +1907,7 @@ begin
end else
begin
// The cells need to be written in order, row by row, cell by cell
+ (*
c1 := AWorksheet.GetFirstColIndex;
c2 := AWorksheet.GetLastColIndex;
if (c1 = $FFFFFFFF) and (c2 = 0) then c1 := 0; // avoid arithmetic overflow in case of empty worksheet
@@ -1912,6 +1915,7 @@ begin
r2 := AWorksheet.GetlastRowIndex;
if (r1 = $FFFFFFFF) and (r2 = 0) then r1 := 0; // avoid arithmetic overflow in case of empty worksheet
// for r := 0 to AWorksheet.GetLastRowIndex do begin
+ *)
for r := r1 to r2 do begin
// If the row has a custom height add this value to the specification
row := AWorksheet.FindRow(r);
@@ -2298,8 +2302,8 @@ begin
FPointSeparatorSettings.DecimalSeparator := '.';
// http://en.wikipedia.org/wiki/List_of_spreadsheet_software#Specifications
- FLimitations.MaxCols := 16384;
- FLimitations.MaxRows := 1048576;
+ FLimitations.MaxColCount := 16384;
+ FLimitations.MaxRowCount := 1048576;
end;
procedure TsSpreadOOXMLWriter.CreateNumFormatList;