bufstream.pp 6.1 KB

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