JclStreams.pas 92 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124
  1. {**************************************************************************************************}
  2. { }
  3. { Project JEDI Code Library (JCL) }
  4. { }
  5. { The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
  6. { you may not use this file except in compliance with the License. You may obtain a copy of the }
  7. { License at http://www.mozilla.org/MPL/ }
  8. { }
  9. { Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
  10. { ANY KIND, either express or implied. See the License for the specific language governing rights }
  11. { and limitations under the License. }
  12. { }
  13. { The Original Code is JclStreams.pas. }
  14. { }
  15. { The Initial Developer of the Original Code is Robert Marquardt. Portions created by }
  16. { Robert Marquardt are Copyright (C) Robert Marquardt (robert_marquardt att gmx dott de) }
  17. { All rights reserved. }
  18. { }
  19. { Contributors: }
  20. { Florent Ouchet (outchy) }
  21. { Heinz Zastrau }
  22. { Andreas Schmidt }
  23. { }
  24. {**************************************************************************************************}
  25. { }
  26. { Stream-related functions and classes }
  27. { }
  28. {**************************************************************************************************}
  29. { }
  30. { Last modified: $Date:: $ }
  31. { Revision: $Rev:: $ }
  32. { Author: $Author:: $ }
  33. { }
  34. {**************************************************************************************************}
  35. unit JclStreams;
  36. {$I jcl.inc}
  37. interface
  38. uses
  39. {$IFDEF UNITVERSIONING}
  40. JclUnitVersioning,
  41. {$ENDIF UNITVERSIONING}
  42. {$IFDEF HAS_UNITSCOPE}
  43. {$IFDEF MSWINDOWS}
  44. Winapi.Windows,
  45. {$ENDIF MSWINDOWS}
  46. System.SysUtils, System.Classes,
  47. System.Contnrs,
  48. {$ELSE ~HAS_UNITSCOPE}
  49. {$IFDEF MSWINDOWS}
  50. Windows,
  51. {$ENDIF MSWINDOWS}
  52. SysUtils, Classes,
  53. Contnrs,
  54. {$ENDIF ~HAS_UNITSCOPE}
  55. {$IFDEF HAS_UNIT_LIBC}
  56. Libc,
  57. {$ENDIF HAS_UNIT_LIBC}
  58. JclBase, JclStringConversions;
  59. const
  60. StreamDefaultBufferSize = 4096;
  61. type
  62. EJclStreamError = class(EJclError);
  63. // abstraction layer to support Delphi 5 and C++Builder 5 streams
  64. // 64 bit version of overloaded functions are introduced
  65. TJclStream = class(TStream)
  66. protected
  67. procedure SetSize(NewSize: Longint); overload; override;
  68. procedure SetSize(const NewSize: Int64); overload; override;
  69. public
  70. function Seek(Offset: Longint; Origin: Word): Longint; overload; override;
  71. function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; overload; override;
  72. procedure LoadFromStream(Source: TStream; BufferSize: Longint = StreamDefaultBufferSize); virtual;
  73. procedure LoadFromFile(const FileName: TFileName; BufferSize: Longint = StreamDefaultBufferSize); virtual;
  74. procedure SaveToStream(Dest: TStream; BufferSize: Longint = StreamDefaultBufferSize); virtual;
  75. procedure SaveToFile(const FileName: TFileName; BufferSize: Longint = StreamDefaultBufferSize); virtual;
  76. end;
  77. //=== VCL stream replacements ===
  78. TJclHandleStream = class(TJclStream)
  79. private
  80. FHandle: THandle;
  81. protected
  82. procedure SetSize(const NewSize: Int64); override;
  83. public
  84. constructor Create(AHandle: THandle);
  85. function Read(var Buffer; Count: Longint): Longint; override;
  86. function Write(const Buffer; Count: Longint): Longint; override;
  87. function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
  88. property Handle: THandle read FHandle;
  89. end;
  90. TJclFileStream = class(TJclHandleStream)
  91. public
  92. constructor Create(const FileName: TFileName; Mode: Word; Rights: Cardinal = $666);
  93. destructor Destroy; override;
  94. end;
  95. {
  96. TJclCustomMemoryStream = class(TJclStream)
  97. end;
  98. TJclMemoryStream = class(TJclCustomMemoryStream)
  99. end;
  100. TJclStringStream = class(TJclStream)
  101. end;
  102. TJclResourceStream = class(TJclCustomMemoryStream)
  103. end;
  104. }
  105. //=== new stream ideas ===
  106. TJclEmptyStream = class(TJclStream)
  107. protected
  108. procedure SetSize(const NewSize: Int64); override;
  109. public
  110. function Read(var Buffer; Count: Longint): Longint; override;
  111. function Write(const Buffer; Count: Longint): Longint; override;
  112. function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
  113. end;
  114. TJclNullStream = class(TJclStream)
  115. private
  116. FPosition: Int64;
  117. FSize: Int64;
  118. protected
  119. procedure SetSize(const NewSize: Int64); override;
  120. public
  121. function Read(var Buffer; Count: Longint): Longint; override;
  122. function Write(const Buffer; Count: Longint): Longint; override;
  123. function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
  124. end;
  125. TJclRandomStream = class(TJclNullStream)
  126. protected
  127. function GetRandSeed: Longint; virtual;
  128. procedure SetRandSeed(Seed: Longint); virtual;
  129. public
  130. function RandomData: Byte; virtual;
  131. procedure Randomize; dynamic;
  132. function Read(var Buffer; Count: Longint): Longint; override;
  133. property RandSeed: Longint read GetRandSeed write SetRandSeed;
  134. end;
  135. TJclMultiplexStream = class(TJclStream)
  136. private
  137. FStreams: TList;
  138. FReadStreamIndex: Integer;
  139. function GetStream(Index: Integer): TStream;
  140. function GetCount: Integer;
  141. procedure SetStream(Index: Integer; const Value: TStream);
  142. function GetReadStream: TStream;
  143. procedure SetReadStream(const Value: TStream);
  144. procedure SetReadStreamIndex(const Value: Integer);
  145. protected
  146. procedure SetSize(const NewSize: Int64); override;
  147. public
  148. constructor Create;
  149. destructor Destroy; override;
  150. function Read(var Buffer; Count: Longint): Longint; override;
  151. function Write(const Buffer; Count: Longint): Longint; override;
  152. function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
  153. function Add(NewStream: TStream): Integer;
  154. procedure Clear;
  155. function Remove(AStream: TStream): Integer;
  156. procedure Delete(const Index: Integer);
  157. property Streams[Index: Integer]: TStream read GetStream write SetStream;
  158. property ReadStreamIndex: Integer read FReadStreamIndex write SetReadStreamIndex;
  159. property ReadStream: TStream read GetReadStream write SetReadStream;
  160. property Count: Integer read GetCount;
  161. end;
  162. TJclStreamDecorator = class(TJclStream)
  163. private
  164. FAfterStreamChange: TNotifyEvent;
  165. FBeforeStreamChange: TNotifyEvent;
  166. FOwnsStream: Boolean;
  167. FStream: TStream;
  168. procedure SetStream(Value: TStream);
  169. protected
  170. procedure DoAfterStreamChange; virtual;
  171. procedure DoBeforeStreamChange; virtual;
  172. procedure SetSize(const NewSize: Int64); override;
  173. public
  174. constructor Create(AStream: TStream; AOwnsStream: Boolean = False);
  175. destructor Destroy; override;
  176. function Read(var Buffer; Count: Longint): Longint; override;
  177. function Write(const Buffer; Count: Longint): Longint; override;
  178. function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
  179. property AfterStreamChange: TNotifyEvent read FAfterStreamChange write FAfterStreamChange;
  180. property BeforeStreamChange: TNotifyEvent read FBeforeStreamChange write FBeforeStreamChange;
  181. property OwnsStream: Boolean read FOwnsStream write FOwnsStream;
  182. property Stream: TStream read FStream write SetStream;
  183. end;
  184. TJclBufferedStream = class(TJclStreamDecorator)
  185. protected
  186. FBuffer: array of Byte;
  187. FBufferCurrentSize: Longint;
  188. FBufferMaxModifiedPos: Longint;
  189. FBufferSize: Longint;
  190. FBufferStart: Int64; // position of the first byte of the buffer in stream
  191. FPosition: Int64; // current position in stream
  192. function BufferHit: Boolean;
  193. function GetCalcedSize: Int64; virtual;
  194. function LoadBuffer: Boolean; virtual;
  195. function ReadFromBuffer(var Buffer; Count, Start: Longint): Longint;
  196. function WriteToBuffer(const Buffer; Count, Start: Longint): Longint;
  197. protected
  198. procedure DoAfterStreamChange; override;
  199. procedure DoBeforeStreamChange; override;
  200. procedure SetSize(const NewSize: Int64); override;
  201. public
  202. constructor Create(AStream: TStream; AOwnsStream: Boolean = False);
  203. destructor Destroy; override;
  204. procedure Flush; virtual;
  205. function Read(var Buffer; Count: Longint): Longint; override;
  206. function Write(const Buffer; Count: Longint): Longint; override;
  207. function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
  208. property BufferSize: Longint read FBufferSize write FBufferSize;
  209. end;
  210. TStreamNotifyEvent = procedure(Sender: TObject; Position: Int64; Size: Int64) of object;
  211. TJclEventStream = class(TJclStreamDecorator)
  212. private
  213. FNotification: TStreamNotifyEvent;
  214. procedure DoNotification;
  215. protected
  216. procedure DoBeforeStreamChange; override;
  217. procedure DoAfterStreamChange; override;
  218. procedure SetSize(const NewSize: Int64); override;
  219. public
  220. constructor Create(AStream: TStream; ANotification: TStreamNotifyEvent = nil;
  221. AOwnsStream: Boolean = False);
  222. function Read(var Buffer; Count: Longint): Longint; override;
  223. function Write(const Buffer; Count: Longint): Longint; override;
  224. function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
  225. property OnNotification: TStreamNotifyEvent read FNotification write FNotification;
  226. end;
  227. TJclEasyStream = class(TJclStreamDecorator)
  228. public
  229. function IsEqual(Stream: TStream): Boolean;
  230. function ReadBoolean: Boolean;
  231. function ReadChar: Char;
  232. function ReadAnsiChar: AnsiChar;
  233. function ReadWideChar: WideChar;
  234. function ReadByte: Byte;
  235. function ReadCurrency: Currency;
  236. function ReadDateTime: TDateTime;
  237. function ReadExtended: Extended;
  238. function ReadDouble: Double;
  239. function ReadInt64: Int64;
  240. function ReadInteger: Integer;
  241. function ReadCString: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  242. function ReadCAnsiString: AnsiString;
  243. function ReadCWideString: WideString;
  244. function ReadShortString: string;
  245. function ReadSingle: Single;
  246. function ReadSizedString: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  247. function ReadSizedAnsiString: AnsiString;
  248. function ReadSizedWideString: WideString;
  249. procedure WriteBoolean(Value: Boolean);
  250. procedure WriteChar(Value: Char);
  251. procedure WriteAnsiChar(Value: AnsiChar);
  252. procedure WriteWideChar(Value: WideChar);
  253. procedure WriteByte(Value: Byte);
  254. procedure WriteCurrency(const Value: Currency);
  255. procedure WriteDateTime(const Value: TDateTime);
  256. procedure WriteExtended(const Value: Extended);
  257. procedure WriteDouble(const Value: Double);
  258. procedure WriteInt64(Value: Int64); overload;
  259. procedure WriteInteger(Value: Integer); overload;
  260. procedure WriteCString(const Value: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  261. procedure WriteCAnsiString(const Value: AnsiString);
  262. procedure WriteCWideString(const Value: WideString);
  263. // use WriteCString
  264. procedure WriteShortString(const Value: ShortString);
  265. procedure WriteSingle(const Value: Single);
  266. procedure WriteSizedString(const Value: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  267. procedure WriteSizedAnsiString(const Value: AnsiString);
  268. procedure WriteSizedWideString(const Value: WideString);
  269. end;
  270. TJclScopedStream = class(TJclStream)
  271. private
  272. FParentStream: TStream;
  273. FStartPos: Int64;
  274. FCurrentPos: Int64;
  275. FMaxSize: Int64;
  276. protected
  277. procedure SetSize(const NewSize: Int64); override;
  278. public
  279. // scopedstream starting at the current position of the ParentStream
  280. // if MaxSize is positive or null, read and write operations cannot overrun this size or the ParentStream limitation
  281. // if MaxSize is negative, read and write operations are unlimited (up to the ParentStream limitation)
  282. constructor Create(AParentStream: TStream; const AMaxSize: Int64 = -1); overload;
  283. constructor Create(AParentStream: TStream; const AStartPos, AMaxSize: Int64); overload;
  284. function Read(var Buffer; Count: Longint): Longint; override;
  285. function Write(const Buffer; Count: Longint): Longint; override;
  286. function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
  287. property ParentStream: TStream read FParentStream;
  288. property StartPos: Int64 read FStartPos;
  289. property MaxSize: Int64 read FMaxSize write FMaxSize;
  290. end;
  291. TJclStreamSeekEvent = function(Sender: TObject; const Offset: Int64;
  292. Origin: TSeekOrigin): Int64 of object;
  293. TJclStreamReadEvent = function(Sender: TObject; var Buffer; Count: Longint): Longint of object;
  294. TJclStreamWriteEvent = function(Sender: TObject; const Buffer;Count: Longint): Longint of object;
  295. TJclStreamSizeEvent = procedure(Sender: TObject; const NewSize: Int64) of object;
  296. TJclDelegatedStream = class(TJclStream)
  297. private
  298. FOnSeek: TJclStreamSeekEvent;
  299. FOnRead: TJclStreamReadEvent;
  300. FOnWrite: TJclStreamWriteEvent;
  301. FOnSize: TJclStreamSizeEvent;
  302. protected
  303. procedure SetSize(const NewSize: Int64); override;
  304. public
  305. function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
  306. function Read(var Buffer; Count: Longint): Longint; override;
  307. function Write(const Buffer; Count: Longint): Longint; override;
  308. property OnSeek: TJclStreamSeekEvent read FOnSeek write FOnSeek;
  309. property OnRead: TJclStreamReadEvent read FOnRead write FOnRead;
  310. property OnWrite: TJclStreamWriteEvent read FOnWrite write FOnWrite;
  311. property OnSize: TJclStreamSizeEvent read FOnSize write FOnSize;
  312. end;
  313. // ancestor classes for streams with checksums and encrypted streams
  314. // data are stored in sectors: each BufferSize-d buffer is followed by FSectorOverHead bytes
  315. // containing the checksum. In case of an encrypted stream, there is no byte
  316. // but sector is encrypted
  317. // reusing some code from TJclBufferedStream
  318. TJclSectoredStream = class(TJclBufferedStream)
  319. protected
  320. FSectorOverHead: Longint;
  321. function FlatToSectored(const Position: Int64): Int64;
  322. function SectoredToFlat(const Position: Int64): Int64;
  323. function GetCalcedSize: Int64; override;
  324. function LoadBuffer: Boolean; override;
  325. procedure DoAfterStreamChange; override;
  326. procedure AfterBlockRead; virtual; // override to check protection
  327. procedure BeforeBlockWrite; virtual; // override to compute protection
  328. procedure SetSize(const NewSize: Int64); override;
  329. public
  330. constructor Create(AStorageStream: TStream; AOwnsStream: Boolean = False;
  331. ASectorOverHead: Longint = 0);
  332. procedure Flush; override;
  333. end;
  334. TJclCRC16Stream = class(TJclSectoredStream)
  335. protected
  336. procedure AfterBlockRead; override;
  337. procedure BeforeBlockWrite; override;
  338. public
  339. constructor Create(AStorageStream: TStream; AOwnsStream: Boolean = False);
  340. end;
  341. TJclCRC32Stream = class(TJclSectoredStream)
  342. protected
  343. procedure AfterBlockRead; override;
  344. procedure BeforeBlockWrite; override;
  345. public
  346. constructor Create(AStorageStream: TStream; AOwnsStream: Boolean = False);
  347. end;
  348. {$IFDEF COMPILER7_UP}
  349. {$DEFINE SIZE64}
  350. {$ENDIF ~COMPILER7_UP}
  351. {$IFDEF FPC}
  352. {$DEFINE SIZE64}
  353. {$ENDIF FPC}
  354. TJclSplitStream = class(TJclStream)
  355. private
  356. FVolume: TStream;
  357. FVolumeIndex: Integer;
  358. FVolumeMaxSize: Int64;
  359. FPosition: Int64;
  360. FVolumePosition: Int64;
  361. FForcePosition: Boolean;
  362. protected
  363. function GetVolume(Index: Integer): TStream; virtual; abstract;
  364. function GetVolumeMaxSize(Index: Integer): Int64; virtual; abstract;
  365. function GetSize: Int64; {$IFDEF SIZE64}override;{$ENDIF SIZE64}
  366. procedure SetSize(const NewSize: Int64); override;
  367. function InternalLoadVolume(Index: Integer): Boolean;
  368. public
  369. constructor Create(AForcePosition: Boolean = False);
  370. function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
  371. function Read(var Buffer; Count: Longint): Longint; override;
  372. function Write(const Buffer; Count: Longint): Longint; override;
  373. property ForcePosition: Boolean read FForcePosition write FForcePosition;
  374. end;
  375. TJclVolumeEvent = function(Index: Integer): TStream of object;
  376. TJclVolumeMaxSizeEvent = function(Index: Integer): Int64 of object;
  377. TJclDynamicSplitStream = class(TJclSplitStream)
  378. private
  379. FOnVolume: TJclVolumeEvent;
  380. FOnVolumeMaxSize: TJclVolumeMaxSizeEvent;
  381. protected
  382. function GetVolume(Index: Integer): TStream; override;
  383. function GetVolumeMaxSize(Index: Integer): Int64; override;
  384. public
  385. property OnVolume: TJclVolumeEvent read FOnVolume write FOnVolume;
  386. property OnVolumeMaxSize: TJclVolumeMaxSizeEvent read FOnVolumeMaxSize
  387. write FOnVolumeMaxSize;
  388. end;
  389. TJclSplitVolume = class
  390. public
  391. MaxSize: Int64;
  392. Stream: TStream;
  393. OwnStream: Boolean;
  394. end;
  395. TJclStaticSplitStream = class(TJclSplitStream)
  396. private
  397. FVolumes: TObjectList;
  398. function GetVolumeCount: Integer;
  399. protected
  400. function GetVolume(Index: Integer): TStream; override;
  401. function GetVolumeMaxSize(Index: Integer): Int64; override;
  402. public
  403. constructor Create(AForcePosition: Boolean = False);
  404. destructor Destroy; override;
  405. function AddVolume(AStream: TStream; AMaxSize: Int64 = 0;
  406. AOwnStream: Boolean = False): Integer;
  407. property VolumeCount: Integer read GetVolumeCount;
  408. property Volumes[Index: Integer]: TStream read GetVolume;
  409. property VolumeMaxSizes[Index: Integer]: Int64 read GetVolumeMaxSize;
  410. end;
  411. TJclStringStream = class
  412. protected
  413. FStream: TStream;
  414. FOwnStream: Boolean;
  415. FBOM: array of Byte;
  416. FBufferSize: SizeInt;
  417. FStrPosition: Int64; // current position in characters
  418. FStrBuffer: TUCS4Array; // buffer for read/write operations
  419. FStrBufferPosition: Int64; // position of the first character of the read/write buffer
  420. FStrBufferCurrentSize: Int64; // numbers of characters available in str buffer
  421. FStrBufferModifiedSize: Int64; // numbers of characters modified in str buffer
  422. FStrBufferStart: Int64; // position of the first byte of the read/write buffer in stream
  423. FStrBufferNext: Int64; // position of the next character following the read/write buffer in stream
  424. FStrPeekPosition: Int64; // current peek position in characters
  425. FStrPeekBuffer: TUCS4Array; // buffer for peek operations
  426. FStrPeekBufferPosition: Int64; // index of the first character of the peek buffer
  427. FStrPeekBufferCurrentSize: SizeInt; // numbers of characters available in peek buffer
  428. FStrPeekBufferStart: Int64; // position of the first byte of the peek buffer in stream
  429. FStrPeekBufferNext: Int64; // position of the next character following the peek buffer in stream
  430. function LoadBuffer: Boolean;
  431. function LoadPeekBuffer: Boolean;
  432. function InternalGetNextChar(S: TStream; out Ch: UCS4): Boolean; virtual; abstract;
  433. function InternalGetNextBuffer(S: TStream; var Buffer: TUCS4Array; Start, Count: SizeInt): Longint; virtual;
  434. function InternalSetNextChar(S: TStream; Ch: UCS4): Boolean; virtual; abstract;
  435. function InternalSetNextBuffer(S: TStream; const Buffer: TUCS4Array; Start, Count: SizeInt): Longint; virtual;
  436. procedure InvalidateBuffers;
  437. public
  438. constructor Create(AStream: TStream; AOwnsStream: Boolean = False); virtual;
  439. destructor Destroy; override;
  440. procedure Flush; virtual;
  441. function ReadString(var Buffer: string; Start, Count: Longint): Longint; overload;
  442. function ReadString(BufferSize: Longint = StreamDefaultBufferSize): string; overload;
  443. function ReadAnsiString(var Buffer: AnsiString; Start, Count: Longint): Longint; overload;
  444. function ReadAnsiString(BufferSize: Longint = StreamDefaultBufferSize): AnsiString; overload;
  445. function ReadWideString(var Buffer: WideString; Start, Count: Longint): Longint; overload;
  446. function ReadWideString(BufferSize: Longint = StreamDefaultBufferSize): WideString; overload;
  447. function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; virtual;
  448. function WriteString(const Buffer: string; Start, Count: Longint): Longint;
  449. function WriteAnsiString(const Buffer: AnsiString; Start, Count: Longint): Longint;
  450. function WriteWideString(const Buffer: WideString; Start, Count: Longint): Longint;
  451. function PeekChar(out Buffer: Char): Boolean;
  452. function PeekAnsiChar(out Buffer: AnsiChar): Boolean;
  453. function PeekUCS4(out Buffer: UCS4): Boolean;
  454. function PeekWideChar(out Buffer: WideChar): Boolean;
  455. function ReadChar(out Buffer: Char): Boolean;
  456. function ReadAnsiChar(out Buffer: AnsiChar): Boolean;
  457. function ReadUCS4(out Buffer: UCS4): Boolean;
  458. function ReadWideChar(out Buffer: WideChar): Boolean;
  459. function WriteChar(Value: Char): Boolean;
  460. function WriteAnsiChar(Value: AnsiChar): Boolean;
  461. function WriteUCS4(Value: UCS4): Boolean;
  462. function WriteWideChar(Value: WideChar): Boolean;
  463. function SkipBOM: LongInt; virtual;
  464. function WriteBOM: Longint; virtual;
  465. property BufferSize: SizeInt read FBufferSize write FBufferSize;
  466. property PeekPosition: Int64 read FStrPeekPosition;
  467. property Position: Int64 read FStrPosition;
  468. property Stream: TStream read FStream;
  469. property OwnStream: Boolean read FOwnStream;
  470. end;
  471. TJclStringStreamClass = class of TJclStringStream;
  472. TJclAnsiStream = class(TJclStringStream)
  473. private
  474. FCodePage: Word;
  475. protected
  476. function InternalGetNextChar(S: TStream; out Ch: UCS4): Boolean; override;
  477. function InternalGetNextBuffer(S: TStream; var Buffer: TUCS4Array; Start, Count: SizeInt): Longint; override;
  478. function InternalSetNextChar(S: TStream; Ch: UCS4): Boolean; override;
  479. function InternalSetNextBuffer(S: TStream; const Buffer: TUCS4Array; Start, Count: SizeInt): Longint; override;
  480. public
  481. constructor Create(AStream: TStream; AOwnsStream: Boolean = False); override;
  482. property CodePage: Word read FCodePage write FCodePage;
  483. end;
  484. TJclUTF8Stream = class(TJclStringStream)
  485. protected
  486. function InternalGetNextChar(S: TStream; out Ch: UCS4): Boolean; override;
  487. function InternalGetNextBuffer(S: TStream; var Buffer: TUCS4Array; Start, Count: SizeInt): Longint; override;
  488. function InternalSetNextChar(S: TStream; Ch: UCS4): Boolean; override;
  489. function InternalSetNextBuffer(S: TStream; const Buffer: TUCS4Array; Start, Count: SizeInt): Longint; override;
  490. public
  491. constructor Create(AStream: TStream; AOwnsStream: Boolean = False); override;
  492. end;
  493. TJclUTF16Stream = class(TJclStringStream)
  494. protected
  495. function InternalGetNextChar(S: TStream; out Ch: UCS4): Boolean; override;
  496. function InternalGetNextBuffer(S: TStream; var Buffer: TUCS4Array; Start, Count: SizeInt): Longint; override;
  497. function InternalSetNextChar(S: TStream; Ch: UCS4): Boolean; override;
  498. function InternalSetNextBuffer(S: TStream; const Buffer: TUCS4Array; Start, Count: SizeInt): Longint; override;
  499. public
  500. constructor Create(AStream: TStream; AOwnsStream: Boolean = False); override;
  501. end;
  502. TJclStringEncoding = (seAnsi, seUTF8, seUTF16, seAuto);
  503. TJclAutoStream = class(TJclStringStream)
  504. private
  505. FCodePage: Word;
  506. FEncoding: TJclStringEncoding;
  507. procedure SetCodePage(Value: Word);
  508. protected
  509. function InternalGetNextChar(S: TStream; out Ch: UCS4): Boolean; override;
  510. function InternalGetNextBuffer(S: TStream; var Buffer: TUCS4Array; Start, Count: SizeInt): Longint; override;
  511. function InternalSetNextChar(S: TStream; Ch: UCS4): Boolean; override;
  512. function InternalSetNextBuffer(S: TStream; const Buffer: TUCS4Array; Start, Count: SizeInt): Longint; override;
  513. public
  514. constructor Create(AStream: TStream; AOwnsStream: Boolean = False); override;
  515. function SkipBOM: LongInt; override;
  516. property CodePage: Word read FCodePage write SetCodePage;
  517. property Encoding: TJclStringEncoding read FEncoding;
  518. end;
  519. // buffered copy of all available bytes from Source to Dest
  520. // returns the number of bytes that were copied
  521. function StreamCopy(Source: TStream; Dest: TStream; BufferSize: Longint = StreamDefaultBufferSize): Int64;
  522. // buffered copy of all available characters from Source to Dest
  523. // retuns the number of characters (in specified encoding) that were copied
  524. function StringStreamCopy(Source, Dest: TJclStringStream; BufferLength: Longint = StreamDefaultBufferSize): Int64;
  525. function AnsiStringStreamCopy(Source, Dest: TJclStringStream; BufferLength: Longint = StreamDefaultBufferSize): Int64;
  526. function WideStringStreamCopy(Source, Dest: TJclStringStream; BufferLength: Longint = StreamDefaultBufferSize): Int64;
  527. // compares 2 streams for differencies
  528. function CompareStreams(A, B : TStream; BufferSize: Longint = StreamDefaultBufferSize): Boolean;
  529. // compares 2 files for differencies (calling CompareStreams)
  530. function CompareFiles(const FileA, FileB: TFileName; BufferSize: Longint = StreamDefaultBufferSize): Boolean;
  531. {$IFDEF UNITVERSIONING}
  532. const
  533. UnitVersioning: TUnitVersionInfo = (
  534. RCSfile: '$URL$';
  535. Revision: '$Revision$';
  536. Date: '$Date$';
  537. LogPath: 'JCL\source\common';
  538. Extra: '';
  539. Data: nil
  540. );
  541. {$ENDIF UNITVERSIONING}
  542. implementation
  543. uses
  544. {$IFDEF HAS_UNITSCOPE}
  545. System.Types,
  546. {$ENDIF HAS_UNITSCOPE}
  547. JclResources,
  548. JclCharsets,
  549. JclMath,
  550. JclSysUtils;
  551. function StreamCopy(Source: TStream; Dest: TStream; BufferSize: Longint): Int64;
  552. var
  553. Buffer: array of Byte;
  554. ByteCount: Longint;
  555. begin
  556. Result := 0;
  557. SetLength(Buffer, BufferSize);
  558. repeat
  559. ByteCount := Source.Read(Buffer[0], BufferSize);
  560. Result := Result + ByteCount;
  561. Dest.WriteBuffer(Buffer[0], ByteCount);
  562. until ByteCount < BufferSize;
  563. end;
  564. function StringStreamCopy(Source, Dest: TJclStringStream; BufferLength: Longint): Int64;
  565. var
  566. Buffer: string;
  567. CharCount: Longint;
  568. begin
  569. Result := 0;
  570. SetLength(Buffer, BufferLength);
  571. repeat
  572. CharCount := Source.ReadString(Buffer, 1, BufferLength);
  573. Result := Result + CharCount;
  574. CharCount := Dest.WriteString(Buffer, 1, CharCount);
  575. until CharCount = 0;
  576. end;
  577. function AnsiStringStreamCopy(Source, Dest: TJclStringStream; BufferLength: Longint): Int64;
  578. var
  579. Buffer: AnsiString;
  580. CharCount: Longint;
  581. begin
  582. Result := 0;
  583. SetLength(Buffer, BufferLength);
  584. repeat
  585. CharCount := Source.ReadAnsiString(Buffer, 1, BufferLength);
  586. Result := Result + CharCount;
  587. CharCount := Dest.WriteAnsiString(Buffer, 1, CharCount);
  588. until CharCount = 0;
  589. end;
  590. function WideStringStreamCopy(Source, Dest: TJclStringStream; BufferLength: Longint): Int64;
  591. var
  592. Buffer: WideString;
  593. CharCount: Longint;
  594. begin
  595. Result := 0;
  596. SetLength(Buffer, BufferLength);
  597. repeat
  598. CharCount := Source.ReadWideString(Buffer, 1, BufferLength);
  599. Result := Result + CharCount;
  600. CharCount := Dest.WriteWideString(Buffer, 1, CharCount);
  601. until CharCount = 0;
  602. end;
  603. function CompareStreams(A, B : TStream; BufferSize: Longint): Boolean;
  604. var
  605. BufferA, BufferB: array of Byte;
  606. ByteCountA, ByteCountB: Longint;
  607. begin
  608. SetLength(BufferA, BufferSize);
  609. try
  610. SetLength(BufferB, BufferSize);
  611. try
  612. repeat
  613. ByteCountA := A.Read(BufferA[0], BufferSize);
  614. ByteCountB := B.Read(BufferB[0], BufferSize);
  615. Result := (ByteCountA = ByteCountB);
  616. Result := Result and CompareMem(BufferA, BufferB, ByteCountA);
  617. until (ByteCountA <> BufferSize) or (ByteCountB <> BufferSize) or not Result;
  618. finally
  619. SetLength(BufferB, 0);
  620. end;
  621. finally
  622. SetLength(BufferA, 0);
  623. end;
  624. end;
  625. function CompareFiles(const FileA, FileB: TFileName; BufferSize: Longint): Boolean;
  626. var
  627. A, B: TStream;
  628. begin
  629. A := TFileStream.Create(FileA, fmOpenRead or fmShareDenyWrite);
  630. try
  631. B := TFileStream.Create(FileB, fmOpenRead or fmShareDenyWrite);
  632. try
  633. Result := CompareStreams(A, B, BufferSize);
  634. finally
  635. B.Free;
  636. end;
  637. finally
  638. A.Free;
  639. end;
  640. end;
  641. //=== { TJclStream } =========================================================
  642. function TJclStream.Seek(Offset: Longint; Origin: Word): Longint;
  643. var
  644. Result64: Int64;
  645. begin
  646. case Origin of
  647. soFromBeginning:
  648. Result64 := Seek(Int64(Offset), soBeginning);
  649. soFromCurrent:
  650. Result64 := Seek(Int64(Offset), soCurrent);
  651. soFromEnd:
  652. Result64 := Seek(Int64(Offset), soEnd);
  653. else
  654. Result64 := -1;
  655. end;
  656. if (Result64 < 0) or (Result64 > High(Longint)) then
  657. Result64 := -1;
  658. Result := Result64;
  659. end;
  660. procedure TJclStream.LoadFromFile(const FileName: TFileName;
  661. BufferSize: Integer);
  662. var
  663. FS: TStream;
  664. begin
  665. FS := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
  666. try
  667. LoadFromStream(FS, BufferSize);
  668. finally
  669. FS.Free;
  670. end;
  671. end;
  672. procedure TJclStream.LoadFromStream(Source: TStream; BufferSize: Integer);
  673. begin
  674. StreamCopy(Source, Self, BufferSize);
  675. end;
  676. procedure TJclStream.SaveToFile(const FileName: TFileName; BufferSize: Integer);
  677. var
  678. FS: TStream;
  679. begin
  680. FS := TFileStream.Create(FileName, fmCreate);
  681. try
  682. SaveToStream(FS, BufferSize);
  683. finally
  684. FS.Free;
  685. end;
  686. end;
  687. procedure TJclStream.SaveToStream(Dest: TStream; BufferSize: Integer);
  688. begin
  689. StreamCopy(Self, Dest, BufferSize);
  690. end;
  691. function TJclStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  692. begin
  693. // override to customize
  694. Result := -1;
  695. end;
  696. procedure TJclStream.SetSize(NewSize: Longint);
  697. begin
  698. SetSize(Int64(NewSize));
  699. end;
  700. procedure TJclStream.SetSize(const NewSize: Int64);
  701. begin
  702. // override to customize
  703. end;
  704. //=== { TJclHandleStream } ===================================================
  705. constructor TJclHandleStream.Create(AHandle: THandle);
  706. begin
  707. inherited Create;
  708. FHandle := AHandle;
  709. end;
  710. function TJclHandleStream.Read(var Buffer; Count: Longint): Longint;
  711. begin
  712. Result := 0;
  713. {$IFDEF MSWINDOWS}
  714. if (Count <= 0) or not ReadFile(Handle, Buffer, DWORD(Count), DWORD(Result), nil) then
  715. Result := 0;
  716. {$ENDIF MSWINDOWS}
  717. {$IFDEF LINUX}
  718. Result := __read(Handle, Buffer, Count);
  719. {$ENDIF LINUX}
  720. end;
  721. function TJclHandleStream.Write(const Buffer; Count: Longint): Longint;
  722. begin
  723. Result := 0;
  724. {$IFDEF MSWINDOWS}
  725. if (Count <= 0) or not WriteFile(Handle, Buffer, DWORD(Count), DWORD(Result), nil) then
  726. Result := 0;
  727. {$ENDIF MSWINDOWS}
  728. {$IFDEF LINUX}
  729. Result := __write(Handle, Buffer, Count);
  730. {$ENDIF LINUX}
  731. end;
  732. {$IFDEF MSWINDOWS}
  733. function TJclHandleStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  734. const
  735. INVALID_SET_FILE_POINTER = -1;
  736. type
  737. TLarge = record
  738. case Boolean of
  739. False:
  740. (OffsetLo: Longint;
  741. OffsetHi: Longint);
  742. True:
  743. (Offset64: Int64);
  744. end;
  745. var
  746. Offs: TLarge;
  747. begin
  748. Offs.Offset64 := Offset;
  749. Offs.OffsetLo := SetFilePointer(Handle, Offs.OffsetLo, @Offs.OffsetHi, Ord(Origin));
  750. if (Offs.OffsetLo = INVALID_SET_FILE_POINTER) and (GetLastError <> NO_ERROR) then
  751. Result := -1
  752. else
  753. Result := Offs.Offset64;
  754. end;
  755. {$ENDIF MSWINDOWS}
  756. {$IFDEF LINUX}
  757. function TJclHandleStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  758. const
  759. SeekOrigins: array [TSeekOrigin] of Cardinal = ( SEEK_SET {soBeginning}, SEEK_CUR {soCurrent}, SEEK_END {soEnd} );
  760. begin
  761. Result := lseek(Handle, Offset, SeekOrigins[Origin]);
  762. end;
  763. {$ENDIF LINUX}
  764. procedure TJclHandleStream.SetSize(const NewSize: Int64);
  765. begin
  766. Seek(NewSize, soBeginning);
  767. {$IFDEF MSWINDOWS}
  768. if not SetEndOfFile(Handle) then
  769. RaiseLastOSError;
  770. {$ENDIF MSWINDOWS}
  771. {$IFDEF LINUX}
  772. if ftruncate(Handle, Position) = -1 then
  773. raise EJclStreamError.CreateRes(@RsStreamsSetSizeError);
  774. {$ENDIF LINUX}
  775. end;
  776. //=== { TJclFileStream } =====================================================
  777. constructor TJclFileStream.Create(const FileName: TFileName; Mode: Word; Rights: Cardinal);
  778. var
  779. H: THandle;
  780. {$IFDEF LINUX}
  781. const
  782. INVALID_HANDLE_VALUE = -1;
  783. {$ENDIF LINUX}
  784. begin
  785. if Mode = fmCreate then
  786. begin
  787. {$IFDEF LINUX}
  788. H := open(PChar(FileName), O_CREAT or O_RDWR, Rights);
  789. {$ENDIF LINUX}
  790. {$IFDEF MSWINDOWS}
  791. H := CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE,
  792. 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  793. {$ENDIF MSWINDOWS}
  794. inherited Create(H);
  795. if Handle = INVALID_HANDLE_VALUE then
  796. raise EJclStreamError.CreateResFmt(@RsStreamsCreateError, [FileName]);
  797. end
  798. else
  799. begin
  800. H := THandle(FileOpen(FileName, Mode));
  801. inherited Create(H);
  802. if Handle = INVALID_HANDLE_VALUE then
  803. raise EJclStreamError.CreateResFmt(@RsStreamsOpenError, [FileName]);
  804. end;
  805. end;
  806. destructor TJclFileStream.Destroy;
  807. begin
  808. {$IFDEF MSWINDOWS}
  809. if Handle <> INVALID_HANDLE_VALUE then
  810. CloseHandle(Handle);
  811. {$ENDIF MSWINDOWS}
  812. {$IFDEF LINUX}
  813. __close(Handle);
  814. {$ENDIF LINUX}
  815. inherited Destroy;
  816. end;
  817. //=== { TJclEmptyStream } ====================================================
  818. // a stream which stays empty no matter what you do
  819. // so it is a Unix /dev/null equivalent
  820. procedure TJclEmptyStream.SetSize(const NewSize: Int64);
  821. begin
  822. // nothing
  823. end;
  824. function TJclEmptyStream.Read(var Buffer; Count: Longint): Longint;
  825. begin
  826. // you cannot read anything
  827. Result := 0;
  828. end;
  829. function TJclEmptyStream.Write(const Buffer; Count: Longint): Longint;
  830. begin
  831. // you cannot write anything
  832. Result := 0;
  833. end;
  834. function TJclEmptyStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  835. begin
  836. if Offset <> 0 then
  837. // seeking to anywhere except the position 0 is an error
  838. Result := -1
  839. else
  840. Result := 0;
  841. end;
  842. //=== { TJclNullStream } =====================================================
  843. // a stream which only keeps position and size, but no data
  844. // so it is a Unix /dev/zero equivalent (?)
  845. procedure TJclNullStream.SetSize(const NewSize: Int64);
  846. begin
  847. if NewSize > 0 then
  848. FSize := NewSize
  849. else
  850. FSize := 0;
  851. if FPosition > FSize then
  852. FPosition := FSize;
  853. end;
  854. function TJclNullStream.Read(var Buffer; Count: Longint): Longint;
  855. begin
  856. if Count < 0 then
  857. Count := 0;
  858. // FPosition > FSize is possible!
  859. if FSize - FPosition < Count then
  860. Count := FSize - FPosition;
  861. // does not read if beyond EOF
  862. if Count > 0 then
  863. begin
  864. ResetMemory(Buffer, Count);
  865. FPosition := FPosition + Count;
  866. end;
  867. Result := Count;
  868. end;
  869. function TJclNullStream.Write(const Buffer; Count: Longint): Longint;
  870. begin
  871. if Count < 0 then
  872. Count := 0;
  873. FPosition := FPosition + Count;
  874. // writing when FPosition > FSize is possible!
  875. if FPosition > FSize then
  876. FSize := FPosition;
  877. Result := Count;
  878. end;
  879. function TJclNullStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  880. var
  881. Rel: Int64;
  882. begin
  883. case Origin of
  884. soBeginning:
  885. Rel := 0;
  886. soCurrent:
  887. Rel := FPosition;
  888. soEnd:
  889. Rel := FSize;
  890. else
  891. // force Rel + Offset = -1 (code is never reached)
  892. Rel := Offset - 1;
  893. end;
  894. if Rel + Offset >= 0 then
  895. begin
  896. // all non-negative destination positions including beyond EOF are valid
  897. FPosition := Rel + Offset;
  898. Result := FPosition;
  899. end
  900. else
  901. Result := -1;
  902. end;
  903. //=== { TJclRandomStream } ===================================================
  904. // A TJclNullStream decendant which returns random data when read
  905. // so it is a Unix /dev/random equivalent
  906. function TJclRandomStream.GetRandSeed: Longint;
  907. begin
  908. Result := System.RandSeed;
  909. end;
  910. procedure TJclRandomStream.SetRandSeed(Seed: Longint);
  911. begin
  912. System.RandSeed := Seed;
  913. end;
  914. function TJclRandomStream.RandomData: Byte;
  915. begin
  916. Result := System.Random(256);
  917. end;
  918. procedure TJclRandomStream.Randomize;
  919. begin
  920. System.Randomize;
  921. end;
  922. function TJclRandomStream.Read(var Buffer; Count: Longint): Longint;
  923. var
  924. I: Longint;
  925. BufferPtr: PByte;
  926. begin
  927. // this handles all necessary checks
  928. Count := inherited Read(Buffer, Count);
  929. BufferPtr := @Buffer;
  930. for I := 0 to Count - 1 do
  931. begin
  932. BufferPtr^ := RandomData;
  933. Inc(BufferPtr);
  934. end;
  935. Result := Count;
  936. end;
  937. //=== { TJclMultiplexStream } ================================================
  938. constructor TJclMultiplexStream.Create;
  939. begin
  940. inherited Create;
  941. FStreams := TList.Create;
  942. FReadStreamIndex := -1;
  943. end;
  944. destructor TJclMultiplexStream.Destroy;
  945. begin
  946. FStreams.Free;
  947. inherited Destroy;
  948. end;
  949. function TJclMultiplexStream.Add(NewStream: TStream): Integer;
  950. begin
  951. Result := FStreams.Add(Pointer(NewStream));
  952. end;
  953. procedure TJclMultiplexStream.Clear;
  954. begin
  955. FStreams.Clear;
  956. FReadStreamIndex := -1;
  957. end;
  958. procedure TJclMultiplexStream.Delete(const Index: Integer);
  959. begin
  960. FStreams.Delete(Index);
  961. if ReadStreamIndex = Index then
  962. FReadStreamIndex := -1
  963. else
  964. if ReadStreamIndex > Index then
  965. Dec(FReadStreamIndex);
  966. end;
  967. function TJclMultiplexStream.GetReadStream: TStream;
  968. begin
  969. if FReadStreamIndex >= 0 then
  970. Result := TStream(FStreams.Items[FReadStreamIndex])
  971. else
  972. Result := nil;
  973. end;
  974. function TJclMultiplexStream.GetStream(Index: Integer): TStream;
  975. begin
  976. Result := TStream(FStreams.Items[Index]);
  977. end;
  978. function TJclMultiplexStream.GetCount: Integer;
  979. begin
  980. Result := FStreams.Count;
  981. end;
  982. function TJclMultiplexStream.Read(var Buffer; Count: Longint): Longint;
  983. var
  984. Stream: TStream;
  985. begin
  986. Stream := ReadStream;
  987. if Assigned(Stream) then
  988. Result := Stream.Read(Buffer, Count)
  989. else
  990. Result := 0;
  991. end;
  992. function TJclMultiplexStream.Remove(AStream: TStream): Integer;
  993. begin
  994. Result := FStreams.Remove(Pointer(AStream));
  995. if FReadStreamIndex = Result then
  996. FReadStreamIndex := -1
  997. else
  998. if FReadStreamIndex > Result then
  999. Dec(FReadStreamIndex);
  1000. end;
  1001. function TJclMultiplexStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  1002. begin
  1003. // what should this function do?
  1004. Result := -1;
  1005. end;
  1006. procedure TJclMultiplexStream.SetReadStream(const Value: TStream);
  1007. begin
  1008. FReadStreamIndex := FStreams.IndexOf(Pointer(Value));
  1009. end;
  1010. procedure TJclMultiplexStream.SetReadStreamIndex(const Value: Integer);
  1011. begin
  1012. FReadStreamIndex := Value;
  1013. end;
  1014. procedure TJclMultiplexStream.SetSize(const NewSize: Int64);
  1015. begin
  1016. // what should this function do?
  1017. end;
  1018. procedure TJclMultiplexStream.SetStream(Index: Integer; const Value: TStream);
  1019. begin
  1020. FStreams.Items[Index] := Pointer(Value);
  1021. end;
  1022. function TJclMultiplexStream.Write(const Buffer; Count: Longint): Longint;
  1023. var
  1024. Index: Integer;
  1025. ByteWritten, MinByteWritten: Longint;
  1026. begin
  1027. MinByteWritten := Count;
  1028. for Index := 0 to Self.Count - 1 do
  1029. begin
  1030. ByteWritten := TStream(FStreams.Items[Index]).Write(Buffer, Count);
  1031. if ByteWritten < MinByteWritten then
  1032. MinByteWritten := ByteWritten;
  1033. end;
  1034. Result := MinByteWritten;
  1035. end;
  1036. //=== { TJclStreamDecorator } ================================================
  1037. constructor TJclStreamDecorator.Create(AStream: TStream; AOwnsStream: Boolean = False);
  1038. begin
  1039. inherited Create;
  1040. FStream := AStream;
  1041. FOwnsStream := AOwnsStream;
  1042. end;
  1043. destructor TJclStreamDecorator.Destroy;
  1044. begin
  1045. if OwnsStream then
  1046. FStream.Free;
  1047. inherited Destroy;
  1048. end;
  1049. procedure TJclStreamDecorator.DoAfterStreamChange;
  1050. begin
  1051. if Assigned(FAfterStreamChange) then
  1052. FAfterStreamChange(Self);
  1053. end;
  1054. procedure TJclStreamDecorator.DoBeforeStreamChange;
  1055. begin
  1056. if Assigned(FBeforeStreamChange) then
  1057. FBeforeStreamChange(Self);
  1058. end;
  1059. function TJclStreamDecorator.Read(var Buffer; Count: Longint): Longint;
  1060. begin
  1061. if Assigned(FStream) then
  1062. Result := Stream.Read(Buffer, Count)
  1063. else
  1064. Result := 0;
  1065. end;
  1066. function TJclStreamDecorator.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  1067. begin
  1068. Result := Stream.Seek(Offset, Origin);
  1069. end;
  1070. procedure TJclStreamDecorator.SetSize(const NewSize: Int64);
  1071. begin
  1072. if Assigned(FStream) then
  1073. Stream.Size := NewSize;
  1074. end;
  1075. procedure TJclStreamDecorator.SetStream(Value: TStream);
  1076. begin
  1077. if Value <> FStream then
  1078. try
  1079. DoBeforeStreamChange;
  1080. finally
  1081. if OwnsStream then
  1082. FStream.Free;
  1083. FStream := Value;
  1084. DoAfterStreamChange;
  1085. end;
  1086. end;
  1087. function TJclStreamDecorator.Write(const Buffer; Count: Longint): Longint;
  1088. begin
  1089. if Assigned(FStream) then
  1090. Result := Stream.Write(Buffer, Count)
  1091. else
  1092. Result := 0;
  1093. end;
  1094. //=== { TJclBufferedStream } =================================================
  1095. constructor TJclBufferedStream.Create(AStream: TStream; AOwnsStream: Boolean = False);
  1096. begin
  1097. inherited Create(AStream, AOwnsStream);
  1098. if Stream <> nil then
  1099. FPosition := Stream.Position;
  1100. BufferSize := StreamDefaultBufferSize;
  1101. LoadBuffer;
  1102. end;
  1103. destructor TJclBufferedStream.Destroy;
  1104. begin
  1105. Flush;
  1106. inherited Destroy;
  1107. end;
  1108. function TJclBufferedStream.BufferHit: Boolean;
  1109. begin
  1110. Result := (FBufferStart <= FPosition) and (FPosition < (FBufferStart + FBufferCurrentSize));
  1111. end;
  1112. procedure TJclBufferedStream.DoAfterStreamChange;
  1113. begin
  1114. inherited DoAfterStreamChange;
  1115. FBufferCurrentSize := 0; // invalidate buffer after stream is changed
  1116. FBufferStart := 0;
  1117. if Stream <> nil then
  1118. FPosition := Stream.Position;
  1119. end;
  1120. procedure TJclBufferedStream.DoBeforeStreamChange;
  1121. begin
  1122. inherited DoBeforeStreamChange;
  1123. Flush;
  1124. end;
  1125. procedure TJclBufferedStream.Flush;
  1126. begin
  1127. if (Stream <> nil) and (FBufferMaxModifiedPos > 0) then
  1128. begin
  1129. Stream.Position := FBufferStart;
  1130. Stream.WriteBuffer(FBuffer[0], FBufferMaxModifiedPos);
  1131. FBufferMaxModifiedPos := 0;
  1132. end;
  1133. end;
  1134. function TJclBufferedStream.GetCalcedSize: Int64;
  1135. begin
  1136. if Assigned(Stream) then
  1137. Result := Stream.Size
  1138. else
  1139. Result := 0;
  1140. if Result < FBufferMaxModifiedPos + FBufferStart then
  1141. Result := FBufferMaxModifiedPos + FBufferStart;
  1142. end;
  1143. function TJclBufferedStream.LoadBuffer: Boolean;
  1144. begin
  1145. Flush;
  1146. if Length(FBuffer) <> FBufferSize then
  1147. SetLength(FBuffer, FBufferSize);
  1148. if Stream <> nil then
  1149. begin
  1150. Stream.Position := FPosition;
  1151. FBufferCurrentSize := Stream.Read(FBuffer[0], FBufferSize);
  1152. end
  1153. else
  1154. FBufferCurrentSize := 0;
  1155. FBufferStart := FPosition;
  1156. Result := (FBufferCurrentSize > 0);
  1157. end;
  1158. function TJclBufferedStream.Read(var Buffer; Count: Longint): Longint;
  1159. const
  1160. Offset = 0;
  1161. begin
  1162. Result := Count + Offset;
  1163. while Count > 0 do
  1164. begin
  1165. if not BufferHit then
  1166. if not LoadBuffer then
  1167. Break;
  1168. Dec(Count, ReadFromBuffer(Buffer, Count, Result - Count));
  1169. end;
  1170. Result := Result - Count - Offset;
  1171. end;
  1172. function TJclBufferedStream.ReadFromBuffer(var Buffer; Count, Start: Longint): Longint;
  1173. var
  1174. BufPos: Longint;
  1175. P: PAnsiChar;
  1176. begin
  1177. Result := Count;
  1178. BufPos := FPosition - FBufferStart;
  1179. if Result > FBufferCurrentSize - BufPos then
  1180. Result := FBufferCurrentSize - BufPos;
  1181. P := @Buffer;
  1182. Move(FBuffer[BufPos], P[Start], Result);
  1183. Inc(FPosition, Result);
  1184. end;
  1185. function TJclBufferedStream.Seek(const Offset: Int64;
  1186. Origin: TSeekOrigin): Int64;
  1187. var
  1188. NewPos: Int64;
  1189. begin
  1190. NewPos := FPosition;
  1191. case Origin of
  1192. soBeginning:
  1193. NewPos := Offset;
  1194. soCurrent:
  1195. Inc(NewPos, Offset);
  1196. soEnd:
  1197. NewPos := GetCalcedSize + Offset;
  1198. else
  1199. NewPos := -1;
  1200. end;
  1201. if NewPos < 0 then
  1202. NewPos := -1
  1203. else
  1204. FPosition := NewPos;
  1205. Result := NewPos;
  1206. end;
  1207. procedure TJclBufferedStream.SetSize(const NewSize: Int64);
  1208. begin
  1209. inherited SetSize(NewSize);
  1210. if NewSize < (FBufferStart + FBufferMaxModifiedPos) then
  1211. begin
  1212. FBufferMaxModifiedPos := NewSize - FBufferStart;
  1213. if FBufferMaxModifiedPos < 0 then
  1214. FBufferMaxModifiedPos := 0;
  1215. end;
  1216. if NewSize < (FBufferStart + FBufferCurrentSize) then
  1217. begin
  1218. FBufferCurrentSize := NewSize - FBufferStart;
  1219. if FBufferCurrentSize < 0 then
  1220. FBufferCurrentSize := 0;
  1221. end;
  1222. // fix from Marcelo Rocha
  1223. if Stream <> nil then
  1224. FPosition := Stream.Position;
  1225. end;
  1226. function TJclBufferedStream.Write(const Buffer; Count: Longint): Longint;
  1227. const
  1228. Offset = 0;
  1229. begin
  1230. Result := Count + Offset;
  1231. while Count > 0 do
  1232. begin
  1233. if (FBufferStart > FPosition) or (FPosition >= (FBufferStart + FBufferSize)) then
  1234. LoadBuffer;
  1235. Dec(Count, WriteToBuffer(Buffer, Count, Result - Count));
  1236. end;
  1237. Result := Result - Count - Offset;
  1238. end;
  1239. function TJclBufferedStream.WriteToBuffer(const Buffer; Count, Start: Longint): Longint;
  1240. var
  1241. BufPos: Longint;
  1242. P: PAnsiChar;
  1243. begin
  1244. Result := Count;
  1245. BufPos := FPosition - FBufferStart;
  1246. if Result > Length(FBuffer) - BufPos then
  1247. Result := Length(FBuffer) - BufPos;
  1248. if FBufferCurrentSize < BufPos + Result then
  1249. FBufferCurrentSize := BufPos + Result;
  1250. P := @Buffer;
  1251. Move(P[Start], FBuffer[BufPos], Result);
  1252. if FBufferMaxModifiedPos < BufPos + Result then
  1253. FBufferMaxModifiedPos := BufPos + Result;
  1254. Inc(FPosition, Result);
  1255. end;
  1256. //=== { TJclEventStream } ====================================================
  1257. constructor TJclEventStream.Create(AStream: TStream; ANotification:
  1258. TStreamNotifyEvent = nil; AOwnsStream: Boolean = False);
  1259. begin
  1260. inherited Create(AStream, AOwnsStream);
  1261. FNotification := ANotification;
  1262. end;
  1263. procedure TJclEventStream.DoAfterStreamChange;
  1264. begin
  1265. inherited DoAfterStreamChange;
  1266. if Stream <> nil then
  1267. DoNotification;
  1268. end;
  1269. procedure TJclEventStream.DoBeforeStreamChange;
  1270. begin
  1271. inherited DoBeforeStreamChange;
  1272. if Stream <> nil then
  1273. DoNotification;
  1274. end;
  1275. procedure TJclEventStream.DoNotification;
  1276. begin
  1277. if Assigned(FNotification) then
  1278. FNotification(Self, Stream.Position, Stream.Size);
  1279. end;
  1280. function TJclEventStream.Read(var Buffer; Count: Longint): Longint;
  1281. begin
  1282. Result := inherited Read(Buffer, Count);
  1283. DoNotification;
  1284. end;
  1285. function TJclEventStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  1286. begin
  1287. Result := inherited Seek(Offset, Origin);
  1288. DoNotification;
  1289. end;
  1290. procedure TJclEventStream.SetSize(const NewSize: Int64);
  1291. begin
  1292. inherited SetSize(NewSize);
  1293. DoNotification;
  1294. end;
  1295. function TJclEventStream.Write(const Buffer; Count: Longint): Longint;
  1296. begin
  1297. Result := inherited Write(Buffer, Count);
  1298. DoNotification;
  1299. end;
  1300. //=== { TJclEasyStream } =====================================================
  1301. function TJclEasyStream.IsEqual(Stream: TStream): Boolean;
  1302. var
  1303. SavePos, StreamSavePos: Int64;
  1304. begin
  1305. SavePos := Position;
  1306. StreamSavePos := Stream.Position;
  1307. try
  1308. Position := 0;
  1309. Stream.Position := 0;
  1310. Result := CompareStreams(Self, Stream);
  1311. finally
  1312. Position := SavePos;
  1313. Stream.Position := StreamSavePos;
  1314. end;
  1315. end;
  1316. function TJclEasyStream.ReadBoolean: Boolean;
  1317. begin
  1318. Result := False;
  1319. ReadBuffer(Result, SizeOf(Result));
  1320. end;
  1321. function TJclEasyStream.ReadChar: Char;
  1322. begin
  1323. Result := #0;
  1324. ReadBuffer(Result, SizeOf(Result));
  1325. end;
  1326. function TJclEasyStream.ReadAnsiChar: AnsiChar;
  1327. begin
  1328. Result := #0;
  1329. ReadBuffer(Result, SizeOf(Result));
  1330. end;
  1331. function TJclEasyStream.ReadWideChar: WideChar;
  1332. begin
  1333. Result := #0;
  1334. ReadBuffer(Result, SizeOf(Result));
  1335. end;
  1336. function TJclEasyStream.ReadByte: Byte;
  1337. begin
  1338. Result := 0;
  1339. ReadBuffer(Result, SizeOf(Result));
  1340. end;
  1341. function TJclEasyStream.ReadCurrency: Currency;
  1342. begin
  1343. Result := 0;
  1344. ReadBuffer(Result, SizeOf(Result));
  1345. end;
  1346. function TJclEasyStream.ReadDateTime: TDateTime;
  1347. begin
  1348. Result := 0;
  1349. ReadBuffer(Result, SizeOf(Result));
  1350. end;
  1351. function TJclEasyStream.ReadDouble: Double;
  1352. begin
  1353. Result := 0;
  1354. ReadBuffer(Result, SizeOf(Result));
  1355. end;
  1356. function TJclEasyStream.ReadExtended: Extended;
  1357. begin
  1358. Result := 0;
  1359. ReadBuffer(Result, SizeOf(Result));
  1360. end;
  1361. function TJclEasyStream.ReadInt64: Int64;
  1362. begin
  1363. Result := 0;
  1364. ReadBuffer(Result, SizeOf(Result));
  1365. end;
  1366. function TJclEasyStream.ReadInteger: Integer;
  1367. begin
  1368. Result := 0;
  1369. ReadBuffer(Result, SizeOf(Result));
  1370. end;
  1371. function TJclEasyStream.ReadCString: string;
  1372. begin
  1373. {$IFDEF SUPPORTS_UNICODE}
  1374. Result := ReadCWideString;
  1375. {$ELSE ~SUPPORTS_UNICODE}
  1376. Result := ReadCAnsiString;
  1377. {$ENDIF ~SUPPORTS_UNICODE}
  1378. end;
  1379. function TJclEasyStream.ReadCAnsiString: AnsiString;
  1380. var
  1381. CurrPos: Longint;
  1382. StrSize: Integer;
  1383. begin
  1384. CurrPos := Position;
  1385. repeat
  1386. until ReadAnsiChar = #0;
  1387. StrSize := Position - CurrPos; // Get number of bytes
  1388. SetLength(Result, StrSize div SizeOf(AnsiChar) - 1); // Set number of chars without #0
  1389. Position := CurrPos; // Seek to start read
  1390. ReadBuffer(Result[1], StrSize); // Read ansi data and #0
  1391. end;
  1392. function TJclEasyStream.ReadCWideString: WideString;
  1393. var
  1394. CurrPos: Integer;
  1395. StrSize: Integer;
  1396. begin
  1397. CurrPos := Position;
  1398. repeat
  1399. until ReadWideChar = #0;
  1400. StrSize := Position - CurrPos; // Get number of bytes
  1401. SetLength(Result, StrSize div SizeOf(WideChar) - 1); // Set number of chars without #0
  1402. Position := CurrPos; // Seek to start read
  1403. ReadBuffer(Result[1], StrSize); // Read wide data and #0
  1404. end;
  1405. function TJclEasyStream.ReadShortString: string;
  1406. var
  1407. StrSize: Integer;
  1408. begin
  1409. StrSize := Ord(ReadChar);
  1410. SetString(Result, PChar(nil), StrSize);
  1411. ReadBuffer(Pointer(Result)^, StrSize);
  1412. end;
  1413. function TJclEasyStream.ReadSingle: Single;
  1414. begin
  1415. Result := 0;
  1416. ReadBuffer(Result, SizeOf(Result));
  1417. end;
  1418. function TJclEasyStream.ReadSizedString: string;
  1419. begin
  1420. {$IFDEF SUPPORTS_UNICODE}
  1421. Result := ReadSizedWideString;
  1422. {$ELSE ~SUPPORTS_UNICODE}
  1423. Result := ReadSizedAnsiString;
  1424. {$ENDIF ~SUPPORTS_UNICODE}
  1425. end;
  1426. function TJclEasyStream.ReadSizedAnsiString: AnsiString;
  1427. var
  1428. StrSize: Integer;
  1429. begin
  1430. StrSize := ReadInteger;
  1431. SetLength(Result, StrSize);
  1432. ReadBuffer(Result[1], StrSize * SizeOf(Result[1]));
  1433. end;
  1434. function TJclEasyStream.ReadSizedWideString: WideString;
  1435. var
  1436. StrSize: Integer;
  1437. begin
  1438. StrSize := ReadInteger;
  1439. SetLength(Result, StrSize);
  1440. ReadBuffer(Result[1], StrSize * SizeOf(Result[1]));
  1441. end;
  1442. procedure TJclEasyStream.WriteBoolean(Value: Boolean);
  1443. begin
  1444. WriteBuffer(Value, SizeOf(Value));
  1445. end;
  1446. procedure TJclEasyStream.WriteChar(Value: Char);
  1447. begin
  1448. WriteBuffer(Value, SizeOf(Value));
  1449. end;
  1450. procedure TJclEasyStream.WriteAnsiChar(Value: AnsiChar);
  1451. begin
  1452. WriteBuffer(Value, SizeOf(Value));
  1453. end;
  1454. procedure TJclEasyStream.WriteWideChar(Value: WideChar);
  1455. begin
  1456. WriteBuffer(Value, SizeOf(Value));
  1457. end;
  1458. procedure TJclEasyStream.WriteByte(Value: Byte);
  1459. begin
  1460. WriteBuffer(Value, SizeOf(Value));
  1461. end;
  1462. procedure TJclEasyStream.WriteCurrency(const Value: Currency);
  1463. begin
  1464. WriteBuffer(Value, SizeOf(Value));
  1465. end;
  1466. procedure TJclEasyStream.WriteDateTime(const Value: TDateTime);
  1467. begin
  1468. WriteBuffer(Value, SizeOf(Value));
  1469. end;
  1470. procedure TJclEasyStream.WriteDouble(const Value: Double);
  1471. begin
  1472. WriteBuffer(Value, SizeOf(Value));
  1473. end;
  1474. procedure TJclEasyStream.WriteExtended(const Value: Extended);
  1475. begin
  1476. WriteBuffer(Value, SizeOf(Value));
  1477. end;
  1478. procedure TJclEasyStream.WriteInt64(Value: Int64);
  1479. begin
  1480. WriteBuffer(Value, SizeOf(Value));
  1481. end;
  1482. procedure TJclEasyStream.WriteInteger(Value: Integer);
  1483. begin
  1484. WriteBuffer(Value, SizeOf(Value));
  1485. end;
  1486. procedure TJclEasyStream.WriteCString(const Value: string);
  1487. begin
  1488. {$IFDEF SUPPORTS_UNICODE}
  1489. WriteCWideString(Value);
  1490. {$ELSE ~SUPPORTS_UNICODE}
  1491. WriteCAnsiString(Value);
  1492. {$ENDIF ~SUPPORTS_UNICODE}
  1493. end;
  1494. procedure TJclEasyStream.WriteCAnsiString(const Value: AnsiString);
  1495. var
  1496. StrSize: Integer;
  1497. begin
  1498. StrSize := Length(Value);
  1499. WriteBuffer(Value[1], (StrSize + 1) * SizeOf(Value[1]));
  1500. end;
  1501. procedure TJclEasyStream.WriteCWideString(const Value: WideString);
  1502. var
  1503. StrSize: Integer;
  1504. begin
  1505. StrSize := Length(Value);
  1506. WriteBuffer(Value[1], (StrSize + 1) * SizeOf(Value[1]));
  1507. end;
  1508. procedure TJclEasyStream.WriteShortString(const Value: ShortString);
  1509. begin
  1510. WriteBuffer(Value[0], Length(Value) + 1);
  1511. end;
  1512. procedure TJclEasyStream.WriteSingle(const Value: Single);
  1513. begin
  1514. WriteBuffer(Value, SizeOf(Value));
  1515. end;
  1516. procedure TJclEasyStream.WriteSizedString(const Value: string);
  1517. begin
  1518. {$IFDEF SUPPORTS_UNICODE}
  1519. WriteSizedWideString(Value);
  1520. {$ELSE ~SUPPORTS_UNICODE}
  1521. WriteSizedAnsiString(Value);
  1522. {$ENDIF ~SUPPORTS_UNICODE}
  1523. end;
  1524. procedure TJclEasyStream.WriteSizedAnsiString(const Value: AnsiString);
  1525. var
  1526. StrSize: Integer;
  1527. begin
  1528. StrSize := Length(Value);
  1529. WriteInteger(StrSize);
  1530. WriteBuffer(Value[1], StrSize * SizeOf(Value[1]));
  1531. end;
  1532. procedure TJclEasyStream.WriteSizedWideString(const Value: WideString);
  1533. var
  1534. StrSize: Integer;
  1535. begin
  1536. StrSize := Length(Value);
  1537. WriteInteger(StrSize);
  1538. WriteBuffer(Value[1], StrSize * SizeOf(Value[1]));
  1539. end;
  1540. //=== { TJclScopedStream } ===================================================
  1541. constructor TJclScopedStream.Create(AParentStream: TStream; const AMaxSize: Int64);
  1542. begin
  1543. inherited Create;
  1544. FParentStream := AParentStream;
  1545. FStartPos := ParentStream.Position;
  1546. FCurrentPos := 0;
  1547. FMaxSize := AMaxSize;
  1548. end;
  1549. constructor TJclScopedStream.Create(AParentStream: TStream; const AStartPos, AMaxSize: Int64);
  1550. begin
  1551. inherited Create;
  1552. FParentStream := AParentStream;
  1553. FStartPos := AStartPos;
  1554. FCurrentPos := 0;
  1555. FMaxSize := AMaxSize;
  1556. end;
  1557. function TJclScopedStream.Read(var Buffer; Count: Longint): Longint;
  1558. begin
  1559. if (MaxSize >= 0) and ((FCurrentPos + Count) > MaxSize) then
  1560. Count := MaxSize - FCurrentPos;
  1561. if (Count > 0) and Assigned(ParentStream) then
  1562. begin
  1563. Result := ParentStream.Read(Buffer, Count);
  1564. Inc(FCurrentPos, Result);
  1565. end
  1566. else
  1567. Result := 0;
  1568. end;
  1569. function TJclScopedStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  1570. begin
  1571. case Origin of
  1572. soBeginning:
  1573. begin
  1574. if (Offset < 0) or ((MaxSize >= 0) and (Offset > MaxSize)) then
  1575. Result := -1 // low and high bound check
  1576. else
  1577. Result := ParentStream.Seek(StartPos + Offset, soBeginning) - StartPos;
  1578. end;
  1579. soCurrent:
  1580. begin
  1581. if Offset = 0 then
  1582. Result := FCurrentPos // speeding the Position property up
  1583. else if ((FCurrentPos + Offset) < 0) or ((MaxSize >= 0)
  1584. and ((FCurrentPos + Offset) > MaxSize)) then
  1585. Result := -1 // low and high bound check
  1586. else
  1587. Result := ParentStream.Seek(Offset, soCurrent) - StartPos;
  1588. end;
  1589. soEnd:
  1590. begin
  1591. if (MaxSize >= 0) then
  1592. begin
  1593. if (Offset > 0) or (MaxSize < -Offset) then // low and high bound check
  1594. Result := -1
  1595. else
  1596. Result := ParentStream.Seek(StartPos + MaxSize + Offset, soBeginning) - StartPos;
  1597. end
  1598. else
  1599. begin
  1600. Result := ParentStream.Seek(Offset, soEnd);
  1601. if (Result <> -1) and (Result < StartPos) then // low bound check
  1602. begin
  1603. Result := -1;
  1604. ParentStream.Seek(StartPos + FCurrentPos, soBeginning);
  1605. end;
  1606. end;
  1607. end;
  1608. else
  1609. Result := -1;
  1610. end;
  1611. if Result <> -1 then
  1612. FCurrentPos := Result;
  1613. end;
  1614. procedure TJclScopedStream.SetSize(const NewSize: Int64);
  1615. var
  1616. ScopedNewSize: Int64;
  1617. begin
  1618. if (FMaxSize >= 0) and (NewSize >= (FStartPos + FMaxSize)) then
  1619. ScopedNewSize := FMaxSize + FStartPos
  1620. else
  1621. ScopedNewSize := NewSize;
  1622. inherited SetSize(ScopedNewSize);
  1623. end;
  1624. function TJclScopedStream.Write(const Buffer; Count: Longint): Longint;
  1625. begin
  1626. if (MaxSize >= 0) and ((FCurrentPos + Count) > MaxSize) then
  1627. Count := MaxSize - FCurrentPos;
  1628. if (Count > 0) and Assigned(ParentStream) then
  1629. begin
  1630. Result := ParentStream.Write(Buffer, Count);
  1631. Inc(FCurrentPos, Result);
  1632. end
  1633. else
  1634. Result := 0;
  1635. end;
  1636. //=== { TJclDelegateStream } =================================================
  1637. procedure TJclDelegatedStream.SetSize(const NewSize: Int64);
  1638. begin
  1639. if Assigned(FOnSize) then
  1640. FOnSize(Self, NewSize);
  1641. end;
  1642. function TJclDelegatedStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  1643. begin
  1644. if Assigned(FOnSeek) then
  1645. Result := FOnSeek(Self, Offset, Origin)
  1646. else
  1647. Result := -1;
  1648. end;
  1649. function TJclDelegatedStream.Read(var Buffer; Count: Longint): Longint;
  1650. begin
  1651. if Assigned(FOnRead) then
  1652. Result := FOnRead(Self, Buffer, Count)
  1653. else
  1654. Result := -1;
  1655. end;
  1656. function TJclDelegatedStream.Write(const Buffer; Count: Longint): Longint;
  1657. begin
  1658. if Assigned(FOnWrite) then
  1659. Result := FOnWrite(Self, Buffer, Count)
  1660. else
  1661. Result := -1;
  1662. end;
  1663. //=== { TJclSectoredStream } =================================================
  1664. procedure TJclSectoredStream.AfterBlockRead;
  1665. begin
  1666. // override to customize (checks of protection)
  1667. end;
  1668. procedure TJclSectoredStream.BeforeBlockWrite;
  1669. begin
  1670. // override to customize (computation of protection)
  1671. end;
  1672. constructor TJclSectoredStream.Create(AStorageStream: TStream;
  1673. AOwnsStream: Boolean; ASectorOverHead: Integer);
  1674. begin
  1675. inherited Create(AStorageStream, AOwnsStream);
  1676. FSectorOverHead := ASectorOverHead;
  1677. if Stream <> nil then
  1678. FPosition := SectoredToFlat(Stream.Position);
  1679. end;
  1680. procedure TJclSectoredStream.DoAfterStreamChange;
  1681. begin
  1682. inherited DoAfterStreamChange;
  1683. if Stream <> nil then
  1684. FPosition := SectoredToFlat(Stream.Position);
  1685. end;
  1686. function TJclSectoredStream.FlatToSectored(const Position: Int64): Int64;
  1687. begin
  1688. Result := (Position div BufferSize) * (Int64(BufferSize) + FSectorOverHead) // add overheads of previous buffers
  1689. + (Position mod BufferSize); // offset in sector
  1690. end;
  1691. procedure TJclSectoredStream.Flush;
  1692. begin
  1693. if (Stream <> nil) and (FBufferMaxModifiedPos > 0) then
  1694. begin
  1695. BeforeBlockWrite;
  1696. Stream.Position := FlatToSectored(FBufferStart);
  1697. Stream.WriteBuffer(FBuffer[0], FBufferCurrentSize + FSectorOverHead);
  1698. FBufferMaxModifiedPos := 0;
  1699. end;
  1700. end;
  1701. function TJclSectoredStream.GetCalcedSize: Int64;
  1702. var
  1703. VirtualSize: Int64;
  1704. begin
  1705. if Assigned(Stream) then
  1706. Result := SectoredToFlat(Stream.Size)
  1707. else
  1708. Result := 0;
  1709. VirtualSize := FBufferMaxModifiedPos + FBufferStart;
  1710. if Result < VirtualSize then
  1711. Result := VirtualSize;
  1712. end;
  1713. function TJclSectoredStream.LoadBuffer: Boolean;
  1714. var
  1715. TotalSectorSize: Longint;
  1716. begin
  1717. Flush;
  1718. TotalSectorSize := FBufferSize + FSectorOverHead;
  1719. if Length(FBuffer) <> TotalSectorSize then
  1720. SetLength(FBuffer, TotalSectorSize);
  1721. FBufferStart := (FPosition div BufferSize) * BufferSize;
  1722. if Stream <> nil then
  1723. begin
  1724. Stream.Position := FlatToSectored(FBufferStart);
  1725. FBufferCurrentSize := Stream.Read(FBuffer[0], TotalSectorSize);
  1726. if FBufferCurrentSize > 0 then
  1727. begin
  1728. Dec(FBufferCurrentSize, FSectorOverHead);
  1729. AfterBlockRead;
  1730. end;
  1731. end
  1732. else
  1733. FBufferCurrentSize := 0;
  1734. Result := (FBufferCurrentSize > 0);
  1735. end;
  1736. function TJclSectoredStream.SectoredToFlat(const Position: Int64): Int64;
  1737. var
  1738. TotalSectorSize: Int64;
  1739. begin
  1740. TotalSectorSize := Int64(BufferSize) + FSectorOverHead;
  1741. Result := (Position div TotalSectorSize) * BufferSize // remove previous overheads
  1742. + Position mod TotalSectorSize; // offset in sector
  1743. end;
  1744. procedure TJclSectoredStream.SetSize(const NewSize: Int64);
  1745. begin
  1746. inherited SetSize(FlatToSectored(NewSize));
  1747. end;
  1748. //=== { TJclCRC16Stream } ====================================================
  1749. procedure TJclCRC16Stream.AfterBlockRead;
  1750. var
  1751. CRC: Word;
  1752. begin
  1753. CRC := Word(FBuffer[FBufferCurrentSize]) or (Word(FBuffer[FBufferCurrentSize + 1]) shl 8);
  1754. if CheckCrc16(FBuffer, FBufferCurrentSize, CRC) < 0 then
  1755. raise EJclStreamError.CreateRes(@RsStreamsCRCError);
  1756. end;
  1757. procedure TJclCRC16Stream.BeforeBlockWrite;
  1758. var
  1759. CRC: Word;
  1760. begin
  1761. CRC := Crc16(FBuffer, FBufferCurrentSize);
  1762. FBuffer[FBufferCurrentSize] := CRC and $FF;
  1763. FBuffer[FBufferCurrentSize + 1] := CRC shr 8;
  1764. end;
  1765. constructor TJclCRC16Stream.Create(AStorageStream: TStream; AOwnsStream: Boolean);
  1766. begin
  1767. inherited Create(AStorageStream, AOwnsStream, 2);
  1768. end;
  1769. //=== { TJclCRC32Stream } ====================================================
  1770. procedure TJclCRC32Stream.AfterBlockRead;
  1771. var
  1772. CRC: Cardinal;
  1773. begin
  1774. CRC := Cardinal(FBuffer[FBufferCurrentSize]) or (Cardinal(FBuffer[FBufferCurrentSize + 1]) shl 8)
  1775. or (Cardinal(FBuffer[FBufferCurrentSize + 2]) shl 16) or (Cardinal(FBuffer[FBufferCurrentSize + 3]) shl 24);
  1776. if CheckCrc32(FBuffer, FBufferCurrentSize, CRC) < 0 then
  1777. raise EJclStreamError.CreateRes(@RsStreamsCRCError);
  1778. end;
  1779. procedure TJclCRC32Stream.BeforeBlockWrite;
  1780. var
  1781. CRC: Cardinal;
  1782. begin
  1783. CRC := Crc32(FBuffer, FBufferCurrentSize);
  1784. FBuffer[FBufferCurrentSize] := CRC and $FF;
  1785. FBuffer[FBufferCurrentSize + 1] := (CRC shr 8) and $FF;
  1786. FBuffer[FBufferCurrentSize + 2] := (CRC shr 16) and $FF;
  1787. FBuffer[FBufferCurrentSize + 3] := (CRC shr 24) and $FF;
  1788. end;
  1789. constructor TJclCRC32Stream.Create(AStorageStream: TStream;
  1790. AOwnsStream: Boolean);
  1791. begin
  1792. inherited Create(AStorageStream, AOwnsStream, 4);
  1793. end;
  1794. //=== { TJclSplitStream } ====================================================
  1795. constructor TJclSplitStream.Create(AForcePosition: Boolean);
  1796. begin
  1797. inherited Create;
  1798. FVolume := nil;
  1799. FVolumeIndex := -1;
  1800. FVolumeMaxSize := 0;
  1801. FPosition := 0;
  1802. FVolumePosition := 0;
  1803. FForcePosition := AForcePosition;
  1804. end;
  1805. function TJclSplitStream.GetSize: Int64;
  1806. var
  1807. OldVolumeIndex: Integer;
  1808. OldVolumePosition, OldPosition: Int64;
  1809. begin
  1810. OldVolumeIndex := FVolumeIndex;
  1811. OldVolumePosition := FVolumePosition;
  1812. OldPosition := FPosition;
  1813. Result := 0;
  1814. try
  1815. FVolumeIndex := -1;
  1816. repeat
  1817. if not InternalLoadVolume(FVolumeIndex + 1) then
  1818. Break;
  1819. Result := Result + FVolume.Size;
  1820. until FVolume.Size = 0;
  1821. finally
  1822. InternalLoadVolume(OldVolumeIndex);
  1823. FPosition := OldPosition;
  1824. if Assigned(FVolume) then
  1825. FVolumePosition := FVolume.Seek(OldVolumePosition, soBeginning);
  1826. end;
  1827. end;
  1828. function TJclSplitStream.InternalLoadVolume(Index: Integer): Boolean;
  1829. var
  1830. OldVolumeIndex: Integer;
  1831. OldVolumePosition: Int64;
  1832. OldVolume: TStream;
  1833. begin
  1834. if Index = -1 then
  1835. Index := 0;
  1836. if Index <> FVolumeIndex then
  1837. begin
  1838. // save current pointers
  1839. OldVolumeIndex := FVolumeIndex;
  1840. OldVolumePosition := FVolumePosition;
  1841. OldVolume := FVolume;
  1842. FVolumeIndex := Index;
  1843. FVolumePosition := 0;
  1844. FVolume := GetVolume(Index);
  1845. Result := Assigned(FVolume);
  1846. if Result then begin
  1847. FVolumeMaxSize := GetVolumeMaxSize(Index);
  1848. FVolume.Seek(0, soBeginning)
  1849. end
  1850. else
  1851. begin
  1852. // restore old pointers if volume load failed
  1853. FVolumeIndex := OldVolumeIndex;
  1854. FVolumePosition := OldVolumePosition;
  1855. FVolume := OldVolume;
  1856. end;
  1857. end
  1858. else
  1859. Result := Assigned(FVolume);
  1860. end;
  1861. function TJclSplitStream.Read(var Buffer; Count: Longint): Longint;
  1862. var
  1863. Data: PByte;
  1864. Total, LoopRead: Longint;
  1865. begin
  1866. Result := 0;
  1867. if not InternalLoadVolume(FVolumeIndex) then
  1868. Exit;
  1869. Data := PByte(@Buffer);
  1870. Total := Count;
  1871. repeat
  1872. // force position
  1873. if ForcePosition then
  1874. FVolume.Seek(FVolumePosition, soBeginning);
  1875. // try to read (Count) bytes from current stream
  1876. LoopRead := FVolume.Read(Data^, Count);
  1877. FVolumePosition := FVolumePosition + LoopRead;
  1878. FPosition := FPosition + LoopRead;
  1879. Inc(Result, LoopRead);
  1880. if Result = Total then
  1881. Break;
  1882. // with next volume
  1883. Dec(Count, LoopRead);
  1884. Inc(Data, LoopRead);
  1885. if not InternalLoadVolume(FVolumeIndex + 1) then
  1886. Break;
  1887. until False;
  1888. end;
  1889. function TJclSplitStream.Seek(const Offset: Int64;
  1890. Origin: TSeekOrigin): Int64;
  1891. var
  1892. ExpectedPosition, RemainingOffset: Int64;
  1893. begin
  1894. case TSeekOrigin(Origin) of
  1895. soBeginning:
  1896. ExpectedPosition := Offset;
  1897. soCurrent:
  1898. ExpectedPosition := FPosition + Offset;
  1899. soEnd:
  1900. ExpectedPosition := Size + Offset;
  1901. else
  1902. raise EJclStreamError.CreateRes(@RsStreamsSeekError);
  1903. end;
  1904. RemainingOffset := ExpectedPosition - FPosition;
  1905. Result := FPosition;
  1906. repeat
  1907. if not InternalLoadVolume(FVolumeIndex) then
  1908. Break;
  1909. if RemainingOffset < 0 then
  1910. begin
  1911. // FPosition > ExpectedPosition, seek backward
  1912. if FVolumePosition >= -RemainingOffset then
  1913. begin
  1914. // seek in current volume
  1915. FVolumePosition := FVolume.Seek(FVolumePosition + RemainingOffset, soBeginning);
  1916. Result := Result + RemainingOffset;
  1917. FPosition := Result;
  1918. RemainingOffset := 0;
  1919. end
  1920. else
  1921. begin
  1922. // seek to previous volume
  1923. if FVolumeIndex = 0 then
  1924. Exit;
  1925. // seek to the beginning of current volume
  1926. RemainingOffset := RemainingOffset + FVolumePosition;
  1927. Result := Result - FVolumePosition;
  1928. FPosition := Result;
  1929. FVolumePosition := FVolume.Seek(0, soBeginning);
  1930. // load previous volume
  1931. if not InternalLoadVolume(FVolumeIndex - 1) then
  1932. Break;
  1933. Result := Result - FVolume.Size;
  1934. FPosition := Result;
  1935. RemainingOffset := RemainingOffset + FVolume.Size;
  1936. end;
  1937. end
  1938. else if RemainingOffset > 0 then
  1939. begin
  1940. // FPosition < ExpectedPosition, seek forward
  1941. if (FVolumeMaxSize = 0) or ((FVolumePosition + RemainingOffset) < FVolumeMaxSize) then
  1942. begin
  1943. // can seek in current volume
  1944. FVolumePosition := FVolume.Seek(FVolumePosition + RemainingOffset, soBeginning);
  1945. Result := Result + RemainingOffset;
  1946. FPosition := Result;
  1947. RemainingOffset := 0;
  1948. end
  1949. else
  1950. begin
  1951. // seek to next volume
  1952. RemainingOffset := RemainingOffset - FVolumeMaxSize + FVolumePosition;
  1953. Result := Result + FVolumeMaxSize - FVolumePosition;
  1954. FPosition := Result;
  1955. if not InternalLoadVolume(FVolumeIndex + 1) then begin
  1956. FVolumePosition := FVolumeMaxSize;
  1957. Break;
  1958. end;
  1959. end;
  1960. end;
  1961. until RemainingOffset = 0;
  1962. end;
  1963. procedure TJclSplitStream.SetSize(const NewSize: Int64);
  1964. var
  1965. OldVolumeIndex: Integer;
  1966. OldVolumePosition, OldPosition, RemainingSize, VolumeSize: Int64;
  1967. begin
  1968. OldVolumeIndex := FVolumeIndex;
  1969. OldVolumePosition := FVolumePosition;
  1970. OldPosition := FPosition;
  1971. RemainingSize := NewSize;
  1972. try
  1973. FVolumeIndex := 0;
  1974. repeat
  1975. if not InternalLoadVolume(FVolumeIndex) then
  1976. Break;
  1977. if (FVolumeMaxSize > 0) and (RemainingSize > FVolumeMaxSize) then
  1978. VolumeSize := FVolumeMaxSize
  1979. else
  1980. VolumeSize := RemainingSize;
  1981. FVolume.Size := VolumeSize;
  1982. RemainingSize := RemainingSize - VolumeSize;
  1983. Inc(FVolumeIndex);
  1984. until RemainingSize = 0;
  1985. finally
  1986. InternalLoadVolume(OldVolumeIndex);
  1987. FPosition := OldPosition;
  1988. if Assigned(FVolume) then
  1989. FVolumePosition := FVolume.Seek(OldVolumePosition, soBeginning);
  1990. end;
  1991. end;
  1992. function TJclSplitStream.Write(const Buffer; Count: Longint): Longint;
  1993. var
  1994. Data: PByte;
  1995. Total, LoopWritten: Longint;
  1996. begin
  1997. Result := 0;
  1998. if not InternalLoadVolume(FVolumeIndex) then
  1999. Exit;
  2000. Data := PByte(@Buffer);
  2001. Total := Count;
  2002. repeat
  2003. // force position
  2004. if ForcePosition then
  2005. FVolume.Seek(FVolumePosition, soBeginning);
  2006. // do not write more than (VolumeMaxSize) bytes in current stream
  2007. if (FVolumeMaxSize > 0) and ((Count + FVolumePosition) > FVolumeMaxSize) then
  2008. LoopWritten := FVolumeMaxSize - FVolumePosition
  2009. else
  2010. LoopWritten := Count;
  2011. // try to write (Count) bytes from current stream
  2012. LoopWritten := FVolume.Write(Data^, LoopWritten);
  2013. FVolumePosition := FVolumePosition + LoopWritten;
  2014. FPosition := FPosition + LoopWritten;
  2015. Inc(Result, LoopWritten);
  2016. if Result = Total then
  2017. Break;
  2018. // with next volume
  2019. Dec(Count, LoopWritten);
  2020. Inc(Data, LoopWritten);
  2021. if not InternalLoadVolume(FVolumeIndex + 1) then
  2022. Break;
  2023. until False;
  2024. end;
  2025. //=== { TJclDynamicSplitStream } =============================================
  2026. function TJclDynamicSplitStream.GetVolume(Index: Integer): TStream;
  2027. begin
  2028. if Assigned(FOnVolume) then
  2029. Result := FOnVolume(Index)
  2030. else
  2031. Result := nil;
  2032. end;
  2033. function TJclDynamicSplitStream.GetVolumeMaxSize(Index: Integer): Int64;
  2034. begin
  2035. if Assigned(FOnVolumeMaxSize) then
  2036. Result := FOnVolumeMaxSize(Index)
  2037. else
  2038. Result := 0;
  2039. end;
  2040. //=== { TJclStaticSplitStream } ===========================================
  2041. constructor TJclStaticSplitStream.Create(AForcePosition: Boolean);
  2042. begin
  2043. inherited Create(AForcePosition);
  2044. FVolumes := TObjectList.Create(True);
  2045. end;
  2046. destructor TJclStaticSplitStream.Destroy;
  2047. var
  2048. Index: Integer;
  2049. AVolumeRec: TJclSplitVolume;
  2050. begin
  2051. if Assigned(FVolumes) then
  2052. begin
  2053. for Index := 0 to FVolumes.Count - 1 do
  2054. begin
  2055. AVolumeRec := TJclSplitVolume(FVolumes.Items[Index]);
  2056. if AVolumeRec.OwnStream then
  2057. AVolumeRec.Stream.Free;
  2058. end;
  2059. FVolumes.Free;
  2060. end;
  2061. inherited Destroy;
  2062. end;
  2063. function TJclStaticSplitStream.AddVolume(AStream: TStream; AMaxSize: Int64;
  2064. AOwnStream: Boolean): Integer;
  2065. var
  2066. AVolumeRec: TJclSplitVolume;
  2067. begin
  2068. AVolumeRec := TJclSplitVolume.Create;
  2069. AVolumeRec.MaxSize := AMaxSize;
  2070. AVolumeRec.Stream := AStream;
  2071. AVolumeRec.OwnStream := AOwnStream;
  2072. Result := FVolumes.Add(AVolumeRec);
  2073. end;
  2074. function TJclStaticSplitStream.GetVolume(Index: Integer): TStream;
  2075. begin
  2076. Result := TJclSplitVolume(FVolumes.Items[Index]).Stream;
  2077. end;
  2078. function TJclStaticSplitStream.GetVolumeCount: Integer;
  2079. begin
  2080. Result := FVolumes.Count;
  2081. end;
  2082. function TJclStaticSplitStream.GetVolumeMaxSize(Index: Integer): Int64;
  2083. begin
  2084. Result := TJclSplitVolume(FVolumes.Items[Index]).MaxSize;
  2085. end;
  2086. //=== { TJclStringStream } ====================================================
  2087. constructor TJclStringStream.Create(AStream: TStream; AOwnsStream: Boolean);
  2088. begin
  2089. inherited Create;
  2090. FStream := AStream;
  2091. FOwnStream := AOwnsStream;
  2092. FBufferSize := StreamDefaultBufferSize;
  2093. end;
  2094. destructor TJclStringStream.Destroy;
  2095. begin
  2096. Flush;
  2097. if FOwnStream then
  2098. FStream.Free;
  2099. inherited;
  2100. end;
  2101. procedure TJclStringStream.Flush;
  2102. begin
  2103. if FStrBufferModifiedSize > 0 then
  2104. begin
  2105. FStream.Position := FStrBufferStart;
  2106. InternalSetNextBuffer(FStream, FStrBuffer, 0, FStrBufferModifiedSize);
  2107. FStrBufferNext := FStream.Seek(0, soCurrent);
  2108. FStrBufferModifiedSize := 0;
  2109. end;
  2110. end;
  2111. function TJclStringStream.InternalGetNextBuffer(S: TStream;
  2112. var Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2113. var
  2114. Ch: UCS4;
  2115. begin
  2116. // override to optimize
  2117. Result := 0;
  2118. while Count > 0 do
  2119. begin
  2120. if InternalGetNextChar(S, Ch) then
  2121. begin
  2122. Buffer[Start] := Ch;
  2123. Inc(Start);
  2124. Inc(Result);
  2125. end
  2126. else
  2127. Break;
  2128. Dec(Count);
  2129. end;
  2130. end;
  2131. function TJclStringStream.InternalSetNextBuffer(S: TStream;
  2132. const Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2133. begin
  2134. // override to optimize
  2135. Result := 0;
  2136. while Count > 0 do
  2137. begin
  2138. if InternalSetNextChar(S, Buffer[Start]) then
  2139. begin
  2140. Inc(Start);
  2141. Inc(Result);
  2142. end
  2143. else
  2144. Break;
  2145. Dec(Count);
  2146. end;
  2147. end;
  2148. procedure TJclStringStream.InvalidateBuffers;
  2149. begin
  2150. FStrBufferStart := FStream.Seek(0, soCurrent);
  2151. FStrBufferNext := FStrBufferStart;
  2152. FStrBufferPosition := 0;
  2153. FStrBufferCurrentSize := 0;
  2154. FStrBufferModifiedSize := 0;
  2155. FStrPeekBufferStart := FStrBufferStart;
  2156. FStrPeekBufferNext := FStrBufferNext;
  2157. FStrPeekPosition := 0;
  2158. FStrPeekBufferCurrentSize := 0;
  2159. end;
  2160. function TJclStringStream.LoadBuffer: Boolean;
  2161. begin
  2162. Flush;
  2163. // first test if the peek buffer contains the value
  2164. if (FStrBufferNext >= FStrPeekBufferStart) and (FStrBufferNext < FStrPeekBufferNext) then
  2165. begin
  2166. // the requested buffer is already loaded in the peek buffer
  2167. FStrBufferStart := FStrPeekBufferStart;
  2168. FStrBufferNext := FStrPeekBufferNext;
  2169. if Length(FStrBuffer) <> Length(FStrPeekBuffer) then
  2170. SetLength(FStrBuffer, Length(FStrPeekBuffer));
  2171. FStrBufferPosition := FStrPeekBufferPosition;
  2172. FStrBufferCurrentSize := FStrPeekBufferCurrentSize;
  2173. Move(FStrPeekBuffer[0], FStrBuffer[0], FStrBufferCurrentSize * SizeOf(FStrBuffer[0]));
  2174. end
  2175. else
  2176. begin
  2177. // load a new buffer
  2178. if Length(FStrBuffer) <> FBufferSize then
  2179. SetLength(FStrBuffer, FBufferSize);
  2180. Inc(FStrBufferPosition, FStrBufferCurrentSize);
  2181. FStrBufferStart := FStrBufferNext;
  2182. FStream.Seek(FStrBufferStart, soBeginning);
  2183. FStrBufferCurrentSize := InternalGetNextBuffer(FStream, FStrBuffer, 0, FBufferSize);
  2184. FStrBufferNext := FStream.Seek(0, soCurrent);
  2185. // reset the peek buffer
  2186. FStrPeekBufferPosition := FStrBufferPosition + FStrBufferCurrentSize;
  2187. FStrPeekBufferCurrentSize := 0;
  2188. FStrPeekBufferNext := FStrBufferNext;
  2189. FStrPeekBufferStart := FStrBufferNext;
  2190. end;
  2191. Result := (FStrPosition >= FStrBufferPosition) and (FStrPosition < (FStrBufferPosition + FStrBufferCurrentSize));
  2192. end;
  2193. function TJclStringStream.LoadPeekBuffer: Boolean;
  2194. begin
  2195. if Length(FStrPeekBuffer) <> FBufferSize then
  2196. SetLength(FStrPeekBuffer, FBufferSize);
  2197. if FStrPeekBufferPosition > FStrPeekPosition then
  2198. begin
  2199. // the peek position is rolling back, load the buffer after the read buffer
  2200. FStrPeekBufferPosition := FStrBufferPosition;
  2201. FStrPeekBufferCurrentSize := FStrBufferCurrentSize;
  2202. FStrPeekBufferStart := FStrBufferStart;
  2203. FStrPeekBufferNext := FStrBufferNext;
  2204. end;
  2205. FStrPeekBufferStart := FStrPeekBufferNext;
  2206. Inc(FStrPeekBufferPosition, FStrPeekBufferCurrentSize);
  2207. FStream.Seek(FStrPeekBufferStart, soBeginning);
  2208. FStrPeekBufferCurrentSize := InternalGetNextBuffer(FStream, FStrPeekBuffer, 0, FBufferSize);
  2209. FStrPeekBufferNext := FStream.Seek(0, soCurrent);
  2210. Result := (FStrPeekPosition >= FStrPeekBufferPosition) and (FStrPeekPosition < (FStrPeekBufferPosition + FStrPeekBufferCurrentSize));
  2211. end;
  2212. function TJclStringStream.PeekAnsiChar(out Buffer: AnsiChar): Boolean;
  2213. var
  2214. Ch: UCS4;
  2215. begin
  2216. Result := PeekUCS4(Ch);
  2217. if Result then
  2218. Buffer := UCS4ToAnsiChar(Ch);
  2219. end;
  2220. function TJclStringStream.PeekChar(out Buffer: Char): Boolean;
  2221. var
  2222. Ch: UCS4;
  2223. begin
  2224. Result := PeekUCS4(Ch);
  2225. if Result then
  2226. Buffer := UCS4ToChar(Ch);
  2227. end;
  2228. function TJclStringStream.PeekUCS4(out Buffer: UCS4): Boolean;
  2229. begin
  2230. if (FStrPeekPosition >= FStrPeekBufferPosition) and (FStrPeekPosition < (FStrPeekBufferPosition + FStrPeekBufferCurrentSize)) then
  2231. begin
  2232. // read from the peek buffer
  2233. Result := True;
  2234. Buffer := FStrPeekBuffer[FStrPeekPosition - FStrPeekBufferPosition];
  2235. Inc(FStrPeekPosition);
  2236. end
  2237. else
  2238. if (FStrPeekPosition >= FStrBufferPosition) and (FStrPeekPosition < (FStrBufferPosition + FStrBufferCurrentSize)) then
  2239. begin
  2240. // read from the read/write buffer
  2241. Result := True;
  2242. Buffer := FStrBuffer[FStrPeekPosition - FStrBufferPosition];
  2243. Inc(FStrPeekPosition);
  2244. end
  2245. else
  2246. begin
  2247. // load a new peek buffer
  2248. Result := LoadPeekBuffer;
  2249. if Result then
  2250. begin
  2251. Buffer := FStrPeekBuffer[FStrPeekPosition - FStrPeekBufferPosition];
  2252. Inc(FStrPeekPosition);
  2253. end;
  2254. end;
  2255. end;
  2256. function TJclStringStream.PeekWideChar(out Buffer: WideChar): Boolean;
  2257. var
  2258. Ch: UCS4;
  2259. begin
  2260. Result := PeekUCS4(Ch);
  2261. if Result then
  2262. Buffer := UCS4ToWideChar(Ch);
  2263. end;
  2264. function TJclStringStream.ReadString(var Buffer: string; Start, Count: Longint): Longint;
  2265. var
  2266. Index: Integer;
  2267. StrPos: SizeInt;
  2268. Ch: UCS4;
  2269. begin
  2270. Index := Start;
  2271. while Index < Start + Count - 1 do // avoid overflow on surrogate pairs for WideString
  2272. begin
  2273. if ReadUCS4(Ch) then
  2274. begin
  2275. StrPos := Index;
  2276. if StringSetNextChar(Buffer, StrPos, Ch) and (StrPos > 0) then
  2277. Index := StrPos
  2278. else
  2279. Break; // end of string (write)
  2280. end
  2281. else
  2282. Break; // end of stream (read)
  2283. end;
  2284. Result := Index - Start;
  2285. end;
  2286. function TJclStringStream.ReadString(BufferSize: Longint): string;
  2287. var
  2288. Buffer: string;
  2289. ProcessedLength: Longint;
  2290. begin
  2291. Result := '';
  2292. SetLength(Buffer, BufferSize);
  2293. repeat
  2294. ProcessedLength := ReadString(Buffer, 1, BufferSize);
  2295. if ProcessedLength > 0 then
  2296. Result := Result + Copy(Buffer, 1, ProcessedLength);
  2297. until ProcessedLength = 0;
  2298. end;
  2299. function TJclStringStream.ReadAnsiChar(out Buffer: AnsiChar): Boolean;
  2300. var
  2301. Ch: UCS4;
  2302. begin
  2303. Result := ReadUCS4(Ch);
  2304. if Result then
  2305. Buffer := UCS4ToAnsiChar(Ch);
  2306. end;
  2307. function TJclStringStream.ReadAnsiString(var Buffer: AnsiString; Start, Count: Longint): Longint;
  2308. var
  2309. Index: Integer;
  2310. StrPos: SizeInt;
  2311. Ch: UCS4;
  2312. begin
  2313. Index := Start;
  2314. while Index < Start + Count do
  2315. begin
  2316. if ReadUCS4(Ch) then
  2317. begin
  2318. StrPos := Index;
  2319. if AnsiSetNextChar(Buffer, StrPos, Ch) and (StrPos > 0) then
  2320. Index := StrPos
  2321. else
  2322. Break; // end of string (write)
  2323. end
  2324. else
  2325. Break; // end of stream (read)
  2326. end;
  2327. Result := Index - Start;
  2328. end;
  2329. function TJclStringStream.ReadAnsiString(BufferSize: Longint): AnsiString;
  2330. var
  2331. Buffer: AnsiString;
  2332. ProcessedLength: Longint;
  2333. begin
  2334. Result := '';
  2335. SetLength(Buffer, BufferSize);
  2336. repeat
  2337. ProcessedLength := ReadAnsiString(Buffer, 1, BufferSize);
  2338. if ProcessedLength > 0 then
  2339. Result := Result + Copy(Buffer, 1, ProcessedLength);
  2340. until ProcessedLength = 0;
  2341. end;
  2342. function TJclStringStream.ReadChar(out Buffer: Char): Boolean;
  2343. var
  2344. Ch: UCS4;
  2345. begin
  2346. Result := ReadUCS4(Ch);
  2347. if Result then
  2348. Buffer := UCS4ToChar(Ch);
  2349. end;
  2350. function TJclStringStream.ReadUCS4(out Buffer: UCS4): Boolean;
  2351. begin
  2352. if (FStrPosition >= FStrBufferPosition) and (FStrPosition < (FStrBufferPosition + FStrBufferCurrentSize)) then
  2353. begin
  2354. // load from buffer
  2355. Result := True;
  2356. Buffer := FStrBuffer[FStrPosition - FStrBufferPosition];
  2357. Inc(FStrPosition);
  2358. end
  2359. else
  2360. begin
  2361. // load a new buffer
  2362. Result := LoadBuffer;
  2363. if Result then
  2364. begin
  2365. Buffer := FStrBuffer[FStrPosition - FStrBufferPosition];
  2366. Inc(FStrPosition);
  2367. end;
  2368. end;
  2369. FStrPeekPosition := FStrPosition;
  2370. end;
  2371. function TJclStringStream.ReadWideChar(out Buffer: WideChar): Boolean;
  2372. var
  2373. Ch: UCS4;
  2374. begin
  2375. Result := ReadUCS4(Ch);
  2376. if Result then
  2377. Buffer := UCS4ToWideChar(Ch);
  2378. end;
  2379. function TJclStringStream.ReadWideString(var Buffer: WideString; Start, Count: Longint): Longint;
  2380. var
  2381. Index: Integer;
  2382. StrPos: SizeInt;
  2383. Ch: UCS4;
  2384. begin
  2385. Index := Start;
  2386. while Index < Start + Count - 1 do // avoid overflow on surrogate pairs
  2387. begin
  2388. if ReadUCS4(Ch) then
  2389. begin
  2390. StrPos := Index;
  2391. if UTF16SetNextChar(Buffer, StrPos, Ch) and (StrPos > 0) then
  2392. Index := StrPos
  2393. else
  2394. Break; // end of string (write)
  2395. end
  2396. else
  2397. Break; // end of stream (read)
  2398. end;
  2399. Result := Index - Start;
  2400. end;
  2401. function TJclStringStream.ReadWideString(BufferSize: Longint): WideString;
  2402. var
  2403. Buffer: WideString;
  2404. ProcessedLength: Longint;
  2405. begin
  2406. Result := '';
  2407. SetLength(Buffer, BufferSize);
  2408. repeat
  2409. ProcessedLength := ReadWideString(Buffer, 1, BufferSize);
  2410. if ProcessedLength > 0 then
  2411. Result := Result + Copy(Buffer, 1, ProcessedLength);
  2412. until ProcessedLength = 0;
  2413. end;
  2414. function TJclStringStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  2415. begin
  2416. case Origin of
  2417. soBeginning:
  2418. if Offset = 0 then
  2419. begin
  2420. Flush;
  2421. FStrPosition := 0;
  2422. FStrBufferPosition := 0;
  2423. FStrBufferCurrentSize := 0;
  2424. FStrBufferStart := 0;
  2425. FStrBufferNext := 0;
  2426. FStrPeekBufferPosition := 0;
  2427. FStrPeekBufferCurrentSize := 0;
  2428. FStrPeekBufferStart := 0;
  2429. FStrPeekBufferNext := 0;
  2430. end
  2431. else
  2432. raise EJclStreamError.CreateRes(@RsStreamsSeekError);
  2433. soCurrent:
  2434. if Offset <> 0 then
  2435. raise EJclStreamError.CreateRes(@RsStreamsSeekError);
  2436. soEnd:
  2437. raise EJclStreamError.CreateRes(@RsStreamsSeekError);
  2438. end;
  2439. Result := FStrPosition;
  2440. FStrPeekPosition := FStrPosition;
  2441. end;
  2442. function TJclStringStream.SkipBOM: Longint;
  2443. var
  2444. Pos: Int64;
  2445. I: Integer;
  2446. BOM: array of Byte;
  2447. begin
  2448. if Length(FBOM) > 0 then
  2449. begin
  2450. Pos := FStream.Seek(0, soCurrent);
  2451. SetLength(BOM, Length(FBOM));
  2452. Result := FStream.Read(BOM[0], Length(BOM) * SizeOf(BOM[0]));
  2453. if Result = Length(FBOM) * SizeOf(FBOM[0]) then
  2454. for I := Low(FBOM) to High(FBOM) do
  2455. if BOM[I - Low(FBOM)] <> FBOM[I] then
  2456. Result := 0;
  2457. if Result <> Length(FBOM) * SizeOf(FBOM[0]) then
  2458. FStream.Seek(Pos, soBeginning);
  2459. end
  2460. else
  2461. Result := 0;
  2462. InvalidateBuffers;
  2463. end;
  2464. function TJclStringStream.WriteBOM: Longint;
  2465. begin
  2466. if Length(FBOM) > 0 then
  2467. Result := FStream.Write(FBOM[0], Length(FBOM) * SizeOf(FBOM[0]))
  2468. else
  2469. Result := 0;
  2470. InvalidateBuffers;
  2471. end;
  2472. function TJclStringStream.WriteChar(Value: Char): Boolean;
  2473. begin
  2474. Result := WriteUCS4(CharToUCS4(Value));
  2475. end;
  2476. function TJclStringStream.WriteString(const Buffer: string; Start, Count: Longint): Longint;
  2477. var
  2478. Index: Integer;
  2479. StrPos: SizeInt;
  2480. Ch: UCS4;
  2481. begin
  2482. Index := Start;
  2483. while Index < Start + Count do
  2484. begin
  2485. StrPos := Index;
  2486. Ch := StringGetNextChar(Buffer, StrPos);
  2487. if (StrPos > 0) and WriteUCS4(Ch) then
  2488. Index := StrPos
  2489. else
  2490. Break; // end of string (read) or end of stream (write)
  2491. end;
  2492. Result := Index - Start;
  2493. end;
  2494. function TJclStringStream.WriteAnsiChar(Value: AnsiChar): Boolean;
  2495. begin
  2496. Result := WriteUCS4(AnsiCharToUCS4(Value));
  2497. end;
  2498. function TJclStringStream.WriteAnsiString(const Buffer: AnsiString; Start, Count: Longint): Longint;
  2499. var
  2500. Index: Integer;
  2501. StrPos: SizeInt;
  2502. Ch: UCS4;
  2503. begin
  2504. Index := Start;
  2505. while Index < Start + Count do
  2506. begin
  2507. StrPos := Index;
  2508. Ch := AnsiGetNextChar(Buffer, StrPos);
  2509. if (StrPos > 0) and WriteUCS4(Ch) then
  2510. Index := StrPos
  2511. else
  2512. Break; // end of string (read) or end of stream (write)
  2513. end;
  2514. Result := Index - Start;
  2515. end;
  2516. function TJclStringStream.WriteUCS4(Value: UCS4): Boolean;
  2517. var
  2518. BufferPos: Int64;
  2519. begin
  2520. if FStrPosition >= (FStrBufferPosition + FBufferSize) then
  2521. // load the next buffer first
  2522. LoadBuffer;
  2523. // write to current buffer
  2524. BufferPos := FStrPosition - FStrBufferPosition;
  2525. Result := True;
  2526. if Length(FStrBuffer) <> FBufferSize then
  2527. SetLength(FStrBuffer, FBufferSize);
  2528. FStrBuffer[BufferPos] := Value;
  2529. Inc(FStrPosition);
  2530. Inc(BufferPos);
  2531. if FStrBufferModifiedSize < BufferPos then
  2532. FStrBufferModifiedSize := BufferPos;
  2533. if FStrBufferCurrentSize < BufferPos then
  2534. FStrBufferCurrentSize := BufferPos;
  2535. FStrPeekPosition := FStrPosition;
  2536. end;
  2537. function TJclStringStream.WriteWideChar(Value: WideChar): Boolean;
  2538. begin
  2539. Result := WriteUCS4(WideCharToUCS4(Value));
  2540. end;
  2541. function TJclStringStream.WriteWideString(const Buffer: WideString; Start, Count: Longint): Longint;
  2542. var
  2543. Index: Integer;
  2544. StrPos: SizeInt;
  2545. Ch: UCS4;
  2546. begin
  2547. Index := Start;
  2548. while Index < Start + Count do
  2549. begin
  2550. StrPos := Index;
  2551. Ch := UTF16GetNextChar(Buffer, StrPos);
  2552. if (StrPos > 0) and WriteUCS4(Ch) then
  2553. Index := StrPos
  2554. else
  2555. Break; // end of string (read) or end of stream (write)
  2556. end;
  2557. Result := Index - Start;
  2558. end;
  2559. //=== { TJclAnsiStream } ======================================================
  2560. constructor TJclAnsiStream.Create(AStream: TStream; AOwnsStream: Boolean);
  2561. begin
  2562. inherited Create(AStream, AOwnsStream);
  2563. SetLength(FBOM, 0);
  2564. FCodePage := CP_ACP;
  2565. end;
  2566. function TJclAnsiStream.InternalGetNextBuffer(S: TStream;
  2567. var Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2568. begin
  2569. if FCodePage = CP_ACP then
  2570. Result := AnsiGetNextBufferFromStream(S, Buffer, Start, Count)
  2571. else
  2572. Result := AnsiGetNextBufferFromStream(S, FCodePage, Buffer, Start, Count);
  2573. end;
  2574. function TJclAnsiStream.InternalGetNextChar(S: TStream; out Ch: UCS4): Boolean;
  2575. begin
  2576. if FCodePage = CP_ACP then
  2577. Result := AnsiGetNextCharFromStream(S, Ch)
  2578. else
  2579. Result := AnsiGetNextCharFromStream(S, FCodePage, Ch);
  2580. end;
  2581. function TJclAnsiStream.InternalSetNextBuffer(S: TStream;
  2582. const Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2583. begin
  2584. if FCodePage = CP_ACP then
  2585. Result := AnsiSetNextBufferToStream(S, Buffer, Start, Count)
  2586. else
  2587. Result := AnsiSetNextBufferToStream(S, FCodePage, Buffer, Start, Count);
  2588. end;
  2589. function TJclAnsiStream.InternalSetNextChar(S: TStream; Ch: UCS4): Boolean;
  2590. begin
  2591. if FCodePage = CP_ACP then
  2592. Result := AnsiSetNextCharToStream(S, Ch)
  2593. else
  2594. Result := AnsiSetNextCharToStream(S, FCodePage, Ch);
  2595. end;
  2596. //=== { TJclUTF8Stream } ======================================================
  2597. constructor TJclUTF8Stream.Create(AStream: TStream; AOwnsStream: Boolean);
  2598. var
  2599. I: Integer;
  2600. begin
  2601. inherited Create(AStream, AOwnsStream);
  2602. SetLength(FBOM, Length(BOM_UTF8));
  2603. for I := Low(BOM_UTF8) to High(BOM_UTF8) do
  2604. FBOM[I - Low(BOM_UTF8)] := BOM_UTF8[I];
  2605. end;
  2606. function TJclUTF8Stream.InternalGetNextBuffer(S: TStream;
  2607. var Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2608. begin
  2609. Result := UTF8GetNextBufferFromStream(S, Buffer, Start, Count);
  2610. end;
  2611. function TJclUTF8Stream.InternalGetNextChar(S: TStream; out Ch: UCS4): Boolean;
  2612. begin
  2613. Result := UTF8GetNextCharFromStream(S, Ch);
  2614. end;
  2615. function TJclUTF8Stream.InternalSetNextBuffer(S: TStream;
  2616. const Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2617. begin
  2618. Result := UTF8SetNextBufferToStream(S, Buffer, Start, Count);
  2619. end;
  2620. function TJclUTF8Stream.InternalSetNextChar(S: TStream; Ch: UCS4): Boolean;
  2621. begin
  2622. Result := UTF8SetNextCharToStream(S, Ch);
  2623. end;
  2624. //=== { TJclUTF16Stream } =====================================================
  2625. constructor TJclUTF16Stream.Create(AStream: TStream; AOwnsStream: Boolean);
  2626. var
  2627. I: Integer;
  2628. begin
  2629. inherited Create(AStream, AOwnsStream);
  2630. SetLength(FBOM, Length(BOM_UTF16_LSB));
  2631. for I := Low(BOM_UTF16_LSB) to High(BOM_UTF16_LSB) do
  2632. FBOM[I - Low(BOM_UTF16_LSB)] := BOM_UTF16_LSB[I];
  2633. end;
  2634. function TJclUTF16Stream.InternalGetNextBuffer(S: TStream;
  2635. var Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2636. begin
  2637. Result := UTF16GetNextBufferFromStream(S, Buffer, Start, Count);
  2638. end;
  2639. function TJclUTF16Stream.InternalGetNextChar(S: TStream; out Ch: UCS4): Boolean;
  2640. begin
  2641. Result := UTF16GetNextCharFromStream(S, Ch);
  2642. end;
  2643. function TJclUTF16Stream.InternalSetNextBuffer(S: TStream;
  2644. const Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2645. begin
  2646. Result := UTF16SetNextBufferToStream(S, Buffer, Start, Count);
  2647. end;
  2648. function TJclUTF16Stream.InternalSetNextChar(S: TStream; Ch: UCS4): Boolean;
  2649. begin
  2650. Result := UTF16SetNextCharToStream(S, Ch);
  2651. end;
  2652. //=== { TJclAutoStream } ======================================================
  2653. constructor TJclAutoStream.Create(AStream: TStream; AOwnsStream: Boolean);
  2654. var
  2655. I, MaxLength, ReadLength: Integer;
  2656. BOM: array of Byte;
  2657. begin
  2658. inherited Create(AStream, AOwnsStream);
  2659. MaxLength := Length(BOM_UTF8);
  2660. if MaxLength < Length(BOM_UTF16_LSB) then
  2661. MaxLength := Length(BOM_UTF16_LSB);
  2662. SetLength(BOM, MaxLength);
  2663. ReadLength := FStream.Read(BOM[0], Length(BOM) * SizeOf(BOM[0])) div SizeOf(BOM[0]);
  2664. FEncoding := seAuto;
  2665. // try UTF8 BOM
  2666. if (FEncoding = seAuto) and (ReadLength >= Length(BOM_UTF8) * SizeOf(BOM_UTF8[0])) then
  2667. begin
  2668. FCodePage := CP_UTF8;
  2669. FEncoding := seUTF8;
  2670. for I := Low(BOM_UTF8) to High(BOM_UTF8) do
  2671. if BOM[I - Low(BOM_UTF8)] <> BOM_UTF8[I] then
  2672. begin
  2673. FEncoding := seAuto;
  2674. Break;
  2675. end;
  2676. end;
  2677. // try UTF16 BOM
  2678. if (FEncoding = seAuto) and (ReadLength >= Length(BOM_UTF16_LSB) * SizeOf(BOM_UTF16_LSB[0])) then
  2679. begin
  2680. FCodePage := CP_UTF16LE;
  2681. FEncoding := seUTF16;
  2682. for I := Low(BOM_UTF16_LSB) to High(BOM_UTF16_LSB) do
  2683. if BOM[I - Low(BOM_UTF8)] <> BOM_UTF16_LSB[I] then
  2684. begin
  2685. FEncoding := seAuto;
  2686. Break;
  2687. end;
  2688. end;
  2689. case FEncoding of
  2690. seUTF8:
  2691. begin
  2692. FCodePage := CP_UTF8;
  2693. SetLength(FBOM, Length(BOM_UTF8));
  2694. for I := Low(BOM_UTF8) to High(BOM_UTF8) do
  2695. FBOM[I - Low(BOM_UTF8)] := BOM_UTF8[I];
  2696. end;
  2697. seUTF16:
  2698. begin
  2699. FCodePage := CP_UTF16LE;
  2700. SetLength(FBOM, Length(BOM_UTF16_LSB));
  2701. for I := Low(BOM_UTF16_LSB) to High(BOM_UTF16_LSB) do
  2702. FBOM[I - Low(BOM_UTF16_LSB)] := BOM_UTF16_LSB[I];
  2703. end;
  2704. seAuto,
  2705. seAnsi:
  2706. begin
  2707. // defaults to Ansi
  2708. FCodePage := CP_ACP;
  2709. FEncoding := seAnsi;
  2710. SetLength(FBOM, 0);
  2711. end;
  2712. end;
  2713. FStream.Seek(Length(FBOM) - ReadLength, soCurrent);
  2714. InvalidateBuffers;
  2715. end;
  2716. function TJclAutoStream.InternalGetNextBuffer(S: TStream;
  2717. var Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2718. begin
  2719. case FCodePage of
  2720. CP_UTF8:
  2721. Result := UTF8GetNextBufferFromStream(S, Buffer, Start, Count);
  2722. CP_UTF16LE:
  2723. Result := UTF16GetNextBufferFromStream(S, Buffer, Start, Count);
  2724. CP_ACP:
  2725. Result := AnsiGetNextBufferFromStream(S, Buffer, Start, Count);
  2726. else
  2727. Result := AnsiGetNextBufferFromStream(S, CodePage, Buffer, Start, Count);
  2728. end;
  2729. end;
  2730. function TJclAutoStream.InternalGetNextChar(S: TStream; out Ch: UCS4): Boolean;
  2731. begin
  2732. case FCodePage of
  2733. CP_UTF8:
  2734. Result := UTF8GetNextCharFromStream(S, Ch);
  2735. CP_UTF16LE:
  2736. Result := UTF16GetNextCharFromStream(S, Ch);
  2737. CP_ACP:
  2738. Result := AnsiGetNextCharFromStream(S, Ch);
  2739. else
  2740. Result := AnsiGetNextCharFromStream(S, CodePage, Ch);
  2741. end;
  2742. end;
  2743. function TJclAutoStream.InternalSetNextBuffer(S: TStream;
  2744. const Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2745. begin
  2746. case FCodePage of
  2747. CP_UTF8:
  2748. Result := UTF8SetNextBufferToStream(S, Buffer, Start, Count);
  2749. CP_UTF16LE:
  2750. Result := UTF16SetNextBufferToStream(S, Buffer, Start, Count);
  2751. CP_ACP:
  2752. Result := AnsiSetNextBufferToStream(S, Buffer, Start, Count);
  2753. else
  2754. Result := AnsiSetNextBufferToStream(S, CodePage, Buffer, Start, Count);
  2755. end;
  2756. end;
  2757. function TJclAutoStream.InternalSetNextChar(S: TStream; Ch: UCS4): Boolean;
  2758. begin
  2759. case FCodePage of
  2760. CP_UTF8:
  2761. Result := UTF8SetNextCharToStream(S, Ch);
  2762. CP_UTF16LE:
  2763. Result := UTF16SetNextCharToStream(S, Ch);
  2764. CP_ACP:
  2765. Result := AnsiSetNextCharToStream(S, Ch);
  2766. else
  2767. Result := AnsiSetNextCharToStream(S, CodePage, Ch);
  2768. end;
  2769. end;
  2770. procedure TJclAutoStream.SetCodePage(Value: Word);
  2771. begin
  2772. if Value = CP_UTF8 then
  2773. FEncoding := seUTF8
  2774. else
  2775. if Value = CP_UTF16LE then
  2776. FEncoding := seUTF16
  2777. else
  2778. if Value = CP_ACP then
  2779. FEncoding := seAnsi
  2780. else
  2781. FEncoding := seAuto;
  2782. FCodePage := Value;
  2783. end;
  2784. function TJclAutoStream.SkipBOM: LongInt;
  2785. begin
  2786. // already skipped to determine encoding
  2787. Result := 0;
  2788. InvalidateBuffers;
  2789. end;
  2790. {$IFDEF UNITVERSIONING}
  2791. initialization
  2792. RegisterUnitVersion(HInstance, UnitVersioning);
  2793. finalization
  2794. UnregisterUnitVersion(HInstance);
  2795. {$ENDIF UNITVERSIONING}
  2796. end.