| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381 | {**************************************************************************************************}{                                                                                                  }{ 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;// 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;{$ENDIF ~WINSCP}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): Cardinal; overload;function Execute(const CommandLine: string; AbortEvent: TJclEvent;  OutputLineCallback: TTextHandler; RawOutput: Boolean = False; ProcessPriority: TJclProcessPriority = ppNormal): Cardinal; overload;function Execute(const CommandLine: string; var Output: string; RawOutput: Boolean = False;  AbortPtr: PBoolean = nil; ProcessPriority: TJclProcessPriority = ppNormal): Cardinal; overload;function Execute(const CommandLine: string; AbortEvent: TJclEvent;  var Output: string; RawOutput: Boolean = False; ProcessPriority: TJclProcessPriority = ppNormal): Cardinal; overload;function Execute(const CommandLine: string; OutputLineCallback, ErrorLineCallback: TTextHandler;  RawOutput: Boolean = False; RawError: Boolean = False; AbortPtr: PBoolean = nil; ProcessPriority: TJclProcessPriority = ppNormal): Cardinal; overload;function Execute(const CommandLine: string; AbortEvent: TJclEvent;  OutputLineCallback, ErrorLineCallback: TTextHandler; RawOutput: Boolean = False; RawError: Boolean = False; ProcessPriority: TJclProcessPriority = ppNormal): Cardinal; overload;function Execute(const CommandLine: string; var Output, Error: string;  RawOutput: Boolean = False; RawError: Boolean = False; AbortPtr: PBoolean = nil; ProcessPriority: TJclProcessPriority = ppNormal): Cardinal; overload;function Execute(const CommandLine: string; AbortEvent: TJclEvent;  var Output, Error: string; RawOutput: Boolean = False; RawError: Boolean = False; ProcessPriority: TJclProcessPriority = ppNormal): Cardinal; overload;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;{$IFNDEF WINSCP}// 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;  function ArrayItemPointer(Item: SizeInt): Pointer;  begin    Assert(Item >= 0);    Result := Pointer(TJclAddr(ArrayPtr) + TJclAddr(Item * SizeInt(ElementSize)));  end;  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 := ArrayItemPointer((L + R) shr 1);      repeat        IPtr := ArrayItemPointer(I);        JPtr := ArrayItemPointer(J);        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;//=== 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;{$ENDIF ~WINSCP}//=== 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;    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;begin  PipeInfo.Buffer[PipeBytesRead] := #0;  PipeInfo.Line := PipeInfo.Line + string(PipeInfo.Buffer);  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);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): Cardinal;var  OutPipeInfo, ErrorPipeInfo: TPipeInfo;  Index: Cardinal;{$IFDEF MSWINDOWS}var  StartupInfo: TStartupInfo;  ProcessInfo: TProcessInformation;  SecurityAttr: TSecurityAttributes;  OutOverlapped, ErrorOverlapped: TOverlapped;  ProcessEvent: TJclDispatcherObject;  WaitEvents: array of TJclDispatcherObject;  InternalAbort: Boolean;  LastError: DWORD;begin  // hack to pass a null reference to the parameter lpNumberOfBytesRead of ReadFile  Result := $FFFFFFFF;  SecurityAttr.nLength := SizeOf(SecurityAttr);  SecurityAttr.lpSecurityDescriptor := nil;  SecurityAttr.bInheritHandle := True;  ResetMemory(OutPipeInfo, SizeOf(OutPipeInfo));  OutPipeInfo.TextHandler := OutputLineCallback;  OutPipeInfo.RawOutput := RawOutput;  if not CreateAsyncPipe(OutPipeInfo.PipeRead, OutPipeInfo.PipeWrite, @SecurityAttr, 0) then  begin    Result := GetLastError;    Exit;  end;  OutPipeInfo.Event := TJclEvent.Create(@SecurityAttr, False {automatic reset}, False {not flagged}, '' {anonymous});  ResetMemory(ErrorPipeInfo, SizeOf(ErrorPipeInfo));  if not MergeError then  begin    ErrorPipeInfo.TextHandler := ErrorLineCallback;    ErrorPipeInfo.RawOutput := RawError;    if not CreateAsyncPipe(ErrorPipeInfo.PipeRead, ErrorPipeInfo.PipeWrite, @SecurityAttr, 0) then    begin      Result := 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_USESHOWWINDOW or STARTF_USESTDHANDLES;  StartupInfo.wShowWindow := SW_HIDE;  StartupInfo.hStdInput := GetStdHandle(STD_INPUT_HANDLE);  StartupInfo.hStdOutput := OutPipeInfo.PipeWrite;  if MergeError then    StartupInfo.hStdError := OutPipeInfo.PipeWrite  else    StartupInfo.hStdError := ErrorPipeInfo.PipeWrite;  UniqueString(CommandLine); // CommandLine must be in a writable memory block  ResetMemory(ProcessInfo, SizeOf(ProcessInfo));  ProcessEvent := nil;  try    if CreateProcess(nil, PChar(CommandLine), nil, nil, True, ProcessPriorities[ProcessPriority],      nil, nil, StartupInfo, ProcessInfo) then    begin      try        // init out and error events        CloseHandle(OutPipeInfo.PipeWrite);        OutPipeInfo.PipeWrite := 0;        if not MergeError then        begin          CloseHandle(ErrorPipeInfo.PipeWrite);          ErrorPipeInfo.PipeWrite := 0;        end;        InternalAbort := False;        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 MergeError then        begin          SetLength(WaitEvents, 3);          WaitEvents[2] := ErrorPipeInfo.Event;        end;        // add the abort event if any        if AbortEvent <> nil then        begin          AbortEvent.ResetEvent;          Index := Length(WaitEvents);          SetLength(WaitEvents, Index + 1);          WaitEvents[Index] := AbortEvent;        end;        // init the asynchronous reads        ResetMemory(OutOverlapped, SizeOf(OutOverlapped));        OutOverlapped.hEvent := OutPipeInfo.Event.Handle;        InternalExecuteReadPipe(OutPipeInfo, OutOverlapped);        if not 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 MergeError then          begin            // event on error            InternalExecuteHandlePipeEvent(ErrorPipeInfo, ErrorOverlapped);          end          else          if ((Index = (WAIT_OBJECT_0 + 2)) and MergeError) or             ((Index = (WAIT_OBJECT_0 + 3)) and not 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, Result) then          Result := $FFFFFFFF;        CloseHandle(ProcessInfo.hThread);        ProcessInfo.hThread := 0;        if OutPipeInfo.PipeRead <> 0 then          // read data remaining in output pipe          InternalExecuteFlushPipe(OutPipeinfo, OutOverlapped);        if not 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 occured 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, Result);        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', [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 RawOutput then        Output := Output + OutPipeInfo.Line      else        Output := Output + 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 RawError then        Error := Error + ErrorPipeInfo.Line      else        Error := Error + InternalExecuteMuteCRTerminatedLines(ErrorPipeInfo.Line);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): Cardinal;var  Error: string;begin  Error := '';  Result := InternalExecute(CommandLine, AbortPtr, nil, Output, nil, RawOutput, True, Error, nil, False, ProcessPriority);end;function Execute(const CommandLine: string; AbortEvent: TJclEvent; var Output: string; RawOutput: Boolean; ProcessPriority: TJclProcessPriority): Cardinal;var  Error: string;begin  Error := '';  Result := InternalExecute(CommandLine, nil, AbortEvent, Output, nil, RawOutput, True, Error, nil, False, ProcessPriority);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): Cardinal;var  Output, Error: string;begin  Output := '';  Error := '';  Result := InternalExecute(CommandLine, AbortPtr, nil, Output, OutputLineCallback, RawOutput, True, Error, nil, False, ProcessPriority);end;function Execute(const CommandLine: string; AbortEvent: TJclEvent; OutputLineCallback: TTextHandler; RawOutput: Boolean; ProcessPriority: TJclProcessPriority): Cardinal;var  Output, Error: string;begin  Output := '';  Error := '';  Result := InternalExecute(CommandLine, nil, AbortEvent, Output, OutputLineCallback, RawOutput, True, Error, nil, False, ProcessPriority);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): Cardinal;begin  Result := InternalExecute(CommandLine, AbortPtr, nil, Output, nil, RawOutput, False, Error, nil, RawError, ProcessPriority);end;function Execute(const CommandLine: string; AbortEvent: TJclEvent; var Output, Error: string;  RawOutput, RawError: Boolean; ProcessPriority: TJclProcessPriority): Cardinal;begin  Result := InternalExecute(CommandLine, nil, AbortEvent, Output, nil, RawOutput, False, Error, nil, RawError, ProcessPriority);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): Cardinal;var  Output, Error: string;begin  Output := '';  Error := '';  Result := InternalExecute(CommandLine, AbortPtr, nil, Output, OutputLineCallback, RawOutput, False, Error, ErrorLineCallback, RawError, ProcessPriority);end;function Execute(const CommandLine: string; AbortEvent: TJclEvent; OutputLineCallback, ErrorLineCallback: TTextHandler;  RawOutput, RawError: Boolean; ProcessPriority: TJclProcessPriority): Cardinal;var  Output, Error: string;begin  Output := '';  Error := '';  Result := InternalExecute(CommandLine, nil, AbortEvent, Output, OutputLineCallback, RawOutput, False, Error, ErrorLineCallback, RawError, ProcessPriority);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 := LowerCase(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 ======================================================{$IFNDEF WINSCP}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.
 |