streams.inc 29 KB

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