resdatastream.pp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2008 by Giulio Bernardi
  4. Stream classes to provide copy-on-write functionality
  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. {$IFNDEF FPC_DOTTEDUNITS}
  12. unit resdatastream;
  13. {$ENDIF FPC_DOTTEDUNITS}
  14. {$MODE OBJFPC}
  15. interface
  16. {$IFDEF FPC_DOTTEDUNITS}
  17. uses System.Classes, System.SysUtils, System.Resources.Resource;
  18. {$ELSE FPC_DOTTEDUNITS}
  19. uses Classes, SysUtils, resource;
  20. {$ENDIF FPC_DOTTEDUNITS}
  21. type
  22. TCachedDataStream = class (TStream)
  23. private
  24. protected
  25. fStream : TStream;
  26. fSize : int64;
  27. fPosition : int64;
  28. function GetPosition: Int64; override;
  29. procedure SetPosition(const Pos: Int64); override;
  30. function GetSize: Int64; override;
  31. procedure SetSize64(const NewSize: Int64); override;
  32. public
  33. constructor Create(aStream : TStream; aResource : TAbstractResource; aSize : int64); virtual;
  34. function Write(const Buffer; Count: Longint): Longint; override;
  35. function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
  36. end;
  37. { TCachedResourceDataStream }
  38. TCachedResourceDataStream = class (TCachedDataStream)
  39. private
  40. fOffset : int64;
  41. protected
  42. public
  43. constructor Create(aStream : TStream; aResource : TAbstractResource; aSize : int64); override;
  44. function Read(var Buffer; Count: Longint): Longint; override;
  45. end;
  46. TCachedStreamClass = class of TCachedDataStream;
  47. TUnderlyingStreamType = (usCached, usMemory, usCustom);
  48. { TResourceDataStream }
  49. TResourceDataStream = class(TStream)
  50. private
  51. fStream : TStream;
  52. fStreamType : TUnderlyingStreamType;
  53. fResource : TAbstractResource;
  54. procedure CheckChangeStream;
  55. function GetCached : boolean;
  56. procedure SetCached(aValue : boolean);
  57. protected
  58. function GetPosition: Int64; override;
  59. procedure SetPosition(const Pos: Int64); override;
  60. function GetSize: Int64; override;
  61. procedure SetSize64(const NewSize: Int64); override;
  62. public
  63. constructor Create(aStream : TStream; aResource : TAbstractResource; aSize : int64; aClass: TCachedStreamClass);
  64. destructor Destroy; override;
  65. function Compare(aStream : TStream) : boolean;
  66. procedure SetCustomStream(aStream : TStream);
  67. function Read(var Buffer; Count: Longint): Longint; override;
  68. function Write(const Buffer; Count: Longint): Longint; override;
  69. function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
  70. property Cached : boolean read GetCached write SetCached;
  71. end;
  72. implementation
  73. { TCachedDataStream }
  74. function TCachedDataStream.GetPosition: Int64;
  75. begin
  76. Result:=fPosition;
  77. end;
  78. procedure TCachedDataStream.SetPosition(const Pos: Int64);
  79. begin
  80. fPosition:=Pos;
  81. end;
  82. function TCachedDataStream.GetSize: Int64;
  83. begin
  84. Result:=fSize;
  85. end;
  86. procedure TCachedDataStream.SetSize64(const NewSize: Int64);
  87. begin
  88. raise EInvalidOperation.Create('');
  89. end;
  90. constructor TCachedDataStream.Create(aStream: TStream; aResource : TAbstractResource; aSize : int64);
  91. begin
  92. fStream:=aStream;
  93. fSize:=aSize;
  94. fPosition:=0;
  95. end;
  96. function TCachedDataStream.Write(const Buffer; Count: Longint): Longint;
  97. begin
  98. raise EInvalidOperation.Create('');
  99. end;
  100. function TCachedDataStream.Seek(const Offset: Int64; Origin: TSeekOrigin
  101. ): Int64;
  102. var newpos : int64;
  103. begin
  104. case Origin of
  105. soBeginning : newpos:=Offset;
  106. soCurrent : newpos:=Position+Offset;
  107. soEnd : newpos:=fSize+Offset;
  108. end;
  109. SetPosition(newpos);
  110. Result:=Position;
  111. end;
  112. { TCachedResourceDataStream }
  113. constructor TCachedResourceDataStream.Create(aStream: TStream; aResource : TAbstractResource; aSize : int64);
  114. begin
  115. inherited Create(aStream,aResource,aSize);
  116. fOffset:=fStream.Position;
  117. end;
  118. function TCachedResourceDataStream.Read(var Buffer; Count: Longint): Longint;
  119. var oldpos : int64;
  120. begin
  121. Result:=fSize-Position;
  122. if Count<Result then Result:=Count;
  123. if Result<0 then Result:=0;
  124. if Result>0 then
  125. begin
  126. oldpos:=fStream.Position;
  127. fStream.Position:=Position+fOffset;
  128. Result:=fStream.Read(Buffer,Result);
  129. fPosition:=fStream.Position-fOffset;
  130. fStream.Position:=oldpos;
  131. end;
  132. end;
  133. { TResourceDataStream }
  134. procedure TResourceDataStream.CheckChangeStream;
  135. var NewStream : TMemoryStream;
  136. oldpos : int64;
  137. begin
  138. if fStreamType = usCached then
  139. begin
  140. NewStream:=TMemoryStream.Create;
  141. try
  142. oldpos:=fStream.Position;
  143. fStream.Position:=0;
  144. NewStream.CopyFrom(fStream,fStream.Size);
  145. NewStream.Position:=oldpos;
  146. except
  147. NewStream.Free;
  148. raise;
  149. end;
  150. fStream.Free;
  151. fStream:=NewStream;
  152. fStreamType:=usMemory;
  153. end;
  154. end;
  155. function TResourceDataStream.GetCached: boolean;
  156. begin
  157. Result:=fStreamType = usCached;
  158. end;
  159. procedure TResourceDataStream.SetCached(aValue: boolean);
  160. begin
  161. if aValue=false then CheckChangeStream;
  162. end;
  163. function TResourceDataStream.GetPosition: Int64;
  164. begin
  165. Result:=fStream.Position;
  166. end;
  167. procedure TResourceDataStream.SetPosition(const Pos: Int64);
  168. begin
  169. fStream.Position:=Pos;
  170. end;
  171. function TResourceDataStream.GetSize: Int64;
  172. begin
  173. Result:=fStream.Size;
  174. end;
  175. procedure TResourceDataStream.SetSize64(const NewSize: Int64);
  176. begin
  177. CheckChangeStream;
  178. fStream.Size:=NewSize;
  179. end;
  180. constructor TResourceDataStream.Create(aStream: TStream; aResource :
  181. TAbstractResource; aSize : int64; aClass: TCachedStreamClass);
  182. begin
  183. if aStream=nil then fStreamType:=usMemory
  184. else fStreamType:=usCached;
  185. case fStreamType of
  186. usMemory : fStream:=TMemoryStream.Create;
  187. usCached : fStream:=aClass.Create(aStream,aResource,aSize);
  188. end;
  189. fResource:=aResource;
  190. end;
  191. destructor TResourceDataStream.Destroy;
  192. begin
  193. if fStreamType<>usCustom then fStream.Free;
  194. end;
  195. function TResourceDataStream.Compare(aStream : TStream) : boolean;
  196. var tmp1, tmp2 : PtrUint;
  197. b1,b2 : byte;
  198. oldpos1,oldpos2 : int64;
  199. tocompare : longword;
  200. begin
  201. Result:=aStream=self;
  202. if Result then exit;
  203. Result:=aStream<>nil;
  204. if not Result then exit;
  205. Result:=Size=aStream.Size;
  206. if not Result then exit;
  207. oldpos1:=Position;
  208. oldpos2:=aStream.Position;
  209. Position:=0;
  210. aStream.Position:=0;
  211. tocompare:=Size;
  212. while tocompare >= sizeof(PtrUInt) do
  213. begin
  214. ReadBuffer(tmp1,sizeof(PtrUInt));
  215. aStream.ReadBuffer(tmp2,sizeof(PtrUInt));
  216. Result:=tmp1=tmp2;
  217. if not result then
  218. begin
  219. tocompare:=0;
  220. break;
  221. end;
  222. dec(tocompare,sizeof(PtrUInt));
  223. end;
  224. while tocompare > 0 do
  225. begin
  226. ReadBuffer(b1,1);
  227. aStream.ReadBuffer(b2,1);
  228. Result:=b1=b2;
  229. if not result then
  230. break;
  231. dec(tocompare);
  232. end;
  233. Position:=oldpos1;
  234. aStream.Position:=oldpos2;
  235. end;
  236. procedure TResourceDataStream.SetCustomStream(aStream: TStream);
  237. begin
  238. if fStreamType<>usCustom then fStream.Free;
  239. if aStream=nil then
  240. begin
  241. fStream:=TMemoryStream.Create;
  242. fStreamType:=usMemory;
  243. end
  244. else
  245. begin
  246. fStreamType:=usCustom;
  247. fStream:=aStream;
  248. end;
  249. end;
  250. function TResourceDataStream.Read(var Buffer; Count: Longint): Longint;
  251. begin
  252. Result:=fStream.Read(Buffer,Count);
  253. end;
  254. function TResourceDataStream.Write(const Buffer; Count: Longint): Longint;
  255. begin
  256. CheckChangeStream;
  257. Result:=fStream.Write(Buffer,Count);
  258. end;
  259. function TResourceDataStream.Seek(const Offset: Int64; Origin: TSeekOrigin
  260. ): Int64;
  261. var newpos : int64;
  262. begin
  263. case Origin of
  264. soBeginning : newpos:=Offset;
  265. soCurrent : newpos:=Position+Offset;
  266. soEnd : newpos:=Size+Offset;
  267. end;
  268. SetPosition(newpos);
  269. Result:=Position;
  270. end;
  271. end.