IdIOHandlerStream.pas 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.21 3/10/05 3:24:30 PM RLebeau
  18. Updated ReadFromSource() and WriteDirect() to access the Intercept property
  19. directly.
  20. Rev 1.20 10/21/2004 11:07:30 PM BGooijen
  21. works in win32 now too
  22. Rev 1.19 10/21/2004 1:52:56 PM BGooijen
  23. Raid 214235
  24. Rev 1.18 7/23/04 6:20:52 PM RLebeau
  25. Removed memory leaks in Send/ReceiveStream property setters
  26. Rev 1.17 2004.05.20 11:39:08 AM czhower
  27. IdStreamVCL
  28. Rev 1.16 23/04/2004 20:29:36 CCostelloe
  29. Minor change to support IdMessageClient's new TIdIOHandlerStreamMsg
  30. Rev 1.15 2004.04.16 11:30:32 PM czhower
  31. Size fix to IdBuffer, optimizations, and memory leaks
  32. Rev 1.14 2004.04.08 3:56:36 PM czhower
  33. Fixed bug with Intercept byte count. Also removed Bytes from Buffer.
  34. Rev 1.13 2004.03.07 11:48:46 AM czhower
  35. Flushbuffer fix + other minor ones found
  36. Rev 1.12 2004.03.03 11:55:04 AM czhower
  37. IdStream change
  38. Rev 1.11 2004.02.03 4:17:16 PM czhower
  39. For unit name changes.
  40. Rev 1.10 11/01/2004 19:52:44 CCostelloe
  41. Revisions for TIdMessage SaveToFile & LoadFromFile for D7 & D8
  42. Rev 1.8 08/01/2004 23:37:16 CCostelloe
  43. Minor changes
  44. Rev 1.7 1/8/2004 1:01:22 PM BGooijen
  45. Cleaned up
  46. Rev 1.6 1/8/2004 4:23:06 AM BGooijen
  47. temp fixed TIdIOHandlerStream.WriteToDestination
  48. Rev 1.5 08/01/2004 00:25:22 CCostelloe
  49. Start of reimplementing LoadFrom/SaveToFile
  50. Rev 1.4 2003.12.31 7:44:54 PM czhower
  51. Matched constructors visibility to ancestor.
  52. Rev 1.3 2003.10.24 10:44:54 AM czhower
  53. IdStream implementation, bug fixes.
  54. Rev 1.2 2003.10.14 11:19:14 PM czhower
  55. Updated for better functionality.
  56. Rev 1.1 2003.10.14 1:27:14 PM czhower
  57. Uupdates + Intercept support
  58. Rev 1.0 2003.10.13 6:40:40 PM czhower
  59. Moved from root
  60. Rev 1.9 2003.10.11 10:00:36 PM czhower
  61. Compiles again.
  62. Rev 1.8 10/10/2003 10:53:42 PM BGooijen
  63. Changed const-ness of some methods to reflect base class changes
  64. Rev 1.7 7/10/2003 6:07:58 PM SGrobety
  65. .net
  66. Rev 1.6 17/07/2003 00:01:24 CCostelloe
  67. Added (empty) procedures for the base classes' abstract CheckForDataOnSource
  68. and CheckForDisconnect
  69. Rev 1.5 7/1/2003 12:45:56 PM BGooijen
  70. changed FInputBuffer.Size := 0 to FInputBuffer.Clear
  71. Rev 1.4 12-8-2002 21:05:28 BGooijen
  72. Removed call to Close in .Destroy, this is already done in
  73. TIdIOHandler.Destroy
  74. Rev 1.3 12/7/2002 06:42:44 PM JPMugaas
  75. These should now compile except for Socks server. IPVersion has to be a
  76. property someplace for that.
  77. Rev 1.2 12/5/2002 02:53:52 PM JPMugaas
  78. Updated for new API definitions.
  79. Rev 1.1 05/12/2002 15:29:16 AO'Neill
  80. Rev 1.0 11/13/2002 07:55:08 AM JPMugaas
  81. }
  82. unit IdIOHandlerStream;
  83. interface
  84. {$I IdCompilerDefines.inc}
  85. uses
  86. Classes,
  87. IdBaseComponent,
  88. IdGlobal,
  89. IdIOHandler;
  90. type
  91. TIdIOHandlerStream = class;
  92. TIdIOHandlerStreamType = (stRead, stWrite, stReadWrite);
  93. TIdOnGetStreams = procedure(ASender: TIdIOHandlerStream;
  94. var VReceiveStream: TStream; var VSendStream: TStream) of object;
  95. TIdIOHandlerStream = class(TIdIOHandler)
  96. protected
  97. FFreeStreams: Boolean;
  98. FOnGetStreams: TIdOnGetStreams;
  99. FReceiveStream: TStream;
  100. FSendStream: TStream;
  101. FStreamType: TIdIOHandlerStreamType;
  102. //
  103. function ReadDataFromSource(var VBuffer: TIdBytes): Integer; override;
  104. function WriteDataToTarget(const ABuffer: TIdBytes; const AOffset, ALength: Integer): Integer; override;
  105. function SourceIsAvailable: Boolean; override;
  106. function CheckForError(ALastResult: Integer): Integer; override;
  107. procedure RaiseError(AError: Integer); override;
  108. public
  109. constructor Create(AOwner: TComponent); overload; override;
  110. constructor Create(AOwner: TComponent; AReceiveStream: TStream; ASendStream: TStream = nil); overload; virtual;
  111. function StreamingAvailable: Boolean;
  112. procedure CheckForDisconnect(ARaiseExceptionIfDisconnected: Boolean = True;
  113. AIgnoreBuffer: Boolean = False); override;
  114. function Connected: Boolean; override;
  115. procedure Close; override;
  116. procedure Open; override;
  117. function Readable(AMSec: integer = IdTimeoutDefault): boolean; override;
  118. //
  119. property ReceiveStream: TStream read FReceiveStream;
  120. property SendStream: TStream read FSendStream;
  121. property StreamType: TIdIOHandlerStreamType read FStreamType;
  122. published
  123. property FreeStreams: Boolean read FFreeStreams write FFreeStreams default True;
  124. //
  125. property OnGetStreams: TIdOnGetStreams read FOnGetStreams write FOnGetStreams;
  126. end;
  127. implementation
  128. uses
  129. IdException, IdComponent, SysUtils;
  130. { TIdIOHandlerStream }
  131. constructor TIdIOHandlerStream.Create(AOwner: TComponent);
  132. begin
  133. Create(AOwner, nil, nil);
  134. end;
  135. constructor TIdIOHandlerStream.Create(AOwner: TComponent; AReceiveStream: TStream;
  136. ASendStream: TStream = nil);
  137. begin
  138. inherited Create(AOwner);
  139. //
  140. FDefStringEncoding := IndyTextEncoding_8Bit;
  141. FFreeStreams := True;
  142. FReceiveStream := AReceiveStream;
  143. FSendStream := ASendStream;
  144. //
  145. if Assigned(FReceiveStream) and (not Assigned(FSendStream)) then begin
  146. FStreamType := stRead;
  147. end else if (not Assigned(FReceiveStream)) and Assigned(FSendStream) then begin
  148. FStreamType := stWrite;
  149. end else begin
  150. FStreamType := stReadWrite;
  151. end;
  152. end;
  153. procedure TIdIOHandlerStream.CheckForDisconnect(
  154. ARaiseExceptionIfDisconnected: Boolean = True;
  155. AIgnoreBuffer: Boolean = False);
  156. var
  157. LDisconnected: Boolean;
  158. begin
  159. // ClosedGracefully // Server disconnected
  160. // IOHandler = nil // Client disconnected
  161. if ClosedGracefully then begin
  162. if StreamingAvailable then begin
  163. Close;
  164. // Call event handlers to inform the user that we were disconnected
  165. DoStatus(hsDisconnected);
  166. //DoOnDisconnected;
  167. end;
  168. LDisconnected := True;
  169. end else begin
  170. LDisconnected := not StreamingAvailable;
  171. end;
  172. // Do not raise unless all data has been read by the user
  173. if LDisconnected then begin
  174. if (InputBufferIsEmpty or AIgnoreBuffer) and ARaiseExceptionIfDisconnected then begin
  175. RaiseConnClosedGracefully;
  176. end;
  177. end;
  178. end;
  179. procedure TIdIOHandlerStream.Close;
  180. begin
  181. inherited Close;
  182. if FreeStreams then begin
  183. IdDisposeAndNil(FReceiveStream);
  184. IdDisposeAndNil(FSendStream);
  185. end else begin
  186. FReceiveStream := nil;
  187. FSendStream := nil;
  188. end;
  189. end;
  190. function TIdIOHandlerStream.StreamingAvailable: Boolean;
  191. begin
  192. Result := False; // Just to avoid warning message
  193. case FStreamType of
  194. stRead: Result := Assigned(ReceiveStream);
  195. stWrite: Result := Assigned(SendStream);
  196. stReadWrite: Result := Assigned(ReceiveStream) and Assigned(SendStream);
  197. end;
  198. end;
  199. function TIdIOHandlerStream.Connected: Boolean;
  200. begin
  201. Result := (StreamingAvailable and inherited Connected) or (not InputBufferIsEmpty);
  202. end;
  203. procedure TIdIOHandlerStream.Open;
  204. begin
  205. inherited Open;
  206. if Assigned(OnGetStreams) then begin
  207. OnGetStreams(Self, FReceiveStream, FSendStream);
  208. end;
  209. if Assigned(FReceiveStream) and (not Assigned(FSendStream)) then begin
  210. FStreamType := stRead;
  211. end else if (not Assigned(FReceiveStream)) and Assigned(FSendStream) then begin
  212. FStreamType := stWrite;
  213. end else begin
  214. FStreamType := stReadWrite;
  215. end;
  216. end;
  217. function TIdIOHandlerStream.Readable(AMSec: Integer): Boolean;
  218. begin
  219. Result := Assigned(ReceiveStream);
  220. // RLebeau: not checking the Position anymore. Was
  221. // causing deadlocks when trying to read past EOF.
  222. // This way, when EOF is reached, ReadFromSource()
  223. // will return 0, which will be interpretted as the
  224. // connnection being closed...
  225. {
  226. if Result then begin
  227. Result := ReceiveStream.Position < ReceiveStream.Size;
  228. end;
  229. }
  230. end;
  231. function TIdIOHandlerStream.ReadDataFromSource(var VBuffer: TIdBytes): Integer;
  232. begin
  233. // We dont want to read the whole stream in at a time. If its a big
  234. // file will consume way too much memory by loading it all at once.
  235. // So lets read it in chunks.
  236. if Assigned(FReceiveStream) then begin
  237. Result := IndyMin(32 * 1024, Length(VBuffer));
  238. if Result > 0 then begin
  239. Result := FReceiveStream.Read(VBuffer[0], Result);
  240. end;
  241. end else begin
  242. Result := 0;
  243. end;
  244. end;
  245. function TIdIOHandlerStream.WriteDataToTarget(const ABuffer: TIdBytes; const AOffset, ALength: Integer): Integer;
  246. begin
  247. Result := IndyLength(ABuffer, ALength, AOffset);
  248. if Assigned(FSendStream) and (Result > 0) then begin
  249. FSendStream.WriteBuffer(ABuffer[AOffset], Result);
  250. end;
  251. end;
  252. function TIdIOHandlerStream.SourceIsAvailable: Boolean;
  253. begin
  254. Result := Assigned(ReceiveStream);
  255. end;
  256. function TIdIOHandlerStream.CheckForError(ALastResult: Integer): Integer;
  257. begin
  258. Result := ALastResult;
  259. if Result < 0 then begin
  260. raise EIdException.Create('Stream error'); {do not localize} // TODO: add a resource string, and create a new Exception class for this
  261. end;
  262. end;
  263. procedure TIdIOHandlerStream.RaiseError(AError: Integer);
  264. begin
  265. raise EIdException.Create('Stream error'); {do not localize} // TODO: add a resource string, and create a new Exception class for this
  266. end;
  267. end.