📄 idstream.pas
字号:
{ $HDR$}
{**********************************************************************}
{ Unit archived using Team Coherence }
{ Team Coherence is Copyright 2002 by Quality Software Components }
{ }
{ For further information / comments, visit our WEB site at }
{ http://www.TeamCoherence.com }
{**********************************************************************}
{}
{ $Log: 10351: IdStream.pas
{
{ Rev 1.0 2002.11.12 10:54:04 PM czhower
}
unit IdStream;
{
2002-04-10 -Andrew P.Rybin
-Read*, Write*, ReadLn optimization (for many strings use TIdReadLineStreamProxy)
2002-04-16 -Andrew P.Rybin
-TIdStreamSafe, TIdStreamLight, TIdReadLineStreamProxy, optimization, misc
}
{$I IdCompilerDefines.inc}
interface
uses
Classes,
IdException, IdGlobal;
type
EIdEndOfStream = class(EIdException);
TIdStream = class(TStream)
// IMPORTANT!!!!!!!!
// NO data members may exist in this class
// This class is used to "hackcast" a TStream to add functionality
public
function ReadLn(AMaxLineLength: Integer = -1; AExceptionIfEOF: Boolean = FALSE): String;
class function FindEOL(ABuf: PChar; var VLineBufSize: Integer; var VCrEncountered: Boolean): Integer;{Ret: StringSize}
procedure Write(const AData: string); reintroduce; overload;
procedure WriteLn(const AData: string = ''); overload; {Do not Localize}
procedure WriteLn(const AData: string; const AArgs: array of const); overload;
function This: TIdStream; // Result := SELF; "THIS Object"
function BOF: Boolean; {Begin of Stream}
function EOF: Boolean; {End of Stream}
procedure Skip(ASize: Integer);
function ReadInteger (const AConvert: Boolean = TRUE): Integer; //network order
procedure WriteInteger(AValue: Integer; const AConvert: Boolean = True);
function ReadString (const AConvert: Boolean = TRUE): String;
procedure WriteString(const AStr: String; const AConvert: Boolean = True);
End;//TIdStream
implementation
uses
IdResourceStrings,
IdStack,
IdTCPConnection,
IdTCPStream,
SysUtils;
const
LBUFMAXSIZE = 2048;
EOLArray = [CR,LF];
WCSize = SizeOf(WideChar);
{ TIdStream }
class function TIdStream.FindEOL(ABuf: PChar; var VLineBufSize: Integer; var VCrEncountered: Boolean): Integer;
var
i: Integer;
begin
Result := VLineBufSize; //EOL not found => use all
i := 0; //[0..ALineBufSize-1]
while i < VLineBufSize do begin
case ABuf[i] of
LF:
begin
Result := i; {string size}
VCrEncountered := TRUE;
VLineBufSize := i+1;
BREAK;
end;//LF
CR:
begin
Result := i; {string size}
VCrEncountered := TRUE;
inc(i); //crLF?
if (i < VLineBufSize) and (ABuf[i] = LF) then begin
VLineBufSize := i+1;
end
else begin
VLineBufSize := i;
end;
BREAK;
end;//CR
end;//case
Inc(i);
end;//while
End;//FindEOL
function TIdStream.ReadLn(AMaxLineLength: Integer = -1; AExceptionIfEOF: Boolean = FALSE): String;
//TODO: Continue to optimize this function. Its performance severely impacts
// the coders
var
LBufSize, LStringLen, LResultLen: Integer;
LBuf: packed array [0..LBUFMAXSIZE] of Char;
LStrmPos, LStrmSize: Integer; //LBytesToRead = stream size - Position
LCrEncountered: Boolean;
begin
// 'is' does not work here - compiler error
if InheritsFrom(TIdTCPStream) then begin
Result := TIdTCPStream(Self).Connection.ReadLn(LF,-1,AMaxLineLength);
end
else begin
if AMaxLineLength < 0 then begin
AMaxLineLength := MaxInt;
end;//if
LCrEncountered := FALSE;
Result := '';
{ we store the stream size for the whole routine to prevent
so do not incur a performance penalty with TStream.Size. It has
to use something such as Seek each time the size is obtained}
{LStrmPos := SrcStream.Position; LStrmSize:= SrcStream.Size; 4 seek vs 3 seek}
LStrmPos := Seek(0, soFromCurrent); //Position
LStrmSize:= Seek(0, soFromEnd); //Size
Seek(LStrmPos, soFromBeginning); //return position
if (LStrmSize - LStrmPos) > 0 then begin
while (LStrmPos < LStrmSize) and NOT LCrEncountered do begin
LBufSize := Min(LStrmSize - LStrmPos, LBUFMAXSIZE);
ReadBuffer(LBuf, LBufSize);
LStringLen := FindEOL(LBuf,LBufSize,LCrEncountered);
Inc(LStrmPos,LBufSize);
LResultLen := Length(Result);
if (LResultLen + LStringLen) > AMaxLineLength then begin
LStringLen := AMaxLineLength - LResultLen;
LCrEncountered := TRUE;
Dec(LStrmPos,LBufSize);
Inc(LStrmPos,LStringLen);
end;//if
SetLength(Result, LResultLen + LStringLen);
Move(LBuf[0], PChar(Result)[LResultLen], LStringLen);
end;//while
Position := LStrmPos;
end
else begin
if AExceptionIfEOF then begin
raise EIdEndOfStream.Create(Format('End of stream: %s at %d',[ClassName,LStrmPos])); //LOCALIZE
end;
end;//if NOT EOF
end;//if
End;//ReadLn
{function TIdStream.ReadLn: string;
//TODO: Continue to optimize this function. Its performance severely impacts
// the coders
var
i: Integer;
LBuf : String;
LBufSize, LBufPos : Integer;
LBytesToRead : Integer; //stream size - Position
LLn: Integer;
LStrmPos, LStrmSize : Integer;
LCrEncountered : Boolean;
begin
LCrEncountered := False;
// 'is' does not work here - compiler error
if InheritsFrom(TIdTCPStream) then begin
Result := TIdTCPStream(Self).Connection.ReadLn;
end else begin
Result := '';
LStrmPos := Position;
{ we store the stream size for the whole routine to prevent
so do not incur a performance penalty with TStream.Size. It has
to use something such as Seek each time the size is obtained
}
{ LStrmSize := Size;
LBytesToRead := LStrmSize - LStrmPos;
if LBytesToRead > 0 then begin
LBufPos := 0;
while (LStrmPos < LStrmSize) and (LCrEncountered = False) do
// while (LStrmPos <= LBytesToRead) and (LCrEncountered = False) do
begin
if LBufPos < LBytesToRead then
begin
LBufSize := Min(LBytesToRead - LBufPos,LBUFMAXSIZE);
SetLength(LBuf, LBufSize);
ReadBuffer(LBuf[1], LBufSize);
for i := 1 to LBufSize do
begin
case LBuf[i] of
CR : begin
lln := i;
LBufSize := i+1;
if (i < LBufSize) and (LBuf[LBufSize]<>LF) then
begin
Dec(LBufSize);
end;
LCrEncountered := True;
Break;
end;
LF : begin
lln := i;
LBufSize := i+1;
if (i < LBufSize) and (LBuf[LBufSize]<>CR) then
begin
Dec(LBufSize);
end;
LCrEncountered := True;
Break;
end;
end;
end;
if LCrEncountered then
begin
Dec(lln);
SetLength(LBuf,lln);
end;
Inc(LStrmPos,LBufSize);
Result := Result + LBuf;
end;
end;
Position := LStrmPos;
end;
end;
end; }
{nction TIdStream.ReadLn: string;
//TODO: Continue to optimize this function. Its performance severely impacts
// the coders
var
i: Integer;
LBuf : String;
LBufSize, LBufPos : Integer;
LBytesToRead : Integer; //stream size - Position
LLn: Integer;
LStrmPos, LStrmSize : Integer;
LCrEncountered : Boolean;
begin
LCrEncountered := False;
// 'is' does not work here - compiler error
if InheritsFrom(TIdTCPStream) then begin
Result := TIdTCPStream(Self).Connection.ReadLn;
end else begin
Result := '';
LStrmPos := Position;
{ we store the stream size for the whole routine to prevent
so do not incur a performance penalty with TStream.Size. It has
to use something such as Seek each time the size is obtained
}
{ LStrmSize := Size;
LBytesToRead := LStrmSize - LStrmPos;
if LBytesToRead > 0 then begin
LBufPos := 0;
while (LStrmPos < LStrmSize) and (LCrEncountered = False) do
// while (LStrmPos <= LBytesToRead) and (LCrEncountered = False) do
begin
if LBufPos < LBytesToRead then
begin
LBufSize := LBytesToRead - LBufPos;
if LBufSize > LBUFMAXSIZE then
begin
LBufSize := LBUFMAXSIZE;
end;
SetLength(LBuf, LBufSize);
ReadBuffer(LBuf[1], LBufSize);
lln := IndyPos(LF, LBuf);
i := IndyPos(CR, LBuf);
LCrEncountered := (lln > 0) or (i > 0);
if LCrEncountered then
begin
//we only want i and lln not to equal zero unless both are zero
//The reason is that some broken things might return just a CR or a LF
//instead of both
if lln = 0 then
begin
lln := i;
end;
if i = 0 then
begin
i := lln;
end;
//we do these two tests to make sure the CR and LF are together.
//if they are appart, we assume they are two different line endings.
if (lln > (i+1)) then
begin
lln := i;
end;
if (i > (lln+1)) then
begin
i := lln;
end;
LBufSize := IdGlobal.Max(lln,i);
end;
Inc(LStrmPos,LBufSize);
Result := Result + LBuf;
if LCrEncountered then
begin
SetLength(Result,Min(lln,i)-1);
end;
end;
end;
Position := LStrmPos;
end;
end;
end; }
procedure TIdStream.Write(const AData: string);
var
LDataLen: Integer;
begin
LDataLen := Length(AData);
if LDataLen > 0 then begin
WriteBuffer(Pointer(AData)^, LDataLen);
end;
end;
procedure TIdStream.WriteLn(const AData: string = ''); {Do not Localize}
begin
Write(AData + sLineBreak);
end;
procedure TIdStream.WriteLn(const AData: string; const AArgs: array of const);
Begin
WriteLn(Format(AData, AArgs));
End;//
function TIdStream.This: TIdStream;
Begin
Result := SELF;
End;//
function TIdStream.BOF: Boolean;
Begin
Result := Seek(0,soFromCurrent)<=0; //Stream.Position
End;
function TIdStream.EOF: Boolean;
var
LPos: Int64;
Begin
LPos := Seek(0,soFromCurrent);
Result := LPos>=Seek(0,soFromEnd);
Seek(LPos,soFromBeginning);
End;//EOF
procedure TIdStream.Skip(ASize: Integer);
Begin
Seek(ASize, soFromCurrent);
End;//Skip
function TIdStream.ReadInteger(const AConvert: Boolean): Integer;
begin
ReadBuffer(Result, SizeOf(Result));
if AConvert then begin
Result := Integer(GStack.WSNToHL(LongWord(Result)));
end;
end;
procedure TIdStream.WriteInteger(AValue: Integer; const AConvert: Boolean = True);
begin
if AConvert then begin
AValue := Integer(GStack.WSHToNL(LongWord(AValue)));
end;
WriteBuffer(AValue, SizeOf(AValue));
end;
function TIdStream.ReadString(const AConvert: Boolean = TRUE): String;
var
L: Integer;
Begin
L := ReadInteger(AConvert);
if L>0 then begin
SetString(Result, NIL, L);
ReadBuffer(Pointer(Result)^,L);
end
else begin
Result := '';
end;
End;//ReadString
procedure TIdStream.WriteString(const AStr: String; const AConvert: Boolean = True);
var
L: Integer;
Begin
L:= Length(AStr);
WriteInteger(L, AConvert);
if L>0 then begin
WriteBuffer(Pointer(AStr)^,L);
end;
End;//WriteS
END.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -