* PChar -> PansiChar

This commit is contained in:
Michaël Van Canneyt 2023-01-17 17:15:03 +01:00
parent eb009243aa
commit fdd26e6fca

View File

@ -52,17 +52,21 @@ Type
TCSVHandler = class(TPersistent) TCSVHandler = class(TPersistent)
private private
function GetDelimiter: TCSVChar;
function GetLineEnding: String;
function GetQuoteChar: TCSVChar;
procedure SetDelimiter(const AValue: TCSVChar); procedure SetDelimiter(const AValue: TCSVChar);
procedure SetLineEnding(AValue: String);
procedure SetQuoteChar(const AValue: TCSVChar); procedure SetQuoteChar(const AValue: TCSVChar);
procedure UpdateCachedChars; procedure UpdateCachedChars;
protected protected
// special chars // special chars
FDelimiter: TCSVChar; FDelimiter: AnsiChar;
FQuoteChar: TCSVChar; FQuoteChar: AnsiChar;
FLineEnding: String; FLineEnding: AnsiString;
// cached values to speed up special chars operations // cached values to speed up special chars operations
FSpecialChars: TSysCharSet; FSpecialChars: TSysCharSet;
FDoubleQuote: String; FDoubleQuote: AnsiString;
// parser settings // parser settings
FIgnoreOuterWhitespace: Boolean; FIgnoreOuterWhitespace: Boolean;
// builder settings // builder settings
@ -74,13 +78,13 @@ Type
procedure Assign(ASource: TPersistent); override; procedure Assign(ASource: TPersistent); override;
procedure AssignCSVProperties(ASource: TCSVHandler); procedure AssignCSVProperties(ASource: TCSVHandler);
// Delimiter that separates the field, e.g. comma, semicolon, tab // Delimiter that separates the field, e.g. comma, semicolon, tab
property Delimiter: TCSVChar read FDelimiter write SetDelimiter; property Delimiter: TCSVChar read GetDelimiter write SetDelimiter;
// Character used to quote "problematic" data // Character used to quote "problematic" data
// (e.g. with delimiters or spaces in them) // (e.g. with delimiters or spaces in them)
// A common quotechar is " // A common quotechar is "
property QuoteChar: TCSVChar read FQuoteChar write SetQuoteChar; property QuoteChar: TCSVChar read GetQuoteChar write SetQuoteChar;
// String at the end of the line of data (e.g. CRLF) // String at the end of the line of data (e.g. CRLF)
property LineEnding: String read FLineEnding write FLineEnding; property LineEnding: String read GetLineEnding write SetLineEnding;
// Ignore whitespace between delimiters and field data // Ignore whitespace between delimiters and field data
property IgnoreOuterWhitespace: Boolean read FIgnoreOuterWhitespace write FIgnoreOuterWhitespace; property IgnoreOuterWhitespace: Boolean read FIgnoreOuterWhitespace write FIgnoreOuterWhitespace;
// Use quotes when outer whitespace is found // Use quotes when outer whitespace is found
@ -106,14 +110,15 @@ Type
// parser state // parser state
EndOfFile: Boolean; EndOfFile: Boolean;
EndOfLine: Boolean; EndOfLine: Boolean;
FCurrentChar: TCSVChar; FCurrentChar: AnsiChar;
FCurrentRow: Integer; FCurrentRow: Integer;
FCurrentCol: Integer; FCurrentCol: Integer;
FMaxColCount: Integer; FMaxColCount: Integer;
// output buffers // output buffers
FCellBuffer: String; FCellBuffer: RawByteString;
FWhitespaceBuffer: String; FWhitespaceBuffer: RawByteString;
procedure ClearOutput; procedure ClearOutput;
function GetCurrentCell: String;
// basic parsing // basic parsing
procedure SkipEndOfLine; procedure SkipEndOfLine;
procedure SkipDelimiter; procedure SkipDelimiter;
@ -140,7 +145,7 @@ Type
// Current column (0 based); -1 if invalid/before beginning of file // Current column (0 based); -1 if invalid/before beginning of file
property CurrentCol: Integer read FCurrentCol; property CurrentCol: Integer read FCurrentCol;
// Data in current cell // Data in current cell
property CurrentCellText: String read FCellBuffer; property CurrentCellText: String read GetCurrentCell;
// The maximum number of columns found in the stream: // The maximum number of columns found in the stream:
property MaxColCount: Integer read FMaxColCount; property MaxColCount: Integer read FMaxColCount;
// Does the parser own the stream ? If true, a previous stream is freed when set or when parser is destroyed. // Does the parser own the stream ? If true, a previous stream is freed when set or when parser is destroyed.
@ -193,6 +198,28 @@ const
WhitespaceChars = [HTAB, SPACE]; WhitespaceChars = [HTAB, SPACE];
LineEndingChars = [CR, LF]; LineEndingChars = [CR, LF];
Procedure AppendStr(Var Dest : RawByteString; Src : RawByteString); inline;
begin
Dest:=Dest+Src;
end;
procedure RemoveTrailingChars(VAR S: RawByteString; const CSet: TSysCharset);
VAR I,J: LONGINT;
Begin
I:=Length(S);
IF (I>0) Then
Begin
J:=I;
While (j>0) and (S[J] IN CSet) DO DEC(J);
IF J<>I Then
SetLength(S,J);
End;
End;
// The following implementation of ChangeLineEndings function originates from // The following implementation of ChangeLineEndings function originates from
// Lazarus CodeTools library by Mattias Gaertner. It was explicitly allowed // Lazarus CodeTools library by Mattias Gaertner. It was explicitly allowed
// by Mattias to relicense it under modified LGPL and include into CsvDocument. // by Mattias to relicense it under modified LGPL and include into CsvDocument.
@ -261,6 +288,21 @@ end;
{ TCSVHandler } { TCSVHandler }
function TCSVHandler.GetDelimiter: TCSVChar;
begin
Result:=FDelimiter;
end;
function TCSVHandler.GetLineEnding: String;
begin
Result:=UTF8Decode(FLineEnding);
end;
function TCSVHandler.GetQuoteChar: TCSVChar;
begin
Result:=FQuoteChar;
end;
procedure TCSVHandler.SetDelimiter(const AValue: TCSVChar); procedure TCSVHandler.SetDelimiter(const AValue: TCSVChar);
begin begin
if FDelimiter <> AValue then if FDelimiter <> AValue then
@ -270,6 +312,11 @@ begin
end; end;
end; end;
procedure TCSVHandler.SetLineEnding(AValue: String);
begin
FLineEnding:=UTF8ENcode(AValue)
end;
procedure TCSVHandler.SetQuoteChar(const AValue: TCSVChar); procedure TCSVHandler.SetQuoteChar(const AValue: TCSVChar);
begin begin
if FQuoteChar <> AValue then if FQuoteChar <> AValue then
@ -327,6 +374,11 @@ begin
FMaxColCount := 0; FMaxColCount := 0;
end; end;
function TCSVParser.GetCurrentCell: String;
begin
Result:=FCellBuffer
end;
procedure TCSVParser.SkipEndOfLine; procedure TCSVParser.SkipEndOfLine;
begin begin
// treat LF+CR as two linebreaks, not one // treat LF+CR as two linebreaks, not one
@ -350,7 +402,7 @@ end;
procedure TCSVParser.NextChar; procedure TCSVParser.NextChar;
begin begin
if FSourceStream.Read(FCurrentChar, CsvCharSize) < CsvCharSize then if FSourceStream.Read(FCurrentChar, SizeOf(FCurrentChar)) < SizeOf(FCurrentChar) then
begin begin
FCurrentChar := #0; FCurrentChar := #0;
EndOfFile := True; EndOfFile := True;
@ -544,10 +596,13 @@ end;
procedure TCSVBuilder.AppendStringToStream(const AString: String; AStream: TStream); procedure TCSVBuilder.AppendStringToStream(const AString: String; AStream: TStream);
var var
StrLen: Integer; StrLen: Integer;
S : AnsiString;
begin begin
StrLen := Length(AString); S:=aString;
StrLen := Length(S);
if StrLen > 0 then if StrLen > 0 then
AStream.WriteBuffer(AString[1], StrLen); AStream.WriteBuffer(S[1], StrLen);
end; end;
function TCSVBuilder.QuoteCSVString(const AValue: String): String; function TCSVBuilder.QuoteCSVString(const AValue: String): String;
@ -622,7 +677,7 @@ var
CellValue: String; CellValue: String;
begin begin
if FNeedLeadingDelimiter then if FNeedLeadingDelimiter then
FOutputStream.WriteBuffer(FDelimiter, CsvCharSize); FOutputStream.WriteBuffer(FDelimiter, SizeOf(FDelimiter));
CellValue := ChangeLineEndings(AValue, FLineEnding); CellValue := ChangeLineEndings(AValue, FLineEnding);
CellValue := QuoteCSVString(CellValue); CellValue := QuoteCSVString(CellValue);