JclStreams.pas 93 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129
  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. // Must call this method so that buffer initial values are properly set.
  2094. // This is most useful when AStream is not located at position zero
  2095. // before being used by us.
  2096. InvalidateBuffers;
  2097. end;
  2098. destructor TJclStringStream.Destroy;
  2099. begin
  2100. Flush;
  2101. if FOwnStream then
  2102. FStream.Free;
  2103. inherited;
  2104. end;
  2105. procedure TJclStringStream.Flush;
  2106. begin
  2107. if FStrBufferModifiedSize > 0 then
  2108. begin
  2109. FStream.Position := FStrBufferStart;
  2110. InternalSetNextBuffer(FStream, FStrBuffer, 0, FStrBufferModifiedSize);
  2111. FStrBufferNext := FStream.Seek(0, soCurrent);
  2112. FStrBufferModifiedSize := 0;
  2113. end;
  2114. end;
  2115. function TJclStringStream.InternalGetNextBuffer(S: TStream;
  2116. var Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2117. var
  2118. Ch: UCS4;
  2119. begin
  2120. // override to optimize
  2121. Result := 0;
  2122. while Count > 0 do
  2123. begin
  2124. if InternalGetNextChar(S, Ch) then
  2125. begin
  2126. Buffer[Start] := Ch;
  2127. Inc(Start);
  2128. Inc(Result);
  2129. end
  2130. else
  2131. Break;
  2132. Dec(Count);
  2133. end;
  2134. end;
  2135. function TJclStringStream.InternalSetNextBuffer(S: TStream;
  2136. const Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2137. begin
  2138. // override to optimize
  2139. Result := 0;
  2140. while Count > 0 do
  2141. begin
  2142. if InternalSetNextChar(S, Buffer[Start]) then
  2143. begin
  2144. Inc(Start);
  2145. Inc(Result);
  2146. end
  2147. else
  2148. Break;
  2149. Dec(Count);
  2150. end;
  2151. end;
  2152. procedure TJclStringStream.InvalidateBuffers;
  2153. begin
  2154. FStrBufferStart := FStream.Seek(0, soCurrent);
  2155. FStrBufferNext := FStrBufferStart;
  2156. FStrBufferPosition := 0;
  2157. FStrBufferCurrentSize := 0;
  2158. FStrBufferModifiedSize := 0;
  2159. FStrPeekBufferStart := FStrBufferStart;
  2160. FStrPeekBufferNext := FStrBufferNext;
  2161. FStrPeekPosition := 0;
  2162. FStrPeekBufferCurrentSize := 0;
  2163. end;
  2164. function TJclStringStream.LoadBuffer: Boolean;
  2165. begin
  2166. Flush;
  2167. // first test if the peek buffer contains the value
  2168. if (FStrBufferNext >= FStrPeekBufferStart) and (FStrBufferNext < FStrPeekBufferNext) then
  2169. begin
  2170. // the requested buffer is already loaded in the peek buffer
  2171. FStrBufferStart := FStrPeekBufferStart;
  2172. FStrBufferNext := FStrPeekBufferNext;
  2173. if Length(FStrBuffer) <> Length(FStrPeekBuffer) then
  2174. SetLength(FStrBuffer, Length(FStrPeekBuffer));
  2175. FStrBufferPosition := FStrPeekBufferPosition;
  2176. FStrBufferCurrentSize := FStrPeekBufferCurrentSize;
  2177. Move(FStrPeekBuffer[0], FStrBuffer[0], FStrBufferCurrentSize * SizeOf(FStrBuffer[0]));
  2178. end
  2179. else
  2180. begin
  2181. // load a new buffer
  2182. if Length(FStrBuffer) <> FBufferSize then
  2183. SetLength(FStrBuffer, FBufferSize);
  2184. Inc(FStrBufferPosition, FStrBufferCurrentSize);
  2185. FStrBufferStart := FStrBufferNext;
  2186. FStream.Seek(FStrBufferStart, soBeginning);
  2187. FStrBufferCurrentSize := InternalGetNextBuffer(FStream, FStrBuffer, 0, FBufferSize);
  2188. FStrBufferNext := FStream.Seek(0, soCurrent);
  2189. // reset the peek buffer
  2190. FStrPeekBufferPosition := FStrBufferPosition + FStrBufferCurrentSize;
  2191. FStrPeekBufferCurrentSize := 0;
  2192. FStrPeekBufferNext := FStrBufferNext;
  2193. FStrPeekBufferStart := FStrBufferNext;
  2194. end;
  2195. Result := (FStrPosition >= FStrBufferPosition) and (FStrPosition < (FStrBufferPosition + FStrBufferCurrentSize));
  2196. end;
  2197. function TJclStringStream.LoadPeekBuffer: Boolean;
  2198. begin
  2199. if Length(FStrPeekBuffer) <> FBufferSize then
  2200. SetLength(FStrPeekBuffer, FBufferSize);
  2201. if FStrPeekBufferPosition > FStrPeekPosition then
  2202. begin
  2203. // the peek position is rolling back, load the buffer after the read buffer
  2204. FStrPeekBufferPosition := FStrBufferPosition;
  2205. FStrPeekBufferCurrentSize := FStrBufferCurrentSize;
  2206. FStrPeekBufferStart := FStrBufferStart;
  2207. FStrPeekBufferNext := FStrBufferNext;
  2208. end;
  2209. FStrPeekBufferStart := FStrPeekBufferNext;
  2210. Inc(FStrPeekBufferPosition, FStrPeekBufferCurrentSize);
  2211. FStream.Seek(FStrPeekBufferStart, soBeginning);
  2212. FStrPeekBufferCurrentSize := InternalGetNextBuffer(FStream, FStrPeekBuffer, 0, FBufferSize);
  2213. FStrPeekBufferNext := FStream.Seek(0, soCurrent);
  2214. Result := (FStrPeekPosition >= FStrPeekBufferPosition) and (FStrPeekPosition < (FStrPeekBufferPosition + FStrPeekBufferCurrentSize));
  2215. end;
  2216. function TJclStringStream.PeekAnsiChar(out Buffer: AnsiChar): Boolean;
  2217. var
  2218. Ch: UCS4;
  2219. begin
  2220. Result := PeekUCS4(Ch);
  2221. if Result then
  2222. Buffer := UCS4ToAnsiChar(Ch);
  2223. end;
  2224. function TJclStringStream.PeekChar(out Buffer: Char): Boolean;
  2225. var
  2226. Ch: UCS4;
  2227. begin
  2228. Result := PeekUCS4(Ch);
  2229. if Result then
  2230. Buffer := UCS4ToChar(Ch);
  2231. end;
  2232. function TJclStringStream.PeekUCS4(out Buffer: UCS4): Boolean;
  2233. begin
  2234. if (FStrPeekPosition >= FStrPeekBufferPosition) and (FStrPeekPosition < (FStrPeekBufferPosition + FStrPeekBufferCurrentSize)) then
  2235. begin
  2236. // read from the peek buffer
  2237. Result := True;
  2238. Buffer := FStrPeekBuffer[FStrPeekPosition - FStrPeekBufferPosition];
  2239. Inc(FStrPeekPosition);
  2240. end
  2241. else
  2242. if (FStrPeekPosition >= FStrBufferPosition) and (FStrPeekPosition < (FStrBufferPosition + FStrBufferCurrentSize)) then
  2243. begin
  2244. // read from the read/write buffer
  2245. Result := True;
  2246. Buffer := FStrBuffer[FStrPeekPosition - FStrBufferPosition];
  2247. Inc(FStrPeekPosition);
  2248. end
  2249. else
  2250. begin
  2251. // load a new peek buffer
  2252. Result := LoadPeekBuffer;
  2253. if Result then
  2254. begin
  2255. Buffer := FStrPeekBuffer[FStrPeekPosition - FStrPeekBufferPosition];
  2256. Inc(FStrPeekPosition);
  2257. end;
  2258. end;
  2259. end;
  2260. function TJclStringStream.PeekWideChar(out Buffer: WideChar): Boolean;
  2261. var
  2262. Ch: UCS4;
  2263. begin
  2264. Result := PeekUCS4(Ch);
  2265. if Result then
  2266. Buffer := UCS4ToWideChar(Ch);
  2267. end;
  2268. function TJclStringStream.ReadString(var Buffer: string; Start, Count: Longint): Longint;
  2269. var
  2270. Index: Integer;
  2271. StrPos: SizeInt;
  2272. Ch: UCS4;
  2273. begin
  2274. Index := Start;
  2275. while Index < Start + Count - 1 do // avoid overflow on surrogate pairs for WideString
  2276. begin
  2277. if ReadUCS4(Ch) then
  2278. begin
  2279. StrPos := Index;
  2280. if StringSetNextChar(Buffer, StrPos, Ch) and (StrPos > 0) then
  2281. Index := StrPos
  2282. else
  2283. Break; // end of string (write)
  2284. end
  2285. else
  2286. Break; // end of stream (read)
  2287. end;
  2288. Result := Index - Start;
  2289. end;
  2290. function TJclStringStream.ReadString(BufferSize: Longint): string;
  2291. var
  2292. Buffer: string;
  2293. ProcessedLength: Longint;
  2294. begin
  2295. Result := '';
  2296. SetLength(Buffer, BufferSize);
  2297. repeat
  2298. ProcessedLength := ReadString(Buffer, 1, BufferSize);
  2299. if ProcessedLength > 0 then
  2300. Result := Result + Copy(Buffer, 1, ProcessedLength);
  2301. until ProcessedLength = 0;
  2302. end;
  2303. function TJclStringStream.ReadAnsiChar(out Buffer: AnsiChar): Boolean;
  2304. var
  2305. Ch: UCS4;
  2306. begin
  2307. Result := ReadUCS4(Ch);
  2308. if Result then
  2309. Buffer := UCS4ToAnsiChar(Ch);
  2310. end;
  2311. function TJclStringStream.ReadAnsiString(var Buffer: AnsiString; Start, Count: Longint): Longint;
  2312. var
  2313. Index: Integer;
  2314. StrPos: SizeInt;
  2315. Ch: UCS4;
  2316. begin
  2317. Index := Start;
  2318. while Index < Start + Count do
  2319. begin
  2320. if ReadUCS4(Ch) then
  2321. begin
  2322. StrPos := Index;
  2323. if AnsiSetNextChar(Buffer, StrPos, Ch) and (StrPos > 0) then
  2324. Index := StrPos
  2325. else
  2326. Break; // end of string (write)
  2327. end
  2328. else
  2329. Break; // end of stream (read)
  2330. end;
  2331. Result := Index - Start;
  2332. end;
  2333. function TJclStringStream.ReadAnsiString(BufferSize: Longint): AnsiString;
  2334. var
  2335. Buffer: AnsiString;
  2336. ProcessedLength: Longint;
  2337. begin
  2338. Result := '';
  2339. SetLength(Buffer, BufferSize);
  2340. repeat
  2341. ProcessedLength := ReadAnsiString(Buffer, 1, BufferSize);
  2342. if ProcessedLength > 0 then
  2343. Result := Result + Copy(Buffer, 1, ProcessedLength);
  2344. until ProcessedLength = 0;
  2345. end;
  2346. function TJclStringStream.ReadChar(out Buffer: Char): Boolean;
  2347. var
  2348. Ch: UCS4;
  2349. begin
  2350. Result := ReadUCS4(Ch);
  2351. if Result then
  2352. Buffer := UCS4ToChar(Ch);
  2353. end;
  2354. function TJclStringStream.ReadUCS4(out Buffer: UCS4): Boolean;
  2355. begin
  2356. if (FStrPosition >= FStrBufferPosition) and (FStrPosition < (FStrBufferPosition + FStrBufferCurrentSize)) then
  2357. begin
  2358. // load from buffer
  2359. Result := True;
  2360. Buffer := FStrBuffer[FStrPosition - FStrBufferPosition];
  2361. Inc(FStrPosition);
  2362. end
  2363. else
  2364. begin
  2365. // load a new buffer
  2366. Result := LoadBuffer;
  2367. if Result then
  2368. begin
  2369. Buffer := FStrBuffer[FStrPosition - FStrBufferPosition];
  2370. Inc(FStrPosition);
  2371. end;
  2372. end;
  2373. FStrPeekPosition := FStrPosition;
  2374. end;
  2375. function TJclStringStream.ReadWideChar(out Buffer: WideChar): Boolean;
  2376. var
  2377. Ch: UCS4;
  2378. begin
  2379. Result := ReadUCS4(Ch);
  2380. if Result then
  2381. Buffer := UCS4ToWideChar(Ch);
  2382. end;
  2383. function TJclStringStream.ReadWideString(var Buffer: WideString; Start, Count: Longint): Longint;
  2384. var
  2385. Index: Integer;
  2386. StrPos: SizeInt;
  2387. Ch: UCS4;
  2388. begin
  2389. Index := Start;
  2390. while Index < Start + Count - 1 do // avoid overflow on surrogate pairs
  2391. begin
  2392. if ReadUCS4(Ch) then
  2393. begin
  2394. StrPos := Index;
  2395. if UTF16SetNextChar(Buffer, StrPos, Ch) and (StrPos > 0) then
  2396. Index := StrPos
  2397. else
  2398. Break; // end of string (write)
  2399. end
  2400. else
  2401. Break; // end of stream (read)
  2402. end;
  2403. Result := Index - Start;
  2404. end;
  2405. function TJclStringStream.ReadWideString(BufferSize: Longint): WideString;
  2406. var
  2407. Buffer: WideString;
  2408. ProcessedLength: Longint;
  2409. begin
  2410. Result := '';
  2411. SetLength(Buffer, BufferSize);
  2412. repeat
  2413. ProcessedLength := ReadWideString(Buffer, 1, BufferSize);
  2414. if ProcessedLength > 0 then
  2415. Result := Result + Copy(Buffer, 1, ProcessedLength);
  2416. until ProcessedLength = 0;
  2417. end;
  2418. function TJclStringStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  2419. begin
  2420. case Origin of
  2421. soBeginning:
  2422. if Offset = 0 then
  2423. begin
  2424. Flush;
  2425. FStrPosition := 0;
  2426. FStrBufferPosition := 0;
  2427. FStrBufferCurrentSize := 0;
  2428. FStrBufferStart := 0;
  2429. FStrBufferNext := 0;
  2430. FStrPeekBufferPosition := 0;
  2431. FStrPeekBufferCurrentSize := 0;
  2432. FStrPeekBufferStart := 0;
  2433. FStrPeekBufferNext := 0;
  2434. end
  2435. else
  2436. raise EJclStreamError.CreateRes(@RsStreamsSeekError);
  2437. soCurrent:
  2438. if Offset <> 0 then
  2439. raise EJclStreamError.CreateRes(@RsStreamsSeekError);
  2440. soEnd:
  2441. raise EJclStreamError.CreateRes(@RsStreamsSeekError);
  2442. end;
  2443. Result := FStrPosition;
  2444. FStrPeekPosition := FStrPosition;
  2445. end;
  2446. function TJclStringStream.SkipBOM: Longint;
  2447. var
  2448. Pos: Int64;
  2449. I: Integer;
  2450. BOM: array of Byte;
  2451. begin
  2452. if Length(FBOM) > 0 then
  2453. begin
  2454. Pos := FStream.Seek(0, soCurrent);
  2455. SetLength(BOM, Length(FBOM));
  2456. Result := FStream.Read(BOM[0], Length(BOM) * SizeOf(BOM[0]));
  2457. if Result = Length(FBOM) * SizeOf(FBOM[0]) then
  2458. for I := Low(FBOM) to High(FBOM) do
  2459. if BOM[I - Low(FBOM)] <> FBOM[I] then
  2460. Result := 0;
  2461. if Result <> Length(FBOM) * SizeOf(FBOM[0]) then
  2462. FStream.Seek(Pos, soBeginning);
  2463. end
  2464. else
  2465. Result := 0;
  2466. InvalidateBuffers;
  2467. end;
  2468. function TJclStringStream.WriteBOM: Longint;
  2469. begin
  2470. if Length(FBOM) > 0 then
  2471. Result := FStream.Write(FBOM[0], Length(FBOM) * SizeOf(FBOM[0]))
  2472. else
  2473. Result := 0;
  2474. InvalidateBuffers;
  2475. end;
  2476. function TJclStringStream.WriteChar(Value: Char): Boolean;
  2477. begin
  2478. Result := WriteUCS4(CharToUCS4(Value));
  2479. end;
  2480. function TJclStringStream.WriteString(const Buffer: string; Start, Count: Longint): Longint;
  2481. var
  2482. Index: Integer;
  2483. StrPos: SizeInt;
  2484. Ch: UCS4;
  2485. begin
  2486. Index := Start;
  2487. while Index < Start + Count do
  2488. begin
  2489. StrPos := Index;
  2490. Ch := StringGetNextChar(Buffer, StrPos);
  2491. if (StrPos > 0) and WriteUCS4(Ch) then
  2492. Index := StrPos
  2493. else
  2494. Break; // end of string (read) or end of stream (write)
  2495. end;
  2496. Result := Index - Start;
  2497. end;
  2498. function TJclStringStream.WriteAnsiChar(Value: AnsiChar): Boolean;
  2499. begin
  2500. Result := WriteUCS4(AnsiCharToUCS4(Value));
  2501. end;
  2502. function TJclStringStream.WriteAnsiString(const Buffer: AnsiString; Start, Count: Longint): Longint;
  2503. var
  2504. Index: Integer;
  2505. StrPos: SizeInt;
  2506. Ch: UCS4;
  2507. begin
  2508. Index := Start;
  2509. while Index < Start + Count do
  2510. begin
  2511. StrPos := Index;
  2512. Ch := AnsiGetNextChar(Buffer, StrPos);
  2513. if (StrPos > 0) and WriteUCS4(Ch) then
  2514. Index := StrPos
  2515. else
  2516. Break; // end of string (read) or end of stream (write)
  2517. end;
  2518. Result := Index - Start;
  2519. end;
  2520. function TJclStringStream.WriteUCS4(Value: UCS4): Boolean;
  2521. var
  2522. BufferPos: Int64;
  2523. begin
  2524. if FStrPosition >= (FStrBufferPosition + FBufferSize) then
  2525. // load the next buffer first
  2526. LoadBuffer;
  2527. // write to current buffer
  2528. BufferPos := FStrPosition - FStrBufferPosition;
  2529. Result := True;
  2530. if Length(FStrBuffer) <> FBufferSize then
  2531. SetLength(FStrBuffer, FBufferSize);
  2532. FStrBuffer[BufferPos] := Value;
  2533. Inc(FStrPosition);
  2534. Inc(BufferPos);
  2535. if FStrBufferModifiedSize < BufferPos then
  2536. FStrBufferModifiedSize := BufferPos;
  2537. if FStrBufferCurrentSize < BufferPos then
  2538. FStrBufferCurrentSize := BufferPos;
  2539. FStrPeekPosition := FStrPosition;
  2540. end;
  2541. function TJclStringStream.WriteWideChar(Value: WideChar): Boolean;
  2542. begin
  2543. Result := WriteUCS4(WideCharToUCS4(Value));
  2544. end;
  2545. function TJclStringStream.WriteWideString(const Buffer: WideString; Start, Count: Longint): Longint;
  2546. var
  2547. Index: Integer;
  2548. StrPos: SizeInt;
  2549. Ch: UCS4;
  2550. begin
  2551. Index := Start;
  2552. while Index < Start + Count do
  2553. begin
  2554. StrPos := Index;
  2555. Ch := UTF16GetNextChar(Buffer, StrPos);
  2556. if (StrPos > 0) and WriteUCS4(Ch) then
  2557. Index := StrPos
  2558. else
  2559. Break; // end of string (read) or end of stream (write)
  2560. end;
  2561. Result := Index - Start;
  2562. end;
  2563. //=== { TJclAnsiStream } ======================================================
  2564. constructor TJclAnsiStream.Create(AStream: TStream; AOwnsStream: Boolean);
  2565. begin
  2566. inherited Create(AStream, AOwnsStream);
  2567. SetLength(FBOM, 0);
  2568. FCodePage := CP_ACP;
  2569. end;
  2570. function TJclAnsiStream.InternalGetNextBuffer(S: TStream;
  2571. var Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2572. begin
  2573. if FCodePage = CP_ACP then
  2574. Result := AnsiGetNextBufferFromStream(S, Buffer, Start, Count)
  2575. else
  2576. Result := AnsiGetNextBufferFromStream(S, FCodePage, Buffer, Start, Count);
  2577. end;
  2578. function TJclAnsiStream.InternalGetNextChar(S: TStream; out Ch: UCS4): Boolean;
  2579. begin
  2580. if FCodePage = CP_ACP then
  2581. Result := AnsiGetNextCharFromStream(S, Ch)
  2582. else
  2583. Result := AnsiGetNextCharFromStream(S, FCodePage, Ch);
  2584. end;
  2585. function TJclAnsiStream.InternalSetNextBuffer(S: TStream;
  2586. const Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2587. begin
  2588. if FCodePage = CP_ACP then
  2589. Result := AnsiSetNextBufferToStream(S, Buffer, Start, Count)
  2590. else
  2591. Result := AnsiSetNextBufferToStream(S, FCodePage, Buffer, Start, Count);
  2592. end;
  2593. function TJclAnsiStream.InternalSetNextChar(S: TStream; Ch: UCS4): Boolean;
  2594. begin
  2595. if FCodePage = CP_ACP then
  2596. Result := AnsiSetNextCharToStream(S, Ch)
  2597. else
  2598. Result := AnsiSetNextCharToStream(S, FCodePage, Ch);
  2599. end;
  2600. //=== { TJclUTF8Stream } ======================================================
  2601. constructor TJclUTF8Stream.Create(AStream: TStream; AOwnsStream: Boolean);
  2602. var
  2603. I: Integer;
  2604. begin
  2605. inherited Create(AStream, AOwnsStream);
  2606. SetLength(FBOM, Length(BOM_UTF8));
  2607. for I := Low(BOM_UTF8) to High(BOM_UTF8) do
  2608. FBOM[I - Low(BOM_UTF8)] := BOM_UTF8[I];
  2609. end;
  2610. function TJclUTF8Stream.InternalGetNextBuffer(S: TStream;
  2611. var Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2612. begin
  2613. Result := UTF8GetNextBufferFromStream(S, Buffer, Start, Count);
  2614. end;
  2615. function TJclUTF8Stream.InternalGetNextChar(S: TStream; out Ch: UCS4): Boolean;
  2616. begin
  2617. Result := UTF8GetNextCharFromStream(S, Ch);
  2618. end;
  2619. function TJclUTF8Stream.InternalSetNextBuffer(S: TStream;
  2620. const Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2621. begin
  2622. Result := UTF8SetNextBufferToStream(S, Buffer, Start, Count);
  2623. end;
  2624. function TJclUTF8Stream.InternalSetNextChar(S: TStream; Ch: UCS4): Boolean;
  2625. begin
  2626. Result := UTF8SetNextCharToStream(S, Ch);
  2627. end;
  2628. //=== { TJclUTF16Stream } =====================================================
  2629. constructor TJclUTF16Stream.Create(AStream: TStream; AOwnsStream: Boolean);
  2630. var
  2631. I: Integer;
  2632. begin
  2633. inherited Create(AStream, AOwnsStream);
  2634. SetLength(FBOM, Length(BOM_UTF16_LSB));
  2635. for I := Low(BOM_UTF16_LSB) to High(BOM_UTF16_LSB) do
  2636. FBOM[I - Low(BOM_UTF16_LSB)] := BOM_UTF16_LSB[I];
  2637. end;
  2638. function TJclUTF16Stream.InternalGetNextBuffer(S: TStream;
  2639. var Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2640. begin
  2641. Result := UTF16GetNextBufferFromStream(S, Buffer, Start, Count);
  2642. end;
  2643. function TJclUTF16Stream.InternalGetNextChar(S: TStream; out Ch: UCS4): Boolean;
  2644. begin
  2645. Result := UTF16GetNextCharFromStream(S, Ch);
  2646. end;
  2647. function TJclUTF16Stream.InternalSetNextBuffer(S: TStream;
  2648. const Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2649. begin
  2650. Result := UTF16SetNextBufferToStream(S, Buffer, Start, Count);
  2651. end;
  2652. function TJclUTF16Stream.InternalSetNextChar(S: TStream; Ch: UCS4): Boolean;
  2653. begin
  2654. Result := UTF16SetNextCharToStream(S, Ch);
  2655. end;
  2656. //=== { TJclAutoStream } ======================================================
  2657. constructor TJclAutoStream.Create(AStream: TStream; AOwnsStream: Boolean);
  2658. var
  2659. I, MaxLength, ReadLength: Integer;
  2660. BOM: array of Byte;
  2661. begin
  2662. inherited Create(AStream, AOwnsStream);
  2663. MaxLength := Length(BOM_UTF8);
  2664. if MaxLength < Length(BOM_UTF16_LSB) then
  2665. MaxLength := Length(BOM_UTF16_LSB);
  2666. SetLength(BOM, MaxLength);
  2667. ReadLength := FStream.Read(BOM[0], Length(BOM) * SizeOf(BOM[0])) div SizeOf(BOM[0]);
  2668. FEncoding := seAuto;
  2669. // try UTF8 BOM
  2670. if (FEncoding = seAuto) and (ReadLength >= Length(BOM_UTF8) * SizeOf(BOM_UTF8[0])) then
  2671. begin
  2672. FCodePage := CP_UTF8;
  2673. FEncoding := seUTF8;
  2674. for I := Low(BOM_UTF8) to High(BOM_UTF8) do
  2675. if BOM[I - Low(BOM_UTF8)] <> BOM_UTF8[I] then
  2676. begin
  2677. FEncoding := seAuto;
  2678. Break;
  2679. end;
  2680. end;
  2681. // try UTF16 BOM
  2682. if (FEncoding = seAuto) and (ReadLength >= Length(BOM_UTF16_LSB) * SizeOf(BOM_UTF16_LSB[0])) then
  2683. begin
  2684. FCodePage := CP_UTF16LE;
  2685. FEncoding := seUTF16;
  2686. for I := Low(BOM_UTF16_LSB) to High(BOM_UTF16_LSB) do
  2687. if BOM[I - Low(BOM_UTF8)] <> BOM_UTF16_LSB[I] then
  2688. begin
  2689. FEncoding := seAuto;
  2690. Break;
  2691. end;
  2692. end;
  2693. case FEncoding of
  2694. seUTF8:
  2695. begin
  2696. FCodePage := CP_UTF8;
  2697. SetLength(FBOM, Length(BOM_UTF8));
  2698. for I := Low(BOM_UTF8) to High(BOM_UTF8) do
  2699. FBOM[I - Low(BOM_UTF8)] := BOM_UTF8[I];
  2700. end;
  2701. seUTF16:
  2702. begin
  2703. FCodePage := CP_UTF16LE;
  2704. SetLength(FBOM, Length(BOM_UTF16_LSB));
  2705. for I := Low(BOM_UTF16_LSB) to High(BOM_UTF16_LSB) do
  2706. FBOM[I - Low(BOM_UTF16_LSB)] := BOM_UTF16_LSB[I];
  2707. end;
  2708. seAuto,
  2709. seAnsi:
  2710. begin
  2711. // defaults to Ansi
  2712. FCodePage := CP_ACP;
  2713. FEncoding := seAnsi;
  2714. SetLength(FBOM, 0);
  2715. end;
  2716. end;
  2717. FStream.Seek(Length(FBOM) - ReadLength, soCurrent);
  2718. InvalidateBuffers;
  2719. end;
  2720. function TJclAutoStream.InternalGetNextBuffer(S: TStream;
  2721. var Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2722. begin
  2723. case FCodePage of
  2724. CP_UTF8:
  2725. Result := UTF8GetNextBufferFromStream(S, Buffer, Start, Count);
  2726. CP_UTF16LE:
  2727. Result := UTF16GetNextBufferFromStream(S, Buffer, Start, Count);
  2728. CP_ACP:
  2729. Result := AnsiGetNextBufferFromStream(S, Buffer, Start, Count);
  2730. else
  2731. Result := AnsiGetNextBufferFromStream(S, CodePage, Buffer, Start, Count);
  2732. end;
  2733. end;
  2734. function TJclAutoStream.InternalGetNextChar(S: TStream; out Ch: UCS4): Boolean;
  2735. begin
  2736. case FCodePage of
  2737. CP_UTF8:
  2738. Result := UTF8GetNextCharFromStream(S, Ch);
  2739. CP_UTF16LE:
  2740. Result := UTF16GetNextCharFromStream(S, Ch);
  2741. CP_ACP:
  2742. Result := AnsiGetNextCharFromStream(S, Ch);
  2743. else
  2744. Result := AnsiGetNextCharFromStream(S, CodePage, Ch);
  2745. end;
  2746. end;
  2747. function TJclAutoStream.InternalSetNextBuffer(S: TStream;
  2748. const Buffer: TUCS4Array; Start, Count: SizeInt): Longint;
  2749. begin
  2750. case FCodePage of
  2751. CP_UTF8:
  2752. Result := UTF8SetNextBufferToStream(S, Buffer, Start, Count);
  2753. CP_UTF16LE:
  2754. Result := UTF16SetNextBufferToStream(S, Buffer, Start, Count);
  2755. CP_ACP:
  2756. Result := AnsiSetNextBufferToStream(S, Buffer, Start, Count);
  2757. else
  2758. Result := AnsiSetNextBufferToStream(S, CodePage, Buffer, Start, Count);
  2759. end;
  2760. end;
  2761. function TJclAutoStream.InternalSetNextChar(S: TStream; Ch: UCS4): Boolean;
  2762. begin
  2763. case FCodePage of
  2764. CP_UTF8:
  2765. Result := UTF8SetNextCharToStream(S, Ch);
  2766. CP_UTF16LE:
  2767. Result := UTF16SetNextCharToStream(S, Ch);
  2768. CP_ACP:
  2769. Result := AnsiSetNextCharToStream(S, Ch);
  2770. else
  2771. Result := AnsiSetNextCharToStream(S, CodePage, Ch);
  2772. end;
  2773. end;
  2774. procedure TJclAutoStream.SetCodePage(Value: Word);
  2775. begin
  2776. if Value = CP_UTF8 then
  2777. FEncoding := seUTF8
  2778. else
  2779. if Value = CP_UTF16LE then
  2780. FEncoding := seUTF16
  2781. else
  2782. if Value = CP_ACP then
  2783. FEncoding := seAnsi
  2784. else
  2785. FEncoding := seAuto;
  2786. FCodePage := Value;
  2787. end;
  2788. function TJclAutoStream.SkipBOM: LongInt;
  2789. begin
  2790. // already skipped to determine encoding
  2791. Result := 0;
  2792. InvalidateBuffers;
  2793. end;
  2794. {$IFDEF UNITVERSIONING}
  2795. initialization
  2796. RegisterUnitVersion(HInstance, UnitVersioning);
  2797. finalization
  2798. UnregisterUnitVersion(HInstance);
  2799. {$ENDIF UNITVERSIONING}
  2800. end.