diff --git a/components/fpspreadsheet/examples/fpsctrls/main.pas b/components/fpspreadsheet/examples/fpsctrls/main.pas
index 3c0c5ffb0..b73fa2c68 100644
--- a/components/fpspreadsheet/examples/fpsctrls/main.pas
+++ b/components/fpspreadsheet/examples/fpsctrls/main.pas
@@ -321,7 +321,7 @@ begin
7: WorkbookSource.FileFormat := sfOpenDocument; // Open/LibreOffice
8: WorkbookSource.FileFormat := sfCSV; // Text files
end;
- WorkbookSource.FileName := AcFileOpen.Dialog.FileName; // this loads the file
+ WorkbookSource.FileName := UTF8ToAnsi(AcFileOpen.Dialog.FileName); // this loads the file
UpdateCaption;
end;
@@ -341,7 +341,7 @@ begin
6: fmt := sfCSV;
7: fmt := sfWikiTable_WikiMedia;
end;
- WorkbookSource.SaveToSpreadsheetFile(AcFileSaveAs.Dialog.FileName, fmt);
+ WorkbookSource.SaveToSpreadsheetFile(UTF8ToAnsi(AcFileSaveAs.Dialog.FileName), fmt);
UpdateCaption;
finally
Screen.Cursor := crDefault;
@@ -401,7 +401,7 @@ begin
Caption := 'demo_ctrls'
else
Caption := Format('demo_ctrls - "%s" [%s]', [
- WorkbookSource.Filename,
+ AnsiToUTF8(WorkbookSource.Filename),
GetFileFormatName(WorkbookSource.Workbook.FileFormat)
]);
end;
diff --git a/components/fpspreadsheet/examples/fpsctrls_no_install/main.pas b/components/fpspreadsheet/examples/fpsctrls_no_install/main.pas
index f442919d6..55ddf8750 100644
--- a/components/fpspreadsheet/examples/fpsctrls_no_install/main.pas
+++ b/components/fpspreadsheet/examples/fpsctrls_no_install/main.pas
@@ -120,6 +120,8 @@ implementation
{ TForm1 }
procedure TForm1.BtnLoadClick(Sender: TObject);
+var
+ fn: ansistring;
begin
if OpenDialog.Execute then begin
WorkbookSource.AutodetectFormat := false;
@@ -136,16 +138,17 @@ begin
end;
// There are 3 possibilities to open a file:
+ fn := UTF8ToAnsi(OpenDialog.Filename);
case CbLoader.ItemIndex of
0: if WorkbookSource.AutodetectFormat then
- WorkbookSource.Workbook.ReadFromFile(OpenDialog.FileName)
+ WorkbookSource.Workbook.ReadFromFile(fn)
else
- WorkbookSource.Workbook.ReadFromFile(OpenDialog.Filename, WorkbookSource.FileFormat);
- 1: WorkbookSource.FileName := OpenDialog.FileName; // this loads the file
+ WorkbookSource.Workbook.ReadFromFile(fn, WorkbookSource.FileFormat);
+ 1: WorkbookSource.FileName := fn; // this loads the file
2: if WorkbookSource.AutodetectFormat then
- WorksheetGrid.LoadFromSpreadsheetFile(OpenDialog.FileName)
+ WorksheetGrid.LoadFromSpreadsheetFile(fn)
else
- WorksheetGrid.LoadFromSpreadsheetFile(OpenDialog.FileName, WorkbookSource.FileFormat);
+ WorksheetGrid.LoadFromSpreadsheetFile(fn, WorkbookSource.FileFormat);
end;
end;
end;
diff --git a/components/fpspreadsheet/examples/fpsgrid/mainform.pas b/components/fpspreadsheet/examples/fpsgrid/mainform.pas
index 12f165e9c..8794027e7 100644
--- a/components/fpspreadsheet/examples/fpsgrid/mainform.pas
+++ b/components/fpspreadsheet/examples/fpsgrid/mainform.pas
@@ -115,21 +115,22 @@ end;
// Saves sheet in grid to file, overwriting existing file
procedure TForm1.BtnSaveClick(Sender: TObject);
var
- err: String;
+ err, fn: String;
begin
if WorksheetGrid.Workbook = nil then
exit;
if WorksheetGrid.Workbook.Filename <>'' then begin
- SaveDialog.InitialDir := ExtractFileDir(WorksheetGrid.Workbook.FileName);
- SaveDialog.FileName := ChangeFileExt(ExtractFileName(WorksheetGrid.Workbook.FileName), '');
+ fn := AnsiToUTF8(WorksheetGrid.Workbook.Filename);
+ SaveDialog.InitialDir := ExtractFileDir(fn);
+ SaveDialog.FileName := ChangeFileExt(ExtractFileName(fn), '');
end;
if SaveDialog.Execute then
begin
Screen.Cursor := crHourglass;
try
- WorksheetGrid.SaveToSpreadsheetFile(SaveDialog.FileName);
+ WorksheetGrid.SaveToSpreadsheetFile(UTF8ToAnsi(SaveDialog.FileName));
finally
Screen.Cursor := crDefault;
// Show a message in case of error(s)
diff --git a/components/fpspreadsheet/examples/fpsgrid_no_install/fpsgrid.lpr b/components/fpspreadsheet/examples/fpsgrid_no_install/fpsgrid.lpr
index ab57e44ac..1752eb846 100644
--- a/components/fpspreadsheet/examples/fpsgrid_no_install/fpsgrid.lpr
+++ b/components/fpspreadsheet/examples/fpsgrid_no_install/fpsgrid.lpr
@@ -7,7 +7,7 @@ uses
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
- Forms, mainfrm, fpsHelpers
+ Forms, mainfrm, fpsCell
{ you can add units after this };
{$R *.res}
diff --git a/components/fpspreadsheet/examples/fpsgrid_no_install/mainfrm.pas b/components/fpspreadsheet/examples/fpsgrid_no_install/mainfrm.pas
index f5596e871..d91f9673a 100644
--- a/components/fpspreadsheet/examples/fpsgrid_no_install/mainfrm.pas
+++ b/components/fpspreadsheet/examples/fpsgrid_no_install/mainfrm.pas
@@ -92,21 +92,23 @@ end;
procedure TForm1.BtnSaveClick(Sender: TObject);
var
err: String;
+ fn: String;
begin
if Grid.Workbook = nil then
exit;
if Grid.Workbook.Filename <>'' then
begin
- SaveDialog.InitialDir := ExtractFileDir(Grid.Workbook.FileName);
- SaveDialog.FileName := ChangeFileExt(ExtractFileName(Grid.Workbook.FileName), '');
+ fn := AnsiToUtf8(Grid.Workbook.Filename);
+ SaveDialog.InitialDir := ExtractFileDir(fn);
+ SaveDialog.FileName := ChangeFileExt(ExtractFileName(fn), '');
end;
if SaveDialog.Execute then
begin
Screen.Cursor := crHourglass;
try
- Grid.SaveToSpreadsheetFile(SaveDialog.FileName);
+ Grid.SaveToSpreadsheetFile(UTF8ToAnsi(SaveDialog.FileName));
finally
Screen.Cursor := crDefault;
// Show a message in case of error(s)
diff --git a/components/fpspreadsheet/examples/spready/mainform.lfm b/components/fpspreadsheet/examples/spready/mainform.lfm
index 00f3bb5a2..f8f1f1694 100644
--- a/components/fpspreadsheet/examples/spready/mainform.lfm
+++ b/components/fpspreadsheet/examples/spready/mainform.lfm
@@ -498,7 +498,7 @@ object MainFrm: TMainFrm
BorderStyle = bsNone
ColCount = 27
MouseWheelOption = mwGrid
- Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goRowSizing, goColSizing, goThumbTracking, goDblClickAutoSize, goHeaderHotTracking, goHeaderPushedLook, goFixedColSizing]
+ Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goRowSizing, goColSizing, goThumbTracking, goDblClickAutoSize, goHeaderHotTracking, goHeaderPushedLook, goFixedColSizing, goCellHints]
RowCount = 101
TabOrder = 1
TitleStyle = tsNative
diff --git a/components/fpspreadsheet/examples/spready/mainform.pas b/components/fpspreadsheet/examples/spready/mainform.pas
index 70926426e..96836145e 100644
--- a/components/fpspreadsheet/examples/spready/mainform.pas
+++ b/components/fpspreadsheet/examples/spready/mainform.pas
@@ -324,6 +324,7 @@ type
procedure WorksheetGridHeaderClick(Sender: TObject; IsColumn: Boolean;
Index: Integer);
procedure WorksheetGridSelection(Sender: TObject; aCol, aRow: Integer);
+
private
FCopiedFormat: TCell;
procedure LoadFile(const AFileName: String);
@@ -759,7 +760,7 @@ begin
7: fmt := sfWikiTable_wikimedia;
end;
try
- WorksheetGrid.SaveToSpreadsheetFile(SaveDialog.FileName, fmt);
+ WorksheetGrid.SaveToSpreadsheetFile(Utf8ToAnsi(SaveDialog.FileName), fmt);
finally
Screen.Cursor := crDefault;
err := WorksheetGrid.Workbook.ErrorMsg;
@@ -1006,7 +1007,7 @@ begin
end;
procedure TMainFrm.LoadFile(const AFileName: String);
-// Loads first worksheet from file into grid
+// Loads first worksheet from file into grid. File name is UTF8.
var
err: String;
begin
@@ -1014,7 +1015,7 @@ begin
Screen.Cursor := crHourglass;
try
try
- WorksheetGrid.LoadFromSpreadsheetFile(UTF8ToSys(AFileName));
+ WorksheetGrid.LoadFromSpreadsheetFile(utf8ToAnsi(AFileName));
except
on E: Exception do begin
// In an error occurs show at least an empty valid worksheet
diff --git a/components/fpspreadsheet/fpsactions.pas b/components/fpspreadsheet/fpsactions.pas
index 60774c062..bfc546553 100644
--- a/components/fpspreadsheet/fpsactions.pas
+++ b/components/fpspreadsheet/fpsactions.pas
@@ -1248,9 +1248,9 @@ procedure TsCellCommentAction.ExecuteTarget(Target: TObject);
var
txt: String;
cellStr: String;
- x, y: Integer;
- R: TRect;
begin
+ Unused(Target);
+
if Worksheet = nil then
exit;
@@ -1275,6 +1275,8 @@ end;
procedure TsCellCommentAction.UpdateTarget(Target: TObject);
begin
+ Unused(Target);
+
case FMode of
ccmNew : Enabled := (Worksheet <> nil) and (Length(GetSelection) > 0);
ccmEdit,
diff --git a/components/fpspreadsheet/fpscsv.pas b/components/fpspreadsheet/fpscsv.pas
index d82487343..83d887866 100644
--- a/components/fpspreadsheet/fpscsv.pas
+++ b/components/fpspreadsheet/fpscsv.pas
@@ -65,7 +65,7 @@ type
LineEnding: TsCSVLineEnding; // W: Specification for line ending to be written
Delimiter: Char; // RW: Column delimiter
QuoteChar: Char; // RW: Character for quoting texts
- Encoding: String; // RW: Encoding of file
+ Encoding: String; // RW: Encoding of file (code page, such as "utf8", "cp1252" etc)
DetectContentType: Boolean; // R: try to convert strings to content types
NumberFormat: String; // W: if empty write numbers like in sheet, otherwise use this format
AutoDetectNumberFormat: Boolean; // R: automatically detects decimal/thousand separator used in numbers
@@ -202,8 +202,6 @@ end;
constructor TsCSVReader.Create(AWorkbook: TsWorkbook);
begin
inherited Create(AWorkbook);
- FFormatSettings := CSVParams.FormatSettings;
- ReplaceFormatSettings(FFormatSettings, AWorkbook.FormatSettings);
FWorksheetName := 'Sheet1'; // will be replaced by filename
end;
@@ -455,6 +453,9 @@ begin
FWorkbook := AData;
FWorksheet := AData.AddWorksheet(FWorksheetName, true);
+ FFormatSettings := CSVParams.FormatSettings;
+ ReplaceFormatSettings(FFormatSettings, FWorkbook.FormatSettings);
+
// Create csv parser, read file and store in worksheet
Parser := TCSVParser.Create;
try
diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas
index 43ec7d180..00d02db30 100755
--- a/components/fpspreadsheet/fpspreadsheet.pas
+++ b/components/fpspreadsheet/fpspreadsheet.pas
@@ -59,9 +59,9 @@ type
MergeBase: PCell; // Upper left cell of a merged range
Comment: String; // Comment attached to the cell
{ Cell content }
- UTF8StringValue: String; // strings cannot be part of a variant record
+ UTF8StringValue: String; // Strings cannot be part of a variant record
FormulaValue: String;
- case ContentType: TCellContentType of // must be at the end of the declaration
+ case ContentType: TCellContentType of // variant part must be at the end
cctEmpty : (); // has no data at all
cctFormula : (); // FormulaValue is outside the variant record
cctNumber : (Numbervalue: Double);
@@ -187,9 +187,9 @@ type
procedure UpdateCaches;
{ Reading of values }
- function ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring; overload;
- function ReadAsUTF8Text(ACell: PCell): ansistring; overload;
- function ReadAsUTF8Text(ACell: PCell; AFormatSettings: TFormatSettings): ansistring; overload;
+ function ReadAsUTF8Text(ARow, ACol: Cardinal): string; overload; //ansistring; overload;
+ function ReadAsUTF8Text(ACell: PCell): string; overload; //ansistring; overload;
+ function ReadAsUTF8Text(ACell: PCell; AFormatSettings: TFormatSettings): string; overload; //ansistring; overload;
function ReadAsNumber(ARow, ACol: Cardinal): Double; overload;
function ReadAsNumber(ACell: PCell): Double; overload;
function ReadAsDateTime(ARow, ACol: Cardinal; out AResult: TDateTime): Boolean; overload;
@@ -555,7 +555,8 @@ type
private
{ Internal data }
FWorksheets: TFPList;
- FEncoding: TsEncoding;
+ FCodePage: String;
+// FEncoding: TsEncoding;
FFormat: TsSpreadsheetFormat;
FBuiltinFontCount: Integer;
FPalette: array of TsColorValue;
@@ -694,7 +695,8 @@ type
property ActiveWorksheet: TsWorksheet read FActiveWorksheet;
{@@ This property is only used for formats which don't support unicode
and support a single encoding for the whole document, like Excel 2 to 5 }
- property Encoding: TsEncoding read FEncoding write FEncoding;
+ property CodePage: String read FCodePage write FCodepage;
+// property Encoding: TsEncoding read FEncoding write FEncoding;
{@@ Retrieves error messages collected during reading/writing }
property ErrorMsg: String read GetErrorMsg;
{@@ Filename of the saved workbook }
@@ -2446,13 +2448,13 @@ end;
Reads the contents of a cell and returns an user readable text
representing the contents of the cell.
- The resulting ansistring is UTF-8 encoded.
+ The resulting string is UTF-8 encoded.
@param ARow The row of the cell
@param ACol The column of the cell
@return The text representation of the cell
-------------------------------------------------------------------------------}
-function TsWorksheet.ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring;
+function TsWorksheet.ReadAsUTF8Text(ARow, ACol: Cardinal): string; //ansistring;
begin
Result := ReadAsUTF8Text(GetCell(ARow, ACol));
end;
@@ -2461,21 +2463,21 @@ end;
Reads the contents of a cell and returns an user readable text
representing the contents of the cell.
- The resulting ansistring is UTF-8 encoded.
+ The resulting string is UTF-8 encoded.
@param ACell Pointer to the cell
@return The text representation of the cell
-------------------------------------------------------------------------------}
-function TsWorksheet.ReadAsUTF8Text(ACell: PCell): ansistring;
+function TsWorksheet.ReadAsUTF8Text(ACell: PCell): string; //ansistring;
begin
Result := ReadAsUTF8Text(ACell, FWorkbook.FormatSettings);
end;
function TsWorksheet.ReadAsUTF8Text(ACell: PCell;
- AFormatSettings: TFormatSettings): ansistring;
+ AFormatSettings: TFormatSettings): string; //ansistring;
function FloatToStrNoNaN(const AValue: Double;
- ANumberFormat: TsNumberFormat; ANumberFormatStr: string): ansistring;
+ ANumberFormat: TsNumberFormat; ANumberFormatStr: string): string; //ansistring;
begin
if IsNan(AValue) then
Result := ''
@@ -2493,7 +2495,7 @@ function TsWorksheet.ReadAsUTF8Text(ACell: PCell;
end;
function DateTimeToStrNoNaN(const Value: Double;
- ANumberFormat: TsNumberFormat; ANumberFormatStr: String): ansistring;
+ ANumberFormat: TsNumberFormat; ANumberFormatStr: String): string; //ansistring;
var
fmtp, fmtn, fmt0: String;
begin
@@ -6424,11 +6426,14 @@ end;
constructor TsWorkbook.Create;
var
fmt: TsCellFormat;
+ cp: String;
begin
inherited Create;
FWorksheets := TFPList.Create;
FLog := TStringList.Create;
FFormat := sfExcel8;
+ FCodePage := GetDefaultTextEncoding;
+// FEncoding := seLatin1;
FormatSettings := UTF8FormatSettings;
FormatSettings.ShortDateFormat := MakeShortDateFormat(FormatSettings.ShortDateFormat);
@@ -8736,6 +8741,7 @@ end;
-------------------------------------------------------------------------------}
procedure TsCustomSpreadWriter.WriteComment(AStream: TStream; ACell: PCell);
begin
+ Unused(AStream, ACell);
end;
{@@ ----------------------------------------------------------------------------
diff --git a/components/fpspreadsheet/fpspreadsheetgrid.pas b/components/fpspreadsheet/fpspreadsheetgrid.pas
index 96ff39c49..492ca29e3 100644
--- a/components/fpspreadsheet/fpspreadsheetgrid.pas
+++ b/components/fpspreadsheet/fpspreadsheetgrid.pas
@@ -1845,7 +1845,6 @@ var
lCell: PCell;
justif: Byte;
fmt: PsCellFormat;
- savedBrushColor: TColor;
begin
if (Worksheet = nil) then
exit;
diff --git a/components/fpspreadsheet/fpsrpn.pas b/components/fpspreadsheet/fpsrpn.pas
index 5ea43f2fb..a184b13ef 100644
--- a/components/fpspreadsheet/fpsrpn.pas
+++ b/components/fpspreadsheet/fpsrpn.pas
@@ -10,7 +10,7 @@
unit fpsRPN;
{$ifdef fpc}
- {$mode delphi}{$H+}
+ {$mode objfpc}{$H+}
{$endif}
interface
@@ -436,6 +436,7 @@ begin
while item <> nil do begin
nextitem := item^.Next;
Result[n] := item^.FE;
+ Result[n].StringValue := item^.FE.StringValue;
if AReverse then dec(n) else inc(n);
DisposeRPNItem(item);
item := nextitem;
diff --git a/components/fpspreadsheet/fpsstrings.pas b/components/fpspreadsheet/fpsstrings.pas
index 5082c83e9..60d6e858a 100644
--- a/components/fpspreadsheet/fpsstrings.pas
+++ b/components/fpspreadsheet/fpsstrings.pas
@@ -52,6 +52,7 @@ resourcestring
'text found in cell %s.';
rsIndexInSSTOutOfRange = 'Index %d in SST out of range (0-%d).';
rsAmbiguousDecThouSeparator = 'Assuming usage of decimal separator in "%s".';
+ rsCodePageNotSupported = 'Code page "%s" is not supported. Using "cp1252" (Latin 1) instead.';
rsTRUE = 'TRUE'; // wp: Do we really want to translate these strings?
diff --git a/components/fpspreadsheet/fpstypes.pas b/components/fpspreadsheet/fpstypes.pas
index 631877524..d17b16dd2 100644
--- a/components/fpspreadsheet/fpstypes.pas
+++ b/components/fpspreadsheet/fpstypes.pas
@@ -48,7 +48,7 @@ const
type
-
+ (*
{@@ Possible encodings for a non-unicode encoded text }
TsEncoding = (
seLatin1,
@@ -57,8 +57,9 @@ type
seGreek,
seTurkish,
seHebrew,
- seArabic
- );
+ seArabic,
+ seUTF16
+ ); *)
{@@ Tokens to identify the elements in an expanded formula.
@@ -110,7 +111,7 @@ type
ElementKind: TFEKind;
Row, Row2: Cardinal; // zero-based
Col, Col2: Cardinal; // zero-based
- Param1, Param2: Word; // Extra parameters
+// Param1, Param2: Word; // Extra parameters
DoubleValue: double;
IntValue: Word;
StringValue: String;
@@ -228,7 +229,7 @@ type
Due to limitations of the text mode the characters are not rotated here.
There is, however, also a "stacked" variant which looks exactly like
- the former case.
+ the 90-degrees-clockwise case.
}
TsTextRotation = (trHorizontal, rt90DegreeClockwiseRotation,
rt90DegreeCounterClockwiseRotation, rtStacked);
diff --git a/components/fpspreadsheet/reference/BIFFExplorer/bebiffgrid.pas b/components/fpspreadsheet/reference/BIFFExplorer/bebiffgrid.pas
index f92d30291..cd17afadd 100644
--- a/components/fpspreadsheet/reference/BIFFExplorer/bebiffgrid.pas
+++ b/components/fpspreadsheet/reference/BIFFExplorer/bebiffgrid.pas
@@ -228,7 +228,7 @@ begin
SetLength(sa, ls);
ANumbytes := ls*SizeOf(AnsiChar) + ALenBytes + 1;
Move(FBuffer[ABufIndex + ALenBytes + 1], sa[1], ls*SizeOf(AnsiChar));
- AString := sa;
+ AString := AnsiToUTF8(sa);
end else begin
SetLength(sw, ls);
ANumBytes := ls*SizeOf(WideChar) + ALenBytes + 1;
diff --git a/components/fpspreadsheet/tests/datetests.pas b/components/fpspreadsheet/tests/datetests.pas
index bc3a2ad06..39ac20804 100644
--- a/components/fpspreadsheet/tests/datetests.pas
+++ b/components/fpspreadsheet/tests/datetests.pas
@@ -381,7 +381,9 @@ var
ActualDateTime: TDateTime;
Row: Cardinal;
TempFile: string; //write xls/xml to this file and read back from it
+ ErrorMargin: TDateTime;
begin
+ ErrorMargin := 1.0/(24*60*60*1000*100); // 0.01 ms
TempFile:=NewTempFile;
{// Not needed: use workbook.writetofile with overwrite=true
if fileexists(TempFile) then
@@ -397,7 +399,8 @@ begin
// Some checks inside worksheet itself
if not(MyWorkSheet.ReadAsDateTime(Row,0,ActualDateTime)) then
Fail('Failed writing date time for cell '+CellNotation(MyWorkSheet,Row));
- CheckEquals(SollDates[Row],ActualDateTime,'Test date/time value mismatch cell '+CellNotation(MyWorksheet,Row));
+ CheckEquals(SollDates[Row], ActualDateTime,
+ 'Test date/time value mismatch cell '+CellNotation(MyWorksheet,Row));
end;
MyWorkBook.WriteToFile(TempFile, AFormat, true);
finally
@@ -420,7 +423,8 @@ begin
begin
if not(MyWorkSheet.ReadAsDateTime(Row,0,ActualDateTime)) then
Fail('Could not read date time for cell '+CellNotation(MyWorkSheet,Row));
- CheckEquals(SollDates[Row],ActualDateTime,'Test date/time value mismatch cell '+CellNotation(MyWorkSheet,Row));
+ CheckEquals(SollDates[Row], ActualDateTime, ErrorMargin,
+ 'Test date/time value mismatch cell '+CellNotation(MyWorkSheet,Row));
end;
finally
MyWorkbook.Free;
diff --git a/components/fpspreadsheet/tests/spreadtestgui.lpi b/components/fpspreadsheet/tests/spreadtestgui.lpi
index 0aaa75d33..af201c8de 100644
--- a/components/fpspreadsheet/tests/spreadtestgui.lpi
+++ b/components/fpspreadsheet/tests/spreadtestgui.lpi
@@ -48,6 +48,7 @@
+
@@ -60,7 +61,6 @@
-
@@ -69,21 +69,19 @@
-
-
+
-
@@ -96,15 +94,16 @@
+
+
-
@@ -121,7 +120,6 @@
-
@@ -130,7 +128,6 @@
-
diff --git a/components/fpspreadsheet/tests/testcases_calcrpnformula.inc b/components/fpspreadsheet/tests/testcases_calcrpnformula.inc
index 8532e5727..1867ed1d2 100644
--- a/components/fpspreadsheet/tests/testcases_calcrpnformula.inc
+++ b/components/fpspreadsheet/tests/testcases_calcrpnformula.inc
@@ -52,7 +52,7 @@
{!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! DO NOT CHANGE THIS FORMULA - ITS RESULT (-9) IS HARD-CODED IN OTHER TESTS !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
-
+ (*
// Add cell values - relative addresses
inc(Row);
formula := 'B1+B2';
@@ -3001,7 +3001,7 @@
SetLength(sollValues, Row+1);
sollValues[Row] := StringResult('Ha');
Myworksheet.WriteUTF8Text(Row, 2, sollValues[Row].ResString);
-
+ *)
// LEFT (2 parameters, utf8)
inc(Row);
formula := 'LEFT("Ändern",3)';
diff --git a/components/fpspreadsheet/xlsbiff2.pas b/components/fpspreadsheet/xlsbiff2.pas
index d6a51bfef..35e5c829d 100755
--- a/components/fpspreadsheet/xlsbiff2.pas
+++ b/components/fpspreadsheet/xlsbiff2.pas
@@ -57,7 +57,7 @@ type
TsSpreadBIFF2Reader = class(TsSpreadBIFFReader)
private
- WorkBookEncoding: TsEncoding;
+// WorkBookEncoding: TsEncoding;
FFont: TsFont;
protected
procedure CreateNumFormatList; override;
@@ -110,6 +110,8 @@ type
ACell: PCell); override;
procedure WriteBool(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: Boolean; ACell: PCell); override;
+// procedure WriteCodePage(AStream: TStream; AEncoding: TsEncoding); override;
+ procedure WriteCodePage(AStream: TStream; ACodePage: String); override;
procedure WriteError(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: TsErrorValue; ACell: PCell); override;
procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal;
@@ -512,7 +514,7 @@ begin
FWorkbook.RemoveAllFonts;
{ Store some data about the workbook that other routines need }
- WorkBookEncoding := AData.Encoding;
+ //WorkBookEncoding := AData.Encoding;
BIFF2EOF := False;
@@ -531,6 +533,7 @@ begin
case RecordType of
INT_EXCEL_ID_BLANK : ReadBlank(AStream);
INT_EXCEL_ID_BOOLERROR : ReadBool(AStream);
+ INT_EXCEL_ID_CODEPAGE : ReadCodePage(AStream);
INT_EXCEL_ID_NOTE : ReadComment(AStream);
INT_EXCEL_ID_FONT : ReadFont(AStream);
INT_EXCEL_ID_FONTCOLOR : ReadFontColor(AStream);
@@ -648,8 +651,8 @@ var
L: Byte;
ARow, ACol: Cardinal;
XF: Word;
- AValue: ansistring;
- AStrValue: UTF8String;
+ ansiStr: ansistring;
+ valueStr: UTF8String;
cell: PCell;
begin
{ Read entire record, starting at Row, except for string data }
@@ -661,10 +664,12 @@ begin
{ String with 8-bit size }
L := rec.TextLen;
- SetLength(AValue, L);
- AStream.ReadBuffer(AValue[1], L);
+ SetLength(ansiStr, L);
+ AStream.ReadBuffer(ansiStr[1], L);
{ Save the data }
+ valueStr := ConvertEncoding(ansiStr, FCodePage, encodingUTF8);
+ {
case WorkBookEncoding of
seLatin2: AStrValue := CP1250ToUTF8(AValue);
seCyrillic: AStrValue := CP1251ToUTF8(AValue);
@@ -676,6 +681,7 @@ begin
// Latin 1 is the default
AStrValue := CP1252ToUTF8(AValue);
end;
+ }
{ Create cell }
if FIsVirtualMode then begin
@@ -683,7 +689,7 @@ begin
cell := @FVirtualCell;
end else
cell := FWorksheet.GetCell(ARow, ACol);
- FWorksheet.WriteUTF8Text(cell, AStrValue);
+ FWorksheet.WriteUTF8Text(cell, valueStr);
{ Apply formatting to cell }
ApplyCellFormatting(cell, XF);
@@ -870,7 +876,8 @@ begin
begin
// The "IncompleteCell" has been identified in the sheet when reading
// the FORMULA record which precedes the String record.
- FIncompleteCell^.UTF8StringValue := AnsiToUTF8(s);
+// FIncompleteCell^.UTF8StringValue := AnsiToUTF8(s);
+ FIncompleteCell^.UTF8StringValue := ConvertEncoding(s, FCodePage, encodingUTF8);
FIncompleteCell^.ContentType := cctUTF8String;
if FIsVirtualMode then
Workbook.OnReadCellData(Workbook, FIncompleteCell^.Row, FIncompleteCell^.Col, FIncompleteCell);
@@ -1141,6 +1148,32 @@ begin
AStream.WriteBuffer(rec, SizeOf(rec));
end;
+{@@ ----------------------------------------------------------------------------
+ Writes an Excel 2 CODEPAGE record
+-------------------------------------------------------------------------------}
+procedure TsSpreadBIFF2Writer.WriteCodePage(AStream: TStream; ACodePage: String);
+// AEncoding: TsEncoding);
+begin
+ if ACodePage = 'cp1251' then begin
+ AStream.WriteWord(WordToLE(INT_EXCEL_ID_CODEPAGE));
+ AStream.WriteWord(WordToLE(2));
+ AStream.WriteWord(WordToLE(WORD_CP_1258_Latin1_BIFF2_3));
+ FCodePage := ACodePage;
+ end else
+ inherited;
+ (*
+ if AEncoding = seLatin1 then begin
+ cp := WORD_CP_1258_Latin1_BIFF2_3;
+ FCodePage := 'cp1252';
+
+ { BIFF Record header }
+ AStream.WriteWord(WordToLE(INT_EXCEL_ID_CODEPAGE));
+ AStream.WriteWord(WordToLE(2));
+ AStream.WriteWord(WordToLE(cp));
+ end else
+ inherited; *)
+end;
+
{@@ ----------------------------------------------------------------------------
Writes an Excel 2 COLWIDTH record
-------------------------------------------------------------------------------}
@@ -1245,6 +1278,7 @@ begin
WriteBOF(AStream);
WriteFonts(AStream);
+ WriteCodePage(AStream, Workbook.CodePage); //Encoding);
WriteFormatCount(AStream);
WriteNumFormats(AStream);
WriteXFRecords(AStream);
@@ -1531,7 +1565,7 @@ var
begin
Unused(ANumFormatData);
- s := NumFormatList.FormatStringForWriting(AListIndex);
+ s := ConvertEncoding(NumFormatList.FormatStringForWriting(AListIndex), encodingUTF8, FCodePage);
len := Length(s);
{ BIFF record header }
diff --git a/components/fpspreadsheet/xlsbiff5.pas b/components/fpspreadsheet/xlsbiff5.pas
index a342bae23..da1a39c93 100755
--- a/components/fpspreadsheet/xlsbiff5.pas
+++ b/components/fpspreadsheet/xlsbiff5.pas
@@ -34,19 +34,15 @@ EOF
The row and column numbering in BIFF files is zero-based.
Excel file format specification obtained from:
-
-http://sc.openoffice.org/excelfileformat.pdf
+ http://sc.openoffice.org/excelfileformat.pdf
Records Needed to Make a BIFF5 File Microsoft Excel Can Use obtained from:
-
-http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q147732&ID=KB;EN-US;Q147732&LN=EN-US&rnk=2&SD=msdn&FR=0&qry=BIFF&src=DHCS_MSPSS_msdn_SRCH&SPR=MSALL&
+ http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q147732&ID=KB;EN-US;Q147732&LN=EN-US&rnk=2&SD=msdn&FR=0&qry=BIFF&src=DHCS_MSPSS_msdn_SRCH&SPR=MSALL&
Microsoft BIFF 5 writer example:
+ http://support.microsoft.com/kb/150447/en-us
-http://support.microsoft.com/kb/150447/en-us
-
-Encoding information: ISO_8859_1 is used, to have support to
-other characters, please use a format which support unicode
+Encoding information: as specified fy the Encoding property of the workbook.
AUTHORS: Felipe Monteiro de Carvalho
}
@@ -101,8 +97,6 @@ type
{ TsSpreadBIFF5Writer }
TsSpreadBIFF5Writer = class(TsSpreadBIFFWriter)
- private
- WorkBookEncoding: TsEncoding;
protected
{ Record writing methods }
procedure WriteBOF(AStream: TStream; ADataType: Word);
@@ -353,6 +347,7 @@ begin
case RecordType of
INT_EXCEL_ID_BOF : ;
INT_EXCEL_ID_BOUNDSHEET : ReadBoundSheet(AStream);
+ INT_EXCEL_ID_CODEPAGE : ReadCodePage(AStream);
INT_EXCEL_ID_FONT : ReadFont(AStream);
INT_EXCEL_ID_FORMAT : ReadFormat(AStream);
INT_EXCEL_ID_XF : ReadXF(AStream);
@@ -481,7 +476,8 @@ begin
SetLength(s, Len);
AStream.ReadBuffer(s[1], Len*SizeOf(AnsiChar));
- sheetName := AnsiToUTF8(s);
+// sheetName := AnsiToUTF8(s);
+ sheetName := ConvertEncoding(s, FCodePage, EncodingUTF8);
FWorksheetNames.Add(sheetName);
end;
@@ -550,7 +546,8 @@ begin
SetLength(s, Len);
AStream.ReadBuffer(s[1], len);
if (FIncompleteCell <> nil) and (s <> '') then begin
- FIncompleteCell^.UTF8StringValue := AnsiToUTF8(s);
+// FIncompleteCell^.UTF8StringValue := AnsiToUTF8(s);
+ FIncompletecell^.UTF8StringValue := ConvertEncoding(s, FCodePage, encodingUTF8);
FIncompleteCell^.ContentType := cctUTF8String;
if FIsVirtualMode then
Workbook.OnReadCellData(Workbook, FIncompleteCell^.Row, FIncompleteCell^.Col, FIncompleteCell);
@@ -720,7 +717,6 @@ end;
procedure TsSpreadBIFF5Reader.ReadFromStream(AStream: TStream; AData: TsWorkbook);
var
BIFF5EOF: Boolean;
- p,s: Int64;
begin
{ Initializations }
@@ -743,8 +739,6 @@ begin
ReadWorksheet(AStream, AData);
// Check for the end of the file
- p := AStream.Position;
- s := AStream.Size;
if AStream.Position >= AStream.Size then BIFF5EOF := True;
// Final preparations
@@ -818,7 +812,7 @@ begin
Len := AStream.ReadByte();
SetLength(fontname, Len);
AStream.ReadBuffer(fontname[1], Len);
- font.FontName := fontname;
+ font.FontName := ConvertEncoding(fontname, FCodePage, encodingUTF8);
{ Add font to workbook's font list }
FWorkbook.AddFont(font);
@@ -846,7 +840,8 @@ begin
AStream.ReadBuffer(fmtString[1], len);
// Add to the list
- NumFormatList.AnalyzeAndAdd(fmtIndex, AnsiToUTF8(fmtString));
+// NumFormatList.AnalyzeAndAdd(fmtIndex, AnsiToUTF8(fmtString));
+ NumFormatList.AnalyzeAndAdd(fmtIndex, ConvertEncoding(fmtString, FCodePage, encodingUTF8));
end;
procedure TsSpreadBIFF5Reader.ReadLabel(AStream: TStream);
@@ -856,7 +851,8 @@ var
ARow, ACol: Cardinal;
XF: WORD;
cell: PCell;
- AValue: ansistring;
+ ansistr: ansistring;
+ valuestr: String;
begin
rec.Row := 0; // to silence the compiler...
@@ -868,8 +864,8 @@ begin
{ Byte String with 16-bit size }
L := WordLEToN(rec.TextLen);
- SetLength(AValue, L);
- AStream.ReadBuffer(AValue[1], L);
+ SetLength(ansistr, L);
+ AStream.ReadBuffer(ansistr[1], L);
{ Create cell }
if FIsVirtualMode then begin
@@ -879,7 +875,8 @@ begin
cell := FWorksheet.GetCell(ARow, ACol);
{ Save the data }
- FWorksheet.WriteUTF8Text(cell, ISO_8859_1ToUTF8(AValue));
+ valueStr := ConvertEncoding(ansistr, FCodePage, encodingUTF8);
+ FWorksheet.WriteUTF8Text(cell, valueStr); //ISO_8859_1ToUTF8(ansistr));
{ Add attributes }
ApplyCellFormatting(cell, XF);
@@ -939,14 +936,11 @@ var
i, len: Integer;
pane: Byte;
begin
- { Store some data about the workbook that other routines need }
- WorkBookEncoding := Workbook.Encoding;
-
{ Write workbook globals }
WriteBOF(AStream, INT_BOF_WORKBOOK_GLOBALS);
- WriteCodepage(AStream, WorkBookEncoding);
+ WriteCodepage(AStream, Workbook.CodePage); //WorkBook.Encoding);
WriteWindow1(AStream);
WriteFonts(AStream);
WriteNumFormats(AStream);
@@ -1042,11 +1036,14 @@ end;
function TsSpreadBIFF5Writer.WriteBoundsheet(AStream: TStream; ASheetName: string): Int64;
var
Len: Byte;
- LatinSheetName: string;
+ xlsSheetName: ansistring;
begin
+ xlsSheetName := ConvertEncoding(ASheetName, encodingUTF8, FCodePage);
+ Len := Length(xlsSheetName);
+ {
LatinSheetName := UTF8ToISO_8859_1(ASheetName);
Len := Length(LatinSheetName);
-
+ }
{ BIFF Record header }
AStream.WriteWord(WordToLE(INT_EXCEL_ID_BOUNDSHEET));
AStream.WriteWord(WordToLE(6 + 1 + Len));
@@ -1064,7 +1061,8 @@ begin
{ Sheet name: Byte string, 8-bit length }
AStream.WriteByte(Len);
- AStream.WriteBuffer(LatinSheetName[1], Len);
+// AStream.WriteBuffer(LatinSheetName[1], Len);
+ AStream.WriteBuffer(xlsSheetName[1], Len);
end;
{@@ ----------------------------------------------------------------------------
@@ -1204,15 +1202,18 @@ type
end;
var
len: Integer;
- s: ansistring;
+ fmtStr: String;
+ ansiFmtStr: ansiString;
rec: TNumFormatRecord;
buf: array of byte;
begin
if (ANumFormatData = nil) or (ANumFormatData.FormatString = '') then
exit;
- s := UTF8ToAnsi(NumFormatList.FormatStringForWriting(AListIndex));
- len := Length(s);
+// s := UTF8ToAnsi(NumFormatList.FormatStringForWriting(AListIndex));
+ fmtStr := NumFormatList.FormatStringForWriting(AListIndex);
+ ansiFmtStr := ConvertEncoding(fmtStr, encodingUTF8, FCodePage);
+ len := Length(ansiFmtStr);
{ BIFF record header }
rec.RecordID := WordToLE(INT_EXCEL_ID_FORMAT);
@@ -1227,7 +1228,7 @@ begin
{ Copy the format string characters into a buffer immediately after rec }
SetLength(buf, SizeOf(rec) + SizeOf(ansiChar)*len);
Move(rec, buf[0], SizeOf(rec));
- Move(s[1], buf[SizeOf(rec)], len*SizeOf(ansiChar));
+ Move(ansiFmtStr[1], buf[SizeOf(rec)], len*SizeOf(ansiChar));
{ Write out }
AStream.WriteBuffer(buf[0], SizeOf(Rec) + SizeOf(ansiChar)*len);
@@ -1284,6 +1285,8 @@ begin
if (ARow >= FLimitations.MaxRowCount) or (ACol >= FLimitations.MaxColCount) then
exit;
+ ansiValue := ConvertEncoding(AValue, encodingUTF8, FCodePage);
+ {
case WorkBookEncoding of
seLatin2: AnsiValue := UTF8ToCP1250(AValue);
seCyrillic: AnsiValue := UTF8ToCP1251(AValue);
@@ -1295,6 +1298,7 @@ begin
// Latin 1 is the default
AnsiValue := UTF8ToCP1252(AValue);
end;
+ }
if AnsiValue = '' then begin
// Bad formatted UTF8String (maybe ANSI?)
@@ -1354,7 +1358,8 @@ var
s: ansistring;
len: Integer;
begin
- s := UTF8ToAnsi(AString);
+// s := UTF8ToAnsi(AString);
+ s := ConvertEncoding(AString, encodingUTF8, FCodePage);
len := Length(s);
{ BIFF Record header }
diff --git a/components/fpspreadsheet/xlsbiff8.pas b/components/fpspreadsheet/xlsbiff8.pas
index be30152c2..d73fa91c0 100755
--- a/components/fpspreadsheet/xlsbiff8.pas
+++ b/components/fpspreadsheet/xlsbiff8.pas
@@ -78,7 +78,7 @@ type
procedure ReadWorkbookGlobals(AStream: TStream; AData: TsWorkbook);
procedure ReadWorksheet(AStream: TStream; AData: TsWorkbook);
procedure ReadBoundsheet(AStream: TStream);
- function ReadString(const AStream: TStream; const ALength: WORD): UTF8String;
+ function ReadString(const AStream: TStream; const ALength: WORD): String;
protected
procedure ReadFont(const AStream: TStream);
procedure ReadFormat(AStream: TStream); override;
@@ -219,7 +219,7 @@ var
implementation
uses
- Math, fpsStrings, fpsStreams, fpsExprParser;
+ Math, lconvencoding, fpsStrings, fpsStreams, fpsExprParser;
const
{ Excel record IDs }
@@ -349,81 +349,80 @@ var
lLen: SizeInt;
RecordType: WORD;
RecordSize: WORD;
- C: char;
+ C: WideChar;
begin
StringFlags:=AStream.ReadByte;
Dec(PendingRecordSize);
if StringFlags and 4 = 4 then begin
//Asian phonetics
//Read Asian phonetics Length (not used)
- AsianPhoneticBytes:=DWordLEtoN(AStream.ReadDWord);
+ AsianPhoneticBytes := DWordLEtoN(AStream.ReadDWord);
end;
if StringFlags and 8 = 8 then begin
//Rich string
- RunsCounter:=WordLEtoN(AStream.ReadWord);
+ RunsCounter := WordLEtoN(AStream.ReadWord);
dec(PendingRecordSize,2);
end;
if StringFlags and 1 = 1 Then begin
//String is WideStringLE
if (ALength*SizeOf(WideChar)) > PendingRecordSize then begin
- SetLength(Result,PendingRecordSize div 2);
- AStream.ReadBuffer(Result[1],PendingRecordSize);
- Dec(PendingRecordSize,PendingRecordSize);
+ SetLength(Result, PendingRecordSize div 2);
+ AStream.ReadBuffer(Result[1], PendingRecordSize);
+ Dec(PendingRecordSize, PendingRecordSize);
end else begin
SetLength(Result, ALength);
- AStream.ReadBuffer(Result[1],ALength * SizeOf(WideChar));
- Dec(PendingRecordSize,ALength * SizeOf(WideChar));
+ AStream.ReadBuffer(Result[1], ALength * SizeOf(WideChar));
+ Dec(PendingRecordSize, ALength * SizeOf(WideChar));
end;
Result := WideStringLEToN(Result);
end else begin
- //String is 1 byte per char, this is UTF-16 with the high byte ommited because it is zero
- //so decompress and then convert
- lLen:=ALength;
+ // String is 1 byte per char, this is UTF-16 with the high byte ommited
+ // because it is zero, so decompress and then convert
+ lLen := ALength;
SetLength(DecomprStrValue, lLen);
for i := 1 to lLen do
begin
- C:=WideChar(AStream.ReadByte());
+ C := WideChar(AStream.ReadByte); // Read 1 byte, but put it into a 2-byte char
DecomprStrValue[i] := C;
Dec(PendingRecordSize);
- if (PendingRecordSize<=0) and (iINT_EXCEL_ID_CONTINUE then begin
+ if RecordType <> INT_EXCEL_ID_CONTINUE then begin
Raise Exception.Create('[TsSpreadBIFF8Reader.ReadWideString] Expected CONTINUE record not found.');
end else begin
- PendingRecordSize:=RecordSize;
- DecomprStrValue:=copy(DecomprStrValue,1,i)+ReadWideString(AStream,ALength-i);
+ PendingRecordSize := RecordSize;
+ DecomprStrValue := copy(DecomprStrValue,1,i) + ReadWideString(AStream, ALength-i);
break;
end;
end;
end;
-
Result := DecomprStrValue;
end;
if StringFlags and 8 = 8 then begin
//Rich string (This only happened in BIFF8)
for j := 1 to RunsCounter do begin
- if (PendingRecordSize<=0) then begin
+ if (PendingRecordSize <= 0) then begin
//A CONTINUE may happend here
RecordType := WordLEToN(AStream.ReadWord);
RecordSize := WordLEToN(AStream.ReadWord);
- if RecordType<>INT_EXCEL_ID_CONTINUE then begin
+ if RecordType <> INT_EXCEL_ID_CONTINUE then begin
Raise Exception.Create('[TsSpreadBIFF8Reader.ReadWideString] Expected CONTINUE record not found.');
end else begin
- PendingRecordSize:=RecordSize;
+ PendingRecordSize := RecordSize;
end;
end;
AStream.ReadWord;
AStream.ReadWord;
- dec(PendingRecordSize,2*2);
+ dec(PendingRecordSize, 2*2);
end;
end;
if StringFlags and 4 = 4 then begin
//Asian phonetics
//Read Asian phonetics, discarded as not used.
- SetLength(AnsiStrValue,AsianPhoneticBytes);
- AStream.ReadBuffer(AnsiStrValue[1],AsianPhoneticBytes);
+ SetLength(AnsiStrValue, AsianPhoneticBytes);
+ AStream.ReadBuffer(AnsiStrValue[1], AsianPhoneticBytes);
end;
end;
@@ -572,7 +571,7 @@ begin
end;
function TsSpreadBIFF8Reader.ReadString(const AStream: TStream;
- const ALength: WORD): UTF8String;
+ const ALength: WORD): String;
begin
Result := UTF16ToUTF8(ReadWideString(AStream, ALength));
end;
@@ -618,18 +617,16 @@ begin
BIFF8EOF := False;
{ Read workbook globals }
-
ReadWorkbookGlobals(AStream, AData);
// Check for the end of the file
if AStream.Position >= AStream.Size then BIFF8EOF := True;
{ Now read all worksheets }
-
while (not BIFF8EOF) do
begin
//Safe to not read beyond assigned worksheet names.
- if FCurrentWorksheet>FWorksheetNames.Count-1 then break;
+ if FCurrentWorksheet > FWorksheetNames.Count-1 then break;
ReadWorksheet(AStream, AData);
@@ -647,9 +644,7 @@ begin
FWorkbook.UsePalette(@PALETTE_BIFF8, Length(PALETTE_BIFF8));
{ Finalizations }
-
FWorksheetNames.Free;
-
end;
procedure TsSpreadBIFF8Reader.ReadLabel(AStream: TStream);
@@ -956,20 +951,22 @@ end;
{ Helper function for reading a string with 8-bit length. }
function TsSpreadBIFF8Reader.ReadString_8bitLen(AStream: TStream): String;
+const
+ HAS_8BITLEN = true;
var
- s: widestring;
+ wideStr: widestring;
begin
- s := ReadWideString(AStream, true);
- Result := UTF8Encode(s);
+ wideStr := ReadWideString(AStream, HAS_8BITLEN);
+ Result := UTF8Encode(wideStr);
end;
procedure TsSpreadBIFF8Reader.ReadStringRecord(AStream: TStream);
var
- s: String;
+ wideStr: WideString;
begin
- s := ReadWideString(AStream, false);
- if (FIncompleteCell <> nil) and (s <> '') then begin
- FIncompleteCell^.UTF8StringValue := UTF8Encode(s);
+ wideStr := ReadWideString(AStream, false);
+ if (FIncompleteCell <> nil) and (wideStr <> '') then begin
+ FIncompleteCell^.UTF8StringValue := UTF8Encode(wideStr);
FIncompleteCell^.ContentType := cctUTF8String;
if FIsVirtualMode then
Workbook.OnReadCellData(Workbook, FIncompleteCell^.Row, FIncompleteCell^.Col, FIncompleteCell);
@@ -984,14 +981,12 @@ procedure TsSpreadBIFF8Reader.ReadXF(const AStream: TStream);
begin
case dw of
$01..$07: result := TsLineStyle(dw-1);
-// $07: Result := lsDotted;
else Result := lsDashed;
end;
end;
var
rec: TBIFF8_XFRecord;
fmt: TsCellFormat;
-// xf: TXFRecord;
b: Byte;
dw: DWord;
fill: Integer;
@@ -1271,9 +1266,8 @@ var
pane: Byte;
begin
{ Write workbook globals }
-
WriteBOF(AStream, INT_BOF_WORKBOOK_GLOBALS);
-
+ WriteCodePage(AStream, 'ucs2le'); //seUTF16);
WriteWindow1(AStream);
WriteFonts(AStream);
WriteNumFormats(AStream);
@@ -1293,7 +1287,6 @@ begin
WriteEOF(AStream);
{ Write each worksheet }
-
for i := 0 to Workbook.GetWorksheetCount - 1 do
begin
FWorksheet := Workbook.GetWorksheetByIndex(i);
@@ -1483,7 +1476,7 @@ begin
if AFont.Size <= 0.0 then
raise Exception.Create('Font size not specified.');
- WideFontName := AFont.FontName;
+ WideFontName := UTF8Decode(AFont.FontName);
Len := Length(WideFontName);
{ BIFF Record header }
diff --git a/components/fpspreadsheet/xlscommon.pas b/components/fpspreadsheet/xlscommon.pas
index d6849050c..218bf630b 100644
--- a/components/fpspreadsheet/xlscommon.pas
+++ b/components/fpspreadsheet/xlscommon.pas
@@ -4,20 +4,13 @@ unit xlscommon;
OpenOffice Microsoft Excel File Format document }
{$ifdef fpc}
- {$mode delphi}{$H+}
+ {$mode objfpc}{$H+}
{$endif}
interface
uses
Classes, SysUtils, DateUtils,
- (*
- {$ifdef USE_NEW_OLE}
- fpolebasic,
- {$else}
- fpolestorage,
- {$endif}
- *)
fpstypes, fpspreadsheet, fpsutils, lconvencoding;
const
@@ -73,6 +66,11 @@ const
{ CODEPAGE record constants }
WORD_ASCII = 367;
+ WORD_CP_437_DOS_US = 437;
+ WORD_CP_850_DOS_Latin1 = 850;
+ WORD_CP_852_DOS_Latin2 = 852;
+ WORD_CP_866_DOS_Cyrillic = 866;
+ WORD_CP_874_Thai = 874;
WORD_UTF_16 = 1200; // BIFF 8
WORD_CP_1250_Latin2 = 1250;
WORD_CP_1251_Cyrillic = 1251;
@@ -304,6 +302,7 @@ type
FDateMode: TDateMode;
FLastRow: Cardinal;
FLastCol: Cardinal;
+ FCodePage: String; // in a format prepared for lconvencoding.ConvertEncoding
procedure CreateNumFormatList; override;
function FindXFIndex(ACell: PCell): Integer; virtual;
function FixColor(AColor: TsColor): TsColor; override;
@@ -321,7 +320,7 @@ type
procedure WriteBool(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: Boolean; ACell: PCell); override;
// Writes out used codepage for character encoding
- procedure WriteCodepage(AStream: TStream; AEncoding: TsEncoding);
+ procedure WriteCodePage(AStream: TStream; ACodePage: String); virtual;
// Writes out column info(s)
procedure WriteColInfo(AStream: TStream; ACol: PCol);
procedure WriteColInfos(AStream: TStream; ASheet: TsWorksheet);
@@ -403,7 +402,7 @@ implementation
uses
AVL_Tree, Math, Variants,
- {%H-}fpspatches, xlsConst, fpsNumFormatParser, fpsrpn, fpsExprParser;
+ {%H-}fpspatches, fpsStrings, xlsConst, fpsNumFormatParser, fpsrpn, fpsExprParser;
const
{ Helper table for rpn formulas:
@@ -827,49 +826,41 @@ begin
lCodePage := WordLEToN(AStream.ReadWord());
case lCodePage of
- // 016FH = 367 = ASCII
- // 01B5H = 437 = IBM PC CP-437 (US)
- //02D0H = 720 = IBM PC CP-720 (OEM Arabic)
- //02E1H = 737 = IBM PC CP-737 (Greek)
- //0307H = 775 = IBM PC CP-775 (Baltic)
- //0352H = 850 = IBM PC CP-850 (Latin I)
- $0352: FCodepage := 'cp850';
- //0354H = 852 = IBM PC CP-852 (Latin II (Central European))
- $0354: FCodepage := 'cp852';
- //0357H = 855 = IBM PC CP-855 (Cyrillic)
- $0357: FCodepage := 'cp855';
- //0359H = 857 = IBM PC CP-857 (Turkish)
- $0359: FCodepage := 'cp857';
- //035AH = 858 = IBM PC CP-858 (Multilingual Latin I with Euro)
- //035CH = 860 = IBM PC CP-860 (Portuguese)
- //035DH = 861 = IBM PC CP-861 (Icelandic)
- //035EH = 862 = IBM PC CP-862 (Hebrew)
- //035FH = 863 = IBM PC CP-863 (Canadian (French))
- //0360H = 864 = IBM PC CP-864 (Arabic)
- //0361H = 865 = IBM PC CP-865 (Nordic)
- //0362H = 866 = IBM PC CP-866 (Cyrillic (Russian))
- //0365H = 869 = IBM PC CP-869 (Greek (Modern))
- //036AH = 874 = Windows CP-874 (Thai)
- //03A4H = 932 = Windows CP-932 (Japanese Shift-JIS)
- //03A8H = 936 = Windows CP-936 (Chinese Simplified GBK)
- //03B5H = 949 = Windows CP-949 (Korean (Wansung))
- //03B6H = 950 = Windows CP-950 (Chinese Traditional BIG5)
- //04B0H = 1200 = UTF-16 (BIFF8)
- $04B0: FCodepage := 'utf-16';
- //04E2H = 1250 = Windows CP-1250 (Latin II) (Central European)
- //04E3H = 1251 = Windows CP-1251 (Cyrillic)
- //04E4H = 1252 = Windows CP-1252 (Latin I) (BIFF4-BIFF5)
- //04E5H = 1253 = Windows CP-1253 (Greek)
- //04E6H = 1254 = Windows CP-1254 (Turkish)
- $04E6: FCodepage := 'cp1254';
- //04E7H = 1255 = Windows CP-1255 (Hebrew)
- //04E8H = 1256 = Windows CP-1256 (Arabic)
- //04E9H = 1257 = Windows CP-1257 (Baltic)
- //04EAH = 1258 = Windows CP-1258 (Vietnamese)
- //0551H = 1361 = Windows CP-1361 (Korean (Johab))
- //2710H = 10000 = Apple Roman
- //8000H = 32768 = Apple Roman
- //8001H = 32769 = Windows CP-1252 (Latin I) (BIFF2-BIFF3)
+ // 016FH = 367 = ASCII
+ WORD_CP_437_DOS_US: FCodePage := 'cp437'; // IBM PC CP-437 (US)
+ //02D0H = 720 = IBM PC CP-720 (OEM Arabic)
+ //02E1H = 737 = IBM PC CP-737 (Greek)
+ //0307H = 775 = IBM PC CP-775 (Baltic)
+ WORD_CP_850_DOS_Latin1: FCodepage := 'cp850'; // IBM PC CP-850 (Latin I)
+ WORD_CP_852_DOS_Latin2: FCodepage := 'cp852'; // IBM PC CP-852 (Latin II (Central European))
+ //035AH = 858 = IBM PC CP-858 (Multilingual Latin I with Euro)
+ //035CH = 860 = IBM PC CP-860 (Portuguese)
+ //035DH = 861 = IBM PC CP-861 (Icelandic)
+ //035EH = 862 = IBM PC CP-862 (Hebrew)
+ //035FH = 863 = IBM PC CP-863 (Canadian (French))
+ //0360H = 864 = IBM PC CP-864 (Arabic)
+ //0361H = 865 = IBM PC CP-865 (Nordic)
+ WORD_CP_866_DOS_Cyrillic: FCodePage := 'cp866'; // IBM PC CP-866 (Cyrillic Russian)
+ //0365H = 869 = IBM PC CP-869 (Greek (Modern))
+ WORD_CP_874_Thai: FCodePage := 'cp874'; // 874 = Windows CP-874 (Thai)
+ //03A4H = 932 = Windows CP-932 (Japanese Shift-JIS)
+ //03A8H = 936 = Windows CP-936 (Chinese Simplified GBK)
+ //03B5H = 949 = Windows CP-949 (Korean (Wansung))
+ //03B6H = 950 = Windows CP-950 (Chinese Traditional BIG5)
+ WORD_UTF_16 : FCodePage := 'ucs2le'; // UTF-16 (BIFF8)
+ WORD_CP_1250_Latin2: FCodepage := 'cp1250'; // Windows CP-1250 (Latin II) (Central European)
+ WORD_CP_1251_Cyrillic: FCodePage := 'cp1251'; // Windows CP-1251 (Cyrillic)
+ WORD_CP_1252_Latin1: FCodePage := 'cp1252'; // Windows CP-1252 (Latin I) (BIFF4-BIFF5)
+ WORD_CP_1253_Greek: FCodePage := 'cp1253'; // Windows CP-1253 (Greek)
+ WORD_CP_1254_Turkish: FCodepage := 'cp1254'; // Windows CP-1254 (Turkish)
+ WORD_CP_1255_Hebrew: FCodePage := 'cp1255'; // Windows CP-1255 (Hebrew)
+ WORD_CP_1256_Arabic: FCodePage := 'cp1256'; // Windows CP-1256 (Arabic)
+ WORD_CP_1257_Baltic: FCodePage := 'cp1257'; // Windows CP-1257 (Baltic)
+ WORD_CP_1258_Vietnamese: FCodePage := 'cp1258'; // Windows CP-1258 (Vietnamese)
+ //0551H = 1361 = Windows CP-1361 (Korean (Johab))
+ //2710H = 10000 = Apple Roman
+ //8000H = 32768 = Apple Roman
+ WORD_CP_1258_Latin1_BIFF2_3: FCodePage := 'cp1252'; // Windows CP-1252 (Latin I) (BIFF2-BIFF3)
end;
end;
@@ -1711,7 +1702,8 @@ begin
len := AStream.ReadByte;
SetLength(s, len);
AStream.ReadBuffer(s[1], len);
- Result := ansiToUTF8(s);
+ Result := ConvertEncoding(s, FCodePage, encodingUTF8);
+// Result := ansiToUTF8(s);
end;
{ Reads a STRING record. It immediately precedes a FORMULA record which has a
@@ -1806,7 +1798,7 @@ end;
function TsSpreadBIFFWriter.GetLastRowIndex(AWorksheet: TsWorksheet): Integer;
begin
FLastRow := 0;
- IterateThroughCells(nil, AWorksheet.Cells, GetLastRowCallback);
+ IterateThroughCells(nil, AWorksheet.Cells, @GetLastRowCallback);
Result := FLastRow;
end;
@@ -1819,7 +1811,7 @@ end;
function TsSpreadBIFFWriter.GetLastColIndex(AWorksheet: TsWorksheet): Word;
begin
FLastCol := 0;
- IterateThroughCells(nil, AWorksheet.Cells, GetLastColCallback);
+ IterateThroughCells(nil, AWorksheet.Cells, @GetLastColCallback);
Result := FLastCol;
end;
@@ -1878,28 +1870,44 @@ begin
AStream.WriteBuffer(rec, SizeOf(rec));
end;
-procedure TsSpreadBIFFWriter.WriteCodepage(AStream: TStream;
- AEncoding: TsEncoding);
+{@@ ----------------------------------------------------------------------------
+ Writes the code page identifier defined by the workbook to the stream.
+ BIFF2 has to be overridden because is uses cp1252, but has a different
+ number code.
+-------------------------------------------------------------------------------}
+procedure TsSpreadBIFFWriter.WriteCodepage(AStream: TStream; ACodePage: String);
+// AEncoding: TsEncoding);
var
- lCodepage: Word;
+ cp: Word;
begin
{ BIFF Record header }
AStream.WriteWord(WordToLE(INT_EXCEL_ID_CODEPAGE));
AStream.WriteWord(WordToLE(2));
{ Codepage }
- case AEncoding of
- seLatin2: lCodepage := WORD_CP_1250_Latin2;
- seCyrillic: lCodepage := WORD_CP_1251_Cyrillic;
- seGreek: lCodepage := WORD_CP_1253_Greek;
- seTurkish: lCodepage := WORD_CP_1254_Turkish;
- seHebrew: lCodepage := WORD_CP_1255_Hebrew;
- seArabic: lCodepage := WORD_CP_1256_Arabic;
+ FCodePage := lowercase(ACodePage);
+ case FCodePage of
+ 'ucs2le': cp := WORD_UTF_16; // Biff 7
+ 'cp437' : cp := WORD_CP_437_DOS_US;
+ 'cp850' : cp := WORD_CP_850_DOS_Latin1;
+ 'cp852' : cp := WORD_CP_852_DOS_Latin2;
+ 'cp866' : cp := WORD_CP_866_DOS_Cyrillic;
+ 'cp874' : cp := WORD_CP_874_Thai;
+ 'cp1250': cp := WORD_CP_1250_Latin2;
+ 'cp1251': cp := WORD_CP_1251_Cyrillic;
+ 'cp1252': cp := WORD_CP_1252_Latin1;
+ 'cp1253': cp := WORD_CP_1253_Greek;
+ 'cp1254': cp := WORD_CP_1254_Turkish;
+ 'cp1255': cp := WORD_CP_1255_Hebrew;
+ 'cp1256': cp := WORD_CP_1256_Arabic;
+ 'cp1257': cp := WORD_CP_1257_Baltic;
+ 'cp1258': cp := WORD_CP_1258_Vietnamese;
else
- // Default is Latin1
- lCodepage := WORD_CP_1252_Latin1;
+ Workbook.AddErrorMsg(rsCodePageNotSupported, [FCodePage]);
+ FCodePage := 'cp1252';
+ cp := WORD_CP_1252_Latin1;
end;
- AStream.WriteWord(WordToLE(lCodepage));
+ AStream.WriteWord(WordToLE(cp));
end;
{ Writes column info for the given column. Currently only the colum width is used.
@@ -1958,7 +1966,8 @@ begin
end;
end;
-{ Writes a NOTE record which describes a comment attached to a cell }
+{ Writes a NOTE record which describes a comment attached to a cell
+ Valid für Biff2 and BIFF5}
procedure TsSpreadBIFFWriter.WriteComment(AStream: TStream; ACell: PCell);
const
CHUNK_SIZE = 2048;
@@ -1977,7 +1986,7 @@ begin
List := TStringList.Create;
try
- List.Text := UTF8ToAnsi(ACell^.Comment);
+ List.Text := ConvertEncoding(ACell^.Comment, encodingUTF8, FCodePage);
comment := List[0];
for p := 1 to List.Count-1 do
comment := comment + #$0A + List[p];
@@ -2402,8 +2411,8 @@ begin
shared formula RECORD here. The shared formula RECORD must follow the
first FORMULA record referring to the shared formula}
if (ACell^.SharedFormulaBase <> nil) and
- (ARow = ACell^.SharedFormulaBase.Row) and
- (ACol = ACell^.SharedFormulaBase.Col)
+ (ARow = ACell^.SharedFormulaBase^.Row) and
+ (ACol = ACell^.SharedFormulaBase^.Col)
then
WriteSharedFormula(AStream, ACell^.SharedFormulaBase);
@@ -2484,8 +2493,8 @@ var
begin
rec.FormulaSize := WordToLE(5);
rec.Token := INT_EXCEL_TOKEN_TEXP; // Marks the cell for using a shared formula
- rec.Row := WordToLE(ACell^.SharedFormulaBase.Row);
- rec.Col := WordToLE(ACell^.SharedFormulaBase.Col);
+ rec.Row := WordToLE(ACell^.SharedFormulaBase^.Row);
+ rec.Col := WordToLE(ACell^.SharedFormulaBase^.Col);
AStream.WriteBuffer(rec, SizeOf(rec));
RPNLength := SizeOf(rec);
end;
@@ -2929,7 +2938,7 @@ var
len: Byte;
s: ansistring;
begin
- s := UTF8ToAnsi(AString);
+ s := ConvertEncoding(AString, encodingUTF8, FCodePage);
len := Length(s);
AStream.WriteByte(len);
AStream.WriteBuffer(s[1], len);
diff --git a/components/fpspreadsheet/xlsxooxml.pas b/components/fpspreadsheet/xlsxooxml.pas
index 7a9d835bc..facd893a9 100755
--- a/components/fpspreadsheet/xlsxooxml.pas
+++ b/components/fpspreadsheet/xlsxooxml.pas
@@ -2395,6 +2395,8 @@ end;
procedure TsSpreadOOXMLWriter.WriteWorksheetRels(AWorksheet: TsWorksheet);
begin
+ Unused(AWorksheet);
+
// Create stream
SetLength(FSSheetRels, FCurSheetNum + 1);
if (boBufStream in Workbook.Options) then