1 { Copyright (C) 2009 Bas Steendijk and Peter Green
\r
2 For conditions of distribution and use, see copyright notice in zlib_license.txt
\r
3 which is included in the package
\r
4 ----------------------------------------------------------------------------- }
\r
14 this can be used to read a text file exposed as a tstream line by line.
\r
15 automatic handling of CR, LF, and CRLF line endings, and readout of detected line ending type.
\r
16 fast: 1.5-2 times faster than textfile readln in tests.
\r
31 treadtxt=class(tobject)
\r
33 buf:array[0..bufsize-1] of byte;
\r
36 currenteol,preveol:integer;
\r
37 fileeof,reachedeof:boolean;
\r
38 fdetectedeol:integer;
\r
39 procedure checkandread;
\r
41 sourcestream:tstream;
\r
42 destroysourcestream:boolean;
\r
44 constructor create(asourcestream: tstream; adestroysourcestream:boolean);
\r
45 constructor createf(filename : string);
\r
47 function readline:ansistring;
\r
48 function eof:boolean;
\r
49 destructor destroy; override;
\r
50 property detectedeol : integer read fdetectedeol;
\r
55 constructor treadtxt.create(asourcestream: tstream; adestroysourcestream:boolean);
\r
58 sourcestream := asourcestream;
\r
59 destroysourcestream := adestroysourcestream;
\r
61 //if sourcestream.Position >= sourcestream.size then fileeof := true;
\r
62 bufpointer := bufsize;
\r
65 constructor treadtxt.createf(filename: string);
\r
67 create(tfilestream.create(filename,fmOpenRead or fmShareDenyWrite),true);
\r
71 procedure treadtxt.checkandread;
\r
73 if bufpointer >= numread then begin
\r
74 numread := sourcestream.read(buf,bufsize);
\r
76 if numread = 0 then fileeof := true;
\r
81 function treadtxt.readline;
\r
93 {core search loop begin}
\r
95 for a := bufpointer to b do begin
\r
97 //check if the character can possiblly be a line ending before getting
\r
98 //into the more complex checks that depend on eol type
\r
99 if (c = 10) or (c = 13) then case allowedeol of
\r
105 if (c = 13) then begin
\r
111 if (c = 10) then begin
\r
116 eoltype_crlf: begin
\r
117 if (c = 10) and (prevchar= 13) then begin
\r
125 raise exception.create('undefined eol type set');
\r
130 {core search loop end}
\r
132 c := length(result);
\r
133 if (d = -1) then begin
\r
134 {ran out of buffer before end of line}
\r
135 b := numread-bufpointer;
\r
136 setlength(result,c+b);
\r
137 move(buf[bufpointer],result[c+1],b);
\r
138 bufpointer := numread;
\r
139 if fileeof then begin
\r
140 {we reached the end of the file, return what we have}
\r
141 reachedeof := true;
\r
146 preveol := currenteol;
\r
147 currenteol := buf[d];
\r
149 {end of line before end of buffer}
\r
150 if (currenteol = 10) and (preveol = 13) and (bufpointer = d) then begin
\r
151 {it's the second EOL char of a DOS line ending, don't cause a line}
\r
153 fdetectedeol := eoltype_crlf;
\r
155 if fdetectedeol = eoltype_none then begin
\r
156 if (currenteol = 10) then fdetectedeol := eoltype_lf else fdetectedeol := eoltype_cr;
\r
159 if trimchar then begin
\r
160 setlength(result,c+b-1);
\r
161 move(buf[bufpointer],result[c+1],b-1);
\r
164 setlength(result,c+b);
\r
165 move(buf[bufpointer],result[c+1],b);
\r
170 if fileeof then begin
\r
171 if (bufpointer >= numread) then reachedeof := true;
\r
172 if (currenteol = 13) and (bufpointer = numread-1) then if (buf[bufpointer] = 10) then reachedeof := true;
\r
181 function treadtxt.eof:boolean;
\r
184 result := ((bufpointer >= numread) and fileeof) or reachedeof;
\r
187 destructor treadtxt.destroy;
\r
189 if destroysourcestream then if assigned(sourcestream) then sourcestream.destroy;
\r