JclSysUtils.pas 136 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562
  1. {**************************************************************************************************}
  2. { }
  3. { Project JEDI Code Library (JCL) }
  4. { }
  5. { The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
  6. { you may not use this file except in compliance with the License. You may obtain a copy of the }
  7. { License at http://www.mozilla.org/MPL/ }
  8. { }
  9. { Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
  10. { ANY KIND, either express or implied. See the License for the specific language governing rights }
  11. { and limitations under the License. }
  12. { }
  13. { The Original Code is JclSysUtils.pas. }
  14. { }
  15. { The Initial Developer of the Original Code is Marcel van Brakel. }
  16. { Portions created by Marcel van Brakel are Copyright (C) Marcel van Brakel. All rights reserved. }
  17. { }
  18. { Contributors: }
  19. { Alexander Radchenko, }
  20. { Andreas Hausladen (ahuser) }
  21. { Anthony Steele }
  22. { Bernhard Berger }
  23. { Heri Bender }
  24. { Jean-Fabien Connault (cycocrew) }
  25. { Jens Fudickar }
  26. { Jeroen Speldekamp }
  27. { Marcel van Brakel }
  28. { Peter Friese }
  29. { Petr Vones (pvones) }
  30. { Python }
  31. { Robert Marquardt (marquardt) }
  32. { Robert R. Marsh }
  33. { Robert Rossmair (rrossmair) }
  34. { Rudy Velthuis }
  35. { Uwe Schuster (uschuster) }
  36. { Wayne Sherman }
  37. { }
  38. {**************************************************************************************************}
  39. { }
  40. { Description: Various pointer and class related routines. }
  41. { }
  42. {**************************************************************************************************}
  43. { }
  44. { Last modified: $Date:: $ }
  45. { Revision: $Rev:: $ }
  46. { Author: $Author:: $ }
  47. { }
  48. {**************************************************************************************************}
  49. unit JclSysUtils;
  50. {$I jcl.inc}
  51. interface
  52. uses
  53. {$IFDEF UNITVERSIONING}
  54. JclUnitVersioning,
  55. {$ENDIF UNITVERSIONING}
  56. {$IFDEF HAS_UNITSCOPE}
  57. {$IFDEF MSWINDOWS}
  58. Winapi.Windows,
  59. {$ENDIF MSWINDOWS}
  60. System.SysUtils, System.Classes, System.TypInfo, System.SyncObjs,
  61. {$ELSE ~HAS_UNITSCOPE}
  62. {$IFDEF MSWINDOWS}
  63. Windows,
  64. {$ENDIF MSWINDOWS}
  65. SysUtils, Classes, TypInfo, SyncObjs,
  66. {$ENDIF ~HAS_UNITSCOPE}
  67. JclBase, JclSynch;
  68. // memory initialization
  69. // first parameter is "out" to make FPC happy with uninitialized values
  70. procedure ResetMemory(out P; Size: Longint);
  71. // Pointer manipulation
  72. procedure GetAndFillMem(var P: Pointer; const Size: Integer; const Value: Byte);
  73. procedure FreeMemAndNil(var P: Pointer);
  74. function PCharOrNil(const S: string): PChar;
  75. function PAnsiCharOrNil(const S: AnsiString): PAnsiChar;
  76. {$IFDEF SUPPORTS_WIDESTRING}
  77. function PWideCharOrNil(const W: WideString): PWideChar;
  78. {$ENDIF SUPPORTS_WIDESTRING}
  79. function SizeOfMem(const APointer: Pointer): Integer;
  80. function WriteProtectedMemory(BaseAddress, Buffer: Pointer; Size: Cardinal;
  81. out WrittenBytes: Cardinal): Boolean;
  82. // Guards
  83. type
  84. ISafeGuard = interface
  85. function ReleaseItem: Pointer;
  86. function GetItem: Pointer;
  87. procedure FreeItem;
  88. property Item: Pointer read GetItem;
  89. end;
  90. IMultiSafeGuard = interface (IInterface)
  91. function AddItem(Item: Pointer): Pointer;
  92. procedure FreeItem(Index: Integer);
  93. function GetCount: Integer;
  94. function GetItem(Index: Integer): Pointer;
  95. function ReleaseItem(Index: Integer): Pointer;
  96. property Count: Integer read GetCount;
  97. property Items[Index: Integer]: Pointer read GetItem;
  98. end;
  99. TJclSafeGuard = class(TInterfacedObject, ISafeGuard)
  100. private
  101. FItem: Pointer;
  102. public
  103. constructor Create(Mem: Pointer);
  104. destructor Destroy; override;
  105. { ISafeGuard }
  106. function ReleaseItem: Pointer;
  107. function GetItem: Pointer;
  108. procedure FreeItem; virtual;
  109. property Item: Pointer read GetItem;
  110. end;
  111. TJclObjSafeGuard = class(TJclSafeGuard, ISafeGuard)
  112. public
  113. constructor Create(Obj: TObject);
  114. { ISafeGuard }
  115. procedure FreeItem; override;
  116. end;
  117. TJclMultiSafeGuard = class(TInterfacedObject, IMultiSafeGuard)
  118. private
  119. FItems: TList;
  120. public
  121. constructor Create;
  122. destructor Destroy; override;
  123. { IMultiSafeGuard }
  124. function AddItem(Item: Pointer): Pointer;
  125. procedure FreeItem(Index: Integer); virtual;
  126. function GetCount: Integer;
  127. function GetItem(Index: Integer): Pointer;
  128. function ReleaseItem(Index: Integer): Pointer;
  129. property Count: Integer read GetCount;
  130. property Items[Index: Integer]: Pointer read GetItem;
  131. end;
  132. TJclObjMultiSafeGuard = class(TJclMultiSafeGuard, IMultiSafeGuard)
  133. public
  134. { IMultiSafeGuard }
  135. procedure FreeItem(Index: Integer); override;
  136. end;
  137. function Guard(Mem: Pointer; out SafeGuard: ISafeGuard): Pointer; overload;
  138. function Guard(Obj: TObject; out SafeGuard: ISafeGuard): TObject; overload;
  139. function Guard(Mem: Pointer; var SafeGuard: IMultiSafeGuard): Pointer; overload;
  140. function Guard(Obj: TObject; var SafeGuard: IMultiSafeGuard): TObject; overload;
  141. function GuardGetMem(Size: Cardinal; out SafeGuard: ISafeGuard): Pointer;
  142. function GuardAllocMem(Size: Cardinal; out SafeGuard: ISafeGuard): Pointer;
  143. (*
  144. {$IFDEF SUPPORTS_GENERICS}
  145. type
  146. ISafeGuard<T: class> = interface
  147. function ReleaseItem: T;
  148. function GetItem: T;
  149. procedure FreeItem;
  150. property Item: T read GetItem;
  151. end;
  152. TSafeGuard<T: class> = class(TObject, ISafeGuard<T>)
  153. private
  154. FItem: T;
  155. function ReleaseItem: T;
  156. function GetItem: T;
  157. procedure FreeItem;
  158. constructor Create(Instance: T);
  159. destructor Destroy; override;
  160. public
  161. class function New(Instance: T): ISafeGuard<T>; static;
  162. end;
  163. {$ENDIF SUPPORTS_GENERICS}
  164. *)
  165. { Shared memory between processes functions }
  166. // Functions for the shared memory owner
  167. type
  168. ESharedMemError = class(EJclError);
  169. {$IFDEF MSWINDOWS}
  170. { SharedGetMem return ERROR_ALREADY_EXISTS if the shared memory is already
  171. allocated, otherwise it returns 0.
  172. Throws ESharedMemError if the Name is invalid. }
  173. function SharedGetMem(var P{: Pointer}; const Name: string; Size: Cardinal;
  174. DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Integer;
  175. { SharedAllocMem calls SharedGetMem and then fills the memory with zero if
  176. it was not already allocated.
  177. Throws ESharedMemError if the Name is invalid. }
  178. function SharedAllocMem(const Name: string; Size: Cardinal;
  179. DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Pointer;
  180. { SharedFreeMem releases the shared memory if it was the last reference. }
  181. function SharedFreeMem(var P{: Pointer}): Boolean;
  182. // Functions for the shared memory user
  183. { SharedOpenMem returns True if the shared memory was already allocated by
  184. SharedGetMem or SharedAllocMem. Otherwise it returns False.
  185. Throws ESharedMemError if the Name is invalid. }
  186. function SharedOpenMem(var P{: Pointer}; const Name: string;
  187. DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Boolean; overload;
  188. { SharedOpenMem return nil if the shared memory was not already allocated
  189. by SharedGetMem or SharedAllocMem.
  190. Throws ESharedMemError if the Name is invalid. }
  191. function SharedOpenMem(const Name: string;
  192. DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Pointer; overload;
  193. { SharedCloseMem releases the shared memory if it was the last reference. }
  194. function SharedCloseMem(var P{: Pointer}): Boolean;
  195. {$ENDIF MSWINDOWS}
  196. // Binary search
  197. function SearchSortedList(List: TList; SortFunc: TListSortCompare; Item: Pointer;
  198. Nearest: Boolean = False): Integer;
  199. type
  200. TUntypedSearchCompare = function(Param: Pointer; ItemIndex: Integer; const Value): Integer;
  201. function SearchSortedUntyped(Param: Pointer; ItemCount: Integer; SearchFunc: TUntypedSearchCompare;
  202. const Value; Nearest: Boolean = False): Integer;
  203. // Dynamic array sort and search routines
  204. type
  205. TDynArraySortCompare = function (Item1, Item2: Pointer): Integer;
  206. procedure SortDynArray(const ArrayPtr: Pointer; ElementSize: Cardinal; SortFunc: TDynArraySortCompare);
  207. // Usage: SortDynArray(Array, SizeOf(Array[0]), SortFunction);
  208. function SearchDynArray(const ArrayPtr: Pointer; ElementSize: Cardinal; SortFunc: TDynArraySortCompare;
  209. ValuePtr: Pointer; Nearest: Boolean = False): SizeInt;
  210. // Usage: SearchDynArray(Array, SizeOf(Array[0]), SortFunction, @SearchedValue);
  211. { Various compare functions for basic types }
  212. function DynArrayCompareByte(Item1, Item2: Pointer): Integer;
  213. function DynArrayCompareShortInt(Item1, Item2: Pointer): Integer;
  214. function DynArrayCompareWord(Item1, Item2: Pointer): Integer;
  215. function DynArrayCompareSmallInt(Item1, Item2: Pointer): Integer;
  216. function DynArrayCompareInteger(Item1, Item2: Pointer): Integer;
  217. function DynArrayCompareCardinal(Item1, Item2: Pointer): Integer;
  218. function DynArrayCompareInt64(Item1, Item2: Pointer): Integer;
  219. function DynArrayCompareSingle(Item1, Item2: Pointer): Integer;
  220. function DynArrayCompareDouble(Item1, Item2: Pointer): Integer;
  221. function DynArrayCompareExtended(Item1, Item2: Pointer): Integer;
  222. function DynArrayCompareFloat(Item1, Item2: Pointer): Integer;
  223. function DynArrayCompareAnsiString(Item1, Item2: Pointer): Integer;
  224. function DynArrayCompareAnsiText(Item1, Item2: Pointer): Integer;
  225. function DynArrayCompareWideString(Item1, Item2: Pointer): Integer;
  226. function DynArrayCompareWideText(Item1, Item2: Pointer): Integer;
  227. function DynArrayCompareString(Item1, Item2: Pointer): Integer;
  228. function DynArrayCompareText(Item1, Item2: Pointer): Integer;
  229. // Object lists
  230. procedure ClearObjectList(List: TList);
  231. procedure FreeObjectList(var List: TList);
  232. // Reference memory stream
  233. type
  234. TJclReferenceMemoryStream = class(TCustomMemoryStream)
  235. public
  236. constructor Create(const Ptr: Pointer; Size: Longint);
  237. function Write(const Buffer; Count: Longint): Longint; override;
  238. end;
  239. // AutoPtr
  240. type
  241. IAutoPtr = interface
  242. { Returns the object as pointer, so it is easier to assign it to a variable }
  243. function AsPointer: Pointer;
  244. { Returns the AutoPtr handled object }
  245. function AsObject: TObject;
  246. { Releases the object from the AutoPtr. The AutoPtr looses the control over
  247. the object. }
  248. function ReleaseObject: TObject;
  249. end;
  250. TJclAutoPtr = class(TInterfacedObject, IAutoPtr)
  251. private
  252. FValue: TObject;
  253. public
  254. constructor Create(AValue: TObject);
  255. destructor Destroy; override;
  256. { IAutoPtr }
  257. function AsPointer: Pointer;
  258. function AsObject: TObject;
  259. function ReleaseObject: TObject;
  260. end;
  261. function CreateAutoPtr(Value: TObject): IAutoPtr;
  262. // Replacement for the C ternary conditional operator ? :
  263. function Iff(const Condition: Boolean; const TruePart, FalsePart: string): string; overload;
  264. function Iff(const Condition: Boolean; const TruePart, FalsePart: Char): Char; overload;
  265. function Iff(const Condition: Boolean; const TruePart, FalsePart: Byte): Byte; overload;
  266. function Iff(const Condition: Boolean; const TruePart, FalsePart: Integer): Integer; overload;
  267. function Iff(const Condition: Boolean; const TruePart, FalsePart: Cardinal): Cardinal; overload;
  268. function Iff(const Condition: Boolean; const TruePart, FalsePart: Float): Float; overload;
  269. function Iff(const Condition: Boolean; const TruePart, FalsePart: Boolean): Boolean; overload;
  270. function Iff(const Condition: Boolean; const TruePart, FalsePart: Pointer): Pointer; overload;
  271. function Iff(const Condition: Boolean; const TruePart, FalsePart: Int64): Int64; overload;
  272. {$IFDEF SUPPORTS_VARIANT}
  273. function Iff(const Condition: Boolean; const TruePart, FalsePart: Variant): Variant; overload;
  274. {$ENDIF SUPPORTS_VARIANT}
  275. // Classes information and manipulation
  276. type
  277. EJclVMTError = class(EJclError);
  278. // Virtual Methods
  279. {$IFNDEF FPC}
  280. function GetVirtualMethodCount(AClass: TClass): Integer;
  281. {$ENDIF ~FPC}
  282. function GetVirtualMethod(AClass: TClass; const Index: Integer): Pointer;
  283. procedure SetVirtualMethod(AClass: TClass; const Index: Integer; const Method: Pointer);
  284. // Dynamic Methods
  285. type
  286. TDynamicIndexList = array [0..MaxInt div 16] of Word;
  287. PDynamicIndexList = ^TDynamicIndexList;
  288. TDynamicAddressList = array [0..MaxInt div 16] of Pointer;
  289. PDynamicAddressList = ^TDynamicAddressList;
  290. function GetDynamicMethodCount(AClass: TClass): Integer;
  291. function GetDynamicIndexList(AClass: TClass): PDynamicIndexList;
  292. function GetDynamicAddressList(AClass: TClass): PDynamicAddressList;
  293. function HasDynamicMethod(AClass: TClass; Index: Integer): Boolean;
  294. {$IFNDEF FPC}
  295. function GetDynamicMethod(AClass: TClass; Index: Integer): Pointer;
  296. {$ENDIF ~FPC}
  297. { init table methods }
  298. function GetInitTable(AClass: TClass): PTypeInfo;
  299. { field table methods }
  300. type
  301. PFieldEntry = ^TFieldEntry;
  302. TFieldEntry = packed record
  303. OffSet: Integer;
  304. IDX: Word;
  305. Name: ShortString;
  306. end;
  307. PFieldClassTable = ^TFieldClassTable;
  308. TFieldClassTable = packed record
  309. Count: Smallint;
  310. Classes: array [0..8191] of ^TPersistentClass;
  311. end;
  312. PFieldTable = ^TFieldTable;
  313. TFieldTable = packed record
  314. EntryCount: Word;
  315. FieldClassTable: PFieldClassTable;
  316. FirstEntry: TFieldEntry;
  317. {Entries: array [1..65534] of TFieldEntry;}
  318. end;
  319. function GetFieldTable(AClass: TClass): PFieldTable;
  320. { method table }
  321. type
  322. PMethodEntry = ^TMethodEntry;
  323. TMethodEntry = packed record
  324. EntrySize: Word;
  325. Address: Pointer;
  326. Name: ShortString;
  327. end;
  328. PMethodTable = ^TMethodTable;
  329. TMethodTable = packed record
  330. Count: Word;
  331. FirstEntry: TMethodEntry;
  332. {Entries: array [1..65534] of TMethodEntry;}
  333. end;
  334. function GetMethodTable(AClass: TClass): PMethodTable;
  335. function GetMethodEntry(MethodTable: PMethodTable; Index: Integer): PMethodEntry;
  336. // Function to compare if two methods/event handlers are equal
  337. function MethodEquals(aMethod1, aMethod2: TMethod): boolean;
  338. function NotifyEventEquals(aMethod1, aMethod2: TNotifyEvent): boolean;
  339. // Class Parent
  340. procedure SetClassParent(AClass: TClass; NewClassParent: TClass);
  341. function GetClassParent(AClass: TClass): TClass;
  342. {$IFNDEF FPC}
  343. function IsClass(Address: Pointer): Boolean;
  344. function IsObject(Address: Pointer): Boolean;
  345. {$ENDIF ~FPC}
  346. function InheritsFromByName(AClass: TClass; const AClassName: string): Boolean;
  347. // Interface information
  348. function GetImplementorOfInterface(const I: IInterface): TObject;
  349. // interfaced persistent
  350. type
  351. TJclInterfacedPersistent = class(TInterfacedPersistent, IInterface)
  352. protected
  353. FOwnerInterface: IInterface;
  354. FRefCount: Integer;
  355. public
  356. procedure AfterConstruction; override;
  357. { IInterface }
  358. // function QueryInterface(const IID: TGUID; out Obj): HRESULT; virtual; stdcall;
  359. function _AddRef: Integer; stdcall;
  360. function _Release: Integer; stdcall;
  361. end;
  362. // Numeric formatting routines
  363. type
  364. TDigitCount = 0..255;
  365. TDigitValue = -1..35; // invalid, '0'..'9', 'A'..'Z'
  366. TNumericSystemBase = 2..Succ(High(TDigitValue));
  367. {$IFNDEF WINSCP}
  368. TJclNumericFormat = class(TObject)
  369. private
  370. FWantedPrecision: TDigitCount;
  371. FPrecision: TDigitCount;
  372. FNumberOfFractionalDigits: TDigitCount;
  373. FExpDivision: Integer;
  374. FDigitBlockSize: TDigitCount;
  375. FWidth: TDigitCount;
  376. FSignChars: array [Boolean] of Char;
  377. FBase: TNumericSystemBase;
  378. FFractionalPartSeparator: Char;
  379. FDigitBlockSeparator: Char;
  380. FShowPositiveSign: Boolean;
  381. FPaddingChar: Char;
  382. FMultiplier: string;
  383. function GetDigitValue(Digit: Char): Integer;
  384. function GetNegativeSign: Char;
  385. function GetPositiveSign: Char;
  386. procedure InvalidDigit(Digit: Char);
  387. procedure SetPrecision(const Value: TDigitCount);
  388. procedure SetBase(const Value: TNumericSystemBase);
  389. procedure SetNegativeSign(const Value: Char);
  390. procedure SetPositiveSign(const Value: Char);
  391. procedure SetExpDivision(const Value: Integer);
  392. protected
  393. function IntToStr(const Value: Int64; out FirstDigitPos: Integer): string; overload;
  394. function ShowSign(const Value: Float): Boolean; overload;
  395. function ShowSign(const Value: Int64): Boolean; overload;
  396. function SignChar(const Value: Float): Char; overload;
  397. function SignChar(const Value: Int64): Char; overload;
  398. property WantedPrecision: TDigitCount read FWantedPrecision;
  399. public
  400. constructor Create;
  401. function Digit(DigitValue: TDigitValue): Char;
  402. function DigitValue(Digit: Char): TDigitValue;
  403. function IsDigit(Value: Char): Boolean;
  404. function Sign(Value: Char): Integer;
  405. procedure GetMantissaExp(const Value: Float; out Mantissa: string; out Exponent: Integer);
  406. function FloatToHTML(const Value: Float): string;
  407. function IntToStr(const Value: Int64): string; overload;
  408. function FloatToStr(const Value: Float): string; overload;
  409. function StrToInt(const Value: string): Int64;
  410. property Base: TNumericSystemBase read FBase write SetBase;
  411. property Precision: TDigitCount read FPrecision write SetPrecision;
  412. property NumberOfFractionalDigits: TDigitCount read FNumberOfFractionalDigits write FNumberOfFractionalDigits;
  413. property ExponentDivision: Integer read FExpDivision write SetExpDivision;
  414. property DigitBlockSize: TDigitCount read FDigitBlockSize write FDigitBlockSize;
  415. property DigitBlockSeparator: Char read FDigitBlockSeparator write FDigitBlockSeparator;
  416. property FractionalPartSeparator: Char read FFractionalPartSeparator write FFractionalPartSeparator;
  417. property Multiplier: string read FMultiplier write FMultiplier;
  418. property PaddingChar: Char read FPaddingChar write FPaddingChar;
  419. property ShowPositiveSign: Boolean read FShowPositiveSign write FShowPositiveSign;
  420. property Width: TDigitCount read FWidth write FWidth;
  421. property NegativeSign: Char read GetNegativeSign write SetNegativeSign;
  422. property PositiveSign: Char read GetPositiveSign write SetPositiveSign;
  423. end;
  424. function IntToStrZeroPad(Value, Count: Integer): string;
  425. // Child processes
  426. type
  427. // e.g. TStrings.Append
  428. TTextHandler = procedure(const Text: string) of object;
  429. TJclProcessPriority = (ppIdle, ppNormal, ppHigh, ppRealTime, ppBelowNormal, ppAboveNormal);
  430. const
  431. ABORT_EXIT_CODE = {$IFDEF MSWINDOWS} ERROR_CANCELLED {$ELSE} 1223 {$ENDIF};
  432. function Execute(const CommandLine: string; OutputLineCallback: TTextHandler; RawOutput: Boolean = False;
  433. AbortPtr: PBoolean = nil; ProcessPriority: TJclProcessPriority = ppNormal;
  434. AutoConvertOem: Boolean = False): Cardinal; overload;
  435. function Execute(const CommandLine: string; AbortEvent: TJclEvent;
  436. OutputLineCallback: TTextHandler; RawOutput: Boolean = False; ProcessPriority: TJclProcessPriority = ppNormal;
  437. AutoConvertOem: Boolean = False): Cardinal; overload;
  438. function Execute(const CommandLine: string; var Output: string; RawOutput: Boolean = False;
  439. AbortPtr: PBoolean = nil; ProcessPriority: TJclProcessPriority = ppNormal;
  440. AutoConvertOem: Boolean = False): Cardinal; overload;
  441. function Execute(const CommandLine: string; AbortEvent: TJclEvent;
  442. var Output: string; RawOutput: Boolean = False; ProcessPriority: TJclProcessPriority = ppNormal;
  443. AutoConvertOem: Boolean = False): Cardinal; overload;
  444. function Execute(const CommandLine: string; OutputLineCallback, ErrorLineCallback: TTextHandler;
  445. RawOutput: Boolean = False; RawError: Boolean = False; AbortPtr: PBoolean = nil;
  446. ProcessPriority: TJclProcessPriority = ppNormal; AutoConvertOem: Boolean = False): Cardinal; overload;
  447. function Execute(const CommandLine: string; AbortEvent: TJclEvent;
  448. OutputLineCallback, ErrorLineCallback: TTextHandler; RawOutput: Boolean = False; RawError: Boolean = False;
  449. ProcessPriority: TJclProcessPriority = ppNormal; AutoConvertOem: Boolean = False): Cardinal; overload;
  450. function Execute(const CommandLine: string; var Output, Error: string;
  451. RawOutput: Boolean = False; RawError: Boolean = False; AbortPtr: PBoolean = nil;
  452. ProcessPriority: TJclProcessPriority = ppNormal; AutoConvertOem: Boolean = False): Cardinal; overload;
  453. function Execute(const CommandLine: string; AbortEvent: TJclEvent;
  454. var Output, Error: string; RawOutput: Boolean = False; RawError: Boolean = False;
  455. ProcessPriority: TJclProcessPriority = ppNormal; AutoConvertOem: Boolean = False): Cardinal; overload;
  456. type
  457. {$IFDEF MSWINDOWS}
  458. TJclExecuteCmdProcessOptionBeforeResumeEvent = procedure(const ProcessInfo: TProcessInformation) of object;
  459. TStartupVisibility = (svHide, svShow, svNotSet);
  460. {$ENDIF MSWINDOWS}
  461. TJclExecuteCmdProcessOptions = {record} class(TObject)
  462. private
  463. FCommandLine: string;
  464. FAbortPtr: PBoolean;
  465. FAbortEvent: TJclEvent;
  466. FOutputLineCallback: TTextHandler;
  467. FRawOutput: Boolean;
  468. FMergeError: Boolean;
  469. FErrorLineCallback: TTextHandler;
  470. FRawError: Boolean;
  471. FProcessPriority: TJclProcessPriority;
  472. FAutoConvertOem: Boolean;
  473. {$IFDEF MSWINDOWS}
  474. FCreateProcessFlags: DWORD;
  475. FStartupVisibility: TStartupVisibility;
  476. FBeforeResume: TJclExecuteCmdProcessOptionBeforeResumeEvent;
  477. {$ENDIF MSWINDOWS}
  478. FExitCode: Cardinal;
  479. FOutput: string;
  480. FError: string;
  481. public
  482. // in:
  483. property CommandLine: string read FCommandLine write FCommandLine;
  484. property AbortPtr: PBoolean read FAbortPtr write FAbortPtr;
  485. property AbortEvent: TJclEvent read FAbortEvent write FAbortEvent;
  486. property OutputLineCallback: TTextHandler read FOutputLineCallback write FOutputLineCallback;
  487. property RawOutput: Boolean read FRawOutput write FRawOutput default False;
  488. property MergeError: Boolean read FMergeError write FMergeError default False;
  489. property ErrorLineCallback: TTextHandler read FErrorLineCallback write FErrorLineCallback;
  490. property RawError: Boolean read FRawError write FRawError default False;
  491. property ProcessPriority: TJclProcessPriority read FProcessPriority write FProcessPriority default ppNormal;
  492. // AutoConvertOem assumes the process outputs OEM encoded strings and converts them to the
  493. // default string encoding.
  494. property AutoConvertOem: Boolean read FAutoConvertOem write FAutoConvertOem default True;
  495. {$IFDEF MSWINDOWS}
  496. property CreateProcessFlags: DWORD read FCreateProcessFlags write FCreateProcessFlags;
  497. property StartupVisibility: TStartupVisibility read FStartupVisibility write FStartupVisibility;
  498. property BeforeResume: TJclExecuteCmdProcessOptionBeforeResumeEvent read FBeforeResume write FBeforeResume;
  499. {$ENDIF MSWINDOWS}
  500. // out:
  501. property ExitCode: Cardinal read FExitCode;
  502. property Output: string read FOutput;
  503. property Error: string read FError;
  504. public
  505. constructor Create(const ACommandLine: string);
  506. end;
  507. function ExecuteCmdProcess(Options: TJclExecuteCmdProcessOptions): Boolean;
  508. type
  509. {$HPPEMIT 'namespace Jclsysutils'}
  510. {$HPPEMIT '{'}
  511. {$HPPEMIT ' // For some reason, the generator puts this interface after its first'}
  512. {$HPPEMIT ' // usage, resulting in an unusable header file. We fix this by forward'}
  513. {$HPPEMIT ' // declaring the interface.'}
  514. {$HPPEMIT ' __interface IJclCommandLineTool;'}
  515. (*$HPPEMIT '}'*)
  516. IJclCommandLineTool = interface
  517. ['{A0034B09-A074-D811-847D-0030849E4592}']
  518. function GetExeName: string;
  519. function GetOptions: TStrings;
  520. function GetOutput: string;
  521. function GetOutputCallback: TTextHandler;
  522. procedure AddPathOption(const Option, Path: string);
  523. function Execute(const CommandLine: string): Boolean;
  524. procedure SetOutputCallback(const CallbackMethod: TTextHandler);
  525. property ExeName: string read GetExeName;
  526. property Options: TStrings read GetOptions;
  527. property OutputCallback: TTextHandler read GetOutputCallback write SetOutputCallback;
  528. property Output: string read GetOutput;
  529. end;
  530. EJclCommandLineToolError = class(EJclError);
  531. TJclCommandLineTool = class(TInterfacedObject, IJclCommandLineTool)
  532. private
  533. FExeName: string;
  534. FOptions: TStringList;
  535. FOutput: string;
  536. FOutputCallback: TTextHandler;
  537. public
  538. constructor Create(const AExeName: string);
  539. destructor Destroy; override;
  540. { IJclCommandLineTool }
  541. function GetExeName: string;
  542. function GetOptions: TStrings;
  543. function GetOutput: string;
  544. function GetOutputCallback: TTextHandler;
  545. procedure AddPathOption(const Option, Path: string);
  546. function Execute(const CommandLine: string): Boolean;
  547. procedure SetOutputCallback(const CallbackMethod: TTextHandler);
  548. property ExeName: string read GetExeName;
  549. property Options: TStrings read GetOptions;
  550. property OutputCallback: TTextHandler read GetOutputCallback write SetOutputCallback;
  551. property Output: string read GetOutput;
  552. end;
  553. // Console Utilities
  554. function ReadKey: Char;
  555. {$ENDIF ~WINSCP}
  556. // Loading of modules (DLLs)
  557. type
  558. {$IFDEF MSWINDOWS}
  559. TModuleHandle = HINST;
  560. {$ENDIF MSWINDOWS}
  561. {$IFDEF LINUX}
  562. TModuleHandle = Pointer;
  563. {$ENDIF LINUX}
  564. const
  565. INVALID_MODULEHANDLE_VALUE = TModuleHandle(0);
  566. function LoadModule(var Module: TModuleHandle; FileName: string): Boolean;
  567. function LoadModuleEx(var Module: TModuleHandle; FileName: string; Flags: Cardinal): Boolean;
  568. procedure UnloadModule(var Module: TModuleHandle);
  569. function GetModuleSymbol(Module: TModuleHandle; SymbolName: string): Pointer;
  570. function GetModuleSymbolEx(Module: TModuleHandle; SymbolName: string; var Accu: Boolean): Pointer;
  571. function ReadModuleData(Module: TModuleHandle; SymbolName: string; var Buffer; Size: Cardinal): Boolean;
  572. function WriteModuleData(Module: TModuleHandle; SymbolName: string; var Buffer; Size: Cardinal): Boolean;
  573. // Conversion Utilities
  574. type
  575. EJclConversionError = class(EJclError);
  576. function StrToBoolean(const S: string): Boolean;
  577. function BooleanToStr(B: Boolean): string;
  578. function IntToBool(I: Integer): Boolean;
  579. function BoolToInt(B: Boolean): Integer;
  580. function TryStrToUInt(const Value: string; out Res: Cardinal): Boolean;
  581. function StrToUIntDef(const Value: string; const Default: Cardinal): Cardinal;
  582. function StrToUInt(const Value: string): Cardinal;
  583. {$IFNDEF WINSCP}
  584. const
  585. {$IFDEF MSWINDOWS}
  586. ListSeparator = ';';
  587. {$ENDIF MSWINDOWS}
  588. {$IFDEF LINUX}
  589. ListSeparator = ':';
  590. {$ENDIF LINUX}
  591. {$ENDIF}
  592. // functions to handle items in a separated list of items
  593. // add items at the end
  594. procedure ListAddItems(var List: string; const Separator, Items: string);
  595. // add items at the end if they are not present
  596. procedure ListIncludeItems(var List: string; const Separator, Items: string);
  597. // delete multiple items
  598. procedure ListRemoveItems(var List: string; const Separator, Items: string);
  599. // delete one item
  600. procedure ListDelItem(var List: string; const Separator: string;
  601. const Index: Integer);
  602. // return the number of item
  603. function ListItemCount(const List, Separator: string): Integer;
  604. // return the Nth item
  605. function ListGetItem(const List, Separator: string;
  606. const Index: Integer): string;
  607. // set the Nth item
  608. procedure ListSetItem(var List: string; const Separator: string;
  609. const Index: Integer; const Value: string);
  610. // return the index of an item
  611. function ListItemIndex(const List, Separator, Item: string): Integer;
  612. // RTL package information
  613. function SystemTObjectInstance: TJclAddr;
  614. function IsCompiledWithPackages: Boolean;
  615. // GUID
  616. function JclGUIDToString(const GUID: TGUID): string;
  617. function JclStringToGUID(const S: string): TGUID;
  618. function GUIDEquals(const GUID1, GUID2: TGUID): Boolean;
  619. // thread safe support
  620. type
  621. TJclIntfCriticalSection = class(TInterfacedObject, IInterface)
  622. private
  623. FCriticalSection: TCriticalSection;
  624. public
  625. constructor Create;
  626. destructor Destroy; override;
  627. { IInterface }
  628. // function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
  629. function _AddRef: Integer; stdcall;
  630. function _Release: Integer; stdcall;
  631. end;
  632. type
  633. {$IFDEF BORLAND}
  634. {$IFDEF COMPILER16_UP}
  635. TFileHandle = THandle;
  636. {$ELSE ~COMPILER16_UP}
  637. TFileHandle = Integer;
  638. {$ENDIF ~COMPILER16_UP}
  639. {$ELSE ~BORLAND}
  640. TFileHandle = THandle;
  641. {$ENDIF ~BORLAND}
  642. {$IFNDEF WINSCP}
  643. TJclSimpleLog = class (TObject)
  644. private
  645. FDateTimeFormatStr: String;
  646. FLogFileHandle: TFileHandle;
  647. FLogFileName: string;
  648. FLoggingActive: Boolean;
  649. FLogWasEmpty: Boolean;
  650. function GetLogOpen: Boolean;
  651. protected
  652. function CreateDefaultFileName: string;
  653. public
  654. constructor Create(const ALogFileName: string = '');
  655. destructor Destroy; override;
  656. procedure ClearLog;
  657. procedure CloseLog;
  658. procedure OpenLog;
  659. procedure Write(const Text: string; Indent: Integer = 0; KeepOpen: Boolean = true); overload;
  660. procedure Write(Strings: TStrings; Indent: Integer = 0; KeepOpen: Boolean = true); overload;
  661. //Writes a line to the log file. The current timestamp is written before the line.
  662. procedure TimeWrite(const Text: string; Indent: Integer = 0; KeepOpen: Boolean = true); overload;
  663. procedure TimeWrite(Strings: TStrings; Indent: Integer = 0; KeepOpen: Boolean = true); overload;
  664. procedure WriteStamp(SeparatorLen: Integer = 0; KeepOpen: Boolean = true);
  665. // DateTimeFormatStr property assumes the values described in "FormatDateTime Function" in Delphi Help
  666. property DateTimeFormatStr: String read FDateTimeFormatStr write FDateTimeFormatStr;
  667. property LogFileName: string read FLogFileName;
  668. //1 Property to activate / deactivate the logging
  669. property LoggingActive: Boolean read FLoggingActive write FLoggingActive default True;
  670. property LogOpen: Boolean read GetLogOpen;
  671. end;
  672. {$ENDIF ~WINSCP}
  673. type
  674. TJclFormatSettings = class
  675. private
  676. function GetCurrencyDecimals: Byte; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  677. function GetCurrencyFormat: Byte; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  678. function GetCurrencyString: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  679. function GetDateSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  680. function GetDayNamesHighIndex: Integer; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  681. function GetDayNamesLowIndex: Integer; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  682. function GetDecimalSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  683. function GetListSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  684. function GetLongDateFormat: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  685. function GetLongDayNames(AIndex: Integer): string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  686. function GetLongMonthNames(AIndex: Integer): string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  687. function GetLongTimeFormat: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  688. function GetMonthNamesHighIndex: Integer; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  689. function GetMonthNamesLowIndex: Integer; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  690. function GetNegCurrFormat: Byte; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  691. function GetShortDateFormat: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  692. function GetShortDayNames(AIndex: Integer): string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  693. function GetShortMonthNames(AIndex: Integer): string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  694. function GetShortTimeFormat: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  695. function GetThousandSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  696. function GetTimeAMString: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  697. function GetTimePMString: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  698. function GetTimeSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  699. function GetTwoDigitYearCenturyWindow: Word; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  700. procedure SetCurrencyDecimals(AValue: Byte); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  701. procedure SetCurrencyFormat(const AValue: Byte); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  702. procedure SetCurrencyString(AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  703. procedure SetDateSeparator(const AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  704. procedure SetDecimalSeparator(AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  705. procedure SetListSeparator(const AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  706. procedure SetLongDateFormat(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  707. procedure SetLongTimeFormat(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  708. procedure SetNegCurrFormat(const AValue: Byte); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  709. procedure SetShortDateFormat(AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  710. procedure SetShortTimeFormat(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  711. procedure SetThousandSeparator(AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  712. procedure SetTimeAMString(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  713. procedure SetTimePMString(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  714. procedure SetTimeSeparator(const AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  715. procedure SetTwoDigitYearCenturyWindow(const AValue: Word); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  716. public
  717. property CurrencyDecimals: Byte read GetCurrencyDecimals write SetCurrencyDecimals;
  718. property CurrencyFormat: Byte read GetCurrencyFormat write SetCurrencyFormat;
  719. property CurrencyString: string read GetCurrencyString write SetCurrencyString;
  720. property DateSeparator: Char read GetDateSeparator write SetDateSeparator;
  721. property DayNamesHighIndex: Integer read GetDayNamesHighIndex;
  722. property DayNamesLowIndex: Integer read GetDayNamesLowIndex;
  723. property DecimalSeparator: Char read GetDecimalSeparator write SetDecimalSeparator;
  724. property ListSeparator: Char read GetListSeparator write SetListSeparator;
  725. property LongDateFormat: string read GetLongDateFormat write SetLongDateFormat;
  726. property LongDayNames[AIndex: Integer]: string read GetLongDayNames;
  727. property LongMonthNames[AIndex: Integer]: string read GetLongMonthNames;
  728. property LongTimeFormat: string read GetLongTimeFormat write SetLongTimeFormat;
  729. property MonthNamesHighIndex: Integer read GetMonthNamesHighIndex;
  730. property MonthNamesLowIndex: Integer read GetMonthNamesLowIndex;
  731. property NegCurrFormat: Byte read GetNegCurrFormat write SetNegCurrFormat;
  732. property ShortDateFormat: string read GetShortDateFormat write SetShortDateFormat;
  733. property ShortDayNames[AIndex: Integer]: string read GetShortDayNames;
  734. property ShortMonthNames[AIndex: Integer]: string read GetShortMonthNames;
  735. property ShortTimeFormat: string read GetShortTimeFormat write SetShortTimeFormat;
  736. property ThousandSeparator: Char read GetThousandSeparator write SetThousandSeparator;
  737. property TimeAMString: string read GetTimeAMString write SetTimeAMString;
  738. property TimePMString: string read GetTimePMString write SetTimePMString;
  739. property TimeSeparator: Char read GetTimeSeparator write SetTimeSeparator;
  740. property TwoDigitYearCenturyWindow: Word read GetTwoDigitYearCenturyWindow write SetTwoDigitYearCenturyWindow;
  741. end;
  742. var
  743. JclFormatSettings: TJclFormatSettings;
  744. {$IFNDEF WINSCP}
  745. // Procedure to initialize the SimpleLog Variable
  746. procedure InitSimpleLog(const ALogFileName: string = ''; AOpenLog: Boolean = true);
  747. // Global Variable to make it easier for an application wide log handling.
  748. // Must be initialized with InitSimpleLog before using
  749. var
  750. SimpleLog : TJclSimpleLog;
  751. {$ENDIF ~WINSCP}
  752. // Validates if then variant value is null or is empty
  753. function VarIsNullEmpty(const V: Variant): Boolean;
  754. // Validates if then variant value is null or is empty or VarToStr is a blank string
  755. function VarIsNullEmptyBlank(const V: Variant): Boolean;
  756. {$IFDEF UNITVERSIONING}
  757. const
  758. UnitVersioning: TUnitVersionInfo = (
  759. RCSfile: '$URL$';
  760. Revision: '$Revision$';
  761. Date: '$Date$';
  762. LogPath: 'JCL\source\common';
  763. Extra: '';
  764. Data: nil
  765. );
  766. {$ENDIF UNITVERSIONING}
  767. implementation
  768. uses
  769. {$IFDEF HAS_UNIT_LIBC}
  770. Libc,
  771. {$ENDIF HAS_UNIT_LIBC}
  772. {$IFDEF MSWINDOWS}
  773. {$IFNDEF WINSCP}
  774. JclConsole,
  775. {$ENDIF ~WINSCP}
  776. {$ENDIF MSWINDOWS}
  777. {$IFDEF HAS_UNITSCOPE}
  778. System.Variants, System.Types, System.Contnrs,
  779. {$IFDEF HAS_UNIT_ANSISTRINGS}
  780. System.AnsiStrings,
  781. {$ENDIF HAS_UNIT_ANSISTRINGS}
  782. {$ELSE ~HAS_UNITSCOPE}
  783. Variants, Types, Contnrs,
  784. {$IFDEF HAS_UNIT_ANSISTRINGS}
  785. AnsiStrings,
  786. {$ENDIF HAS_UNIT_ANSISTRINGS}
  787. {$ENDIF ~HAS_UNITSCOPE}
  788. JclFileUtils, {$IFNDEF WINSCP}JclMath,{$ENDIF ~WINSCP} JclResources, JclStrings,
  789. {$IFNDEF WINSCP}JclStringConversions,{$ENDIF ~WINSCP} JclSysInfo, JclWin32;
  790. // memory initialization
  791. procedure ResetMemory(out P; Size: Longint);
  792. begin
  793. if Size > 0 then
  794. begin
  795. Byte(P) := 0;
  796. FillChar(P, Size, 0);
  797. end;
  798. end;
  799. // Pointer manipulation
  800. procedure GetAndFillMem(var P: Pointer; const Size: Integer; const Value: Byte);
  801. begin
  802. GetMem(P, Size);
  803. FillChar(P^, Size, Value);
  804. end;
  805. procedure FreeMemAndNil(var P: Pointer);
  806. var
  807. Q: Pointer;
  808. begin
  809. Q := P;
  810. P := nil;
  811. FreeMem(Q);
  812. end;
  813. function PCharOrNil(const S: string): PChar;
  814. begin
  815. Result := Pointer(S);
  816. end;
  817. function PAnsiCharOrNil(const S: AnsiString): PAnsiChar;
  818. begin
  819. Result := Pointer(S);
  820. end;
  821. {$IFDEF SUPPORTS_WIDESTRING}
  822. function PWideCharOrNil(const W: WideString): PWideChar;
  823. begin
  824. Result := Pointer(W);
  825. end;
  826. {$ENDIF SUPPORTS_WIDESTRING}
  827. {$IFDEF MSWINDOWS}
  828. type
  829. PUsed = ^TUsed;
  830. TUsed = record
  831. SizeFlags: Integer;
  832. end;
  833. const
  834. cThisUsedFlag = 2;
  835. cPrevFreeFlag = 1;
  836. cFillerFlag = Integer($80000000);
  837. cFlags = cThisUsedFlag or cPrevFreeFlag or cFillerFlag;
  838. function SizeOfMem(const APointer: Pointer): Integer;
  839. var
  840. U: PUsed;
  841. begin
  842. if IsMemoryManagerSet then
  843. Result:= -1
  844. else
  845. begin
  846. Result := 0;
  847. if APointer <> nil then
  848. begin
  849. U := APointer;
  850. U := PUsed(TJclAddr(U) - SizeOf(TUsed));
  851. if (U.SizeFlags and cThisUsedFlag) <> 0 then
  852. Result := (U.SizeFlags) and (not cFlags - SizeOf(TUsed));
  853. end;
  854. end;
  855. end;
  856. {$ENDIF MSWINDOWS}
  857. {$IFDEF LINUX}
  858. function SizeOfMem(const APointer: Pointer): Integer;
  859. begin
  860. if IsMemoryManagerSet then
  861. Result:= -1
  862. else
  863. begin
  864. if APointer <> nil then
  865. Result := malloc_usable_size(APointer)
  866. else
  867. Result := 0;
  868. end;
  869. end;
  870. {$ENDIF LINUX}
  871. function WriteProtectedMemory(BaseAddress, Buffer: Pointer;
  872. Size: Cardinal; out WrittenBytes: Cardinal): Boolean;
  873. {$IFDEF MSWINDOWS}
  874. var
  875. OldProtect, Dummy: Cardinal;
  876. begin
  877. WrittenBytes := 0;
  878. if Size > 0 then
  879. begin
  880. // (outchy) VirtualProtect for DEP issues
  881. OldProtect := 0;
  882. Result := VirtualProtect(BaseAddress, Size, PAGE_EXECUTE_READWRITE, OldProtect);
  883. if Result then
  884. try
  885. Move(Buffer^, BaseAddress^, Size);
  886. WrittenBytes := Size;
  887. if OldProtect in [PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY] then
  888. FlushInstructionCache(GetCurrentProcess, BaseAddress, Size);
  889. finally
  890. Dummy := 0;
  891. VirtualProtect(BaseAddress, Size, OldProtect, Dummy);
  892. end;
  893. end;
  894. Result := WrittenBytes = Size;
  895. end;
  896. {$ENDIF MSWINDOWS}
  897. {$IFDEF LINUX}
  898. { TODO -cHelp : Author: Andreas Hausladen }
  899. { TODO : Works so far, but causes app to hang on termination }
  900. var
  901. AlignedAddress: Cardinal;
  902. PageSize, ProtectSize: Cardinal;
  903. begin
  904. Result := False;
  905. WrittenBytes := 0;
  906. PageSize := Cardinal(getpagesize);
  907. AlignedAddress := Cardinal(BaseAddress) and not (PageSize - 1); // start memory page
  908. // get the number of needed memory pages
  909. ProtectSize := PageSize;
  910. while Cardinal(BaseAddress) + Size > AlignedAddress + ProtectSize do
  911. Inc(ProtectSize, PageSize);
  912. if mprotect(Pointer(AlignedAddress), ProtectSize,
  913. PROT_READ or PROT_WRITE or PROT_EXEC) = 0 then // obtain write access
  914. begin
  915. try
  916. Move(Buffer^, BaseAddress^, Size); // replace code
  917. Result := True;
  918. WrittenBytes := Size;
  919. finally
  920. // Is there any function that returns the current page protection?
  921. // mprotect(p, ProtectSize, PROT_READ or PROT_EXEC); // lock memory page
  922. end;
  923. end;
  924. end;
  925. procedure FlushInstructionCache;
  926. { TODO -cHelp : Author: Andreas Hausladen }
  927. begin
  928. // do nothing
  929. end;
  930. {$ENDIF LINUX}
  931. // Guards
  932. //=== { TJclSafeGuard } ======================================================
  933. constructor TJclSafeGuard.Create(Mem: Pointer);
  934. begin
  935. inherited Create;
  936. FItem := Mem;
  937. end;
  938. destructor TJclSafeGuard.Destroy;
  939. begin
  940. FreeItem;
  941. inherited Destroy;
  942. end;
  943. function TJclSafeGuard.ReleaseItem: Pointer;
  944. begin
  945. Result := FItem;
  946. FItem := nil;
  947. end;
  948. function TJclSafeGuard.GetItem: Pointer;
  949. begin
  950. Result := FItem;
  951. end;
  952. procedure TJclSafeGuard.FreeItem;
  953. begin
  954. if FItem <> nil then
  955. FreeMem(FItem);
  956. FItem := nil;
  957. end;
  958. //=== { TJclObjSafeGuard } ===================================================
  959. constructor TJclObjSafeGuard.Create(Obj: TObject);
  960. begin
  961. inherited Create(Pointer(Obj));
  962. end;
  963. procedure TJclObjSafeGuard.FreeItem;
  964. begin
  965. if FItem <> nil then
  966. begin
  967. TObject(FItem).Free;
  968. FItem := nil;
  969. end;
  970. end;
  971. //=== { TJclMultiSafeGuard } =================================================
  972. constructor TJclMultiSafeGuard.Create;
  973. begin
  974. inherited Create;
  975. FItems := TList.Create;
  976. end;
  977. destructor TJclMultiSafeGuard.Destroy;
  978. var
  979. I: Integer;
  980. begin
  981. for I := FItems.Count - 1 downto 0 do
  982. FreeItem(I);
  983. FItems.Free;
  984. inherited Destroy;
  985. end;
  986. function TJclMultiSafeGuard.AddItem(Item: Pointer): Pointer;
  987. begin
  988. Result := Item;
  989. FItems.Add(Item);
  990. end;
  991. procedure TJclMultiSafeGuard.FreeItem(Index: Integer);
  992. begin
  993. FreeMem(FItems[Index]);
  994. FItems.Delete(Index);
  995. end;
  996. function TJclMultiSafeGuard.GetCount: Integer;
  997. begin
  998. Result := FItems.Count;
  999. end;
  1000. function TJclMultiSafeGuard.GetItem(Index: Integer): Pointer;
  1001. begin
  1002. Result := FItems[Index];
  1003. end;
  1004. function TJclMultiSafeGuard.ReleaseItem(Index: Integer): Pointer;
  1005. begin
  1006. Result := FItems[Index];
  1007. FItems.Delete(Index);
  1008. end;
  1009. function Guard(Mem: Pointer; var SafeGuard: IMultiSafeGuard): Pointer; overload;
  1010. begin
  1011. if SafeGuard = nil then
  1012. SafeGuard := TJclMultiSafeGuard.Create;
  1013. Result := SafeGuard.AddItem(Mem);
  1014. end;
  1015. //=== { TJclObjMultiSafeGuard } ==============================================
  1016. procedure TJclObjMultiSafeGuard.FreeItem(Index: Integer);
  1017. begin
  1018. TObject(FItems[Index]).Free;
  1019. FItems.Delete(Index);
  1020. end;
  1021. function Guard(Obj: TObject; var SafeGuard: IMultiSafeGuard): TObject; overload;
  1022. begin
  1023. if SafeGuard = nil then
  1024. SafeGuard := TJclObjMultiSafeGuard.Create;
  1025. Result := SafeGuard.AddItem(Obj);
  1026. end;
  1027. function Guard(Mem: Pointer; out SafeGuard: ISafeGuard): Pointer; overload;
  1028. begin
  1029. Result := Mem;
  1030. SafeGuard := TJclSafeGuard.Create(Mem);
  1031. end;
  1032. function Guard(Obj: TObject; out SafeGuard: ISafeGuard): TObject; overload;
  1033. begin
  1034. Result := Obj;
  1035. SafeGuard := TJclObjSafeGuard.Create(Obj);
  1036. end;
  1037. function GuardGetMem(Size: Cardinal; out SafeGuard: ISafeGuard): Pointer;
  1038. begin
  1039. GetMem(Result, Size);
  1040. Guard(Result, SafeGuard);
  1041. end;
  1042. function GuardAllocMem(Size: Cardinal; out SafeGuard: ISafeGuard): Pointer;
  1043. begin
  1044. Result := AllocMem(Size);
  1045. Guard(Result, SafeGuard);
  1046. end;
  1047. {$IFDEF SUPPORTS_GENERICS_}
  1048. //=== { TSafeGuard<T> } ======================================================
  1049. constructor TSafeGuard<T>.Create(Instance: T);
  1050. begin
  1051. inherited Create;
  1052. FItem := Instance;
  1053. end;
  1054. destructor TSafeGuard<T>.Destroy;
  1055. begin
  1056. FreeItem;
  1057. inherited Destroy;
  1058. end;
  1059. function TSafeGuard<T>.ReleaseItem: T;
  1060. begin
  1061. Result := FItem;
  1062. FItem := nil;
  1063. end;
  1064. function TSafeGuard<T>.GetItem: T;
  1065. begin
  1066. Result := FItem;
  1067. end;
  1068. procedure TSafeGuard<T>.FreeItem;
  1069. begin
  1070. if FItem <> nil then
  1071. FItem.Free;
  1072. FItem := nil;
  1073. end;
  1074. {$ENDIF SUPPORTS_GENERICS_}
  1075. //=== Shared memory functions ================================================
  1076. type
  1077. PMMFHandleListItem = ^TMMFHandleListItem;
  1078. TMMFHandleListItem = record
  1079. Next: PMMFHandleListItem;
  1080. Memory: Pointer;
  1081. Handle: THandle;
  1082. Name: string;
  1083. References: Integer;
  1084. end;
  1085. PMMFHandleList = PMMFHandleListItem;
  1086. var
  1087. MMFHandleList: PMMFHandleList = nil;
  1088. {$IFDEF THREADSAFE}
  1089. MMFFinalized: Boolean = False;
  1090. GlobalMMFHandleListCS: TJclIntfCriticalSection = nil;
  1091. {$ENDIF THREADSAFE}
  1092. {$IFDEF THREADSAFE}
  1093. function GetAccessToHandleList: IInterface;
  1094. var
  1095. OldValue: Pointer;
  1096. CS: TJclIntfCriticalSection;
  1097. begin
  1098. if not Assigned(GlobalMMFHandleListCS) and not MMFFinalized then
  1099. begin
  1100. CS := TJclIntfCriticalSection.Create;
  1101. {$IFDEF RTL200_UP} // Delphi 2009+
  1102. OldValue := InterlockedCompareExchangePointer(Pointer(GlobalMMFHandleListCS), Pointer(CS), nil);
  1103. {$ELSE}
  1104. {$IFDEF RTL160_UP} // Delphi 7-2007
  1105. OldValue := Pointer(InterlockedCompareExchange(Longint(GlobalMMFHandleListCS), Longint(CS), 0));
  1106. {$ELSE} // Delphi 5, 6
  1107. OldValue := InterlockedCompareExchange(Pointer(GlobalMMFHandleListCS), Pointer(CS), nil);
  1108. {$ENDIF RTL180_UP}
  1109. {$ENDIF RTL185_UP}
  1110. if OldValue <> nil then
  1111. CS.Free;
  1112. end;
  1113. Result := GlobalMMFHandleListCS;
  1114. end;
  1115. {$ENDIF THREADSAFE}
  1116. {$IFDEF MSWINDOWS}
  1117. function SharedGetMem(var P{: Pointer}; const Name: string; Size: Cardinal;
  1118. DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Integer;
  1119. var
  1120. FileMappingHandle: THandle;
  1121. Iterate, NewListItem: PMMFHandleListItem;
  1122. Protect: Cardinal;
  1123. {$IFDEF THREADSAFE}
  1124. HandleListAccess: IInterface;
  1125. {$ENDIF THREADSAFE}
  1126. begin
  1127. Result := 0;
  1128. Pointer(P) := nil;
  1129. if not JclCheckWinVersion(5, 0) and ((Name = '') or (Pos('\', Name) > 0)) then
  1130. raise ESharedMemError.CreateResFmt(@RsInvalidMMFName, [Name]);
  1131. {$IFDEF THREADSAFE}
  1132. HandleListAccess := GetAccessToHandleList;
  1133. {$ENDIF THREADSAFE}
  1134. // search for same name
  1135. Iterate := MMFHandleList;
  1136. while Iterate <> nil do
  1137. begin
  1138. if CompareText(Iterate^.Name, Name) = 0 then
  1139. begin
  1140. Inc(Iterate^.References);
  1141. Pointer(P) := Iterate^.Memory;
  1142. Result := ERROR_ALREADY_EXISTS;
  1143. Exit;
  1144. end;
  1145. Iterate := Iterate^.Next;
  1146. end;
  1147. // open file mapping
  1148. FileMappingHandle := OpenFileMapping(DesiredAccess, False, PChar(Name));
  1149. if FileMappingHandle = 0 then
  1150. begin
  1151. if Size = 0 then
  1152. raise ESharedMemError.CreateResFmt(@RsInvalidMMFEmpty, [Name]);
  1153. Protect := PAGE_READWRITE;
  1154. if (Win32Platform = VER_PLATFORM_WIN32_WINDOWS) and (DesiredAccess = FILE_MAP_COPY) then
  1155. Protect := PAGE_WRITECOPY;
  1156. FileMappingHandle := CreateFileMapping(INVALID_HANDLE_VALUE, nil, Protect,
  1157. 0, Size, PChar(Name));
  1158. end
  1159. else
  1160. Result := ERROR_ALREADY_EXISTS;
  1161. if GetLastError = ERROR_ALREADY_EXISTS then
  1162. Result := ERROR_ALREADY_EXISTS
  1163. else
  1164. begin
  1165. if FileMappingHandle = 0 then
  1166. RaiseLastOSError;
  1167. end;
  1168. // map view
  1169. Pointer(P) := MapViewOfFile(FileMappingHandle, DesiredAccess, 0, 0, Size);
  1170. if Pointer(P) = nil then
  1171. begin
  1172. try
  1173. RaiseLastOSError;
  1174. except
  1175. CloseHandle(FileMappingHandle);
  1176. raise;
  1177. end;
  1178. end;
  1179. // add list item to MMFHandleList
  1180. New(NewListItem);
  1181. NewListItem^.Name := Name;
  1182. NewListItem^.Handle := FileMappingHandle;
  1183. NewListItem^.Memory := Pointer(P);
  1184. NewListItem^.References := 1;
  1185. NewListItem^.Next := MMFHandleList;
  1186. MMFHandleList := NewListItem;
  1187. end;
  1188. function SharedAllocMem(const Name: string; Size: Cardinal;
  1189. DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Pointer;
  1190. begin
  1191. Result := nil;
  1192. if (SharedGetMem(Result, Name, Size, DesiredAccess) <> ERROR_ALREADY_EXISTS) and
  1193. ((DesiredAccess and (FILE_MAP_WRITE or FILE_MAP_COPY)) <> 0) and
  1194. (Size > 0) and (Result <> nil) then
  1195. ResetMemory(Pointer(Result)^, Size);
  1196. end;
  1197. function SharedFreeMem(var P{: Pointer}): Boolean;
  1198. var
  1199. N, Iterate: PMMFHandleListItem;
  1200. {$IFDEF THREADSAFE}
  1201. HandleListAccess: IInterface;
  1202. {$ENDIF THREADSAFE}
  1203. begin
  1204. if Pointer(P) <> nil then
  1205. begin
  1206. Result := False;
  1207. {$IFDEF THREADSAFE}
  1208. HandleListAccess := GetAccessToHandleList;
  1209. {$ENDIF THREADSAFE}
  1210. Iterate := MMFHandleList;
  1211. N := nil;
  1212. while Iterate <> nil do
  1213. begin
  1214. if Iterate^.Memory = Pointer(P) then
  1215. begin
  1216. if Iterate^.References > 1 then
  1217. begin
  1218. Dec(Iterate^.References);
  1219. Pointer(P) := nil;
  1220. Result := True;
  1221. Exit;
  1222. end;
  1223. UnmapViewOfFile(Iterate^.Memory);
  1224. CloseHandle(Iterate^.Handle);
  1225. if N = nil then
  1226. MMFHandleList := Iterate^.Next
  1227. else
  1228. N^.Next := Iterate^.Next;
  1229. Dispose(Iterate);
  1230. Pointer(P) := nil;
  1231. Result := True;
  1232. Break;
  1233. end;
  1234. N := Iterate;
  1235. Iterate := Iterate^.Next;
  1236. end;
  1237. end
  1238. else
  1239. Result := True;
  1240. end;
  1241. function SharedOpenMem(var P{: Pointer}; const Name: string;
  1242. DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Boolean;
  1243. begin
  1244. Result := SharedGetMem(P, Name, 0, DesiredAccess) = ERROR_ALREADY_EXISTS;
  1245. end;
  1246. function SharedOpenMem(const Name: string;
  1247. DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Pointer;
  1248. begin
  1249. Result := nil;
  1250. SharedGetMem(Result, Name, 0, DesiredAccess);
  1251. end;
  1252. function SharedCloseMem(var P{: Pointer}): Boolean;
  1253. begin
  1254. Result := SharedFreeMem(P);
  1255. end;
  1256. {$ENDIF MSWINDOWS}
  1257. //=== Binary search ==========================================================
  1258. function SearchSortedList(List: TList; SortFunc: TListSortCompare; Item: Pointer; Nearest: Boolean): Integer;
  1259. var
  1260. L, H, I, C: Integer;
  1261. B: Boolean;
  1262. begin
  1263. Result := -1;
  1264. if List <> nil then
  1265. begin
  1266. L := 0;
  1267. H := List.Count - 1;
  1268. B := False;
  1269. while L <= H do
  1270. begin
  1271. I := (L + H) shr 1;
  1272. C := SortFunc(List.List{$IFNDEF RTL230_UP}^{$ENDIF !RTL230_UP}[I], Item);
  1273. if C < 0 then
  1274. L := I + 1
  1275. else
  1276. begin
  1277. H := I - 1;
  1278. if C = 0 then
  1279. begin
  1280. B := True;
  1281. L := I;
  1282. end;
  1283. end;
  1284. end;
  1285. if B then
  1286. Result := L
  1287. else
  1288. if Nearest and (H >= 0) then
  1289. Result := H;
  1290. end;
  1291. end;
  1292. function SearchSortedUntyped(Param: Pointer; ItemCount: Integer; SearchFunc: TUntypedSearchCompare;
  1293. const Value; Nearest: Boolean): Integer;
  1294. var
  1295. L, H, I, C: Integer;
  1296. B: Boolean;
  1297. begin
  1298. Result := -1;
  1299. if ItemCount > 0 then
  1300. begin
  1301. L := 0;
  1302. H := ItemCount - 1;
  1303. B := False;
  1304. while L <= H do
  1305. begin
  1306. I := (L + H) shr 1;
  1307. C := SearchFunc(Param, I, Value);
  1308. if C < 0 then
  1309. L := I + 1
  1310. else
  1311. begin
  1312. H := I - 1;
  1313. if C = 0 then
  1314. begin
  1315. B := True;
  1316. L := I;
  1317. end;
  1318. end;
  1319. end;
  1320. if B then
  1321. Result := L
  1322. else
  1323. if Nearest and (H >= 0) then
  1324. Result := H;
  1325. end;
  1326. end;
  1327. //=== Dynamic array sort and search routines =================================
  1328. procedure SortDynArray(const ArrayPtr: Pointer; ElementSize: Cardinal; SortFunc: TDynArraySortCompare);
  1329. var
  1330. TempBuf: TDynByteArray;
  1331. procedure QuickSort(L, R: SizeInt);
  1332. var
  1333. I, J, T: SizeInt;
  1334. P, IPtr, JPtr: Pointer;
  1335. ElSize: Integer;
  1336. begin
  1337. ElSize := ElementSize;
  1338. repeat
  1339. I := L;
  1340. J := R;
  1341. P := Pointer(TJclAddr(ArrayPtr) + TJclAddr(((L + R) shr 1) * SizeInt(ElementSize)));
  1342. repeat
  1343. IPtr := Pointer(TJclAddr(ArrayPtr) + TJclAddr(I * SizeInt(ElementSize)));
  1344. JPtr := Pointer(TJclAddr(ArrayPtr) + TJclAddr(J * SizeInt(ElementSize)));
  1345. while SortFunc(IPtr, P) < 0 do
  1346. begin
  1347. Inc(I);
  1348. Inc(PByte(IPtr), ElSize);
  1349. end;
  1350. while SortFunc(JPtr, P) > 0 do
  1351. begin
  1352. Dec(J);
  1353. Dec(PByte(JPtr), ElSize);
  1354. end;
  1355. if I <= J then
  1356. begin
  1357. if I <> J then
  1358. begin
  1359. case ElementSize of
  1360. SizeOf(Byte):
  1361. begin
  1362. T := PByte(IPtr)^;
  1363. PByte(IPtr)^ := PByte(JPtr)^;
  1364. PByte(JPtr)^ := T;
  1365. end;
  1366. SizeOf(Word):
  1367. begin
  1368. T := PWord(IPtr)^;
  1369. PWord(IPtr)^ := PWord(JPtr)^;
  1370. PWord(JPtr)^ := T;
  1371. end;
  1372. SizeOf(Integer):
  1373. begin
  1374. T := PInteger(IPtr)^;
  1375. PInteger(IPtr)^ := PInteger(JPtr)^;
  1376. PInteger(JPtr)^ := T;
  1377. end;
  1378. else
  1379. Move(IPtr^, TempBuf[0], ElementSize);
  1380. Move(JPtr^, IPtr^, ElementSize);
  1381. Move(TempBuf[0], JPtr^, ElementSize);
  1382. end;
  1383. end;
  1384. if P = IPtr then
  1385. P := JPtr
  1386. else
  1387. if P = JPtr then
  1388. P := IPtr;
  1389. Inc(I);
  1390. Dec(J);
  1391. end;
  1392. until I > J;
  1393. if L < J then
  1394. QuickSort(L, J);
  1395. L := I;
  1396. until I >= R;
  1397. end;
  1398. begin
  1399. if ArrayPtr <> nil then
  1400. begin
  1401. SetLength(TempBuf, ElementSize);
  1402. QuickSort(0, PSizeInt(TJclAddr(ArrayPtr) - SizeOf(SizeInt))^ - 1);
  1403. end;
  1404. end;
  1405. function SearchDynArray(const ArrayPtr: Pointer; ElementSize: Cardinal; SortFunc: TDynArraySortCompare;
  1406. ValuePtr: Pointer; Nearest: Boolean): SizeInt;
  1407. var
  1408. L, H, I, C: SizeInt;
  1409. B: Boolean;
  1410. begin
  1411. Result := -1;
  1412. if ArrayPtr <> nil then
  1413. begin
  1414. L := 0;
  1415. H := PSizeInt(TJclAddr(ArrayPtr) - SizeOf(SizeInt))^ - 1;
  1416. B := False;
  1417. while L <= H do
  1418. begin
  1419. I := (L + H) shr 1;
  1420. C := SortFunc(Pointer(TJclAddr(ArrayPtr) + TJclAddr(I * SizeInt(ElementSize))), ValuePtr);
  1421. if C < 0 then
  1422. L := I + 1
  1423. else
  1424. begin
  1425. H := I - 1;
  1426. if C = 0 then
  1427. begin
  1428. B := True;
  1429. L := I;
  1430. end;
  1431. end;
  1432. end;
  1433. if B then
  1434. Result := L
  1435. else
  1436. if Nearest and (H >= 0) then
  1437. Result := H;
  1438. end;
  1439. end;
  1440. { Various compare functions for basic types }
  1441. function DynArrayCompareByte(Item1, Item2: Pointer): Integer;
  1442. begin
  1443. Result := PByte(Item1)^ - PByte(Item2)^;
  1444. end;
  1445. function DynArrayCompareShortInt(Item1, Item2: Pointer): Integer;
  1446. begin
  1447. Result := PShortInt(Item1)^ - PShortInt(Item2)^;
  1448. end;
  1449. function DynArrayCompareWord(Item1, Item2: Pointer): Integer;
  1450. begin
  1451. Result := PWord(Item1)^ - PWord(Item2)^;
  1452. end;
  1453. function DynArrayCompareSmallInt(Item1, Item2: Pointer): Integer;
  1454. begin
  1455. Result := PSmallInt(Item1)^ - PSmallInt(Item2)^;
  1456. end;
  1457. function DynArrayCompareInteger(Item1, Item2: Pointer): Integer;
  1458. begin
  1459. if PInteger(Item1)^ < PInteger(Item2)^ then
  1460. Result := -1
  1461. else
  1462. if PInteger(Item1)^ > PInteger(Item2)^ then
  1463. Result := 1
  1464. else
  1465. Result := 0;
  1466. end;
  1467. function DynArrayCompareCardinal(Item1, Item2: Pointer): Integer;
  1468. begin
  1469. if PCardinal(Item1)^ < PCardinal(Item2)^ then
  1470. Result := -1
  1471. else
  1472. if PCardinal(Item1)^ > PCardinal(Item2)^ then
  1473. Result := 1
  1474. else
  1475. Result := 0;
  1476. end;
  1477. function DynArrayCompareInt64(Item1, Item2: Pointer): Integer;
  1478. begin
  1479. if PInt64(Item1)^ < PInt64(Item2)^ then
  1480. Result := -1
  1481. else
  1482. if PInt64(Item1)^ > PInt64(Item2)^ then
  1483. Result := 1
  1484. else
  1485. Result := 0;
  1486. end;
  1487. function DynArrayCompareSingle(Item1, Item2: Pointer): Integer;
  1488. begin
  1489. if PSingle(Item1)^ < PSingle(Item2)^ then
  1490. Result := -1
  1491. else
  1492. if PSingle(Item1)^ > PSingle(Item2)^ then
  1493. Result := 1
  1494. else
  1495. Result := 0;
  1496. end;
  1497. function DynArrayCompareDouble(Item1, Item2: Pointer): Integer;
  1498. begin
  1499. if PDouble(Item1)^ < PDouble(Item2)^ then
  1500. Result := -1
  1501. else
  1502. if PDouble(Item1)^ > PDouble(Item2)^ then
  1503. Result := 1
  1504. else
  1505. Result := 0;
  1506. end;
  1507. function DynArrayCompareExtended(Item1, Item2: Pointer): Integer;
  1508. begin
  1509. if PExtended(Item1)^ < PExtended(Item2)^ then
  1510. Result := -1
  1511. else
  1512. if PExtended(Item1)^ > PExtended(Item2)^ then
  1513. Result := 1
  1514. else
  1515. Result := 0;
  1516. end;
  1517. function DynArrayCompareFloat(Item1, Item2: Pointer): Integer;
  1518. begin
  1519. if PFloat(Item1)^ < PFloat(Item2)^ then
  1520. Result := -1
  1521. else
  1522. if PFloat(Item1)^ > PFloat(Item2)^ then
  1523. Result := 1
  1524. else
  1525. Result := 0;
  1526. end;
  1527. function DynArrayCompareAnsiString(Item1, Item2: Pointer): Integer;
  1528. begin
  1529. Result := AnsiCompareStr(PAnsiString(Item1)^, PAnsiString(Item2)^);
  1530. end;
  1531. function DynArrayCompareAnsiText(Item1, Item2: Pointer): Integer;
  1532. begin
  1533. Result := AnsiCompareText(PAnsiString(Item1)^, PAnsiString(Item2)^);
  1534. end;
  1535. function DynArrayCompareWideString(Item1, Item2: Pointer): Integer;
  1536. begin
  1537. Result := WideCompareStr(PWideString(Item1)^, PWideString(Item2)^);
  1538. end;
  1539. function DynArrayCompareWideText(Item1, Item2: Pointer): Integer;
  1540. begin
  1541. Result := WideCompareText(PWideString(Item1)^, PWideString(Item2)^);
  1542. end;
  1543. function DynArrayCompareString(Item1, Item2: Pointer): Integer;
  1544. begin
  1545. Result := CompareStr(PString(Item1)^, PString(Item2)^);
  1546. end;
  1547. function DynArrayCompareText(Item1, Item2: Pointer): Integer;
  1548. begin
  1549. Result := CompareText(PString(Item1)^, PString(Item2)^);
  1550. end;
  1551. //=== Object lists ===========================================================
  1552. procedure ClearObjectList(List: TList);
  1553. var
  1554. I: Integer;
  1555. begin
  1556. if List <> nil then
  1557. begin
  1558. for I := List.Count - 1 downto 0 do
  1559. begin
  1560. if List[I] <> nil then
  1561. begin
  1562. if TObject(List[I]) is TList then
  1563. begin
  1564. // recursively delete TList sublists
  1565. ClearObjectList(TList(List[I]));
  1566. end;
  1567. TObject(List[I]).Free;
  1568. if (not (List is TComponentList))
  1569. and ((not(List is TObjectList)) or not TObjectList(List).OwnsObjects) then
  1570. List[I] := nil;
  1571. end;
  1572. end;
  1573. List.Clear;
  1574. end;
  1575. end;
  1576. procedure FreeObjectList(var List: TList);
  1577. begin
  1578. if List <> nil then
  1579. begin
  1580. ClearObjectList(List);
  1581. FreeAndNil(List);
  1582. end;
  1583. end;
  1584. //=== { TJclReferenceMemoryStream } ==========================================
  1585. constructor TJclReferenceMemoryStream.Create(const Ptr: Pointer; Size: Longint);
  1586. begin
  1587. {$IFDEF MSWINDOWS}
  1588. Assert(not IsBadReadPtr(Ptr, Size));
  1589. {$ENDIF MSWINDOWS}
  1590. inherited Create;
  1591. SetPointer(Ptr, Size);
  1592. end;
  1593. function TJclReferenceMemoryStream.Write(const Buffer; Count: Longint): Longint;
  1594. begin
  1595. raise EJclError.CreateRes(@RsCannotWriteRefStream);
  1596. end;
  1597. //=== { TJclAutoPtr } ========================================================
  1598. constructor TJclAutoPtr.Create(AValue: TObject);
  1599. begin
  1600. inherited Create;
  1601. FValue := AValue;
  1602. end;
  1603. destructor TJclAutoPtr.Destroy;
  1604. begin
  1605. FValue.Free;
  1606. inherited Destroy;
  1607. end;
  1608. function TJclAutoPtr.AsObject: TObject;
  1609. begin
  1610. Result := FValue;
  1611. end;
  1612. function TJclAutoPtr.AsPointer: Pointer;
  1613. begin
  1614. Result := FValue;
  1615. end;
  1616. function TJclAutoPtr.ReleaseObject: TObject;
  1617. begin
  1618. Result := FValue;
  1619. FValue := nil;
  1620. end;
  1621. function CreateAutoPtr(Value: TObject): IAutoPtr;
  1622. begin
  1623. Result := TJclAutoPtr.Create(Value);
  1624. end;
  1625. //=== replacement for the C distfix operator ? : =============================
  1626. function Iff(const Condition: Boolean; const TruePart, FalsePart: string): string;
  1627. begin
  1628. if Condition then
  1629. Result := TruePart
  1630. else
  1631. Result := FalsePart;
  1632. end;
  1633. function Iff(const Condition: Boolean; const TruePart, FalsePart: Char): Char;
  1634. begin
  1635. if Condition then
  1636. Result := TruePart
  1637. else
  1638. Result := FalsePart;
  1639. end;
  1640. function Iff(const Condition: Boolean; const TruePart, FalsePart: Byte): Byte;
  1641. begin
  1642. if Condition then
  1643. Result := TruePart
  1644. else
  1645. Result := FalsePart;
  1646. end;
  1647. function Iff(const Condition: Boolean; const TruePart, FalsePart: Integer): Integer;
  1648. begin
  1649. if Condition then
  1650. Result := TruePart
  1651. else
  1652. Result := FalsePart;
  1653. end;
  1654. function Iff(const Condition: Boolean; const TruePart, FalsePart: Cardinal): Cardinal;
  1655. begin
  1656. if Condition then
  1657. Result := TruePart
  1658. else
  1659. Result := FalsePart;
  1660. end;
  1661. function Iff(const Condition: Boolean; const TruePart, FalsePart: Float): Float;
  1662. begin
  1663. if Condition then
  1664. Result := TruePart
  1665. else
  1666. Result := FalsePart;
  1667. end;
  1668. function Iff(const Condition: Boolean; const TruePart, FalsePart: Boolean): Boolean;
  1669. begin
  1670. if Condition then
  1671. Result := TruePart
  1672. else
  1673. Result := FalsePart;
  1674. end;
  1675. function Iff(const Condition: Boolean; const TruePart, FalsePart: Pointer): Pointer;
  1676. begin
  1677. if Condition then
  1678. Result := TruePart
  1679. else
  1680. Result := FalsePart;
  1681. end;
  1682. function Iff(const Condition: Boolean; const TruePart, FalsePart: Int64): Int64;
  1683. begin
  1684. if Condition then
  1685. Result := TruePart
  1686. else
  1687. Result := FalsePart;
  1688. end;
  1689. {$IFDEF SUPPORTS_VARIANT}
  1690. function Iff(const Condition: Boolean; const TruePart, FalsePart: Variant): Variant; overload;
  1691. begin
  1692. if Condition then
  1693. Result := TruePart
  1694. else
  1695. Result := FalsePart;
  1696. end;
  1697. {$ENDIF SUPPORTS_VARIANT}
  1698. //=== Classes information and manipulation ===================================
  1699. // Virtual Methods
  1700. // Helper method
  1701. procedure SetVMTPointer(AClass: TClass; Offset: Integer; Value: Pointer);
  1702. var
  1703. WrittenBytes: DWORD;
  1704. PatchAddress: PPointer;
  1705. begin
  1706. {$OVERFLOWCHECKS OFF}
  1707. PatchAddress := Pointer(TJclAddr(AClass) + TJclAddr(Offset));
  1708. {$IFDEF OVERFLOWCHECKS_ON}
  1709. {$OVERFLOWCHECKS ON}
  1710. {$ENDIF OVERFLOWCHECKS_ON}
  1711. if not WriteProtectedMemory(PatchAddress, @Value, SizeOf(Value), WrittenBytes) then
  1712. raise EJclVMTError.CreateResFmt(@RsVMTMemoryWriteError,
  1713. [SysErrorMessage({$IFDEF FPC}GetLastOSError{$ELSE}GetLastError{$ENDIF})]);
  1714. if WrittenBytes <> SizeOf(Pointer) then
  1715. raise EJclVMTError.CreateResFmt(@RsVMTMemoryWriteError, [IntToStr(WrittenBytes)]);
  1716. // make sure that everything keeps working in a dual processor setting
  1717. // (outchy) done by WriteProtectedMemory
  1718. // FlushInstructionCache{$IFDEF MSWINDOWS}(GetCurrentProcess, PatchAddress, SizeOf(Pointer)){$ENDIF};
  1719. end;
  1720. {$IFNDEF FPC}
  1721. function GetVirtualMethodCount(AClass: TClass): Integer;
  1722. type
  1723. PINT_PTR = ^INT_PTR;
  1724. var
  1725. BeginVMT: INT_PTR;
  1726. EndVMT: INT_PTR;
  1727. TablePointer: INT_PTR;
  1728. I: Integer;
  1729. begin
  1730. BeginVMT := INT_PTR(AClass);
  1731. // Scan the offset entries in the class table for the various fields,
  1732. // namely vmtIntfTable, vmtAutoTable, ..., vmtDynamicTable
  1733. // The last entry is always the vmtClassName, so stop once we got there
  1734. // After the last virtual method there is one of these entries.
  1735. EndVMT := PINT_PTR(INT_PTR(AClass) + vmtClassName)^;
  1736. // Set iterator to first item behind VMT table pointer
  1737. I := vmtSelfPtr + SizeOf(Pointer);
  1738. repeat
  1739. TablePointer := PINT_PTR(INT_PTR(AClass) + I)^;
  1740. if (TablePointer <> 0) and (TablePointer >= BeginVMT) and
  1741. (TablePointer < EndVMT) then
  1742. EndVMT := INT_PTR(TablePointer);
  1743. Inc(I, SizeOf(Pointer));
  1744. until I >= vmtClassName;
  1745. Result := (EndVMT - BeginVMT) div SizeOf(Pointer);
  1746. end;
  1747. {$ENDIF ~FPC}
  1748. function GetVirtualMethod(AClass: TClass; const Index: Integer): Pointer;
  1749. begin
  1750. {$OVERFLOWCHECKS OFF}
  1751. Result := PPointer(TJclAddr(AClass) + TJclAddr(Index * SizeOf(Pointer)))^;
  1752. {$IFDEF OVERFLOWCHECKS_ON}
  1753. {$OVERFLOWCHECKS ON}
  1754. {$ENDIF OVERFLOWCHECKS_ON}
  1755. end;
  1756. procedure SetVirtualMethod(AClass: TClass; const Index: Integer; const Method: Pointer);
  1757. begin
  1758. SetVMTPointer(AClass, Index * SizeOf(Pointer), Method);
  1759. end;
  1760. function GetDynamicMethodCount(AClass: TClass): Integer; assembler;
  1761. asm
  1762. {$IFDEF CPU32}
  1763. // --> RAX AClass
  1764. // <-- EAX Result
  1765. MOV EAX, [EAX].vmtDynamicTable
  1766. TEST EAX, EAX
  1767. JE @@Exit
  1768. MOVZX EAX, WORD PTR [EAX]
  1769. {$ENDIF CPU32}
  1770. {$IFDEF CPU64}
  1771. // --> RCX AClass
  1772. // <-- EAX Result
  1773. MOV RAX, [RCX].vmtDynamicTable
  1774. TEST RAX, RAX
  1775. JE @@Exit
  1776. MOVZX RAX, WORD PTR [RAX]
  1777. {$ENDIF CPU64}
  1778. @@Exit:
  1779. end;
  1780. function GetDynamicIndexList(AClass: TClass): PDynamicIndexList; assembler;
  1781. asm
  1782. {$IFDEF CPU32}
  1783. // --> EAX AClass
  1784. // <-- EAX Result
  1785. MOV EAX, [EAX].vmtDynamicTable
  1786. ADD EAX, 2
  1787. {$ENDIF CPU32}
  1788. {$IFDEF CPU64}
  1789. // --> RCX AClass
  1790. // <-- RAX Result
  1791. MOV RAX, [RCX].vmtDynamicTable
  1792. ADD RAX, 2
  1793. {$ENDIF CPU64}
  1794. end;
  1795. function GetDynamicAddressList(AClass: TClass): PDynamicAddressList; assembler;
  1796. asm
  1797. {$IFDEF CPU32}
  1798. // --> EAX AClass
  1799. // <-- EAX Result
  1800. MOV EAX, [EAX].vmtDynamicTable
  1801. MOVZX EDX, Word ptr [EAX]
  1802. ADD EAX, EDX
  1803. ADD EAX, EDX
  1804. ADD EAX, 2
  1805. {$ENDIF CPU32}
  1806. {$IFDEF CPU64}
  1807. // --> RCX AClass
  1808. // <-- RAX Result
  1809. MOV RAX, [RCX].vmtDynamicTable
  1810. MOVZX RDX, Word ptr [RAX]
  1811. ADD RAX, RDX
  1812. ADD RAX, RDX
  1813. ADD RAX, 2
  1814. {$ENDIF CPU64}
  1815. end;
  1816. function HasDynamicMethod(AClass: TClass; Index: Integer): Boolean; assembler;
  1817. // Mainly copied from System.GetDynaMethod
  1818. asm
  1819. {$IFDEF CPU32}
  1820. // --> EAX AClass
  1821. // EDX Index
  1822. // <-- AL Result
  1823. PUSH EDI
  1824. XCHG EAX, EDX
  1825. JMP @@HaveVMT
  1826. @@OuterLoop:
  1827. MOV EDX, [EDX]
  1828. @@HaveVMT:
  1829. MOV EDI, [EDX].vmtDynamicTable
  1830. TEST EDI, EDI
  1831. JE @@Parent
  1832. MOVZX ECX, WORD PTR [EDI]
  1833. PUSH ECX
  1834. ADD EDI,2
  1835. REPNE SCASW
  1836. JE @@Found
  1837. POP ECX
  1838. @@Parent:
  1839. MOV EDX,[EDX].vmtParent
  1840. TEST EDX,EDX
  1841. JNE @@OuterLoop
  1842. MOV EAX, 0
  1843. JMP @@Exit
  1844. @@Found:
  1845. POP EAX
  1846. MOV EAX, 1
  1847. @@Exit:
  1848. POP EDI
  1849. {$ENDIF CPU32}
  1850. {$IFDEF CPU64}
  1851. // --> RCX AClass
  1852. // EDX Index
  1853. // <-- AL Result
  1854. MOV EAX, EDX
  1855. MOV RDX, RCX
  1856. JMP @@HaveVMT
  1857. @@OuterLoop:
  1858. MOV RDX, [RDX]
  1859. @@HaveVMT:
  1860. MOV RDI, [RDX].vmtDynamicTable
  1861. TEST RDI, RDI
  1862. JE @@Parent
  1863. MOVZX RCX, WORD PTR [RDI]
  1864. PUSH RCX
  1865. ADD RDI,2
  1866. REPNE SCASW
  1867. JE @@Found
  1868. POP RCX
  1869. @@Parent:
  1870. MOV RDX,[RDX].vmtParent
  1871. TEST RDX,RDX
  1872. JNE @@OuterLoop
  1873. MOV RAX, 0
  1874. JMP @@Exit
  1875. @@Found:
  1876. POP RAX
  1877. MOV RAX, 1
  1878. @@Exit:
  1879. {$ENDIF CPU64}
  1880. end;
  1881. {$IFNDEF FPC}
  1882. function GetDynamicMethod(AClass: TClass; Index: Integer): Pointer; assembler;
  1883. asm
  1884. CALL System.@FindDynaClass
  1885. end;
  1886. {$ENDIF ~FPC}
  1887. //=== Interface Table ========================================================
  1888. function GetInitTable(AClass: TClass): PTypeInfo; assembler;
  1889. asm
  1890. {$IFDEF CPU32}
  1891. // --> EAX AClass
  1892. // <-- EAX Result
  1893. MOV EAX, [EAX].vmtInitTable
  1894. {$ENDIF CPU32}
  1895. {$IFDEF CPU64}
  1896. // --> RCX AClass
  1897. // <-- RAX Result
  1898. MOV RAX, [RCX].vmtInitTable
  1899. {$ENDIF CPU64}
  1900. end;
  1901. function GetFieldTable(AClass: TClass): PFieldTable; assembler;
  1902. asm
  1903. {$IFDEF CPU32}
  1904. // --> EAX AClass
  1905. // <-- EAX Result
  1906. MOV EAX, [EAX].vmtFieldTable
  1907. {$ENDIF CPU32}
  1908. {$IFDEF CPU64}
  1909. // --> RCX AClass
  1910. // <-- RAX Result
  1911. MOV RAX, [RCX].vmtFieldTable
  1912. {$ENDIF CPU64}
  1913. end;
  1914. function GetMethodTable(AClass: TClass): PMethodTable; assembler;
  1915. asm
  1916. {$IFDEF CPU32}
  1917. // --> EAX AClass
  1918. // <-- EAX Result
  1919. MOV EAX, [EAX].vmtMethodTable
  1920. {$ENDIF CPU32}
  1921. {$IFDEF CPU64}
  1922. // --> RCX AClass
  1923. // <-- RAX Result
  1924. MOV RAX, [RCX].vmtMethodTable
  1925. {$ENDIF CPU64}
  1926. end;
  1927. function GetMethodEntry(MethodTable: PMethodTable; Index: Integer): PMethodEntry;
  1928. begin
  1929. Result := Pointer(TJclAddr(MethodTable) + 2);
  1930. for Index := Index downto 1 do
  1931. Inc(TJclAddr(Result), Result^.EntrySize);
  1932. end;
  1933. function MethodEquals(aMethod1, aMethod2: TMethod): boolean;
  1934. begin
  1935. Result := (aMethod1.Code = aMethod2.Code) and
  1936. (aMethod1.Data = aMethod2.Data);
  1937. end;
  1938. function NotifyEventEquals(aMethod1, aMethod2: TNotifyEvent): boolean;
  1939. begin
  1940. Result := MethodEquals(TMethod(aMethod1),TMethod(aMethod2));
  1941. end;
  1942. //=== Class Parent methods ===================================================
  1943. procedure SetClassParent(AClass: TClass; NewClassParent: TClass);
  1944. var
  1945. WrittenBytes: DWORD;
  1946. PatchAddress: Pointer;
  1947. begin
  1948. {$OVERFLOWCHECKS OFF}
  1949. PatchAddress := PPointer(TJclAddr(AClass) + TJclAddr(vmtParent))^;
  1950. {$IFDEF OVERFLOWCHECKS_ON}
  1951. {$OVERFLOWCHECKS ON}
  1952. {$ENDIF OVERFLOWCHECKS_ON}
  1953. if not WriteProtectedMemory(PatchAddress, @NewClassParent, SizeOf(Pointer), WrittenBytes) then
  1954. raise EJclVMTError.CreateResFmt(@RsVMTMemoryWriteError,
  1955. [SysErrorMessage({$IFDEF FPC}GetLastOSError{$ELSE}GetLastError{$ENDIF})]);
  1956. if WrittenBytes <> SizeOf(Pointer) then
  1957. raise EJclVMTError.CreateResFmt(@RsVMTMemoryWriteError, [IntToStr(WrittenBytes)]);
  1958. // make sure that everything keeps working in a dual processor setting
  1959. // (outchy) done by WriteProtectedMemory
  1960. // FlushInstructionCache{$IFDEF MSWINDOWS}(GetCurrentProcess, PatchAddress, SizeOf(Pointer)){$ENDIF};
  1961. end;
  1962. function GetClassParent(AClass: TClass): TClass; assembler;
  1963. asm
  1964. {$IFDEF CPU32}
  1965. // --> EAX AClass
  1966. // <-- EAX Result
  1967. MOV EAX, [EAX].vmtParent
  1968. TEST EAX, EAX
  1969. JE @@Exit
  1970. MOV EAX, [EAX]
  1971. {$ENDIF CPU32}
  1972. {$IFDEF CPU64}
  1973. // --> RCX AClass
  1974. // <-- RAX Result
  1975. MOV RAX, [RCX].vmtParent
  1976. TEST RAX, RAX
  1977. JE @@Exit
  1978. MOV RAX, [RAX]
  1979. {$ENDIF CPU64}
  1980. @@Exit:
  1981. end;
  1982. {$IFDEF BORLAND}
  1983. function IsClass(Address: Pointer): Boolean; assembler;
  1984. asm
  1985. CMP Address, Address.vmtSelfPtr
  1986. JNZ @False
  1987. MOV Result, True
  1988. JMP @Exit
  1989. @False:
  1990. MOV Result, False
  1991. @Exit:
  1992. end;
  1993. {$ENDIF BORLAND}
  1994. {$IFDEF BORLAND}
  1995. function IsObject(Address: Pointer): Boolean; assembler;
  1996. asm
  1997. // or IsClass(Pointer(Address^));
  1998. MOV EAX, [Address]
  1999. CMP EAX, EAX.vmtSelfPtr
  2000. JNZ @False
  2001. MOV Result, True
  2002. JMP @Exit
  2003. @False:
  2004. MOV Result, False
  2005. @Exit:
  2006. end;
  2007. {$ENDIF BORLAND}
  2008. function InheritsFromByName(AClass: TClass; const AClassName: string): Boolean;
  2009. begin
  2010. while (AClass <> nil) and not AClass.ClassNameIs(AClassName) do
  2011. AClass := AClass.ClassParent;
  2012. Result := AClass <> nil;
  2013. end;
  2014. //=== Interface information ==================================================
  2015. function GetImplementorOfInterface(const I: IInterface): TObject;
  2016. { TODO -cDOC : Original code by Hallvard Vassbotn }
  2017. { TODO -cTesting : Check the implemetation for any further version of compiler }
  2018. const
  2019. AddByte = $04244483; // opcode for ADD DWORD PTR [ESP+4], Shortint
  2020. AddLong = $04244481; // opcode for ADD DWORD PTR [ESP+4], Longint
  2021. type
  2022. PAdjustSelfThunk = ^TAdjustSelfThunk;
  2023. TAdjustSelfThunk = packed record
  2024. case AddInstruction: Longint of
  2025. AddByte: (AdjustmentByte: ShortInt);
  2026. AddLong: (AdjustmentLong: Longint);
  2027. end;
  2028. PInterfaceMT = ^TInterfaceMT;
  2029. TInterfaceMT = packed record
  2030. QueryInterfaceThunk: PAdjustSelfThunk;
  2031. end;
  2032. TInterfaceRef = ^PInterfaceMT;
  2033. var
  2034. QueryInterfaceThunk: PAdjustSelfThunk;
  2035. begin
  2036. try
  2037. Result := Pointer(I);
  2038. if Assigned(Result) then
  2039. begin
  2040. QueryInterfaceThunk := TInterfaceRef(I)^.QueryInterfaceThunk;
  2041. case QueryInterfaceThunk.AddInstruction of
  2042. AddByte:
  2043. Inc(PByte(Result), QueryInterfaceThunk.AdjustmentByte);
  2044. AddLong:
  2045. Inc(PByte(Result), QueryInterfaceThunk.AdjustmentLong);
  2046. else
  2047. Result := nil;
  2048. end;
  2049. end;
  2050. except
  2051. Result := nil;
  2052. end;
  2053. end;
  2054. //=== { TJclInterfacedPersistent } ===========================================
  2055. procedure TJclInterfacedPersistent.AfterConstruction;
  2056. begin
  2057. inherited AfterConstruction;
  2058. if GetOwner <> nil then
  2059. GetOwner.GetInterface(IInterface, FOwnerInterface);
  2060. end;
  2061. function TJclInterfacedPersistent._AddRef: Integer;
  2062. begin
  2063. if FOwnerInterface <> nil then
  2064. Result := FOwnerInterface._AddRef
  2065. else
  2066. Result := InterlockedIncrement(FRefCount);
  2067. end;
  2068. function TJclInterfacedPersistent._Release: Integer;
  2069. begin
  2070. if FOwnerInterface <> nil then
  2071. Result := FOwnerInterface._Release
  2072. else
  2073. begin
  2074. Result := InterlockedDecrement(FRefCount);
  2075. if Result = 0 then
  2076. Destroy;
  2077. end;
  2078. end;
  2079. //=== Numeric formatting routines ============================================
  2080. function IntToStrZeroPad(Value, Count: Integer): string;
  2081. begin
  2082. Result := IntToStr(Value);
  2083. if Length(Result) < Count then
  2084. Result := StrRepeatChar('0', Count - Length(Result)) + Result;
  2085. end;
  2086. //=== { TJclNumericFormat } ==================================================
  2087. { TODO -cHelp : Author: Robert Rossmair }
  2088. { Digit: converts a digit value (number) to a digit (char)
  2089. DigitValue: converts a digit (char) into a number (digit value)
  2090. IntToStr,
  2091. FloatToStr,
  2092. FloatToHTML: converts a numeric value to a base <Base> numeric representation with formating options
  2093. StrToIn: converts a base <Base> numeric representation into an integer, if possible
  2094. GetMantisseExponent: similar to AsString, but returns the Exponent separately as an integer
  2095. }
  2096. const
  2097. {$IFDEF MATH_EXTENDED_PRECISION}
  2098. BinaryPrecision = 64;
  2099. {$ENDIF MATH_EXTENDED_PRECISION}
  2100. {$IFDEF MATH_DOUBLE_PRECISION}
  2101. BinaryPrecision = 53;
  2102. {$ENDIF MATH_DOUBLE_PRECISION}
  2103. {$IFDEF MATH_SINGLE_PRECISION}
  2104. BinaryPrecision = 24;
  2105. {$ENDIF MATH_SINGLE_PRECISION}
  2106. {$IFNDEF WINSCP}
  2107. constructor TJclNumericFormat.Create;
  2108. begin
  2109. inherited Create;
  2110. { TODO : Initialize, when possible, from locale info }
  2111. FBase := 10;
  2112. FExpDivision := 1;
  2113. SetPrecision(6);
  2114. FNumberOfFractionalDigits := BinaryPrecision;
  2115. FSignChars[False] := '-';
  2116. FSignChars[True] := '+';
  2117. FPaddingChar := ' ';
  2118. FMultiplier := '×';
  2119. FFractionalPartSeparator := JclFormatSettings.DecimalSeparator;
  2120. FDigitBlockSeparator := JclFormatSettings.ThousandSeparator;
  2121. end;
  2122. procedure TJclNumericFormat.InvalidDigit(Digit: Char);
  2123. begin
  2124. raise EConvertError.CreateResFmt(@RsInvalidDigit, [Base, Digit]);
  2125. end;
  2126. function TJclNumericFormat.Digit(DigitValue: TDigitValue): Char;
  2127. begin
  2128. Assert(DigitValue < Base, Format(LoadResString(@RsInvalidDigitValue), [Base, DigitValue]));
  2129. if DigitValue > 9 then
  2130. Result := Chr(Ord('A') + DigitValue - 10)
  2131. else
  2132. Result := Chr(Ord('0') + DigitValue);
  2133. end;
  2134. function TJclNumericFormat.GetDigitValue(Digit: Char): Integer;
  2135. begin
  2136. Result := CharHex(Digit);
  2137. if (Result = $FF) or (Result >= Base) then
  2138. Result := -1;
  2139. end;
  2140. function TJclNumericFormat.DigitValue(Digit: Char): TDigitValue;
  2141. begin
  2142. Result := GetDigitValue(Digit);
  2143. if Result = -1 then
  2144. InvalidDigit(Digit);
  2145. end;
  2146. function TJclNumericFormat.IsDigit(Value: Char): Boolean;
  2147. begin
  2148. Result := GetDigitValue(Value) <> -1;
  2149. end;
  2150. function TJclNumericFormat.FloatToHTML(const Value: Float): string;
  2151. var
  2152. Mantissa: string;
  2153. Exponent: Integer;
  2154. begin
  2155. GetMantissaExp(Value, Mantissa, Exponent);
  2156. Result := Format('%s %s %d<sup>%d</sup>', [Mantissa, Multiplier, Base, Exponent]);
  2157. end;
  2158. procedure TJclNumericFormat.GetMantissaExp(const Value: Float;
  2159. out Mantissa: string; out Exponent: Integer);
  2160. const
  2161. {$IFDEF FPC}
  2162. InfMantissa: array [Boolean] of string[4] = ('inf', '-inf');
  2163. {$ElSE ~FPC}
  2164. InfMantissa: array [Boolean] of string = ('inf', '-inf');
  2165. {$ENDIF ~FPC}
  2166. var
  2167. BlockDigits: TDigitCount;
  2168. IntDigits, FracDigits: Integer;
  2169. FirstDigitPos, Prec: Integer;
  2170. I, J, N: Integer;
  2171. K: Int64;
  2172. X: Extended;
  2173. HighDigit: Char;
  2174. function GetDigit(X: Extended): Char;
  2175. var
  2176. N: Integer;
  2177. begin
  2178. N := Trunc(X);
  2179. if N > 9 then
  2180. Result := Chr(Ord('A') + N - 10)
  2181. else
  2182. Result := Chr(Ord('0') + N);
  2183. end;
  2184. begin
  2185. X := Abs(Value);
  2186. if X > MaxFloatingPoint then
  2187. begin
  2188. Mantissa := InfMantissa[Value < 0];
  2189. Exponent := 1;
  2190. Exit;
  2191. end
  2192. else
  2193. if X < MinFloatingPoint then
  2194. begin
  2195. Mantissa := Format('%.*f', [Precision, 0.0]);
  2196. Exponent := 1;
  2197. Exit;
  2198. end;
  2199. IntDigits := 1;
  2200. Prec := Precision;
  2201. Exponent := Trunc(LogBaseN(Base, X));
  2202. if FExpDivision > 1 then
  2203. begin
  2204. N := Exponent mod FExpDivision;
  2205. Dec(Exponent, N);
  2206. Inc(IntDigits, N);
  2207. end;
  2208. X := X / Power(Base, Exponent);
  2209. if X < 1.0 then
  2210. begin
  2211. Dec(Exponent, FExpDivision);
  2212. X := X * PowerInt(Base, FExpDivision);
  2213. Inc(IntDigits, FExpDivision - 1);
  2214. end;
  2215. { TODO : Here's a problem if X > High(Int64).
  2216. It *seems* to surface only if ExponentDivision > 12, but it
  2217. has not been investigated if ExponentDivision <= 12 is safe. }
  2218. K := Trunc(X);
  2219. if Value < 0 then
  2220. K := -K;
  2221. Mantissa := IntToStr(K, FirstDigitPos);
  2222. FracDigits := Prec - IntDigits;
  2223. if FracDigits > NumberOfFractionalDigits then
  2224. FracDigits := NumberOfFractionalDigits;
  2225. if FracDigits > 0 then
  2226. begin
  2227. J := Length(Mantissa) + 1;
  2228. // allocate sufficient space for point + digits + digit block separators
  2229. SetLength(Mantissa, FracDigits * 2 + J);
  2230. Mantissa[J] := FractionalPartSeparator;
  2231. I := J + 1;
  2232. BlockDigits := 0;
  2233. while FracDigits > 0 do
  2234. begin
  2235. if (BlockDigits > 0) and (BlockDigits = DigitBlockSize) then
  2236. begin
  2237. Mantissa[I] := DigitBlockSeparator;
  2238. Inc(I);
  2239. BlockDigits := 0;
  2240. end;
  2241. X := Frac(X) * Base;
  2242. Mantissa[I] := GetDigit(X);
  2243. Inc(I);
  2244. Inc(BlockDigits);
  2245. Dec(FracDigits);
  2246. end;
  2247. Mantissa[I] := #0;
  2248. StrResetLength(Mantissa);
  2249. end;
  2250. if Frac(X) >= 0.5 then
  2251. // round up
  2252. begin
  2253. HighDigit := Digit(Base - 1);
  2254. for I := Length(Mantissa) downto 1 do
  2255. begin
  2256. if Mantissa[I] = HighDigit then
  2257. if (I = FirstDigitPos) then
  2258. begin
  2259. Mantissa[I] := '1';
  2260. Inc(Exponent);
  2261. Break;
  2262. end
  2263. else
  2264. Mantissa[I] := '0'
  2265. else
  2266. if (Mantissa[I] = DigitBlockSeparator) or (Mantissa[I] = FractionalPartSeparator) then
  2267. Continue
  2268. else
  2269. begin
  2270. if Mantissa[I] = '9' then
  2271. Mantissa[I] := 'A'
  2272. else
  2273. Mantissa[I] := Succ(Mantissa[I]);
  2274. Break;
  2275. end;
  2276. end;
  2277. end;
  2278. end;
  2279. function TJclNumericFormat.FloatToStr(const Value: Float): string;
  2280. var
  2281. Mantissa: string;
  2282. Exponent: Integer;
  2283. begin
  2284. GetMantissaExp(Value, Mantissa, Exponent);
  2285. Result := Format('%s %s %d^%d', [Mantissa, Multiplier, Base, Exponent]);
  2286. end;
  2287. function TJclNumericFormat.IntToStr(const Value: Int64): string;
  2288. var
  2289. FirstDigitPos: Integer;
  2290. begin
  2291. Result := IntToStr(Value, FirstDigitPos);
  2292. end;
  2293. function TJclNumericFormat.IntToStr(const Value: Int64; out FirstDigitPos: Integer): string;
  2294. const
  2295. MaxResultLen = 64 + 63 + 1; // max. digits + max. group separators + sign
  2296. var
  2297. Remainder: Int64;
  2298. I, N: Integer;
  2299. Chars, Digits: Cardinal;
  2300. LoopFinished, HasSign, SpacePadding: Boolean;
  2301. begin
  2302. SpacePadding := PaddingChar = ' ';
  2303. HasSign := ShowSign(Value);
  2304. Chars := MaxResultLen;
  2305. if Width > Chars then
  2306. Chars := Width;
  2307. Result := StrRepeatChar(' ', Chars);
  2308. Remainder := Abs(Value);
  2309. Digits := 0;
  2310. Chars := 0;
  2311. if HasSign then
  2312. Chars := 1;
  2313. I := MaxResultLen;
  2314. while True do
  2315. begin
  2316. N := Remainder mod Base;
  2317. Remainder := Remainder div Base;
  2318. if N > 9 then
  2319. Result[I] := Chr(Ord('A') + N - 10)
  2320. else
  2321. Result[I] := Chr(Ord('0') + N);
  2322. Dec(I);
  2323. Inc(Digits);
  2324. Inc(Chars);
  2325. if (Remainder = 0) and (SpacePadding or (Chars >= Width)) then
  2326. Break;
  2327. if (Digits = DigitBlockSize) then
  2328. begin
  2329. Inc(Chars);
  2330. LoopFinished := (Remainder = 0) and (Chars = Width);
  2331. if LoopFinished then
  2332. Result[I] := ' '
  2333. else
  2334. Result[I] := DigitBlockSeparator;
  2335. Dec(I);
  2336. if LoopFinished then
  2337. Break;
  2338. Digits := 0;
  2339. end;
  2340. end;
  2341. FirstDigitPos := I + 1;
  2342. if HasSign then
  2343. Result[I] := SignChar(Value)
  2344. else
  2345. Inc(I);
  2346. N := MaxResultLen - Width + 1;
  2347. if N < I then
  2348. I := N;
  2349. Result := Copy(Result, I, MaxResultLen);
  2350. Dec(FirstDigitPos, I - 1);
  2351. end;
  2352. procedure TJclNumericFormat.SetBase(const Value: TNumericSystemBase);
  2353. begin
  2354. FBase := Value;
  2355. SetPrecision(FWantedPrecision);
  2356. end;
  2357. procedure TJclNumericFormat.SetExpDivision(const Value: Integer);
  2358. begin
  2359. if Value <= 1 then
  2360. FExpDivision := 1
  2361. else
  2362. // see TODO in GetMantissaExp
  2363. if Value > 12 then
  2364. FExpDivision := 12
  2365. else
  2366. FExpDivision := Value;
  2367. end;
  2368. procedure TJclNumericFormat.SetPrecision(const Value: TDigitCount);
  2369. begin
  2370. FWantedPrecision := Value;
  2371. // Do not display more digits than Float precision justifies
  2372. if Base = 2 then
  2373. FPrecision := BinaryPrecision
  2374. else
  2375. FPrecision := Trunc(BinaryPrecision / LogBase2(Base));
  2376. if Value < FPrecision then
  2377. FPrecision := Value;
  2378. end;
  2379. function TJclNumericFormat.Sign(Value: Char): Integer;
  2380. begin
  2381. Result := 0;
  2382. if Value = FSignChars[False] then
  2383. Result := -1;
  2384. if Value = FSignChars[True] then
  2385. Result := +1;
  2386. end;
  2387. function TJclNumericFormat.StrToInt(const Value: string): Int64;
  2388. var
  2389. I, N: Integer;
  2390. C: Char;
  2391. begin
  2392. Result := 0;
  2393. I := 1;
  2394. if (Length(Value) >= I)
  2395. and ((Value[I] = '+') or (Value[I] = '-')) then
  2396. Inc(I);
  2397. for I := I to Length(Value) do
  2398. begin
  2399. C := Value[I];
  2400. if C = DigitBlockSeparator then
  2401. Continue
  2402. else
  2403. begin
  2404. N := CharHex(C);
  2405. if (N = $FF) or (N >= Base) then
  2406. InvalidDigit(C);
  2407. Result := Result * Base + N;
  2408. end;
  2409. end;
  2410. if Value[1] = '-' then
  2411. Result := -Result;
  2412. end;
  2413. function TJclNumericFormat.ShowSign(const Value: Float): Boolean;
  2414. begin
  2415. Result := FShowPositiveSign or (Value < 0);
  2416. end;
  2417. function TJclNumericFormat.ShowSign(const Value: Int64): Boolean;
  2418. begin
  2419. Result := FShowPositiveSign or (Value < 0);
  2420. end;
  2421. function TJclNumericFormat.SignChar(const Value: Float): Char;
  2422. begin
  2423. Result := FSignChars[Value >= 0];
  2424. end;
  2425. function TJclNumericFormat.SignChar(const Value: Int64): Char;
  2426. begin
  2427. Result := FSignChars[Value >= 0];
  2428. end;
  2429. function TJclNumericFormat.GetNegativeSign: Char;
  2430. begin
  2431. Result := FSignChars[False];
  2432. end;
  2433. function TJclNumericFormat.GetPositiveSign: Char;
  2434. begin
  2435. Result := FSignChars[True];
  2436. end;
  2437. procedure TJclNumericFormat.SetNegativeSign(const Value: Char);
  2438. begin
  2439. FSignChars[False] := Value;
  2440. end;
  2441. procedure TJclNumericFormat.SetPositiveSign(const Value: Char);
  2442. begin
  2443. FSignChars[True] := Value;
  2444. end;
  2445. //=== Child processes ========================================================
  2446. const
  2447. BufferSize = 255;
  2448. type
  2449. TBuffer = array [0..BufferSize] of AnsiChar;
  2450. TPipeInfo = record
  2451. PipeRead, PipeWrite: THandle;
  2452. Buffer: TBuffer;
  2453. Line: string;
  2454. TextHandler: TTextHandler;
  2455. RawOutput: Boolean;
  2456. AutoConvertOem: Boolean;
  2457. Event: TJclEvent;
  2458. end;
  2459. PPipeInfo = ^TPipeInfo;
  2460. // MuteCRTerminatedLines was "outsourced" from Win32ExecAndRedirectOutput
  2461. function InternalExecuteMuteCRTerminatedLines(const RawOutput: string): string;
  2462. const
  2463. Delta = 1024;
  2464. var
  2465. BufPos, OutPos, LfPos, EndPos: Integer;
  2466. C: Char;
  2467. begin
  2468. SetLength(Result, Length(RawOutput));
  2469. OutPos := 1;
  2470. LfPos := OutPos;
  2471. EndPos := OutPos;
  2472. for BufPos := 1 to Length(RawOutput) do
  2473. begin
  2474. if OutPos >= Length(Result)-2 then
  2475. SetLength(Result, Length(Result) + Delta);
  2476. C := RawOutput[BufPos];
  2477. case C of
  2478. NativeCarriageReturn:
  2479. OutPos := LfPos;
  2480. NativeLineFeed:
  2481. begin
  2482. OutPos := EndPos;
  2483. Result[OutPos] := NativeCarriageReturn;
  2484. Inc(OutPos);
  2485. Result[OutPos] := C;
  2486. Inc(OutPos);
  2487. EndPos := OutPos;
  2488. LfPos := OutPos;
  2489. end;
  2490. else
  2491. Result[OutPos] := C;
  2492. Inc(OutPos);
  2493. EndPos := OutPos;
  2494. end;
  2495. end;
  2496. SetLength(Result, OutPos - 1);
  2497. end;
  2498. procedure InternalExecuteProcessLine(const PipeInfo: TPipeInfo; LineEnd: Integer);
  2499. begin
  2500. if PipeInfo.RawOutput or (PipeInfo.Line[LineEnd] <> NativeCarriageReturn) then
  2501. begin
  2502. while (LineEnd > 0) and CharIsReturn(PipeInfo.Line[LineEnd]) do
  2503. Dec(LineEnd);
  2504. PipeInfo.TextHandler(Copy(PipeInfo.Line, 1, LineEnd));
  2505. end;
  2506. end;
  2507. procedure InternalExecuteProcessBuffer(var PipeInfo: TPipeInfo; PipeBytesRead: Cardinal);
  2508. var
  2509. CR, LF: Integer;
  2510. {$IFDEF MSWINDOWS}
  2511. LineLen, Len: Integer;
  2512. {$ENDIF MSWINDOWS}
  2513. S: AnsiString;
  2514. begin
  2515. {$IFDEF MSWINDOWS}
  2516. if PipeInfo.AutoConvertOem then
  2517. begin
  2518. {$IFDEF UNICODE}
  2519. Len := MultiByteToWideChar(CP_OEMCP, 0, PipeInfo.Buffer, PipeBytesRead, nil, 0);
  2520. LineLen := Length(PipeInfo.Line);
  2521. // Convert directly into the PipeInfo.Line string
  2522. SetLength(PipeInfo.Line, LineLen + Len);
  2523. MultiByteToWideChar(CP_OEMCP, 0, PipeInfo.Buffer, PipeBytesRead, PChar(PipeInfo.Line) + LineLen, Len);
  2524. {$ELSE}
  2525. Len := PipeBytesRead;
  2526. LineLen := Length(PipeInfo.Line);
  2527. // Convert directly into the PipeInfo.Line string
  2528. SetLength(PipeInfo.Line, LineLen + Len);
  2529. OemToAnsiBuff(PipeInfo.Buffer, PAnsiChar(PipeInfo.Line) + LineLen, PipeBytesRead);
  2530. {$ENDIF UNICODE}
  2531. end
  2532. else
  2533. {$ENDIF MSWINDOWS}
  2534. begin
  2535. SetString(S, PipeInfo.Buffer, PipeBytesRead); // interpret as ANSI
  2536. {$IFDEF UNICODE}
  2537. PipeInfo.Line := PipeInfo.Line + string(S); // ANSI => UNICODE
  2538. {$ELSE}
  2539. PipeInfo.Line := PipeInfo.Line + S;
  2540. {$ENDIF UNICODE}
  2541. end;
  2542. if Assigned(PipeInfo.TextHandler) then
  2543. repeat
  2544. CR := Pos(NativeCarriageReturn, PipeInfo.Line);
  2545. if CR = Length(PipeInfo.Line) then
  2546. CR := 0; // line feed at CR + 1 might be missing
  2547. LF := Pos(NativeLineFeed, PipeInfo.Line);
  2548. if (CR > 0) and ((LF > CR + 1) or (LF = 0)) then
  2549. LF := CR; // accept CR as line end
  2550. if LF > 0 then
  2551. begin
  2552. InternalExecuteProcessLine(PipeInfo, LF);
  2553. Delete(PipeInfo.Line, 1, LF);
  2554. end;
  2555. until LF = 0;
  2556. end;
  2557. procedure InternalExecuteReadPipe(var PipeInfo: TPipeInfo; var Overlapped: TOverlapped);
  2558. var
  2559. NullDWORD: ^DWORD; // XE4 broke PDWORD
  2560. Res: DWORD;
  2561. begin
  2562. NullDWORD := nil;
  2563. if not ReadFile(PipeInfo.PipeRead, PipeInfo.Buffer[0], BufferSize, NullDWORD^, @Overlapped) then
  2564. begin
  2565. Res := GetLastError;
  2566. case Res of
  2567. ERROR_BROKEN_PIPE:
  2568. begin
  2569. CloseHandle(PipeInfo.PipeRead);
  2570. PipeInfo.PipeRead := 0;
  2571. end;
  2572. ERROR_IO_PENDING:
  2573. ;
  2574. else
  2575. {$IFDEF DELPHI11_UP}
  2576. RaiseLastOSError(Res);
  2577. {$ELSE}
  2578. RaiseLastOSError;
  2579. {$ENDIF DELPHI11_UP}
  2580. end;
  2581. end;
  2582. end;
  2583. procedure InternalExecuteHandlePipeEvent(var PipeInfo: TPipeInfo; var Overlapped: TOverlapped);
  2584. var
  2585. PipeBytesRead: DWORD;
  2586. begin
  2587. if GetOverlappedResult(PipeInfo.PipeRead, Overlapped, PipeBytesRead, False) then
  2588. begin
  2589. InternalExecuteProcessBuffer(PipeInfo, PipeBytesRead);
  2590. // automatically launch the next read
  2591. InternalExecuteReadPipe(PipeInfo, Overlapped);
  2592. end
  2593. else
  2594. if GetLastError = ERROR_BROKEN_PIPE then
  2595. begin
  2596. CloseHandle(PipeInfo.PipeRead);
  2597. PipeInfo.PipeRead := 0;
  2598. end
  2599. else
  2600. RaiseLastOSError;
  2601. end;
  2602. procedure InternalExecuteFlushPipe(var PipeInfo: TPipeInfo; var Overlapped: TOverlapped);
  2603. var
  2604. PipeBytesRead: DWORD;
  2605. begin
  2606. CancelIo(PipeInfo.PipeRead);
  2607. GetOverlappedResult(PipeInfo.PipeRead, Overlapped, PipeBytesRead, True);
  2608. if PipeBytesRead > 0 then
  2609. InternalExecuteProcessBuffer(PipeInfo, PipeBytesRead);
  2610. while PeekNamedPipe(PipeInfo.PipeRead, nil, 0, nil, @PipeBytesRead, nil) and (PipeBytesRead > 0) do
  2611. begin
  2612. if PipeBytesRead > BufferSize then
  2613. PipeBytesRead := BufferSize;
  2614. if not ReadFile(PipeInfo.PipeRead, PipeInfo.Buffer[0], PipeBytesRead, PipeBytesRead, nil) then
  2615. RaiseLastOSError;
  2616. InternalExecuteProcessBuffer(PipeInfo, PipeBytesRead);
  2617. end;
  2618. end;
  2619. var
  2620. AsyncPipeCounter: Integer;
  2621. // CreateAsyncPipe creates a pipe that uses overlapped reading.
  2622. function CreateAsyncPipe(var hReadPipe, hWritePipe: THandle;
  2623. lpPipeAttributes: PSecurityAttributes; nSize: DWORD): BOOL;
  2624. var
  2625. PipeName: string;
  2626. Error: DWORD;
  2627. PipeReadHandle, PipeWriteHandle: THandle;
  2628. begin
  2629. Result := False;
  2630. if (@hReadPipe = nil) or (@hWritePipe = nil) then
  2631. begin
  2632. SetLastError(ERROR_INVALID_PARAMETER);
  2633. Exit;
  2634. end;
  2635. if nSize = 0 then
  2636. nSize := 4096;
  2637. InterlockedIncrement(AsyncPipeCounter);
  2638. // In some (not so) rare instances there is a race condition
  2639. // where the counter is the same for two threads at the same
  2640. // time. This makes the CreateNamedPipe call below fail
  2641. // because of the limit set to 1 in the call.
  2642. // So, to be sure this call succeeds, we put both the process
  2643. // and thread id in the name of the pipe.
  2644. // This was found to happen while simply starting 7 instances
  2645. // of the same exe file in parallel.
  2646. PipeName := Format('\\.\Pipe\AsyncAnonPipe.%.8x.%.8x.%.8x', [GetCurrentProcessId, GetCurrentThreadId, AsyncPipeCounter]);
  2647. PipeReadHandle := CreateNamedPipe(PChar(PipeName), PIPE_ACCESS_INBOUND or FILE_FLAG_OVERLAPPED,
  2648. PIPE_TYPE_BYTE or PIPE_WAIT, 1, nSize, nSize, 120 * 1000, lpPipeAttributes);
  2649. if PipeReadHandle = INVALID_HANDLE_VALUE then
  2650. Exit;
  2651. PipeWriteHandle := CreateFile(PChar(PipeName), GENERIC_WRITE, 0, lpPipeAttributes, OPEN_EXISTING,
  2652. FILE_ATTRIBUTE_NORMAL {or FILE_FLAG_OVERLAPPED}, 0);
  2653. if PipeWriteHandle = INVALID_HANDLE_VALUE then
  2654. begin
  2655. Error := GetLastError;
  2656. CloseHandle(PipeReadHandle);
  2657. SetLastError(Error);
  2658. Exit;
  2659. end;
  2660. hReadPipe := PipeReadHandle;
  2661. hWritePipe := PipeWriteHandle;
  2662. Result := True;
  2663. end;
  2664. const
  2665. BELOW_NORMAL_PRIORITY_CLASS = $00004000;
  2666. ABOVE_NORMAL_PRIORITY_CLASS = $00008000;
  2667. ProcessPriorities: array [TJclProcessPriority] of DWORD =
  2668. (IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, HIGH_PRIORITY_CLASS, REALTIME_PRIORITY_CLASS,
  2669. BELOW_NORMAL_PRIORITY_CLASS, ABOVE_NORMAL_PRIORITY_CLASS);
  2670. { TJclExecuteCmdProcessOptions }
  2671. constructor TJclExecuteCmdProcessOptions.Create(const ACommandLine: string);
  2672. begin
  2673. inherited Create;
  2674. FCommandLine := ACommandLine;
  2675. FAutoConvertOem := True;
  2676. FProcessPriority := ppNormal;
  2677. end;
  2678. function ExecuteCmdProcess(Options: TJclExecuteCmdProcessOptions): Boolean;
  2679. var
  2680. OutPipeInfo, ErrorPipeInfo: TPipeInfo;
  2681. Index: Cardinal;
  2682. {$IFDEF MSWINDOWS}
  2683. const
  2684. StartupVisibilityFlags: array[TStartupVisibility] of DWORD = (SW_HIDE, SW_SHOW, SW_SHOWDEFAULT);
  2685. var
  2686. StartupInfo: TStartupInfo;
  2687. ProcessInfo: TProcessInformation;
  2688. SecurityAttr: TSecurityAttributes;
  2689. OutOverlapped, ErrorOverlapped: TOverlapped;
  2690. ProcessEvent: TJclDispatcherObject;
  2691. WaitEvents: array of TJclDispatcherObject;
  2692. InternalAbort: Boolean;
  2693. LastError: DWORD;
  2694. CommandLine: string;
  2695. AbortPtr: PBoolean;
  2696. Flags: DWORD;
  2697. begin
  2698. Result := False;
  2699. // hack to pass a null reference to the parameter lpNumberOfBytesRead of ReadFile
  2700. Options.FExitCode := $FFFFFFFF;
  2701. SecurityAttr.nLength := SizeOf(SecurityAttr);
  2702. SecurityAttr.lpSecurityDescriptor := nil;
  2703. SecurityAttr.bInheritHandle := True;
  2704. ResetMemory(OutPipeInfo, SizeOf(OutPipeInfo));
  2705. OutPipeInfo.TextHandler := Options.OutputLineCallback;
  2706. OutPipeInfo.RawOutput := Options.RawOutput;
  2707. OutPipeInfo.AutoConvertOem := Options.AutoConvertOem;
  2708. if not CreateAsyncPipe(OutPipeInfo.PipeRead, OutPipeInfo.PipeWrite, @SecurityAttr, 0) then
  2709. begin
  2710. Options.FExitCode := GetLastError;
  2711. Exit;
  2712. end;
  2713. OutPipeInfo.Event := TJclEvent.Create(@SecurityAttr, False {automatic reset}, False {not flagged}, '' {anonymous});
  2714. ResetMemory(ErrorPipeInfo, SizeOf(ErrorPipeInfo));
  2715. if not Options.MergeError then
  2716. begin
  2717. ErrorPipeInfo.TextHandler := Options.ErrorLineCallback;
  2718. ErrorPipeInfo.RawOutput := Options.RawError;
  2719. ErrorPipeInfo.AutoConvertOem := Options.AutoConvertOem;
  2720. if not CreateAsyncPipe(ErrorPipeInfo.PipeRead, ErrorPipeInfo.PipeWrite, @SecurityAttr, 0) then
  2721. begin
  2722. Options.FExitCode := GetLastError;
  2723. CloseHandle(OutPipeInfo.PipeWrite);
  2724. CloseHandle(OutPipeInfo.PipeRead);
  2725. OutPipeInfo.Event.Free;
  2726. Exit;
  2727. end;
  2728. ErrorPipeInfo.Event := TJclEvent.Create(@SecurityAttr, False {automatic reset}, False {not flagged}, '' {anonymous});
  2729. end;
  2730. ResetMemory(StartupInfo, SizeOf(TStartupInfo));
  2731. StartupInfo.cb := SizeOf(TStartupInfo);
  2732. StartupInfo.dwFlags := STARTF_USESTDHANDLES;
  2733. if Options.StartupVisibility <> svNotSet then
  2734. begin
  2735. StartupInfo.dwFlags := StartupInfo.dwFlags or STARTF_USESHOWWINDOW;
  2736. StartupInfo.wShowWindow := StartupVisibilityFlags[Options.StartupVisibility];
  2737. end;
  2738. StartupInfo.hStdInput := GetStdHandle(STD_INPUT_HANDLE);
  2739. StartupInfo.hStdOutput := OutPipeInfo.PipeWrite;
  2740. if Options.MergeError then
  2741. StartupInfo.hStdError := OutPipeInfo.PipeWrite
  2742. else
  2743. StartupInfo.hStdError := ErrorPipeInfo.PipeWrite;
  2744. CommandLine := Options.CommandLine;
  2745. UniqueString(CommandLine); // CommandLine must be in a writable memory block
  2746. ResetMemory(ProcessInfo, SizeOf(ProcessInfo));
  2747. ProcessEvent := nil;
  2748. try
  2749. Flags := Options.CreateProcessFlags and not (NORMAL_PRIORITY_CLASS or IDLE_PRIORITY_CLASS or
  2750. HIGH_PRIORITY_CLASS or REALTIME_PRIORITY_CLASS);
  2751. Flags := Flags or ProcessPriorities[Options.ProcessPriority];
  2752. if Assigned(Options.BeforeResume) then
  2753. Flags := Flags or CREATE_SUSPENDED;
  2754. if CreateProcess(nil, PChar(CommandLine), nil, nil, True, Flags,
  2755. nil, nil, StartupInfo, ProcessInfo) then
  2756. begin
  2757. Result := True;
  2758. try
  2759. try
  2760. if Assigned(Options.BeforeResume) then
  2761. Options.BeforeResume(ProcessInfo);
  2762. finally
  2763. if Flags and CREATE_SUSPENDED <> 0 then // CREATE_SUSPENDED may also have come from CreateProcessFlags
  2764. ResumeThread(ProcessInfo.hThread);
  2765. end;
  2766. // init out and error events
  2767. CloseHandle(OutPipeInfo.PipeWrite);
  2768. OutPipeInfo.PipeWrite := 0;
  2769. if not Options.MergeError then
  2770. begin
  2771. CloseHandle(ErrorPipeInfo.PipeWrite);
  2772. ErrorPipeInfo.PipeWrite := 0;
  2773. end;
  2774. InternalAbort := False;
  2775. AbortPtr := Options.AbortPtr;
  2776. if AbortPtr <> nil then
  2777. AbortPtr^ := {$IFDEF FPC}Byte({$ENDIF}False{$IFDEF FPC}){$ENDIF}
  2778. else
  2779. AbortPtr := @InternalAbort;
  2780. // init the array of events to wait for
  2781. ProcessEvent := TJclDispatcherObject.Attach(ProcessInfo.hProcess);
  2782. SetLength(WaitEvents, 2);
  2783. // add the process first
  2784. WaitEvents[0] := ProcessEvent;
  2785. // add the output event
  2786. WaitEvents[1] := OutPipeInfo.Event;
  2787. // add the error event
  2788. if not Options.MergeError then
  2789. begin
  2790. SetLength(WaitEvents, 3);
  2791. WaitEvents[2] := ErrorPipeInfo.Event;
  2792. end;
  2793. // add the abort event if any
  2794. if Options.AbortEvent <> nil then
  2795. begin
  2796. Options.AbortEvent.ResetEvent;
  2797. Index := Length(WaitEvents);
  2798. SetLength(WaitEvents, Index + 1);
  2799. WaitEvents[Index] := Options.AbortEvent;
  2800. end;
  2801. // init the asynchronous reads
  2802. ResetMemory(OutOverlapped, SizeOf(OutOverlapped));
  2803. OutOverlapped.hEvent := OutPipeInfo.Event.Handle;
  2804. InternalExecuteReadPipe(OutPipeInfo, OutOverlapped);
  2805. if not Options.MergeError then
  2806. begin
  2807. ResetMemory(ErrorOverlapped, SizeOf(ErrorOverlapped));
  2808. ErrorOverlapped.hEvent := ErrorPipeInfo.Event.Handle;
  2809. InternalExecuteReadPipe(ErrorPipeInfo, ErrorOverlapped);
  2810. end;
  2811. // event based loop
  2812. while not {$IFDEF FPC}Boolean({$ENDIF}AbortPtr^{$IFDEF FPC}){$ENDIF} do
  2813. begin
  2814. Index := WaitAlertableForMultipleObjects(WaitEvents, False, INFINITE);
  2815. if Index = WAIT_OBJECT_0 then
  2816. // the subprocess has ended
  2817. Break
  2818. else
  2819. if Index = (WAIT_OBJECT_0 + 1) then
  2820. begin
  2821. // event on output
  2822. InternalExecuteHandlePipeEvent(OutPipeInfo, OutOverlapped);
  2823. end
  2824. else
  2825. if (Index = (WAIT_OBJECT_0 + 2)) and not Options.MergeError then
  2826. begin
  2827. // event on error
  2828. InternalExecuteHandlePipeEvent(ErrorPipeInfo, ErrorOverlapped);
  2829. end
  2830. else
  2831. if ((Index = (WAIT_OBJECT_0 + 2)) and Options.MergeError) or
  2832. ((Index = (WAIT_OBJECT_0 + 3)) and not Options.MergeError) then
  2833. // event on abort
  2834. AbortPtr^ := {$IFDEF FPC}Byte({$ENDIF}True{$IFDEF FPC}){$ENDIF}
  2835. else
  2836. {$IFDEF DELPHI11_UP}
  2837. RaiseLastOSError(Index);
  2838. {$ELSE}
  2839. RaiseLastOSError;
  2840. {$ENDIF DELPHI11_UP}
  2841. end;
  2842. if {$IFDEF FPC}Boolean({$ENDIF}AbortPtr^{$IFDEF FPC}){$ENDIF} then
  2843. TerminateProcess(ProcessEvent.Handle, Cardinal(ABORT_EXIT_CODE));
  2844. if (ProcessEvent.WaitForever = {$IFDEF RTL280_UP}TJclWaitResult.{$ENDIF RTL280_UP}wrSignaled) and not GetExitCodeProcess(ProcessEvent.Handle, Options.FExitCode) then
  2845. Options.FExitCode := $FFFFFFFF;
  2846. CloseHandle(ProcessInfo.hThread);
  2847. ProcessInfo.hThread := 0;
  2848. if OutPipeInfo.PipeRead <> 0 then
  2849. // read data remaining in output pipe
  2850. InternalExecuteFlushPipe(OutPipeinfo, OutOverlapped);
  2851. if not Options.MergeError and (ErrorPipeInfo.PipeRead <> 0) then
  2852. // read data remaining in error pipe
  2853. InternalExecuteFlushPipe(ErrorPipeInfo, ErrorOverlapped);
  2854. except
  2855. // always terminate process in case of an exception.
  2856. // This is especially useful when an exception occurred in one of
  2857. // the texthandler but only do it if the process actually started,
  2858. // this prevents eating up the last error value by calling those
  2859. // three functions with an invalid handle
  2860. // Note that we don't do it in the finally block because these
  2861. // calls would also then eat up the last error value which we tried
  2862. // to avoid in the first place
  2863. if ProcessInfo.hProcess <> 0 then
  2864. begin
  2865. TerminateProcess(ProcessInfo.hProcess, Cardinal(ABORT_EXIT_CODE));
  2866. WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
  2867. GetExitCodeProcess(ProcessInfo.hProcess, Options.FExitCode);
  2868. end;
  2869. raise;
  2870. end;
  2871. end;
  2872. finally
  2873. LastError := GetLastError;
  2874. try
  2875. if OutPipeInfo.PipeRead <> 0 then
  2876. CloseHandle(OutPipeInfo.PipeRead);
  2877. if OutPipeInfo.PipeWrite <> 0 then
  2878. CloseHandle(OutPipeInfo.PipeWrite);
  2879. if ErrorPipeInfo.PipeRead <> 0 then
  2880. CloseHandle(ErrorPipeInfo.PipeRead);
  2881. if ErrorPipeInfo.PipeWrite <> 0 then
  2882. CloseHandle(ErrorPipeInfo.PipeWrite);
  2883. if ProcessInfo.hThread <> 0 then
  2884. CloseHandle(ProcessInfo.hThread);
  2885. if Assigned(ProcessEvent) then
  2886. ProcessEvent.Free // this calls CloseHandle(ProcessInfo.hProcess)
  2887. else if ProcessInfo.hProcess <> 0 then
  2888. CloseHandle(ProcessInfo.hProcess);
  2889. OutPipeInfo.Event.Free;
  2890. ErrorPipeInfo.Event.Free;
  2891. finally
  2892. SetLastError(LastError);
  2893. end;
  2894. end;
  2895. {$ENDIF MSWINDOWS}
  2896. {$IFDEF UNIX}
  2897. var
  2898. PipeBytesRead: Cardinal;
  2899. Pipe: PIOFile;
  2900. Cmd: string;
  2901. begin
  2902. Cmd := Format('%s 2>&1', [Options.CommandLine]);
  2903. Pipe := nil;
  2904. try
  2905. Pipe := Libc.popen(PChar(Cmd), 'r');
  2906. { TODO : handle Abort }
  2907. repeat
  2908. PipeBytesRead := fread_unlocked(@OutBuffer, 1, BufferSize, Pipe);
  2909. if PipeBytesRead > 0 then
  2910. ProcessBuffer(OutBuffer, OutLine, PipeBytesRead);
  2911. until PipeBytesRead = 0;
  2912. Result := pclose(Pipe);
  2913. Pipe := nil;
  2914. wait(nil);
  2915. finally
  2916. if Pipe <> nil then
  2917. pclose(Pipe);
  2918. wait(nil);
  2919. end;
  2920. {$ENDIF UNIX}
  2921. if OutPipeInfo.Line <> '' then
  2922. if Assigned(OutPipeInfo.TextHandler) then
  2923. // output wasn't terminated by a line feed...
  2924. // (shouldn't happen, but you never know)
  2925. InternalExecuteProcessLine(OutPipeInfo, Length(OutPipeInfo.Line))
  2926. else
  2927. if Options.RawOutput then
  2928. Options.FOutput := OutPipeInfo.Line
  2929. else
  2930. Options.FOutput := InternalExecuteMuteCRTerminatedLines(OutPipeInfo.Line);
  2931. if ErrorPipeInfo.Line <> '' then
  2932. if Assigned(ErrorPipeInfo.TextHandler) then
  2933. // error wasn't terminated by a line feed...
  2934. // (shouldn't happen, but you never know)
  2935. InternalExecuteProcessLine(ErrorPipeInfo, Length(ErrorPipeInfo.Line))
  2936. else
  2937. if Options.RawError then
  2938. Options.FError := ErrorPipeInfo.Line
  2939. else
  2940. Options.FError := InternalExecuteMuteCRTerminatedLines(ErrorPipeInfo.Line);
  2941. end;
  2942. function InternalExecute(CommandLine: string; AbortPtr: PBoolean; AbortEvent: TJclEvent;
  2943. var Output: string; OutputLineCallback: TTextHandler; RawOutput: Boolean;
  2944. MergeError: Boolean; var Error: string; ErrorLineCallback: TTextHandler; RawError: Boolean;
  2945. ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
  2946. var
  2947. Options: TJclExecuteCmdProcessOptions;
  2948. begin
  2949. Options := TJclExecuteCmdProcessOptions.Create(CommandLine);
  2950. try
  2951. Options.AutoConvertOem := AutoConvertOem;
  2952. Options.AbortPtr := AbortPtr;
  2953. Options.AbortEvent := AbortEvent;
  2954. Options.OutputLineCallback := OutputLineCallback;
  2955. Options.RawOutput := RawOutput;
  2956. Options.MergeError := MergeError;
  2957. Options.ErrorLineCallback := ErrorLineCallback;
  2958. Options.RawError := RawError;
  2959. Options.ProcessPriority := ProcessPriority;
  2960. ExecuteCmdProcess(Options);
  2961. Result := Options.ExitCode;
  2962. // Append => backward compatiblity
  2963. Output := Output + Options.Output;
  2964. Error := Error + Options.Error;
  2965. finally
  2966. Options.Free;
  2967. end;
  2968. end;
  2969. { TODO -cHelp :
  2970. RawOutput: Do not process isolated carriage returns (#13).
  2971. That is, for RawOutput = False, lines not terminated by a line feed (#10) are deleted from Output. }
  2972. function Execute(const CommandLine: string; var Output: string; RawOutput: Boolean;
  2973. AbortPtr: PBoolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
  2974. var
  2975. Error: string;
  2976. begin
  2977. Error := '';
  2978. Result := InternalExecute(CommandLine, AbortPtr, nil, Output, nil, RawOutput, True, Error,
  2979. nil, False, ProcessPriority, AutoConvertOem);
  2980. end;
  2981. function Execute(const CommandLine: string; AbortEvent: TJclEvent; var Output: string; RawOutput: Boolean;
  2982. ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
  2983. var
  2984. Error: string;
  2985. begin
  2986. Error := '';
  2987. Result := InternalExecute(CommandLine, nil, AbortEvent, Output, nil, RawOutput, True, Error,
  2988. nil, False, ProcessPriority, AutoConvertOem);
  2989. end;
  2990. { TODO -cHelp :
  2991. Author: Robert Rossmair
  2992. OutputLineCallback called once per line of output. }
  2993. function Execute(const CommandLine: string; OutputLineCallback: TTextHandler; RawOutput: Boolean;
  2994. AbortPtr: PBoolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
  2995. var
  2996. Output, Error: string;
  2997. begin
  2998. Output := '';
  2999. Error := '';
  3000. Result := InternalExecute(CommandLine, AbortPtr, nil, Output, OutputLineCallback, RawOutput, True, Error,
  3001. nil, False, ProcessPriority, AutoConvertOem);
  3002. end;
  3003. function Execute(const CommandLine: string; AbortEvent: TJclEvent; OutputLineCallback: TTextHandler; RawOutput: Boolean;
  3004. ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
  3005. var
  3006. Output, Error: string;
  3007. begin
  3008. Output := '';
  3009. Error := '';
  3010. Result := InternalExecute(CommandLine, nil, AbortEvent, Output, OutputLineCallback, RawOutput, True, Error,
  3011. nil, False, ProcessPriority, AutoConvertOem);
  3012. end;
  3013. { TODO -cHelp :
  3014. RawOutput: Do not process isolated carriage returns (#13).
  3015. That is, for RawOutput = False, lines not terminated by a line feed (#10) are deleted from Output. }
  3016. function Execute(const CommandLine: string; var Output, Error: string; RawOutput, RawError: Boolean;
  3017. AbortPtr: PBoolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
  3018. begin
  3019. Result := InternalExecute(CommandLine, AbortPtr, nil, Output, nil, RawOutput, False, Error,
  3020. nil, RawError, ProcessPriority, AutoConvertOem);
  3021. end;
  3022. function Execute(const CommandLine: string; AbortEvent: TJclEvent; var Output, Error: string;
  3023. RawOutput, RawError: Boolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
  3024. begin
  3025. Result := InternalExecute(CommandLine, nil, AbortEvent, Output, nil, RawOutput, False, Error,
  3026. nil, RawError, ProcessPriority, AutoConvertOem);
  3027. end;
  3028. { TODO -cHelp :
  3029. Author: Robert Rossmair
  3030. OutputLineCallback called once per line of output. }
  3031. function Execute(const CommandLine: string; OutputLineCallback, ErrorLineCallback: TTextHandler;
  3032. RawOutput, RawError: Boolean; AbortPtr: PBoolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
  3033. var
  3034. Output, Error: string;
  3035. begin
  3036. Output := '';
  3037. Error := '';
  3038. Result := InternalExecute(CommandLine, AbortPtr, nil, Output, OutputLineCallback, RawOutput, False, Error,
  3039. ErrorLineCallback, RawError, ProcessPriority, AutoConvertOem);
  3040. end;
  3041. function Execute(const CommandLine: string; AbortEvent: TJclEvent; OutputLineCallback, ErrorLineCallback: TTextHandler;
  3042. RawOutput, RawError: Boolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
  3043. var
  3044. Output, Error: string;
  3045. begin
  3046. Output := '';
  3047. Error := '';
  3048. Result := InternalExecute(CommandLine, nil, AbortEvent, Output, OutputLineCallback, RawOutput, False, Error,
  3049. ErrorLineCallback, RawError, ProcessPriority, AutoConvertOem);
  3050. end;
  3051. //=== { TJclCommandLineTool } ================================================
  3052. constructor TJclCommandLineTool.Create(const AExeName: string);
  3053. begin
  3054. inherited Create;
  3055. FOptions := TStringList.Create;
  3056. FExeName := AExeName;
  3057. end;
  3058. destructor TJclCommandLineTool.Destroy;
  3059. begin
  3060. FreeAndNil(FOptions);
  3061. inherited Destroy;
  3062. end;
  3063. procedure TJclCommandLineTool.AddPathOption(const Option, Path: string);
  3064. var
  3065. S: string;
  3066. begin
  3067. S := PathRemoveSeparator(Path);
  3068. {$IFDEF MSWINDOWS}
  3069. S := AnsiLowerCase(S); // file names are case insensitive
  3070. {$ENDIF MSWINDOWS}
  3071. S := Format('-%s%s', [Option, S]);
  3072. // avoid duplicate entries (note that search is case sensitive)
  3073. if GetOptions.IndexOf(S) = -1 then
  3074. GetOptions.Add(S);
  3075. end;
  3076. function TJclCommandLineTool.Execute(const CommandLine: string): Boolean;
  3077. begin
  3078. if Assigned(FOutputCallback) then
  3079. Result := JclSysUtils.Execute(Format('"%s" %s', [ExeName, CommandLine]), FOutputCallback) = 0
  3080. else
  3081. Result := JclSysUtils.Execute(Format('"%s" %s', [ExeName, CommandLine]), FOutput) = 0;
  3082. end;
  3083. function TJclCommandLineTool.GetExeName: string;
  3084. begin
  3085. Result := FExeName;
  3086. end;
  3087. function TJclCommandLineTool.GetOptions: TStrings;
  3088. begin
  3089. Result := FOptions;
  3090. end;
  3091. function TJclCommandLineTool.GetOutput: string;
  3092. begin
  3093. Result := FOutput;
  3094. end;
  3095. function TJclCommandLineTool.GetOutputCallback: TTextHandler;
  3096. begin
  3097. Result := FOutputCallback;
  3098. end;
  3099. procedure TJclCommandLineTool.SetOutputCallback(const CallbackMethod: TTextHandler);
  3100. begin
  3101. FOutputCallback := CallbackMethod;
  3102. end;
  3103. //=== Console Utilities ======================================================
  3104. function ReadKey: Char;
  3105. {$IFDEF MSWINDOWS}
  3106. { TODO -cHelp : Contributor: Robert Rossmair }
  3107. var
  3108. Console: TJclConsole;
  3109. InputMode: TJclConsoleInputModes;
  3110. begin
  3111. Console := TJclConsole.Default;
  3112. InputMode := Console.Input.Mode;
  3113. Console.Input.Mode := [imProcessed];
  3114. Console.Input.Clear;
  3115. Result := Char(Console.Input.GetEvent.Event.KeyEvent.AsciiChar);
  3116. Console.Input.Mode := InputMode;
  3117. end;
  3118. {$ENDIF MSWINDOWS}
  3119. {$IFDEF UNIX}
  3120. { TODO -cHelp : Donator: Wayne Sherman }
  3121. var
  3122. ReadFileDescriptor: TFDSet;
  3123. TimeVal: TTimeVal;
  3124. SaveTerminalSettings: TTermIos;
  3125. RawTerminalSettings: TTermIos;
  3126. begin
  3127. Result := #0;
  3128. //Save Original Terminal Settings
  3129. tcgetattr(stdin, SaveTerminalSettings);
  3130. tcgetattr(stdin, RawTerminalSettings);
  3131. //Put Terminal in RAW mode
  3132. cfmakeraw(RawTerminalSettings);
  3133. tcsetattr(stdin, TCSANOW, RawTerminalSettings);
  3134. try
  3135. //Setup file I/O descriptor for STDIN
  3136. FD_ZERO(ReadFileDescriptor);
  3137. FD_SET(stdin, ReadFileDescriptor);
  3138. TimeVal.tv_sec := High(LongInt); //wait forever
  3139. TimeVal.tv_usec := 0;
  3140. //clear keyboard buffer first
  3141. TCFlush(stdin, TCIFLUSH);
  3142. //wait for a key to be pressed
  3143. if select(1, @ReadFileDescriptor, nil, nil, @TimeVal) > 0 then
  3144. begin
  3145. //Now read the character
  3146. Result := Char(getchar);
  3147. end
  3148. else
  3149. raise EJclError.CreateRes(@RsReadKeyError);
  3150. finally
  3151. //Restore Original Terminal Settings
  3152. tcsetattr(stdin, TCSANOW, SaveTerminalSettings);
  3153. end;
  3154. end;
  3155. {$ENDIF UNIX}
  3156. {$ENDIF ~WINSCP}
  3157. //=== Loading of modules (DLLs) ==============================================
  3158. function LoadModule(var Module: TModuleHandle; FileName: string): Boolean;
  3159. {$IFDEF MSWINDOWS}
  3160. begin
  3161. if Module = INVALID_MODULEHANDLE_VALUE then
  3162. Module := SafeLoadLibrary(FileName);
  3163. Result := Module <> INVALID_MODULEHANDLE_VALUE;
  3164. end;
  3165. {$ENDIF MSWINDOWS}
  3166. {$IFDEF UNIX}
  3167. begin
  3168. if Module = INVALID_MODULEHANDLE_VALUE then
  3169. Module := dlopen(PChar(FileName), RTLD_NOW);
  3170. Result := Module <> INVALID_MODULEHANDLE_VALUE;
  3171. end;
  3172. {$ENDIF UNIX}
  3173. function LoadModuleEx(var Module: TModuleHandle; FileName: string; Flags: Cardinal): Boolean;
  3174. {$IFDEF MSWINDOWS}
  3175. begin
  3176. if Module = INVALID_MODULEHANDLE_VALUE then
  3177. Module := LoadLibraryEx(PChar(FileName), 0, Flags); // SafeLoadLibrary?
  3178. Result := Module <> INVALID_MODULEHANDLE_VALUE;
  3179. end;
  3180. {$ENDIF MSWINDOWS}
  3181. {$IFDEF UNIX}
  3182. begin
  3183. if Module = INVALID_MODULEHANDLE_VALUE then
  3184. Module := dlopen(PChar(FileName), Flags);
  3185. Result := Module <> INVALID_MODULEHANDLE_VALUE;
  3186. end;
  3187. {$ENDIF UNIX}
  3188. procedure UnloadModule(var Module: TModuleHandle);
  3189. {$IFDEF MSWINDOWS}
  3190. begin
  3191. if Module <> INVALID_MODULEHANDLE_VALUE then
  3192. FreeLibrary(Module);
  3193. Module := INVALID_MODULEHANDLE_VALUE;
  3194. end;
  3195. {$ENDIF MSWINDOWS}
  3196. {$IFDEF UNIX}
  3197. begin
  3198. if Module <> INVALID_MODULEHANDLE_VALUE then
  3199. dlclose(Pointer(Module));
  3200. Module := INVALID_MODULEHANDLE_VALUE;
  3201. end;
  3202. {$ENDIF UNIX}
  3203. function GetModuleSymbol(Module: TModuleHandle; SymbolName: string): Pointer;
  3204. {$IFDEF MSWINDOWS}
  3205. begin
  3206. Result := nil;
  3207. if Module <> INVALID_MODULEHANDLE_VALUE then
  3208. Result := GetProcAddress(Module, PChar(SymbolName));
  3209. end;
  3210. {$ENDIF MSWINDOWS}
  3211. {$IFDEF UNIX}
  3212. begin
  3213. Result := nil;
  3214. if Module <> INVALID_MODULEHANDLE_VALUE then
  3215. Result := dlsym(Module, PChar(SymbolName));
  3216. end;
  3217. {$ENDIF UNIX}
  3218. function GetModuleSymbolEx(Module: TModuleHandle; SymbolName: string; var Accu: Boolean): Pointer;
  3219. {$IFDEF MSWINDOWS}
  3220. begin
  3221. Result := nil;
  3222. if Module <> INVALID_MODULEHANDLE_VALUE then
  3223. Result := GetProcAddress(Module, PChar(SymbolName));
  3224. Accu := Accu and (Result <> nil);
  3225. end;
  3226. {$ENDIF MSWINDOWS}
  3227. {$IFDEF UNIX}
  3228. begin
  3229. Result := nil;
  3230. if Module <> INVALID_MODULEHANDLE_VALUE then
  3231. Result := dlsym(Module, PChar(SymbolName));
  3232. Accu := Accu and (Result <> nil);
  3233. end;
  3234. {$ENDIF UNIX}
  3235. function ReadModuleData(Module: TModuleHandle; SymbolName: string; var Buffer; Size: Cardinal): Boolean;
  3236. var
  3237. Sym: Pointer;
  3238. begin
  3239. Result := True;
  3240. Sym := GetModuleSymbolEx(Module, SymbolName, Result);
  3241. if Result then
  3242. Move(Sym^, Buffer, Size);
  3243. end;
  3244. function WriteModuleData(Module: TModuleHandle; SymbolName: string; var Buffer; Size: Cardinal): Boolean;
  3245. var
  3246. Sym: Pointer;
  3247. begin
  3248. Result := True;
  3249. Sym := GetModuleSymbolEx(Module, SymbolName, Result);
  3250. if Result then
  3251. Move(Buffer, Sym^, Size);
  3252. end;
  3253. //=== Conversion Utilities ===================================================
  3254. const
  3255. DefaultTrueBoolStr = 'True'; // DO NOT LOCALIZE
  3256. DefaultFalseBoolStr = 'False'; // DO NOT LOCALIZE
  3257. DefaultYesBoolStr = 'Yes'; // DO NOT LOCALIZE
  3258. DefaultNoBoolStr = 'No'; // DO NOT LOCALIZE
  3259. function StrToBoolean(const S: string): Boolean;
  3260. var
  3261. LowerCasedText: string;
  3262. begin
  3263. { TODO : Possibility to add localized strings, like in Delphi 7 }
  3264. { TODO : Lower case constants }
  3265. LowerCasedText := LowerCase(S);
  3266. Result := ((S = '1') or
  3267. (LowerCasedText = LowerCase(DefaultTrueBoolStr)) or (LowerCasedText = LowerCase(DefaultYesBoolStr))) or
  3268. (LowerCasedText = LowerCase(DefaultTrueBoolStr[1])) or (LowerCasedText = LowerCase(DefaultYesBoolStr[1]));
  3269. if not Result then
  3270. begin
  3271. Result := not ((S = '0') or
  3272. (LowerCasedText = LowerCase(DefaultFalseBoolStr)) or (LowerCasedText = LowerCase(DefaultNoBoolStr)) or
  3273. (LowerCasedText = LowerCase(DefaultFalseBoolStr[1])) or (LowerCasedText = LowerCase(DefaultNoBoolStr[1])));
  3274. if Result then
  3275. raise EJclConversionError.CreateResFmt(@RsStringToBoolean, [S]);
  3276. end;
  3277. end;
  3278. function BooleanToStr(B: Boolean): string;
  3279. begin
  3280. if B then
  3281. Result := DefaultTrueBoolStr
  3282. else
  3283. Result := DefaultFalseBoolStr;
  3284. end;
  3285. function IntToBool(I: Integer): Boolean;
  3286. begin
  3287. Result := I <> 0;
  3288. end;
  3289. function BoolToInt(B: Boolean): Integer;
  3290. begin
  3291. Result := Ord(B);
  3292. end;
  3293. function TryStrToUInt(const Value: string; out Res: Cardinal): Boolean;
  3294. var i6: Int64;
  3295. begin
  3296. Result := false;
  3297. if not TryStrToInt64(Value, i6) then exit;
  3298. if ( i6 < Low(Res)) or ( i6 > High(Res)) then exit;
  3299. Result := true;
  3300. Res := i6;
  3301. end;
  3302. function StrToUIntDef(const Value: string; const Default: Cardinal): Cardinal;
  3303. begin
  3304. if not TryStrToUInt(Value, Result)
  3305. then Result := Default;
  3306. end;
  3307. function StrToUInt(const Value: string): Cardinal;
  3308. begin
  3309. if not TryStrToUInt(Value, Result)
  3310. then raise EConvertError.Create('"'+Value+'" is not within range of Cardinal data type');
  3311. end;
  3312. //=== RTL package information ================================================
  3313. function SystemTObjectInstance: TJclAddr;
  3314. begin
  3315. Result := ModuleFromAddr(Pointer(System.TObject));
  3316. end;
  3317. function IsCompiledWithPackages: Boolean;
  3318. begin
  3319. Result := SystemTObjectInstance <> HInstance;
  3320. end;
  3321. //=== GUID ===================================================================
  3322. function JclGUIDToString(const GUID: TGUID): string;
  3323. begin
  3324. Result := Format('{%.8x-%.4x-%.4x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x}',
  3325. [GUID.D1, GUID.D2, GUID.D3, GUID.D4[0], GUID.D4[1], GUID.D4[2],
  3326. GUID.D4[3], GUID.D4[4], GUID.D4[5], GUID.D4[6], GUID.D4[7]]);
  3327. end;
  3328. function JclStringToGUID(const S: string): TGUID;
  3329. begin
  3330. if (Length(S) <> 38) or (S[1] <> '{') or (S[10] <> '-') or (S[15] <> '-') or
  3331. (S[20] <> '-') or (S[25] <> '-') or (S[38] <> '}') then
  3332. raise EJclConversionError.CreateResFmt(@RsInvalidGUIDString, [S]);
  3333. Result.D1 := StrToInt('$' + Copy(S, 2, 8));
  3334. Result.D2 := StrToInt('$' + Copy(S, 11, 4));
  3335. Result.D3 := StrToInt('$' + Copy(S, 16, 4));
  3336. Result.D4[0] := StrToInt('$' + Copy(S, 21, 2));
  3337. Result.D4[1] := StrToInt('$' + Copy(S, 23, 2));
  3338. Result.D4[2] := StrToInt('$' + Copy(S, 26, 2));
  3339. Result.D4[3] := StrToInt('$' + Copy(S, 28, 2));
  3340. Result.D4[4] := StrToInt('$' + Copy(S, 30, 2));
  3341. Result.D4[5] := StrToInt('$' + Copy(S, 32, 2));
  3342. Result.D4[6] := StrToInt('$' + Copy(S, 34, 2));
  3343. Result.D4[7] := StrToInt('$' + Copy(S, 36, 2));
  3344. end;
  3345. function GUIDEquals(const GUID1, GUID2: TGUID): Boolean;
  3346. begin
  3347. Result := (GUID1.D1 = GUID2.D1) and (GUID1.D2 = GUID2.D2) and (GUID1.D3 = GUID2.D3) and
  3348. (GUID1.D4[0] = GUID2.D4[0]) and (GUID1.D4[1] = GUID2.D4[1]) and
  3349. (GUID1.D4[2] = GUID2.D4[2]) and (GUID1.D4[3] = GUID2.D4[3]) and
  3350. (GUID1.D4[4] = GUID2.D4[4]) and (GUID1.D4[5] = GUID2.D4[5]) and
  3351. (GUID1.D4[6] = GUID2.D4[6]) and (GUID1.D4[7] = GUID2.D4[7]);
  3352. end;
  3353. // add items at the end
  3354. procedure ListAddItems(var List: string; const Separator, Items: string);
  3355. var
  3356. StrList, NewItems: TStringList;
  3357. Index: Integer;
  3358. begin
  3359. StrList := TStringList.Create;
  3360. try
  3361. StrToStrings(List, Separator, StrList, False);
  3362. NewItems := TStringList.Create;
  3363. try
  3364. StrToStrings(Items, Separator, NewItems);
  3365. for Index := 0 to NewItems.Count - 1 do
  3366. StrList.Add(NewItems.Strings[Index]);
  3367. List := StringsToStr(StrList, Separator);
  3368. finally
  3369. NewItems.Free;
  3370. end;
  3371. finally
  3372. StrList.Free;
  3373. end;
  3374. end;
  3375. // add items at the end if they are not present
  3376. procedure ListIncludeItems(var List: string; const Separator, Items: string);
  3377. var
  3378. StrList, NewItems: TStringList;
  3379. Index: Integer;
  3380. Item: string;
  3381. begin
  3382. StrList := TStringList.Create;
  3383. try
  3384. StrToStrings(List, Separator, StrList, False);
  3385. NewItems := TStringList.Create;
  3386. try
  3387. StrToStrings(Items, Separator, NewItems);
  3388. for Index := 0 to NewItems.Count - 1 do
  3389. begin
  3390. Item := NewItems.Strings[Index];
  3391. if StrList.IndexOf(Item) = -1 then
  3392. StrList.Add(Item);
  3393. end;
  3394. List := StringsToStr(StrList, Separator);
  3395. finally
  3396. NewItems.Free;
  3397. end;
  3398. finally
  3399. StrList.Free;
  3400. end;
  3401. end;
  3402. // delete multiple items
  3403. procedure ListRemoveItems(var List: string; const Separator, Items: string);
  3404. var
  3405. StrList, RemItems: TStringList;
  3406. Index, Position: Integer;
  3407. Item: string;
  3408. begin
  3409. StrList := TStringList.Create;
  3410. try
  3411. StrToStrings(List, Separator, StrList, False);
  3412. RemItems := TStringList.Create;
  3413. try
  3414. StrToStrings(Items, Separator, RemItems, False);
  3415. for Index := 0 to RemItems.Count - 1 do
  3416. begin
  3417. Item := RemItems.Strings[Index];
  3418. repeat
  3419. Position := StrList.IndexOf(Item);
  3420. if Position >= 0 then
  3421. StrList.Delete(Position);
  3422. until Position < 0;
  3423. end;
  3424. List := StringsToStr(StrList, Separator);
  3425. finally
  3426. RemItems.Free;
  3427. end;
  3428. finally
  3429. StrList.Free;
  3430. end;
  3431. end;
  3432. // delete one item
  3433. procedure ListDelItem(var List: string; const Separator: string; const Index: Integer);
  3434. var
  3435. StrList: TStringList;
  3436. begin
  3437. StrList := TStringList.Create;
  3438. try
  3439. StrToStrings(List, Separator, StrList, False);
  3440. StrList.Delete(Index);
  3441. List := StringsToStr(StrList, Separator);
  3442. finally
  3443. StrList.Free;
  3444. end;
  3445. end;
  3446. // return the number of item
  3447. function ListItemCount(const List, Separator: string): Integer;
  3448. var
  3449. StrList: TStringList;
  3450. begin
  3451. StrList := TStringList.Create;
  3452. try
  3453. StrToStrings(List, Separator, StrList, False);
  3454. Result := StrList.Count;
  3455. finally
  3456. StrList.Free;
  3457. end;
  3458. end;
  3459. // return the Nth item
  3460. function ListGetItem(const List, Separator: string; const Index: Integer): string;
  3461. var
  3462. StrList: TStringList;
  3463. begin
  3464. StrList := TStringList.Create;
  3465. try
  3466. StrToStrings(List, Separator, StrList, False);
  3467. Result := StrList.Strings[Index];
  3468. finally
  3469. StrList.Free;
  3470. end;
  3471. end;
  3472. // set the Nth item
  3473. procedure ListSetItem(var List: string; const Separator: string;
  3474. const Index: Integer; const Value: string);
  3475. var
  3476. StrList: TStringList;
  3477. begin
  3478. StrList := TStringList.Create;
  3479. try
  3480. StrToStrings(List, Separator, StrList, False);
  3481. StrList.Strings[Index] := Value;
  3482. List := StringsToStr(StrList, Separator);
  3483. finally
  3484. StrList.Free;
  3485. end;
  3486. end;
  3487. // return the index of an item
  3488. function ListItemIndex(const List, Separator, Item: string): Integer;
  3489. var
  3490. StrList: TStringList;
  3491. begin
  3492. StrList := TStringList.Create;
  3493. try
  3494. StrToStrings(List, Separator, StrList, False);
  3495. Result := StrList.IndexOf(Item);
  3496. finally
  3497. StrList.Free;
  3498. end;
  3499. end;
  3500. //=== { TJclIntfCriticalSection } ============================================
  3501. constructor TJclIntfCriticalSection.Create;
  3502. begin
  3503. inherited Create;
  3504. FCriticalSection := TCriticalSection.Create;
  3505. end;
  3506. destructor TJclIntfCriticalSection.Destroy;
  3507. begin
  3508. FCriticalSection.Free;
  3509. inherited Destroy;
  3510. end;
  3511. function TJclIntfCriticalSection._AddRef: Integer;
  3512. begin
  3513. FCriticalSection.Acquire;
  3514. Result := -1;
  3515. end;
  3516. function TJclIntfCriticalSection._Release: Integer;
  3517. begin
  3518. FCriticalSection.Release;
  3519. Result := -1;
  3520. end;
  3521. {$IFNDEF WINSCP}
  3522. //=== { TJclSimpleLog } ======================================================
  3523. {$IFDEF LINUX}
  3524. const
  3525. INVALID_HANDLE_VALUE = 0;
  3526. {$ENDIF LINUX}
  3527. constructor TJclSimpleLog.Create(const ALogFileName: string = '');
  3528. begin
  3529. if ALogFileName = '' then
  3530. FLogFileName := CreateDefaultFileName
  3531. else
  3532. FLogFileName := ALogFileName;
  3533. FLogFileHandle := TFileHandle(INVALID_HANDLE_VALUE);
  3534. FLoggingActive := True;
  3535. end;
  3536. function TJclSimpleLog.CreateDefaultFileName: string;
  3537. begin
  3538. Result := PathExtractFileDirFixed(ParamStr(0)) +
  3539. PathExtractFileNameNoExt(ParamStr(0)) + '_Err.log';
  3540. end;
  3541. destructor TJclSimpleLog.Destroy;
  3542. begin
  3543. CloseLog;
  3544. inherited Destroy;
  3545. end;
  3546. procedure TJclSimpleLog.ClearLog;
  3547. var
  3548. WasOpen: Boolean;
  3549. begin
  3550. WasOpen := LogOpen;
  3551. if WasOpen then
  3552. CloseLog;
  3553. if not FileExists(FlogFileName) then
  3554. Exit;
  3555. FLogFileHandle := FileCreate(FLogFileName);
  3556. FLogWasEmpty := True;
  3557. if Not WasOpen then
  3558. CloseLog;
  3559. end;
  3560. procedure TJclSimpleLog.CloseLog;
  3561. begin
  3562. if LogOpen then
  3563. begin
  3564. FileClose(FLogFileHandle);
  3565. FLogFileHandle := TFileHandle(INVALID_HANDLE_VALUE);
  3566. FLogWasEmpty := False;
  3567. end;
  3568. end;
  3569. function TJclSimpleLog.GetLogOpen: Boolean;
  3570. begin
  3571. Result := DWORD_PTR(FLogFileHandle) <> INVALID_HANDLE_VALUE;
  3572. end;
  3573. procedure TJclSimpleLog.OpenLog;
  3574. begin
  3575. if not LogOpen then
  3576. begin
  3577. FLogFileHandle := FileOpen(FLogFileName, fmOpenWrite or fmShareDenyWrite);
  3578. if LogOpen then
  3579. FLogWasEmpty := FileSeek(FLogFileHandle, 0, soFromEnd) = 0
  3580. else
  3581. begin
  3582. FLogFileHandle := FileCreate(FLogFileName);
  3583. FLogWasEmpty := True;
  3584. if LogOpen then
  3585. FileWrite(FLogFileHandle, BOM_UTF8[0], Length(BOM_UTF8));
  3586. end;
  3587. end
  3588. else
  3589. FLogWasEmpty := False;
  3590. end;
  3591. procedure TJclSimpleLog.Write(const Text: string; Indent: Integer = 0; KeepOpen: Boolean = true);
  3592. var
  3593. S: string;
  3594. UTF8S: TUTF8String;
  3595. SL: TStringList;
  3596. I: Integer;
  3597. WasOpen: Boolean;
  3598. begin
  3599. if LoggingActive then
  3600. begin
  3601. WasOpen := LogOpen;
  3602. if not WasOpen then
  3603. OpenLog;
  3604. if LogOpen then
  3605. begin
  3606. SL := TStringList.Create;
  3607. try
  3608. SL.Text := Text;
  3609. for I := 0 to SL.Count - 1 do
  3610. begin
  3611. S := StringOfChar(' ', Indent) + StrEnsureSuffix(NativeLineBreak, TrimRight(SL[I]));
  3612. UTF8S := StringToUTF8(S);
  3613. FileWrite(FLogFileHandle, UTF8S[1], Length(UTF8S));
  3614. end;
  3615. finally
  3616. SL.Free;
  3617. end;
  3618. // Keep the logfile Open when it was opened before and the KeepOpen is active
  3619. if not (WasOpen and KeepOpen) then
  3620. CloseLog;
  3621. end;
  3622. end;
  3623. end;
  3624. procedure TJclSimpleLog.Write(Strings: TStrings; Indent: Integer = 0; KeepOpen: Boolean = true);
  3625. begin
  3626. if Assigned(Strings) then
  3627. Write(Strings.Text, Indent, KeepOpen);
  3628. end;
  3629. procedure TJclSimpleLog.TimeWrite(const Text: string; Indent: Integer = 0; KeepOpen: Boolean = true);
  3630. var
  3631. S: string;
  3632. UTF8S: TUTF8String;
  3633. SL: TStringList;
  3634. I: Integer;
  3635. WasOpen: Boolean;
  3636. begin
  3637. if LoggingActive then
  3638. begin
  3639. WasOpen := LogOpen;
  3640. if not LogOpen then
  3641. OpenLog;
  3642. if LogOpen then
  3643. begin
  3644. SL := TStringList.Create;
  3645. try
  3646. SL.Text := Text;
  3647. for I := 0 to SL.Count - 1 do
  3648. begin
  3649. if DateTimeFormatStr = '' then
  3650. S := DateTimeToStr(Now)+' : '+StringOfChar(' ', Indent) + StrEnsureSuffix(NativeLineBreak, TrimRight(SL[I]))
  3651. else
  3652. S := FormatDateTime( DateTimeFormatStr, Now)+' : '+StringOfChar(' ', Indent) + StrEnsureSuffix(NativeLineBreak, TrimRight(SL[I]));
  3653. UTF8S := StringToUTF8(S);
  3654. FileWrite(FLogFileHandle, UTF8S[1], Length(UTF8S));
  3655. end;
  3656. finally
  3657. SL.Free;
  3658. end;
  3659. if Not WasOpen and Not KeepOpen then
  3660. CloseLog;
  3661. end;
  3662. end;
  3663. end;
  3664. procedure TJclSimpleLog.TimeWrite(Strings: TStrings; Indent: Integer = 0; KeepOpen: Boolean = true);
  3665. begin
  3666. if Assigned(Strings) then
  3667. TimeWrite(Strings.Text, Indent, KeepOpen);
  3668. end;
  3669. procedure TJclSimpleLog.WriteStamp(SeparatorLen: Integer = 0; KeepOpen: Boolean = true);
  3670. var
  3671. WasOpen: Boolean;
  3672. begin
  3673. if SeparatorLen <= 0 then
  3674. SeparatorLen := 40;
  3675. if LoggingActive then
  3676. begin
  3677. WasOpen := LogOpen;
  3678. if not LogOpen then
  3679. begin
  3680. OpenLog;
  3681. if LogOpen and not FLogWasEmpty then
  3682. Write(NativeLineBreak);
  3683. end;
  3684. if LogOpen then
  3685. begin
  3686. Write(StrRepeat('=', SeparatorLen), 0, True);
  3687. if DateTimeFormatStr = '' then
  3688. Write(Format('= %-*s =', [SeparatorLen - 4, DateTimeToStr(Now)]), 0, True)
  3689. else
  3690. Write(Format('= %-*s =', [SeparatorLen - 4, FormatDateTime( DateTimeFormatStr, Now)]), 0, True);
  3691. Write(StrRepeat('=', SeparatorLen), 0, True);
  3692. if Not WasOpen and Not KeepOpen then
  3693. CloseLog;
  3694. end;
  3695. end;
  3696. end;
  3697. procedure InitSimpleLog(const ALogFileName: string = ''; AOpenLog: Boolean = true);
  3698. begin
  3699. if Assigned(SimpleLog) then
  3700. FreeAndNil(SimpleLog);
  3701. SimpleLog := TJclSimpleLog.Create(ALogFileName);
  3702. if AOpenLog then
  3703. SimpleLog.OpenLog;
  3704. end;
  3705. {$ENDIF ~WINSCP}
  3706. function TJclFormatSettings.GetCurrencyDecimals: Byte;
  3707. begin
  3708. {$IFDEF RTL220_UP}
  3709. Result := FormatSettings.CurrencyDecimals;
  3710. {$ELSE}
  3711. Result := SysUtils.CurrencyDecimals;
  3712. {$ENDIF}
  3713. end;
  3714. function TJclFormatSettings.GetCurrencyFormat: Byte;
  3715. begin
  3716. {$IFDEF RTL220_UP}
  3717. Result := FormatSettings.CurrencyFormat;
  3718. {$ELSE}
  3719. Result := SysUtils.CurrencyFormat;
  3720. {$ENDIF}
  3721. end;
  3722. function TJclFormatSettings.GetCurrencyString: string;
  3723. begin
  3724. {$IFDEF RTL220_UP}
  3725. Result := FormatSettings.CurrencyString;
  3726. {$ELSE}
  3727. Result := SysUtils.CurrencyString;
  3728. {$ENDIF}
  3729. end;
  3730. function TJclFormatSettings.GetDateSeparator: Char;
  3731. begin
  3732. {$IFDEF RTL220_UP}
  3733. Result := FormatSettings.DateSeparator;
  3734. {$ELSE}
  3735. Result := SysUtils.DateSeparator;
  3736. {$ENDIF}
  3737. end;
  3738. function TJclFormatSettings.GetDayNamesHighIndex: Integer;
  3739. begin
  3740. {$IFDEF RTL220_UP}
  3741. Result := High(FormatSettings.LongDayNames);
  3742. {$ELSE}
  3743. Result := High(SysUtils.LongDayNames);
  3744. {$ENDIF}
  3745. end;
  3746. function TJclFormatSettings.GetDayNamesLowIndex: Integer;
  3747. begin
  3748. {$IFDEF RTL220_UP}
  3749. Result := Low(FormatSettings.LongDayNames);
  3750. {$ELSE}
  3751. Result := Low(SysUtils.LongDayNames);
  3752. {$ENDIF}
  3753. end;
  3754. function TJclFormatSettings.GetDecimalSeparator: Char;
  3755. begin
  3756. {$IFDEF RTL220_UP}
  3757. Result := FormatSettings.DecimalSeparator;
  3758. {$ELSE}
  3759. Result := SysUtils.DecimalSeparator;
  3760. {$ENDIF}
  3761. end;
  3762. function TJclFormatSettings.GetListSeparator: Char;
  3763. begin
  3764. {$IFDEF RTL220_UP}
  3765. Result := FormatSettings.ListSeparator;
  3766. {$ELSE}
  3767. Result := SysUtils.ListSeparator;
  3768. {$ENDIF}
  3769. end;
  3770. function TJclFormatSettings.GetLongDateFormat: string;
  3771. begin
  3772. {$IFDEF RTL220_UP}
  3773. Result := FormatSettings.LongDateFormat;
  3774. {$ELSE}
  3775. Result := SysUtils.LongDateFormat;
  3776. {$ENDIF}
  3777. end;
  3778. { TJclFormatSettings }
  3779. function TJclFormatSettings.GetLongDayNames(AIndex: Integer): string;
  3780. begin
  3781. {$IFDEF RTL220_UP}
  3782. Result := FormatSettings.LongDayNames[AIndex];
  3783. {$ELSE}
  3784. Result := SysUtils.LongDayNames[AIndex];
  3785. {$ENDIF}
  3786. end;
  3787. function TJclFormatSettings.GetLongMonthNames(AIndex: Integer): string;
  3788. begin
  3789. {$IFDEF RTL220_UP}
  3790. Result := FormatSettings.LongMonthNames[AIndex];
  3791. {$ELSE}
  3792. Result := SysUtils.LongMonthNames[AIndex];
  3793. {$ENDIF}
  3794. end;
  3795. function TJclFormatSettings.GetLongTimeFormat: string;
  3796. begin
  3797. {$IFDEF RTL220_UP}
  3798. Result := FormatSettings.LongTimeFormat;
  3799. {$ELSE}
  3800. Result := SysUtils.LongTimeFormat;
  3801. {$ENDIF}
  3802. end;
  3803. function TJclFormatSettings.GetMonthNamesHighIndex: Integer;
  3804. begin
  3805. {$IFDEF RTL220_UP}
  3806. Result := High(FormatSettings.LongMonthNames);
  3807. {$ELSE}
  3808. Result := High(SysUtils.LongMonthNames);
  3809. {$ENDIF}
  3810. end;
  3811. function TJclFormatSettings.GetMonthNamesLowIndex: Integer;
  3812. begin
  3813. {$IFDEF RTL220_UP}
  3814. Result := Low(FormatSettings.LongMonthNames);
  3815. {$ELSE}
  3816. Result := Low(SysUtils.LongMonthNames);
  3817. {$ENDIF}
  3818. end;
  3819. function TJclFormatSettings.GetNegCurrFormat: Byte;
  3820. begin
  3821. {$IFDEF RTL220_UP}
  3822. Result := FormatSettings.NegCurrFormat;
  3823. {$ELSE}
  3824. Result := SysUtils.NegCurrFormat;
  3825. {$ENDIF}
  3826. end;
  3827. function TJclFormatSettings.GetShortDateFormat: string;
  3828. begin
  3829. {$IFDEF RTL220_UP}
  3830. Result := FormatSettings.ShortDateFormat;
  3831. {$ELSE}
  3832. Result := SysUtils.ShortDateFormat;
  3833. {$ENDIF}
  3834. end;
  3835. function TJclFormatSettings.GetShortDayNames(AIndex: Integer): string;
  3836. begin
  3837. {$IFDEF RTL220_UP}
  3838. Result := FormatSettings.ShortDayNames[AIndex];
  3839. {$ELSE}
  3840. Result := SysUtils.ShortDayNames[AIndex];
  3841. {$ENDIF}
  3842. end;
  3843. function TJclFormatSettings.GetShortMonthNames(AIndex: Integer): string;
  3844. begin
  3845. {$IFDEF RTL220_UP}
  3846. Result := FormatSettings.ShortMonthNames[AIndex];
  3847. {$ELSE}
  3848. Result := SysUtils.ShortMonthNames[AIndex];
  3849. {$ENDIF}
  3850. end;
  3851. function TJclFormatSettings.GetShortTimeFormat: string;
  3852. begin
  3853. {$IFDEF RTL220_UP}
  3854. Result := FormatSettings.ShortTimeFormat;
  3855. {$ELSE}
  3856. Result := SysUtils.ShortTimeFormat;
  3857. {$ENDIF}
  3858. end;
  3859. function TJclFormatSettings.GetThousandSeparator: Char;
  3860. begin
  3861. {$IFDEF RTL220_UP}
  3862. Result := FormatSettings.ThousandSeparator;
  3863. {$ELSE}
  3864. Result := SysUtils.ThousandSeparator;
  3865. {$ENDIF}
  3866. end;
  3867. function TJclFormatSettings.GetTimeAMString: string;
  3868. begin
  3869. {$IFDEF RTL220_UP}
  3870. Result := FormatSettings.TimeAMString;
  3871. {$ELSE}
  3872. Result := SysUtils.TimeAMString;
  3873. {$ENDIF}
  3874. end;
  3875. function TJclFormatSettings.GetTimePMString: string;
  3876. begin
  3877. {$IFDEF RTL220_UP}
  3878. Result := FormatSettings.TimePMString;
  3879. {$ELSE}
  3880. Result := SysUtils.TimePMString;
  3881. {$ENDIF}
  3882. end;
  3883. function TJclFormatSettings.GetTimeSeparator: Char;
  3884. begin
  3885. {$IFDEF RTL220_UP}
  3886. Result := FormatSettings.TimeSeparator;
  3887. {$ELSE}
  3888. Result := SysUtils.TimeSeparator;
  3889. {$ENDIF}
  3890. end;
  3891. function TJclFormatSettings.GetTwoDigitYearCenturyWindow: Word;
  3892. begin
  3893. {$IFDEF RTL220_UP}
  3894. Result := FormatSettings.TwoDigitYearCenturyWindow;
  3895. {$ELSE}
  3896. Result := SysUtils.TwoDigitYearCenturyWindow;
  3897. {$ENDIF}
  3898. end;
  3899. procedure TJclFormatSettings.SetCurrencyDecimals(AValue: Byte);
  3900. begin
  3901. {$IFDEF RTL220_UP}
  3902. FormatSettings.CurrencyDecimals := AValue;
  3903. {$ELSE}
  3904. SysUtils.CurrencyDecimals := AValue;
  3905. {$ENDIF}
  3906. end;
  3907. procedure TJclFormatSettings.SetCurrencyFormat(const AValue: Byte);
  3908. begin
  3909. {$IFDEF RTL220_UP}
  3910. FormatSettings.CurrencyFormat := AValue;
  3911. {$ELSE}
  3912. SysUtils.CurrencyFormat := AValue;
  3913. {$ENDIF}
  3914. end;
  3915. procedure TJclFormatSettings.SetCurrencyString(AValue: string);
  3916. begin
  3917. {$IFDEF RTL220_UP}
  3918. FormatSettings.CurrencyString := AValue;
  3919. {$ELSE}
  3920. SysUtils.CurrencyString := AValue;
  3921. {$ENDIF}
  3922. end;
  3923. procedure TJclFormatSettings.SetDateSeparator(const AValue: Char);
  3924. begin
  3925. {$IFDEF RTL220_UP}
  3926. FormatSettings.DateSeparator := AValue;
  3927. {$ELSE}
  3928. SysUtils.DateSeparator := AValue;
  3929. {$ENDIF}
  3930. end;
  3931. procedure TJclFormatSettings.SetDecimalSeparator(AValue: Char);
  3932. begin
  3933. {$IFDEF RTL220_UP}
  3934. FormatSettings.DecimalSeparator := AValue;
  3935. {$ELSE}
  3936. SysUtils.DecimalSeparator := AValue;
  3937. {$ENDIF}
  3938. end;
  3939. procedure TJclFormatSettings.SetListSeparator(const AValue: Char);
  3940. begin
  3941. {$IFDEF RTL220_UP}
  3942. FormatSettings.ListSeparator := AValue;
  3943. {$ELSE}
  3944. SysUtils.ListSeparator := AValue;
  3945. {$ENDIF}
  3946. end;
  3947. procedure TJclFormatSettings.SetLongDateFormat(const AValue: string);
  3948. begin
  3949. {$IFDEF RTL220_UP}
  3950. FormatSettings.LongDateFormat := AValue;
  3951. {$ELSE}
  3952. SysUtils.LongDateFormat := AValue;
  3953. {$ENDIF}
  3954. end;
  3955. procedure TJclFormatSettings.SetLongTimeFormat(const AValue: string);
  3956. begin
  3957. {$IFDEF RTL220_UP}
  3958. FormatSettings.LongTimeFormat := AValue;
  3959. {$ELSE}
  3960. SysUtils.LongTimeFormat := AValue;
  3961. {$ENDIF}
  3962. end;
  3963. procedure TJclFormatSettings.SetNegCurrFormat(const AValue: Byte);
  3964. begin
  3965. {$IFDEF RTL220_UP}
  3966. FormatSettings.NegCurrFormat := AValue;
  3967. {$ELSE}
  3968. SysUtils.NegCurrFormat := AValue;
  3969. {$ENDIF}
  3970. end;
  3971. procedure TJclFormatSettings.SetShortDateFormat(AValue: string);
  3972. begin
  3973. {$IFDEF RTL220_UP}
  3974. FormatSettings.ShortDateFormat := AValue;
  3975. {$ELSE}
  3976. SysUtils.ShortDateFormat := AValue;
  3977. {$ENDIF}
  3978. end;
  3979. procedure TJclFormatSettings.SetShortTimeFormat(const AValue: string);
  3980. begin
  3981. {$IFDEF RTL220_UP}
  3982. FormatSettings.ShortTimeFormat := AValue;
  3983. {$ELSE}
  3984. SysUtils.ShortTimeFormat := AValue;
  3985. {$ENDIF}
  3986. end;
  3987. procedure TJclFormatSettings.SetThousandSeparator(AValue: Char);
  3988. begin
  3989. {$IFDEF RTL220_UP}
  3990. FormatSettings.TimeSeparator := AValue;
  3991. {$ELSE}
  3992. SysUtils.TimeSeparator := AValue;
  3993. {$ENDIF}
  3994. end;
  3995. procedure TJclFormatSettings.SetTimeAMString(const AValue: string);
  3996. begin
  3997. {$IFDEF RTL220_UP}
  3998. FormatSettings.TimeAMString := AValue;
  3999. {$ELSE}
  4000. SysUtils.TimeAMString := AValue;
  4001. {$ENDIF}
  4002. end;
  4003. procedure TJclFormatSettings.SetTimePMString(const AValue: string);
  4004. begin
  4005. {$IFDEF RTL220_UP}
  4006. FormatSettings.TimePMString := AValue;
  4007. {$ELSE}
  4008. SysUtils.TimePMString := AValue;
  4009. {$ENDIF}
  4010. end;
  4011. procedure TJclFormatSettings.SetTimeSeparator(const AValue: Char);
  4012. begin
  4013. {$IFDEF RTL220_UP}
  4014. FormatSettings.TimeSeparator := AValue;
  4015. {$ELSE}
  4016. SysUtils.TimeSeparator := AValue;
  4017. {$ENDIF}
  4018. end;
  4019. procedure TJclFormatSettings.SetTwoDigitYearCenturyWindow(const AValue: Word);
  4020. begin
  4021. {$IFDEF RTL220_UP}
  4022. FormatSettings.TwoDigitYearCenturyWindow:= AValue;
  4023. {$ELSE}
  4024. SysUtils.TwoDigitYearCenturyWindow:= AValue;
  4025. {$ENDIF}
  4026. end;
  4027. function VarIsNullEmpty(const V: Variant): Boolean;
  4028. begin
  4029. Result := VarIsNull(V) or VarIsEmpty(V);
  4030. end;
  4031. function VarIsNullEmptyBlank(const V: Variant): Boolean;
  4032. begin
  4033. Result := VarIsNull(V) or VarIsEmpty(V) or (VarToStr(V) = '');
  4034. end;
  4035. initialization
  4036. {$IFNDEF WINSCP}
  4037. SimpleLog := nil;
  4038. {$ENDIF ~WINSCP}
  4039. {$IFDEF UNITVERSIONING}
  4040. RegisterUnitVersion(HInstance, UnitVersioning);
  4041. {$ENDIF UNITVERSIONING}
  4042. finalization
  4043. {$IFDEF UNITVERSIONING}
  4044. UnregisterUnitVersion(HInstance);
  4045. {$ENDIF UNITVERSIONING}
  4046. {$IFDEF MSWINDOWS}
  4047. {$IFDEF THREADSAFE}
  4048. // The user must release shared memory blocks himself. We don't clean up his
  4049. // memory leaks and make it impossible to release the shared memory in other
  4050. // unit's finalization blocks.
  4051. MMFFinalized := True;
  4052. FreeAndNil(GlobalMMFHandleListCS);
  4053. {$ENDIF THREADSAFE}
  4054. {$ENDIF MSWINDOWS}
  4055. {$IFNDEF WINSCP}
  4056. if Assigned(SimpleLog) then
  4057. FreeAndNil(SimpleLog);
  4058. {$ENDIF ~WINSCP}
  4059. end.