You've already forked lazarus-ccr
fpspreadsheet: Initial support for reading html files (data only, no formats, no nested tables).
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4236 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@@ -23,7 +23,7 @@ begin
|
|||||||
MyDir := ExtractFilePath(ParamStr(0));
|
MyDir := ExtractFilePath(ParamStr(0));
|
||||||
InputFileName := MyDir + 'test' + STR_COMMA_SEPARATED_EXTENSION;
|
InputFileName := MyDir + 'test' + STR_COMMA_SEPARATED_EXTENSION;
|
||||||
if not FileExists(InputFileName) then begin
|
if not FileExists(InputFileName) then begin
|
||||||
WriteLn('Input file ', InputFileName, ' does not exist. Please run excel2write first.');
|
WriteLn('Input file ', InputFileName, ' does not exist. Please run csvwrite first.');
|
||||||
Halt;
|
Halt;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@@ -0,0 +1,66 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<CONFIG>
|
||||||
|
<ProjectOptions>
|
||||||
|
<Version Value="9"/>
|
||||||
|
<PathDelim Value="\"/>
|
||||||
|
<General>
|
||||||
|
<Flags>
|
||||||
|
<LRSInOutputDirectory Value="False"/>
|
||||||
|
</Flags>
|
||||||
|
<SessionStorage Value="InProjectDir"/>
|
||||||
|
<MainUnit Value="0"/>
|
||||||
|
<Title Value="htmlread"/>
|
||||||
|
<UseAppBundle Value="False"/>
|
||||||
|
</General>
|
||||||
|
<VersionInfo>
|
||||||
|
<StringTable ProductVersion=""/>
|
||||||
|
</VersionInfo>
|
||||||
|
<BuildModes Count="1">
|
||||||
|
<Item1 Name="default" Default="True"/>
|
||||||
|
</BuildModes>
|
||||||
|
<PublishOptions>
|
||||||
|
<Version Value="2"/>
|
||||||
|
<IgnoreBinaries Value="False"/>
|
||||||
|
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
|
||||||
|
<ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
|
||||||
|
</PublishOptions>
|
||||||
|
<RunParams>
|
||||||
|
<local>
|
||||||
|
<FormatVersion Value="1"/>
|
||||||
|
<LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
|
||||||
|
</local>
|
||||||
|
</RunParams>
|
||||||
|
<RequiredPackages Count="1">
|
||||||
|
<Item1>
|
||||||
|
<PackageName Value="LazUtils"/>
|
||||||
|
</Item1>
|
||||||
|
</RequiredPackages>
|
||||||
|
<Units Count="1">
|
||||||
|
<Unit0>
|
||||||
|
<Filename Value="htmlread.lpr"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
</Unit0>
|
||||||
|
</Units>
|
||||||
|
</ProjectOptions>
|
||||||
|
<CompilerOptions>
|
||||||
|
<Version Value="11"/>
|
||||||
|
<PathDelim Value="\"/>
|
||||||
|
<Target>
|
||||||
|
<Filename Value="htmlread"/>
|
||||||
|
</Target>
|
||||||
|
<SearchPaths>
|
||||||
|
<OtherUnitFiles Value="..\..\.."/>
|
||||||
|
<UnitOutputDirectory Value="..\..\lib\$(TargetCPU)-$(TargetOS)"/>
|
||||||
|
</SearchPaths>
|
||||||
|
<Parsing>
|
||||||
|
<SyntaxOptions>
|
||||||
|
<UseAnsiStrings Value="False"/>
|
||||||
|
</SyntaxOptions>
|
||||||
|
</Parsing>
|
||||||
|
<Linking>
|
||||||
|
<Debugging>
|
||||||
|
<DebugInfoType Value="dsDwarf2Set"/>
|
||||||
|
</Debugging>
|
||||||
|
</Linking>
|
||||||
|
</CompilerOptions>
|
||||||
|
</CONFIG>
|
@@ -0,0 +1,70 @@
|
|||||||
|
{
|
||||||
|
htmlread.dpr
|
||||||
|
|
||||||
|
Demonstrates how to read a html file using the fpspreadsheet library.
|
||||||
|
IMPORTANT: Requires the output file of the htmlwrite demo.
|
||||||
|
}
|
||||||
|
|
||||||
|
program htmlread;
|
||||||
|
|
||||||
|
{$mode delphi}{$H+}
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, LazUTF8, fpstypes, fpsutils, fpspreadsheet, fpshtml;
|
||||||
|
|
||||||
|
var
|
||||||
|
MyWorkbook: TsWorkbook;
|
||||||
|
MyWorksheet: TsWorksheet;
|
||||||
|
InputFilename: string;
|
||||||
|
MyDir: string;
|
||||||
|
i: Integer;
|
||||||
|
CurCell: PCell;
|
||||||
|
|
||||||
|
begin
|
||||||
|
// Open the input file
|
||||||
|
MyDir := ExtractFilePath(ParamStr(0));
|
||||||
|
InputFileName := MyDir + 'test' + STR_HTML_EXTENSION;
|
||||||
|
if not FileExists(InputFileName) then begin
|
||||||
|
WriteLn('Input file ', InputFileName, ' does not exist. Please run htmlwrite first.');
|
||||||
|
Halt;
|
||||||
|
end;
|
||||||
|
|
||||||
|
WriteLn('Opening input file ', InputFilename);
|
||||||
|
|
||||||
|
// Parameters
|
||||||
|
HTMLParams.TableIndex := 0;
|
||||||
|
|
||||||
|
// Create the spreadsheet
|
||||||
|
MyWorkbook := TsWorkbook.Create;
|
||||||
|
try
|
||||||
|
MyWorkbook.Options := MyWorkbook.Options + [boReadFormulas];
|
||||||
|
MyWorkbook.ReadFromFile(InputFilename, sfHTML);
|
||||||
|
|
||||||
|
MyWorksheet := MyWorkbook.GetFirstWorksheet;
|
||||||
|
|
||||||
|
// Write all cells with contents to the console
|
||||||
|
WriteLn('');
|
||||||
|
WriteLn('Contents of the first worksheet of the file:');
|
||||||
|
WriteLn('');
|
||||||
|
|
||||||
|
for CurCell in MyWorksheet.Cells do
|
||||||
|
begin
|
||||||
|
WriteLn(
|
||||||
|
'Row: ', CurCell^.Row,
|
||||||
|
' Col: ', CurCell^.Col,
|
||||||
|
' Value: ', UTF8ToConsole(MyWorkSheet.ReadAsUTF8Text(CurCell^.Row, CurCell^.Col))
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
|
||||||
|
finally
|
||||||
|
// Finalization
|
||||||
|
MyWorkbook.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{$IFDEF MSWINDOWS}
|
||||||
|
WriteLn;
|
||||||
|
WriteLn('Press ENTER to exit.');
|
||||||
|
ReadLn;
|
||||||
|
{$ENDIF}
|
||||||
|
end.
|
||||||
|
|
@@ -1 +1,3 @@
|
|||||||
This demo demonstrates how to use fpspreadsheet to read and write html files which can be opened by the browser.
|
This demo demonstrates how to use fpspreadsheet to read and write html files which can be opened by the browser.
|
||||||
|
|
||||||
|
Please run the write demo before the read demo in order to create the required spreadsheet file.
|
||||||
|
@@ -641,7 +641,7 @@ object MainForm: TMainForm
|
|||||||
end
|
end
|
||||||
object OpenDialog: TOpenDialog
|
object OpenDialog: TOpenDialog
|
||||||
DefaultExt = '.xls'
|
DefaultExt = '.xls'
|
||||||
Filter = 'All spreadsheet files|*.xls;*.xlsx;*.ods;*.csv|All Excel files (*.xls, *.xlsx)|*.xls;*.xlsx|Excel XML spreadsheet (*.xlsx)|*.xlsx|Excel 97-2003 spreadsheets (*.xls)|*.xls|Excel 5 spreadsheet (*.xls)|*.xls|Excel 2.1 spreadsheets (*.xls)|*.xls|LibreOffice/OpenOffice spreadsheet (*.ods)|*.ods|Comma-delimited files (*.csv)|*.csv'
|
Filter = 'All spreadsheet files|*.xls;*.xlsx;*.ods;*.csv|All Excel files (*.xls, *.xlsx)|*.xls;*.xlsx|Excel XML spreadsheet (*.xlsx)|*.xlsx|Excel 97-2003 spreadsheets (*.xls)|*.xls|Excel 5 spreadsheet (*.xls)|*.xls|Excel 2.1 spreadsheets (*.xls)|*.xls|LibreOffice/OpenOffice spreadsheet (*.ods)|*.ods|HTML files (*.html; *.htm)|*.html;*.htm|Comma-delimited files (*.csv)|*.csv'
|
||||||
Options = [ofExtensionDifferent, ofEnableSizing, ofViewDetail]
|
Options = [ofExtensionDifferent, ofEnableSizing, ofViewDetail]
|
||||||
left = 312
|
left = 312
|
||||||
top = 160
|
top = 160
|
||||||
@@ -943,7 +943,7 @@ object MainForm: TMainForm
|
|||||||
object AcFileOpen: TFileOpen
|
object AcFileOpen: TFileOpen
|
||||||
Category = 'File'
|
Category = 'File'
|
||||||
Caption = '&Open ...'
|
Caption = '&Open ...'
|
||||||
Dialog.Filter = 'All spreadsheet files|*.xls;*.xlsx;*.ods;*.csv|All Excel files (*.xls, *.xlsx)|*.xls;*.xlsx|Excel XML spreadsheet (*.xlsx)|*.xlsx|Excel 97-2003 spreadsheets (*.xls)|*.xls|Excel 5 spreadsheet (*.xls)|*.xls|Excel 2.1 spreadsheets (*.xls)|*.xls|LibreOffice/OpenOffice spreadsheet (*.ods)|*.ods|Comma-delimited files (*.csv)|*.csv'
|
Dialog.Filter = 'All supported spreadsheet files|*.xls;*.xlsx;*.ods;*.csv;*.html;*.htm|All Excel files (*.xls, *.xlsx)|*.xls;*.xlsx|Excel XML spreadsheet (*.xlsx)|*.xlsx|Excel 97-2003 spreadsheets (*.xls)|*.xls|Excel 5 spreadsheet (*.xls)|*.xls|Excel 2.1 spreadsheets (*.xls)|*.xls|LibreOffice/OpenOffice spreadsheet (*.ods)|*.ods|Comma-delimited files (*.csv)|*.csv|HTML files (*.html; *.htm)|*.html;*.htm'
|
||||||
Dialog.Options = [ofExtensionDifferent, ofFileMustExist, ofEnableSizing, ofViewDetail]
|
Dialog.Options = [ofExtensionDifferent, ofFileMustExist, ofEnableSizing, ofViewDetail]
|
||||||
Hint = 'Open spreadsheet file'
|
Hint = 'Open spreadsheet file'
|
||||||
ImageIndex = 44
|
ImageIndex = 44
|
||||||
|
@@ -460,6 +460,7 @@ var
|
|||||||
F: TNumFormatForm;
|
F: TNumFormatForm;
|
||||||
sample: Double;
|
sample: Double;
|
||||||
begin
|
begin
|
||||||
|
Unused(AWorkbook);
|
||||||
F := TNumFormatForm.Create(nil);
|
F := TNumFormatForm.Create(nil);
|
||||||
try
|
try
|
||||||
F.Position := poMainFormCenter;
|
F.Position := poMainFormCenter;
|
||||||
|
0
components/fpspreadsheet/fpolestorage.pas
Executable file → Normal file
0
components/fpspreadsheet/fpolestorage.pas
Executable file → Normal file
@@ -13,11 +13,6 @@ type
|
|||||||
private
|
private
|
||||||
FWorksheetName: String;
|
FWorksheetName: String;
|
||||||
FFormatSettings: TFormatSettings;
|
FFormatSettings: TFormatSettings;
|
||||||
function IsBool(AText: String; out AValue: Boolean): Boolean;
|
|
||||||
function IsDateTime(AText: String; out ADateTime: TDateTime;
|
|
||||||
out ANumFormat: TsNumberFormat): Boolean;
|
|
||||||
function IsNumber(AText: String; out ANumber: Double; out ANumFormat: TsNumberFormat;
|
|
||||||
out ADecimals: Integer; out ACurrencySymbol, AWarning: String): Boolean;
|
|
||||||
function IsQuotedText(var AText: String): Boolean;
|
function IsQuotedText(var AText: String): Boolean;
|
||||||
procedure ReadCellValue(ARow, ACol: Cardinal; AText: String);
|
procedure ReadCellValue(ARow, ACol: Cardinal; AText: String);
|
||||||
protected
|
protected
|
||||||
@@ -96,93 +91,7 @@ implementation
|
|||||||
uses
|
uses
|
||||||
//StrUtils,
|
//StrUtils,
|
||||||
DateUtils, LConvEncoding, Math,
|
DateUtils, LConvEncoding, Math,
|
||||||
fpsUtils, fpsCurrency, fpsNumFormat;
|
fpsUtils, fpsNumFormat;
|
||||||
|
|
||||||
{ Initializes the FormatSettings of the CSVParams to default values which
|
|
||||||
can be replaced by the FormatSettings of the workbook's FormatSettings }
|
|
||||||
procedure InitCSVFormatSettings;
|
|
||||||
var
|
|
||||||
i: Integer;
|
|
||||||
begin
|
|
||||||
with CSVParams.FormatSettings do
|
|
||||||
begin
|
|
||||||
CurrencyFormat := Byte(-1);
|
|
||||||
NegCurrFormat := Byte(-1);
|
|
||||||
ThousandSeparator := #0;
|
|
||||||
DecimalSeparator := #0;
|
|
||||||
CurrencyDecimals := Byte(-1);
|
|
||||||
DateSeparator := #0;
|
|
||||||
TimeSeparator := #0;
|
|
||||||
ListSeparator := #0;
|
|
||||||
CurrencyString := '';
|
|
||||||
ShortDateFormat := '';
|
|
||||||
LongDateFormat := '';
|
|
||||||
TimeAMString := '';
|
|
||||||
TimePMString := '';
|
|
||||||
ShortTimeFormat := '';
|
|
||||||
LongTimeFormat := '';
|
|
||||||
for i:=1 to 12 do
|
|
||||||
begin
|
|
||||||
ShortMonthNames[i] := '';
|
|
||||||
LongMonthNames[i] := '';
|
|
||||||
end;
|
|
||||||
for i:=1 to 7 do
|
|
||||||
begin
|
|
||||||
ShortDayNames[i] := '';
|
|
||||||
LongDayNames[i] := '';
|
|
||||||
end;
|
|
||||||
TwoDigitYearCenturyWindow := Word(-1);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure ReplaceFormatSettings(var AFormatSettings: TFormatSettings;
|
|
||||||
const ADefaultFormats: TFormatSettings);
|
|
||||||
var
|
|
||||||
i: Integer;
|
|
||||||
begin
|
|
||||||
if AFormatSettings.CurrencyFormat = Byte(-1) then
|
|
||||||
AFormatSettings.CurrencyFormat := ADefaultFormats.CurrencyFormat;
|
|
||||||
if AFormatSettings.NegCurrFormat = Byte(-1) then
|
|
||||||
AFormatSettings.NegCurrFormat := ADefaultFormats.NegCurrFormat;
|
|
||||||
if AFormatSettings.ThousandSeparator = #0 then
|
|
||||||
AFormatSettings.ThousandSeparator := ADefaultFormats.ThousandSeparator;
|
|
||||||
if AFormatSettings.DecimalSeparator = #0 then
|
|
||||||
AFormatSettings.DecimalSeparator := ADefaultFormats.DecimalSeparator;
|
|
||||||
if AFormatSettings.CurrencyDecimals = Byte(-1) then
|
|
||||||
AFormatSettings.CurrencyDecimals := ADefaultFormats.CurrencyDecimals;
|
|
||||||
if AFormatSettings.DateSeparator = #0 then
|
|
||||||
AFormatSettings.DateSeparator := ADefaultFormats.DateSeparator;
|
|
||||||
if AFormatSettings.TimeSeparator = #0 then
|
|
||||||
AFormatSettings.TimeSeparator := ADefaultFormats.TimeSeparator;
|
|
||||||
if AFormatSettings.ListSeparator = #0 then
|
|
||||||
AFormatSettings.ListSeparator := ADefaultFormats.ListSeparator;
|
|
||||||
if AFormatSettings.CurrencyString = '' then
|
|
||||||
AFormatSettings.CurrencyString := ADefaultFormats.CurrencyString;
|
|
||||||
if AFormatSettings.ShortDateFormat = '' then
|
|
||||||
AFormatSettings.ShortDateFormat := ADefaultFormats.ShortDateFormat;
|
|
||||||
if AFormatSettings.LongDateFormat = '' then
|
|
||||||
AFormatSettings.LongDateFormat := ADefaultFormats.LongDateFormat;
|
|
||||||
if AFormatSettings.ShortTimeFormat = '' then
|
|
||||||
AFormatSettings.ShortTimeFormat := ADefaultFormats.ShortTimeFormat;
|
|
||||||
if AFormatSettings.LongTimeFormat = '' then
|
|
||||||
AFormatSettings.LongTimeFormat := ADefaultFormats.LongTimeFormat;
|
|
||||||
for i:=1 to 12 do
|
|
||||||
begin
|
|
||||||
if AFormatSettings.ShortMonthNames[i] = '' then
|
|
||||||
AFormatSettings.ShortMonthNames[i] := ADefaultFormats.ShortMonthNames[i];
|
|
||||||
if AFormatSettings.LongMonthNames[i] = '' then
|
|
||||||
AFormatSettings.LongMonthNames[i] := ADefaultFormats.LongMonthNames[i];
|
|
||||||
end;
|
|
||||||
for i:=1 to 7 do
|
|
||||||
begin
|
|
||||||
if AFormatSettings.ShortDayNames[i] = '' then
|
|
||||||
AFormatSettings.ShortDayNames[i] := ADefaultFormats.ShortDayNames[i];
|
|
||||||
if AFormatSettings.LongDayNames[i] = '' then
|
|
||||||
AFormatSettings.LongDayNames[i] := ADefaultFormats.LongDayNames[i];
|
|
||||||
end;
|
|
||||||
if AFormatSettings.TwoDigitYearCenturyWindow = Word(-1) then
|
|
||||||
AFormatSettings.TwoDigitYearCenturyWindow := ADefaultFormats.TwoDigitYearCenturyWindow;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function LineEndingAsString(ALineEnding: TsCSVLineEnding): String;
|
function LineEndingAsString(ALineEnding: TsCSVLineEnding): String;
|
||||||
begin
|
begin
|
||||||
@@ -207,152 +116,6 @@ begin
|
|||||||
ReplaceFormatSettings(FFormatSettings, FWorkbook.FormatSettings);
|
ReplaceFormatSettings(FFormatSettings, FWorkbook.FormatSettings);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TsCSVReader.IsBool(AText: String; out AValue: Boolean): Boolean;
|
|
||||||
begin
|
|
||||||
if SameText(AText, CSVParams.TrueText) then
|
|
||||||
begin
|
|
||||||
AValue := true;
|
|
||||||
Result := true;
|
|
||||||
end else
|
|
||||||
if SameText(AText, CSVParams.FalseText) then
|
|
||||||
begin
|
|
||||||
AValue := false;
|
|
||||||
Result := true;
|
|
||||||
end else
|
|
||||||
Result := false;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TsCSVReader.IsDateTime(AText: String; out ADateTime: TDateTime;
|
|
||||||
out ANumFormat: TsNumberFormat): Boolean;
|
|
||||||
|
|
||||||
{ Test whether the text is formatted according to a built-in date/time format.
|
|
||||||
Converts the obtained date/time value back to a string and compares. }
|
|
||||||
function TestFormat(lNumFmt: TsNumberFormat): Boolean;
|
|
||||||
var
|
|
||||||
fmt: string;
|
|
||||||
begin
|
|
||||||
fmt := BuildDateTimeFormatString(lNumFmt, FFormatSettings);
|
|
||||||
Result := FormatDateTime(fmt, ADateTime, FFormatSettings) = AText;
|
|
||||||
if Result then ANumFormat := lNumFmt;
|
|
||||||
end;
|
|
||||||
|
|
||||||
begin
|
|
||||||
Result := TryStrToDateTime(AText, ADateTime, FFormatSettings);
|
|
||||||
if Result then
|
|
||||||
begin
|
|
||||||
ANumFormat := nfCustom;
|
|
||||||
if abs(ADateTime) > 1 then // this is most probably a date
|
|
||||||
begin
|
|
||||||
if TestFormat(nfShortDateTime) then
|
|
||||||
exit;
|
|
||||||
if TestFormat(nfLongDate) then
|
|
||||||
exit;
|
|
||||||
if TestFormat(nfShortDate) then
|
|
||||||
exit;
|
|
||||||
end else
|
|
||||||
begin // this case is time-only
|
|
||||||
if TestFormat(nfLongTimeAM) then
|
|
||||||
exit;
|
|
||||||
if TestFormat(nfLongTime) then
|
|
||||||
exit;
|
|
||||||
if TestFormat(nfShortTimeAM) then
|
|
||||||
exit;
|
|
||||||
if TestFormat(nfShortTime) then
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TsCSVReader.IsNumber(AText: String; out ANumber: Double;
|
|
||||||
out ANumFormat: TsNumberFormat; out ADecimals: Integer;
|
|
||||||
out ACurrencySymbol, AWarning: String): Boolean;
|
|
||||||
var
|
|
||||||
p: Integer;
|
|
||||||
DecSep, ThousSep: Char;
|
|
||||||
begin
|
|
||||||
Result := false;
|
|
||||||
AWarning := '';
|
|
||||||
|
|
||||||
// To detect whether the text is a currency value we look for the currency
|
|
||||||
// string. If we find it, we delete it and convert the remaining string to
|
|
||||||
// a number.
|
|
||||||
ACurrencySymbol := FFormatSettings.CurrencyString;
|
|
||||||
if RemoveCurrencySymbol(ACurrencySymbol, AText) then
|
|
||||||
begin
|
|
||||||
if IsNegative(AText) then
|
|
||||||
begin
|
|
||||||
if AText = '' then
|
|
||||||
exit;
|
|
||||||
AText := '-' + AText;
|
|
||||||
end;
|
|
||||||
end else
|
|
||||||
ACurrencySymbol := '';
|
|
||||||
|
|
||||||
if CSVParams.AutoDetectNumberFormat then
|
|
||||||
Result := TryStrToFloatAuto(AText, ANumber, DecSep, ThousSep, AWarning)
|
|
||||||
else begin
|
|
||||||
Result := TryStrToFloat(AText, ANumber, FFormatSettings);
|
|
||||||
if Result then
|
|
||||||
begin
|
|
||||||
if pos(FFormatSettings.DecimalSeparator, AText) = 0
|
|
||||||
then DecSep := #0
|
|
||||||
else DecSep := FFormatSettings.DecimalSeparator;
|
|
||||||
if pos(CSVParams.FormatSettings.ThousandSeparator, AText) = 0
|
|
||||||
then ThousSep := #0
|
|
||||||
else ThousSep := FFormatSettings.ThousandSeparator;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Try to determine the number format
|
|
||||||
if Result then
|
|
||||||
begin
|
|
||||||
if ThousSep <> #0 then
|
|
||||||
ANumFormat := nfFixedTh
|
|
||||||
else
|
|
||||||
ANumFormat := nfGeneral;
|
|
||||||
// count number of decimal places and try to catch special formats
|
|
||||||
ADecimals := 0;
|
|
||||||
if DecSep <> #0 then
|
|
||||||
begin
|
|
||||||
// Go to the decimal separator and search towards the end of the string
|
|
||||||
p := pos(DecSep, AText) + 1;
|
|
||||||
while (p <= Length(AText)) do begin
|
|
||||||
// exponential format
|
|
||||||
if AText[p] in ['+', '-', 'E', 'e'] then
|
|
||||||
begin
|
|
||||||
ANumFormat := nfExp;
|
|
||||||
break;
|
|
||||||
end else
|
|
||||||
// percent format
|
|
||||||
if AText[p] = '%' then
|
|
||||||
begin
|
|
||||||
ANumFormat := nfPercentage;
|
|
||||||
break;
|
|
||||||
end else
|
|
||||||
begin
|
|
||||||
inc(p);
|
|
||||||
inc(ADecimals);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
if (ADecimals > 0) and (ADecimals < 9) and (ANumFormat = nfGeneral) then
|
|
||||||
// "no formatting" assumed if there are "many" decimals
|
|
||||||
ANumFormat := nfFixed;
|
|
||||||
end else
|
|
||||||
begin
|
|
||||||
p := Length(AText);
|
|
||||||
while (p > 0) do begin
|
|
||||||
case AText[p] of
|
|
||||||
'%' : ANumFormat := nfPercentage;
|
|
||||||
'e', 'E': ANumFormat := nfExp;
|
|
||||||
else dec(p);
|
|
||||||
end;
|
|
||||||
break;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end else
|
|
||||||
ACurrencySymbol := '';
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ Checks if text is quoted; strips any starting and ending quotes }
|
{ Checks if text is quoted; strips any starting and ending quotes }
|
||||||
function TsCSVReader.IsQuotedText(var AText: String): Boolean;
|
function TsCSVReader.IsQuotedText(var AText: String): Boolean;
|
||||||
begin
|
begin
|
||||||
@@ -399,7 +162,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
// Check for a NUMBER or CURRENCY cell
|
// Check for a NUMBER or CURRENCY cell
|
||||||
if IsNumber(AText, dblValue, nf, decs, currSym, warning) then
|
if IsNumberValue(AText, CSVParams.AutoDetectNumberFormat, FFormatSettings,
|
||||||
|
dblValue, nf, decs, currSym, warning) then
|
||||||
begin
|
begin
|
||||||
if currSym <> '' then
|
if currSym <> '' then
|
||||||
FWorksheet.WriteCurrency(cell, dblValue, nfCurrency, decs, currSym)
|
FWorksheet.WriteCurrency(cell, dblValue, nfCurrency, decs, currSym)
|
||||||
@@ -412,14 +176,14 @@ begin
|
|||||||
|
|
||||||
// Check for a DATE/TIME cell
|
// Check for a DATE/TIME cell
|
||||||
// No idea how to apply the date/time formatsettings here...
|
// No idea how to apply the date/time formatsettings here...
|
||||||
if IsDateTime(AText, dtValue, nf) then
|
if IsDateTimeValue(AText, FFormatSettings, dtValue, nf) then
|
||||||
begin
|
begin
|
||||||
FWorksheet.WriteDateTime(cell, dtValue, nf);
|
FWorksheet.WriteDateTime(cell, dtValue, nf);
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Check for a BOOLEAN cell
|
// Check for a BOOLEAN cell
|
||||||
if IsBool(AText, boolValue) then
|
if IsBoolValue(AText, CSVParams.TrueText, CSVParams.FalseText, boolValue) then
|
||||||
begin
|
begin
|
||||||
FWorksheet.WriteBoolValue(cell, boolValue);
|
FWorksheet.WriteBoolValue(cell, boolValue);
|
||||||
exit;
|
exit;
|
||||||
@@ -656,7 +420,7 @@ end;
|
|||||||
|
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
InitCSVFormatSettings;
|
InitFormatSettings(CSVParams.FormatSettings);
|
||||||
RegisterSpreadFormat(TsCSVReader, TsCSVWriter, sfCSV);
|
RegisterSpreadFormat(TsCSVReader, TsCSVWriter, sfCSV);
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
@@ -8,30 +8,38 @@ uses
|
|||||||
Classes, SysUtils, fasthtmlparser,
|
Classes, SysUtils, fasthtmlparser,
|
||||||
fpstypes, fpspreadsheet, fpsReaderWriter;
|
fpstypes, fpspreadsheet, fpsReaderWriter;
|
||||||
|
|
||||||
type (*
|
type
|
||||||
|
TsHTMLTokenKind = (htkTABLE, htkTR, htkTH, htkTD, htkDIV, htkSPAN, htkP);
|
||||||
|
{
|
||||||
|
TsHTMLToken = class
|
||||||
|
Kind: TsHTMLTokenKind;
|
||||||
|
Parent: TsHTMLToken;
|
||||||
|
Children
|
||||||
|
}
|
||||||
TsHTMLReader = class(TsCustomSpreadReader)
|
TsHTMLReader = class(TsCustomSpreadReader)
|
||||||
private
|
private
|
||||||
FWorksheetName: String;
|
|
||||||
FFormatSettings: TFormatSettings;
|
FFormatSettings: TFormatSettings;
|
||||||
function IsBool(AText: String; out AValue: Boolean): Boolean;
|
parser: THTMLParser;
|
||||||
function IsDateTime(AText: String; out ADateTime: TDateTime;
|
FInTable: Boolean;
|
||||||
out ANumFormat: TsNumberFormat): Boolean;
|
FInSubTable: Boolean;
|
||||||
function IsNumber(AText: String; out ANumber: Double; out ANumFormat: TsNumberFormat;
|
FInCell: Boolean;
|
||||||
out ADecimals: Integer; out ACurrencySymbol, AWarning: String): Boolean;
|
FInSpan: Boolean;
|
||||||
function IsQuotedText(var AText: String): Boolean;
|
FInA: Boolean;
|
||||||
procedure ReadCellValue(ARow, ACol: Cardinal; AText: String);
|
FInHeader: Boolean;
|
||||||
|
FTableCounter: Integer;
|
||||||
|
FCurrRow, FCurrCol: LongInt;
|
||||||
|
FCelLText: String;
|
||||||
|
procedure TagFoundHandler(NoCaseTag, ActualTag: string);
|
||||||
|
procedure TextFoundHandler(AText: String);
|
||||||
protected
|
protected
|
||||||
procedure ReadBlank(AStream: TStream); override;
|
procedure ProcessCellValue(ARow, ACol: LongInt; AText: String);
|
||||||
procedure ReadFormula(AStream: TStream); override;
|
|
||||||
procedure ReadLabel(AStream: TStream); override;
|
|
||||||
procedure ReadNumber(AStream: TStream); override;
|
|
||||||
public
|
public
|
||||||
constructor Create(AWorkbook: TsWorkbook); override;
|
constructor Create(AWorkbook: TsWorkbook); override;
|
||||||
procedure ReadFromFile(AFileName: String); override;
|
destructor Destroy; override;
|
||||||
procedure ReadFromStream(AStream: TStream); override;
|
procedure ReadFromStream(AStream: TStream); override;
|
||||||
procedure ReadFromStrings(AStrings: TStrings); override;
|
procedure ReadFromStrings(AStrings: TStrings); override;
|
||||||
end;
|
end;
|
||||||
*)
|
|
||||||
TsHTMLWriter = class(TsCustomSpreadWriter)
|
TsHTMLWriter = class(TsCustomSpreadWriter)
|
||||||
private
|
private
|
||||||
FPointSeparatorSettings: TFormatSettings;
|
FPointSeparatorSettings: TFormatSettings;
|
||||||
@@ -78,26 +86,523 @@ type (*
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
TsHTMLParams = record
|
TsHTMLParams = record
|
||||||
|
TableIndex: Integer; // R: Index of the table in the HTML file
|
||||||
SheetIndex: Integer; // W: Index of the sheet to be written
|
SheetIndex: Integer; // W: Index of the sheet to be written
|
||||||
ShowRowColHeaders: Boolean; // RW: Show row/column headers
|
ShowRowColHeaders: Boolean; // RW: Show row/column headers
|
||||||
|
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
|
||||||
TrueText: String; // RW: String for boolean TRUE
|
TrueText: String; // RW: String for boolean TRUE
|
||||||
FalseText: String; // RW: String for boolean FALSE
|
FalseText: String; // RW: String for boolean FALSE
|
||||||
|
FormatSettings: TFormatSettings; // RW: add'l parameters for conversion
|
||||||
end;
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
HTMLParams: TsHTMLParams = (
|
HTMLParams: TsHTMLParams = (
|
||||||
|
TableIndex: -1; // -1 = all tables
|
||||||
SheetIndex: -1; // -1 = active sheet, MaxInt = all sheets
|
SheetIndex: -1; // -1 = active sheet, MaxInt = all sheets
|
||||||
ShowRowColHeaders: false;
|
ShowRowColHeaders: false;
|
||||||
|
DetectContentType: true;
|
||||||
|
NumberFormat: '';
|
||||||
|
AutoDetectNumberFormat: true;
|
||||||
TrueText: 'TRUE';
|
TrueText: 'TRUE';
|
||||||
FalseText: 'FALSE';
|
FalseText: 'FALSE';
|
||||||
);
|
{%H-});
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
LazUTF8, URIParser, Math, StrUtils,
|
LazUTF8, URIParser, StrUtils,
|
||||||
fpsUtils;
|
fpsUtils, fpsHTMLUtils, fpsNumFormat;
|
||||||
|
(*
|
||||||
|
type
|
||||||
|
THTMLEntity = record
|
||||||
|
E: String;
|
||||||
|
Ch: String;
|
||||||
|
end;
|
||||||
|
|
||||||
|
const
|
||||||
|
HTMLEntities: array[0..251] of THTMLEntity = (
|
||||||
|
// A
|
||||||
|
(E: 'Acirc'; Ch: 'Â'), // 0
|
||||||
|
(E: 'acirc'; Ch: 'â'),
|
||||||
|
(E: 'acute'; Ch: '´'),
|
||||||
|
(E: 'AElig'; Ch: 'Æ'),
|
||||||
|
(E: 'aelig'; Ch: 'æ'),
|
||||||
|
(E: 'Agrave'; Ch: 'À'),
|
||||||
|
(E: 'agrave'; Ch: 'à'),
|
||||||
|
(E: 'alefsym';Ch: 'ℵ'),
|
||||||
|
(E: 'Alpha'; Ch: 'Α'),
|
||||||
|
(E: 'alpha'; Ch: 'α'),
|
||||||
|
(E: 'amp'; Ch: '&'), // 10
|
||||||
|
(E: 'and'; Ch: '∧'),
|
||||||
|
(E: 'ang'; Ch: '∠'),
|
||||||
|
(E: 'apos'; Ch: ''''),
|
||||||
|
(E: 'Aring'; Ch: 'Å'),
|
||||||
|
(E: 'aring'; Ch: 'å'),
|
||||||
|
(E: 'asymp'; Ch: '≈'),
|
||||||
|
(E: 'Atilde'; Ch: 'Ã'),
|
||||||
|
(E: 'atilde'; Ch: 'ã'),
|
||||||
|
(E: 'Auml'; Ch: 'Ä'),
|
||||||
|
(E: 'auml'; Ch: 'ä'), // 20
|
||||||
|
// B
|
||||||
|
(E: 'bdquo'; Ch: '„'), // 21
|
||||||
|
(E: 'Beta'; Ch: 'Β'),
|
||||||
|
(E: 'beta'; Ch: 'β'),
|
||||||
|
(E: 'brvbar'; Ch: '¦'),
|
||||||
|
(E: 'bull'; Ch: '•'),
|
||||||
|
// C
|
||||||
|
(E: 'cap'; Ch: '∩'), // 26
|
||||||
|
(E: 'Ccedil'; Ch: 'Ç'),
|
||||||
|
(E: 'ccedil'; Ch: 'ç'),
|
||||||
|
(E: 'cedil'; Ch: '¸'),
|
||||||
|
(E: 'cent'; Ch: '¢'), // 39
|
||||||
|
(E: 'Chi'; Ch: 'Χ'),
|
||||||
|
(E: 'chi'; Ch: 'χ'),
|
||||||
|
(E: 'circ'; Ch: 'ˆ'),
|
||||||
|
(E: 'clubs'; Ch: '♣'),
|
||||||
|
(E: 'cong'; Ch: '≅'), // approximately equal
|
||||||
|
(E: 'copy'; Ch: '©'),
|
||||||
|
(E: 'crarr'; Ch: '↵'), // carriage return
|
||||||
|
(E: 'cup'; Ch: '∪'),
|
||||||
|
(E: 'curren'; Ch: '¤'),
|
||||||
|
// D
|
||||||
|
(E: 'Dagger'; Ch: '‡'), // 40
|
||||||
|
(E: 'dagger'; Ch: '†'),
|
||||||
|
(E: 'dArr'; Ch: '⇓'), // wide down-arrow
|
||||||
|
(E: 'darr'; Ch: '↓'), // narrow down-arrow
|
||||||
|
(E: 'deg'; Ch: '°'),
|
||||||
|
(E: 'Delta'; Ch: 'Δ'),
|
||||||
|
(E: 'delta'; Ch: 'δ'),
|
||||||
|
(E: 'diams'; Ch: '♦'),
|
||||||
|
(E: 'divide'; Ch: '÷'),
|
||||||
|
// E
|
||||||
|
(E: 'Eacute'; Ch: 'É'),
|
||||||
|
(E: 'eacute'; Ch: 'é'),
|
||||||
|
(E: 'Ecirc'; Ch: 'Ê'),
|
||||||
|
(E: 'ecirc'; Ch: 'ê'),
|
||||||
|
(E: 'Egrave'; Ch: 'È'),
|
||||||
|
(E: 'egrave'; Ch: 'è'),
|
||||||
|
(E: 'empty'; Ch: '∅'),
|
||||||
|
(E: 'emsp'; Ch: ' '), // Space character width of "m"
|
||||||
|
(E: 'ensp'; Ch: ' '), // Space character width of "n"
|
||||||
|
(E: 'Epsilon';Ch: 'Ε'), // capital epsilon
|
||||||
|
(E: 'epsilon';Ch: 'ε'),
|
||||||
|
(E: 'equiv'; Ch: '≡'),
|
||||||
|
(E: 'Eta'; Ch: 'Η'),
|
||||||
|
(E: 'eta'; Ch: 'η'),
|
||||||
|
(E: 'ETH'; Ch: 'Ð'),
|
||||||
|
(E: 'eth'; Ch: 'ð'),
|
||||||
|
(E: 'Euml'; Ch: 'Ë'),
|
||||||
|
(E: 'euml'; Ch: 'ë'),
|
||||||
|
(E: 'euro'; Ch: '€'),
|
||||||
|
(E: 'exist'; Ch: '∃'),
|
||||||
|
// F
|
||||||
|
(E: 'fnof'; Ch: 'ƒ'),
|
||||||
|
(E: 'forall'; Ch: '∀'),
|
||||||
|
(E: 'frac12'; Ch: '½'),
|
||||||
|
(E: 'frac14'; Ch: '¼'),
|
||||||
|
(E: 'frac34'; Ch: '¾'),
|
||||||
|
(E: 'frasl'; Ch: '⁄'),
|
||||||
|
// G
|
||||||
|
(E: 'Gamma'; Ch: 'Γ'),
|
||||||
|
(E: 'gamma'; Ch: 'γ'),
|
||||||
|
(E: 'ge'; Ch: '≥'),
|
||||||
|
(E: 'gt'; Ch: '>'),
|
||||||
|
// H
|
||||||
|
(E: 'hArr'; Ch: '⇔'), // wide horizontal double arrow
|
||||||
|
(E: 'harr'; Ch: '↔'), // narrow horizontal double arrow
|
||||||
|
(E: 'hearts'; Ch: '♥'),
|
||||||
|
(E: 'hellip'; Ch: '…'),
|
||||||
|
// I
|
||||||
|
(E: 'Iacute'; Ch: 'Í'),
|
||||||
|
(E: 'iacute'; Ch: 'í'),
|
||||||
|
(E: 'Icirc'; Ch: 'Î'),
|
||||||
|
(E: 'icirc'; Ch: 'î'),
|
||||||
|
(E: 'iexcl'; Ch: '¡'),
|
||||||
|
(E: 'Igrave'; Ch: 'Ì'),
|
||||||
|
(E: 'igrave'; Ch: 'ì'),
|
||||||
|
(E: 'image'; Ch: 'ℑ'), //
|
||||||
|
(E: 'infin'; Ch: '∞'),
|
||||||
|
(E: 'int'; Ch: '∫'),
|
||||||
|
(E: 'Iota'; Ch: 'Ι'),
|
||||||
|
(E: 'iota'; Ch: 'ι'),
|
||||||
|
(E: 'iquest'; Ch: '¿'),
|
||||||
|
(E: 'isin'; Ch: '∈'),
|
||||||
|
(E: 'Iuml'; Ch: 'Ï'),
|
||||||
|
(E: 'iuml'; Ch: 'ï'),
|
||||||
|
// K
|
||||||
|
(E: 'Kappa'; Ch: 'Κ'),
|
||||||
|
(E: 'kappa'; Ch: 'κ'),
|
||||||
|
// L
|
||||||
|
(E: 'Lambda'; Ch: 'Λ'),
|
||||||
|
(E: 'lambda'; Ch: 'λ'),
|
||||||
|
(E: 'lang'; Ch: '⟨'), // Left-pointing angle bracket
|
||||||
|
(E: 'laquo'; Ch: '«'),
|
||||||
|
(E: 'lArr'; Ch: '⇐'), // Left-pointing wide arrow
|
||||||
|
(E: 'larr'; Ch: '←'),
|
||||||
|
(E: 'lceil'; Ch: '⌈'), // Left ceiling
|
||||||
|
(E: 'ldquo'; Ch: '“'),
|
||||||
|
(E: 'le'; Ch: '≤'),
|
||||||
|
(E: 'lfloor'; Ch: '⌊'), // Left floor
|
||||||
|
(E: 'lowast'; Ch: '∗'), // Low asterisk
|
||||||
|
(E: 'loz'; Ch: '◊'),
|
||||||
|
(E: 'lrm'; Ch: ''), // Left-to-right mark
|
||||||
|
(E: 'lsaquo'; Ch: '‹'),
|
||||||
|
(E: 'lsquo'; Ch: '‘'),
|
||||||
|
(E: 'lt'; Ch: '<'),
|
||||||
|
// M
|
||||||
|
(E: 'macr'; Ch: '¯'),
|
||||||
|
(E: 'mdash'; Ch: '—'),
|
||||||
|
(E: 'micro'; Ch: 'µ'),
|
||||||
|
(E: 'middot'; Ch: '·'),
|
||||||
|
(E: 'minus'; Ch: '−'),
|
||||||
|
(E: 'Mu'; Ch: 'Μ'),
|
||||||
|
(E: 'mu'; Ch: 'μ'),
|
||||||
|
// N
|
||||||
|
(E: 'nabla'; Ch: '∇'),
|
||||||
|
(E: 'nbsp'; Ch: ' '),
|
||||||
|
(E: 'ndash'; Ch: '–'),
|
||||||
|
(E: 'ne'; Ch: '≠'),
|
||||||
|
(E: 'ni'; Ch: '∋'),
|
||||||
|
(E: 'not'; Ch: '¬'),
|
||||||
|
(E: 'notin'; Ch: '∉'), // math: "not in"
|
||||||
|
(E: 'nsub'; Ch: '⊄'), // math: "not a subset of"
|
||||||
|
(E: 'Ntilde'; Ch: 'Ñ'),
|
||||||
|
(E: 'ntilde'; Ch: 'ñ'),
|
||||||
|
(E: 'Nu'; Ch: 'Ν'),
|
||||||
|
(E: 'nu'; Ch: 'ν'),
|
||||||
|
// O
|
||||||
|
(E: 'Oacute'; Ch: 'Ó'),
|
||||||
|
(E: 'oacute'; Ch: 'ó'),
|
||||||
|
(E: 'Ocirc'; Ch: 'Ô'),
|
||||||
|
(E: 'ocirc'; Ch: 'ô'),
|
||||||
|
(E: 'OElig'; Ch: 'Œ'),
|
||||||
|
(E: 'oelig'; Ch: 'œ'),
|
||||||
|
(E: 'Ograve'; Ch: 'Ò'),
|
||||||
|
(E: 'ograve'; Ch: 'ò'),
|
||||||
|
(E: 'oline'; Ch: '‾'),
|
||||||
|
(E: 'Omega'; Ch: 'Ω'),
|
||||||
|
(E: 'omega'; Ch: 'ω'),
|
||||||
|
(E: 'Omicron';Ch: 'Ο'),
|
||||||
|
(E: 'omicron';Ch: 'ο'),
|
||||||
|
(E: 'oplus'; Ch: '⊕'), // Circled plus
|
||||||
|
(E: 'or'; Ch: '∨'),
|
||||||
|
(E: 'ordf'; Ch: 'ª'),
|
||||||
|
(E: 'ordm'; Ch: 'º'),
|
||||||
|
(E: 'Oslash'; Ch: 'Ø'),
|
||||||
|
(E: 'oslash'; Ch: 'ø'),
|
||||||
|
(E: 'Otilde'; Ch: 'Õ'),
|
||||||
|
(E: 'otilde'; Ch: 'õ'),
|
||||||
|
(E: 'otimes'; Ch: '⊗'), // Circled times
|
||||||
|
(E: 'Ouml'; Ch: 'Ö'),
|
||||||
|
(E: 'ouml'; Ch: 'ö'),
|
||||||
|
// P
|
||||||
|
(E: 'para'; Ch: '¶'),
|
||||||
|
(E: 'part'; Ch: '∂'),
|
||||||
|
(E: 'permil'; Ch: '‰'),
|
||||||
|
(E: 'perp'; Ch: '⊥'),
|
||||||
|
(E: 'Phi'; Ch: 'Φ'),
|
||||||
|
(E: 'phi'; Ch: 'φ'),
|
||||||
|
(E: 'Pi'; Ch: 'Π'),
|
||||||
|
(E: 'pi'; Ch: 'π'), // lower-case pi
|
||||||
|
(E: 'piv'; Ch: 'ϖ'),
|
||||||
|
(E: 'plusmn'; Ch: '±'),
|
||||||
|
(E: 'pound'; Ch: '£'),
|
||||||
|
(E: 'Prime'; Ch: '″'),
|
||||||
|
(E: 'prime'; Ch: '′'),
|
||||||
|
(E: 'prod'; Ch: '∏'),
|
||||||
|
(E: 'prop'; Ch: '∝'),
|
||||||
|
(E: 'Psi'; Ch: 'Ψ'),
|
||||||
|
(E: 'psi'; Ch: 'ψ'),
|
||||||
|
// Q
|
||||||
|
(E: 'quot'; Ch: '"'),
|
||||||
|
// R
|
||||||
|
(E: 'radic'; Ch: '√'),
|
||||||
|
(E: 'rang'; Ch: '⟩'), // right-pointing angle bracket
|
||||||
|
(E: 'raquo'; Ch: '»'),
|
||||||
|
(E: 'rArr'; Ch: '⇒'),
|
||||||
|
(E: 'rarr'; Ch: '→'),
|
||||||
|
(E: 'rceil'; Ch: '⌉'), // right ceiling
|
||||||
|
(E: 'rdquo'; Ch: '”'),
|
||||||
|
(E: 'real'; Ch: 'ℜ'), // R in factura
|
||||||
|
(E: 'reg'; Ch: '®'),
|
||||||
|
(E: 'rfloor'; Ch: '⌋'), // Right floor
|
||||||
|
(E: 'Rho'; Ch: 'Ρ'),
|
||||||
|
(E: 'rho'; Ch: 'ρ'),
|
||||||
|
(E: 'rlm'; Ch: ''), // right-to-left mark
|
||||||
|
(E: 'rsaquo'; Ch: '›'),
|
||||||
|
(E: 'rsquo'; Ch: '’'),
|
||||||
|
|
||||||
|
// S
|
||||||
|
(E: 'sbquo'; Ch: '‚'),
|
||||||
|
(E: 'Scaron'; Ch: 'Š'),
|
||||||
|
(E: 'scaron'; Ch: 'š'),
|
||||||
|
(E: 'sdot'; Ch: '⋅'), // math: dot operator
|
||||||
|
(E: 'sect'; Ch: '§'),
|
||||||
|
(E: 'shy'; Ch: ''), // conditional hyphen
|
||||||
|
(E: 'Sigma'; Ch: 'Σ'),
|
||||||
|
(E: 'sigma'; Ch: 'σ'),
|
||||||
|
(E: 'sigmaf'; Ch: 'ς'),
|
||||||
|
(E: 'sim'; Ch: '∼'), // similar
|
||||||
|
(E: 'spades'; Ch: '♠'),
|
||||||
|
(E: 'sub'; Ch: '⊂'),
|
||||||
|
(E: 'sube'; Ch: '⊆'),
|
||||||
|
(E: 'sum'; Ch: '∑'),
|
||||||
|
(E: 'sup'; Ch: '⊃'),
|
||||||
|
(E: 'sup1'; Ch: '¹'),
|
||||||
|
(E: 'sup2'; Ch: '²'),
|
||||||
|
(E: 'sup3'; Ch: '³'),
|
||||||
|
(E: 'supe'; Ch: '⊇'),
|
||||||
|
(E: 'szlig'; Ch: 'ß'),
|
||||||
|
//T
|
||||||
|
(E: 'Tau'; Ch: 'Τ'),
|
||||||
|
(E: 'tau'; Ch: 'τ'),
|
||||||
|
(E: 'there4'; Ch: '∴'),
|
||||||
|
(E: 'Theta'; Ch: 'Θ'),
|
||||||
|
(E: 'theta'; Ch: 'θ'),
|
||||||
|
(E: 'thetasym';Ch: 'ϑ'),
|
||||||
|
(E: 'thinsp'; Ch: ' '), // thin space
|
||||||
|
(E: 'THORN'; Ch: 'Þ'),
|
||||||
|
(E: 'thorn'; Ch: 'þ'),
|
||||||
|
(E: 'tilde'; Ch: '˜'),
|
||||||
|
(E: 'times'; Ch: '×'),
|
||||||
|
(E: 'trade'; Ch: '™'),
|
||||||
|
// U
|
||||||
|
(E: 'Uacute'; Ch: 'Ú'),
|
||||||
|
(E: 'uacute'; Ch: 'ú'),
|
||||||
|
(E: 'uArr'; Ch: '⇑'), // wide up-arrow
|
||||||
|
(E: 'uarr'; Ch: '↑'),
|
||||||
|
(E: 'Ucirc'; Ch: 'Û'),
|
||||||
|
(E: 'ucirc'; Ch: 'û'),
|
||||||
|
(E: 'Ugrave'; Ch: 'Ù'),
|
||||||
|
(E: 'ugrave'; Ch: 'ù'),
|
||||||
|
(E: 'uml'; Ch: '¨'),
|
||||||
|
(E: 'upsih'; Ch: 'ϒ'),
|
||||||
|
(E: 'Upsilon';Ch: 'Υ'),
|
||||||
|
(E: 'upsilon';Ch: 'υ'),
|
||||||
|
(E: 'Uuml'; Ch: 'Ü'),
|
||||||
|
(E: 'uuml'; Ch: 'ü'),
|
||||||
|
// W
|
||||||
|
(E: 'weierp'; Ch: '℘'), // Script Capital P; Weierstrass Elliptic Function
|
||||||
|
// X
|
||||||
|
(E: 'Xi'; Ch: 'Ξ'),
|
||||||
|
(E: 'xi'; Ch: 'ξ'),
|
||||||
|
// Y
|
||||||
|
(E: 'Yacute'; Ch: 'Ý'),
|
||||||
|
(E: 'yacute'; Ch: 'ý'),
|
||||||
|
(E: 'yen'; Ch: '¥'),
|
||||||
|
(E: 'Yuml'; Ch: 'Ÿ'),
|
||||||
|
(E: 'yuml'; Ch: 'ÿ'),
|
||||||
|
// Z
|
||||||
|
(E: 'Zeta'; Ch: 'Ζ'),
|
||||||
|
(E: 'zeta'; Ch: 'ζ'),
|
||||||
|
(E: 'zwj'; Ch: ''), // Zero-width joiner
|
||||||
|
(E: 'zwnj'; Ch: ''), // Zero-width non-joiner
|
||||||
|
|
||||||
|
(E: '#160'; Ch: ' ') // numerical value of " "
|
||||||
|
);
|
||||||
|
*)
|
||||||
|
{==============================================================================}
|
||||||
|
{ TsHTMLReader }
|
||||||
|
{==============================================================================}
|
||||||
|
|
||||||
|
constructor TsHTMLReader.Create(AWorkbook: TsWorkbook);
|
||||||
|
begin
|
||||||
|
inherited Create(AWorkbook);
|
||||||
|
FFormatSettings := HTMLParams.FormatSettings;
|
||||||
|
ReplaceFormatSettings(FFormatSettings, FWorkbook.FormatSettings);
|
||||||
|
FTableCounter := -1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TsHTMLReader.Destroy;
|
||||||
|
begin
|
||||||
|
FreeAndNil(parser);
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsHTMLReader.ReadFromStream(AStream: TStream);
|
||||||
|
var
|
||||||
|
list: TStringList;
|
||||||
|
begin
|
||||||
|
list := TStringList.Create;
|
||||||
|
try
|
||||||
|
list.LoadFromStream(AStream);
|
||||||
|
ReadFromStrings(list);
|
||||||
|
if FWorkbook.GetWorksheetCount = 0 then
|
||||||
|
begin
|
||||||
|
FWorkbook.AddErrorMsg('Requested table not found, or no tables in html file');
|
||||||
|
FWorkbook.AddWorksheet('Dummy');
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
list.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsHTMLReader.ReadFromStrings(AStrings: TStrings);
|
||||||
|
begin
|
||||||
|
// Create html parser
|
||||||
|
FreeAndNil(parser);
|
||||||
|
parser := THTMLParser.Create(AStrings.Text);
|
||||||
|
parser.OnFoundTag := @TagFoundHandler;
|
||||||
|
parser.OnFoundText := @TextFoundHandler;
|
||||||
|
// Execute the html parser
|
||||||
|
parser.Exec;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsHTMLReader.ProcessCellValue(ARow, ACol: LongInt; AText: String);
|
||||||
|
var
|
||||||
|
cell: PCell;
|
||||||
|
dblValue: Double;
|
||||||
|
dtValue: TDateTime;
|
||||||
|
boolValue: Boolean;
|
||||||
|
nf: TsNumberFormat;
|
||||||
|
decs: Integer;
|
||||||
|
currSym: String;
|
||||||
|
warning: String;
|
||||||
|
begin
|
||||||
|
// Empty strings are blank cells -- nothing to do
|
||||||
|
if (AText = '') then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
cell := FWorksheet.AddCell(ARow, ACol);
|
||||||
|
|
||||||
|
// Do not try to interpret the strings. --> everything is a LABEL cell.
|
||||||
|
if not HTMLParams.DetectContentType then
|
||||||
|
begin
|
||||||
|
FWorksheet.WriteUTF8Text(cell, AText);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Check for a NUMBER or CURRENCY cell
|
||||||
|
if IsNumberValue(AText, HTMLParams.AutoDetectNumberFormat, FFormatSettings,
|
||||||
|
dblValue, nf, decs, currSym, warning) then
|
||||||
|
begin
|
||||||
|
if currSym <> '' then
|
||||||
|
FWorksheet.WriteCurrency(cell, dblValue, nfCurrency, decs, currSym)
|
||||||
|
else
|
||||||
|
FWorksheet.WriteNumber(cell, dblValue, nf, decs);
|
||||||
|
if warning <> '' then
|
||||||
|
FWorkbook.AddErrorMsg('Cell %s: %s', [GetCellString(ARow, ACol), warning]);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Check for a DATE/TIME cell
|
||||||
|
// No idea how to apply the date/time formatsettings here...
|
||||||
|
if IsDateTimevalue(AText, FFormatSettings, dtValue, nf) then
|
||||||
|
begin
|
||||||
|
FWorksheet.WriteDateTime(cell, dtValue, nf);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Check for a BOOLEAN cell
|
||||||
|
if IsBoolValue(AText, HTMLParams.TrueText, HTMLParams.FalseText, boolValue) then
|
||||||
|
begin
|
||||||
|
FWorksheet.WriteBoolValue(cell, boolValue);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// What is left is handled as a TEXT cell
|
||||||
|
FWorksheet.WriteUTF8Text(cell, AText);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TsHTMLReader.TagFoundHandler(NoCaseTag, ActualTag: string);
|
||||||
|
begin
|
||||||
|
if pos('<TABLE', NoCaseTag) = 1 then
|
||||||
|
begin
|
||||||
|
inc(FTableCounter);
|
||||||
|
if HTMLParams.TableIndex < 0 then // all tables
|
||||||
|
begin
|
||||||
|
FWorksheet := FWorkbook.AddWorksheet(Format('Table #%d', [FTableCounter+1]));
|
||||||
|
FInTable := true;
|
||||||
|
FCurrRow := -1;
|
||||||
|
FCurrCol := -1;
|
||||||
|
end else
|
||||||
|
if FTableCounter = HTMLParams.TableIndex then
|
||||||
|
begin
|
||||||
|
FWorksheet := FWorkbook.AddWorksheet(Format('Table #%d', [FTableCounter+1]));
|
||||||
|
FInTable := true;
|
||||||
|
FCurrRow := -1;
|
||||||
|
FCurrCol := -1;
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
if ((NoCaseTag = '<TR>') or (pos('<TR ', NoCaseTag) = 1)) and FInTable then
|
||||||
|
begin
|
||||||
|
inc(FCurrRow);
|
||||||
|
FCurrCol := -1;
|
||||||
|
end else
|
||||||
|
if ((NoCaseTag = '<TD>') or (pos('<TD ', NoCaseTag) = 1)) and FInTable then
|
||||||
|
begin
|
||||||
|
FInCell := true;
|
||||||
|
inc(FCurrCol);
|
||||||
|
FCellText := '';
|
||||||
|
end else
|
||||||
|
if ((NoCaseTag = '<TH>') or (pos('<TH ', NoCaseTag) = 1)) and FInTable then
|
||||||
|
begin
|
||||||
|
FInCell := true;
|
||||||
|
FCellText := '';
|
||||||
|
end else
|
||||||
|
if pos('<SPAN', NoCaseTag) = 1 then
|
||||||
|
begin
|
||||||
|
if FInCell then
|
||||||
|
FInSpan := true;
|
||||||
|
end else
|
||||||
|
if pos('<A', NoCaseTag) = 1 then
|
||||||
|
begin
|
||||||
|
if FInCell then
|
||||||
|
FInA := true
|
||||||
|
end else
|
||||||
|
if (pos('<H', NoCaseTag) = 1) and (NoCaseTag[3] in ['1', '2', '3', '4', '5', '6']) then
|
||||||
|
begin
|
||||||
|
if FInCell then
|
||||||
|
FInHeader := true;
|
||||||
|
end else
|
||||||
|
if ((NoCaseTag = '<BR>') or (pos('<BR ', NoCaseTag) = 1)) and FInCell then
|
||||||
|
FCellText := FCellText + LineEnding
|
||||||
|
else
|
||||||
|
case NoCaseTag of
|
||||||
|
'</TABLE>':
|
||||||
|
if FInTable then FInTable := false;
|
||||||
|
'</TD>', '</TH>':
|
||||||
|
if FInCell then
|
||||||
|
begin
|
||||||
|
ProcessCellValue(FCurrRow, FCurrCol, FCellText);
|
||||||
|
FInCell := false;
|
||||||
|
end;
|
||||||
|
'</A>':
|
||||||
|
if FInCell then FInA := false;
|
||||||
|
'</SPAN>':
|
||||||
|
if FInCell then FInSpan := false;
|
||||||
|
'<H1/>', '<H2/>', '<H3/>', '<H4/>', '<H5/>', '<H6/>':
|
||||||
|
if FinCell then FInHeader := false;
|
||||||
|
'<TR/>', '<TR />':
|
||||||
|
if FInTable then inc(FCurrRow);
|
||||||
|
'<TD/>', '<TD />':
|
||||||
|
if FInCell then inc(FCurrCol);
|
||||||
|
'<TH/>', '<TH />':
|
||||||
|
if FInCell then inc(FCurrCol);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsHTMLReader.TextFoundHandler(AText: String);
|
||||||
|
begin
|
||||||
|
if FInCell then
|
||||||
|
begin
|
||||||
|
AText := CleanHTMLString(AText);
|
||||||
|
if AText <> '' then
|
||||||
|
begin
|
||||||
|
if FCellText = '' then
|
||||||
|
FCellText := AText
|
||||||
|
else
|
||||||
|
FCellText := FCellText + ' ' + AText;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{==============================================================================}
|
||||||
|
{ TsHTMLWriter }
|
||||||
|
{==============================================================================}
|
||||||
constructor TsHTMLWriter.Create(AWorkbook: TsWorkbook);
|
constructor TsHTMLWriter.Create(AWorkbook: TsWorkbook);
|
||||||
begin
|
begin
|
||||||
inherited Create(AWorkbook);
|
inherited Create(AWorkbook);
|
||||||
@@ -493,7 +998,7 @@ begin
|
|||||||
Unused(AStream);
|
Unused(AStream);
|
||||||
Unused(ARow, ACol, ACell);
|
Unused(ARow, ACol, ACell);
|
||||||
AppendToStream(AStream,
|
AppendToStream(AStream,
|
||||||
'<div>' + IfThen(AValue, HTMLParams.TrueText, HTMLParams.FalseText) + '</div>');
|
'<div>' + StrUtils.IfThen(AValue, HTMLParams.TrueText, HTMLParams.FalseText) + '</div>');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Write date/time values in the same way they are displayed in the sheet }
|
{ Write date/time values in the same way they are displayed in the sheet }
|
||||||
@@ -502,6 +1007,7 @@ procedure TsHTMLWriter.WriteDateTime(AStream: TStream; const ARow, ACol: Cardina
|
|||||||
var
|
var
|
||||||
s: String;
|
s: String;
|
||||||
begin
|
begin
|
||||||
|
Unused(AValue);
|
||||||
s := FWorksheet.ReadAsUTF8Text(ACell);
|
s := FWorksheet.ReadAsUTF8Text(ACell);
|
||||||
AppendToStream(AStream,
|
AppendToStream(AStream,
|
||||||
'<div>' + s + '</div>');
|
'<div>' + s + '</div>');
|
||||||
@@ -512,6 +1018,7 @@ procedure TsHTMLWriter.WriteError(AStream: TStream;
|
|||||||
var
|
var
|
||||||
s: String;
|
s: String;
|
||||||
begin
|
begin
|
||||||
|
Unused(AValue);
|
||||||
s := FWOrksheet.ReadAsUTF8Text(ACell);
|
s := FWOrksheet.ReadAsUTF8Text(ACell);
|
||||||
AppendToStream(AStream,
|
AppendToStream(AStream,
|
||||||
'<div>' + s + '</div>');
|
'<div>' + s + '</div>');
|
||||||
@@ -663,7 +1170,7 @@ procedure TsHTMLWriter.WriteNumber(AStream: TStream; const ARow, ACol: Cardinal;
|
|||||||
var
|
var
|
||||||
s: String;
|
s: String;
|
||||||
begin
|
begin
|
||||||
Unused(ARow, ACol);
|
Unused(ARow, ACol, AValue);
|
||||||
s := FWorksheet.ReadAsUTF8Text(ACell, FWorkbook.FormatSettings);
|
s := FWorksheet.ReadAsUTF8Text(ACell, FWorkbook.FormatSettings);
|
||||||
AppendToStream(AStream,
|
AppendToStream(AStream,
|
||||||
'<div>' + s + '</div>');
|
'<div>' + s + '</div>');
|
||||||
@@ -873,7 +1380,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
RegisterSpreadFormat(nil, TsHTMLWriter, sfHTML);
|
InitFormatSettings(HTMLParams.FormatSettings);
|
||||||
|
RegisterSpreadFormat(TsHTMLReader, TsHTMLWriter, sfHTML);
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
400
components/fpspreadsheet/fpshtmlutils.pas
Normal file
400
components/fpspreadsheet/fpshtmlutils.pas
Normal file
@@ -0,0 +1,400 @@
|
|||||||
|
unit fpsHTMLUtils;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils;
|
||||||
|
|
||||||
|
type
|
||||||
|
THTMLEntity = record
|
||||||
|
E: String;
|
||||||
|
Ch: String;
|
||||||
|
N: Word;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function IsHTMLEntity(AText: PChar; out AEntity: THTMLEntity): Boolean;
|
||||||
|
function CleanHTMLString(AText: String): String;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
Strings;
|
||||||
|
|
||||||
|
const
|
||||||
|
// http://unicode.e-workers.de/entities.php
|
||||||
|
HTMLEntities: array[0..250] of THTMLEntity = (
|
||||||
|
// A
|
||||||
|
(E: 'Acirc'; Ch: 'Â'; N: 194), // 0
|
||||||
|
(E: 'acirc'; Ch: 'â'; N: 226),
|
||||||
|
(E: 'acute'; Ch: '´'; N: 180),
|
||||||
|
(E: 'AElig'; Ch: 'Æ'; N: 198),
|
||||||
|
(E: 'aelig'; Ch: 'æ'; N: 230),
|
||||||
|
(E: 'Agrave'; Ch: 'À'; N: 192),
|
||||||
|
(E: 'agrave'; Ch: 'à'; N: 224),
|
||||||
|
(E: 'alefsym';Ch: 'ℵ'; N: 8501),
|
||||||
|
(E: 'Alpha'; Ch: 'Α'; N: 913),
|
||||||
|
(E: 'alpha'; Ch: 'α'; N: 945),
|
||||||
|
(E: 'amp'; Ch: '&'; N: 38), // 10
|
||||||
|
(E: 'and'; Ch: '∧'; N: 8743),
|
||||||
|
(E: 'ang'; Ch: '∠'; N: 8736),
|
||||||
|
(E: 'apos'; Ch: ''''; N: 39),
|
||||||
|
(E: 'Aring'; Ch: 'Å'; N: 197),
|
||||||
|
(E: 'aring'; Ch: 'å'; N: 229),
|
||||||
|
(E: 'asymp'; Ch: '≈'; N: 2248),
|
||||||
|
(E: 'Atilde'; Ch: 'Ã'; N: 195),
|
||||||
|
(E: 'atilde'; Ch: 'ã'; N: 227),
|
||||||
|
(E: 'Auml'; Ch: 'Ä'; N: 196),
|
||||||
|
(E: 'auml'; Ch: 'ä'; N: 228), // 20
|
||||||
|
// B
|
||||||
|
(E: 'bdquo'; Ch: '„'; N: 8222), // 21
|
||||||
|
(E: 'Beta'; Ch: 'Β'; N: 914),
|
||||||
|
(E: 'beta'; Ch: 'β'; N: 946),
|
||||||
|
(E: 'brvbar'; Ch: '¦'; N: 166),
|
||||||
|
(E: 'bull'; Ch: '•'; N: 8226),
|
||||||
|
// C
|
||||||
|
(E: 'cap'; Ch: '∩'; N: 8745), // 26
|
||||||
|
(E: 'Ccedil'; Ch: 'Ç'; N: 199),
|
||||||
|
(E: 'ccedil'; Ch: 'ç'; N: 231),
|
||||||
|
(E: 'cedil'; Ch: '¸'; N: 184),
|
||||||
|
(E: 'cent'; Ch: '¢'; N: 162), // 30
|
||||||
|
(E: 'Chi'; Ch: 'Χ'; N: 935),
|
||||||
|
(E: 'chi'; Ch: 'χ'; N: 967),
|
||||||
|
(E: 'circ'; Ch: 'ˆ'; N: 710),
|
||||||
|
(E: 'clubs'; Ch: '♣'; N: 9827),
|
||||||
|
(E: 'cong'; Ch: '≅'; N: 8773), // approximately equal
|
||||||
|
(E: 'copy'; Ch: '©'; N: 169),
|
||||||
|
(E: 'crarr'; Ch: '↵'; N: 8629), // carriage return
|
||||||
|
(E: 'cup'; Ch: '∪'; N: 8746),
|
||||||
|
(E: 'curren'; Ch: '¤'; N: 164),
|
||||||
|
// D
|
||||||
|
(E: 'Dagger'; Ch: '‡'; N: 8225), // 40
|
||||||
|
(E: 'dagger'; Ch: '†'; N: 8224),
|
||||||
|
(E: 'dArr'; Ch: '⇓'; N: 8659), // wide down-arrow
|
||||||
|
(E: 'darr'; Ch: '↓'; N: 8595), // narrow down-arrow
|
||||||
|
(E: 'deg'; Ch: '°'; N: 176),
|
||||||
|
(E: 'Delta'; Ch: 'Δ'; N: 916),
|
||||||
|
(E: 'delta'; Ch: 'δ'; N: 948),
|
||||||
|
(E: 'diams'; Ch: '♦'; N: 9830),
|
||||||
|
(E: 'divide'; Ch: '÷'; N: 247),
|
||||||
|
// E
|
||||||
|
(E: 'Eacute'; Ch: 'É'; N: 201), // 49
|
||||||
|
(E: 'eacute'; Ch: 'é'; N: 233), // 50
|
||||||
|
(E: 'Ecirc'; Ch: 'Ê'; N: 202),
|
||||||
|
(E: 'ecirc'; Ch: 'ê'; N: 234),
|
||||||
|
(E: 'Egrave'; Ch: 'È'; N: 200),
|
||||||
|
(E: 'egrave'; Ch: 'è'; N: 232),
|
||||||
|
(E: 'empty'; Ch: '∅'; N: 8709),
|
||||||
|
(E: 'emsp'; Ch: ' '; N: 8195), // Space character width of "m"
|
||||||
|
(E: 'ensp'; Ch: ' '; N: 8194), // Space character width of "n"
|
||||||
|
(E: 'Epsilon';Ch: 'Ε'; N: 917), // capital epsilon
|
||||||
|
(E: 'epsilon';Ch: 'ε'; N: 949),
|
||||||
|
(E: 'equiv'; Ch: '≡'; N: 8801), // 60
|
||||||
|
(E: 'Eta'; Ch: 'Η'; N: 919),
|
||||||
|
(E: 'eta'; Ch: 'η'; N: 951),
|
||||||
|
(E: 'ETH'; Ch: 'Ð'; N: 208),
|
||||||
|
(E: 'eth'; Ch: 'ð'; N: 240),
|
||||||
|
(E: 'Euml'; Ch: 'Ë'; N: 203),
|
||||||
|
(E: 'euml'; Ch: 'ë'; N: 235),
|
||||||
|
(E: 'euro'; Ch: '€'; N: 8364),
|
||||||
|
(E: 'exist'; Ch: '∃'; N: 8707),
|
||||||
|
// F
|
||||||
|
(E: 'fnof'; Ch: 'ƒ'; N: 402), // 70
|
||||||
|
(E: 'forall'; Ch: '∀'; N: 8704),
|
||||||
|
(E: 'frac12'; Ch: '½'; N: 189),
|
||||||
|
(E: 'frac14'; Ch: '¼'; N: 188),
|
||||||
|
(E: 'frac34'; Ch: '¾'; N: 190),
|
||||||
|
(E: 'frasl'; Ch: '⁄'; N: 8260),
|
||||||
|
// G
|
||||||
|
(E: 'Gamma'; Ch: 'Γ'; N: 915),
|
||||||
|
(E: 'gamma'; Ch: 'γ'; N: 947),
|
||||||
|
(E: 'ge'; Ch: '≥'; N: 8805),
|
||||||
|
(E: 'gt'; Ch: '>'; N: 62),
|
||||||
|
// H
|
||||||
|
(E: 'hArr'; Ch: '⇔'; N: 8660), // 80, wide horizontal double arrow
|
||||||
|
(E: 'harr'; Ch: '↔'; N: 8596), // narrow horizontal double arrow
|
||||||
|
(E: 'hearts'; Ch: '♥'; N: 9829),
|
||||||
|
(E: 'hellip'; Ch: '…'; N: 8230),
|
||||||
|
// I
|
||||||
|
(E: 'Iacute'; Ch: 'Í'; N: 205),
|
||||||
|
(E: 'iacute'; Ch: 'í'; N: 237),
|
||||||
|
(E: 'Icirc'; Ch: 'Î'; N: 206),
|
||||||
|
(E: 'icirc'; Ch: 'î'; N: 238),
|
||||||
|
(E: 'iexcl'; Ch: '¡'; N: 161),
|
||||||
|
(E: 'Igrave'; Ch: 'Ì'; N: 204),
|
||||||
|
(E: 'igrave'; Ch: 'ì'; N: 236), // 90
|
||||||
|
(E: 'image'; Ch: 'ℑ'; N: 2465), // I in factura
|
||||||
|
(E: 'infin'; Ch: '∞'; N: 8734),
|
||||||
|
(E: 'int'; Ch: '∫'; N: 8747),
|
||||||
|
(E: 'Iota'; Ch: 'Ι'; N: 921),
|
||||||
|
(E: 'iota'; Ch: 'ι'; N: 953),
|
||||||
|
(E: 'iquest'; Ch: '¿'; N: 191),
|
||||||
|
(E: 'isin'; Ch: '∈'; N: 8712),
|
||||||
|
(E: 'Iuml'; Ch: 'Ï'; N: 207),
|
||||||
|
(E: 'iuml'; Ch: 'ï'; N: 239),
|
||||||
|
// K
|
||||||
|
(E: 'Kappa'; Ch: 'Κ'; N: 922), // 100
|
||||||
|
(E: 'kappa'; Ch: 'κ'; N: 254),
|
||||||
|
// L
|
||||||
|
(E: 'Lambda'; Ch: 'Λ'; N: 923),
|
||||||
|
(E: 'lambda'; Ch: 'λ'; N: 955),
|
||||||
|
(E: 'lang'; Ch: '⟨'; N: 9001), // Left-pointing angle bracket
|
||||||
|
(E: 'laquo'; Ch: '«'; N: 171),
|
||||||
|
(E: 'lArr'; Ch: '⇐'; N: 8656), // Left-pointing wide arrow
|
||||||
|
(E: 'larr'; Ch: '←'; N: 8592),
|
||||||
|
(E: 'lceil'; Ch: '⌈'; N: 8968), // Left ceiling
|
||||||
|
(E: 'ldquo'; Ch: '“'; N: 8220),
|
||||||
|
(E: 'le'; Ch: '≤'; N: 8804), // 110
|
||||||
|
(E: 'lfloor'; Ch: '⌊'; N: 8970), // Left floor
|
||||||
|
(E: 'lowast'; Ch: '∗'; N: 8727), // Low asterisk
|
||||||
|
(E: 'loz'; Ch: '◊'; N: 9674),
|
||||||
|
(E: 'lrm'; Ch: ''; N: 8206), // Left-to-right mark
|
||||||
|
(E: 'lsaquo'; Ch: '‹'; N: 8249),
|
||||||
|
(E: 'lsquo'; Ch: '‘'; N: 8216),
|
||||||
|
(E: 'lt'; Ch: '<'; N: 60),
|
||||||
|
// M
|
||||||
|
(E: 'macr'; Ch: '¯'; N: 175),
|
||||||
|
(E: 'mdash'; Ch: '—'; N: 8212),
|
||||||
|
(E: 'micro'; Ch: 'µ'; N: 181), // 120
|
||||||
|
(E: 'middot'; Ch: '·'; N: 183),
|
||||||
|
(E: 'minus'; Ch: '−'; N: 8722),
|
||||||
|
(E: 'Mu'; Ch: 'Μ'; N: 924),
|
||||||
|
(E: 'mu'; Ch: 'μ'; N: 956),
|
||||||
|
// N
|
||||||
|
(E: 'nabla'; Ch: '∇'; N: 8711),
|
||||||
|
(E: 'nbsp'; Ch: ' '; N: 160), // 126
|
||||||
|
(E: 'ndash'; Ch: '–'; N: 8211),
|
||||||
|
(E: 'ne'; Ch: '≠'; N: 8800),
|
||||||
|
(E: 'ni'; Ch: '∋'; N: 8715),
|
||||||
|
(E: 'not'; Ch: '¬'; N: 172), // 130
|
||||||
|
(E: 'notin'; Ch: '∉'; N: 8713), // math: "not in"
|
||||||
|
(E: 'nsub'; Ch: '⊄'; N: 8836), // math: "not a subset of"
|
||||||
|
(E: 'Ntilde'; Ch: 'Ñ'; N: 209),
|
||||||
|
(E: 'ntilde'; Ch: 'ñ'; N: 241),
|
||||||
|
(E: 'Nu'; Ch: 'Ν'; N: 925),
|
||||||
|
(E: 'nu'; Ch: 'ν'; N: 957),
|
||||||
|
// O
|
||||||
|
(E: 'Oacute'; Ch: 'Ó'; N: 211),
|
||||||
|
(E: 'oacute'; Ch: 'ó'; N: 243),
|
||||||
|
(E: 'Ocirc'; Ch: 'Ô'; N: 212),
|
||||||
|
(E: 'ocirc'; Ch: 'ô'; N: 244),
|
||||||
|
(E: 'OElig'; Ch: 'Œ'; N: 338),
|
||||||
|
(E: 'oelig'; Ch: 'œ'; N: 339),
|
||||||
|
(E: 'Ograve'; Ch: 'Ò'; N: 210),
|
||||||
|
(E: 'ograve'; Ch: 'ò'; N: 242),
|
||||||
|
(E: 'oline'; Ch: '‾'; N: 8254),
|
||||||
|
(E: 'Omega'; Ch: 'Ω'; N: 937),
|
||||||
|
(E: 'omega'; Ch: 'ω'; N: 969),
|
||||||
|
(E: 'Omicron';Ch: 'Ο'; N: 927),
|
||||||
|
(E: 'omicron';Ch: 'ο'; N: 959),
|
||||||
|
(E: 'oplus'; Ch: '⊕'; N: 8853), // Circled plus
|
||||||
|
(E: 'or'; Ch: '∨'; N: 8744),
|
||||||
|
(E: 'ordf'; Ch: 'ª'; N: 170),
|
||||||
|
(E: 'ordm'; Ch: 'º'; N: 186),
|
||||||
|
(E: 'Oslash'; Ch: 'Ø'; N: 216),
|
||||||
|
(E: 'oslash'; Ch: 'ø'; N: 248),
|
||||||
|
(E: 'Otilde'; Ch: 'Õ'; N: 213),
|
||||||
|
(E: 'otilde'; Ch: 'õ'; N: 245),
|
||||||
|
(E: 'otimes'; Ch: '⊗'; N: 8855), // Circled times
|
||||||
|
(E: 'Ouml'; Ch: 'Ö'; N: 214),
|
||||||
|
(E: 'ouml'; Ch: 'ö'; N: 246),
|
||||||
|
// P
|
||||||
|
(E: 'para'; Ch: '¶'; N: 182),
|
||||||
|
(E: 'part'; Ch: '∂'; N: 8706),
|
||||||
|
(E: 'permil'; Ch: '‰'; N: 8240),
|
||||||
|
(E: 'perp'; Ch: '⊥'; N: 8869),
|
||||||
|
(E: 'Phi'; Ch: 'Φ'; N: 934),
|
||||||
|
(E: 'phi'; Ch: 'φ'; N: 966),
|
||||||
|
(E: 'Pi'; Ch: 'Π'; N: 928),
|
||||||
|
(E: 'pi'; Ch: 'π'; N: 960), // lower-case pi
|
||||||
|
(E: 'piv'; Ch: 'ϖ'; N: 982),
|
||||||
|
(E: 'plusmn'; Ch: '±'; N: 177),
|
||||||
|
(E: 'pound'; Ch: '£'; N: 163),
|
||||||
|
(E: 'Prime'; Ch: '″'; N: 8243),
|
||||||
|
(E: 'prime'; Ch: '′'; N: 8242),
|
||||||
|
(E: 'prod'; Ch: '∏'; N: 8719),
|
||||||
|
(E: 'prop'; Ch: '∝'; N: 8733),
|
||||||
|
(E: 'Psi'; Ch: 'Ψ'; N: 936),
|
||||||
|
(E: 'psi'; Ch: 'ψ'; N: 968),
|
||||||
|
// Q
|
||||||
|
(E: 'quot'; Ch: '"'; N: 34),
|
||||||
|
// R
|
||||||
|
(E: 'radic'; Ch: '√'; N: 8730),
|
||||||
|
(E: 'rang'; Ch: '⟩'; N: 9002), // right-pointing angle bracket
|
||||||
|
(E: 'raquo'; Ch: '»'; N: 187),
|
||||||
|
(E: 'rArr'; Ch: '⇒'; N: 8658),
|
||||||
|
(E: 'rarr'; Ch: '→'; N: 8594),
|
||||||
|
(E: 'rceil'; Ch: '⌉'; N: 8969), // right ceiling
|
||||||
|
(E: 'rdquo'; Ch: '”'; N: 8221),
|
||||||
|
(E: 'real'; Ch: 'ℜ'; N: 8476), // R in factura
|
||||||
|
(E: 'reg'; Ch: '®'; N: 174),
|
||||||
|
(E: 'rfloor'; Ch: '⌋'; N: 8971), // Right floor
|
||||||
|
(E: 'Rho'; Ch: 'Ρ'; N: 929),
|
||||||
|
(E: 'rho'; Ch: 'ρ'; N: 961),
|
||||||
|
(E: 'rlm'; Ch: ''; N: 8207), // right-to-left mark
|
||||||
|
(E: 'rsaquo'; Ch: '›'; N: 8250),
|
||||||
|
(E: 'rsquo'; Ch: '’'; N: 8217),
|
||||||
|
|
||||||
|
// S
|
||||||
|
(E: 'sbquo'; Ch: '‚'; N: 8218),
|
||||||
|
(E: 'Scaron'; Ch: 'Š'; N: 352),
|
||||||
|
(E: 'scaron'; Ch: 'š'; N: 353),
|
||||||
|
(E: 'sdot'; Ch: '⋅'; N: 8901), // math: dot operator
|
||||||
|
(E: 'sect'; Ch: '§'; N: 167),
|
||||||
|
(E: 'shy'; Ch: ''; N: 173), // conditional hyphen
|
||||||
|
(E: 'Sigma'; Ch: 'Σ'; N: 931),
|
||||||
|
(E: 'sigma'; Ch: 'σ'; N: 963),
|
||||||
|
(E: 'sigmaf'; Ch: 'ς'; N: 962),
|
||||||
|
(E: 'sim'; Ch: '∼'; N: 8764), // similar
|
||||||
|
(E: 'spades'; Ch: '♠'; N: 9824),
|
||||||
|
(E: 'sub'; Ch: '⊂'; N: 8834),
|
||||||
|
(E: 'sube'; Ch: '⊆'; N: 8838),
|
||||||
|
(E: 'sum'; Ch: '∑'; N: 8721),
|
||||||
|
(E: 'sup'; Ch: '⊃'; N: 8835),
|
||||||
|
(E: 'sup1'; Ch: '¹'; N: 185),
|
||||||
|
(E: 'sup2'; Ch: '²'; N: 178),
|
||||||
|
(E: 'sup3'; Ch: '³'; N: 179),
|
||||||
|
(E: 'supe'; Ch: '⊇'; N: 8839),
|
||||||
|
(E: 'szlig'; Ch: 'ß'; N: 223),
|
||||||
|
//T
|
||||||
|
(E: 'Tau'; Ch: 'Τ'; N: 932),
|
||||||
|
(E: 'tau'; Ch: 'τ'; N: 964),
|
||||||
|
(E: 'there4'; Ch: '∴'; N: 8756),
|
||||||
|
(E: 'Theta'; Ch: 'Θ'; N: 920),
|
||||||
|
(E: 'theta'; Ch: 'θ'; N: 952),
|
||||||
|
(E: 'thetasym';Ch: 'ϑ'; N: 977),
|
||||||
|
(E: 'thinsp'; Ch: ' '; N: 8201), // thin space
|
||||||
|
(E: 'THORN'; Ch: 'Þ'; N: 222),
|
||||||
|
(E: 'thorn'; Ch: 'þ'; N: 254),
|
||||||
|
(E: 'tilde'; Ch: '˜'; N: 732),
|
||||||
|
(E: 'times'; Ch: '×'; N: 215),
|
||||||
|
(E: 'trade'; Ch: '™'; N: 8482),
|
||||||
|
// U
|
||||||
|
(E: 'Uacute'; Ch: 'Ú'; N: 218),
|
||||||
|
(E: 'uacute'; Ch: 'ú'; N: 250),
|
||||||
|
(E: 'uArr'; Ch: '⇑'; N: 8657), // wide up-arrow
|
||||||
|
(E: 'uarr'; Ch: '↑'; N: 8593),
|
||||||
|
(E: 'Ucirc'; Ch: 'Û'; N: 219),
|
||||||
|
(E: 'ucirc'; Ch: 'û'; N: 251),
|
||||||
|
(E: 'Ugrave'; Ch: 'Ù'; N: 217),
|
||||||
|
(E: 'ugrave'; Ch: 'ù'; N: 249),
|
||||||
|
(E: 'uml'; Ch: '¨'; N: 168),
|
||||||
|
(E: 'upsih'; Ch: 'ϒ'; N: 978),
|
||||||
|
(E: 'Upsilon';Ch: 'Υ'; N: 933),
|
||||||
|
(E: 'upsilon';Ch: 'υ'; N: 965),
|
||||||
|
(E: 'Uuml'; Ch: 'Ü'; N: 220),
|
||||||
|
(E: 'uuml'; Ch: 'ü'; N: 252),
|
||||||
|
// W
|
||||||
|
(E: 'weierp'; Ch: '℘'; N: 8472), // Script Capital P; Weierstrass Elliptic Function
|
||||||
|
// X
|
||||||
|
(E: 'Xi'; Ch: 'Ξ'; N: 926),
|
||||||
|
(E: 'xi'; Ch: 'ξ'; N: 958),
|
||||||
|
// Y
|
||||||
|
(E: 'Yacute'; Ch: 'Ý'; N: 221),
|
||||||
|
(E: 'yacute'; Ch: 'ý'; N: 253),
|
||||||
|
(E: 'yen'; Ch: '¥'; N: 165),
|
||||||
|
(E: 'Yuml'; Ch: 'Ÿ'; N: 376),
|
||||||
|
(E: 'yuml'; Ch: 'ÿ'; N: 255),
|
||||||
|
// Z
|
||||||
|
(E: 'Zeta'; Ch: 'Ζ'; N: 918),
|
||||||
|
(E: 'zeta'; Ch: 'ζ'; N: 950),
|
||||||
|
(E: 'zwj'; Ch: ''; N: 8205), // Zero-width joiner
|
||||||
|
(E: 'zwnj'; Ch: ''; N: 8204) // Zero-width non-joiner
|
||||||
|
);
|
||||||
|
|
||||||
|
function IsHTMLEntity(AText: PChar; out AEntity: THTMLEntity): Boolean;
|
||||||
|
|
||||||
|
function Compare(s: String): Boolean;
|
||||||
|
var
|
||||||
|
j: Integer;
|
||||||
|
begin
|
||||||
|
Result := false;
|
||||||
|
for j:=1 to Length(s) do
|
||||||
|
if s[j] <> PChar(AText)[j-1] then
|
||||||
|
exit;
|
||||||
|
if PChar(AText)[Length(s)] <> ';' then
|
||||||
|
exit;
|
||||||
|
Result := true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
j, k: Integer;
|
||||||
|
equ: Boolean;
|
||||||
|
ch1, ch2: Char;
|
||||||
|
P: PChar;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result := false;
|
||||||
|
for k:=0 to High(HTMLEntities) do
|
||||||
|
begin
|
||||||
|
equ := Compare(HTMLEntities[k].E);
|
||||||
|
if not equ then
|
||||||
|
begin
|
||||||
|
P := AText;
|
||||||
|
ch1 := P^;
|
||||||
|
if ch1 = '#' then
|
||||||
|
begin
|
||||||
|
inc(P);
|
||||||
|
ch2 := P^;
|
||||||
|
if ch1 = 'x' then
|
||||||
|
equ := Compare(Format('#x%x', [HTMLEntities[k].N]))
|
||||||
|
else
|
||||||
|
equ := Compare(Format('#%d', [HTMLEntities[k].N]));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if equ then
|
||||||
|
begin
|
||||||
|
AEntity := HTMLEntities[k];
|
||||||
|
Result := true;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CleanHTMLString(AText: String): String;
|
||||||
|
var
|
||||||
|
len: Integer;
|
||||||
|
ent: THTMLEntity;
|
||||||
|
P: PChar;
|
||||||
|
ch: Char;
|
||||||
|
begin
|
||||||
|
Result := '';
|
||||||
|
|
||||||
|
// Remove leading and trailing spaces and line endings coming from formatted
|
||||||
|
// source lines
|
||||||
|
while (Length(AText) > 0) and (AText[1] in [#9, #10, #13, ' ']) do
|
||||||
|
Delete(AText, 1,1);
|
||||||
|
while (Length(AText) > 0) and (AText[Length(AText)] in [#9, #10, #13, ' ']) do
|
||||||
|
Delete(AText, Length(AText), 1);
|
||||||
|
if AText = '' then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
// Replace HTML entities by their counter part UTF8 characters
|
||||||
|
len := Length(AText);
|
||||||
|
P := @AText[1];
|
||||||
|
while (P^ <> #0) do begin
|
||||||
|
ch := P^;
|
||||||
|
case ch of
|
||||||
|
'&': begin
|
||||||
|
inc(P);
|
||||||
|
if (P <> nil) and IsHTMLEntity(P, ent) then
|
||||||
|
begin
|
||||||
|
Result := Result + ent.Ch;
|
||||||
|
inc(P, Length(ent.E));
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
Result := Result + '&';
|
||||||
|
Continue;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
else Result := Result + ch;
|
||||||
|
end;
|
||||||
|
inc(P);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
@@ -212,6 +212,9 @@ function ConvertFloatToStr(AValue: Double; AParams: TsNumFormatParams;
|
|||||||
AFormatSettings: TFormatSettings): String;
|
AFormatSettings: TFormatSettings): String;
|
||||||
function CountDecs(AFormatString: String; ADecChars: TsDecsChars = ['0']): Byte;
|
function CountDecs(AFormatString: String; ADecChars: TsDecsChars = ['0']): Byte;
|
||||||
|
|
||||||
|
function IsBoolValue(const AText, ATrueText, AFalseText: String;
|
||||||
|
out AValue: Boolean): Boolean;
|
||||||
|
|
||||||
function IsCurrencyFormat(AFormat: TsNumberFormat): Boolean; overload;
|
function IsCurrencyFormat(AFormat: TsNumberFormat): Boolean; overload;
|
||||||
function IsCurrencyFormat(ANumFormat: TsNumFormatParams): Boolean; overload;
|
function IsCurrencyFormat(ANumFormat: TsNumFormatParams): Boolean; overload;
|
||||||
|
|
||||||
@@ -219,6 +222,9 @@ function IsDateTimeFormat(AFormat: TsNumberFormat): Boolean; overload;
|
|||||||
function IsDateTimeFormat(AFormatStr: String): Boolean; overload;
|
function IsDateTimeFormat(AFormatStr: String): Boolean; overload;
|
||||||
function IsDateTimeFormat(ANumFormat: TsNumFormatParams): Boolean; overload;
|
function IsDateTimeFormat(ANumFormat: TsNumFormatParams): Boolean; overload;
|
||||||
|
|
||||||
|
function IsDateTimeValue(AText: String; const AFormatSettings: TFormatSettings;
|
||||||
|
out ADateTime: TDateTime; out ANumFormat: TsNumberFormat): Boolean;
|
||||||
|
|
||||||
function IsDateFormat(ANumFormat: TsNumFormatParams): Boolean;
|
function IsDateFormat(ANumFormat: TsNumFormatParams): Boolean;
|
||||||
|
|
||||||
function IsTimeFormat(AFormat: TsNumberFormat): Boolean; overload;
|
function IsTimeFormat(AFormat: TsNumberFormat): Boolean; overload;
|
||||||
@@ -226,6 +232,11 @@ function IsTimeFormat(AFormatStr: String): Boolean; overload;
|
|||||||
function IsTimeFormat(ANumFormat: TsNumFormatParams): Boolean; overload;
|
function IsTimeFormat(ANumFormat: TsNumFormatParams): Boolean; overload;
|
||||||
function IsLongTimeFormat(AFormatStr: String; ATimeSeparator: char): Boolean; overload;
|
function IsLongTimeFormat(AFormatStr: String; ATimeSeparator: char): Boolean; overload;
|
||||||
|
|
||||||
|
function IsNumberValue(AText: String; AutoDetectNumberFormat: Boolean;
|
||||||
|
const AFormatSettings: TFormatSettings; out ANumber: Double;
|
||||||
|
out ANumFormat: TsNumberFormat; out ADecimals: Integer;
|
||||||
|
out ACurrencySymbol, AWarning: String): Boolean;
|
||||||
|
|
||||||
function IsTimeIntervalFormat(ANumFormat: TsNumFormatParams): Boolean;
|
function IsTimeIntervalFormat(ANumFormat: TsNumFormatParams): Boolean;
|
||||||
|
|
||||||
function MakeLongDateFormat(ADateFormat: String): String;
|
function MakeLongDateFormat(ADateFormat: String): String;
|
||||||
@@ -233,12 +244,15 @@ function MakeShortDateFormat(ADateFormat: String): String;
|
|||||||
procedure MakeTimeIntervalMask(Src: String; var Dest: String);
|
procedure MakeTimeIntervalMask(Src: String; var Dest: String);
|
||||||
function StripAMPM(const ATimeFormatString: String): String;
|
function StripAMPM(const ATimeFormatString: String): String;
|
||||||
|
|
||||||
|
procedure InitFormatSettings(out AFormatSettings: TFormatSettings);
|
||||||
|
procedure ReplaceFormatSettings(var AFormatSettings: TFormatSettings;
|
||||||
|
const ADefaultFormats: TFormatSettings);
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
StrUtils, Math,
|
StrUtils, Math,
|
||||||
fpsUtils, fpsNumFormatParser;
|
fpsUtils, fpsNumFormatParser, fpsCurrency;
|
||||||
|
|
||||||
const
|
const
|
||||||
{@@ Array of format strings identifying the order of number and
|
{@@ Array of format strings identifying the order of number and
|
||||||
@@ -1408,6 +1422,26 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Checks whether the specified text corresponds to a boolean value. For this,
|
||||||
|
it must match the specified TRUE and FALSE text phrases.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function IsBoolValue(const AText, ATrueText, AFalseText: String;
|
||||||
|
out AValue: Boolean): Boolean;
|
||||||
|
begin
|
||||||
|
if SameText(AText, ATrueText) then
|
||||||
|
begin
|
||||||
|
AValue := true;
|
||||||
|
Result := true;
|
||||||
|
end else
|
||||||
|
if SameText(AText, AFalseText) then
|
||||||
|
begin
|
||||||
|
AValue := false;
|
||||||
|
Result := true;
|
||||||
|
end else
|
||||||
|
Result := false;
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Checks whether the given number format code is for currency,
|
Checks whether the given number format code is for currency,
|
||||||
i.e. requires a currency symbol.
|
i.e. requires a currency symbol.
|
||||||
@@ -1479,6 +1513,55 @@ begin
|
|||||||
(ANumFormat.Sections[0].Kind * [nfkDate, nfkTime] <> []);
|
(ANumFormat.Sections[0].Kind * [nfkDate, nfkTime] <> []);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Checks whether the specified text corresponds to a date/time value and returns
|
||||||
|
true, its numerical value and its built-in numberformat if it is.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function IsDateTimeValue(AText: String; const AFormatSettings: TFormatSettings;
|
||||||
|
out ADateTime: TDateTime; out ANumFormat: TsNumberFormat): Boolean;
|
||||||
|
|
||||||
|
{ Test whether the text is formatted according to a built-in date/time format.
|
||||||
|
Converts the obtained date/time value back to a string and compares. }
|
||||||
|
function TestFormat(lNumFmt: TsNumberFormat): Boolean;
|
||||||
|
var
|
||||||
|
fmt: string;
|
||||||
|
begin
|
||||||
|
fmt := BuildDateTimeFormatString(lNumFmt, AFormatSettings);
|
||||||
|
Result := FormatDateTime(fmt, ADateTime, AFormatSettings) = AText;
|
||||||
|
if Result then ANumFormat := lNumFmt;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result := TryStrToDateTime(AText, ADateTime, AFormatSettings);
|
||||||
|
if Result then
|
||||||
|
begin
|
||||||
|
ANumFormat := nfCustom;
|
||||||
|
if abs(ADateTime) > 1 then // this is most probably a date
|
||||||
|
begin
|
||||||
|
if TestFormat(nfShortDateTime) then
|
||||||
|
exit;
|
||||||
|
if TestFormat(nfLongDate) then
|
||||||
|
exit;
|
||||||
|
if TestFormat(nfShortDate) then
|
||||||
|
exit;
|
||||||
|
if TestFormat(nfMonthYear) then
|
||||||
|
exit;
|
||||||
|
if TestFormat(nfDayMonth) then
|
||||||
|
exit;
|
||||||
|
end else
|
||||||
|
begin // this case is time-only
|
||||||
|
if TestFormat(nfLongTimeAM) then
|
||||||
|
exit;
|
||||||
|
if TestFormat(nfLongTime) then
|
||||||
|
exit;
|
||||||
|
if TestFormat(nfShortTimeAM) then
|
||||||
|
exit;
|
||||||
|
if TestFormat(nfShortTime) then
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Checks whether the specified number format parameters apply to a date value.
|
Checks whether the specified number format parameters apply to a date value.
|
||||||
|
|
||||||
@@ -1549,6 +1632,102 @@ begin
|
|||||||
Result := (n=2);
|
Result := (n=2);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Checks whether the specified text corresponds to a numerical value. If it is
|
||||||
|
then the function result is TRUE, and the number value and its formatting
|
||||||
|
parameters are returned.
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
function IsNumberValue(AText: String; AutoDetectNumberFormat: Boolean;
|
||||||
|
const AFormatSettings: TFormatSettings;
|
||||||
|
out ANumber: Double; out ANumFormat: TsNumberFormat; out ADecimals: Integer;
|
||||||
|
out ACurrencySymbol, AWarning: String): Boolean;
|
||||||
|
var
|
||||||
|
p: Integer;
|
||||||
|
DecSep, ThousSep: Char;
|
||||||
|
begin
|
||||||
|
Result := false;
|
||||||
|
AWarning := '';
|
||||||
|
|
||||||
|
// To detect whether the text is a currency value we look for the currency
|
||||||
|
// string. If we find it, we delete it and convert the remaining string to
|
||||||
|
// a number.
|
||||||
|
ACurrencySymbol := AFormatSettings.CurrencyString;
|
||||||
|
if RemoveCurrencySymbol(ACurrencySymbol, AText) then
|
||||||
|
begin
|
||||||
|
if IsNegative(AText) then
|
||||||
|
begin
|
||||||
|
if AText = '' then
|
||||||
|
exit;
|
||||||
|
AText := '-' + AText;
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
ACurrencySymbol := '';
|
||||||
|
|
||||||
|
if AutoDetectNumberFormat then
|
||||||
|
Result := TryStrToFloatAuto(AText, ANumber, DecSep, ThousSep, AWarning)
|
||||||
|
else begin
|
||||||
|
Result := TryStrToFloat(AText, ANumber, AFormatSettings);
|
||||||
|
if Result then
|
||||||
|
begin
|
||||||
|
if pos(AFormatSettings.DecimalSeparator, AText) = 0
|
||||||
|
then DecSep := #0
|
||||||
|
else DecSep := AFormatSettings.DecimalSeparator;
|
||||||
|
if pos(AFormatSettings.ThousandSeparator, AText) = 0
|
||||||
|
then ThousSep := #0
|
||||||
|
else ThousSep := AFormatSettings.ThousandSeparator;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Try to determine the number format
|
||||||
|
if Result then
|
||||||
|
begin
|
||||||
|
if ThousSep <> #0 then
|
||||||
|
ANumFormat := nfFixedTh
|
||||||
|
else
|
||||||
|
ANumFormat := nfGeneral;
|
||||||
|
// count number of decimal places and try to catch special formats
|
||||||
|
ADecimals := 0;
|
||||||
|
if DecSep <> #0 then
|
||||||
|
begin
|
||||||
|
// Go to the decimal separator and search towards the end of the string
|
||||||
|
p := pos(DecSep, AText) + 1;
|
||||||
|
while (p <= Length(AText)) do begin
|
||||||
|
// exponential format
|
||||||
|
if AText[p] in ['+', '-', 'E', 'e'] then
|
||||||
|
begin
|
||||||
|
ANumFormat := nfExp;
|
||||||
|
break;
|
||||||
|
end else
|
||||||
|
// percent format
|
||||||
|
if AText[p] = '%' then
|
||||||
|
begin
|
||||||
|
ANumFormat := nfPercentage;
|
||||||
|
break;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
inc(p);
|
||||||
|
inc(ADecimals);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if (ADecimals > 0) and (ADecimals < 9) and (ANumFormat = nfGeneral) then
|
||||||
|
// "no formatting" assumed if there are "many" decimals
|
||||||
|
ANumFormat := nfFixed;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
p := Length(AText);
|
||||||
|
while (p > 0) do begin
|
||||||
|
case AText[p] of
|
||||||
|
'%' : ANumFormat := nfPercentage;
|
||||||
|
'e', 'E': ANumFormat := nfExp;
|
||||||
|
else dec(p);
|
||||||
|
end;
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
ACurrencySymbol := '';
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Checks whether the specified number format parameters is a time interval
|
Checks whether the specified number format parameters is a time interval
|
||||||
format.
|
format.
|
||||||
@@ -1684,6 +1863,99 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Initializes the FormatSettings of file a import/export parameters record to
|
||||||
|
default values which can be replaced by the FormatSettings of the
|
||||||
|
workbook's FormatSettings
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure InitFormatSettings(out AFormatSettings: TFormatSettings);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
with AFormatSettings do
|
||||||
|
begin
|
||||||
|
CurrencyFormat := Byte(-1);
|
||||||
|
NegCurrFormat := Byte(-1);
|
||||||
|
ThousandSeparator := #0;
|
||||||
|
DecimalSeparator := #0;
|
||||||
|
CurrencyDecimals := Byte(-1);
|
||||||
|
DateSeparator := #0;
|
||||||
|
TimeSeparator := #0;
|
||||||
|
ListSeparator := #0;
|
||||||
|
CurrencyString := '';
|
||||||
|
ShortDateFormat := '';
|
||||||
|
LongDateFormat := '';
|
||||||
|
TimeAMString := '';
|
||||||
|
TimePMString := '';
|
||||||
|
ShortTimeFormat := '';
|
||||||
|
LongTimeFormat := '';
|
||||||
|
for i:=1 to 12 do
|
||||||
|
begin
|
||||||
|
ShortMonthNames[i] := '';
|
||||||
|
LongMonthNames[i] := '';
|
||||||
|
end;
|
||||||
|
for i:=1 to 7 do
|
||||||
|
begin
|
||||||
|
ShortDayNames[i] := '';
|
||||||
|
LongDayNames[i] := '';
|
||||||
|
end;
|
||||||
|
TwoDigitYearCenturyWindow := Word(-1);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Replaces in AFormatSettings all members marked as having default values (#0,
|
||||||
|
-1, '') by the corresponding values of the ADefaultFormats record
|
||||||
|
-------------------------------------------------------------------------------}
|
||||||
|
procedure ReplaceFormatSettings(var AFormatSettings: TFormatSettings;
|
||||||
|
const ADefaultFormats: TFormatSettings);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
if AFormatSettings.CurrencyFormat = Byte(-1) then
|
||||||
|
AFormatSettings.CurrencyFormat := ADefaultFormats.CurrencyFormat;
|
||||||
|
if AFormatSettings.NegCurrFormat = Byte(-1) then
|
||||||
|
AFormatSettings.NegCurrFormat := ADefaultFormats.NegCurrFormat;
|
||||||
|
if AFormatSettings.ThousandSeparator = #0 then
|
||||||
|
AFormatSettings.ThousandSeparator := ADefaultFormats.ThousandSeparator;
|
||||||
|
if AFormatSettings.DecimalSeparator = #0 then
|
||||||
|
AFormatSettings.DecimalSeparator := ADefaultFormats.DecimalSeparator;
|
||||||
|
if AFormatSettings.CurrencyDecimals = Byte(-1) then
|
||||||
|
AFormatSettings.CurrencyDecimals := ADefaultFormats.CurrencyDecimals;
|
||||||
|
if AFormatSettings.DateSeparator = #0 then
|
||||||
|
AFormatSettings.DateSeparator := ADefaultFormats.DateSeparator;
|
||||||
|
if AFormatSettings.TimeSeparator = #0 then
|
||||||
|
AFormatSettings.TimeSeparator := ADefaultFormats.TimeSeparator;
|
||||||
|
if AFormatSettings.ListSeparator = #0 then
|
||||||
|
AFormatSettings.ListSeparator := ADefaultFormats.ListSeparator;
|
||||||
|
if AFormatSettings.CurrencyString = '' then
|
||||||
|
AFormatSettings.CurrencyString := ADefaultFormats.CurrencyString;
|
||||||
|
if AFormatSettings.ShortDateFormat = '' then
|
||||||
|
AFormatSettings.ShortDateFormat := ADefaultFormats.ShortDateFormat;
|
||||||
|
if AFormatSettings.LongDateFormat = '' then
|
||||||
|
AFormatSettings.LongDateFormat := ADefaultFormats.LongDateFormat;
|
||||||
|
if AFormatSettings.ShortTimeFormat = '' then
|
||||||
|
AFormatSettings.ShortTimeFormat := ADefaultFormats.ShortTimeFormat;
|
||||||
|
if AFormatSettings.LongTimeFormat = '' then
|
||||||
|
AFormatSettings.LongTimeFormat := ADefaultFormats.LongTimeFormat;
|
||||||
|
for i:=1 to 12 do
|
||||||
|
begin
|
||||||
|
if AFormatSettings.ShortMonthNames[i] = '' then
|
||||||
|
AFormatSettings.ShortMonthNames[i] := ADefaultFormats.ShortMonthNames[i];
|
||||||
|
if AFormatSettings.LongMonthNames[i] = '' then
|
||||||
|
AFormatSettings.LongMonthNames[i] := ADefaultFormats.LongMonthNames[i];
|
||||||
|
end;
|
||||||
|
for i:=1 to 7 do
|
||||||
|
begin
|
||||||
|
if AFormatSettings.ShortDayNames[i] = '' then
|
||||||
|
AFormatSettings.ShortDayNames[i] := ADefaultFormats.ShortDayNames[i];
|
||||||
|
if AFormatSettings.LongDayNames[i] = '' then
|
||||||
|
AFormatSettings.LongDayNames[i] := ADefaultFormats.LongDayNames[i];
|
||||||
|
end;
|
||||||
|
if AFormatSettings.TwoDigitYearCenturyWindow = Word(-1) then
|
||||||
|
AFormatSettings.TwoDigitYearCenturyWindow := ADefaultFormats.TwoDigitYearCenturyWindow;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{==============================================================================}
|
{==============================================================================}
|
||||||
{ TsNumFormatParams }
|
{ TsNumFormatParams }
|
||||||
|
@@ -1253,7 +1253,6 @@ end;
|
|||||||
procedure TsNumFormatParser.ScanFormat;
|
procedure TsNumFormatParser.ScanFormat;
|
||||||
var
|
var
|
||||||
done: Boolean;
|
done: Boolean;
|
||||||
s: String;
|
|
||||||
n: Integer;
|
n: Integer;
|
||||||
uch: Cardinal;
|
uch: Cardinal;
|
||||||
begin
|
begin
|
||||||
|
@@ -29,7 +29,7 @@
|
|||||||
This package is all you need if you don't want graphical components (like grids and charts)."/>
|
This package is all you need if you don't want graphical components (like grids and charts)."/>
|
||||||
<License Value="LGPL with static linking exception. This is the same license as is used in the LCL (Lazarus Component Library)."/>
|
<License Value="LGPL with static linking exception. This is the same license as is used in the LCL (Lazarus Component Library)."/>
|
||||||
<Version Major="1" Minor="7"/>
|
<Version Major="1" Minor="7"/>
|
||||||
<Files Count="36">
|
<Files Count="37">
|
||||||
<Item1>
|
<Item1>
|
||||||
<Filename Value="fpolestorage.pas"/>
|
<Filename Value="fpolestorage.pas"/>
|
||||||
<UnitName Value="fpolestorage"/>
|
<UnitName Value="fpolestorage"/>
|
||||||
@@ -174,6 +174,10 @@ This package is all you need if you don't want graphical components (like grids
|
|||||||
<Filename Value="fpshtml.pas"/>
|
<Filename Value="fpshtml.pas"/>
|
||||||
<UnitName Value="fpsHTML"/>
|
<UnitName Value="fpsHTML"/>
|
||||||
</Item36>
|
</Item36>
|
||||||
|
<Item37>
|
||||||
|
<Filename Value="fpshtmlutils.pas"/>
|
||||||
|
<UnitName Value="fpshtmlutils"/>
|
||||||
|
</Item37>
|
||||||
</Files>
|
</Files>
|
||||||
<RequiredPkgs Count="2">
|
<RequiredPkgs Count="2">
|
||||||
<Item1>
|
<Item1>
|
||||||
|
@@ -13,7 +13,8 @@ uses
|
|||||||
uvirtuallayer_ole_helpers, uvirtuallayer_ole_types, uvirtuallayer_stream,
|
uvirtuallayer_ole_helpers, uvirtuallayer_ole_types, uvirtuallayer_stream,
|
||||||
fpolebasic, wikitable, fpsNumFormatParser, fpsfunc, fpsRPN, fpsStrings,
|
fpolebasic, wikitable, fpsNumFormatParser, fpsfunc, fpsRPN, fpsStrings,
|
||||||
fpscsv, fpsCsvDocument, fpspatches, fpsTypes, xlsEscher, fpsReaderWriter,
|
fpscsv, fpsCsvDocument, fpspatches, fpsTypes, xlsEscher, fpsReaderWriter,
|
||||||
fpsNumFormat, fpsclasses, fpsHeaderFooterParser, fpsPalette, fpsHTML;
|
fpsNumFormat, fpsclasses, fpsHeaderFooterParser, fpsPalette, fpsHTML,
|
||||||
|
fpshtmlutils;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
@@ -155,6 +155,9 @@
|
|||||||
<OtherUnitFiles Value=".."/>
|
<OtherUnitFiles Value=".."/>
|
||||||
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
|
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
|
||||||
</SearchPaths>
|
</SearchPaths>
|
||||||
|
<Other>
|
||||||
|
<CustomOptions Value="-d-MDelphi"/>
|
||||||
|
</Other>
|
||||||
</CompilerOptions>
|
</CompilerOptions>
|
||||||
<Debugging>
|
<Debugging>
|
||||||
<Exceptions Count="6">
|
<Exceptions Count="6">
|
||||||
|
@@ -519,7 +519,7 @@ end;
|
|||||||
procedure TsSpreadBIFF5Reader.ReadRSTRING(AStream: TStream);
|
procedure TsSpreadBIFF5Reader.ReadRSTRING(AStream: TStream);
|
||||||
var
|
var
|
||||||
L: Word;
|
L: Word;
|
||||||
B, F: Byte;
|
B: Byte;
|
||||||
ARow, ACol: Cardinal;
|
ARow, ACol: Cardinal;
|
||||||
XF: Word;
|
XF: Word;
|
||||||
ansistr: ansistring;
|
ansistr: ansistring;
|
||||||
@@ -629,7 +629,7 @@ procedure TsSpreadBIFF5Reader.ReadXF(AStream: TStream);
|
|||||||
var
|
var
|
||||||
rec: TBIFF5_XFRecord;
|
rec: TBIFF5_XFRecord;
|
||||||
fmt: TsCellFormat;
|
fmt: TsCellFormat;
|
||||||
i, cidx: Integer;
|
cidx: Integer;
|
||||||
nfparams: TsNumFormatParams;
|
nfparams: TsNumFormatParams;
|
||||||
nfs: String;
|
nfs: String;
|
||||||
b: Byte;
|
b: Byte;
|
||||||
|
@@ -557,31 +557,14 @@ function TsSpreadBIFF8Reader.ReadUnformattedWideString(const AStream: TStream;
|
|||||||
var
|
var
|
||||||
flags: Byte;
|
flags: Byte;
|
||||||
DecomprStrValue: WideString;
|
DecomprStrValue: WideString;
|
||||||
AnsiStrValue: ansistring;
|
|
||||||
//RunsCounter: Word;
|
|
||||||
//AsianPhoneticBytes: DWord;
|
|
||||||
i: Integer;
|
i: Integer;
|
||||||
j: SizeUInt;
|
|
||||||
len: SizeInt;
|
len: SizeInt;
|
||||||
recType: Word;
|
recType: Word;
|
||||||
recSize: Word;
|
{%H-}recSize: Word;
|
||||||
C: WideChar;
|
C: WideChar;
|
||||||
begin
|
begin
|
||||||
flags := AStream.ReadByte;
|
flags := AStream.ReadByte;
|
||||||
dec(PendingRecordSize);
|
dec(PendingRecordSize);
|
||||||
{
|
|
||||||
if StringFlags and 4 = 4 then begin
|
|
||||||
//Asian phonetics
|
|
||||||
//Read Asian phonetics Length (not used)
|
|
||||||
AsianPhoneticBytes := DWordLEtoN(AStream.ReadDWord);
|
|
||||||
dec(PendingRecordSize,4);
|
|
||||||
end;
|
|
||||||
if StringFlags and 8 = 8 then begin
|
|
||||||
//Rich string
|
|
||||||
RunsCounter := WordLEtoN(AStream.ReadWord);
|
|
||||||
dec(PendingRecordSize,2);
|
|
||||||
end;
|
|
||||||
}
|
|
||||||
if flags and 1 = 1 Then begin
|
if flags and 1 = 1 Then begin
|
||||||
//String is WideStringLE
|
//String is WideStringLE
|
||||||
if (ALength * SizeOf(WideChar)) > PendingRecordSize then begin
|
if (ALength * SizeOf(WideChar)) > PendingRecordSize then begin
|
||||||
@@ -619,34 +602,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
Result := DecomprStrValue;
|
Result := DecomprStrValue;
|
||||||
end;
|
end;
|
||||||
{
|
|
||||||
if StringFlags and 8 = 8 then begin
|
|
||||||
// Rich string (This only occurs in BIFF8)
|
|
||||||
SetLength(ARichTextRuns, RunsCounter);
|
|
||||||
for j := 0 to RunsCounter - 1 do begin
|
|
||||||
if (PendingRecordSize <= 0) then begin
|
|
||||||
// A CONTINUE may happened here
|
|
||||||
RecordType := WordLEToN(AStream.ReadWord);
|
|
||||||
RecordSize := WordLEToN(AStream.ReadWord);
|
|
||||||
if RecordType <> INT_EXCEL_ID_CONTINUE then begin
|
|
||||||
Raise Exception.Create('[TsSpreadBIFF8Reader.ReadWideString] Expected CONTINUE record not found.');
|
|
||||||
end else begin
|
|
||||||
PendingRecordSize := RecordSize;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
ARichTextRuns[j].FirstIndex := WordLEToN(AStream.ReadWord);
|
|
||||||
ARichTextRuns[j].FontIndex := WordLEToN(AStream.ReadWord);
|
|
||||||
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);
|
|
||||||
dec(PendingRecordSize, AsianPhoneticBytes);
|
|
||||||
end;
|
|
||||||
}
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TsSpreadBIFF8Reader.ReadWideString(const AStream: TStream;
|
function TsSpreadBIFF8Reader.ReadWideString(const AStream: TStream;
|
||||||
@@ -1369,7 +1324,7 @@ var
|
|||||||
cell: PCell;
|
cell: PCell;
|
||||||
ms: TMemoryStream;
|
ms: TMemoryStream;
|
||||||
rtfRuns: TsRichTextFormattingRuns;
|
rtfRuns: TsRichTextFormattingRuns;
|
||||||
j, n: Integer;
|
n: Integer;
|
||||||
begin
|
begin
|
||||||
rec.Row := 0; // to silence the compiler...
|
rec.Row := 0; // to silence the compiler...
|
||||||
|
|
||||||
@@ -1450,16 +1405,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsSpreadBIFF8Reader.ReadXF(const AStream: TStream);
|
procedure TsSpreadBIFF8Reader.ReadXF(const AStream: TStream);
|
||||||
(*
|
|
||||||
function FixLineStyle(dw: DWord): TsLineStyle;
|
|
||||||
{ Not all line styles defined in BIFF8 are supported by fpspreadsheet. }
|
|
||||||
begin
|
|
||||||
case dw of
|
|
||||||
$01..$07: result := TsLineStyle(dw-1);
|
|
||||||
else Result := lsDashed;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
*)
|
|
||||||
var
|
var
|
||||||
rec: TBIFF8_XFRecord;
|
rec: TBIFF8_XFRecord;
|
||||||
fmt: TsCellFormat;
|
fmt: TsCellFormat;
|
||||||
@@ -1469,9 +1414,7 @@ var
|
|||||||
fs: TsFillStyle;
|
fs: TsFillStyle;
|
||||||
nfs: String;
|
nfs: String;
|
||||||
nfParams: TsNumFormatParams;
|
nfParams: TsNumFormatParams;
|
||||||
i: Integer;
|
|
||||||
iclr: Integer;
|
iclr: Integer;
|
||||||
fnt: TsFont;
|
|
||||||
begin
|
begin
|
||||||
InitFormatRecord(fmt);
|
InitFormatRecord(fmt);
|
||||||
fmt.ID := FCellFormatList.Count;
|
fmt.ID := FCellFormatList.Count;
|
||||||
|
@@ -325,6 +325,7 @@ type
|
|||||||
// Adjusts Excel float (date, date/time, time) with the file's base date to get a TDateTime
|
// Adjusts Excel float (date, date/time, time) with the file's base date to get a TDateTime
|
||||||
function ConvertExcelDateTimeToDateTime
|
function ConvertExcelDateTimeToDateTime
|
||||||
(const AExcelDateNum: Double; ADateMode: TDateMode): TDateTime;
|
(const AExcelDateNum: Double; ADateMode: TDateMode): TDateTime;
|
||||||
|
|
||||||
// Adjusts TDateTime with the file's base date to get
|
// Adjusts TDateTime with the file's base date to get
|
||||||
// an Excel float value representing a time/date/datetime
|
// an Excel float value representing a time/date/datetime
|
||||||
function ConvertDateTimeToExcelDateTime
|
function ConvertDateTimeToExcelDateTime
|
||||||
@@ -332,6 +333,7 @@ type
|
|||||||
|
|
||||||
// Converts the error byte read from cells or formulas to fps error value
|
// Converts the error byte read from cells or formulas to fps error value
|
||||||
function ConvertFromExcelError(AValue: Byte): TsErrorValue;
|
function ConvertFromExcelError(AValue: Byte): TsErrorValue;
|
||||||
|
|
||||||
// Converts an fps error value to the byte code needed in xls files
|
// Converts an fps error value to the byte code needed in xls files
|
||||||
function ConvertToExcelError(AValue: TsErrorValue): byte;
|
function ConvertToExcelError(AValue: TsErrorValue): byte;
|
||||||
|
|
||||||
@@ -665,6 +667,16 @@ begin
|
|||||||
case ADateMode of
|
case ADateMode of
|
||||||
dm1900:
|
dm1900:
|
||||||
begin
|
begin
|
||||||
|
{
|
||||||
|
Result := AExcelDateNum + DATEMODE_1900_BASE - 1.0;
|
||||||
|
// Excel and Lotus 1-2-3 incorrectly assume that 1900 was a leap year
|
||||||
|
// Therefore all dates before March 01 are off by 1.
|
||||||
|
// The old fps implementation corrected only Feb 29, but all days are
|
||||||
|
// wrong!
|
||||||
|
if AExcelDateNum < 61 then
|
||||||
|
Result := Result + 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for Lotus 1-2-3 bug with 1900 leap year
|
// Check for Lotus 1-2-3 bug with 1900 leap year
|
||||||
if AExcelDateNum=61.0 then
|
if AExcelDateNum=61.0 then
|
||||||
// 29 feb does not exist, change to 28
|
// 29 feb does not exist, change to 28
|
||||||
@@ -693,9 +705,12 @@ begin
|
|||||||
begin
|
begin
|
||||||
case ADateMode of
|
case ADateMode of
|
||||||
dm1900:
|
dm1900:
|
||||||
result:=ADateTime-DATEMODE_1900_BASE+1.0;
|
begin
|
||||||
|
Result := ADateTime - DATEMODE_1900_BASE + 1.0;
|
||||||
|
// if Result < 61 then Result := Result - 1.0;
|
||||||
|
end;
|
||||||
dm1904:
|
dm1904:
|
||||||
result:=ADateTime-DATEMODE_1904_BASE;
|
Result := ADateTime - DATEMODE_1904_BASE;
|
||||||
else
|
else
|
||||||
raise Exception.CreateFmt('ConvertDateTimeToExcelDateTime: unknown datemode %d. Please correct fpspreadsheet source code. ', [ADateMode]);
|
raise Exception.CreateFmt('ConvertDateTimeToExcelDateTime: unknown datemode %d. Please correct fpspreadsheet source code. ', [ADateMode]);
|
||||||
end;
|
end;
|
||||||
@@ -2271,11 +2286,13 @@ end;
|
|||||||
procedure TsSpreadBIFFReader.ReadWorkbookGlobals(AStream: TStream);
|
procedure TsSpreadBIFFReader.ReadWorkbookGlobals(AStream: TStream);
|
||||||
begin
|
begin
|
||||||
// To be overridden by BIFF5 and BIFF8
|
// To be overridden by BIFF5 and BIFF8
|
||||||
|
Unused(AStream);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsSpreadBIFFReader.ReadWorksheet(AStream: TStream);
|
procedure TsSpreadBIFFReader.ReadWorksheet(AStream: TStream);
|
||||||
begin
|
begin
|
||||||
// To be overridden by BIFF5 and BIFF8
|
// To be overridden by BIFF5 and BIFF8
|
||||||
|
Unused(AStream);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
|
Reference in New Issue
Block a user