IdIOHandlerStream.pas 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  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. IdStream;
  91. type
  92. TIdIOHandlerStream = class;
  93. TIdIOHandlerStreamType = (stRead, stWrite, stReadWrite);
  94. TIdOnGetStreams = procedure(ASender: TIdIOHandlerStream;
  95. var VReceiveStream: TStream; var VSendStream: TStream) of object;
  96. TIdIOHandlerStream = class(TIdIOHandler)
  97. protected
  98. FFreeStreams: Boolean;
  99. FOnGetStreams: TIdOnGetStreams;
  100. FReceiveStream: TStream;
  101. FSendStream: TStream;
  102. FStreamType: TIdIOHandlerStreamType;
  103. //
  104. procedure InitComponent; override;
  105. function ReadDataFromSource(var VBuffer: TIdBytes): Integer; override;
  106. function WriteDataToTarget(const ABuffer: TIdBytes; const AOffset, ALength: Integer): Integer; override;
  107. function SourceIsAvailable: Boolean; override;
  108. function CheckForError(ALastResult: Integer): Integer; override;
  109. procedure RaiseError(AError: Integer); override;
  110. public
  111. function StreamingAvailable: Boolean;
  112. procedure CheckForDisconnect(ARaiseExceptionIfDisconnected: Boolean = True;
  113. AIgnoreBuffer: Boolean = False); override;
  114. constructor Create(AOwner: TComponent; AReceiveStream: TStream; ASendStream: TStream = nil); reintroduce; overload; virtual;
  115. constructor Create(AOwner: TComponent); reintroduce; overload;
  116. function Connected: Boolean; override;
  117. procedure Close; override;
  118. procedure Open; override;
  119. function Readable(AMSec: integer = IdTimeoutDefault): boolean; override;
  120. //
  121. property ReceiveStream: TStream read FReceiveStream;
  122. property SendStream: TStream read FSendStream;
  123. property StreamType: TIdIOHandlerStreamType read FStreamType;
  124. published
  125. property FreeStreams: Boolean read FFreeStreams write FFreeStreams default True;
  126. //
  127. property OnGetStreams: TIdOnGetStreams read FOnGetStreams write FOnGetStreams;
  128. end;
  129. implementation
  130. uses
  131. IdException, IdComponent, SysUtils;
  132. { TIdIOHandlerStream }
  133. procedure TIdIOHandlerStream.InitComponent;
  134. begin
  135. inherited InitComponent;
  136. FDefStringEncoding := IndyTextEncoding_8Bit;
  137. end;
  138. procedure TIdIOHandlerStream.CheckForDisconnect(
  139. ARaiseExceptionIfDisconnected: Boolean = True;
  140. AIgnoreBuffer: Boolean = False);
  141. var
  142. LDisconnected: Boolean;
  143. begin
  144. // ClosedGracefully // Server disconnected
  145. // IOHandler = nil // Client disconnected
  146. if ClosedGracefully then begin
  147. if StreamingAvailable then begin
  148. Close;
  149. // Call event handlers to inform the user that we were disconnected
  150. DoStatus(hsDisconnected);
  151. //DoOnDisconnected;
  152. end;
  153. LDisconnected := True;
  154. end else begin
  155. LDisconnected := not StreamingAvailable;
  156. end;
  157. // Do not raise unless all data has been read by the user
  158. if LDisconnected then begin
  159. if (InputBufferIsEmpty or AIgnoreBuffer) and ARaiseExceptionIfDisconnected then begin
  160. RaiseConnClosedGracefully;
  161. end;
  162. end;
  163. end;
  164. procedure TIdIOHandlerStream.Close;
  165. begin
  166. inherited Close;
  167. if FreeStreams then begin
  168. FreeAndNil(FReceiveStream);
  169. FreeAndNil(FSendStream);
  170. end else begin
  171. FReceiveStream := nil;
  172. FSendStream := nil;
  173. end;
  174. end;
  175. function TIdIOHandlerStream.StreamingAvailable: Boolean;
  176. begin
  177. Result := False; // Just to avoid warning message
  178. case FStreamType of
  179. stRead: Result := Assigned(ReceiveStream);
  180. stWrite: Result := Assigned(SendStream);
  181. stReadWrite: Result := Assigned(ReceiveStream) and Assigned(SendStream);
  182. end;
  183. end;
  184. function TIdIOHandlerStream.Connected: Boolean;
  185. begin
  186. Result := (StreamingAvailable and inherited Connected) or (not InputBufferIsEmpty);
  187. end;
  188. constructor TIdIOHandlerStream.Create(AOwner: TComponent);
  189. begin
  190. inherited Create(AOwner);
  191. FFreeStreams := True;
  192. FStreamType := stReadWrite;
  193. end;
  194. constructor TIdIOHandlerStream.Create(AOwner: TComponent; AReceiveStream: TStream;
  195. ASendStream: TStream = nil);
  196. begin
  197. inherited Create(AOwner);
  198. //
  199. FFreeStreams := True;
  200. FReceiveStream := AReceiveStream;
  201. FSendStream := ASendStream;
  202. //
  203. if Assigned(FReceiveStream) and (not Assigned(FSendStream)) then begin
  204. FStreamType := stRead;
  205. end else if (not Assigned(FReceiveStream)) and Assigned(FSendStream) then begin
  206. FStreamType := stWrite;
  207. end else begin
  208. FStreamType := stReadWrite;
  209. end;
  210. end;
  211. procedure TIdIOHandlerStream.Open;
  212. begin
  213. inherited Open;
  214. if Assigned(OnGetStreams) then begin
  215. OnGetStreams(Self, FReceiveStream, FSendStream);
  216. end;
  217. if Assigned(FReceiveStream) and (not Assigned(FSendStream)) then begin
  218. FStreamType := stRead;
  219. end else if (not Assigned(FReceiveStream)) and Assigned(FSendStream) then begin
  220. FStreamType := stWrite;
  221. end else begin
  222. FStreamType := stReadWrite;
  223. end;
  224. end;
  225. function TIdIOHandlerStream.Readable(AMSec: Integer): Boolean;
  226. begin
  227. Result := Assigned(ReceiveStream);
  228. // RLebeau: not checking the Position anymore. Was
  229. // causing deadlocks when trying to read past EOF.
  230. // This way, when EOF is reached, ReadFromSource()
  231. // will return 0, which will be interpretted as the
  232. // connnection being closed...
  233. {
  234. if Result then begin
  235. Result := ReceiveStream.Position < ReceiveStream.Size;
  236. end;
  237. }
  238. end;
  239. function TIdIOHandlerStream.ReadDataFromSource(var VBuffer: TIdBytes): Integer;
  240. begin
  241. // We dont want to read the whole stream in at a time. If its a big
  242. // file will consume way too much memory by loading it all at once.
  243. // So lets read it in chunks.
  244. if Assigned(FReceiveStream) then begin
  245. Result := IndyMin(32 * 1024, Length(VBuffer));
  246. if Result > 0 then begin
  247. Result := TIdStreamHelper.ReadBytes(FReceiveStream, VBuffer, Result);
  248. end;
  249. end else begin
  250. Result := 0;
  251. end;
  252. end;
  253. function TIdIOHandlerStream.WriteDataToTarget(const ABuffer: TIdBytes; const AOffset, ALength: Integer): Integer;
  254. begin
  255. if Assigned(FSendStream) then begin
  256. Result := TIdStreamHelper.Write(FSendStream, ABuffer, ALength, AOffset);
  257. end else begin
  258. Result := IndyLength(ABuffer, ALength, AOffset);
  259. end;
  260. end;
  261. function TIdIOHandlerStream.SourceIsAvailable: Boolean;
  262. begin
  263. Result := Assigned(ReceiveStream);
  264. end;
  265. function TIdIOHandlerStream.CheckForError(ALastResult: Integer): Integer;
  266. begin
  267. Result := ALastResult;
  268. if Result < 0 then begin
  269. raise EIdException.Create('Stream error'); {do not localize} // TODO: add a resource string, and create a new Exception class for this
  270. end;
  271. end;
  272. procedure RaiseIOStreamError;
  273. {$IFDEF USE_NORETURN}noreturn;{$ENDIF}
  274. begin
  275. raise EIdException.Create('Stream error'); {do not localize} // TODO: add a resource string, and create a new Exception class for this
  276. end;
  277. procedure TIdIOHandlerStream.RaiseError(AError: Integer);
  278. begin
  279. RaiseIOStreamError;
  280. end;
  281. end.