ImagingIO.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. {
  2. Vampyre Imaging Library
  3. by Marek Mauder
  4. https://github.com/galfar/imaginglib
  5. https://imaginglib.sourceforge.io
  6. - - - - -
  7. This Source Code Form is subject to the terms of the Mozilla Public
  8. License, v. 2.0. If a copy of the MPL was not distributed with this
  9. file, You can obtain one at https://mozilla.org/MPL/2.0.
  10. }
  11. { This unit contains default IO functions for reading from/writing to
  12. files, streams and memory.}
  13. unit ImagingIO;
  14. {$I ImagingOptions.inc}
  15. interface
  16. uses
  17. SysUtils, Classes, ImagingTypes, Imaging, ImagingUtility;
  18. type
  19. TMemoryIORec = record
  20. Data: ImagingUtility.PByteArray;
  21. Position: LongInt;
  22. Size: LongInt;
  23. end;
  24. PMemoryIORec = ^TMemoryIORec;
  25. var
  26. OriginalFileIO: TIOFunctions;
  27. FileIO: TIOFunctions;
  28. StreamIO: TIOFunctions;
  29. MemoryIO: TIOFunctions;
  30. { Helper function that returns size of input (from current position to the end)
  31. represented by Handle (and opened and operated on by members of IOFunctions).}
  32. function GetInputSize(const IOFunctions: TIOFunctions; Handle: TImagingHandle): Int64;
  33. { Helper function that initializes TMemoryIORec with given params.}
  34. function PrepareMemIO(Data: Pointer; Size: LongInt): TMemoryIORec;
  35. { Reads one text line from input (CR+LF, CR, or LF as line delimiter).}
  36. function ReadLine(const IOFunctions: TIOFunctions; Handle: TImagingHandle;
  37. out Line: AnsiString; FailOnControlChars: Boolean = False): Boolean;
  38. { Writes one text line to input with optional line delimiter.}
  39. procedure WriteLine(const IOFunctions: TIOFunctions; Handle: TImagingHandle;
  40. const Line: AnsiString; const LineEnding: AnsiString = sLineBreak);
  41. type
  42. TReadMemoryStream = class(TCustomMemoryStream)
  43. public
  44. constructor Create(Data: Pointer; Size: Integer);
  45. class function CreateFromIOHandle(const IOFunctions: TIOFunctions; Handle: TImagingHandle): TReadMemoryStream;
  46. end;
  47. TImagingIOStream = class(TStream)
  48. private
  49. FIO: TIOFunctions;
  50. FHandle: TImagingHandle;
  51. public
  52. constructor Create(const IOFunctions: TIOFunctions; Handle: TImagingHandle);
  53. end;
  54. implementation
  55. const
  56. DefaultBufferSize = 16 * 1024;
  57. type
  58. { Based on TaaBufferedStream
  59. Copyright (c) Julian M Bucknall 1997, 1999 }
  60. TBufferedStream = class
  61. private
  62. FBuffer: PByteArray;
  63. FBufSize: Integer;
  64. FBufStart: Integer;
  65. FBufPos: Integer;
  66. FBytesInBuf: Integer;
  67. FSize: Integer;
  68. FDirty: Boolean;
  69. FStream: TStream;
  70. function GetPosition: Integer;
  71. function GetSize: Integer;
  72. procedure ReadBuffer;
  73. procedure WriteBuffer;
  74. procedure SetPosition(const Value: Integer);
  75. public
  76. constructor Create(AStream: TStream);
  77. destructor Destroy; override;
  78. function Read(var Buffer; Count: Integer): Integer;
  79. function Write(const Buffer; Count: Integer): Integer;
  80. function Seek(Offset: Integer; Origin: Word): Integer;
  81. procedure Commit;
  82. property Stream: TStream read FStream;
  83. property Position: Integer read GetPosition write SetPosition;
  84. property Size: Integer read GetSize;
  85. end;
  86. constructor TBufferedStream.Create(AStream: TStream);
  87. begin
  88. inherited Create;
  89. FStream := AStream;
  90. FBufSize := DefaultBufferSize;
  91. GetMem(FBuffer, FBufSize);
  92. FBufPos := 0;
  93. FBytesInBuf := 0;
  94. FBufStart := 0;
  95. FDirty := False;
  96. FSize := AStream.Size;
  97. end;
  98. destructor TBufferedStream.Destroy;
  99. begin
  100. if FBuffer <> nil then
  101. begin
  102. Commit;
  103. FreeMem(FBuffer);
  104. end;
  105. FStream.Position := Position; // Make sure source stream has right position
  106. inherited Destroy;
  107. end;
  108. function TBufferedStream.GetPosition: Integer;
  109. begin
  110. Result := FBufStart + FBufPos;
  111. end;
  112. procedure TBufferedStream.SetPosition(const Value: Integer);
  113. begin
  114. Seek(Value, soFromCurrent);
  115. end;
  116. function TBufferedStream.GetSize: Integer;
  117. begin
  118. Result := FSize;
  119. end;
  120. procedure TBufferedStream.ReadBuffer;
  121. var
  122. SeekResult: Integer;
  123. begin
  124. SeekResult := FStream.Seek(FBufStart, soBeginning);
  125. if SeekResult = -1 then
  126. raise Exception.Create('TBufferedStream.ReadBuffer: seek failed');
  127. FBytesInBuf := FStream.Read(FBuffer^, FBufSize);
  128. if FBytesInBuf <= 0 then
  129. raise Exception.Create('TBufferedStream.ReadBuffer: read failed');
  130. end;
  131. procedure TBufferedStream.WriteBuffer;
  132. var
  133. SeekResult: Integer;
  134. BytesWritten: Integer;
  135. begin
  136. SeekResult := FStream.Seek(FBufStart, soBeginning);
  137. if SeekResult = -1 then
  138. raise Exception.Create('TBufferedStream.WriteBuffer: seek failed');
  139. BytesWritten := FStream.Write(FBuffer^, FBytesInBuf);
  140. if BytesWritten <> FBytesInBuf then
  141. raise Exception.Create('TBufferedStream.WriteBuffer: write failed');
  142. end;
  143. procedure TBufferedStream.Commit;
  144. begin
  145. if FDirty then
  146. begin
  147. WriteBuffer;
  148. FDirty := False;
  149. end;
  150. end;
  151. function TBufferedStream.Read(var Buffer; Count: Integer): Integer;
  152. var
  153. BufAsBytes: TByteArray absolute Buffer;
  154. BufIdx, BytesToGo, BytesToRead: Integer;
  155. begin
  156. // Calculate the actual number of bytes we can read - this depends on
  157. // the current position and size of the stream as well as the number
  158. // of bytes requested.
  159. BytesToGo := Count;
  160. if FSize < (FBufStart + FBufPos + Count) then
  161. BytesToGo := FSize - (FBufStart + FBufPos);
  162. if BytesToGo <= 0 then
  163. begin
  164. Result := 0;
  165. Exit;
  166. end;
  167. // Remember to return the result of our calculation
  168. Result := BytesToGo;
  169. BufIdx := 0;
  170. if FBytesInBuf = 0 then
  171. ReadBuffer;
  172. // Calculate the number of bytes we can read prior to the loop
  173. BytesToRead := FBytesInBuf - FBufPos;
  174. if BytesToRead > BytesToGo then
  175. BytesToRead := BytesToGo;
  176. // Copy from the stream buffer to the caller's buffer
  177. Move(FBuffer^[FBufPos], BufAsBytes[BufIdx], BytesToRead);
  178. // Calculate the number of bytes still to read}
  179. Dec(BytesToGo, BytesToRead);
  180. // while we have bytes to read, read them
  181. while BytesToGo > 0 do
  182. begin
  183. Inc(BufIdx, BytesToRead);
  184. // As we've exhausted this buffer-full, advance to the next, check
  185. // to see whether we need to write the buffer out first
  186. if FDirty then
  187. begin
  188. WriteBuffer;
  189. FDirty := false;
  190. end;
  191. Inc(FBufStart, FBufSize);
  192. FBufPos := 0;
  193. ReadBuffer;
  194. // Calculate the number of bytes we can read in this cycle
  195. BytesToRead := FBytesInBuf;
  196. if BytesToRead > BytesToGo then
  197. BytesToRead := BytesToGo;
  198. // Copy from the stream buffer to the caller's buffer
  199. Move(FBuffer^, BufAsBytes[BufIdx], BytesToRead);
  200. // Calculate the number of bytes still to read
  201. Dec(BytesToGo, BytesToRead);
  202. end;
  203. // Remember our new position
  204. Inc(FBufPos, BytesToRead);
  205. if FBufPos = FBufSize then
  206. begin
  207. Inc(FBufStart, FBufSize);
  208. FBufPos := 0;
  209. FBytesInBuf := 0;
  210. end;
  211. end;
  212. function TBufferedStream.Seek(Offset: Integer; Origin: Word): Integer;
  213. var
  214. NewBufStart, NewPos: Integer;
  215. begin
  216. // Calculate the new position
  217. case Origin of
  218. soFromBeginning : NewPos := Offset;
  219. soFromCurrent : NewPos := FBufStart + FBufPos + Offset;
  220. soFromEnd : NewPos := FSize + Offset;
  221. else
  222. raise Exception.Create('TBufferedStream.Seek: invalid origin');
  223. end;
  224. if (NewPos < 0) or (NewPos > FSize) then
  225. begin
  226. //NewPos := ClampInt(NewPos, 0, FSize); don't do this - for writing
  227. end;
  228. // Calculate which page of the file we need to be at
  229. NewBufStart := NewPos and not Pred(FBufSize);
  230. // If the new page is different than the old, mark the buffer as being
  231. // ready to be replenished, and if need be write out any dirty data
  232. if NewBufStart <> FBufStart then
  233. begin
  234. if FDirty then
  235. begin
  236. WriteBuffer;
  237. FDirty := False;
  238. end;
  239. FBufStart := NewBufStart;
  240. FBytesInBuf := 0;
  241. end;
  242. // Save the new position
  243. FBufPos := NewPos - NewBufStart;
  244. Result := NewPos;
  245. end;
  246. function TBufferedStream.Write(const Buffer; Count: Integer): Integer;
  247. var
  248. BufAsBytes: TByteArray absolute Buffer;
  249. BufIdx, BytesToGo, BytesToWrite: Integer;
  250. begin
  251. // When we write to this stream we always assume that we can write the
  252. // requested number of bytes: if we can't (eg, the disk is full) we'll
  253. // get an exception somewhere eventually.
  254. BytesToGo := Count;
  255. // Remember to return the result of our calculation
  256. Result := BytesToGo;
  257. BufIdx := 0;
  258. if (FBytesInBuf = 0) and (FSize > FBufStart) then
  259. ReadBuffer;
  260. // Calculate the number of bytes we can write prior to the loop
  261. BytesToWrite := FBufSize - FBufPos;
  262. if BytesToWrite > BytesToGo then
  263. BytesToWrite := BytesToGo;
  264. // Copy from the caller's buffer to the stream buffer
  265. Move(BufAsBytes[BufIdx], FBuffer^[FBufPos], BytesToWrite);
  266. // Mark our stream buffer as requiring a save to the actual stream,
  267. // note that this will suffice for the rest of the routine as well: no
  268. // inner routine will turn off the dirty flag.
  269. FDirty := True;
  270. // Calculate the number of bytes still to write
  271. Dec(BytesToGo, BytesToWrite);
  272. // While we have bytes to write, write them
  273. while BytesToGo > 0 do
  274. begin
  275. Inc(BufIdx, BytesToWrite);
  276. // As we've filled this buffer, write it out to the actual stream
  277. // and advance to the next buffer, reading it if required
  278. FBytesInBuf := FBufSize;
  279. WriteBuffer;
  280. Inc(FBufStart, FBufSize);
  281. FBufPos := 0;
  282. FBytesInBuf := 0;
  283. if FSize > FBufStart then
  284. ReadBuffer;
  285. // Calculate the number of bytes we can write in this cycle
  286. BytesToWrite := FBufSize;
  287. if BytesToWrite > BytesToGo then
  288. BytesToWrite := BytesToGo;
  289. // Copy from the caller's buffer to our buffer
  290. Move(BufAsBytes[BufIdx], FBuffer^, BytesToWrite);
  291. // Calculate the number of bytes still to write
  292. Dec(BytesToGo, BytesToWrite);
  293. end;
  294. // Remember our new position
  295. Inc(FBufPos, BytesToWrite);
  296. // Make sure the count of valid bytes is correct
  297. if FBytesInBuf < FBufPos then
  298. FBytesInBuf := FBufPos;
  299. // Make sure the stream size is correct
  300. if FSize < (FBufStart + FBytesInBuf) then
  301. FSize := FBufStart + FBytesInBuf;
  302. // If we're at the end of the buffer, write it out and advance to the
  303. // start of the next page
  304. if FBufPos = FBufSize then
  305. begin
  306. WriteBuffer;
  307. FDirty := False;
  308. Inc(FBufStart, FBufSize);
  309. FBufPos := 0;
  310. FBytesInBuf := 0;
  311. end;
  312. end;
  313. { File IO functions }
  314. function FileOpen(FileName: PChar; Mode: TOpenMode): TImagingHandle; cdecl;
  315. var
  316. Stream: TStream;
  317. begin
  318. Stream := nil;
  319. case Mode of
  320. omReadOnly: Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
  321. omCreate: Stream := TFileStream.Create(FileName, fmCreate);
  322. omReadWrite:
  323. begin
  324. if FileExists(FileName) then
  325. Stream := TFileStream.Create(FileName, fmOpenReadWrite or fmShareExclusive)
  326. else
  327. Stream := TFileStream.Create(FileName, fmCreate);
  328. end;
  329. end;
  330. Assert(Stream <> nil);
  331. Result := TBufferedStream.Create(Stream);
  332. end;
  333. procedure FileClose(Handle: TImagingHandle); cdecl;
  334. var
  335. Stream: TStream;
  336. begin
  337. Stream := TBufferedStream(Handle).Stream;
  338. TBufferedStream(Handle).Free;
  339. Stream.Free;
  340. end;
  341. function FileEof(Handle: TImagingHandle): Boolean; cdecl;
  342. begin
  343. Result := TBufferedStream(Handle).Position = TBufferedStream(Handle).Size;
  344. end;
  345. function FileSeek(Handle: TImagingHandle; Offset: Int64; Mode: TSeekMode): Int64; cdecl;
  346. begin
  347. Result := TBufferedStream(Handle).Seek(Offset, LongInt(Mode));
  348. end;
  349. function FileTell(Handle: TImagingHandle): Int64; cdecl;
  350. begin
  351. Result := TBufferedStream(Handle).Position;
  352. end;
  353. function FileRead(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): LongInt; cdecl;
  354. begin
  355. Result := TBufferedStream(Handle).Read(Buffer^, Count);
  356. end;
  357. function FileWrite(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): LongInt; cdecl;
  358. begin
  359. Result := TBufferedStream(Handle).Write(Buffer^, Count);
  360. end;
  361. { Stream IO functions }
  362. function StreamOpen(FileName: PChar; Mode: TOpenMode): TImagingHandle; cdecl;
  363. begin
  364. Result := FileName;
  365. end;
  366. procedure StreamClose(Handle: TImagingHandle); cdecl;
  367. begin
  368. end;
  369. function StreamEof(Handle: TImagingHandle): Boolean; cdecl;
  370. begin
  371. Result := TStream(Handle).Position = TStream(Handle).Size;
  372. end;
  373. function StreamSeek(Handle: TImagingHandle; Offset: Int64; Mode: TSeekMode): Int64; cdecl;
  374. begin
  375. Result := TStream(Handle).Seek(Offset, Word(Mode));
  376. end;
  377. function StreamTell(Handle: TImagingHandle): Int64; cdecl;
  378. begin
  379. Result := TStream(Handle).Position;
  380. end;
  381. function StreamRead(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt):
  382. LongInt; cdecl;
  383. begin
  384. Result := TStream(Handle).Read(Buffer^, Count);
  385. end;
  386. function StreamWrite(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): LongInt; cdecl;
  387. begin
  388. Result := TStream(Handle).Write(Buffer^, Count);
  389. end;
  390. { Memory IO functions }
  391. function MemoryOpen(FileName: PChar; Mode: TOpenMode): TImagingHandle; cdecl;
  392. begin
  393. Result := FileName;
  394. end;
  395. procedure MemoryClose(Handle: TImagingHandle); cdecl;
  396. begin
  397. end;
  398. function MemoryEof(Handle: TImagingHandle): Boolean; cdecl;
  399. begin
  400. Result := PMemoryIORec(Handle).Position = PMemoryIORec(Handle).Size;
  401. end;
  402. function MemorySeek(Handle: TImagingHandle; Offset: Int64; Mode: TSeekMode): Int64; cdecl;
  403. begin
  404. Result := PMemoryIORec(Handle).Position;
  405. case Mode of
  406. smFromBeginning: Result := Offset;
  407. smFromCurrent: Result := PMemoryIORec(Handle).Position + Offset;
  408. smFromEnd: Result := PMemoryIORec(Handle).Size + Offset;
  409. end;
  410. //Result := ClampInt(Result, 0, PMemoryIORec(Handle).Size); don't do this - some file formats use it
  411. PMemoryIORec(Handle).Position := Result;
  412. end;
  413. function MemoryTell(Handle: TImagingHandle): Int64; cdecl;
  414. begin
  415. Result := PMemoryIORec(Handle).Position;
  416. end;
  417. function MemoryRead(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt):
  418. LongInt; cdecl;
  419. var
  420. Rec: PMemoryIORec;
  421. begin
  422. Rec := PMemoryIORec(Handle);
  423. Result := Count;
  424. if Rec.Position + Count > Rec.Size then
  425. Result := Rec.Size - Rec.Position;
  426. Move(Rec.Data[Rec.Position], Buffer^, Result);
  427. Rec.Position := Rec.Position + Result;
  428. end;
  429. function MemoryWrite(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): LongInt; cdecl;
  430. var
  431. Rec: PMemoryIORec;
  432. begin
  433. Rec := PMemoryIORec(Handle);
  434. Result := Count;
  435. if Rec.Position + Count > Rec.Size then
  436. Result := Rec.Size - Rec.Position;
  437. Move(Buffer^, Rec.Data[Rec.Position], Result);
  438. Rec.Position := Rec.Position + Result;
  439. end;
  440. { Helper IO functions }
  441. function GetInputSize(const IOFunctions: TIOFunctions; Handle: TImagingHandle): Int64;
  442. var
  443. OldPos: Int64;
  444. begin
  445. OldPos := IOFunctions.Tell(Handle);
  446. IOFunctions.Seek(Handle, 0, smFromEnd);
  447. Result := IOFunctions.Tell(Handle);
  448. IOFunctions.Seek(Handle, OldPos, smFromBeginning);
  449. end;
  450. function PrepareMemIO(Data: Pointer; Size: LongInt): TMemoryIORec;
  451. begin
  452. Result.Data := Data;
  453. Result.Position := 0;
  454. Result.Size := Size;
  455. end;
  456. function ReadLine(const IOFunctions: TIOFunctions; Handle: TImagingHandle;
  457. out Line: AnsiString; FailOnControlChars: Boolean): Boolean;
  458. const
  459. MaxLine = 1024;
  460. var
  461. EolPos, Pos: Integer;
  462. C: AnsiChar;
  463. EolReached: Boolean;
  464. Endings: set of AnsiChar;
  465. begin
  466. Line := '';
  467. Pos := 0;
  468. EolPos := 0;
  469. EolReached := False;
  470. Endings := [#10, #13];
  471. Result := True;
  472. while not IOFunctions.Eof(Handle) do
  473. begin
  474. IOFunctions.Read(Handle, @C, SizeOf(C));
  475. if FailOnControlChars and (Byte(C) < $20) then
  476. begin
  477. Break;
  478. end;
  479. if not (C in Endings) then
  480. begin
  481. if EolReached then
  482. begin
  483. IOFunctions.Seek(Handle, EolPos, smFromBeginning);
  484. Exit;
  485. end
  486. else
  487. begin
  488. SetLength(Line, Length(Line) + 1);
  489. Line[Length(Line)] := C;
  490. end;
  491. end
  492. else if not EolReached then
  493. begin
  494. EolReached := True;
  495. EolPos := IOFunctions.Tell(Handle);
  496. end;
  497. Inc(Pos);
  498. if Pos >= MaxLine then
  499. begin
  500. Break;
  501. end;
  502. end;
  503. Result := False;
  504. IOFunctions.Seek(Handle, -Pos, smFromCurrent);
  505. end;
  506. procedure WriteLine(const IOFunctions: TIOFunctions; Handle: TImagingHandle;
  507. const Line: AnsiString; const LineEnding: AnsiString);
  508. var
  509. ToWrite: AnsiString;
  510. begin
  511. ToWrite := Line + LineEnding;
  512. IOFunctions.Write(Handle, @ToWrite[1], Length(ToWrite));
  513. end;
  514. { TReadMemoryStream }
  515. constructor TReadMemoryStream.Create(Data: Pointer; Size: Integer);
  516. begin
  517. SetPointer(Data, Size);
  518. end;
  519. class function TReadMemoryStream.CreateFromIOHandle(const IOFunctions: TIOFunctions; Handle: TImagingHandle): TReadMemoryStream;
  520. var
  521. Data: Pointer;
  522. Size: Integer;
  523. begin
  524. Size := GetInputSize(IOFunctions, Handle);
  525. GetMem(Data, Size);
  526. IOFunctions.Read(Handle, Data, Size);
  527. Result := TReadMemoryStream.Create(Data, Size);
  528. end;
  529. { TImagingIOStream }
  530. constructor TImagingIOStream.Create(const IOFunctions: TIOFunctions;
  531. Handle: TImagingHandle);
  532. begin
  533. end;
  534. initialization
  535. OriginalFileIO.Open := FileOpen;
  536. OriginalFileIO.Close := FileClose;
  537. OriginalFileIO.Eof := FileEof;
  538. OriginalFileIO.Seek := FileSeek;
  539. OriginalFileIO.Tell := FileTell;
  540. OriginalFileIO.Read := FileRead;
  541. OriginalFileIO.Write := FileWrite;
  542. StreamIO.Open := StreamOpen;
  543. StreamIO.Close := StreamClose;
  544. StreamIO.Eof := StreamEof;
  545. StreamIO.Seek := StreamSeek;
  546. StreamIO.Tell := StreamTell;
  547. StreamIO.Read := StreamRead;
  548. StreamIO.Write := StreamWrite;
  549. MemoryIO.Open := MemoryOpen;
  550. MemoryIO.Close := MemoryClose;
  551. MemoryIO.Eof := MemoryEof;
  552. MemoryIO.Seek := MemorySeek;
  553. MemoryIO.Tell := MemoryTell;
  554. MemoryIO.Read := MemoryRead;
  555. MemoryIO.Write := MemoryWrite;
  556. ResetFileIO;
  557. {
  558. File Notes:
  559. -- TODOS ----------------------------------------------------
  560. - nothing now
  561. -- 0.77.3 ---------------------------------------------------
  562. - IO functions now have 64bit sizes and offsets.
  563. - Added helper classes TReadMemoryStream and TImagingIOStream.
  564. -- 0.77.1 ---------------------------------------------------
  565. - Updated IO Open functions according to changes in ImagingTypes.
  566. - Added ReadLine and WriteLine functions.
  567. -- 0.23 Changes/Bug Fixes -----------------------------------
  568. - Added merge between buffered read-only and write-only file
  569. stream adapters - TIFF saving needed both reading and writing.
  570. - Fixed bug causing wrong value of TBufferedWriteFile.Size
  571. (needed to add buffer pos to size).
  572. -- 0.21 Changes/Bug Fixes -----------------------------------
  573. - Removed TMemoryIORec.Written, use Position to get proper memory
  574. position (Written didn't take Seeks into account).
  575. - Added TBufferedReadFile and TBufferedWriteFile classes for
  576. buffered file reading/writing. File IO functions now use these
  577. classes resulting in performance increase mainly in file formats
  578. that read/write many small chunks.
  579. - Added fmShareDenyWrite to FileOpenRead. You can now read
  580. files opened for reading by Imaging from other apps.
  581. - Added GetInputSize and PrepareMemIO helper functions.
  582. -- 0.19 Changes/Bug Fixes -----------------------------------
  583. - changed behaviour of MemorySeek to act as TStream
  584. based Seeks
  585. }
  586. end.