|
@@ -92,12 +92,16 @@ Type
|
|
|
|
|
|
{ TCSVParser }
|
|
|
|
|
|
+ TCSVByteOrderMark = (bomNone, bomUTF8, bomUTF16LE, bomUTF16BE);
|
|
|
+
|
|
|
TCSVParser = class(TCSVHandler)
|
|
|
private
|
|
|
FFreeStream: Boolean;
|
|
|
// fields
|
|
|
FSourceStream: TStream;
|
|
|
FStrStreamWrapper: TStringStream;
|
|
|
+ FBOM: TCSVByteOrderMark;
|
|
|
+ FDetectBOM: Boolean;
|
|
|
// parser state
|
|
|
EndOfFile: Boolean;
|
|
|
EndOfLine: Boolean;
|
|
@@ -140,6 +144,10 @@ Type
|
|
|
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.
|
|
|
Property FreeStream : Boolean Read FFreeStream Write FFreeStream;
|
|
|
+ // Return BOM found in file
|
|
|
+ property BOM: TCSVByteOrderMark read FBOM;
|
|
|
+ // Detect whether a BOM marker is present. If set to True, then BOM can be used to see what BOM marker there was.
|
|
|
+ property DetectBOM: Boolean read FDetectBOM write FDetectBOM default false;
|
|
|
end;
|
|
|
|
|
|
// Sequential output to CSV stream
|
|
@@ -443,9 +451,32 @@ begin
|
|
|
end;
|
|
|
|
|
|
procedure TCSVParser.ResetParser;
|
|
|
+var
|
|
|
+ b: packed array[0..2] of byte;
|
|
|
+ n: Integer;
|
|
|
begin
|
|
|
ClearOutput;
|
|
|
FSourceStream.Seek(0, soFromBeginning);
|
|
|
+ if FDetectBOM then
|
|
|
+ begin
|
|
|
+ FSourceStream.ReadBuffer(b[0], 3);
|
|
|
+ if (b[0] = $EF) and (b[1] = $BB) and (b[2] = $BF) then begin
|
|
|
+ FBOM := bomUTF8;
|
|
|
+ n := 3;
|
|
|
+ end else
|
|
|
+ if (b[0] = $FE) and (b[1] = $FF) then begin
|
|
|
+ FBOM := bomUTF16BE;
|
|
|
+ n := 2;
|
|
|
+ end else
|
|
|
+ if (b[0] = $FF) and (b[1] = $FE) then begin
|
|
|
+ FBOM := bomUTF16LE;
|
|
|
+ n := 2;
|
|
|
+ end else begin
|
|
|
+ FBOM := bomNone;
|
|
|
+ n := 0;
|
|
|
+ end;
|
|
|
+ FSourceStream.Seek(n, soFromBeginning);
|
|
|
+ end;
|
|
|
EndOfFile := False;
|
|
|
NextChar;
|
|
|
end;
|