streams.inc 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {****************************************************************************}
  11. {* TStream *}
  12. {****************************************************************************}
  13. procedure TStream.ReadNotImplemented;
  14. begin
  15. raise EStreamError.CreateFmt(SStreamNoReading, [ClassName]) at get_caller_addr(get_frame);
  16. end;
  17. procedure TStream.WriteNotImplemented;
  18. begin
  19. raise EStreamError.CreateFmt(SStreamNoWriting, [ClassName]) at get_caller_addr(get_frame);
  20. end;
  21. function TStream.Read(var Buffer; Count: Longint): Longint;
  22. begin
  23. ReadNotImplemented;
  24. Result := 0;
  25. end;
  26. function TStream.Write(const Buffer; Count: Longint): Longint;
  27. begin
  28. WriteNotImplemented;
  29. Result := 0;
  30. end;
  31. function TStream.GetPosition: Int64;
  32. begin
  33. Result:=Seek(0,soCurrent);
  34. end;
  35. procedure TStream.SetPosition(const Pos: Int64);
  36. begin
  37. Seek(pos,soBeginning);
  38. end;
  39. procedure TStream.SetSize64(const NewSize: Int64);
  40. begin
  41. // Required because can't use overloaded functions in properties
  42. SetSize(NewSize);
  43. end;
  44. function TStream.GetSize: Int64;
  45. var
  46. p : int64;
  47. begin
  48. p:=Seek(0,soCurrent);
  49. GetSize:=Seek(0,soEnd);
  50. Seek(p,soBeginning);
  51. end;
  52. procedure TStream.SetSize(NewSize: Longint);
  53. begin
  54. // We do nothing. Pipe streams don't support this
  55. // As wel as possible read-ony streams !!
  56. end;
  57. procedure TStream.SetSize(const NewSize: Int64);
  58. begin
  59. // Backwards compatibility that calls the longint SetSize
  60. if (NewSize<Low(longint)) or
  61. (NewSize>High(longint)) then
  62. raise ERangeError.Create(SRangeError);
  63. SetSize(longint(NewSize));
  64. end;
  65. function TStream.Seek(Offset: Longint; Origin: Word): Longint;
  66. type
  67. TSeek64 = function(const offset:Int64;Origin:TSeekorigin):Int64 of object;
  68. var
  69. CurrSeek,
  70. TStreamSeek : TSeek64;
  71. CurrClass : TClass;
  72. begin
  73. // Redirect calls to 64bit Seek, but we can't call the 64bit Seek
  74. // from TStream, because then we end up in an infinite loop
  75. CurrSeek:=nil;
  76. CurrClass:=Classtype;
  77. while (CurrClass<>nil) and
  78. (CurrClass<>TStream) do
  79. CurrClass:=CurrClass.Classparent;
  80. if CurrClass<>nil then
  81. begin
  82. CurrSeek:[email protected];
  83. TStreamSeek:=@TStream(@CurrClass).Seek;
  84. if TMethod(TStreamSeek).Code=TMethod(CurrSeek).Code then
  85. CurrSeek:=nil;
  86. end;
  87. if CurrSeek<>nil then
  88. Result:=Seek(Int64(offset),TSeekOrigin(origin))
  89. else
  90. raise EStreamError.CreateFmt(SSeekNotImplemented,[ClassName]);
  91. end;
  92. procedure TStream.Discard(const Count: Int64);
  93. const
  94. CSmallSize =255;
  95. CLargeMaxBuffer =32*1024; // 32 KiB
  96. var
  97. Buffer: array[1..CSmallSize] of Byte;
  98. begin
  99. if Count=0 then
  100. Exit;
  101. if Count<=SizeOf(Buffer) then
  102. ReadBuffer(Buffer,Count)
  103. else
  104. DiscardLarge(Count,CLargeMaxBuffer);
  105. end;
  106. procedure TStream.DiscardLarge(Count: int64; const MaxBufferSize: Longint);
  107. var
  108. Buffer: array of Byte;
  109. begin
  110. if Count=0 then
  111. Exit;
  112. if Count>MaxBufferSize then
  113. SetLength(Buffer,MaxBufferSize)
  114. else
  115. SetLength(Buffer,Count);
  116. while (Count>=Length(Buffer)) do
  117. begin
  118. ReadBuffer(Buffer[0],Length(Buffer));
  119. Dec(Count,Length(Buffer));
  120. end;
  121. if Count>0 then
  122. ReadBuffer(Buffer[0],Count);
  123. end;
  124. procedure TStream.InvalidSeek;
  125. begin
  126. raise EStreamError.CreateFmt(SStreamInvalidSeek, [ClassName]) at get_caller_addr(get_frame);
  127. end;
  128. procedure TStream.FakeSeekForward(Offset: Int64; const Origin: TSeekOrigin; const Pos: Int64);
  129. var
  130. Buffer: Pointer;
  131. BufferSize, i: LongInt;
  132. begin
  133. if Origin=soBeginning then
  134. Dec(Offset,Pos);
  135. if (Offset<0) or (Origin=soEnd) then
  136. InvalidSeek;
  137. if Offset>0 then
  138. Discard(Offset);
  139. end;
  140. function TStream.Seek(const Offset: Int64; Origin: TSeekorigin): Int64;
  141. begin
  142. // Backwards compatibility that calls the longint Seek
  143. if (Offset<Low(longint)) or
  144. (Offset>High(longint)) then
  145. raise ERangeError.Create(SRangeError);
  146. Result:=Seek(longint(Offset),ord(Origin));
  147. end;
  148. procedure TStream.ReadBuffer(var Buffer; Count: Longint);
  149. begin
  150. if Read(Buffer,Count)<Count then
  151. Raise EReadError.Create(SReadError);
  152. end;
  153. procedure TStream.WriteBuffer(const Buffer; Count: Longint);
  154. begin
  155. if Write(Buffer,Count)<Count then
  156. Raise EWriteError.Create(SWriteError);
  157. end;
  158. function TStream.CopyFrom(Source: TStream; Count: Int64): Int64;
  159. var
  160. Buffer: Pointer;
  161. BufferSize, i: LongInt;
  162. const
  163. MaxSize = $20000;
  164. begin
  165. Result:=0;
  166. if Count=0 then
  167. Source.Position:=0; // This WILL fail for non-seekable streams...
  168. BufferSize:=MaxSize;
  169. if (Count>0) and (Count<BufferSize) then
  170. BufferSize:=Count; // do not allocate more than needed
  171. GetMem(Buffer,BufferSize);
  172. try
  173. if Count=0 then
  174. repeat
  175. i:=Source.Read(buffer^,BufferSize);
  176. if i>0 then
  177. WriteBuffer(buffer^,i);
  178. Inc(Result,i);
  179. until i<BufferSize
  180. else
  181. while Count>0 do
  182. begin
  183. if Count>BufferSize then
  184. i:=BufferSize
  185. else
  186. i:=Count;
  187. Source.ReadBuffer(buffer^,i);
  188. WriteBuffer(buffer^,i);
  189. Dec(count,i);
  190. Inc(Result,i);
  191. end;
  192. finally
  193. FreeMem(Buffer);
  194. end;
  195. end;
  196. function TStream.ReadComponent(Instance: TComponent): TComponent;
  197. var
  198. Reader: TReader;
  199. begin
  200. Reader := TReader.Create(Self, 4096);
  201. try
  202. Result := Reader.ReadRootComponent(Instance);
  203. finally
  204. Reader.Free;
  205. end;
  206. end;
  207. function TStream.ReadComponentRes(Instance: TComponent): TComponent;
  208. begin
  209. ReadResHeader;
  210. Result := ReadComponent(Instance);
  211. end;
  212. procedure TStream.WriteComponent(Instance: TComponent);
  213. begin
  214. WriteDescendent(Instance, nil);
  215. end;
  216. procedure TStream.WriteComponentRes(const ResName: string; Instance: TComponent);
  217. begin
  218. WriteDescendentRes(ResName, Instance, nil);
  219. end;
  220. procedure TStream.WriteDescendent(Instance, Ancestor: TComponent);
  221. var
  222. Driver : TAbstractObjectWriter;
  223. Writer : TWriter;
  224. begin
  225. Driver := TBinaryObjectWriter.Create(Self, 4096);
  226. Try
  227. Writer := TWriter.Create(Driver);
  228. Try
  229. Writer.WriteDescendent(Instance, Ancestor);
  230. Finally
  231. Writer.Destroy;
  232. end;
  233. Finally
  234. Driver.Free;
  235. end;
  236. end;
  237. procedure TStream.WriteDescendentRes(const ResName: string; Instance, Ancestor: TComponent);
  238. var
  239. FixupInfo: Integer;
  240. begin
  241. { Write a resource header }
  242. WriteResourceHeader(ResName, FixupInfo);
  243. { Write the instance itself }
  244. WriteDescendent(Instance, Ancestor);
  245. { Insert the correct resource size into the resource header }
  246. FixupResourceHeader(FixupInfo);
  247. end;
  248. procedure TStream.WriteResourceHeader(const ResName: string; {!!!: out} var FixupInfo: Integer);
  249. var
  250. ResType, Flags : word;
  251. begin
  252. ResType:=NtoLE(word($000A));
  253. Flags:=NtoLE(word($1030));
  254. { Note: This is a Windows 16 bit resource }
  255. { Numeric resource type }
  256. WriteByte($ff);
  257. { Application defined data }
  258. WriteWord(ResType);
  259. { write the name as asciiz }
  260. WriteBuffer(ResName[1],length(ResName));
  261. WriteByte(0);
  262. { Movable, Pure and Discardable }
  263. WriteWord(Flags);
  264. { Placeholder for the resource size }
  265. WriteDWord(0);
  266. { Return current stream position so that the resource size can be
  267. inserted later }
  268. FixupInfo := Position;
  269. end;
  270. procedure TStream.FixupResourceHeader(FixupInfo: Integer);
  271. var
  272. ResSize,TmpResSize : Integer;
  273. begin
  274. ResSize := Position - FixupInfo;
  275. TmpResSize := NtoLE(longword(ResSize));
  276. { Insert the correct resource size into the placeholder written by
  277. WriteResourceHeader }
  278. Position := FixupInfo - 4;
  279. WriteDWord(TmpResSize);
  280. { Seek back to the end of the resource }
  281. Position := FixupInfo + ResSize;
  282. end;
  283. procedure TStream.ReadResHeader;
  284. var
  285. ResType, Flags : word;
  286. begin
  287. try
  288. { Note: This is a Windows 16 bit resource }
  289. { application specific resource ? }
  290. if ReadByte<>$ff then
  291. raise EInvalidImage.Create(SInvalidImage);
  292. ResType:=LEtoN(ReadWord);
  293. if ResType<>$000a then
  294. raise EInvalidImage.Create(SInvalidImage);
  295. { read name }
  296. while ReadByte<>0 do
  297. ;
  298. { check the access specifier }
  299. Flags:=LEtoN(ReadWord);
  300. if Flags<>$1030 then
  301. raise EInvalidImage.Create(SInvalidImage);
  302. { ignore the size }
  303. ReadDWord;
  304. except
  305. on EInvalidImage do
  306. raise;
  307. else
  308. raise EInvalidImage.create(SInvalidImage);
  309. end;
  310. end;
  311. function TStream.ReadByte : Byte;
  312. var
  313. b : Byte;
  314. begin
  315. ReadBuffer(b,1);
  316. ReadByte:=b;
  317. end;
  318. function TStream.ReadWord : Word;
  319. var
  320. w : Word;
  321. begin
  322. ReadBuffer(w,2);
  323. ReadWord:=w;
  324. end;
  325. function TStream.ReadDWord : Cardinal;
  326. var
  327. d : Cardinal;
  328. begin
  329. ReadBuffer(d,4);
  330. ReadDWord:=d;
  331. end;
  332. function TStream.ReadQWord: QWord;
  333. var
  334. q: QWord;
  335. begin
  336. ReadBuffer(q,8);
  337. ReadQWord:=q;
  338. end;
  339. Function TStream.ReadAnsiString : String;
  340. Var
  341. TheSize : Longint;
  342. P : PByte ;
  343. begin
  344. ReadBuffer (TheSize,SizeOf(TheSize));
  345. SetLength(Result,TheSize);
  346. // Illegal typecast if no AnsiStrings defined.
  347. if TheSize>0 then
  348. begin
  349. ReadBuffer (Pointer(Result)^,TheSize);
  350. P:=Pointer(Result)+TheSize;
  351. p^:=0;
  352. end;
  353. end;
  354. Procedure TStream.WriteAnsiString (const S : String);
  355. Var L : Longint;
  356. begin
  357. L:=Length(S);
  358. WriteBuffer (L,SizeOf(L));
  359. WriteBuffer (Pointer(S)^,L);
  360. end;
  361. procedure TStream.WriteByte(b : Byte);
  362. begin
  363. WriteBuffer(b,1);
  364. end;
  365. procedure TStream.WriteWord(w : Word);
  366. begin
  367. WriteBuffer(w,2);
  368. end;
  369. procedure TStream.WriteDWord(d : Cardinal);
  370. begin
  371. WriteBuffer(d,4);
  372. end;
  373. procedure TStream.WriteQWord(q: QWord);
  374. begin
  375. WriteBuffer(q,8);
  376. end;
  377. {****************************************************************************}
  378. {* THandleStream *}
  379. {****************************************************************************}
  380. Constructor THandleStream.Create(AHandle: THandle);
  381. begin
  382. Inherited Create;
  383. FHandle:=AHandle;
  384. end;
  385. function THandleStream.Read(var Buffer; Count: Longint): Longint;
  386. begin
  387. Result:=FileRead(FHandle,Buffer,Count);
  388. If Result=-1 then Result:=0;
  389. end;
  390. function THandleStream.Write(const Buffer; Count: Longint): Longint;
  391. begin
  392. Result:=FileWrite (FHandle,Buffer,Count);
  393. If Result=-1 then Result:=0;
  394. end;
  395. Procedure THandleStream.SetSize(NewSize: Longint);
  396. begin
  397. SetSize(Int64(NewSize));
  398. end;
  399. Procedure THandleStream.SetSize(const NewSize: Int64);
  400. begin
  401. FileTruncate(FHandle,NewSize);
  402. end;
  403. function THandleStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  404. begin
  405. Result:=FileSeek(FHandle,Offset,ord(Origin));
  406. end;
  407. {****************************************************************************}
  408. {* TFileStream *}
  409. {****************************************************************************}
  410. constructor TFileStream.Create(const AFileName: string; Mode: Word);
  411. begin
  412. FFileName:=AFileName;
  413. If (Mode and fmCreate) > 0 then
  414. FHandle:=FileCreate(AFileName,Mode,438)
  415. else
  416. FHAndle:=FileOpen(AFileName,Mode);
  417. If (THandle(FHandle)=feInvalidHandle) then
  418. If Mode=fmcreate then
  419. raise EFCreateError.createfmt(SFCreateError,[AFileName])
  420. else
  421. raise EFOpenError.Createfmt(SFOpenError,[AFilename]);
  422. end;
  423. constructor TFileStream.Create(const AFileName: string; Mode: Word; Rights: Cardinal);
  424. begin
  425. FFileName:=AFileName;
  426. If (Mode and fmCreate) > 0 then
  427. FHandle:=FileCreate(AFileName,Mode,Rights)
  428. else
  429. FHAndle:=FileOpen(AFileName,Mode);
  430. If (THandle(FHandle)=feInvalidHandle) then
  431. If Mode=fmcreate then
  432. raise EFCreateError.createfmt(SFCreateError,[AFileName])
  433. else
  434. raise EFOpenError.Createfmt(SFOpenError,[AFilename]);
  435. end;
  436. destructor TFileStream.Destroy;
  437. begin
  438. FileClose(FHandle);
  439. end;
  440. {****************************************************************************}
  441. {* TCustomMemoryStream *}
  442. {****************************************************************************}
  443. procedure TCustomMemoryStream.SetPointer(Ptr: Pointer; ASize: PtrInt);
  444. begin
  445. FMemory:=Ptr;
  446. FSize:=ASize;
  447. end;
  448. function TCustomMemoryStream.GetSize: Int64;
  449. begin
  450. Result:=FSize;
  451. end;
  452. function TCustomMemoryStream.GetPosition: Int64;
  453. begin
  454. Result:=FPosition;
  455. end;
  456. function TCustomMemoryStream.Read(var Buffer; Count: LongInt): LongInt;
  457. begin
  458. Result:=0;
  459. If (FSize>0) and (FPosition<Fsize) and (FPosition>=0) then
  460. begin
  461. Result:=FSize-FPosition;
  462. If Result>Count then Result:=Count;
  463. Move ((FMemory+FPosition)^,Buffer,Result);
  464. FPosition:=Fposition+Result;
  465. end;
  466. end;
  467. function TCustomMemoryStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  468. begin
  469. Case Word(Origin) of
  470. soFromBeginning : FPosition:=Offset;
  471. soFromEnd : FPosition:=FSize+Offset;
  472. soFromCurrent : FPosition:=FPosition+Offset;
  473. end;
  474. Result:=FPosition;
  475. {$IFDEF DEBUG}
  476. if Result < 0 then
  477. raise Exception.Create('TCustomMemoryStream');
  478. {$ENDIF}
  479. end;
  480. procedure TCustomMemoryStream.SaveToStream(Stream: TStream);
  481. begin
  482. if FSize>0 then Stream.WriteBuffer (FMemory^,FSize);
  483. end;
  484. procedure TCustomMemoryStream.SaveToFile(const FileName: string);
  485. Var S : TFileStream;
  486. begin
  487. S:=TFileStream.Create (FileName,fmCreate);
  488. Try
  489. SaveToStream(S);
  490. finally
  491. S.free;
  492. end;
  493. end;
  494. {****************************************************************************}
  495. {* TMemoryStream *}
  496. {****************************************************************************}
  497. Const TMSGrow = 4096; { Use 4k blocks. }
  498. procedure TMemoryStream.SetCapacity(NewCapacity: PtrInt);
  499. begin
  500. SetPointer (Realloc(NewCapacity),Fsize);
  501. FCapacity:=NewCapacity;
  502. end;
  503. function TMemoryStream.Realloc(var NewCapacity: PtrInt): Pointer;
  504. begin
  505. If NewCapacity<0 Then
  506. NewCapacity:=0
  507. else
  508. begin
  509. // if growing, grow at least a quarter
  510. if (NewCapacity>FCapacity) and (NewCapacity < (5*FCapacity) div 4) then
  511. NewCapacity := (5*FCapacity) div 4;
  512. // round off to block size.
  513. NewCapacity := (NewCapacity + (TMSGrow-1)) and not (TMSGROW-1);
  514. end;
  515. // Only now check !
  516. If NewCapacity=FCapacity then
  517. Result:=FMemory
  518. else
  519. begin
  520. Result:=Reallocmem(FMemory,Newcapacity);
  521. If (Result=Nil) and (Newcapacity>0) then
  522. Raise EStreamError.Create(SMemoryStreamError);
  523. end;
  524. end;
  525. destructor TMemoryStream.Destroy;
  526. begin
  527. Clear;
  528. Inherited Destroy;
  529. end;
  530. procedure TMemoryStream.Clear;
  531. begin
  532. FSize:=0;
  533. FPosition:=0;
  534. SetCapacity (0);
  535. end;
  536. procedure TMemoryStream.LoadFromStream(Stream: TStream);
  537. begin
  538. Stream.Position:=0;
  539. SetSize(Stream.Size);
  540. If FSize>0 then Stream.ReadBuffer(FMemory^,FSize);
  541. end;
  542. procedure TMemoryStream.LoadFromFile(const FileName: string);
  543. Var S : TFileStream;
  544. begin
  545. S:=TFileStream.Create (FileName,fmOpenRead or fmShareDenyWrite);
  546. Try
  547. LoadFromStream(S);
  548. finally
  549. S.free;
  550. end;
  551. end;
  552. procedure TMemoryStream.SetSize({$ifdef CPU64}const{$endif CPU64} NewSize: PtrInt);
  553. begin
  554. SetCapacity (NewSize);
  555. FSize:=NewSize;
  556. IF FPosition>FSize then
  557. FPosition:=FSize;
  558. end;
  559. function TMemoryStream.Write(const Buffer; Count: LongInt): LongInt;
  560. Var NewPos : PtrInt;
  561. begin
  562. If (Count=0) or (FPosition<0) then
  563. exit(0);
  564. NewPos:=FPosition+Count;
  565. If NewPos>Fsize then
  566. begin
  567. IF NewPos>FCapacity then
  568. SetCapacity (NewPos);
  569. FSize:=Newpos;
  570. end;
  571. System.Move (Buffer,(FMemory+FPosition)^,Count);
  572. FPosition:=NewPos;
  573. Result:=Count;
  574. end;
  575. {****************************************************************************}
  576. {* TBytesStream *}
  577. {****************************************************************************}
  578. constructor TBytesStream.Create(const ABytes: TBytes);
  579. begin
  580. inherited Create;
  581. FBytes:=ABytes;
  582. SetPointer(Pointer(FBytes),Length(FBytes));
  583. FCapacity:=Length(FBytes);
  584. end;
  585. function TBytesStream.Realloc(var NewCapacity: PtrInt): Pointer;
  586. begin
  587. // adapt TMemoryStream code to use with dynamic array
  588. if NewCapacity<0 Then
  589. NewCapacity:=0
  590. else
  591. begin
  592. if (NewCapacity>Capacity) and (NewCapacity < (5*Capacity) div 4) then
  593. NewCapacity := (5*Capacity) div 4;
  594. NewCapacity := (NewCapacity + (TMSGrow-1)) and not (TMSGROW-1);
  595. end;
  596. if NewCapacity=Capacity then
  597. Result:=Pointer(FBytes)
  598. else
  599. begin
  600. SetLength(FBytes,Newcapacity);
  601. Result:=Pointer(FBytes);
  602. if (Result=nil) and (Newcapacity>0) then
  603. raise EStreamError.Create(SMemoryStreamError);
  604. end;
  605. end;
  606. {****************************************************************************}
  607. {* TStringStream *}
  608. {****************************************************************************}
  609. function TStringStream.GetSize: Int64;
  610. begin
  611. Result:=Length(FDataString);
  612. end;
  613. function TStringStream.GetPosition: Int64;
  614. begin
  615. Result:=FPosition;
  616. end;
  617. procedure TStringStream.SetSize(NewSize: Longint);
  618. begin
  619. Setlength(FDataString,NewSize);
  620. If FPosition>NewSize then FPosition:=NewSize;
  621. end;
  622. constructor TStringStream.Create(const AString: string);
  623. begin
  624. Inherited create;
  625. FDataString:=AString;
  626. end;
  627. function TStringStream.Read(var Buffer; Count: Longint): Longint;
  628. begin
  629. Result:=Length(FDataString)-FPosition;
  630. If Result>Count then Result:=Count;
  631. // This supposes FDataString to be of type AnsiString !
  632. Move (Pchar(FDataString)[FPosition],Buffer,Result);
  633. FPosition:=FPosition+Result;
  634. end;
  635. function TStringStream.ReadString(Count: Longint): string;
  636. Var NewLen : Longint;
  637. begin
  638. NewLen:=Length(FDataString)-FPosition;
  639. If NewLen>Count then NewLen:=Count;
  640. SetLength(Result,NewLen);
  641. Read (Pointer(Result)^,NewLen);
  642. end;
  643. function TStringStream.Seek(Offset: Longint; Origin: Word): Longint;
  644. begin
  645. Case Origin of
  646. soFromBeginning : FPosition:=Offset;
  647. soFromEnd : FPosition:=Length(FDataString)+Offset;
  648. soFromCurrent : FPosition:=FPosition+Offset;
  649. end;
  650. If FPosition>Length(FDataString) then
  651. FPosition:=Length(FDataString)
  652. else If FPosition<0 then
  653. FPosition:=0;
  654. Result:=FPosition;
  655. end;
  656. function TStringStream.Write(const Buffer; Count: Longint): Longint;
  657. begin
  658. Result:=Count;
  659. SetSize(FPosition+Count);
  660. // This supposes that FDataString is of type AnsiString)
  661. Move (Buffer,PChar(FDataString)[Fposition],Count);
  662. FPosition:=FPosition+Count;
  663. end;
  664. procedure TStringStream.WriteString(const AString: string);
  665. begin
  666. Write (PChar(Astring)[0],Length(AString));
  667. end;
  668. {****************************************************************************}
  669. {* TResourceStream *}
  670. {****************************************************************************}
  671. {$ifdef UNICODE}
  672. procedure TResourceStream.Initialize(Instance: THandle; Name, ResType: PWideChar; NameIsID: Boolean);
  673. begin
  674. Res:=FindResource(Instance, Name, ResType);
  675. if Res=0 then
  676. if NameIsID then
  677. raise EResNotFound.CreateFmt(SResNotFound,[IntToStr(PtrInt(Name))])
  678. else
  679. raise EResNotFound.CreateFmt(SResNotFound,[Name]);
  680. Handle:=LoadResource(Instance,Res);
  681. if Handle=0 then
  682. if NameIsID then
  683. raise EResNotFound.CreateFmt(SResNotFound,[IntToStr(PtrInt(Name))])
  684. else
  685. raise EResNotFound.CreateFmt(SResNotFound,[Name]);
  686. SetPointer(LockResource(Handle),SizeOfResource(Instance,Res));
  687. end;
  688. constructor TResourceStream.Create(Instance: THandle; const ResName: WideString; ResType: PWideChar);
  689. begin
  690. inherited create;
  691. Initialize(Instance,PWideChar(ResName),ResType,False);
  692. end;
  693. constructor TResourceStream.CreateFromID(Instance: THandle; ResID: Integer; ResType: PWideChar);
  694. begin
  695. inherited create;
  696. Initialize(Instance,PWideChar(ResID),ResType,True);
  697. end;
  698. {$else UNICODE}
  699. procedure TResourceStream.Initialize(Instance: THandle; Name, ResType: PChar; NameIsID: Boolean);
  700. begin
  701. Res:=FindResource(Instance, Name, ResType);
  702. if Res=0 then
  703. if NameIsID then
  704. raise EResNotFound.CreateFmt(SResNotFound,[IntToStr(PtrInt(Name))])
  705. else
  706. raise EResNotFound.CreateFmt(SResNotFound,[Name]);
  707. Handle:=LoadResource(Instance,Res);
  708. if Handle=0 then
  709. if NameIsID then
  710. raise EResNotFound.CreateFmt(SResNotFound,[IntToStr(PtrInt(Name))])
  711. else
  712. raise EResNotFound.CreateFmt(SResNotFound,[Name]);
  713. SetPointer(LockResource(Handle),SizeOfResource(Instance,Res));
  714. end;
  715. constructor TResourceStream.Create(Instance: THandle; const ResName: string; ResType: PChar);
  716. begin
  717. inherited create;
  718. Initialize(Instance,pchar(ResName),ResType,False);
  719. end;
  720. constructor TResourceStream.CreateFromID(Instance: THandle; ResID: Integer; ResType: PChar);
  721. begin
  722. inherited create;
  723. Initialize(Instance,pchar(PtrInt(ResID)),ResType,True);
  724. end;
  725. {$endif UNICODE}
  726. destructor TResourceStream.Destroy;
  727. begin
  728. UnlockResource(Handle);
  729. FreeResource(Handle);
  730. inherited destroy;
  731. end;
  732. {****************************************************************************}
  733. {* TOwnerStream *}
  734. {****************************************************************************}
  735. constructor TOwnerStream.Create(ASource: TStream);
  736. begin
  737. FSource:=ASource;
  738. end;
  739. destructor TOwnerStream.Destroy;
  740. begin
  741. If FOwner then
  742. FreeAndNil(FSource);
  743. inherited Destroy;
  744. end;
  745. {****************************************************************************}
  746. {* TStreamAdapter *}
  747. {****************************************************************************}
  748. constructor TStreamAdapter.Create(Stream: TStream; Ownership: TStreamOwnership = soReference);
  749. begin
  750. inherited Create;
  751. FStream:=Stream;
  752. FOwnership:=Ownership;
  753. m_bReverted:=false; // mantis 15003
  754. // http://www.tech-archive.net/Archive/German/microsoft.public.de.vc/2005-08/msg00791.html
  755. // http://code.google.com/p/ddab-lib/wiki/TPJIStreamWrapper
  756. end;
  757. destructor TStreamAdapter.Destroy;
  758. begin
  759. if StreamOwnership=soOwned then
  760. FreeAndNil(FStream);
  761. inherited Destroy;
  762. end;
  763. {$warnings off}
  764. function TStreamAdapter.Read(pv: Pointer; cb: DWORD; pcbRead: PDWORD): HResult; stdcall;
  765. var
  766. readcount: Longint;
  767. begin
  768. if m_bReverted then
  769. begin
  770. Result := STG_E_REVERTED;
  771. Exit;
  772. end;
  773. if pv = nil then
  774. begin
  775. Result := STG_E_INVALIDPOINTER;
  776. Exit;
  777. end;
  778. readcount := FStream.Read(pv^, cb);
  779. if pcbRead <> nil then pcbRead^ := readcount;
  780. Result := S_OK;
  781. end;
  782. function TStreamAdapter.Write(pv: Pointer; cb: DWORD; pcbWritten: PDWORD): HResult; stdcall;
  783. var
  784. writecount: Longint;
  785. begin
  786. if m_bReverted then
  787. begin
  788. Result := STG_E_REVERTED;
  789. Exit;
  790. end;
  791. if pv = nil then
  792. begin
  793. Result := STG_E_INVALIDPOINTER;
  794. Exit;
  795. end;
  796. writecount := FStream.Write(pv^, cb);
  797. if pcbWritten <> nil then pcbWritten^ := writecount;
  798. Result := S_OK;
  799. end;
  800. function TStreamAdapter.Seek(dlibMove: Largeint; dwOrigin: Longint; out libNewPosition: Largeint): HResult; stdcall;
  801. var
  802. newpos: Int64;
  803. begin
  804. if m_bReverted then
  805. begin
  806. Result := STG_E_REVERTED;
  807. Exit;
  808. end;
  809. case dwOrigin of
  810. STREAM_SEEK_SET: newpos := FStream.Seek(dlibMove, soBeginning);
  811. STREAM_SEEK_CUR: newpos := FStream.Seek(dlibMove, soCurrent);
  812. STREAM_SEEK_END: newpos := FStream.Seek(dlibMove, soEnd);
  813. else
  814. begin
  815. Result := STG_E_INVALIDFUNCTION;
  816. Exit;
  817. end;
  818. end;
  819. if @libNewPosition <> nil then
  820. libNewPosition := newpos;
  821. Result := S_OK;
  822. end;
  823. function TStreamAdapter.SetSize(libNewSize: Largeint): HResult; stdcall;
  824. begin
  825. if m_bReverted then
  826. begin
  827. Result := STG_E_REVERTED;
  828. Exit;
  829. end;
  830. if libNewSize<0 then
  831. begin
  832. Result := STG_E_INVALIDFUNCTION;
  833. Exit;
  834. end;
  835. try
  836. FStream.Size := libNewSize;
  837. Result := S_OK;
  838. except
  839. // TODO: return different error value according to exception like STG_E_MEDIUMFULL
  840. Result := E_FAIL;
  841. end;
  842. end;
  843. function TStreamAdapter.CopyTo(stm: IStream; cb: Largeint; out cbRead: Largeint; out cbWritten: Largeint): HResult; stdcall;
  844. var
  845. sz: dword;
  846. buffer : array[0..1023] of byte;
  847. begin
  848. if m_bReverted then
  849. begin
  850. Result := STG_E_REVERTED;
  851. Exit;
  852. end;
  853. // the method is similar to TStream.CopyFrom => use CopyFrom implementation
  854. cbWritten := 0;
  855. cbRead := 0;
  856. while cb > 0 do
  857. begin
  858. if (cb > sizeof(buffer)) then
  859. sz := sizeof(Buffer)
  860. else
  861. sz := cb;
  862. sz := FStream.Read(buffer, sz);
  863. inc(cbRead, sz);
  864. stm.Write(@buffer[0], sz, @sz);
  865. inc(cbWritten, sz);
  866. if sz = 0 then
  867. begin
  868. Result := E_FAIL;
  869. Exit;
  870. end;
  871. dec(cb, sz);
  872. end;
  873. Result := S_OK;
  874. end;
  875. function TStreamAdapter.Commit(grfCommitFlags: Longint): HResult; stdcall;
  876. begin
  877. if m_bReverted then
  878. Result := STG_E_REVERTED
  879. else
  880. Result := S_OK;
  881. end;
  882. function TStreamAdapter.Revert: HResult; stdcall;
  883. begin
  884. m_bReverted := True;
  885. Result := S_OK;
  886. end;
  887. function TStreamAdapter.LockRegion(libOffset: Largeint; cb: Largeint; dwLockType: Longint): HResult; stdcall;
  888. begin
  889. Result := STG_E_INVALIDFUNCTION;
  890. end;
  891. function TStreamAdapter.UnlockRegion(libOffset: Largeint; cb: Largeint; dwLockType: Longint): HResult; stdcall;
  892. begin
  893. Result := STG_E_INVALIDFUNCTION;
  894. end;
  895. function TStreamAdapter.Stat(out statstg: TStatStg; grfStatFlag: Longint): HResult; stdcall;
  896. begin
  897. if m_bReverted then
  898. begin
  899. Result := STG_E_REVERTED;
  900. Exit;
  901. end;
  902. if grfStatFlag in [STATFLAG_DEFAULT,STATFLAG_NOOPEN,STATFLAG_NONAME] then
  903. begin
  904. if @statstg <> nil then
  905. begin
  906. fillchar(statstg, sizeof(TStatStg),#0);
  907. { //TODO handle pwcsName
  908. if grfStatFlag = STATFLAG_DEFAULT then
  909. runerror(217) //Result :={$ifdef windows} STG_E_INVALIDFLAG{$else}E_INVALID_FLAG{$endif}
  910. }
  911. statstg.dwType := STGTY_STREAM;
  912. statstg.cbSize := FStream.Size;
  913. statstg.grfLocksSupported := LOCK_WRITE;
  914. end;
  915. Result := S_OK;
  916. end else
  917. Result := STG_E_INVALIDFLAG
  918. end;
  919. function TStreamAdapter.Clone(out stm: IStream): HResult; stdcall;
  920. begin
  921. if m_bReverted then
  922. begin
  923. Result := STG_E_REVERTED;
  924. Exit;
  925. end;
  926. // don't raise an exception here return error value that function is not implemented
  927. // to implement this we need a clone method for TStream class
  928. Result := STG_E_UNIMPLEMENTEDFUNCTION;
  929. end;
  930. constructor TProxyStream.Create(const Stream: IStream);
  931. begin
  932. FStream := Stream;
  933. end;
  934. function TProxyStream.Read(var Buffer; Count: Longint): Longint;
  935. begin
  936. Check(FStream.Read(@Buffer, Count, @Result));
  937. end;
  938. function TProxyStream. Seek(const Offset: int64; Origin: TSeekOrigin): int64;
  939. begin
  940. Check(FStream.Seek(Offset, ord(Origin), result));
  941. end;
  942. function TProxyStream.Write(const Buffer; Count: Longint): Longint;
  943. begin
  944. Check(FStream.Write(@Buffer, Count, @Result));
  945. end;
  946. function TProxyStream.GetIStream: IStream;
  947. begin
  948. Result := FStream;
  949. end;
  950. procedure TProxyStream.Check(err:integer);
  951. var e : EInOutError;
  952. begin
  953. e:= EInOutError.Create('Proxystream.Check');
  954. e.Errorcode:=err;
  955. raise e;
  956. end;
  957. {$warnings on}