| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562 | {**************************************************************************************************}{                                                                                                  }{ Project JEDI Code Library (JCL)                                                                  }{                                                                                                  }{ The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }{ you may not use this file except in compliance with the License. You may obtain a copy of the    }{ License at http://www.mozilla.org/MPL/                                                           }{                                                                                                  }{ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF   }{ ANY KIND, either express or implied. See the License for the specific language governing rights  }{ and limitations under the License.                                                               }{                                                                                                  }{ The Original Code is JclSysUtils.pas.                                                            }{                                                                                                  }{ The Initial Developer of the Original Code is Marcel van Brakel.                                 }{ Portions created by Marcel van Brakel are Copyright (C) Marcel van Brakel. All rights reserved.  }{                                                                                                  }{ Contributors:                                                                                    }{   Alexander Radchenko,                                                                           }{   Andreas Hausladen (ahuser)                                                                     }{   Anthony Steele                                                                                 }{   Bernhard Berger                                                                                }{   Heri Bender                                                                                    }{   Jean-Fabien Connault (cycocrew)                                                                }{   Jens Fudickar                                                                                  }{   Jeroen Speldekamp                                                                              }{   Marcel van Brakel                                                                              }{   Peter Friese                                                                                   }{   Petr Vones (pvones)                                                                            }{   Python                                                                                         }{   Robert Marquardt (marquardt)                                                                   }{   Robert R. Marsh                                                                                }{   Robert Rossmair (rrossmair)                                                                    }{   Rudy Velthuis                                                                                  }{   Uwe Schuster (uschuster)                                                                       }{   Wayne Sherman                                                                                  }{                                                                                                  }{**************************************************************************************************}{                                                                                                  }{ Description: Various pointer and class related routines.                                         }{                                                                                                  }{**************************************************************************************************}{                                                                                                  }{ Last modified: $Date::                                                                         $ }{ Revision:      $Rev::                                                                          $ }{ Author:        $Author::                                                                       $ }{                                                                                                  }{**************************************************************************************************}unit JclSysUtils;{$I jcl.inc}interfaceuses  {$IFDEF UNITVERSIONING}  JclUnitVersioning,  {$ENDIF UNITVERSIONING}  {$IFDEF HAS_UNITSCOPE}  {$IFDEF MSWINDOWS}  Winapi.Windows,  {$ENDIF MSWINDOWS}  System.SysUtils, System.Classes, System.TypInfo, System.SyncObjs,  {$ELSE ~HAS_UNITSCOPE}  {$IFDEF MSWINDOWS}  Windows,  {$ENDIF MSWINDOWS}  SysUtils, Classes, TypInfo, SyncObjs,  {$ENDIF ~HAS_UNITSCOPE}  JclBase, JclSynch;// memory initialization// first parameter is "out" to make FPC happy with uninitialized valuesprocedure ResetMemory(out P; Size: Longint);// Pointer manipulationprocedure GetAndFillMem(var P: Pointer; const Size: Integer; const Value: Byte);procedure FreeMemAndNil(var P: Pointer);function PCharOrNil(const S: string): PChar;function PAnsiCharOrNil(const S: AnsiString): PAnsiChar;{$IFDEF SUPPORTS_WIDESTRING}function PWideCharOrNil(const W: WideString): PWideChar;{$ENDIF SUPPORTS_WIDESTRING}function SizeOfMem(const APointer: Pointer): Integer;function WriteProtectedMemory(BaseAddress, Buffer: Pointer; Size: Cardinal;  out WrittenBytes: Cardinal): Boolean;// Guardstype  ISafeGuard = interface    function ReleaseItem: Pointer;    function GetItem: Pointer;    procedure FreeItem;    property Item: Pointer read GetItem;  end;  IMultiSafeGuard = interface (IInterface)    function AddItem(Item: Pointer): Pointer;    procedure FreeItem(Index: Integer);    function GetCount: Integer;    function GetItem(Index: Integer): Pointer;    function ReleaseItem(Index: Integer): Pointer;    property Count: Integer read GetCount;    property Items[Index: Integer]: Pointer read GetItem;  end;  TJclSafeGuard = class(TInterfacedObject, ISafeGuard)  private    FItem: Pointer;  public    constructor Create(Mem: Pointer);    destructor Destroy; override;    { ISafeGuard }    function ReleaseItem: Pointer;    function GetItem: Pointer;    procedure FreeItem; virtual;    property Item: Pointer read GetItem;  end;  TJclObjSafeGuard = class(TJclSafeGuard, ISafeGuard)  public    constructor Create(Obj: TObject);    { ISafeGuard }    procedure FreeItem; override;  end;  TJclMultiSafeGuard = class(TInterfacedObject, IMultiSafeGuard)  private    FItems: TList;  public    constructor Create;    destructor Destroy; override;    { IMultiSafeGuard }    function AddItem(Item: Pointer): Pointer;    procedure FreeItem(Index: Integer); virtual;    function GetCount: Integer;    function GetItem(Index: Integer): Pointer;    function ReleaseItem(Index: Integer): Pointer;    property Count: Integer read GetCount;    property Items[Index: Integer]: Pointer read GetItem;  end;  TJclObjMultiSafeGuard = class(TJclMultiSafeGuard, IMultiSafeGuard)  public    { IMultiSafeGuard }    procedure FreeItem(Index: Integer); override;  end;function Guard(Mem: Pointer; out SafeGuard: ISafeGuard): Pointer; overload;function Guard(Obj: TObject; out SafeGuard: ISafeGuard): TObject; overload;function Guard(Mem: Pointer; var SafeGuard: IMultiSafeGuard): Pointer; overload;function Guard(Obj: TObject; var SafeGuard: IMultiSafeGuard): TObject; overload;function GuardGetMem(Size: Cardinal; out SafeGuard: ISafeGuard): Pointer;function GuardAllocMem(Size: Cardinal; out SafeGuard: ISafeGuard): Pointer;(*{$IFDEF SUPPORTS_GENERICS}type  ISafeGuard<T: class> = interface    function ReleaseItem: T;    function GetItem: T;    procedure FreeItem;    property Item: T read GetItem;  end;  TSafeGuard<T: class> = class(TObject, ISafeGuard<T>)  private    FItem: T;    function ReleaseItem: T;    function GetItem: T;    procedure FreeItem;  constructor Create(Instance: T);  destructor Destroy; override;  public    class function New(Instance: T): ISafeGuard<T>; static;  end;{$ENDIF SUPPORTS_GENERICS}*){ Shared memory between processes functions }// Functions for the shared memory ownertype  ESharedMemError = class(EJclError);{$IFDEF MSWINDOWS}{ SharedGetMem return ERROR_ALREADY_EXISTS if the shared memory is already  allocated, otherwise it returns 0.  Throws ESharedMemError if the Name is invalid. }function SharedGetMem(var P{: Pointer}; const Name: string; Size: Cardinal;  DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Integer;{ SharedAllocMem calls SharedGetMem and then fills the memory with zero if  it was not already allocated.  Throws ESharedMemError if the Name is invalid. }function SharedAllocMem(const Name: string; Size: Cardinal;  DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Pointer;{ SharedFreeMem releases the shared memory if it was the last reference. }function SharedFreeMem(var P{: Pointer}): Boolean;// Functions for the shared memory user{ SharedOpenMem returns True if the shared memory was already allocated by  SharedGetMem or SharedAllocMem. Otherwise it returns False.  Throws ESharedMemError if the Name is invalid. }function SharedOpenMem(var P{: Pointer}; const Name: string;  DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Boolean; overload;{ SharedOpenMem return nil if the shared memory was not already allocated  by SharedGetMem or SharedAllocMem.  Throws ESharedMemError if the Name is invalid. }function SharedOpenMem(const Name: string;  DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Pointer; overload;{ SharedCloseMem releases the shared memory if it was the last reference. }function SharedCloseMem(var P{: Pointer}): Boolean;{$ENDIF MSWINDOWS}// Binary searchfunction SearchSortedList(List: TList; SortFunc: TListSortCompare; Item: Pointer;  Nearest: Boolean = False): Integer;type  TUntypedSearchCompare = function(Param: Pointer; ItemIndex: Integer; const Value): Integer;function SearchSortedUntyped(Param: Pointer; ItemCount: Integer; SearchFunc: TUntypedSearchCompare;  const Value; Nearest: Boolean = False): Integer;// Dynamic array sort and search routinestype  TDynArraySortCompare = function (Item1, Item2: Pointer): Integer;procedure SortDynArray(const ArrayPtr: Pointer; ElementSize: Cardinal; SortFunc: TDynArraySortCompare);// Usage: SortDynArray(Array, SizeOf(Array[0]), SortFunction);function SearchDynArray(const ArrayPtr: Pointer; ElementSize: Cardinal; SortFunc: TDynArraySortCompare;  ValuePtr: Pointer; Nearest: Boolean = False): SizeInt;// Usage: SearchDynArray(Array, SizeOf(Array[0]), SortFunction, @SearchedValue);{ Various compare functions for basic types }function DynArrayCompareByte(Item1, Item2: Pointer): Integer;function DynArrayCompareShortInt(Item1, Item2: Pointer): Integer;function DynArrayCompareWord(Item1, Item2: Pointer): Integer;function DynArrayCompareSmallInt(Item1, Item2: Pointer): Integer;function DynArrayCompareInteger(Item1, Item2: Pointer): Integer;function DynArrayCompareCardinal(Item1, Item2: Pointer): Integer;function DynArrayCompareInt64(Item1, Item2: Pointer): Integer;function DynArrayCompareSingle(Item1, Item2: Pointer): Integer;function DynArrayCompareDouble(Item1, Item2: Pointer): Integer;function DynArrayCompareExtended(Item1, Item2: Pointer): Integer;function DynArrayCompareFloat(Item1, Item2: Pointer): Integer;function DynArrayCompareAnsiString(Item1, Item2: Pointer): Integer;function DynArrayCompareAnsiText(Item1, Item2: Pointer): Integer;function DynArrayCompareWideString(Item1, Item2: Pointer): Integer;function DynArrayCompareWideText(Item1, Item2: Pointer): Integer;function DynArrayCompareString(Item1, Item2: Pointer): Integer;function DynArrayCompareText(Item1, Item2: Pointer): Integer;// Object listsprocedure ClearObjectList(List: TList);procedure FreeObjectList(var List: TList);// Reference memory streamtype  TJclReferenceMemoryStream = class(TCustomMemoryStream)  public    constructor Create(const Ptr: Pointer; Size: Longint);    function Write(const Buffer; Count: Longint): Longint; override;  end;// AutoPtrtype  IAutoPtr = interface    { Returns the object as pointer, so it is easier to assign it to a variable }    function AsPointer: Pointer;    { Returns the AutoPtr handled object }    function AsObject: TObject;    { Releases the object from the AutoPtr. The AutoPtr looses the control over      the object. }    function ReleaseObject: TObject;  end;  TJclAutoPtr = class(TInterfacedObject, IAutoPtr)  private    FValue: TObject;  public    constructor Create(AValue: TObject);    destructor Destroy; override;    { IAutoPtr }    function AsPointer: Pointer;    function AsObject: TObject;    function ReleaseObject: TObject;  end;function CreateAutoPtr(Value: TObject): IAutoPtr;// Replacement for the C ternary conditional operator ? :function Iff(const Condition: Boolean; const TruePart, FalsePart: string): string; overload;function Iff(const Condition: Boolean; const TruePart, FalsePart: Char): Char; overload;function Iff(const Condition: Boolean; const TruePart, FalsePart: Byte): Byte; overload;function Iff(const Condition: Boolean; const TruePart, FalsePart: Integer): Integer; overload;function Iff(const Condition: Boolean; const TruePart, FalsePart: Cardinal): Cardinal; overload;function Iff(const Condition: Boolean; const TruePart, FalsePart: Float): Float; overload;function Iff(const Condition: Boolean; const TruePart, FalsePart: Boolean): Boolean; overload;function Iff(const Condition: Boolean; const TruePart, FalsePart: Pointer): Pointer; overload;function Iff(const Condition: Boolean; const TruePart, FalsePart: Int64): Int64; overload;{$IFDEF SUPPORTS_VARIANT}function Iff(const Condition: Boolean; const TruePart, FalsePart: Variant): Variant; overload;{$ENDIF SUPPORTS_VARIANT}// Classes information and manipulationtype  EJclVMTError = class(EJclError);// Virtual Methods{$IFNDEF FPC}function GetVirtualMethodCount(AClass: TClass): Integer;{$ENDIF ~FPC}function GetVirtualMethod(AClass: TClass; const Index: Integer): Pointer;procedure SetVirtualMethod(AClass: TClass; const Index: Integer; const Method: Pointer);// Dynamic Methodstype  TDynamicIndexList = array [0..MaxInt div 16] of Word;  PDynamicIndexList = ^TDynamicIndexList;  TDynamicAddressList = array [0..MaxInt div 16] of Pointer;  PDynamicAddressList = ^TDynamicAddressList;function GetDynamicMethodCount(AClass: TClass): Integer;function GetDynamicIndexList(AClass: TClass): PDynamicIndexList;function GetDynamicAddressList(AClass: TClass): PDynamicAddressList;function HasDynamicMethod(AClass: TClass; Index: Integer): Boolean;{$IFNDEF FPC}function GetDynamicMethod(AClass: TClass; Index: Integer): Pointer;{$ENDIF ~FPC}{ init table methods }function GetInitTable(AClass: TClass): PTypeInfo;{ field table methods }type  PFieldEntry = ^TFieldEntry;  TFieldEntry = packed record    OffSet: Integer;    IDX: Word;    Name: ShortString;  end;  PFieldClassTable = ^TFieldClassTable;  TFieldClassTable = packed record    Count: Smallint;    Classes: array [0..8191] of ^TPersistentClass;  end;  PFieldTable = ^TFieldTable;  TFieldTable = packed record    EntryCount: Word;    FieldClassTable: PFieldClassTable;    FirstEntry: TFieldEntry;   {Entries: array [1..65534] of TFieldEntry;}  end;function GetFieldTable(AClass: TClass): PFieldTable;{ method table }type  PMethodEntry = ^TMethodEntry;  TMethodEntry = packed record    EntrySize: Word;    Address: Pointer;    Name: ShortString;  end;  PMethodTable = ^TMethodTable;  TMethodTable = packed record    Count: Word;    FirstEntry: TMethodEntry;   {Entries: array [1..65534] of TMethodEntry;}  end;function GetMethodTable(AClass: TClass): PMethodTable;function GetMethodEntry(MethodTable: PMethodTable; Index: Integer): PMethodEntry;// Function to compare if two methods/event handlers are equalfunction MethodEquals(aMethod1, aMethod2: TMethod): boolean;function NotifyEventEquals(aMethod1, aMethod2: TNotifyEvent): boolean;// Class Parentprocedure SetClassParent(AClass: TClass; NewClassParent: TClass);function GetClassParent(AClass: TClass): TClass;{$IFNDEF FPC}function IsClass(Address: Pointer): Boolean;function IsObject(Address: Pointer): Boolean;{$ENDIF ~FPC}function InheritsFromByName(AClass: TClass; const AClassName: string): Boolean;// Interface informationfunction GetImplementorOfInterface(const I: IInterface): TObject;// interfaced persistenttype  TJclInterfacedPersistent = class(TInterfacedPersistent, IInterface)  protected    FOwnerInterface: IInterface;    FRefCount: Integer;  public    procedure AfterConstruction; override;    { IInterface }    // function QueryInterface(const IID: TGUID; out Obj): HRESULT; virtual; stdcall;    function _AddRef: Integer; stdcall;    function _Release: Integer; stdcall;  end;// Numeric formatting routinestype  TDigitCount = 0..255;  TDigitValue = -1..35;  // invalid, '0'..'9', 'A'..'Z'  TNumericSystemBase = 2..Succ(High(TDigitValue));{$IFNDEF WINSCP}  TJclNumericFormat = class(TObject)  private    FWantedPrecision: TDigitCount;    FPrecision: TDigitCount;    FNumberOfFractionalDigits: TDigitCount;    FExpDivision: Integer;    FDigitBlockSize: TDigitCount;    FWidth: TDigitCount;    FSignChars: array [Boolean] of Char;    FBase: TNumericSystemBase;    FFractionalPartSeparator: Char;    FDigitBlockSeparator: Char;    FShowPositiveSign: Boolean;    FPaddingChar: Char;    FMultiplier: string;    function GetDigitValue(Digit: Char): Integer;    function GetNegativeSign: Char;    function GetPositiveSign: Char;    procedure InvalidDigit(Digit: Char);    procedure SetPrecision(const Value: TDigitCount);    procedure SetBase(const Value: TNumericSystemBase);    procedure SetNegativeSign(const Value: Char);    procedure SetPositiveSign(const Value: Char);    procedure SetExpDivision(const Value: Integer);  protected    function IntToStr(const Value: Int64; out FirstDigitPos: Integer): string; overload;    function ShowSign(const Value: Float): Boolean; overload;    function ShowSign(const Value: Int64): Boolean; overload;    function SignChar(const Value: Float): Char; overload;    function SignChar(const Value: Int64): Char; overload;    property WantedPrecision: TDigitCount read FWantedPrecision;  public    constructor Create;    function Digit(DigitValue: TDigitValue): Char;    function DigitValue(Digit: Char): TDigitValue;    function IsDigit(Value: Char): Boolean;    function Sign(Value: Char): Integer;    procedure GetMantissaExp(const Value: Float; out Mantissa: string; out Exponent: Integer);    function FloatToHTML(const Value: Float): string;    function IntToStr(const Value: Int64): string; overload;    function FloatToStr(const Value: Float): string; overload;    function StrToInt(const Value: string): Int64;    property Base: TNumericSystemBase read FBase write SetBase;    property Precision: TDigitCount read FPrecision write SetPrecision;    property NumberOfFractionalDigits: TDigitCount read FNumberOfFractionalDigits write FNumberOfFractionalDigits;    property ExponentDivision: Integer read FExpDivision write SetExpDivision;    property DigitBlockSize: TDigitCount read FDigitBlockSize write FDigitBlockSize;    property DigitBlockSeparator: Char read FDigitBlockSeparator write FDigitBlockSeparator;    property FractionalPartSeparator: Char read FFractionalPartSeparator write FFractionalPartSeparator;    property Multiplier: string read FMultiplier write FMultiplier;    property PaddingChar: Char read FPaddingChar write FPaddingChar;    property ShowPositiveSign: Boolean read FShowPositiveSign write FShowPositiveSign;    property Width: TDigitCount read FWidth write FWidth;    property NegativeSign: Char read GetNegativeSign write SetNegativeSign;    property PositiveSign: Char read GetPositiveSign write SetPositiveSign;  end;function IntToStrZeroPad(Value, Count: Integer): string;// Child processestype  // e.g. TStrings.Append  TTextHandler = procedure(const Text: string) of object;  TJclProcessPriority = (ppIdle, ppNormal, ppHigh, ppRealTime, ppBelowNormal, ppAboveNormal);const  ABORT_EXIT_CODE = {$IFDEF MSWINDOWS} ERROR_CANCELLED {$ELSE} 1223 {$ENDIF};function Execute(const CommandLine: string; OutputLineCallback: TTextHandler; RawOutput: Boolean = False;  AbortPtr: PBoolean = nil; ProcessPriority: TJclProcessPriority = ppNormal;  AutoConvertOem: Boolean = False): Cardinal; overload;function Execute(const CommandLine: string; AbortEvent: TJclEvent;  OutputLineCallback: TTextHandler; RawOutput: Boolean = False; ProcessPriority: TJclProcessPriority = ppNormal;  AutoConvertOem: Boolean = False): Cardinal; overload;function Execute(const CommandLine: string; var Output: string; RawOutput: Boolean = False;  AbortPtr: PBoolean = nil; ProcessPriority: TJclProcessPriority = ppNormal;  AutoConvertOem: Boolean = False): Cardinal; overload;function Execute(const CommandLine: string; AbortEvent: TJclEvent;  var Output: string; RawOutput: Boolean = False; ProcessPriority: TJclProcessPriority = ppNormal;  AutoConvertOem: Boolean = False): Cardinal; overload;function Execute(const CommandLine: string; OutputLineCallback, ErrorLineCallback: TTextHandler;  RawOutput: Boolean = False; RawError: Boolean = False; AbortPtr: PBoolean = nil;  ProcessPriority: TJclProcessPriority = ppNormal; AutoConvertOem: Boolean = False): Cardinal; overload;function Execute(const CommandLine: string; AbortEvent: TJclEvent;  OutputLineCallback, ErrorLineCallback: TTextHandler; RawOutput: Boolean = False; RawError: Boolean = False;  ProcessPriority: TJclProcessPriority = ppNormal; AutoConvertOem: Boolean = False): Cardinal; overload;function Execute(const CommandLine: string; var Output, Error: string;  RawOutput: Boolean = False; RawError: Boolean = False; AbortPtr: PBoolean = nil;  ProcessPriority: TJclProcessPriority = ppNormal; AutoConvertOem: Boolean = False): Cardinal; overload;function Execute(const CommandLine: string; AbortEvent: TJclEvent;  var Output, Error: string; RawOutput: Boolean = False; RawError: Boolean = False;  ProcessPriority: TJclProcessPriority = ppNormal; AutoConvertOem: Boolean = False): Cardinal; overload;type  {$IFDEF MSWINDOWS}  TJclExecuteCmdProcessOptionBeforeResumeEvent = procedure(const ProcessInfo: TProcessInformation) of object;  TStartupVisibility = (svHide, svShow, svNotSet);  {$ENDIF MSWINDOWS}  TJclExecuteCmdProcessOptions = {record} class(TObject)  private    FCommandLine: string;    FAbortPtr: PBoolean;    FAbortEvent: TJclEvent;    FOutputLineCallback: TTextHandler;    FRawOutput: Boolean;    FMergeError: Boolean;    FErrorLineCallback: TTextHandler;    FRawError: Boolean;    FProcessPriority: TJclProcessPriority;    FAutoConvertOem: Boolean;    {$IFDEF MSWINDOWS}    FCreateProcessFlags: DWORD;    FStartupVisibility: TStartupVisibility;    FBeforeResume: TJclExecuteCmdProcessOptionBeforeResumeEvent;    {$ENDIF MSWINDOWS}    FExitCode: Cardinal;    FOutput: string;    FError: string;  public    // in:    property CommandLine: string read FCommandLine write FCommandLine;    property AbortPtr: PBoolean read FAbortPtr write FAbortPtr;    property AbortEvent: TJclEvent read FAbortEvent write FAbortEvent;    property OutputLineCallback: TTextHandler read FOutputLineCallback write FOutputLineCallback;    property RawOutput: Boolean read FRawOutput write FRawOutput default False;    property MergeError: Boolean read FMergeError write FMergeError default False;    property ErrorLineCallback: TTextHandler read FErrorLineCallback write FErrorLineCallback;    property RawError: Boolean read FRawError write FRawError default False;    property ProcessPriority: TJclProcessPriority read FProcessPriority write FProcessPriority default ppNormal;    // AutoConvertOem assumes the process outputs OEM encoded strings and converts them to the    // default string encoding.    property AutoConvertOem: Boolean read FAutoConvertOem write FAutoConvertOem default True;    {$IFDEF MSWINDOWS}    property CreateProcessFlags: DWORD read FCreateProcessFlags write FCreateProcessFlags;    property StartupVisibility: TStartupVisibility read FStartupVisibility write FStartupVisibility;    property BeforeResume: TJclExecuteCmdProcessOptionBeforeResumeEvent read FBeforeResume write FBeforeResume;    {$ENDIF MSWINDOWS}    // out:    property ExitCode: Cardinal read FExitCode;    property Output: string read FOutput;    property Error: string read FError;  public    constructor Create(const ACommandLine: string);  end;function ExecuteCmdProcess(Options: TJclExecuteCmdProcessOptions): Boolean;type{$HPPEMIT 'namespace Jclsysutils'}{$HPPEMIT '{'}{$HPPEMIT '  // For some reason, the generator puts this interface after its first'}{$HPPEMIT '  // usage, resulting in an unusable header file. We fix this by forward'}{$HPPEMIT '  // declaring the interface.'}{$HPPEMIT '  __interface IJclCommandLineTool;'}(*$HPPEMIT '}'*)  IJclCommandLineTool = interface    ['{A0034B09-A074-D811-847D-0030849E4592}']    function GetExeName: string;    function GetOptions: TStrings;    function GetOutput: string;    function GetOutputCallback: TTextHandler;    procedure AddPathOption(const Option, Path: string);    function Execute(const CommandLine: string): Boolean;    procedure SetOutputCallback(const CallbackMethod: TTextHandler);    property ExeName: string read GetExeName;    property Options: TStrings read GetOptions;    property OutputCallback: TTextHandler read GetOutputCallback write SetOutputCallback;    property Output: string read GetOutput;  end;  EJclCommandLineToolError = class(EJclError);  TJclCommandLineTool = class(TInterfacedObject, IJclCommandLineTool)  private    FExeName: string;    FOptions: TStringList;    FOutput: string;    FOutputCallback: TTextHandler;  public    constructor Create(const AExeName: string);    destructor Destroy; override;    { IJclCommandLineTool }    function GetExeName: string;    function GetOptions: TStrings;    function GetOutput: string;    function GetOutputCallback: TTextHandler;    procedure AddPathOption(const Option, Path: string);    function Execute(const CommandLine: string): Boolean;    procedure SetOutputCallback(const CallbackMethod: TTextHandler);    property ExeName: string read GetExeName;    property Options: TStrings read GetOptions;    property OutputCallback: TTextHandler read GetOutputCallback write SetOutputCallback;    property Output: string read GetOutput;  end;// Console Utilitiesfunction ReadKey: Char;{$ENDIF ~WINSCP}// Loading of modules (DLLs)type{$IFDEF MSWINDOWS}  TModuleHandle = HINST;{$ENDIF MSWINDOWS}{$IFDEF LINUX}  TModuleHandle = Pointer;{$ENDIF LINUX}const  INVALID_MODULEHANDLE_VALUE = TModuleHandle(0);function LoadModule(var Module: TModuleHandle; FileName: string): Boolean;function LoadModuleEx(var Module: TModuleHandle; FileName: string; Flags: Cardinal): Boolean;procedure UnloadModule(var Module: TModuleHandle);function GetModuleSymbol(Module: TModuleHandle; SymbolName: string): Pointer;function GetModuleSymbolEx(Module: TModuleHandle; SymbolName: string; var Accu: Boolean): Pointer;function ReadModuleData(Module: TModuleHandle; SymbolName: string; var Buffer; Size: Cardinal): Boolean;function WriteModuleData(Module: TModuleHandle; SymbolName: string; var Buffer; Size: Cardinal): Boolean;// Conversion Utilitiestype  EJclConversionError = class(EJclError);function StrToBoolean(const S: string): Boolean;function BooleanToStr(B: Boolean): string;function IntToBool(I: Integer): Boolean;function BoolToInt(B: Boolean): Integer;function TryStrToUInt(const Value: string; out Res: Cardinal): Boolean;function StrToUIntDef(const Value: string; const Default: Cardinal): Cardinal;function StrToUInt(const Value: string): Cardinal;{$IFNDEF WINSCP}const  {$IFDEF MSWINDOWS}  ListSeparator = ';';  {$ENDIF MSWINDOWS}  {$IFDEF LINUX}  ListSeparator = ':';  {$ENDIF LINUX}{$ENDIF}// functions to handle items in a separated list of items// add items at the endprocedure ListAddItems(var List: string; const Separator, Items: string);// add items at the end if they are not presentprocedure ListIncludeItems(var List: string; const Separator, Items: string);// delete multiple itemsprocedure ListRemoveItems(var List: string; const Separator, Items: string);// delete one itemprocedure ListDelItem(var List: string; const Separator: string;  const Index: Integer);// return the number of itemfunction ListItemCount(const List, Separator: string): Integer;// return the Nth itemfunction ListGetItem(const List, Separator: string;  const Index: Integer): string;// set the Nth itemprocedure ListSetItem(var List: string; const Separator: string;  const Index: Integer; const Value: string);// return the index of an itemfunction ListItemIndex(const List, Separator, Item: string): Integer;// RTL package informationfunction SystemTObjectInstance: TJclAddr;function IsCompiledWithPackages: Boolean;// GUIDfunction JclGUIDToString(const GUID: TGUID): string;function JclStringToGUID(const S: string): TGUID;function GUIDEquals(const GUID1, GUID2: TGUID): Boolean;// thread safe supporttype  TJclIntfCriticalSection = class(TInterfacedObject, IInterface)  private    FCriticalSection: TCriticalSection;  public    constructor Create;    destructor Destroy; override;    { IInterface }    // function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;    function _AddRef: Integer; stdcall;    function _Release: Integer; stdcall;  end;type  {$IFDEF BORLAND}  {$IFDEF COMPILER16_UP}  TFileHandle = THandle;  {$ELSE ~COMPILER16_UP}  TFileHandle = Integer;  {$ENDIF ~COMPILER16_UP}  {$ELSE ~BORLAND}  TFileHandle = THandle;  {$ENDIF ~BORLAND}{$IFNDEF WINSCP}  TJclSimpleLog = class (TObject)  private    FDateTimeFormatStr: String;    FLogFileHandle: TFileHandle;    FLogFileName: string;    FLoggingActive: Boolean;    FLogWasEmpty: Boolean;    function GetLogOpen: Boolean;  protected    function CreateDefaultFileName: string;  public    constructor Create(const ALogFileName: string = '');    destructor Destroy; override;    procedure ClearLog;    procedure CloseLog;    procedure OpenLog;    procedure Write(const Text: string; Indent: Integer = 0; KeepOpen: Boolean = true); overload;    procedure Write(Strings: TStrings; Indent: Integer = 0; KeepOpen: Boolean = true); overload;    //Writes a line to the log file. The current timestamp is written before the line.    procedure TimeWrite(const Text: string; Indent: Integer = 0; KeepOpen: Boolean = true); overload;    procedure TimeWrite(Strings: TStrings; Indent: Integer = 0; KeepOpen: Boolean = true); overload;    procedure WriteStamp(SeparatorLen: Integer = 0; KeepOpen: Boolean = true);    // DateTimeFormatStr property assumes the values described in "FormatDateTime Function" in Delphi Help    property DateTimeFormatStr: String read FDateTimeFormatStr write FDateTimeFormatStr;    property LogFileName: string read FLogFileName;    //1 Property to activate / deactivate the logging    property LoggingActive: Boolean read FLoggingActive write FLoggingActive default True;    property LogOpen: Boolean read GetLogOpen;  end;{$ENDIF ~WINSCP}type  TJclFormatSettings = class  private    function GetCurrencyDecimals: Byte; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetCurrencyFormat: Byte; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetCurrencyString: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetDateSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetDayNamesHighIndex: Integer; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetDayNamesLowIndex: Integer; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetDecimalSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetListSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetLongDateFormat: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetLongDayNames(AIndex: Integer): string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetLongMonthNames(AIndex: Integer): string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetLongTimeFormat: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetMonthNamesHighIndex: Integer; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetMonthNamesLowIndex: Integer; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetNegCurrFormat: Byte; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetShortDateFormat: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetShortDayNames(AIndex: Integer): string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetShortMonthNames(AIndex: Integer): string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetShortTimeFormat: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetThousandSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetTimeAMString: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetTimePMString: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetTimeSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    function GetTwoDigitYearCenturyWindow: Word; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    procedure SetCurrencyDecimals(AValue: Byte); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    procedure SetCurrencyFormat(const AValue: Byte); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    procedure SetCurrencyString(AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    procedure SetDateSeparator(const AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    procedure SetDecimalSeparator(AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    procedure SetListSeparator(const AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    procedure SetLongDateFormat(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    procedure SetLongTimeFormat(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    procedure SetNegCurrFormat(const AValue: Byte); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    procedure SetShortDateFormat(AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    procedure SetShortTimeFormat(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    procedure SetThousandSeparator(AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    procedure SetTimeAMString(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    procedure SetTimePMString(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    procedure SetTimeSeparator(const AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}    procedure SetTwoDigitYearCenturyWindow(const AValue: Word); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}  public    property CurrencyDecimals: Byte read GetCurrencyDecimals write SetCurrencyDecimals;    property CurrencyFormat: Byte read GetCurrencyFormat write SetCurrencyFormat;    property CurrencyString: string read GetCurrencyString write SetCurrencyString;    property DateSeparator: Char read GetDateSeparator write SetDateSeparator;    property DayNamesHighIndex: Integer read GetDayNamesHighIndex;    property DayNamesLowIndex: Integer read GetDayNamesLowIndex;    property DecimalSeparator: Char read GetDecimalSeparator write SetDecimalSeparator;    property ListSeparator: Char read GetListSeparator write SetListSeparator;    property LongDateFormat: string read GetLongDateFormat write SetLongDateFormat;    property LongDayNames[AIndex: Integer]: string read GetLongDayNames;    property LongMonthNames[AIndex: Integer]: string read GetLongMonthNames;    property LongTimeFormat: string read GetLongTimeFormat write SetLongTimeFormat;    property MonthNamesHighIndex: Integer read GetMonthNamesHighIndex;    property MonthNamesLowIndex: Integer read GetMonthNamesLowIndex;    property NegCurrFormat: Byte read GetNegCurrFormat write SetNegCurrFormat;    property ShortDateFormat: string read GetShortDateFormat write SetShortDateFormat;    property ShortDayNames[AIndex: Integer]: string read GetShortDayNames;    property ShortMonthNames[AIndex: Integer]: string read GetShortMonthNames;    property ShortTimeFormat: string read GetShortTimeFormat write SetShortTimeFormat;    property ThousandSeparator: Char read GetThousandSeparator write SetThousandSeparator;    property TimeAMString: string read GetTimeAMString write SetTimeAMString;    property TimePMString: string read GetTimePMString write SetTimePMString;    property TimeSeparator: Char read GetTimeSeparator write SetTimeSeparator;    property TwoDigitYearCenturyWindow: Word read GetTwoDigitYearCenturyWindow write SetTwoDigitYearCenturyWindow;  end;var  JclFormatSettings: TJclFormatSettings;{$IFNDEF WINSCP}// Procedure to initialize the SimpleLog Variableprocedure InitSimpleLog(const ALogFileName: string = ''; AOpenLog: Boolean = true);// Global Variable to make it easier for an application wide log handling.// Must be initialized with InitSimpleLog before usingvar  SimpleLog : TJclSimpleLog;{$ENDIF ~WINSCP}// Validates if then variant value is null or is emptyfunction VarIsNullEmpty(const V: Variant): Boolean;// Validates if then variant value is null or is empty or VarToStr is a blank stringfunction VarIsNullEmptyBlank(const V: Variant): Boolean;{$IFDEF UNITVERSIONING}const  UnitVersioning: TUnitVersionInfo = (    RCSfile: '$URL$';    Revision: '$Revision$';    Date: '$Date$';    LogPath: 'JCL\source\common';    Extra: '';    Data: nil    );{$ENDIF UNITVERSIONING}implementationuses  {$IFDEF HAS_UNIT_LIBC}  Libc,  {$ENDIF HAS_UNIT_LIBC}  {$IFDEF MSWINDOWS}  {$IFNDEF WINSCP}  JclConsole,  {$ENDIF ~WINSCP}  {$ENDIF MSWINDOWS}  {$IFDEF HAS_UNITSCOPE}  System.Variants, System.Types, System.Contnrs,  {$IFDEF HAS_UNIT_ANSISTRINGS}  System.AnsiStrings,  {$ENDIF HAS_UNIT_ANSISTRINGS}  {$ELSE ~HAS_UNITSCOPE}  Variants, Types, Contnrs,  {$IFDEF HAS_UNIT_ANSISTRINGS}  AnsiStrings,  {$ENDIF HAS_UNIT_ANSISTRINGS}  {$ENDIF ~HAS_UNITSCOPE}  JclFileUtils, {$IFNDEF WINSCP}JclMath,{$ENDIF ~WINSCP} JclResources, JclStrings,  {$IFNDEF WINSCP}JclStringConversions,{$ENDIF ~WINSCP} JclSysInfo, JclWin32;// memory initializationprocedure ResetMemory(out P; Size: Longint);begin  if Size > 0 then  begin    Byte(P) := 0;    FillChar(P, Size, 0);  end;end;// Pointer manipulationprocedure GetAndFillMem(var P: Pointer; const Size: Integer; const Value: Byte);begin  GetMem(P, Size);  FillChar(P^, Size, Value);end;procedure FreeMemAndNil(var P: Pointer);var  Q: Pointer;begin  Q := P;  P := nil;  FreeMem(Q);end;function PCharOrNil(const S: string): PChar;begin  Result := Pointer(S);end;function PAnsiCharOrNil(const S: AnsiString): PAnsiChar;begin  Result := Pointer(S);end;{$IFDEF SUPPORTS_WIDESTRING}function PWideCharOrNil(const W: WideString): PWideChar;begin  Result := Pointer(W);end;{$ENDIF SUPPORTS_WIDESTRING}{$IFDEF MSWINDOWS}type  PUsed = ^TUsed;  TUsed = record    SizeFlags: Integer;  end;const  cThisUsedFlag = 2;  cPrevFreeFlag = 1;  cFillerFlag   = Integer($80000000);  cFlags        = cThisUsedFlag or cPrevFreeFlag or cFillerFlag;function SizeOfMem(const APointer: Pointer): Integer;var  U: PUsed;begin  if IsMemoryManagerSet then    Result:= -1  else  begin    Result := 0;    if APointer <> nil then    begin      U := APointer;      U := PUsed(TJclAddr(U) - SizeOf(TUsed));      if (U.SizeFlags and cThisUsedFlag) <> 0 then        Result := (U.SizeFlags) and (not cFlags - SizeOf(TUsed));    end;  end;end;{$ENDIF MSWINDOWS}{$IFDEF LINUX}function SizeOfMem(const APointer: Pointer): Integer;begin  if IsMemoryManagerSet then    Result:= -1  else  begin    if APointer <> nil then      Result := malloc_usable_size(APointer)    else      Result := 0;  end;end;{$ENDIF LINUX}function WriteProtectedMemory(BaseAddress, Buffer: Pointer;  Size: Cardinal; out WrittenBytes: Cardinal): Boolean;{$IFDEF MSWINDOWS}var  OldProtect, Dummy: Cardinal;begin  WrittenBytes := 0;  if Size > 0 then  begin    // (outchy) VirtualProtect for DEP issues    OldProtect := 0;    Result := VirtualProtect(BaseAddress, Size, PAGE_EXECUTE_READWRITE, OldProtect);    if Result then    try      Move(Buffer^, BaseAddress^, Size);      WrittenBytes := Size;      if OldProtect in [PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY] then        FlushInstructionCache(GetCurrentProcess, BaseAddress, Size);    finally      Dummy := 0;      VirtualProtect(BaseAddress, Size, OldProtect, Dummy);    end;  end;  Result := WrittenBytes = Size;end;{$ENDIF MSWINDOWS}{$IFDEF LINUX}{ TODO -cHelp : Author: Andreas Hausladen }{ TODO : Works so far, but causes app to hang on termination }var  AlignedAddress: Cardinal;  PageSize, ProtectSize: Cardinal;begin  Result := False;  WrittenBytes := 0;  PageSize := Cardinal(getpagesize);  AlignedAddress := Cardinal(BaseAddress) and not (PageSize - 1); // start memory page  // get the number of needed memory pages  ProtectSize := PageSize;  while Cardinal(BaseAddress) + Size > AlignedAddress + ProtectSize do    Inc(ProtectSize, PageSize);  if mprotect(Pointer(AlignedAddress), ProtectSize,    PROT_READ or PROT_WRITE or PROT_EXEC) = 0 then // obtain write access  begin    try      Move(Buffer^, BaseAddress^, Size); // replace code      Result := True;      WrittenBytes := Size;    finally      // Is there any function that returns the current page protection?//    mprotect(p, ProtectSize, PROT_READ or PROT_EXEC); // lock memory page    end;  end;end;procedure FlushInstructionCache;{ TODO -cHelp : Author: Andreas Hausladen }begin  // do nothingend;{$ENDIF LINUX}// Guards//=== { TJclSafeGuard } ======================================================constructor TJclSafeGuard.Create(Mem: Pointer);begin  inherited Create;  FItem := Mem;end;destructor TJclSafeGuard.Destroy;begin  FreeItem;  inherited Destroy;end;function TJclSafeGuard.ReleaseItem: Pointer;begin  Result := FItem;  FItem := nil;end;function TJclSafeGuard.GetItem: Pointer;begin  Result := FItem;end;procedure TJclSafeGuard.FreeItem;begin  if FItem <> nil then    FreeMem(FItem);  FItem := nil;end;//=== { TJclObjSafeGuard } ===================================================constructor TJclObjSafeGuard.Create(Obj: TObject);begin  inherited Create(Pointer(Obj));end;procedure TJclObjSafeGuard.FreeItem;begin  if FItem <> nil then  begin    TObject(FItem).Free;    FItem := nil;  end;end;//=== { TJclMultiSafeGuard } =================================================constructor TJclMultiSafeGuard.Create;begin  inherited Create;  FItems := TList.Create;end;destructor TJclMultiSafeGuard.Destroy;var  I: Integer;begin  for I := FItems.Count - 1 downto 0 do    FreeItem(I);  FItems.Free;  inherited Destroy;end;function TJclMultiSafeGuard.AddItem(Item: Pointer): Pointer;begin  Result := Item;  FItems.Add(Item);end;procedure TJclMultiSafeGuard.FreeItem(Index: Integer);begin  FreeMem(FItems[Index]);  FItems.Delete(Index);end;function TJclMultiSafeGuard.GetCount: Integer;begin  Result := FItems.Count;end;function TJclMultiSafeGuard.GetItem(Index: Integer): Pointer;begin  Result := FItems[Index];end;function TJclMultiSafeGuard.ReleaseItem(Index: Integer): Pointer;begin  Result := FItems[Index];  FItems.Delete(Index);end;function Guard(Mem: Pointer; var SafeGuard: IMultiSafeGuard): Pointer; overload;begin  if SafeGuard = nil then    SafeGuard := TJclMultiSafeGuard.Create;  Result := SafeGuard.AddItem(Mem);end;//=== { TJclObjMultiSafeGuard } ==============================================procedure TJclObjMultiSafeGuard.FreeItem(Index: Integer);begin  TObject(FItems[Index]).Free;  FItems.Delete(Index);end;function Guard(Obj: TObject; var SafeGuard: IMultiSafeGuard): TObject; overload;begin  if SafeGuard = nil then    SafeGuard := TJclObjMultiSafeGuard.Create;  Result := SafeGuard.AddItem(Obj);end;function Guard(Mem: Pointer; out SafeGuard: ISafeGuard): Pointer; overload;begin  Result := Mem;  SafeGuard := TJclSafeGuard.Create(Mem);end;function Guard(Obj: TObject; out SafeGuard: ISafeGuard): TObject; overload;begin  Result := Obj;  SafeGuard := TJclObjSafeGuard.Create(Obj);end;function GuardGetMem(Size: Cardinal; out SafeGuard: ISafeGuard): Pointer;begin  GetMem(Result, Size);  Guard(Result, SafeGuard);end;function GuardAllocMem(Size: Cardinal; out SafeGuard: ISafeGuard): Pointer;begin  Result := AllocMem(Size);  Guard(Result, SafeGuard);end;{$IFDEF SUPPORTS_GENERICS_}//=== { TSafeGuard<T> } ======================================================constructor TSafeGuard<T>.Create(Instance: T);begin  inherited Create;  FItem := Instance;end;destructor TSafeGuard<T>.Destroy;begin  FreeItem;  inherited Destroy;end;function TSafeGuard<T>.ReleaseItem: T;begin  Result := FItem;  FItem := nil;end;function TSafeGuard<T>.GetItem: T;begin  Result := FItem;end;procedure TSafeGuard<T>.FreeItem;begin  if FItem <> nil then    FItem.Free;  FItem := nil;end;{$ENDIF SUPPORTS_GENERICS_}//=== Shared memory functions ================================================type  PMMFHandleListItem = ^TMMFHandleListItem;  TMMFHandleListItem = record    Next: PMMFHandleListItem;    Memory: Pointer;    Handle: THandle;    Name: string;    References: Integer;  end;  PMMFHandleList = PMMFHandleListItem;var  MMFHandleList: PMMFHandleList = nil;  {$IFDEF THREADSAFE}  MMFFinalized: Boolean = False;  GlobalMMFHandleListCS: TJclIntfCriticalSection = nil;  {$ENDIF THREADSAFE}{$IFDEF THREADSAFE}function GetAccessToHandleList: IInterface;var  OldValue: Pointer;  CS: TJclIntfCriticalSection;begin  if not Assigned(GlobalMMFHandleListCS) and not MMFFinalized then  begin    CS := TJclIntfCriticalSection.Create;    {$IFDEF RTL200_UP} // Delphi 2009+    OldValue := InterlockedCompareExchangePointer(Pointer(GlobalMMFHandleListCS), Pointer(CS), nil);    {$ELSE}      {$IFDEF RTL160_UP} // Delphi 7-2007    OldValue := Pointer(InterlockedCompareExchange(Longint(GlobalMMFHandleListCS), Longint(CS), 0));      {$ELSE} // Delphi 5, 6    OldValue := InterlockedCompareExchange(Pointer(GlobalMMFHandleListCS), Pointer(CS), nil);      {$ENDIF RTL180_UP}    {$ENDIF RTL185_UP}    if OldValue <> nil then      CS.Free;  end;  Result := GlobalMMFHandleListCS;end;{$ENDIF THREADSAFE}{$IFDEF MSWINDOWS}function SharedGetMem(var P{: Pointer}; const Name: string; Size: Cardinal;  DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Integer;var  FileMappingHandle: THandle;  Iterate, NewListItem: PMMFHandleListItem;  Protect: Cardinal;  {$IFDEF THREADSAFE}  HandleListAccess: IInterface;  {$ENDIF THREADSAFE}begin  Result := 0;  Pointer(P) := nil;  if not JclCheckWinVersion(5, 0) and ((Name = '') or (Pos('\', Name) > 0)) then    raise ESharedMemError.CreateResFmt(@RsInvalidMMFName, [Name]);  {$IFDEF THREADSAFE}  HandleListAccess := GetAccessToHandleList;  {$ENDIF THREADSAFE}  // search for same name  Iterate := MMFHandleList;  while Iterate <> nil do  begin    if CompareText(Iterate^.Name, Name) = 0 then    begin      Inc(Iterate^.References);      Pointer(P) := Iterate^.Memory;      Result := ERROR_ALREADY_EXISTS;      Exit;    end;    Iterate := Iterate^.Next;  end;  // open file mapping  FileMappingHandle := OpenFileMapping(DesiredAccess, False, PChar(Name));  if FileMappingHandle = 0 then  begin    if Size = 0 then      raise ESharedMemError.CreateResFmt(@RsInvalidMMFEmpty, [Name]);    Protect := PAGE_READWRITE;    if (Win32Platform = VER_PLATFORM_WIN32_WINDOWS) and (DesiredAccess = FILE_MAP_COPY) then      Protect := PAGE_WRITECOPY;    FileMappingHandle := CreateFileMapping(INVALID_HANDLE_VALUE, nil, Protect,      0, Size, PChar(Name));  end  else    Result := ERROR_ALREADY_EXISTS;  if GetLastError = ERROR_ALREADY_EXISTS then    Result := ERROR_ALREADY_EXISTS  else  begin    if FileMappingHandle = 0 then      RaiseLastOSError;  end;  // map view  Pointer(P) := MapViewOfFile(FileMappingHandle, DesiredAccess, 0, 0, Size);  if Pointer(P) = nil then  begin    try      RaiseLastOSError;    except      CloseHandle(FileMappingHandle);      raise;    end;  end;  // add list item to MMFHandleList  New(NewListItem);  NewListItem^.Name := Name;  NewListItem^.Handle := FileMappingHandle;  NewListItem^.Memory := Pointer(P);  NewListItem^.References := 1;  NewListItem^.Next := MMFHandleList;  MMFHandleList := NewListItem;end;function SharedAllocMem(const Name: string; Size: Cardinal;  DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Pointer;begin  Result := nil;  if (SharedGetMem(Result, Name, Size, DesiredAccess) <> ERROR_ALREADY_EXISTS) and    ((DesiredAccess and (FILE_MAP_WRITE or FILE_MAP_COPY)) <> 0) and    (Size > 0) and (Result <> nil) then      ResetMemory(Pointer(Result)^, Size);end;function SharedFreeMem(var P{: Pointer}): Boolean;var  N, Iterate: PMMFHandleListItem;  {$IFDEF THREADSAFE}  HandleListAccess: IInterface;  {$ENDIF THREADSAFE}begin  if Pointer(P) <> nil then  begin    Result := False;    {$IFDEF THREADSAFE}    HandleListAccess := GetAccessToHandleList;    {$ENDIF THREADSAFE}    Iterate := MMFHandleList;    N := nil;    while Iterate <> nil do    begin      if Iterate^.Memory = Pointer(P) then      begin        if Iterate^.References > 1 then        begin          Dec(Iterate^.References);          Pointer(P) := nil;          Result := True;          Exit;        end;        UnmapViewOfFile(Iterate^.Memory);        CloseHandle(Iterate^.Handle);        if N = nil then          MMFHandleList := Iterate^.Next        else          N^.Next := Iterate^.Next;        Dispose(Iterate);        Pointer(P) := nil;        Result := True;        Break;      end;      N := Iterate;      Iterate := Iterate^.Next;    end;  end  else    Result := True;end;function SharedOpenMem(var P{: Pointer}; const Name: string;  DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Boolean;begin  Result := SharedGetMem(P, Name, 0, DesiredAccess) = ERROR_ALREADY_EXISTS;end;function SharedOpenMem(const Name: string;  DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Pointer;begin  Result := nil;  SharedGetMem(Result, Name, 0, DesiredAccess);end;function SharedCloseMem(var P{: Pointer}): Boolean;begin  Result := SharedFreeMem(P);end;{$ENDIF MSWINDOWS}//=== Binary search ==========================================================function SearchSortedList(List: TList; SortFunc: TListSortCompare; Item: Pointer; Nearest: Boolean): Integer;var  L, H, I, C: Integer;  B: Boolean;begin  Result := -1;  if List <> nil then  begin    L := 0;    H := List.Count - 1;    B := False;    while L <= H do    begin      I := (L + H) shr 1;      C := SortFunc(List.List{$IFNDEF RTL230_UP}^{$ENDIF !RTL230_UP}[I], Item);      if C < 0 then        L := I + 1      else      begin        H := I - 1;        if C = 0 then        begin          B := True;          L := I;        end;      end;    end;    if B then      Result := L    else    if Nearest and (H >= 0) then      Result := H;  end;end;function SearchSortedUntyped(Param: Pointer; ItemCount: Integer; SearchFunc: TUntypedSearchCompare;  const Value; Nearest: Boolean): Integer;var  L, H, I, C: Integer;  B: Boolean;begin  Result := -1;  if ItemCount > 0 then  begin    L := 0;    H := ItemCount - 1;    B := False;    while L <= H do    begin      I := (L + H) shr 1;      C := SearchFunc(Param, I, Value);      if C < 0 then        L := I + 1      else      begin        H := I - 1;        if C = 0 then        begin          B := True;          L := I;        end;      end;    end;    if B then      Result := L    else    if Nearest and (H >= 0) then      Result := H;  end;end;//=== Dynamic array sort and search routines =================================procedure SortDynArray(const ArrayPtr: Pointer; ElementSize: Cardinal; SortFunc: TDynArraySortCompare);var  TempBuf: TDynByteArray;  procedure QuickSort(L, R: SizeInt);  var    I, J, T: SizeInt;    P, IPtr, JPtr: Pointer;    ElSize: Integer;  begin    ElSize := ElementSize;    repeat      I := L;      J := R;      P := Pointer(TJclAddr(ArrayPtr) + TJclAddr(((L + R) shr 1) * SizeInt(ElementSize)));      repeat        IPtr := Pointer(TJclAddr(ArrayPtr) + TJclAddr(I * SizeInt(ElementSize)));        JPtr := Pointer(TJclAddr(ArrayPtr) + TJclAddr(J * SizeInt(ElementSize)));        while SortFunc(IPtr, P) < 0 do        begin          Inc(I);          Inc(PByte(IPtr), ElSize);        end;        while SortFunc(JPtr, P) > 0 do        begin          Dec(J);          Dec(PByte(JPtr), ElSize);        end;        if I <= J then        begin          if I <> J then          begin            case ElementSize of              SizeOf(Byte):                begin                  T := PByte(IPtr)^;                  PByte(IPtr)^ := PByte(JPtr)^;                  PByte(JPtr)^ := T;                end;              SizeOf(Word):                begin                  T := PWord(IPtr)^;                  PWord(IPtr)^ := PWord(JPtr)^;                  PWord(JPtr)^ := T;                end;              SizeOf(Integer):                begin                  T := PInteger(IPtr)^;                  PInteger(IPtr)^ := PInteger(JPtr)^;                  PInteger(JPtr)^ := T;                end;            else              Move(IPtr^, TempBuf[0], ElementSize);              Move(JPtr^, IPtr^, ElementSize);              Move(TempBuf[0], JPtr^, ElementSize);            end;          end;          if P = IPtr then            P := JPtr          else          if P = JPtr then            P := IPtr;          Inc(I);          Dec(J);        end;      until I > J;      if L < J then        QuickSort(L, J);      L := I;    until I >= R;  end;begin  if ArrayPtr <> nil then  begin    SetLength(TempBuf, ElementSize);    QuickSort(0, PSizeInt(TJclAddr(ArrayPtr) - SizeOf(SizeInt))^ - 1);  end;end;function SearchDynArray(const ArrayPtr: Pointer; ElementSize: Cardinal; SortFunc: TDynArraySortCompare;  ValuePtr: Pointer; Nearest: Boolean): SizeInt;var  L, H, I, C: SizeInt;  B: Boolean;begin  Result := -1;  if ArrayPtr <> nil then  begin    L := 0;    H := PSizeInt(TJclAddr(ArrayPtr) - SizeOf(SizeInt))^ - 1;    B := False;    while L <= H do    begin      I := (L + H) shr 1;      C := SortFunc(Pointer(TJclAddr(ArrayPtr) + TJclAddr(I * SizeInt(ElementSize))), ValuePtr);      if C < 0 then        L := I + 1      else      begin        H := I - 1;        if C = 0 then        begin          B := True;          L := I;        end;      end;    end;    if B then      Result := L    else    if Nearest and (H >= 0) then      Result := H;  end;end;{ Various compare functions for basic types }function DynArrayCompareByte(Item1, Item2: Pointer): Integer;begin  Result := PByte(Item1)^ - PByte(Item2)^;end;function DynArrayCompareShortInt(Item1, Item2: Pointer): Integer;begin  Result := PShortInt(Item1)^ - PShortInt(Item2)^;end;function DynArrayCompareWord(Item1, Item2: Pointer): Integer;begin  Result := PWord(Item1)^ - PWord(Item2)^;end;function DynArrayCompareSmallInt(Item1, Item2: Pointer): Integer;begin  Result := PSmallInt(Item1)^ - PSmallInt(Item2)^;end;function DynArrayCompareInteger(Item1, Item2: Pointer): Integer;begin  if PInteger(Item1)^ < PInteger(Item2)^ then    Result := -1  else  if PInteger(Item1)^ > PInteger(Item2)^ then    Result := 1  else    Result := 0;end;function DynArrayCompareCardinal(Item1, Item2: Pointer): Integer;begin  if PCardinal(Item1)^ < PCardinal(Item2)^ then    Result := -1  else  if PCardinal(Item1)^ > PCardinal(Item2)^ then    Result := 1  else    Result := 0;end;function DynArrayCompareInt64(Item1, Item2: Pointer): Integer;begin  if PInt64(Item1)^ < PInt64(Item2)^ then    Result := -1  else  if PInt64(Item1)^ > PInt64(Item2)^ then    Result := 1  else    Result := 0;end;function DynArrayCompareSingle(Item1, Item2: Pointer): Integer;begin  if PSingle(Item1)^ < PSingle(Item2)^ then    Result := -1  else  if PSingle(Item1)^ > PSingle(Item2)^ then    Result := 1  else    Result := 0;end;function DynArrayCompareDouble(Item1, Item2: Pointer): Integer;begin  if PDouble(Item1)^ < PDouble(Item2)^ then    Result := -1  else  if PDouble(Item1)^ > PDouble(Item2)^ then    Result := 1  else    Result := 0;end;function DynArrayCompareExtended(Item1, Item2: Pointer): Integer;begin  if PExtended(Item1)^ < PExtended(Item2)^ then    Result := -1  else  if PExtended(Item1)^ > PExtended(Item2)^ then    Result := 1  else    Result := 0;end;function DynArrayCompareFloat(Item1, Item2: Pointer): Integer;begin  if PFloat(Item1)^ < PFloat(Item2)^ then    Result := -1  else  if PFloat(Item1)^ > PFloat(Item2)^ then    Result := 1  else    Result := 0;end;function DynArrayCompareAnsiString(Item1, Item2: Pointer): Integer;begin  Result := AnsiCompareStr(PAnsiString(Item1)^, PAnsiString(Item2)^);end;function DynArrayCompareAnsiText(Item1, Item2: Pointer): Integer;begin  Result := AnsiCompareText(PAnsiString(Item1)^, PAnsiString(Item2)^);end;function DynArrayCompareWideString(Item1, Item2: Pointer): Integer;begin  Result := WideCompareStr(PWideString(Item1)^, PWideString(Item2)^);end;function DynArrayCompareWideText(Item1, Item2: Pointer): Integer;begin  Result := WideCompareText(PWideString(Item1)^, PWideString(Item2)^);end;function DynArrayCompareString(Item1, Item2: Pointer): Integer;begin  Result := CompareStr(PString(Item1)^, PString(Item2)^);end;function DynArrayCompareText(Item1, Item2: Pointer): Integer;begin  Result := CompareText(PString(Item1)^, PString(Item2)^);end;//=== Object lists ===========================================================procedure ClearObjectList(List: TList);var  I: Integer;begin  if List <> nil then  begin    for I := List.Count - 1 downto 0 do    begin      if List[I] <> nil then      begin        if TObject(List[I]) is TList then        begin          // recursively delete TList sublists          ClearObjectList(TList(List[I]));        end;        TObject(List[I]).Free;        if (not (List is TComponentList))          and ((not(List is TObjectList)) or not TObjectList(List).OwnsObjects) then          List[I] := nil;      end;    end;    List.Clear;  end;end;procedure FreeObjectList(var List: TList);begin  if List <> nil then  begin    ClearObjectList(List);    FreeAndNil(List);  end;end;//=== { TJclReferenceMemoryStream } ==========================================constructor TJclReferenceMemoryStream.Create(const Ptr: Pointer; Size: Longint);begin  {$IFDEF MSWINDOWS}  Assert(not IsBadReadPtr(Ptr, Size));  {$ENDIF MSWINDOWS}  inherited Create;  SetPointer(Ptr, Size);end;function TJclReferenceMemoryStream.Write(const Buffer; Count: Longint): Longint;begin  raise EJclError.CreateRes(@RsCannotWriteRefStream);end;//=== { TJclAutoPtr } ========================================================constructor TJclAutoPtr.Create(AValue: TObject);begin  inherited Create;  FValue := AValue;end;destructor TJclAutoPtr.Destroy;begin  FValue.Free;  inherited Destroy;end;function TJclAutoPtr.AsObject: TObject;begin  Result := FValue;end;function TJclAutoPtr.AsPointer: Pointer;begin  Result := FValue;end;function TJclAutoPtr.ReleaseObject: TObject;begin  Result := FValue;  FValue := nil;end;function CreateAutoPtr(Value: TObject): IAutoPtr;begin  Result := TJclAutoPtr.Create(Value);end;//=== replacement for the C distfix operator ? : =============================function Iff(const Condition: Boolean; const TruePart, FalsePart: string): string;begin  if Condition then    Result := TruePart  else    Result := FalsePart;end;function Iff(const Condition: Boolean; const TruePart, FalsePart: Char): Char;begin  if Condition then    Result := TruePart  else    Result := FalsePart;end;function Iff(const Condition: Boolean; const TruePart, FalsePart: Byte): Byte;begin  if Condition then    Result := TruePart  else    Result := FalsePart;end;function Iff(const Condition: Boolean; const TruePart, FalsePart: Integer): Integer;begin  if Condition then    Result := TruePart  else    Result := FalsePart;end;function Iff(const Condition: Boolean; const TruePart, FalsePart: Cardinal): Cardinal;begin  if Condition then    Result := TruePart  else    Result := FalsePart;end;function Iff(const Condition: Boolean; const TruePart, FalsePart: Float): Float;begin  if Condition then    Result := TruePart  else    Result := FalsePart;end;function Iff(const Condition: Boolean; const TruePart, FalsePart: Boolean): Boolean;begin  if Condition then    Result := TruePart  else    Result := FalsePart;end;function Iff(const Condition: Boolean; const TruePart, FalsePart: Pointer): Pointer;begin  if Condition then    Result := TruePart  else    Result := FalsePart;end;function Iff(const Condition: Boolean; const TruePart, FalsePart: Int64): Int64;begin  if Condition then    Result := TruePart  else    Result := FalsePart;end;{$IFDEF SUPPORTS_VARIANT}function Iff(const Condition: Boolean; const TruePart, FalsePart: Variant): Variant; overload;begin  if Condition then    Result := TruePart  else    Result := FalsePart;end;{$ENDIF SUPPORTS_VARIANT}//=== Classes information and manipulation ===================================// Virtual Methods// Helper methodprocedure SetVMTPointer(AClass: TClass; Offset: Integer; Value: Pointer);var  WrittenBytes: DWORD;  PatchAddress: PPointer;begin  {$OVERFLOWCHECKS OFF}  PatchAddress := Pointer(TJclAddr(AClass) + TJclAddr(Offset));  {$IFDEF OVERFLOWCHECKS_ON}  {$OVERFLOWCHECKS ON}  {$ENDIF OVERFLOWCHECKS_ON}  if not WriteProtectedMemory(PatchAddress, @Value, SizeOf(Value), WrittenBytes) then    raise EJclVMTError.CreateResFmt(@RsVMTMemoryWriteError,      [SysErrorMessage({$IFDEF FPC}GetLastOSError{$ELSE}GetLastError{$ENDIF})]);  if WrittenBytes <> SizeOf(Pointer) then    raise EJclVMTError.CreateResFmt(@RsVMTMemoryWriteError, [IntToStr(WrittenBytes)]);  // make sure that everything keeps working in a dual processor setting  // (outchy) done by WriteProtectedMemory  // FlushInstructionCache{$IFDEF MSWINDOWS}(GetCurrentProcess, PatchAddress, SizeOf(Pointer)){$ENDIF};end;{$IFNDEF FPC}function GetVirtualMethodCount(AClass: TClass): Integer;type  PINT_PTR = ^INT_PTR;var  BeginVMT: INT_PTR;  EndVMT: INT_PTR;  TablePointer: INT_PTR;  I: Integer;begin  BeginVMT := INT_PTR(AClass);  // Scan the offset entries in the class table for the various fields,  // namely vmtIntfTable, vmtAutoTable, ..., vmtDynamicTable  // The last entry is always the vmtClassName, so stop once we got there  // After the last virtual method there is one of these entries.  EndVMT := PINT_PTR(INT_PTR(AClass) + vmtClassName)^;  // Set iterator to first item behind VMT table pointer  I := vmtSelfPtr + SizeOf(Pointer);  repeat    TablePointer := PINT_PTR(INT_PTR(AClass) + I)^;    if (TablePointer <> 0) and (TablePointer >= BeginVMT) and       (TablePointer < EndVMT) then      EndVMT := INT_PTR(TablePointer);    Inc(I, SizeOf(Pointer));  until I >= vmtClassName;  Result := (EndVMT - BeginVMT) div SizeOf(Pointer);end;{$ENDIF ~FPC}function GetVirtualMethod(AClass: TClass; const Index: Integer): Pointer;begin  {$OVERFLOWCHECKS OFF}  Result := PPointer(TJclAddr(AClass) + TJclAddr(Index * SizeOf(Pointer)))^;  {$IFDEF OVERFLOWCHECKS_ON}  {$OVERFLOWCHECKS ON}  {$ENDIF OVERFLOWCHECKS_ON}end;procedure SetVirtualMethod(AClass: TClass; const Index: Integer; const Method: Pointer);begin  SetVMTPointer(AClass, Index * SizeOf(Pointer), Method);end;function GetDynamicMethodCount(AClass: TClass): Integer; assembler;asm        {$IFDEF CPU32}        // --> RAX AClass        // <-- EAX Result        MOV     EAX, [EAX].vmtDynamicTable        TEST    EAX, EAX        JE      @@Exit        MOVZX   EAX, WORD PTR [EAX]        {$ENDIF CPU32}        {$IFDEF CPU64}        // --> RCX AClass        // <-- EAX Result        MOV     RAX, [RCX].vmtDynamicTable        TEST    RAX, RAX        JE      @@Exit        MOVZX   RAX, WORD PTR [RAX]        {$ENDIF CPU64}@@Exit:end;function GetDynamicIndexList(AClass: TClass): PDynamicIndexList; assembler;asm        {$IFDEF CPU32}        // --> EAX AClass        // <-- EAX Result        MOV     EAX, [EAX].vmtDynamicTable        ADD     EAX, 2        {$ENDIF CPU32}        {$IFDEF CPU64}        // --> RCX AClass        // <-- RAX Result        MOV     RAX, [RCX].vmtDynamicTable        ADD     RAX, 2        {$ENDIF CPU64}end;function GetDynamicAddressList(AClass: TClass): PDynamicAddressList; assembler;asm        {$IFDEF CPU32}        // --> EAX AClass        // <-- EAX Result        MOV     EAX, [EAX].vmtDynamicTable        MOVZX   EDX, Word ptr [EAX]        ADD     EAX, EDX        ADD     EAX, EDX        ADD     EAX, 2        {$ENDIF CPU32}        {$IFDEF CPU64}        // --> RCX AClass        // <-- RAX Result        MOV     RAX, [RCX].vmtDynamicTable        MOVZX   RDX, Word ptr [RAX]        ADD     RAX, RDX        ADD     RAX, RDX        ADD     RAX, 2        {$ENDIF CPU64}end;function HasDynamicMethod(AClass: TClass; Index: Integer): Boolean; assembler;// Mainly copied from System.GetDynaMethodasm        {$IFDEF CPU32}        // --> EAX AClass        //     EDX Index        // <-- AL  Result        PUSH    EDI        XCHG    EAX, EDX        JMP     @@HaveVMT@@OuterLoop:        MOV     EDX, [EDX]@@HaveVMT:        MOV     EDI, [EDX].vmtDynamicTable        TEST    EDI, EDI        JE      @@Parent        MOVZX   ECX, WORD PTR [EDI]        PUSH    ECX        ADD     EDI,2        REPNE   SCASW        JE      @@Found        POP     ECX@@Parent:        MOV     EDX,[EDX].vmtParent        TEST    EDX,EDX        JNE     @@OuterLoop        MOV     EAX, 0        JMP     @@Exit@@Found:        POP     EAX        MOV     EAX, 1@@Exit:        POP     EDI        {$ENDIF CPU32}        {$IFDEF CPU64}        // --> RCX AClass        //     EDX Index        // <-- AL  Result        MOV     EAX, EDX        MOV     RDX, RCX        JMP     @@HaveVMT@@OuterLoop:        MOV     RDX, [RDX]@@HaveVMT:        MOV     RDI, [RDX].vmtDynamicTable        TEST    RDI, RDI        JE      @@Parent        MOVZX   RCX, WORD PTR [RDI]        PUSH    RCX        ADD     RDI,2        REPNE   SCASW        JE      @@Found        POP     RCX@@Parent:        MOV     RDX,[RDX].vmtParent        TEST    RDX,RDX        JNE     @@OuterLoop        MOV     RAX, 0        JMP     @@Exit@@Found:        POP     RAX        MOV     RAX, 1@@Exit:        {$ENDIF CPU64}end;{$IFNDEF FPC}function GetDynamicMethod(AClass: TClass; Index: Integer): Pointer; assembler;asm        CALL    System.@FindDynaClassend;{$ENDIF ~FPC}//=== Interface Table ========================================================function GetInitTable(AClass: TClass): PTypeInfo; assembler;asm        {$IFDEF CPU32}        // --> EAX AClass        // <-- EAX Result        MOV     EAX, [EAX].vmtInitTable        {$ENDIF CPU32}        {$IFDEF CPU64}        // --> RCX AClass        // <-- RAX Result        MOV     RAX, [RCX].vmtInitTable        {$ENDIF CPU64}end;function GetFieldTable(AClass: TClass): PFieldTable; assembler;asm        {$IFDEF CPU32}        // --> EAX AClass        // <-- EAX Result        MOV     EAX, [EAX].vmtFieldTable        {$ENDIF CPU32}        {$IFDEF CPU64}        // --> RCX AClass        // <-- RAX Result        MOV     RAX, [RCX].vmtFieldTable        {$ENDIF CPU64}end;function GetMethodTable(AClass: TClass): PMethodTable; assembler;asm        {$IFDEF CPU32}        // --> EAX AClass        // <-- EAX Result        MOV     EAX, [EAX].vmtMethodTable        {$ENDIF CPU32}        {$IFDEF CPU64}        // --> RCX AClass        // <-- RAX Result        MOV     RAX, [RCX].vmtMethodTable        {$ENDIF CPU64}end;function GetMethodEntry(MethodTable: PMethodTable; Index: Integer): PMethodEntry;begin  Result := Pointer(TJclAddr(MethodTable) + 2);  for Index := Index downto 1 do    Inc(TJclAddr(Result), Result^.EntrySize);end;function MethodEquals(aMethod1, aMethod2: TMethod): boolean;begin  Result := (aMethod1.Code = aMethod2.Code) and            (aMethod1.Data = aMethod2.Data);end;function NotifyEventEquals(aMethod1, aMethod2: TNotifyEvent): boolean;begin  Result := MethodEquals(TMethod(aMethod1),TMethod(aMethod2));end;//=== Class Parent methods ===================================================procedure SetClassParent(AClass: TClass; NewClassParent: TClass);var  WrittenBytes: DWORD;  PatchAddress: Pointer;begin  {$OVERFLOWCHECKS OFF}  PatchAddress := PPointer(TJclAddr(AClass) + TJclAddr(vmtParent))^;  {$IFDEF OVERFLOWCHECKS_ON}  {$OVERFLOWCHECKS ON}  {$ENDIF OVERFLOWCHECKS_ON}  if not WriteProtectedMemory(PatchAddress, @NewClassParent, SizeOf(Pointer), WrittenBytes) then    raise EJclVMTError.CreateResFmt(@RsVMTMemoryWriteError,      [SysErrorMessage({$IFDEF FPC}GetLastOSError{$ELSE}GetLastError{$ENDIF})]);  if WrittenBytes <> SizeOf(Pointer) then    raise EJclVMTError.CreateResFmt(@RsVMTMemoryWriteError, [IntToStr(WrittenBytes)]);  // make sure that everything keeps working in a dual processor setting  // (outchy) done by WriteProtectedMemory  // FlushInstructionCache{$IFDEF MSWINDOWS}(GetCurrentProcess, PatchAddress, SizeOf(Pointer)){$ENDIF};end;function GetClassParent(AClass: TClass): TClass; assembler;asm        {$IFDEF CPU32}        // --> EAX AClass        // <-- EAX Result        MOV     EAX, [EAX].vmtParent        TEST    EAX, EAX        JE      @@Exit        MOV     EAX, [EAX]        {$ENDIF CPU32}        {$IFDEF CPU64}        // --> RCX AClass        // <-- RAX Result        MOV     RAX, [RCX].vmtParent        TEST    RAX, RAX        JE      @@Exit        MOV     RAX, [RAX]        {$ENDIF CPU64}@@Exit:end;{$IFDEF BORLAND}function IsClass(Address: Pointer): Boolean; assembler;asm        CMP     Address, Address.vmtSelfPtr        JNZ     @False        MOV     Result, True        JMP     @Exit@False:        MOV     Result, False@Exit:end;{$ENDIF BORLAND}{$IFDEF BORLAND}function IsObject(Address: Pointer): Boolean; assembler;asm// or IsClass(Pointer(Address^));        MOV     EAX, [Address]        CMP     EAX, EAX.vmtSelfPtr        JNZ     @False        MOV     Result, True        JMP     @Exit@False:        MOV     Result, False@Exit:end;{$ENDIF BORLAND}function InheritsFromByName(AClass: TClass; const AClassName: string): Boolean;begin  while (AClass <> nil) and not AClass.ClassNameIs(AClassName) do    AClass := AClass.ClassParent;  Result := AClass <> nil;end;//=== Interface information ==================================================function GetImplementorOfInterface(const I: IInterface): TObject;{ TODO -cDOC : Original code by Hallvard Vassbotn }{ TODO -cTesting : Check the implemetation for any further version of compiler }const  AddByte = $04244483; // opcode for ADD DWORD PTR [ESP+4], Shortint  AddLong = $04244481; // opcode for ADD DWORD PTR [ESP+4], Longinttype  PAdjustSelfThunk = ^TAdjustSelfThunk;  TAdjustSelfThunk = packed record    case AddInstruction: Longint of      AddByte: (AdjustmentByte: ShortInt);      AddLong: (AdjustmentLong: Longint);  end;  PInterfaceMT = ^TInterfaceMT;  TInterfaceMT = packed record    QueryInterfaceThunk: PAdjustSelfThunk;  end;  TInterfaceRef = ^PInterfaceMT;var  QueryInterfaceThunk: PAdjustSelfThunk;begin  try    Result := Pointer(I);    if Assigned(Result) then    begin      QueryInterfaceThunk := TInterfaceRef(I)^.QueryInterfaceThunk;      case QueryInterfaceThunk.AddInstruction of        AddByte:          Inc(PByte(Result), QueryInterfaceThunk.AdjustmentByte);        AddLong:          Inc(PByte(Result), QueryInterfaceThunk.AdjustmentLong);      else        Result := nil;      end;    end;  except    Result := nil;  end;end;//=== { TJclInterfacedPersistent } ===========================================procedure TJclInterfacedPersistent.AfterConstruction;begin  inherited AfterConstruction;  if GetOwner <> nil then    GetOwner.GetInterface(IInterface, FOwnerInterface);end;function TJclInterfacedPersistent._AddRef: Integer;begin  if FOwnerInterface <> nil then    Result := FOwnerInterface._AddRef  else    Result := InterlockedIncrement(FRefCount);end;function TJclInterfacedPersistent._Release: Integer;begin  if FOwnerInterface <> nil then    Result := FOwnerInterface._Release  else  begin    Result := InterlockedDecrement(FRefCount);    if Result = 0 then      Destroy;  end;end;//=== Numeric formatting routines ============================================function IntToStrZeroPad(Value, Count: Integer): string;begin  Result := IntToStr(Value);  if Length(Result) < Count then    Result := StrRepeatChar('0', Count - Length(Result)) + Result;end;//=== { TJclNumericFormat } =================================================={ TODO -cHelp : Author: Robert Rossmair }{ Digit:         converts a digit value (number) to a digit (char)  DigitValue:    converts a digit (char) into a number (digit value)  IntToStr,  FloatToStr,  FloatToHTML:   converts a numeric value to a base <Base> numeric representation with formating options  StrToIn:       converts a base <Base> numeric representation into an integer, if possible  GetMantisseExponent: similar to AsString, but returns the Exponent separately as an integer}const  {$IFDEF MATH_EXTENDED_PRECISION}  BinaryPrecision = 64;  {$ENDIF MATH_EXTENDED_PRECISION}  {$IFDEF MATH_DOUBLE_PRECISION}  BinaryPrecision = 53;  {$ENDIF MATH_DOUBLE_PRECISION}  {$IFDEF MATH_SINGLE_PRECISION}  BinaryPrecision = 24;  {$ENDIF MATH_SINGLE_PRECISION}{$IFNDEF WINSCP}constructor TJclNumericFormat.Create;begin  inherited Create;  { TODO : Initialize, when possible, from locale info }  FBase := 10;  FExpDivision := 1;  SetPrecision(6);  FNumberOfFractionalDigits := BinaryPrecision;  FSignChars[False] := '-';  FSignChars[True] := '+';  FPaddingChar := ' ';  FMultiplier := '×';  FFractionalPartSeparator := JclFormatSettings.DecimalSeparator;  FDigitBlockSeparator := JclFormatSettings.ThousandSeparator;end;procedure TJclNumericFormat.InvalidDigit(Digit: Char);begin  raise EConvertError.CreateResFmt(@RsInvalidDigit, [Base, Digit]);end;function TJclNumericFormat.Digit(DigitValue: TDigitValue): Char;begin  Assert(DigitValue < Base, Format(LoadResString(@RsInvalidDigitValue), [Base, DigitValue]));  if DigitValue > 9 then    Result := Chr(Ord('A') + DigitValue - 10)  else    Result := Chr(Ord('0') + DigitValue);end;function TJclNumericFormat.GetDigitValue(Digit: Char): Integer;begin  Result := CharHex(Digit);  if (Result = $FF) or (Result >= Base) then    Result := -1;end;function TJclNumericFormat.DigitValue(Digit: Char): TDigitValue;begin  Result := GetDigitValue(Digit);  if Result = -1 then    InvalidDigit(Digit);end;function TJclNumericFormat.IsDigit(Value: Char): Boolean;begin  Result := GetDigitValue(Value) <> -1;end;function TJclNumericFormat.FloatToHTML(const Value: Float): string;var  Mantissa: string;  Exponent: Integer;begin  GetMantissaExp(Value, Mantissa, Exponent);  Result := Format('%s %s %d<sup>%d</sup>', [Mantissa, Multiplier, Base, Exponent]);end;procedure TJclNumericFormat.GetMantissaExp(const Value: Float;  out Mantissa: string; out Exponent: Integer);const  {$IFDEF FPC}  InfMantissa: array [Boolean] of string[4] = ('inf', '-inf');  {$ElSE ~FPC}  InfMantissa: array [Boolean] of string = ('inf', '-inf');  {$ENDIF ~FPC}var  BlockDigits: TDigitCount;  IntDigits, FracDigits: Integer;  FirstDigitPos, Prec: Integer;  I, J, N: Integer;  K: Int64;  X: Extended;  HighDigit: Char;  function GetDigit(X: Extended): Char;  var    N: Integer;  begin    N := Trunc(X);    if N > 9 then      Result := Chr(Ord('A') + N - 10)    else      Result := Chr(Ord('0') + N);  end;begin  X := Abs(Value);  if X > MaxFloatingPoint then  begin    Mantissa := InfMantissa[Value < 0];    Exponent := 1;    Exit;  end  else  if X < MinFloatingPoint then  begin    Mantissa := Format('%.*f', [Precision, 0.0]);    Exponent := 1;    Exit;  end;  IntDigits := 1;  Prec := Precision;  Exponent := Trunc(LogBaseN(Base, X));  if FExpDivision > 1 then  begin    N := Exponent mod FExpDivision;    Dec(Exponent, N);    Inc(IntDigits, N);  end;  X := X / Power(Base, Exponent);  if X < 1.0 then  begin    Dec(Exponent, FExpDivision);    X := X * PowerInt(Base, FExpDivision);    Inc(IntDigits, FExpDivision - 1);  end;{ TODO : Here's a problem if X > High(Int64).It *seems* to surface only if ExponentDivision > 12, but ithas not been investigated if ExponentDivision <= 12 is safe. }  K := Trunc(X);  if Value < 0 then    K := -K;  Mantissa := IntToStr(K, FirstDigitPos);  FracDigits := Prec - IntDigits;  if FracDigits > NumberOfFractionalDigits then    FracDigits := NumberOfFractionalDigits;  if FracDigits > 0 then  begin    J := Length(Mantissa) + 1;    // allocate sufficient space for point + digits + digit block separators    SetLength(Mantissa, FracDigits * 2 + J);    Mantissa[J] := FractionalPartSeparator;    I := J + 1;    BlockDigits := 0;    while FracDigits > 0 do    begin      if (BlockDigits > 0) and (BlockDigits = DigitBlockSize) then      begin        Mantissa[I] := DigitBlockSeparator;        Inc(I);        BlockDigits := 0;      end;      X := Frac(X) * Base;      Mantissa[I] := GetDigit(X);      Inc(I);      Inc(BlockDigits);      Dec(FracDigits);    end;    Mantissa[I] := #0;    StrResetLength(Mantissa);  end;  if Frac(X) >= 0.5 then  // round up  begin    HighDigit := Digit(Base - 1);    for I := Length(Mantissa) downto 1 do    begin      if Mantissa[I] = HighDigit then        if (I = FirstDigitPos) then        begin          Mantissa[I] := '1';          Inc(Exponent);          Break;        end        else          Mantissa[I] := '0'      else      if (Mantissa[I] = DigitBlockSeparator) or (Mantissa[I] = FractionalPartSeparator) then        Continue      else      begin        if Mantissa[I] = '9' then          Mantissa[I] := 'A'        else          Mantissa[I] := Succ(Mantissa[I]);        Break;      end;    end;  end;end;function TJclNumericFormat.FloatToStr(const Value: Float): string;var  Mantissa: string;  Exponent: Integer;begin  GetMantissaExp(Value, Mantissa, Exponent);  Result := Format('%s %s %d^%d', [Mantissa, Multiplier, Base, Exponent]);end;function TJclNumericFormat.IntToStr(const Value: Int64): string;var  FirstDigitPos: Integer;begin  Result := IntToStr(Value, FirstDigitPos);end;function TJclNumericFormat.IntToStr(const Value: Int64; out FirstDigitPos: Integer): string;const  MaxResultLen = 64 + 63 + 1; // max. digits + max. group separators + signvar  Remainder: Int64;  I, N: Integer;  Chars, Digits: Cardinal;  LoopFinished, HasSign, SpacePadding: Boolean;begin  SpacePadding := PaddingChar = ' ';  HasSign := ShowSign(Value);  Chars := MaxResultLen;  if Width > Chars then    Chars := Width;  Result := StrRepeatChar(' ', Chars);  Remainder := Abs(Value);  Digits := 0;  Chars := 0;  if HasSign then    Chars := 1;  I := MaxResultLen;  while True do  begin    N := Remainder mod Base;    Remainder := Remainder div Base;    if N > 9 then      Result[I] := Chr(Ord('A') + N - 10)    else      Result[I] := Chr(Ord('0') + N);    Dec(I);    Inc(Digits);    Inc(Chars);    if (Remainder = 0) and (SpacePadding or (Chars >= Width)) then      Break;    if (Digits = DigitBlockSize) then    begin      Inc(Chars);      LoopFinished := (Remainder = 0) and (Chars = Width);      if LoopFinished then        Result[I] := ' '      else        Result[I] := DigitBlockSeparator;      Dec(I);      if LoopFinished then        Break;      Digits := 0;    end;  end;  FirstDigitPos := I + 1;  if HasSign then    Result[I] := SignChar(Value)  else    Inc(I);  N := MaxResultLen - Width + 1;  if N < I then    I := N;  Result := Copy(Result, I, MaxResultLen);  Dec(FirstDigitPos, I - 1);end;procedure TJclNumericFormat.SetBase(const Value: TNumericSystemBase);begin  FBase := Value;  SetPrecision(FWantedPrecision);end;procedure TJclNumericFormat.SetExpDivision(const Value: Integer);begin  if Value <= 1 then    FExpDivision := 1  else  // see TODO in GetMantissaExp  if Value > 12 then    FExpDivision := 12  else    FExpDivision := Value;end;procedure TJclNumericFormat.SetPrecision(const Value: TDigitCount);begin  FWantedPrecision := Value;  // Do not display more digits than Float precision justifies  if Base = 2 then    FPrecision := BinaryPrecision  else    FPrecision := Trunc(BinaryPrecision / LogBase2(Base));  if Value < FPrecision then    FPrecision := Value;end;function TJclNumericFormat.Sign(Value: Char): Integer;begin  Result := 0;  if Value = FSignChars[False] then    Result := -1;  if Value = FSignChars[True] then    Result := +1;end;function TJclNumericFormat.StrToInt(const Value: string): Int64;var  I, N: Integer;  C: Char;begin  Result := 0;  I := 1;  if (Length(Value) >= I)    and ((Value[I] = '+') or (Value[I] = '-')) then    Inc(I);  for I := I to Length(Value) do  begin    C := Value[I];    if C = DigitBlockSeparator then      Continue    else    begin      N := CharHex(C);      if (N = $FF) or (N >= Base) then        InvalidDigit(C);      Result := Result * Base + N;    end;  end;  if Value[1] = '-' then    Result := -Result;end;function TJclNumericFormat.ShowSign(const Value: Float): Boolean;begin  Result := FShowPositiveSign or (Value < 0);end;function TJclNumericFormat.ShowSign(const Value: Int64): Boolean;begin  Result := FShowPositiveSign or (Value < 0);end;function TJclNumericFormat.SignChar(const Value: Float): Char;begin  Result := FSignChars[Value >= 0];end;function TJclNumericFormat.SignChar(const Value: Int64): Char;begin  Result := FSignChars[Value >= 0];end;function TJclNumericFormat.GetNegativeSign: Char;begin  Result := FSignChars[False];end;function TJclNumericFormat.GetPositiveSign: Char;begin  Result := FSignChars[True];end;procedure TJclNumericFormat.SetNegativeSign(const Value: Char);begin  FSignChars[False] := Value;end;procedure TJclNumericFormat.SetPositiveSign(const Value: Char);begin  FSignChars[True] := Value;end;//=== Child processes ========================================================const  BufferSize = 255;type  TBuffer = array [0..BufferSize] of AnsiChar;  TPipeInfo = record    PipeRead, PipeWrite: THandle;    Buffer: TBuffer;    Line: string;    TextHandler: TTextHandler;    RawOutput: Boolean;    AutoConvertOem: Boolean;    Event: TJclEvent;  end;  PPipeInfo = ^TPipeInfo;// MuteCRTerminatedLines was "outsourced" from Win32ExecAndRedirectOutputfunction InternalExecuteMuteCRTerminatedLines(const RawOutput: string): string;const  Delta = 1024;var  BufPos, OutPos, LfPos, EndPos: Integer;  C: Char;begin  SetLength(Result, Length(RawOutput));  OutPos := 1;  LfPos := OutPos;  EndPos := OutPos;  for BufPos := 1 to Length(RawOutput) do  begin    if OutPos >= Length(Result)-2 then      SetLength(Result, Length(Result) + Delta);    C := RawOutput[BufPos];    case C of      NativeCarriageReturn:        OutPos := LfPos;      NativeLineFeed:        begin          OutPos := EndPos;          Result[OutPos] := NativeCarriageReturn;          Inc(OutPos);          Result[OutPos] := C;          Inc(OutPos);          EndPos := OutPos;          LfPos := OutPos;        end;    else      Result[OutPos] := C;      Inc(OutPos);      EndPos := OutPos;    end;  end;  SetLength(Result, OutPos - 1);end;procedure InternalExecuteProcessLine(const PipeInfo: TPipeInfo; LineEnd: Integer);begin  if PipeInfo.RawOutput or (PipeInfo.Line[LineEnd] <> NativeCarriageReturn) then  begin    while (LineEnd > 0) and CharIsReturn(PipeInfo.Line[LineEnd]) do      Dec(LineEnd);    PipeInfo.TextHandler(Copy(PipeInfo.Line, 1, LineEnd));  end;end;procedure InternalExecuteProcessBuffer(var PipeInfo: TPipeInfo; PipeBytesRead: Cardinal);var  CR, LF: Integer;  {$IFDEF MSWINDOWS}  LineLen, Len: Integer;  {$ENDIF MSWINDOWS}  S: AnsiString;begin  {$IFDEF MSWINDOWS}  if PipeInfo.AutoConvertOem then  begin    {$IFDEF UNICODE}    Len := MultiByteToWideChar(CP_OEMCP, 0, PipeInfo.Buffer, PipeBytesRead, nil, 0);    LineLen := Length(PipeInfo.Line);    // Convert directly into the PipeInfo.Line string    SetLength(PipeInfo.Line, LineLen + Len);    MultiByteToWideChar(CP_OEMCP, 0, PipeInfo.Buffer, PipeBytesRead, PChar(PipeInfo.Line) + LineLen, Len);    {$ELSE}    Len := PipeBytesRead;    LineLen := Length(PipeInfo.Line);    // Convert directly into the PipeInfo.Line string    SetLength(PipeInfo.Line, LineLen + Len);    OemToAnsiBuff(PipeInfo.Buffer, PAnsiChar(PipeInfo.Line) + LineLen, PipeBytesRead);    {$ENDIF UNICODE}  end  else  {$ENDIF MSWINDOWS}  begin    SetString(S, PipeInfo.Buffer, PipeBytesRead); // interpret as ANSI    {$IFDEF UNICODE}    PipeInfo.Line := PipeInfo.Line + string(S); // ANSI => UNICODE    {$ELSE}    PipeInfo.Line := PipeInfo.Line + S;    {$ENDIF UNICODE}  end;  if Assigned(PipeInfo.TextHandler) then    repeat      CR := Pos(NativeCarriageReturn, PipeInfo.Line);      if CR = Length(PipeInfo.Line) then        CR := 0;        // line feed at CR + 1 might be missing      LF := Pos(NativeLineFeed, PipeInfo.Line);      if (CR > 0) and ((LF > CR + 1) or (LF = 0)) then        LF := CR;       // accept CR as line end      if LF > 0 then      begin        InternalExecuteProcessLine(PipeInfo, LF);        Delete(PipeInfo.Line, 1, LF);      end;    until LF = 0;end;procedure InternalExecuteReadPipe(var PipeInfo: TPipeInfo; var Overlapped: TOverlapped);var  NullDWORD: ^DWORD; // XE4 broke PDWORD  Res: DWORD;begin  NullDWORD := nil;  if not ReadFile(PipeInfo.PipeRead, PipeInfo.Buffer[0], BufferSize, NullDWORD^, @Overlapped) then  begin    Res := GetLastError;    case Res of      ERROR_BROKEN_PIPE:        begin          CloseHandle(PipeInfo.PipeRead);          PipeInfo.PipeRead := 0;        end;      ERROR_IO_PENDING:        ;    else      {$IFDEF DELPHI11_UP}      RaiseLastOSError(Res);      {$ELSE}      RaiseLastOSError;      {$ENDIF DELPHI11_UP}    end;  end;end;procedure InternalExecuteHandlePipeEvent(var PipeInfo: TPipeInfo; var Overlapped: TOverlapped);var  PipeBytesRead: DWORD;begin  if GetOverlappedResult(PipeInfo.PipeRead, Overlapped, PipeBytesRead, False) then  begin    InternalExecuteProcessBuffer(PipeInfo, PipeBytesRead);    // automatically launch the next read    InternalExecuteReadPipe(PipeInfo, Overlapped);  end  else  if GetLastError = ERROR_BROKEN_PIPE then  begin    CloseHandle(PipeInfo.PipeRead);    PipeInfo.PipeRead := 0;  end  else    RaiseLastOSError;end;procedure InternalExecuteFlushPipe(var PipeInfo: TPipeInfo; var Overlapped: TOverlapped);var  PipeBytesRead: DWORD;begin  CancelIo(PipeInfo.PipeRead);  GetOverlappedResult(PipeInfo.PipeRead, Overlapped, PipeBytesRead, True);  if PipeBytesRead > 0 then    InternalExecuteProcessBuffer(PipeInfo, PipeBytesRead);  while PeekNamedPipe(PipeInfo.PipeRead, nil, 0, nil, @PipeBytesRead, nil) and (PipeBytesRead > 0) do  begin    if PipeBytesRead > BufferSize then      PipeBytesRead := BufferSize;    if not ReadFile(PipeInfo.PipeRead, PipeInfo.Buffer[0], PipeBytesRead, PipeBytesRead, nil) then      RaiseLastOSError;    InternalExecuteProcessBuffer(PipeInfo, PipeBytesRead);  end;end;var  AsyncPipeCounter: Integer;// CreateAsyncPipe creates a pipe that uses overlapped reading.function CreateAsyncPipe(var hReadPipe, hWritePipe: THandle;  lpPipeAttributes: PSecurityAttributes; nSize: DWORD): BOOL;var  PipeName: string;  Error: DWORD;  PipeReadHandle, PipeWriteHandle: THandle;begin  Result := False;  if (@hReadPipe = nil) or (@hWritePipe = nil) then  begin    SetLastError(ERROR_INVALID_PARAMETER);    Exit;  end;  if nSize = 0 then    nSize := 4096;  InterlockedIncrement(AsyncPipeCounter);  // In some (not so) rare instances there is a race condition  // where the counter is the same for two threads at the same  // time. This makes the CreateNamedPipe call below fail  // because of the limit set to 1 in the call.  // So, to be sure this call succeeds, we put both the process  // and thread id in the name of the pipe.  // This was found to happen while simply starting 7 instances  // of the same exe file in parallel.  PipeName := Format('\\.\Pipe\AsyncAnonPipe.%.8x.%.8x.%.8x', [GetCurrentProcessId, GetCurrentThreadId, AsyncPipeCounter]);  PipeReadHandle := CreateNamedPipe(PChar(PipeName), PIPE_ACCESS_INBOUND or FILE_FLAG_OVERLAPPED,      PIPE_TYPE_BYTE or PIPE_WAIT, 1, nSize, nSize, 120 * 1000, lpPipeAttributes);  if PipeReadHandle = INVALID_HANDLE_VALUE then    Exit;  PipeWriteHandle := CreateFile(PChar(PipeName), GENERIC_WRITE, 0, lpPipeAttributes, OPEN_EXISTING,      FILE_ATTRIBUTE_NORMAL {or FILE_FLAG_OVERLAPPED}, 0);  if PipeWriteHandle = INVALID_HANDLE_VALUE then  begin    Error := GetLastError;    CloseHandle(PipeReadHandle);    SetLastError(Error);    Exit;  end;  hReadPipe := PipeReadHandle;  hWritePipe := PipeWriteHandle;  Result := True;end;const  BELOW_NORMAL_PRIORITY_CLASS = $00004000;  ABOVE_NORMAL_PRIORITY_CLASS = $00008000;  ProcessPriorities: array [TJclProcessPriority] of DWORD =    (IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, HIGH_PRIORITY_CLASS, REALTIME_PRIORITY_CLASS,     BELOW_NORMAL_PRIORITY_CLASS, ABOVE_NORMAL_PRIORITY_CLASS);{ TJclExecuteCmdProcessOptions }constructor TJclExecuteCmdProcessOptions.Create(const ACommandLine: string);begin  inherited Create;  FCommandLine := ACommandLine;  FAutoConvertOem := True;  FProcessPriority := ppNormal;end;function ExecuteCmdProcess(Options: TJclExecuteCmdProcessOptions): Boolean;var  OutPipeInfo, ErrorPipeInfo: TPipeInfo;  Index: Cardinal;{$IFDEF MSWINDOWS}const  StartupVisibilityFlags: array[TStartupVisibility] of DWORD = (SW_HIDE, SW_SHOW, SW_SHOWDEFAULT);var  StartupInfo: TStartupInfo;  ProcessInfo: TProcessInformation;  SecurityAttr: TSecurityAttributes;  OutOverlapped, ErrorOverlapped: TOverlapped;  ProcessEvent: TJclDispatcherObject;  WaitEvents: array of TJclDispatcherObject;  InternalAbort: Boolean;  LastError: DWORD;  CommandLine: string;  AbortPtr: PBoolean;  Flags: DWORD;begin  Result := False;  // hack to pass a null reference to the parameter lpNumberOfBytesRead of ReadFile  Options.FExitCode := $FFFFFFFF;  SecurityAttr.nLength := SizeOf(SecurityAttr);  SecurityAttr.lpSecurityDescriptor := nil;  SecurityAttr.bInheritHandle := True;  ResetMemory(OutPipeInfo, SizeOf(OutPipeInfo));  OutPipeInfo.TextHandler := Options.OutputLineCallback;  OutPipeInfo.RawOutput := Options.RawOutput;  OutPipeInfo.AutoConvertOem := Options.AutoConvertOem;  if not CreateAsyncPipe(OutPipeInfo.PipeRead, OutPipeInfo.PipeWrite, @SecurityAttr, 0) then  begin    Options.FExitCode := GetLastError;    Exit;  end;  OutPipeInfo.Event := TJclEvent.Create(@SecurityAttr, False {automatic reset}, False {not flagged}, '' {anonymous});  ResetMemory(ErrorPipeInfo, SizeOf(ErrorPipeInfo));  if not Options.MergeError then  begin    ErrorPipeInfo.TextHandler := Options.ErrorLineCallback;    ErrorPipeInfo.RawOutput := Options.RawError;    ErrorPipeInfo.AutoConvertOem := Options.AutoConvertOem;    if not CreateAsyncPipe(ErrorPipeInfo.PipeRead, ErrorPipeInfo.PipeWrite, @SecurityAttr, 0) then    begin      Options.FExitCode := GetLastError;      CloseHandle(OutPipeInfo.PipeWrite);      CloseHandle(OutPipeInfo.PipeRead);      OutPipeInfo.Event.Free;      Exit;    end;    ErrorPipeInfo.Event := TJclEvent.Create(@SecurityAttr, False {automatic reset}, False {not flagged}, '' {anonymous});  end;  ResetMemory(StartupInfo, SizeOf(TStartupInfo));  StartupInfo.cb := SizeOf(TStartupInfo);  StartupInfo.dwFlags := STARTF_USESTDHANDLES;  if Options.StartupVisibility <> svNotSet then  begin    StartupInfo.dwFlags := StartupInfo.dwFlags or STARTF_USESHOWWINDOW;    StartupInfo.wShowWindow := StartupVisibilityFlags[Options.StartupVisibility];  end;  StartupInfo.hStdInput := GetStdHandle(STD_INPUT_HANDLE);  StartupInfo.hStdOutput := OutPipeInfo.PipeWrite;  if Options.MergeError then    StartupInfo.hStdError := OutPipeInfo.PipeWrite  else    StartupInfo.hStdError := ErrorPipeInfo.PipeWrite;  CommandLine := Options.CommandLine;  UniqueString(CommandLine); // CommandLine must be in a writable memory block  ResetMemory(ProcessInfo, SizeOf(ProcessInfo));  ProcessEvent := nil;  try    Flags := Options.CreateProcessFlags and not (NORMAL_PRIORITY_CLASS or IDLE_PRIORITY_CLASS or                                                 HIGH_PRIORITY_CLASS or REALTIME_PRIORITY_CLASS);    Flags := Flags or ProcessPriorities[Options.ProcessPriority];    if Assigned(Options.BeforeResume) then      Flags := Flags or CREATE_SUSPENDED;    if CreateProcess(nil, PChar(CommandLine), nil, nil, True, Flags,      nil, nil, StartupInfo, ProcessInfo) then    begin      Result := True;      try        try          if Assigned(Options.BeforeResume) then            Options.BeforeResume(ProcessInfo);        finally          if Flags and CREATE_SUSPENDED <> 0 then // CREATE_SUSPENDED may also have come from CreateProcessFlags            ResumeThread(ProcessInfo.hThread);        end;        // init out and error events        CloseHandle(OutPipeInfo.PipeWrite);        OutPipeInfo.PipeWrite := 0;        if not Options.MergeError then        begin          CloseHandle(ErrorPipeInfo.PipeWrite);          ErrorPipeInfo.PipeWrite := 0;        end;        InternalAbort := False;        AbortPtr := Options.AbortPtr;        if AbortPtr <> nil then          AbortPtr^ := {$IFDEF FPC}Byte({$ENDIF}False{$IFDEF FPC}){$ENDIF}        else          AbortPtr := @InternalAbort;        // init the array of events to wait for        ProcessEvent := TJclDispatcherObject.Attach(ProcessInfo.hProcess);        SetLength(WaitEvents, 2);        // add the process first        WaitEvents[0] := ProcessEvent;        // add the output event        WaitEvents[1] := OutPipeInfo.Event;        // add the error event        if not Options.MergeError then        begin          SetLength(WaitEvents, 3);          WaitEvents[2] := ErrorPipeInfo.Event;        end;        // add the abort event if any        if Options.AbortEvent <> nil then        begin          Options.AbortEvent.ResetEvent;          Index := Length(WaitEvents);          SetLength(WaitEvents, Index + 1);          WaitEvents[Index] := Options.AbortEvent;        end;        // init the asynchronous reads        ResetMemory(OutOverlapped, SizeOf(OutOverlapped));        OutOverlapped.hEvent := OutPipeInfo.Event.Handle;        InternalExecuteReadPipe(OutPipeInfo, OutOverlapped);        if not Options.MergeError then        begin          ResetMemory(ErrorOverlapped, SizeOf(ErrorOverlapped));          ErrorOverlapped.hEvent := ErrorPipeInfo.Event.Handle;          InternalExecuteReadPipe(ErrorPipeInfo, ErrorOverlapped);        end;        // event based loop        while not {$IFDEF FPC}Boolean({$ENDIF}AbortPtr^{$IFDEF FPC}){$ENDIF} do        begin          Index := WaitAlertableForMultipleObjects(WaitEvents, False, INFINITE);          if Index = WAIT_OBJECT_0 then            // the subprocess has ended            Break          else          if Index = (WAIT_OBJECT_0 + 1) then          begin            // event on output            InternalExecuteHandlePipeEvent(OutPipeInfo, OutOverlapped);          end          else          if (Index = (WAIT_OBJECT_0 + 2)) and not Options.MergeError then          begin            // event on error            InternalExecuteHandlePipeEvent(ErrorPipeInfo, ErrorOverlapped);          end          else          if ((Index = (WAIT_OBJECT_0 + 2)) and Options.MergeError) or             ((Index = (WAIT_OBJECT_0 + 3)) and not Options.MergeError) then            // event on abort            AbortPtr^ := {$IFDEF FPC}Byte({$ENDIF}True{$IFDEF FPC}){$ENDIF}          else            {$IFDEF DELPHI11_UP}            RaiseLastOSError(Index);            {$ELSE}            RaiseLastOSError;            {$ENDIF DELPHI11_UP}        end;        if {$IFDEF FPC}Boolean({$ENDIF}AbortPtr^{$IFDEF FPC}){$ENDIF} then          TerminateProcess(ProcessEvent.Handle, Cardinal(ABORT_EXIT_CODE));        if (ProcessEvent.WaitForever = {$IFDEF RTL280_UP}TJclWaitResult.{$ENDIF RTL280_UP}wrSignaled) and not GetExitCodeProcess(ProcessEvent.Handle, Options.FExitCode) then          Options.FExitCode := $FFFFFFFF;        CloseHandle(ProcessInfo.hThread);        ProcessInfo.hThread := 0;        if OutPipeInfo.PipeRead <> 0 then          // read data remaining in output pipe          InternalExecuteFlushPipe(OutPipeinfo, OutOverlapped);        if not Options.MergeError and (ErrorPipeInfo.PipeRead <> 0) then          // read data remaining in error pipe          InternalExecuteFlushPipe(ErrorPipeInfo, ErrorOverlapped);      except        // always terminate process in case of an exception.        // This is especially useful when an exception occurred in one of        // the texthandler but only do it if the process actually started,        // this prevents eating up the last error value by calling those        // three functions with an invalid handle        // Note that we don't do it in the finally block because these        // calls would also then eat up the last error value which we tried        // to avoid in the first place        if ProcessInfo.hProcess <> 0 then        begin          TerminateProcess(ProcessInfo.hProcess, Cardinal(ABORT_EXIT_CODE));          WaitForSingleObject(ProcessInfo.hProcess, INFINITE);          GetExitCodeProcess(ProcessInfo.hProcess, Options.FExitCode);        end;        raise;      end;    end;  finally    LastError := GetLastError;    try      if OutPipeInfo.PipeRead <> 0 then        CloseHandle(OutPipeInfo.PipeRead);      if OutPipeInfo.PipeWrite <> 0 then        CloseHandle(OutPipeInfo.PipeWrite);      if ErrorPipeInfo.PipeRead <> 0 then        CloseHandle(ErrorPipeInfo.PipeRead);      if ErrorPipeInfo.PipeWrite <> 0 then        CloseHandle(ErrorPipeInfo.PipeWrite);      if ProcessInfo.hThread <> 0 then        CloseHandle(ProcessInfo.hThread);      if Assigned(ProcessEvent) then        ProcessEvent.Free // this calls CloseHandle(ProcessInfo.hProcess)      else if ProcessInfo.hProcess <> 0 then        CloseHandle(ProcessInfo.hProcess);      OutPipeInfo.Event.Free;      ErrorPipeInfo.Event.Free;    finally      SetLastError(LastError);    end;  end;{$ENDIF MSWINDOWS}{$IFDEF UNIX}var  PipeBytesRead: Cardinal;  Pipe: PIOFile;  Cmd: string;begin  Cmd := Format('%s 2>&1', [Options.CommandLine]);  Pipe := nil;  try    Pipe := Libc.popen(PChar(Cmd), 'r');    { TODO : handle Abort }    repeat      PipeBytesRead := fread_unlocked(@OutBuffer, 1, BufferSize, Pipe);      if PipeBytesRead > 0 then        ProcessBuffer(OutBuffer, OutLine, PipeBytesRead);    until PipeBytesRead = 0;    Result := pclose(Pipe);    Pipe := nil;    wait(nil);  finally    if Pipe <> nil then      pclose(Pipe);    wait(nil);  end;{$ENDIF UNIX}  if OutPipeInfo.Line <> '' then    if Assigned(OutPipeInfo.TextHandler) then      // output wasn't terminated by a line feed...      // (shouldn't happen, but you never know)      InternalExecuteProcessLine(OutPipeInfo, Length(OutPipeInfo.Line))    else      if Options.RawOutput then        Options.FOutput := OutPipeInfo.Line      else        Options.FOutput := InternalExecuteMuteCRTerminatedLines(OutPipeInfo.Line);  if ErrorPipeInfo.Line <> '' then    if Assigned(ErrorPipeInfo.TextHandler) then      // error wasn't terminated by a line feed...      // (shouldn't happen, but you never know)      InternalExecuteProcessLine(ErrorPipeInfo, Length(ErrorPipeInfo.Line))    else      if Options.RawError then        Options.FError := ErrorPipeInfo.Line      else        Options.FError := InternalExecuteMuteCRTerminatedLines(ErrorPipeInfo.Line);end;function InternalExecute(CommandLine: string; AbortPtr: PBoolean; AbortEvent: TJclEvent;  var Output: string; OutputLineCallback: TTextHandler; RawOutput: Boolean;  MergeError: Boolean; var Error: string; ErrorLineCallback: TTextHandler; RawError: Boolean;  ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;var  Options: TJclExecuteCmdProcessOptions;begin  Options := TJclExecuteCmdProcessOptions.Create(CommandLine);  try    Options.AutoConvertOem := AutoConvertOem;    Options.AbortPtr := AbortPtr;    Options.AbortEvent := AbortEvent;    Options.OutputLineCallback := OutputLineCallback;    Options.RawOutput := RawOutput;    Options.MergeError := MergeError;    Options.ErrorLineCallback := ErrorLineCallback;    Options.RawError := RawError;    Options.ProcessPriority := ProcessPriority;    ExecuteCmdProcess(Options);    Result := Options.ExitCode;    // Append => backward compatiblity    Output := Output + Options.Output;    Error := Error + Options.Error;  finally    Options.Free;  end;end;{ TODO -cHelp :RawOutput: Do not process isolated carriage returns (#13).That is, for RawOutput = False, lines not terminated by a line feed (#10) are deleted from Output. }function Execute(const CommandLine: string; var Output: string; RawOutput: Boolean;  AbortPtr: PBoolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;var  Error: string;begin  Error := '';  Result := InternalExecute(CommandLine, AbortPtr, nil, Output, nil, RawOutput, True, Error,    nil, False, ProcessPriority, AutoConvertOem);end;function Execute(const CommandLine: string; AbortEvent: TJclEvent; var Output: string; RawOutput: Boolean;  ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;var  Error: string;begin  Error := '';  Result := InternalExecute(CommandLine, nil, AbortEvent, Output, nil, RawOutput, True, Error,    nil, False, ProcessPriority, AutoConvertOem);end;{ TODO -cHelp :Author: Robert RossmairOutputLineCallback called once per line of output. }function Execute(const CommandLine: string; OutputLineCallback: TTextHandler; RawOutput: Boolean;  AbortPtr: PBoolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;var  Output, Error: string;begin  Output := '';  Error := '';  Result := InternalExecute(CommandLine, AbortPtr, nil, Output, OutputLineCallback, RawOutput, True, Error,    nil, False, ProcessPriority, AutoConvertOem);end;function Execute(const CommandLine: string; AbortEvent: TJclEvent; OutputLineCallback: TTextHandler; RawOutput: Boolean;  ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;var  Output, Error: string;begin  Output := '';  Error := '';  Result := InternalExecute(CommandLine, nil, AbortEvent, Output, OutputLineCallback, RawOutput, True, Error,    nil, False, ProcessPriority, AutoConvertOem);end;{ TODO -cHelp :RawOutput: Do not process isolated carriage returns (#13).That is, for RawOutput = False, lines not terminated by a line feed (#10) are deleted from Output. }function Execute(const CommandLine: string; var Output, Error: string; RawOutput, RawError: Boolean;  AbortPtr: PBoolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;begin  Result := InternalExecute(CommandLine, AbortPtr, nil, Output, nil, RawOutput, False, Error,    nil, RawError, ProcessPriority, AutoConvertOem);end;function Execute(const CommandLine: string; AbortEvent: TJclEvent; var Output, Error: string;  RawOutput, RawError: Boolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;begin  Result := InternalExecute(CommandLine, nil, AbortEvent, Output, nil, RawOutput, False, Error,    nil, RawError, ProcessPriority, AutoConvertOem);end;{ TODO -cHelp :Author: Robert RossmairOutputLineCallback called once per line of output. }function Execute(const CommandLine: string; OutputLineCallback, ErrorLineCallback: TTextHandler;  RawOutput, RawError: Boolean; AbortPtr: PBoolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;var  Output, Error: string;begin  Output := '';  Error := '';  Result := InternalExecute(CommandLine, AbortPtr, nil, Output, OutputLineCallback, RawOutput, False, Error,    ErrorLineCallback, RawError, ProcessPriority, AutoConvertOem);end;function Execute(const CommandLine: string; AbortEvent: TJclEvent; OutputLineCallback, ErrorLineCallback: TTextHandler;  RawOutput, RawError: Boolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;var  Output, Error: string;begin  Output := '';  Error := '';  Result := InternalExecute(CommandLine, nil, AbortEvent, Output, OutputLineCallback, RawOutput, False, Error,    ErrorLineCallback, RawError, ProcessPriority, AutoConvertOem);end;//=== { TJclCommandLineTool } ================================================constructor TJclCommandLineTool.Create(const AExeName: string);begin  inherited Create;  FOptions := TStringList.Create;  FExeName := AExeName;end;destructor TJclCommandLineTool.Destroy;begin  FreeAndNil(FOptions);  inherited Destroy;end;procedure TJclCommandLineTool.AddPathOption(const Option, Path: string);var  S: string;begin  S := PathRemoveSeparator(Path);  {$IFDEF MSWINDOWS}  S := AnsiLowerCase(S); // file names are case insensitive  {$ENDIF MSWINDOWS}  S := Format('-%s%s', [Option, S]);  // avoid duplicate entries (note that search is case sensitive)  if GetOptions.IndexOf(S) = -1 then    GetOptions.Add(S);end;function TJclCommandLineTool.Execute(const CommandLine: string): Boolean;begin  if Assigned(FOutputCallback) then    Result := JclSysUtils.Execute(Format('"%s" %s', [ExeName, CommandLine]), FOutputCallback) = 0  else    Result := JclSysUtils.Execute(Format('"%s" %s', [ExeName, CommandLine]), FOutput) = 0;end;function TJclCommandLineTool.GetExeName: string;begin  Result := FExeName;end;function TJclCommandLineTool.GetOptions: TStrings;begin  Result := FOptions;end;function TJclCommandLineTool.GetOutput: string;begin  Result := FOutput;end;function TJclCommandLineTool.GetOutputCallback: TTextHandler;begin  Result := FOutputCallback;end;procedure TJclCommandLineTool.SetOutputCallback(const CallbackMethod: TTextHandler);begin  FOutputCallback := CallbackMethod;end;//=== Console Utilities ======================================================function ReadKey: Char;{$IFDEF MSWINDOWS}{ TODO -cHelp : Contributor: Robert Rossmair }var  Console: TJclConsole;  InputMode: TJclConsoleInputModes;begin  Console := TJclConsole.Default;  InputMode := Console.Input.Mode;  Console.Input.Mode := [imProcessed];  Console.Input.Clear;  Result := Char(Console.Input.GetEvent.Event.KeyEvent.AsciiChar);  Console.Input.Mode := InputMode;end;{$ENDIF MSWINDOWS}{$IFDEF UNIX}{ TODO -cHelp : Donator: Wayne Sherman }var  ReadFileDescriptor: TFDSet;  TimeVal: TTimeVal;  SaveTerminalSettings: TTermIos;  RawTerminalSettings: TTermIos;begin  Result := #0;  //Save Original Terminal Settings  tcgetattr(stdin, SaveTerminalSettings);  tcgetattr(stdin, RawTerminalSettings);  //Put Terminal in RAW mode  cfmakeraw(RawTerminalSettings);  tcsetattr(stdin, TCSANOW, RawTerminalSettings);  try    //Setup file I/O descriptor for STDIN    FD_ZERO(ReadFileDescriptor);    FD_SET(stdin, ReadFileDescriptor);    TimeVal.tv_sec := High(LongInt); //wait forever    TimeVal.tv_usec := 0;    //clear keyboard buffer first    TCFlush(stdin, TCIFLUSH);    //wait for a key to be pressed    if select(1, @ReadFileDescriptor, nil, nil, @TimeVal) > 0 then    begin      //Now read the character      Result := Char(getchar);    end    else      raise EJclError.CreateRes(@RsReadKeyError);  finally    //Restore Original Terminal Settings    tcsetattr(stdin, TCSANOW, SaveTerminalSettings);  end;end;{$ENDIF UNIX}{$ENDIF ~WINSCP}//=== Loading of modules (DLLs) ==============================================function LoadModule(var Module: TModuleHandle; FileName: string): Boolean;{$IFDEF MSWINDOWS}begin  if Module = INVALID_MODULEHANDLE_VALUE then    Module := SafeLoadLibrary(FileName);  Result := Module <> INVALID_MODULEHANDLE_VALUE;end;{$ENDIF MSWINDOWS}{$IFDEF UNIX}begin  if Module = INVALID_MODULEHANDLE_VALUE then    Module := dlopen(PChar(FileName), RTLD_NOW);  Result := Module <> INVALID_MODULEHANDLE_VALUE;end;{$ENDIF UNIX}function LoadModuleEx(var Module: TModuleHandle; FileName: string; Flags: Cardinal): Boolean;{$IFDEF MSWINDOWS}begin  if Module = INVALID_MODULEHANDLE_VALUE then    Module := LoadLibraryEx(PChar(FileName), 0, Flags); // SafeLoadLibrary?  Result := Module <> INVALID_MODULEHANDLE_VALUE;end;{$ENDIF MSWINDOWS}{$IFDEF UNIX}begin  if Module = INVALID_MODULEHANDLE_VALUE then    Module := dlopen(PChar(FileName), Flags);  Result := Module <> INVALID_MODULEHANDLE_VALUE;end;{$ENDIF UNIX}procedure UnloadModule(var Module: TModuleHandle);{$IFDEF MSWINDOWS}begin  if Module <> INVALID_MODULEHANDLE_VALUE then    FreeLibrary(Module);  Module := INVALID_MODULEHANDLE_VALUE;end;{$ENDIF MSWINDOWS}{$IFDEF UNIX}begin  if Module <> INVALID_MODULEHANDLE_VALUE then    dlclose(Pointer(Module));  Module := INVALID_MODULEHANDLE_VALUE;end;{$ENDIF UNIX}function GetModuleSymbol(Module: TModuleHandle; SymbolName: string): Pointer;{$IFDEF MSWINDOWS}begin  Result := nil;  if Module <> INVALID_MODULEHANDLE_VALUE then    Result := GetProcAddress(Module, PChar(SymbolName));end;{$ENDIF MSWINDOWS}{$IFDEF UNIX}begin  Result := nil;  if Module <> INVALID_MODULEHANDLE_VALUE then    Result := dlsym(Module, PChar(SymbolName));end;{$ENDIF UNIX}function GetModuleSymbolEx(Module: TModuleHandle; SymbolName: string; var Accu: Boolean): Pointer;{$IFDEF MSWINDOWS}begin  Result := nil;  if Module <> INVALID_MODULEHANDLE_VALUE then    Result := GetProcAddress(Module, PChar(SymbolName));  Accu := Accu and (Result <> nil);end;{$ENDIF MSWINDOWS}{$IFDEF UNIX}begin  Result := nil;  if Module <> INVALID_MODULEHANDLE_VALUE then    Result := dlsym(Module, PChar(SymbolName));  Accu := Accu and (Result <> nil);end;{$ENDIF UNIX}function ReadModuleData(Module: TModuleHandle; SymbolName: string; var Buffer; Size: Cardinal): Boolean;var  Sym: Pointer;begin  Result := True;  Sym := GetModuleSymbolEx(Module, SymbolName, Result);  if Result then    Move(Sym^, Buffer, Size);end;function WriteModuleData(Module: TModuleHandle; SymbolName: string; var Buffer; Size: Cardinal): Boolean;var  Sym: Pointer;begin  Result := True;  Sym := GetModuleSymbolEx(Module, SymbolName, Result);  if Result then    Move(Buffer, Sym^, Size);end;//=== Conversion Utilities ===================================================const  DefaultTrueBoolStr  = 'True';  // DO NOT LOCALIZE  DefaultFalseBoolStr = 'False'; // DO NOT LOCALIZE  DefaultYesBoolStr   = 'Yes';   // DO NOT LOCALIZE  DefaultNoBoolStr    = 'No';    // DO NOT LOCALIZEfunction StrToBoolean(const S: string): Boolean;var  LowerCasedText: string;begin  { TODO : Possibility to add localized strings, like in Delphi 7 }  { TODO : Lower case constants }  LowerCasedText := LowerCase(S);  Result := ((S = '1') or    (LowerCasedText = LowerCase(DefaultTrueBoolStr)) or (LowerCasedText = LowerCase(DefaultYesBoolStr))) or    (LowerCasedText = LowerCase(DefaultTrueBoolStr[1])) or (LowerCasedText = LowerCase(DefaultYesBoolStr[1]));  if not Result then  begin    Result := not ((S = '0') or      (LowerCasedText = LowerCase(DefaultFalseBoolStr)) or (LowerCasedText = LowerCase(DefaultNoBoolStr)) or      (LowerCasedText = LowerCase(DefaultFalseBoolStr[1])) or (LowerCasedText = LowerCase(DefaultNoBoolStr[1])));    if Result then      raise EJclConversionError.CreateResFmt(@RsStringToBoolean, [S]);  end;end;function BooleanToStr(B: Boolean): string;begin  if B then    Result := DefaultTrueBoolStr  else    Result := DefaultFalseBoolStr;end;function IntToBool(I: Integer): Boolean;begin  Result := I <> 0;end;function BoolToInt(B: Boolean): Integer;begin  Result := Ord(B);end;function TryStrToUInt(const Value: string; out Res: Cardinal): Boolean;var i6: Int64;begin  Result := false;  if not TryStrToInt64(Value, i6) then exit;  if ( i6 < Low(Res)) or ( i6 > High(Res)) then exit;  Result := true;  Res := i6;end;function StrToUIntDef(const Value: string; const Default: Cardinal): Cardinal;begin  if not TryStrToUInt(Value, Result)     then Result := Default;end;function StrToUInt(const Value: string): Cardinal;begin  if not TryStrToUInt(Value, Result)     then raise EConvertError.Create('"'+Value+'" is not within range of Cardinal data type');end;//=== RTL package information ================================================function SystemTObjectInstance: TJclAddr;begin  Result := ModuleFromAddr(Pointer(System.TObject));end;function IsCompiledWithPackages: Boolean;begin  Result := SystemTObjectInstance <> HInstance;end;//=== GUID ===================================================================function JclGUIDToString(const GUID: TGUID): string;begin  Result := Format('{%.8x-%.4x-%.4x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x}',    [GUID.D1, GUID.D2, GUID.D3, GUID.D4[0], GUID.D4[1], GUID.D4[2],     GUID.D4[3], GUID.D4[4], GUID.D4[5], GUID.D4[6], GUID.D4[7]]);end;function JclStringToGUID(const S: string): TGUID;begin  if (Length(S) <> 38) or (S[1] <> '{') or (S[10] <> '-') or (S[15] <> '-') or    (S[20] <> '-') or (S[25] <> '-') or (S[38] <> '}') then    raise EJclConversionError.CreateResFmt(@RsInvalidGUIDString, [S]);  Result.D1 := StrToInt('$' + Copy(S, 2, 8));  Result.D2 := StrToInt('$' + Copy(S, 11, 4));  Result.D3 := StrToInt('$' + Copy(S, 16, 4));  Result.D4[0] := StrToInt('$' + Copy(S, 21, 2));  Result.D4[1] := StrToInt('$' + Copy(S, 23, 2));  Result.D4[2] := StrToInt('$' + Copy(S, 26, 2));  Result.D4[3] := StrToInt('$' + Copy(S, 28, 2));  Result.D4[4] := StrToInt('$' + Copy(S, 30, 2));  Result.D4[5] := StrToInt('$' + Copy(S, 32, 2));  Result.D4[6] := StrToInt('$' + Copy(S, 34, 2));  Result.D4[7] := StrToInt('$' + Copy(S, 36, 2));end;function GUIDEquals(const GUID1, GUID2: TGUID): Boolean;begin  Result := (GUID1.D1 = GUID2.D1) and (GUID1.D2 = GUID2.D2) and (GUID1.D3 = GUID2.D3) and    (GUID1.D4[0] = GUID2.D4[0]) and (GUID1.D4[1] = GUID2.D4[1]) and    (GUID1.D4[2] = GUID2.D4[2]) and (GUID1.D4[3] = GUID2.D4[3]) and    (GUID1.D4[4] = GUID2.D4[4]) and (GUID1.D4[5] = GUID2.D4[5]) and    (GUID1.D4[6] = GUID2.D4[6]) and (GUID1.D4[7] = GUID2.D4[7]);end;// add items at the endprocedure ListAddItems(var List: string; const Separator, Items: string);var  StrList, NewItems: TStringList;  Index: Integer;begin  StrList := TStringList.Create;  try    StrToStrings(List, Separator, StrList, False);    NewItems := TStringList.Create;    try      StrToStrings(Items, Separator, NewItems);      for Index := 0 to NewItems.Count - 1 do        StrList.Add(NewItems.Strings[Index]);      List := StringsToStr(StrList, Separator);    finally      NewItems.Free;    end;  finally    StrList.Free;  end;end;// add items at the end if they are not presentprocedure ListIncludeItems(var List: string; const Separator, Items: string);var  StrList, NewItems: TStringList;  Index: Integer;  Item: string;begin  StrList := TStringList.Create;  try    StrToStrings(List, Separator, StrList, False);    NewItems := TStringList.Create;    try      StrToStrings(Items, Separator, NewItems);      for Index := 0 to NewItems.Count - 1 do      begin        Item := NewItems.Strings[Index];        if StrList.IndexOf(Item) = -1 then          StrList.Add(Item);      end;      List := StringsToStr(StrList, Separator);    finally      NewItems.Free;    end;  finally    StrList.Free;  end;end;// delete multiple itemsprocedure ListRemoveItems(var List: string; const Separator, Items: string);var  StrList, RemItems: TStringList;  Index, Position: Integer;  Item: string;begin  StrList := TStringList.Create;  try    StrToStrings(List, Separator, StrList, False);    RemItems := TStringList.Create;    try      StrToStrings(Items, Separator, RemItems, False);      for Index := 0 to RemItems.Count - 1 do      begin        Item := RemItems.Strings[Index];        repeat          Position := StrList.IndexOf(Item);          if Position >= 0 then            StrList.Delete(Position);        until Position < 0;      end;      List := StringsToStr(StrList, Separator);    finally      RemItems.Free;    end;  finally    StrList.Free;  end;end;// delete one itemprocedure ListDelItem(var List: string; const Separator: string; const Index: Integer);var  StrList: TStringList;begin  StrList := TStringList.Create;  try    StrToStrings(List, Separator, StrList, False);    StrList.Delete(Index);    List := StringsToStr(StrList, Separator);  finally    StrList.Free;  end;end;// return the number of itemfunction ListItemCount(const List, Separator: string): Integer;var  StrList: TStringList;begin  StrList := TStringList.Create;  try    StrToStrings(List, Separator, StrList, False);    Result := StrList.Count;  finally    StrList.Free;  end;end;// return the Nth itemfunction ListGetItem(const List, Separator: string; const Index: Integer): string;var  StrList: TStringList;begin  StrList := TStringList.Create;  try    StrToStrings(List, Separator, StrList, False);    Result := StrList.Strings[Index];  finally    StrList.Free;  end;end;// set the Nth itemprocedure ListSetItem(var List: string; const Separator: string;  const Index: Integer; const Value: string);var  StrList: TStringList;begin  StrList := TStringList.Create;  try    StrToStrings(List, Separator, StrList, False);    StrList.Strings[Index] := Value;    List := StringsToStr(StrList, Separator);  finally    StrList.Free;  end;end;// return the index of an itemfunction ListItemIndex(const List, Separator, Item: string): Integer;var  StrList: TStringList;begin  StrList := TStringList.Create;  try    StrToStrings(List, Separator, StrList, False);    Result := StrList.IndexOf(Item);  finally    StrList.Free;  end;end;//=== { TJclIntfCriticalSection } ============================================constructor TJclIntfCriticalSection.Create;begin  inherited Create;  FCriticalSection := TCriticalSection.Create;end;destructor TJclIntfCriticalSection.Destroy;begin  FCriticalSection.Free;  inherited Destroy;end;function TJclIntfCriticalSection._AddRef: Integer;begin  FCriticalSection.Acquire;  Result := -1;end;function TJclIntfCriticalSection._Release: Integer;begin  FCriticalSection.Release;  Result := -1;end;{$IFNDEF WINSCP}//=== { TJclSimpleLog } ======================================================{$IFDEF LINUX}const  INVALID_HANDLE_VALUE = 0;{$ENDIF LINUX}constructor TJclSimpleLog.Create(const ALogFileName: string = '');begin  if ALogFileName = '' then    FLogFileName := CreateDefaultFileName  else    FLogFileName := ALogFileName;  FLogFileHandle := TFileHandle(INVALID_HANDLE_VALUE);  FLoggingActive := True;end;function TJclSimpleLog.CreateDefaultFileName: string;begin  Result := PathExtractFileDirFixed(ParamStr(0)) +    PathExtractFileNameNoExt(ParamStr(0)) + '_Err.log';end;destructor TJclSimpleLog.Destroy;begin  CloseLog;  inherited Destroy;end;procedure TJclSimpleLog.ClearLog;var  WasOpen: Boolean;begin  WasOpen := LogOpen;  if WasOpen then    CloseLog;  if not FileExists(FlogFileName) then    Exit;  FLogFileHandle := FileCreate(FLogFileName);  FLogWasEmpty := True;  if Not WasOpen then    CloseLog;end;procedure TJclSimpleLog.CloseLog;begin  if LogOpen then  begin    FileClose(FLogFileHandle);    FLogFileHandle := TFileHandle(INVALID_HANDLE_VALUE);    FLogWasEmpty := False;  end;end;function TJclSimpleLog.GetLogOpen: Boolean;begin  Result := DWORD_PTR(FLogFileHandle) <> INVALID_HANDLE_VALUE;end;procedure TJclSimpleLog.OpenLog;begin  if not LogOpen then  begin    FLogFileHandle := FileOpen(FLogFileName, fmOpenWrite or fmShareDenyWrite);    if LogOpen then      FLogWasEmpty := FileSeek(FLogFileHandle, 0, soFromEnd) = 0    else    begin      FLogFileHandle := FileCreate(FLogFileName);      FLogWasEmpty := True;      if LogOpen then        FileWrite(FLogFileHandle, BOM_UTF8[0], Length(BOM_UTF8));    end;  end  else    FLogWasEmpty := False;end;procedure TJclSimpleLog.Write(const Text: string; Indent: Integer = 0; KeepOpen: Boolean = true);var  S: string;  UTF8S: TUTF8String;  SL: TStringList;  I: Integer;  WasOpen: Boolean;begin  if LoggingActive then  begin    WasOpen := LogOpen;    if not WasOpen then      OpenLog;    if LogOpen then    begin      SL := TStringList.Create;      try        SL.Text := Text;        for I := 0 to SL.Count - 1 do        begin          S := StringOfChar(' ', Indent) + StrEnsureSuffix(NativeLineBreak, TrimRight(SL[I]));          UTF8S := StringToUTF8(S);          FileWrite(FLogFileHandle, UTF8S[1], Length(UTF8S));        end;      finally        SL.Free;      end;      // Keep the logfile Open when it was opened before and the KeepOpen is active      if not (WasOpen and KeepOpen) then        CloseLog;    end;  end;end;procedure TJclSimpleLog.Write(Strings: TStrings; Indent: Integer = 0; KeepOpen: Boolean = true);begin  if Assigned(Strings) then    Write(Strings.Text, Indent, KeepOpen);end;procedure TJclSimpleLog.TimeWrite(const Text: string; Indent: Integer = 0; KeepOpen: Boolean = true);var  S: string;  UTF8S: TUTF8String;  SL: TStringList;  I: Integer;  WasOpen: Boolean;begin  if LoggingActive then  begin    WasOpen := LogOpen;    if not LogOpen then      OpenLog;    if LogOpen then    begin      SL := TStringList.Create;      try        SL.Text := Text;        for I := 0 to SL.Count - 1 do        begin          if DateTimeFormatStr = '' then            S := DateTimeToStr(Now)+' : '+StringOfChar(' ', Indent) + StrEnsureSuffix(NativeLineBreak, TrimRight(SL[I]))          else            S := FormatDateTime( DateTimeFormatStr, Now)+' : '+StringOfChar(' ', Indent) + StrEnsureSuffix(NativeLineBreak, TrimRight(SL[I]));          UTF8S := StringToUTF8(S);          FileWrite(FLogFileHandle, UTF8S[1], Length(UTF8S));        end;      finally        SL.Free;      end;      if Not WasOpen and Not KeepOpen then        CloseLog;    end;  end;end;procedure TJclSimpleLog.TimeWrite(Strings: TStrings; Indent: Integer = 0; KeepOpen: Boolean = true);begin  if Assigned(Strings) then    TimeWrite(Strings.Text, Indent, KeepOpen);end;procedure TJclSimpleLog.WriteStamp(SeparatorLen: Integer = 0; KeepOpen: Boolean = true);var  WasOpen: Boolean;begin  if SeparatorLen <= 0 then    SeparatorLen := 40;  if LoggingActive then  begin    WasOpen := LogOpen;    if not LogOpen then    begin      OpenLog;      if LogOpen and not FLogWasEmpty then        Write(NativeLineBreak);    end;    if LogOpen then    begin      Write(StrRepeat('=', SeparatorLen), 0, True);      if DateTimeFormatStr = '' then        Write(Format('= %-*s =', [SeparatorLen - 4, DateTimeToStr(Now)]), 0, True)      else        Write(Format('= %-*s =', [SeparatorLen - 4, FormatDateTime( DateTimeFormatStr, Now)]), 0, True);      Write(StrRepeat('=', SeparatorLen), 0, True);      if Not WasOpen and Not KeepOpen then        CloseLog;    end;  end;end;procedure InitSimpleLog(const ALogFileName: string = ''; AOpenLog: Boolean = true);begin  if Assigned(SimpleLog) then    FreeAndNil(SimpleLog);  SimpleLog := TJclSimpleLog.Create(ALogFileName);  if AOpenLog then    SimpleLog.OpenLog;end;{$ENDIF ~WINSCP}function TJclFormatSettings.GetCurrencyDecimals: Byte;begin{$IFDEF RTL220_UP}  Result := FormatSettings.CurrencyDecimals;{$ELSE}  Result := SysUtils.CurrencyDecimals;{$ENDIF}end;function TJclFormatSettings.GetCurrencyFormat: Byte;begin{$IFDEF RTL220_UP}  Result := FormatSettings.CurrencyFormat;{$ELSE}  Result := SysUtils.CurrencyFormat;{$ENDIF}end;function TJclFormatSettings.GetCurrencyString: string;begin{$IFDEF RTL220_UP}  Result := FormatSettings.CurrencyString;{$ELSE}  Result := SysUtils.CurrencyString;{$ENDIF}end;function TJclFormatSettings.GetDateSeparator: Char;begin{$IFDEF RTL220_UP}  Result := FormatSettings.DateSeparator;{$ELSE}  Result := SysUtils.DateSeparator;{$ENDIF}end;function TJclFormatSettings.GetDayNamesHighIndex: Integer;begin{$IFDEF RTL220_UP}  Result := High(FormatSettings.LongDayNames);{$ELSE}  Result := High(SysUtils.LongDayNames);{$ENDIF}end;function TJclFormatSettings.GetDayNamesLowIndex: Integer;begin{$IFDEF RTL220_UP}  Result := Low(FormatSettings.LongDayNames);{$ELSE}  Result := Low(SysUtils.LongDayNames);{$ENDIF}end;function TJclFormatSettings.GetDecimalSeparator: Char;begin{$IFDEF RTL220_UP}  Result := FormatSettings.DecimalSeparator;{$ELSE}  Result := SysUtils.DecimalSeparator;{$ENDIF}end;function TJclFormatSettings.GetListSeparator: Char;begin{$IFDEF RTL220_UP}  Result := FormatSettings.ListSeparator;{$ELSE}  Result := SysUtils.ListSeparator;{$ENDIF}end;function TJclFormatSettings.GetLongDateFormat: string;begin{$IFDEF RTL220_UP}  Result := FormatSettings.LongDateFormat;{$ELSE}  Result := SysUtils.LongDateFormat;{$ENDIF}end;{ TJclFormatSettings }function TJclFormatSettings.GetLongDayNames(AIndex: Integer): string;begin{$IFDEF RTL220_UP}  Result := FormatSettings.LongDayNames[AIndex];{$ELSE}  Result := SysUtils.LongDayNames[AIndex];{$ENDIF}end;function TJclFormatSettings.GetLongMonthNames(AIndex: Integer): string;begin{$IFDEF RTL220_UP}  Result := FormatSettings.LongMonthNames[AIndex];{$ELSE}  Result := SysUtils.LongMonthNames[AIndex];{$ENDIF}end;function TJclFormatSettings.GetLongTimeFormat: string;begin{$IFDEF RTL220_UP}  Result := FormatSettings.LongTimeFormat;{$ELSE}  Result := SysUtils.LongTimeFormat;{$ENDIF}end;function TJclFormatSettings.GetMonthNamesHighIndex: Integer;begin{$IFDEF RTL220_UP}  Result := High(FormatSettings.LongMonthNames);{$ELSE}  Result := High(SysUtils.LongMonthNames);{$ENDIF}end;function TJclFormatSettings.GetMonthNamesLowIndex: Integer;begin{$IFDEF RTL220_UP}  Result := Low(FormatSettings.LongMonthNames);{$ELSE}  Result := Low(SysUtils.LongMonthNames);{$ENDIF}end;function TJclFormatSettings.GetNegCurrFormat: Byte;begin{$IFDEF RTL220_UP}  Result := FormatSettings.NegCurrFormat;{$ELSE}  Result := SysUtils.NegCurrFormat;{$ENDIF}end;function TJclFormatSettings.GetShortDateFormat: string;begin{$IFDEF RTL220_UP}  Result := FormatSettings.ShortDateFormat;{$ELSE}  Result := SysUtils.ShortDateFormat;{$ENDIF}end;function TJclFormatSettings.GetShortDayNames(AIndex: Integer): string;begin{$IFDEF RTL220_UP}  Result := FormatSettings.ShortDayNames[AIndex];{$ELSE}  Result := SysUtils.ShortDayNames[AIndex];{$ENDIF}end;function TJclFormatSettings.GetShortMonthNames(AIndex: Integer): string;begin{$IFDEF RTL220_UP}  Result := FormatSettings.ShortMonthNames[AIndex];{$ELSE}  Result := SysUtils.ShortMonthNames[AIndex];{$ENDIF}end;function TJclFormatSettings.GetShortTimeFormat: string;begin{$IFDEF RTL220_UP}  Result := FormatSettings.ShortTimeFormat;{$ELSE}  Result := SysUtils.ShortTimeFormat;{$ENDIF}end;function TJclFormatSettings.GetThousandSeparator: Char;begin{$IFDEF RTL220_UP}  Result := FormatSettings.ThousandSeparator;{$ELSE}  Result := SysUtils.ThousandSeparator;{$ENDIF}end;function TJclFormatSettings.GetTimeAMString: string;begin{$IFDEF RTL220_UP}  Result := FormatSettings.TimeAMString;{$ELSE}  Result := SysUtils.TimeAMString;{$ENDIF}end;function TJclFormatSettings.GetTimePMString: string;begin{$IFDEF RTL220_UP}  Result := FormatSettings.TimePMString;{$ELSE}  Result := SysUtils.TimePMString;{$ENDIF}end;function TJclFormatSettings.GetTimeSeparator: Char;begin{$IFDEF RTL220_UP}  Result := FormatSettings.TimeSeparator;{$ELSE}  Result := SysUtils.TimeSeparator;{$ENDIF}end;function TJclFormatSettings.GetTwoDigitYearCenturyWindow: Word;begin{$IFDEF RTL220_UP}  Result := FormatSettings.TwoDigitYearCenturyWindow;{$ELSE}  Result := SysUtils.TwoDigitYearCenturyWindow;{$ENDIF}end;procedure TJclFormatSettings.SetCurrencyDecimals(AValue: Byte);begin{$IFDEF RTL220_UP}  FormatSettings.CurrencyDecimals := AValue;{$ELSE}  SysUtils.CurrencyDecimals := AValue;{$ENDIF}end;procedure TJclFormatSettings.SetCurrencyFormat(const AValue: Byte);begin{$IFDEF RTL220_UP}  FormatSettings.CurrencyFormat := AValue;{$ELSE}  SysUtils.CurrencyFormat := AValue;{$ENDIF}end;procedure TJclFormatSettings.SetCurrencyString(AValue: string);begin{$IFDEF RTL220_UP}  FormatSettings.CurrencyString := AValue;{$ELSE}  SysUtils.CurrencyString := AValue;{$ENDIF}end;procedure TJclFormatSettings.SetDateSeparator(const AValue: Char);begin{$IFDEF RTL220_UP}  FormatSettings.DateSeparator := AValue;{$ELSE}  SysUtils.DateSeparator := AValue;{$ENDIF}end;procedure TJclFormatSettings.SetDecimalSeparator(AValue: Char);begin{$IFDEF RTL220_UP}  FormatSettings.DecimalSeparator := AValue;{$ELSE}  SysUtils.DecimalSeparator := AValue;{$ENDIF}end;procedure TJclFormatSettings.SetListSeparator(const AValue: Char);begin{$IFDEF RTL220_UP}  FormatSettings.ListSeparator := AValue;{$ELSE}  SysUtils.ListSeparator := AValue;{$ENDIF}end;procedure TJclFormatSettings.SetLongDateFormat(const AValue: string);begin{$IFDEF RTL220_UP}  FormatSettings.LongDateFormat := AValue;{$ELSE}  SysUtils.LongDateFormat := AValue;{$ENDIF}end;procedure TJclFormatSettings.SetLongTimeFormat(const AValue: string);begin{$IFDEF RTL220_UP}  FormatSettings.LongTimeFormat := AValue;{$ELSE}  SysUtils.LongTimeFormat := AValue;{$ENDIF}end;procedure TJclFormatSettings.SetNegCurrFormat(const AValue: Byte);begin{$IFDEF RTL220_UP}  FormatSettings.NegCurrFormat := AValue;{$ELSE}  SysUtils.NegCurrFormat := AValue;{$ENDIF}end;procedure TJclFormatSettings.SetShortDateFormat(AValue: string);begin{$IFDEF RTL220_UP}  FormatSettings.ShortDateFormat := AValue;{$ELSE}  SysUtils.ShortDateFormat := AValue;{$ENDIF}end;procedure TJclFormatSettings.SetShortTimeFormat(const AValue: string);begin{$IFDEF RTL220_UP}  FormatSettings.ShortTimeFormat := AValue;{$ELSE}  SysUtils.ShortTimeFormat := AValue;{$ENDIF}end;procedure TJclFormatSettings.SetThousandSeparator(AValue: Char);begin{$IFDEF RTL220_UP}  FormatSettings.TimeSeparator := AValue;{$ELSE}  SysUtils.TimeSeparator := AValue;{$ENDIF}end;procedure TJclFormatSettings.SetTimeAMString(const AValue: string);begin{$IFDEF RTL220_UP}  FormatSettings.TimeAMString := AValue;{$ELSE}  SysUtils.TimeAMString := AValue;{$ENDIF}end;procedure TJclFormatSettings.SetTimePMString(const AValue: string);begin{$IFDEF RTL220_UP}  FormatSettings.TimePMString := AValue;{$ELSE}  SysUtils.TimePMString := AValue;{$ENDIF}end;procedure TJclFormatSettings.SetTimeSeparator(const AValue: Char);begin{$IFDEF RTL220_UP}  FormatSettings.TimeSeparator := AValue;{$ELSE}  SysUtils.TimeSeparator := AValue;{$ENDIF}end;procedure TJclFormatSettings.SetTwoDigitYearCenturyWindow(const AValue: Word);begin{$IFDEF RTL220_UP}  FormatSettings.TwoDigitYearCenturyWindow:= AValue;{$ELSE}  SysUtils.TwoDigitYearCenturyWindow:= AValue;{$ENDIF}end;function VarIsNullEmpty(const V: Variant): Boolean;begin  Result := VarIsNull(V) or VarIsEmpty(V);end;function VarIsNullEmptyBlank(const V: Variant): Boolean;begin  Result := VarIsNull(V) or VarIsEmpty(V) or (VarToStr(V) = '');end;initialization  {$IFNDEF WINSCP}  SimpleLog := nil;  {$ENDIF ~WINSCP}  {$IFDEF UNITVERSIONING}  RegisterUnitVersion(HInstance, UnitVersioning);  {$ENDIF UNITVERSIONING}finalization  {$IFDEF UNITVERSIONING}  UnregisterUnitVersion(HInstance);  {$ENDIF UNITVERSIONING}  {$IFDEF MSWINDOWS}  {$IFDEF THREADSAFE}  // The user must release shared memory blocks himself. We don't clean up his  // memory leaks and make it impossible to release the shared memory in other  // unit's finalization blocks.  MMFFinalized := True;  FreeAndNil(GlobalMMFHandleListCS);  {$ENDIF THREADSAFE}  {$ENDIF MSWINDOWS}  {$IFNDEF WINSCP}  if Assigned(SimpleLog) then    FreeAndNil(SimpleLog);  {$ENDIF ~WINSCP}end.
 |