bufstream.pp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. {
  2. $Id$
  3. This file is part of the Free Component Library.
  4. Copyright (c) 1999-2000 by the Free Pascal development team
  5. Implement a buffered stream.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$mode objfpc}
  13. {$H+}
  14. unit bufstream;
  15. interface
  16. uses
  17. Classes, SysUtils;
  18. Const
  19. DefaultBufferCapacity : Integer = 16; // Default buffer capacity in Kb.
  20. Type
  21. { TBufStream }
  22. TBufStream = Class(TOwnerStream)
  23. Private
  24. FTotalPos : Int64;
  25. Fbuffer: Pointer;
  26. FBufPos: Integer;
  27. FBufSize: Integer;
  28. FCapacity: Integer;
  29. procedure SetCapacity(const AValue: Integer);
  30. Protected
  31. procedure BufferError(Msg : String);
  32. Procedure FillBuffer; Virtual;
  33. Procedure FlushBuffer; Virtual;
  34. Public
  35. Constructor Create(ASource : TStream; ACapacity: Integer);
  36. Constructor Create(ASource : TStream);
  37. Destructor Destroy; override;
  38. Property Buffer : Pointer Read Fbuffer;
  39. Property Capacity : Integer Read FCapacity Write SetCapacity;
  40. Property BufferPos : Integer Read FBufPos; // 0 based.
  41. Property BufferSize : Integer Read FBufSize; // Number of bytes in buffer.
  42. end;
  43. { TReadBufStream }
  44. TReadBufStream = Class(TBufStream)
  45. Public
  46. Function Seek(Offset: Longint; Origin: Word): Longint; override;
  47. Function Read(var ABuffer; ACount : LongInt) : Integer; override;
  48. Function Write(Const ABuffer; ACount : LongInt) : Integer; override;
  49. end;
  50. { TWriteBufStream }
  51. TWriteBufStream = Class(TBufStream)
  52. Public
  53. Destructor Destroy; override;
  54. Function Seek(Offset: Longint; Origin: Word): Longint; override;
  55. Function Read(var ABuffer; ACount : LongInt) : Integer; override;
  56. Function Write(Const ABuffer; ACount : LongInt) : Integer; override;
  57. end;
  58. implementation
  59. Resourcestring
  60. SErrCapacityTooSmall = 'Capacity is less than actual buffer size.';
  61. SErrCouldNotFLushBuffer = 'Could not flush buffer';
  62. SErrWriteOnlyStream = 'Illegal stream operation: Only writing is allowed.';
  63. SErrReadOnlyStream = 'Illegal stream operation: Only reading is allowed.';
  64. SErrInvalidSeek = 'Invalid buffer seek operation';
  65. { TBufStream }
  66. procedure TBufStream.SetCapacity(const AValue: Integer);
  67. begin
  68. if (FCapacity<>AValue) then
  69. begin
  70. If (AValue<FBufSize) then
  71. BufferError(SErrCapacityTooSmall);
  72. ReallocMem(FBuffer,AValue);
  73. FCapacity:=AValue;
  74. end;
  75. end;
  76. procedure TBufStream.BufferError(Msg: String);
  77. begin
  78. Raise EStreamError.Create(Msg);
  79. end;
  80. procedure TBufStream.FillBuffer;
  81. Var
  82. RCount : Integer;
  83. P : PChar;
  84. begin
  85. P:=Pchar(FBuffer);
  86. // Reset at beginning if empty.
  87. If (FBufSize-FBufPos)<=0 then
  88. begin
  89. FBufSize:=0;
  90. FBufPos:=0;
  91. end;
  92. Inc(P,FBufSize);
  93. RCount:=1;
  94. while (RCount<>0) and (FBufSize<FCapacity) do
  95. begin
  96. RCount:=FSource.Read(P^,FCapacity-FBufSize);
  97. Inc(P,RCount);
  98. Inc(FBufSize,RCount);
  99. end;
  100. end;
  101. procedure TBufStream.FlushBuffer;
  102. Var
  103. WCount : Integer;
  104. P : PChar;
  105. begin
  106. P:=Pchar(FBuffer);
  107. Inc(P,FBufPos);
  108. WCount:=1;
  109. While (WCount<>0) and ((FBufSize-FBufPos)>0) do
  110. begin
  111. WCount:=FSource.Write(P^,FBufSize-FBufPos);
  112. Inc(P,WCount);
  113. Inc(FBufPos,WCount);
  114. end;
  115. If ((FBufSize-FBufPos)<=0) then
  116. begin
  117. FBufPos:=0;
  118. FBufSize:=0;
  119. end
  120. else
  121. BufferError(SErrCouldNotFLushBuffer);
  122. end;
  123. constructor TBufStream.Create(ASource: TStream; ACapacity: Integer);
  124. begin
  125. Inherited Create(ASource);
  126. SetCapacity(ACapacity);
  127. end;
  128. constructor TBufStream.Create(ASource: TStream);
  129. begin
  130. Create(ASource,DefaultBufferCapacity*1024);
  131. end;
  132. destructor TBufStream.Destroy;
  133. begin
  134. FBufSize:=0;
  135. SetCapacity(0);
  136. inherited Destroy;
  137. end;
  138. { TReadBufStream }
  139. function TReadBufStream.Seek(Offset: Longint; Origin: Word): Longint;
  140. var
  141. I: Integer;
  142. Buf: array [0..4095] of Char;
  143. begin
  144. // Emulate forward seek if possible.
  145. if ((Offset>=0) and (Origin = soFromCurrent)) or
  146. (((Offset-FTotalPos)>=0) and (Origin = soFromBeginning)) then
  147. begin
  148. if (Origin=soFromBeginning) then
  149. Dec(Offset,FTotalPos);
  150. if (Offset>0) then
  151. begin
  152. for I:=1 to (Offset div sizeof(Buf)) do
  153. ReadBuffer(Buf,sizeof(Buf));
  154. ReadBuffer(Buf, Offset mod sizeof(Buf));
  155. end;
  156. Result:=FTotalPos;
  157. end
  158. else
  159. BufferError(SErrInvalidSeek);
  160. end;
  161. function TReadBufStream.Read(var ABuffer; ACount: LongInt): Integer;
  162. Var
  163. P,PB : PChar;
  164. Avail,MSize,RCount : Integer;
  165. begin
  166. Result:=0;
  167. P:=PChar(@ABuffer);
  168. Avail:=1;
  169. While (Result<ACount) and (Avail>0) do
  170. begin
  171. If (FBufSize-FBufPos<=0) then
  172. FillBuffer;
  173. Avail:=FBufSize-FBufPos;
  174. If (Avail>0) then
  175. begin
  176. MSize:=ACount-Result;
  177. If (MSize>Avail) then
  178. MSize:=Avail;
  179. PB:=PChar(FBuffer);
  180. Inc(PB,FBufPos);
  181. Move(PB^,P^,MSIze);
  182. Inc(FBufPos,MSize);
  183. Inc(P,MSize);
  184. Inc(Result,MSize);
  185. end;
  186. end;
  187. Inc(FTotalPos,Result);
  188. end;
  189. function TReadBufStream.Write(const ABuffer; ACount: LongInt): Integer;
  190. begin
  191. BufferError(SErrReadOnlyStream);
  192. end;
  193. { TWriteBufStream }
  194. destructor TWriteBufStream.Destroy;
  195. begin
  196. FlushBuffer;
  197. inherited Destroy;
  198. end;
  199. function TWriteBufStream.Seek(Offset: Longint; Origin: Word): Longint;
  200. begin
  201. if (Offset=0) and (Origin=soFromCurrent) then
  202. Result := FTotalPos
  203. else
  204. BufferError(SErrInvalidSeek);
  205. end;
  206. function TWriteBufStream.Read(var ABuffer; ACount: LongInt): Integer;
  207. begin
  208. BufferError(SErrWriteOnlyStream);
  209. end;
  210. function TWriteBufStream.Write(const ABuffer; ACount: LongInt): Integer;
  211. Var
  212. P,PB : PChar;
  213. Avail,MSize,RCount : Integer;
  214. begin
  215. Result:=0;
  216. P:=PChar(@ABuffer);
  217. While (Result<ACount) do
  218. begin
  219. If (FBufSize=FCapacity) then
  220. FlushBuffer;
  221. Avail:=FCapacity-FBufSize;
  222. MSize:=ACount-Result;
  223. If (MSize>Avail) then
  224. MSize:=Avail;
  225. PB:=PChar(FBuffer);
  226. Inc(PB,FBufSize);
  227. Move(P^,PB^,MSIze);
  228. Inc(FBufSize,MSize);
  229. Inc(P,MSize);
  230. Inc(Result,MSize);
  231. end;
  232. Inc(FTotalPos,Result);
  233. end;
  234. end.