{ $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: 56088: IdWorkOpUnits.pas { Rev 1.4 6/11/2004 8:40:12 AM DSiders Added "Do not Localize" comments. } { { Rev 1.3 2004.05.06 1:47:28 PM czhower { Now uses IndexOf } { { Rev 1.2 2004.04.22 11:45:18 PM czhower { Bug fixes } { { Rev 1.1 2004.02.09 9:16:58 PM czhower { Updated to compile and match lib changes. } { { Rev 1.0 2004.02.03 12:39:10 AM czhower { Move } { { Rev 1.14 2003.10.19 2:50:42 PM czhower { Fiber cleanup } { { Rev 1.13 2003.10.11 5:44:20 PM czhower { Chained servers now functional. } { { Rev 1.12 2003.07.17 4:42:08 PM czhower { More IOCP improvements. } { { Rev 1.11 2003.07.17 3:55:18 PM czhower { Removed IdIOChainEngineIOCP and merged it into TIdChaingEngine in { IdIOHandlerChain.pas. } { { Rev 1.7 2003.07.14 11:00:52 PM czhower { More IOCP fixes. } { { Rev 1.6 2003.07.14 12:54:34 AM czhower { Fixed graceful close detection if it occurs after connect. } { Rev 1.5 7/7/2003 1:25:26 PM BGooijen Added BytesSent property to TIdWorkOpUnitWriteFile } { Rev 1.4 7/5/2003 11:47:14 PM BGooijen Added TIdWorkOpUnitCheckForDisconnect and TIdWorkOpUnitWriteFile } { Rev 1.3 3/27/2003 2:43:06 PM BGooijen Added woWriteStream and woWriteBuffer } { { Rev 1.2 3/22/2003 09:45:30 PM JPMugaas { Now should compile under D4. } { Rev 1.1 3/2/2003 12:36:26 AM BGooijen Added woReadBuffer and TIdWorkOpUnitReadBuffer to read a buffer. Now ReadBuffer doesn't use ReadStream any more. TIdIOHandlerChain.ReadLn now supports MaxLineLength (splitting, and exceptions). woReadLn doesn't check the intire buffer any more, but continued where it stopped the last time. Added basic support for timeouts (probably only on read operations, and maybe connect), accuratie of timeout is currently 500msec. } { Rev 1.0 2/27/2003 10:11:50 PM BGooijen WorkOpUnits combined in one file } unit IdWorkOpUnits; interface uses Classes, IdWorkOpUnit, IdGlobal, SysUtils; type TIdWorkOpUnitStreamBaseRead = class(TIdWorkOpUnitRead) protected FStream: TStream; public constructor Create(AStream: TStream); reintroduce; virtual; end; TIdWorkOpUnitStreamBaseWrite = class(TIdWorkOpUnitWrite) protected FFreeStream: Boolean; FStream: TStream; public constructor Create( AStream: TStream; AFreeStream: Boolean = True ); reintroduce; virtual; destructor Destroy; override; end; TIdWorkOpUnitWriteBuffer = class(TIdWorkOpUnitWrite) protected FBuffer: Pointer; FFreeBuffer: Boolean; FSize: Integer; // procedure Processing(ABytes: Integer); override; procedure Starting; override; public constructor Create(ABuffer: Pointer; ASize: Integer; AFreeBuffer: Boolean = True); reintroduce; virtual; destructor Destroy; override; end; TIdWorkOpUnitWriteFile = class(TIdWorkOpUnitWrite) protected FFilename: String; FBytesSent: Integer; // procedure Processing(ABytes: Integer); override; procedure Starting; override; public constructor Create(AFileName: string); reintroduce; end; TIdWorkOpUnitWriteStream = class(TIdWorkOpUnitStreamBaseWrite) protected FCount: Integer; FStartPos: Integer; // procedure Processing(ABytes: Integer); override; procedure Starting; override; public constructor Create(AStream: TStream; AStartPos, ACount: Integer; AFreeStream: Boolean); reintroduce; virtual; end; TIdWorkOpUnitWaitConnected = class(TIdWorkOpUnit) protected procedure Starting; override; public procedure Process( AOverlapped: PIdOverlapped; AByteCount: Integer ); override; end; TIdWorkOpUnitReadSized = class(TIdWorkOpUnitRead) protected FSize: Integer; // procedure Processing( ABuffer: TIdBytes ); override; public constructor Create(ASize: Integer); reintroduce; end; TIdWorkOpUnitReadSizedStream = class(TIdWorkOpUnitStreamBaseRead) protected FSize: Integer; // procedure Processing( ABuffer: TIdBytes ); override; public constructor Create(AStream: TStream; ASize: Integer); reintroduce; end; TIdWorkOpUnitReadLn = class(TIdWorkOpUnitRead) protected FLastPos: Integer; FMaxLength: Integer; FTerminator: string; // procedure Processing( ABuffer: TIdBytes ); override; public constructor Create( ATerminator: string; AMaxLength: Integer ); reintroduce; end; TIdWorkOpUnitReadUntilDisconnect = class(TIdWorkOpUnitStreamBaseRead) protected procedure Processing( ABuffer: TIdBytes ); override; end; TIdWorkOpUnitReadAvailable = class(TIdWorkOpUnitRead) protected procedure Processing( ABuffer: TIdBytes ); override; end; implementation { TIdWorkOpUnitWriteStream } constructor TIdWorkOpUnitWriteStream.Create(AStream: TStream; AStartPos,ACount:integer; AFreeStream: Boolean); begin inherited Create(AStream, AFreeStream); FStream.Position := AStartPos; FCount := ACount; end; procedure TIdWorkOpUnitWriteStream.Processing(ABytes: Integer); //TODO: This used to use pages from IdBuffer, which because of .Net do not exist // anymore. We need to maybe keep a local persistent buffer instead then for // storage reasons. var LBuffer: TIdBytes; LSize: Integer; begin FCount := FCount - ABytes; if FCount = 0 then begin Complete; end else begin FStream.Position := ABytes; // //TODO: Dont hard code this value. Also find an optimal size for IOCP LSize := Min(FCount, WOPageSize); SetLength(LBuffer, LSize); // FStream.ReadBuffer(LBuffer[0], LSize); Write(@LBuffer[0], LSize); end; end; procedure TIdWorkOpUnitWriteStream.Starting; begin Processing(0); end; { TIdWorkOpUnitWriteBuffer } constructor TIdWorkOpUnitWriteBuffer.Create(ABuffer: pointer; ASize: integer; AFreeBuffer: Boolean = True); begin inherited Create; FSize := ASize; FBuffer := ABuffer; FFreeBuffer := AFreeBuffer; end; destructor TIdWorkOpUnitWriteBuffer.Destroy; begin if FFreeBuffer then begin FreeMem(FBuffer); FBuffer := nil; end; inherited; end; procedure TIdWorkOpUnitWriteBuffer.Processing(ABytes: Integer); begin //TODO: Change the pointer to a type that points to bytes FBuffer := Pointer(Cardinal(FBuffer) + Cardinal(ABytes)); FSize := FSize - ABytes; if FSize = 0 then begin Complete; end else begin //TODO: Reduce this down so it never sends more than a page Write(FBuffer, Min(FSize, WOPageSize)); end; end; procedure TIdWorkOpUnitWriteBuffer.Starting; begin Processing(0); end; { TIdWorkOpUnitWriteFile } constructor TIdWorkOpUnitWriteFile.Create(AFileName:string); begin inherited Create; FFilename := AFileName; end; procedure TIdWorkOpUnitWriteFile.Processing(ABytes: Integer); begin Assert(False, 'Need to implement WriteFile, also add to a bubble'); {do not localize} end; procedure TIdWorkOpUnitWriteFile.Starting; begin end; { TIdWorkOpUnitSizedStream } constructor TIdWorkOpUnitReadSizedStream.Create(AStream: TStream; ASize:integer); begin inherited Create(AStream); FSize := ASize; end; procedure TIdWorkOpUnitWaitConnected.Process( AOverlapped: PIdOverlapped; AByteCount: Integer ); begin end; procedure TIdWorkOpUnitWaitConnected.Starting; begin end; { TIdWorkOpUnitReadLn } constructor TIdWorkOpUnitReadLn.Create( ATerminator: string; AMaxLength: Integer); begin inherited Create; FLastPos := 1; FTerminator := ATerminator; FMaxLength := AMaxLength; end; procedure TIdWorkOpUnitReadLn.Processing( ABuffer: TIdBytes ); begin //TODO: ReadLn is very common. Need to optimize this class and maybe // even pass pack the result directly so we dont search twice. //Also allow for hinting from the user. IOHandler.InputBuffer.Write(ABuffer); if not IOHandler.Connected then begin Complete; end else if IOHandler.InputBuffer.IndexOf(FTerminator, FLastPos) = -1 then begin Read; end else begin Complete; end; end; procedure TIdWorkOpUnitReadUntilDisconnect.Processing( ABuffer: TIdBytes ); begin // 0 is disconnected, so keep requesting til 0 if Length(ABuffer) = 0 then begin Complete; end else begin FStream.WriteBuffer(ABuffer[0], Length(ABuffer)); Read; end; end; { TIdWorkOpUnitReadAvailable } procedure TIdWorkOpUnitReadAvailable.Processing( ABuffer: TIdBytes ); begin Complete; end; { TIdWorkOpUnitReadSized } constructor TIdWorkOpUnitReadSized.Create(ASize: Integer); begin inherited Create; FSize := ASize; end; procedure TIdWorkOpUnitReadSized.Processing( ABuffer: TIdBytes ); begin IOHandler.InputBuffer.Write(ABuffer); FSize := FSize - Length(ABuffer); if FSize = 0 then begin Complete; end else begin Read; end; end; { TIdWorkOpUnitStreamBaseRead } constructor TIdWorkOpUnitStreamBaseRead.Create(AStream: TStream); begin inherited Create; FStream := AStream; end; { TIdWorkOpUnitStreamBaseWrite } constructor TIdWorkOpUnitStreamBaseWrite.Create(AStream: TStream; AFreeStream: Boolean); begin inherited Create; FStream := AStream; FFreeStream := AFreeStream; end; destructor TIdWorkOpUnitStreamBaseWrite.Destroy; begin if FFreeStream then begin FreeAndNil(FStream); end; inherited; end; procedure TIdWorkOpUnitReadSizedStream.Processing( ABuffer: TIdBytes ); begin FStream.WriteBuffer(ABuffer[0], Length(ABuffer)); FSize := FSize - Length(ABuffer); if FSize = 0 then begin Complete; end else begin Read; end; end; end.