333 lines
9.7 KiB
Plaintext
333 lines
9.7 KiB
Plaintext
{
|
|
$Project$
|
|
$Workfile$
|
|
$Revision$
|
|
$DateUTC$
|
|
$Id$
|
|
|
|
This file is part of the Indy (Internet Direct) project, and is offered
|
|
under the dual-licensing agreement described on the Indy website.
|
|
(http://www.indyproject.org/)
|
|
|
|
Copyright:
|
|
(c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
|
|
}
|
|
{
|
|
$Log$
|
|
}
|
|
{
|
|
Rev 1.21 3/10/05 3:24:30 PM RLebeau
|
|
Updated ReadFromSource() and WriteDirect() to access the Intercept property
|
|
directly.
|
|
|
|
Rev 1.20 10/21/2004 11:07:30 PM BGooijen
|
|
works in win32 now too
|
|
|
|
Rev 1.19 10/21/2004 1:52:56 PM BGooijen
|
|
Raid 214235
|
|
|
|
Rev 1.18 7/23/04 6:20:52 PM RLebeau
|
|
Removed memory leaks in Send/ReceiveStream property setters
|
|
|
|
Rev 1.17 2004.05.20 11:39:08 AM czhower
|
|
IdStreamVCL
|
|
|
|
Rev 1.16 23/04/2004 20:29:36 CCostelloe
|
|
Minor change to support IdMessageClient's new TIdIOHandlerStreamMsg
|
|
|
|
Rev 1.15 2004.04.16 11:30:32 PM czhower
|
|
Size fix to IdBuffer, optimizations, and memory leaks
|
|
|
|
Rev 1.14 2004.04.08 3:56:36 PM czhower
|
|
Fixed bug with Intercept byte count. Also removed Bytes from Buffer.
|
|
|
|
Rev 1.13 2004.03.07 11:48:46 AM czhower
|
|
Flushbuffer fix + other minor ones found
|
|
|
|
Rev 1.12 2004.03.03 11:55:04 AM czhower
|
|
IdStream change
|
|
|
|
Rev 1.11 2004.02.03 4:17:16 PM czhower
|
|
For unit name changes.
|
|
|
|
Rev 1.10 11/01/2004 19:52:44 CCostelloe
|
|
Revisions for TIdMessage SaveToFile & LoadFromFile for D7 & D8
|
|
|
|
Rev 1.8 08/01/2004 23:37:16 CCostelloe
|
|
Minor changes
|
|
|
|
Rev 1.7 1/8/2004 1:01:22 PM BGooijen
|
|
Cleaned up
|
|
|
|
Rev 1.6 1/8/2004 4:23:06 AM BGooijen
|
|
temp fixed TIdIOHandlerStream.WriteToDestination
|
|
|
|
Rev 1.5 08/01/2004 00:25:22 CCostelloe
|
|
Start of reimplementing LoadFrom/SaveToFile
|
|
|
|
Rev 1.4 2003.12.31 7:44:54 PM czhower
|
|
Matched constructors visibility to ancestor.
|
|
|
|
Rev 1.3 2003.10.24 10:44:54 AM czhower
|
|
IdStream implementation, bug fixes.
|
|
|
|
Rev 1.2 2003.10.14 11:19:14 PM czhower
|
|
Updated for better functionality.
|
|
|
|
Rev 1.1 2003.10.14 1:27:14 PM czhower
|
|
Uupdates + Intercept support
|
|
|
|
Rev 1.0 2003.10.13 6:40:40 PM czhower
|
|
Moved from root
|
|
|
|
Rev 1.9 2003.10.11 10:00:36 PM czhower
|
|
Compiles again.
|
|
|
|
Rev 1.8 10/10/2003 10:53:42 PM BGooijen
|
|
Changed const-ness of some methods to reflect base class changes
|
|
|
|
Rev 1.7 7/10/2003 6:07:58 PM SGrobety
|
|
.net
|
|
|
|
Rev 1.6 17/07/2003 00:01:24 CCostelloe
|
|
Added (empty) procedures for the base classes' abstract CheckForDataOnSource
|
|
and CheckForDisconnect
|
|
|
|
Rev 1.5 7/1/2003 12:45:56 PM BGooijen
|
|
changed FInputBuffer.Size := 0 to FInputBuffer.Clear
|
|
|
|
Rev 1.4 12-8-2002 21:05:28 BGooijen
|
|
Removed call to Close in .Destroy, this is already done in
|
|
TIdIOHandler.Destroy
|
|
|
|
Rev 1.3 12/7/2002 06:42:44 PM JPMugaas
|
|
These should now compile except for Socks server. IPVersion has to be a
|
|
property someplace for that.
|
|
|
|
Rev 1.2 12/5/2002 02:53:52 PM JPMugaas
|
|
Updated for new API definitions.
|
|
|
|
Rev 1.1 05/12/2002 15:29:16 AO'Neill
|
|
|
|
Rev 1.0 11/13/2002 07:55:08 AM JPMugaas
|
|
}
|
|
|
|
unit IdIOHandlerStream;
|
|
|
|
interface
|
|
|
|
{$I IdCompilerDefines.inc}
|
|
|
|
uses
|
|
Classes,
|
|
IdBaseComponent,
|
|
IdGlobal,
|
|
IdIOHandler,
|
|
IdStream;
|
|
|
|
type
|
|
TIdIOHandlerStream = class;
|
|
TIdIOHandlerStreamType = (stRead, stWrite, stReadWrite);
|
|
TIdOnGetStreams = procedure(ASender: TIdIOHandlerStream;
|
|
var VReceiveStream: TStream; var VSendStream: TStream) of object;
|
|
|
|
TIdIOHandlerStream = class(TIdIOHandler)
|
|
protected
|
|
FFreeStreams: Boolean;
|
|
FOnGetStreams: TIdOnGetStreams;
|
|
FReceiveStream: TStream;
|
|
FSendStream: TStream;
|
|
FStreamType: TIdIOHandlerStreamType;
|
|
//
|
|
procedure InitComponent; override;
|
|
function ReadDataFromSource(var VBuffer: TIdBytes): Integer; override;
|
|
function WriteDataToTarget(const ABuffer: TIdBytes; const AOffset, ALength: Integer): Integer; override;
|
|
function SourceIsAvailable: Boolean; override;
|
|
function CheckForError(ALastResult: Integer): Integer; override;
|
|
procedure RaiseError(AError: Integer); override;
|
|
public
|
|
function StreamingAvailable: Boolean;
|
|
procedure CheckForDisconnect(ARaiseExceptionIfDisconnected: Boolean = True;
|
|
AIgnoreBuffer: Boolean = False); override;
|
|
constructor Create(AOwner: TComponent; AReceiveStream: TStream; ASendStream: TStream = nil); reintroduce; overload; virtual;
|
|
constructor Create(AOwner: TComponent); reintroduce; overload;
|
|
function Connected: Boolean; override;
|
|
procedure Close; override;
|
|
procedure Open; override;
|
|
function Readable(AMSec: integer = IdTimeoutDefault): boolean; override;
|
|
//
|
|
property ReceiveStream: TStream read FReceiveStream;
|
|
property SendStream: TStream read FSendStream;
|
|
property StreamType: TIdIOHandlerStreamType read FStreamType;
|
|
published
|
|
property FreeStreams: Boolean read FFreeStreams write FFreeStreams default True;
|
|
//
|
|
property OnGetStreams: TIdOnGetStreams read FOnGetStreams write FOnGetStreams;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
IdException, IdComponent, SysUtils;
|
|
|
|
{ TIdIOHandlerStream }
|
|
|
|
procedure TIdIOHandlerStream.InitComponent;
|
|
begin
|
|
inherited InitComponent;
|
|
FDefStringEncoding := IndyTextEncoding_8Bit;
|
|
end;
|
|
|
|
procedure TIdIOHandlerStream.CheckForDisconnect(
|
|
ARaiseExceptionIfDisconnected: Boolean = True;
|
|
AIgnoreBuffer: Boolean = False);
|
|
var
|
|
LDisconnected: Boolean;
|
|
begin
|
|
// ClosedGracefully // Server disconnected
|
|
// IOHandler = nil // Client disconnected
|
|
if ClosedGracefully then begin
|
|
if StreamingAvailable then begin
|
|
Close;
|
|
// Call event handlers to inform the user that we were disconnected
|
|
DoStatus(hsDisconnected);
|
|
//DoOnDisconnected;
|
|
end;
|
|
LDisconnected := True;
|
|
end else begin
|
|
LDisconnected := not StreamingAvailable;
|
|
end;
|
|
// Do not raise unless all data has been read by the user
|
|
if LDisconnected then begin
|
|
if (InputBufferIsEmpty or AIgnoreBuffer) and ARaiseExceptionIfDisconnected then begin
|
|
RaiseConnClosedGracefully;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TIdIOHandlerStream.Close;
|
|
begin
|
|
inherited Close;
|
|
if FreeStreams then begin
|
|
FreeAndNil(FReceiveStream);
|
|
FreeAndNil(FSendStream);
|
|
end else begin
|
|
FReceiveStream := nil;
|
|
FSendStream := nil;
|
|
end;
|
|
end;
|
|
|
|
function TIdIOHandlerStream.StreamingAvailable: Boolean;
|
|
begin
|
|
Result := False; // Just to avoid warning message
|
|
case FStreamType of
|
|
stRead: Result := Assigned(ReceiveStream);
|
|
stWrite: Result := Assigned(SendStream);
|
|
stReadWrite: Result := Assigned(ReceiveStream) and Assigned(SendStream);
|
|
end;
|
|
end;
|
|
|
|
function TIdIOHandlerStream.Connected: Boolean;
|
|
begin
|
|
Result := (StreamingAvailable and inherited Connected) or (not InputBufferIsEmpty);
|
|
end;
|
|
|
|
constructor TIdIOHandlerStream.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FFreeStreams := True;
|
|
FStreamType := stReadWrite;
|
|
end;
|
|
|
|
constructor TIdIOHandlerStream.Create(AOwner: TComponent; AReceiveStream: TStream;
|
|
ASendStream: TStream = nil);
|
|
begin
|
|
inherited Create(AOwner);
|
|
//
|
|
FFreeStreams := True;
|
|
FReceiveStream := AReceiveStream;
|
|
FSendStream := ASendStream;
|
|
//
|
|
if Assigned(FReceiveStream) and (not Assigned(FSendStream)) then begin
|
|
FStreamType := stRead;
|
|
end else if (not Assigned(FReceiveStream)) and Assigned(FSendStream) then begin
|
|
FStreamType := stWrite;
|
|
end else begin
|
|
FStreamType := stReadWrite;
|
|
end;
|
|
end;
|
|
|
|
procedure TIdIOHandlerStream.Open;
|
|
begin
|
|
inherited Open;
|
|
if Assigned(OnGetStreams) then begin
|
|
OnGetStreams(Self, FReceiveStream, FSendStream);
|
|
end;
|
|
if Assigned(FReceiveStream) and (not Assigned(FSendStream)) then begin
|
|
FStreamType := stRead;
|
|
end else if (not Assigned(FReceiveStream)) and Assigned(FSendStream) then begin
|
|
FStreamType := stWrite;
|
|
end else begin
|
|
FStreamType := stReadWrite;
|
|
end;
|
|
end;
|
|
|
|
function TIdIOHandlerStream.Readable(AMSec: Integer): Boolean;
|
|
begin
|
|
Result := Assigned(ReceiveStream);
|
|
// RLebeau: not checking the Position anymore. Was
|
|
// causing deadlocks when trying to read past EOF.
|
|
// This way, when EOF is reached, ReadFromSource()
|
|
// will return 0, which will be interpretted as the
|
|
// connnection being closed...
|
|
{
|
|
if Result then begin
|
|
Result := ReceiveStream.Position < ReceiveStream.Size;
|
|
end;
|
|
}
|
|
end;
|
|
|
|
function TIdIOHandlerStream.ReadDataFromSource(var VBuffer: TIdBytes): Integer;
|
|
begin
|
|
// We dont want to read the whole stream in at a time. If its a big
|
|
// file will consume way too much memory by loading it all at once.
|
|
// So lets read it in chunks.
|
|
if Assigned(FReceiveStream) then begin
|
|
Result := IndyMin(32 * 1024, Length(VBuffer));
|
|
if Result > 0 then begin
|
|
Result := TIdStreamHelper.ReadBytes(FReceiveStream, VBuffer, Result);
|
|
end;
|
|
end else begin
|
|
Result := 0;
|
|
end;
|
|
end;
|
|
|
|
function TIdIOHandlerStream.WriteDataToTarget(const ABuffer: TIdBytes; const AOffset, ALength: Integer): Integer;
|
|
begin
|
|
if Assigned(FSendStream) then begin
|
|
Result := TIdStreamHelper.Write(FSendStream, ABuffer, ALength, AOffset);
|
|
end else begin
|
|
Result := IndyLength(ABuffer, ALength, AOffset);
|
|
end;
|
|
end;
|
|
|
|
function TIdIOHandlerStream.SourceIsAvailable: Boolean;
|
|
begin
|
|
Result := Assigned(ReceiveStream);
|
|
end;
|
|
|
|
function TIdIOHandlerStream.CheckForError(ALastResult: Integer): Integer;
|
|
begin
|
|
Result := ALastResult;
|
|
if Result < 0 then begin
|
|
raise EIdException.Create('Stream error'); {do not localize}
|
|
end;
|
|
end;
|
|
|
|
procedure TIdIOHandlerStream.RaiseError(AError: Integer);
|
|
begin
|
|
raise EIdException.Create('Stream error'); {do not localize}
|
|
end;
|
|
|
|
end.
|