Quick.Commons.pas 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055
  1. { ***************************************************************************
  2. Copyright (c) 2016-2020 Kike Pérez
  3. Unit : Quick.Commons
  4. Description : Common functions
  5. Author : Kike Pérez
  6. Version : 2.0
  7. Created : 14/07/2017
  8. Modified : 01/01/2021
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.Commons;
  22. {$i QuickLib.inc}
  23. interface
  24. uses
  25. Classes,
  26. SysUtils,
  27. Types,
  28. {$IFDEF MSWINDOWS}
  29. Windows,
  30. ShlObj,
  31. {$ENDIF MSWINDOWS}
  32. {$IFDEF FPC}
  33. Quick.Files,
  34. {$IFDEF LINUX}
  35. FileInfo,
  36. {$ENDIF}
  37. {$ELSE}
  38. IOUtils,
  39. {$ENDIF}
  40. {$IFDEF ANDROID}
  41. Androidapi.JNI.Os,
  42. Androidapi.Helpers,
  43. Androidapi.JNI.JavaTypes,
  44. Androidapi.JNI.GraphicsContentViewText,
  45. {$ENDIF}
  46. {$IFDEF IOS}
  47. iOSapi.UIKit,
  48. Posix.SysSysctl,
  49. Posix.StdDef,
  50. iOSapi.Foundation,
  51. Macapi.ObjectiveC,
  52. Macapi.Helpers,
  53. {$ENDIF}
  54. {$IFDEF OSX}
  55. Macapi.Foundation,
  56. Macapi.Helpers,
  57. FMX.Helpers.Mac,
  58. Macapi.ObjectiveC,
  59. {$ENDIF}
  60. {$IFDEF POSIX}
  61. Posix.Unistd,
  62. {$ENDIF}
  63. DateUtils;
  64. type
  65. TLogEventType = (etInfo, etSuccess, etWarning, etError, etDebug, etDone, etTrace, etCritical, etException);
  66. TLogVerbose = set of TLogEventType;
  67. const
  68. LOG_ONLYERRORS = [etInfo,etError];
  69. LOG_ERRORSANDWARNINGS = [etInfo,etWarning,etError];
  70. LOG_TRACE = [etInfo,etError,etWarning,etTrace];
  71. LOG_ALL = [etInfo, etSuccess, etWarning, etError, etDebug, etDone, etTrace, etCritical, etException];
  72. LOG_DEBUG = [etInfo,etSuccess,etWarning,etError,etDebug];
  73. {$IFDEF DELPHIXE7_UP}
  74. EventStr : array of string = ['INFO','SUCC','WARN','ERROR','DEBUG','TRACE'];
  75. {$ELSE}
  76. EventStr : array[0..5] of string = ('INFO','SUCC','WARN','ERROR','DEBUG','TRACE');
  77. {$ENDIF}
  78. type
  79. TPasswordComplexity = set of (pfIncludeNumbers,pfIncludeSigns);
  80. TEnvironmentPath = record
  81. EXEPATH : string;
  82. {$IFDEF MSWINDOWS}
  83. WINDOWS : string;
  84. SYSTEM : string;
  85. PROGRAMFILES : string;
  86. COMMONFILES : string;
  87. HOMEDRIVE : string;
  88. TEMP : string;
  89. USERPROFILE : string;
  90. INSTDRIVE : string;
  91. DESKTOP : string;
  92. STARTMENU : string;
  93. DESKTOP_ALLUSERS : string;
  94. STARTMENU_ALLUSERS : string;
  95. STARTUP : string;
  96. APPDATA : String;
  97. PROGRAMDATA : string;
  98. ALLUSERSPROFILE : string;
  99. {$ENDIF MSWINDOWS}
  100. end;
  101. {$IFNDEF FPC}
  102. TFileHelper = record helper for TFile
  103. {$IF DEFINED(MSWINDOWS) OR DEFINED(DELPHILINUX)}
  104. class function IsInUse(const FileName : string) : Boolean; static;
  105. {$ENDIF}
  106. class function GetSize(const FileName: String): Int64; static;
  107. end;
  108. TDirectoryHelper = record helper for TDirectory
  109. class function GetSize(const Path: String): Int64; static;
  110. end;
  111. {$ENDIF}
  112. {$IFDEF FPC}
  113. {$IFDEF LINUX}
  114. UINT = cardinal;
  115. {$ENDIF}
  116. PLASTINPUTINFO = ^LASTINPUTINFO;
  117. tagLASTINPUTINFO = record
  118. cbSize: UINT;
  119. dwTime: DWORD;
  120. end;
  121. LASTINPUTINFO = tagLASTINPUTINFO;
  122. TLastInputInfo = LASTINPUTINFO;
  123. type
  124. TCmdLineSwitchType = (clstValueNextParam, clstValueAppended);
  125. TCmdLineSwitchTypes = set of TCmdLineSwitchType;
  126. {$ENDIF}
  127. TCounter = record
  128. private
  129. fMaxValue : Integer;
  130. fCurrentValue : Integer;
  131. public
  132. property MaxValue : Integer read fMaxValue;
  133. procedure Init(aMaxValue : Integer);
  134. function Count : Integer;
  135. function CountIs(aValue : Integer) : Boolean;
  136. function Check : Boolean;
  137. procedure Reset;
  138. end;
  139. TTimeCounter = record
  140. private
  141. fCurrentTime : TDateTime;
  142. fDoneEvery : Integer;
  143. public
  144. property DoneEvery : Integer read fDoneEvery;
  145. procedure Init(MillisecondsToReach : Integer);
  146. function Check : Boolean;
  147. procedure Reset;
  148. end;
  149. {$IFNDEF FPC}
  150. {$IFNDEF DELPHIXE7_UP}
  151. TArrayUtil<T> = class
  152. class procedure Delete(var aArray : TArray<T>; aIndex : Integer);
  153. end;
  154. {$ENDIF}
  155. TArrayOfStringHelper = record helper for TArray<string>
  156. public
  157. function Any : Boolean; overload;
  158. function Any(const aValue : string) : Boolean; overload;
  159. function Add(const aValue : string) : Integer;
  160. function AddIfNotExists(const aValue : string; aCaseSense : Boolean = False) : Integer;
  161. function Remove(const aValue : string) : Boolean;
  162. function Exists(const aValue : string) : Boolean;
  163. function Count : Integer;
  164. end;
  165. TDelegate<T> = reference to procedure(Value : T);
  166. {$ENDIF}
  167. TPairItem = record
  168. Name : string;
  169. Value : string;
  170. constructor Create(const aName, aValue : string);
  171. end;
  172. TPairList = class
  173. type
  174. TPairEnumerator = class
  175. private
  176. fArray : ^TArray<TPairItem>;
  177. fIndex : Integer;
  178. function GetCurrent: TPairItem;
  179. public
  180. constructor Create(var aArray: TArray<TPairItem>);
  181. property Current : TPairItem read GetCurrent;
  182. function MoveNext: Boolean;
  183. end;
  184. private
  185. fItems : TArray<TPairItem>;
  186. public
  187. function GetEnumerator : TPairEnumerator;
  188. function GetValue(const aName : string) : string;
  189. function GetPair(const aName : string) : TPairItem;
  190. function Add(aPair : TPairItem) : Integer; overload;
  191. function Add(const aName, aValue : string) : Integer; overload;
  192. procedure AddOrUpdate(const aName, aValue : string);
  193. function Exists(const aName : string) : Boolean;
  194. function Remove(const aName : string) : Boolean;
  195. function Count : Integer;
  196. property Items[const aName : string] : string read GetValue write AddOrUpdate;
  197. function ToArray : TArray<TPairItem>;
  198. procedure FromArray(aValue : TArray<TPairItem>);
  199. procedure Clear;
  200. end;
  201. EEnvironmentPath = class(Exception);
  202. EShellError = class(Exception);
  203. //generates a random password with complexity options
  204. function RandomPassword(const PasswordLength : Integer; Complexity : TPasswordComplexity = [pfIncludeNumbers,pfIncludeSigns]) : string;
  205. //generates a random string
  206. function RandomString(const aLength: Integer) : string;
  207. //extracts file extension from a filename
  208. function ExtractFileNameWithoutExt(const FileName: string): string;
  209. //converts a Unix path to Windows path
  210. function UnixToWindowsPath(const UnixPath: string): string;
  211. //converts a Windows path to Unix path
  212. function WindowsToUnixPath(const WindowsPath: string): string;
  213. //corrects malformed urls
  214. function CorrectURLPath(cUrl : string) : string;
  215. //get typical environment paths as temp, desktop, etc
  216. procedure GetEnvironmentPaths;
  217. {$IFDEF MSWINDOWS}
  218. function GetSpecialFolderPath(folderID : Integer) : string;
  219. //checks if running on a 64bit OS
  220. function Is64bitOS : Boolean;
  221. //checks if is a console app
  222. function IsConsole : Boolean;
  223. function HasConsoleOutput : Boolean;
  224. //checks if compiled in debug mode
  225. {$ENDIF}
  226. function IsDebug : Boolean;
  227. {$IFDEF MSWINDOWS}
  228. //checks if running as a service
  229. function IsService : Boolean;
  230. //gets number of seconds without user interaction (mouse, keyboard)
  231. function SecondsIdle: DWord;
  232. //frees process memory not needed
  233. procedure FreeUnusedMem;
  234. //changes screen resolution
  235. function SetScreenResolution(Width, Height: integer): Longint;
  236. {$ENDIF MSWINDOWS}
  237. //returns last day of current month
  238. function LastDayCurrentMonth: TDateTime;
  239. {$IFDEF FPC}
  240. function DateTimeInRange(ADateTime: TDateTime; AStartDateTime, AEndDateTime: TDateTime; aInclusive: Boolean = True): Boolean;
  241. {$ENDIF}
  242. //checks if two datetimes are in same day
  243. function IsSameDay(cBefore, cNow : TDateTime) : Boolean;
  244. //change Time of a DateTime
  245. function ChangeTimeOfADay(aDate : TDateTime; aHour, aMinute, aSecond : Word; aMilliSecond : Word = 0) : TDateTime;
  246. //change Date of a DateTime
  247. function ChangeDateOfADay(aDate : TDateTime; aYear, aMonth, aDay : Word) : TDateTime;
  248. //returns n times a char
  249. function FillStr(const C : Char; const Count : Integer) : string;
  250. //checks if string exists in array of string
  251. function StrInArray(const aValue : string; const aInArray : array of string; aCaseSensitive : Boolean = True) : Boolean;
  252. //checks if integer exists in array of integer
  253. function IntInArray(const aValue : Integer; const aInArray : array of Integer) : Boolean;
  254. //check if array is empty
  255. function IsEmptyArray(aArray : TArray<string>) : Boolean; overload;
  256. function IsEmptyArray(aArray : TArray<Integer>) : Boolean; overload;
  257. //returns a number leading zero
  258. function Zeroes(const Number, Len : Int64) : string;
  259. //converts a number to thousand delimeter string
  260. function NumberToStr(const Number : Int64) : string;
  261. //returns n spaces
  262. function Spaces(const Count : Integer) : string;
  263. //returns current date as a string
  264. function NowStr : string;
  265. //returns a new GUID as string
  266. function NewGuidStr : string;
  267. //compare a string with a wildcard pattern (? or *)
  268. function IsLike(cText, Pattern: string) : Boolean;
  269. //Upper case for first letter
  270. function Capitalize(s: string): string;
  271. function CapitalizeWords(s: string): string;
  272. //returns current logged user
  273. function GetLoggedUserName : string;
  274. //returns computer name
  275. function GetComputerName : string;
  276. //check if remote desktop session
  277. {$IFDEF MSWINDOWS}
  278. function IsRemoteSession : Boolean;
  279. {$ENDIF}
  280. //extract domain and user name from user login
  281. function ExtractDomainAndUser(const aUser : string; out oDomain, oUser : string) : Boolean;
  282. //Changes incorrect delims in path
  283. function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
  284. //combine paths normalized with delim
  285. function CombinePaths(const aFirstPath, aSecondPath: string; aDelim : Char): string;
  286. //Removes firs segment of a path
  287. function RemoveFirstPathSegment(const cdir : string) : string;
  288. //Removes last segment of a path
  289. function RemoveLastPathSegment(const cDir : string) : string;
  290. //returns path delimiter if found
  291. function GetPathDelimiter(const aPath : string) : string;
  292. //returns first segment of a path
  293. function GetFirstPathSegment(const aPath : string) : string;
  294. //returns last segment of a path
  295. function GetLastPathSegment(const aPath : string) : string;
  296. //finds swith in commandline params
  297. function ParamFindSwitch(const Switch : string) : Boolean;
  298. //gets value for a switch if exists
  299. function ParamGetSwitch(const Switch : string; var cvalue : string) : Boolean;
  300. //returns app name (filename based)
  301. function GetAppName : string;
  302. //returns app version (major & minor)
  303. function GetAppVersionStr: string;
  304. //returns app version full (major, minor, release & compiled)
  305. function GetAppVersionFullStr: string;
  306. //convert UTC DateTime to Local DateTime
  307. function UTCToLocalTime(GMTTime: TDateTime): TDateTime;
  308. //convert Local DateTime to UTC DateTime
  309. function LocalTimeToUTC(LocalTime : TDateTime): TDateTime;
  310. //convert DateTime to GTM Time string
  311. function DateTimeToGMT(aDate : TDateTime) : string;
  312. //convert GMT Time string to DateTime
  313. function GMTToDateTime(aDate : string) : TDateTime;
  314. //convert DateTime to Json Date format
  315. function DateTimeToJsonDate(aDateTime : TDateTime) : string;
  316. //convert Json Date format to DateTime
  317. function JsonDateToDateTime(const aJsonDate : string) : TDateTime;
  318. //count number of digits of a Integer
  319. function CountDigits(anInt: Cardinal): Cardinal; inline;
  320. //count times a string is present in other string
  321. function CountStr(const aFindStr, aSourceStr : string) : Integer;
  322. //save stream to file
  323. procedure SaveStreamToFile(aStream : TStream; const aFilename : string);
  324. //save stream to string
  325. function StreamToString(const aStream: TStream; const aEncoding: TEncoding): string;
  326. function StreamToStringEx(aStream : TStream) : string;
  327. //save string to stream
  328. procedure StringToStream(const aStr : string; aStream : TStream; const aEncoding: TEncoding);
  329. procedure StringToStreamEx(const aStr : string; aStream : TStream);
  330. //returns a real comma separated text from stringlist
  331. function CommaText(aList : TStringList) : string; overload;
  332. //returns a real comma separated text from array of string
  333. function CommaText(aArray : TArray<string>) : string; overload;
  334. //returns a string CRLF from array of string
  335. function ArrayToString(aArray : TArray<string>) : string;
  336. //converts TStrings to array
  337. function StringsToArray(aStrings : TStrings) : TArray<string>;
  338. {$IFDEF MSWINDOWS}
  339. //process messages on console applications
  340. procedure ProcessMessages;
  341. //get last error message
  342. function GetLastOSError : String;
  343. {$ENDIF}
  344. {$IF DEFINED(FPC) AND DEFINED(MSWINDOWS)}
  345. function GetLastInputInfo(var plii: TLastInputInfo): BOOL;stdcall; external 'user32' name 'GetLastInputInfo';
  346. {$ENDIF}
  347. function RemoveLastChar(const aText : string) : string;
  348. function DateTimeToSQL(aDateTime : TDateTime) : string;
  349. function IsInteger(const aValue : string) : Boolean;
  350. function IsFloat(const aValue : string) : Boolean;
  351. function IsBoolean(const aValue : string) : Boolean;
  352. //extract a substring and deletes from source string
  353. function ExtractStr(var vSource : string; aIndex : Integer; aCount : Integer) : string;
  354. //get first string between string delimiters
  355. function GetSubString(const aSource, aFirstDelimiter, aLastDelimiter : string) : string;
  356. //get double quoted or dequoted string
  357. function DbQuotedStr(const str : string): string;
  358. function UnDbQuotedStr(const str: string) : string;
  359. //get simple quoted or dequoted string
  360. function SpQuotedStr(const str : string): string;
  361. function UnSpQuotedStr(const str : string): string;
  362. //ternary operator
  363. function Ifx(aCondition : Boolean; const aIfIsTrue, aIfIsFalse : string) : string; overload;
  364. function Ifx(aCondition : Boolean; const aIfIsTrue, aIfIsFalse : Integer) : Integer; overload;
  365. function Ifx(aCondition : Boolean; const aIfIsTrue, aIfIsFalse : Extended) : Extended; overload;
  366. function Ifx(aCondition : Boolean; const aIfIsTrue, aIfIsFalse : TObject) : TObject; overload;
  367. var
  368. path : TEnvironmentPath;
  369. //Enabled if QuickService is defined
  370. IsQuickServiceApp : Boolean;
  371. implementation
  372. {TFileHelper}
  373. {$IFNDEF FPC}
  374. {$IFDEF MSWINDOWS}
  375. class function TFileHelper.IsInUse(const FileName : string) : Boolean;
  376. var
  377. HFileRes: HFILE;
  378. begin
  379. Result := False;
  380. if not FileExists(FileName) then Exit;
  381. try
  382. HFileRes := CreateFile(PChar(FileName)
  383. ,GENERIC_READ or GENERIC_WRITE
  384. ,0
  385. ,nil
  386. ,OPEN_EXISTING
  387. ,FILE_ATTRIBUTE_NORMAL
  388. ,0);
  389. Result := (HFileRes = INVALID_HANDLE_VALUE);
  390. if not(Result) then begin
  391. CloseHandle(HFileRes);
  392. end;
  393. except
  394. Result := True;
  395. end;
  396. end;
  397. {$ENDIF}
  398. {$IFDEF DELPHILINUX}
  399. class function TFileHelper.IsInUse(const FileName : string) : Boolean;
  400. var
  401. fs : TFileStream;
  402. begin
  403. try
  404. fs := TFileStream.Create(FileName, fmOpenReadWrite, fmShareExclusive);
  405. Result := True;
  406. fs.Free;
  407. except
  408. Result := False;
  409. end;
  410. end;
  411. {$ENDIF}
  412. {$IFDEF MSWINDOWS}
  413. class function TFileHelper.GetSize(const FileName: String): Int64;
  414. var
  415. info: TWin32FileAttributeData;
  416. begin
  417. Result := -1;
  418. if not GetFileAttributesEx(PWideChar(FileName), GetFileExInfoStandard, @info) then Exit;
  419. Result := Int64(info.nFileSizeLow) or Int64(info.nFileSizeHigh shl 32);
  420. end;
  421. {$ELSE}
  422. class function TFileHelper.GetSize(const FileName: String): Int64;
  423. var
  424. sr : TSearchRec;
  425. begin
  426. if FindFirst(fileName, faAnyFile, sr ) = 0 then Result := sr.Size
  427. else Result := -1;
  428. end;
  429. {$ENDIF}
  430. {TDirectoryHelper}
  431. class function TDirectoryHelper.GetSize(const Path: String): Int64;
  432. var
  433. filename : string;
  434. begin
  435. Result := -1;
  436. for filename in TDirectory.GetFiles(Path) do
  437. begin
  438. Result := Result + TFile.GetSize(filename);
  439. end;
  440. end;
  441. {$ENDIF}
  442. {other functions}
  443. function RandomPassword(const PasswordLength : Integer; Complexity : TPasswordComplexity = [pfIncludeNumbers,pfIncludeSigns]) : string;
  444. const
  445. PassAlpha = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  446. PassSigns = '@!&$';
  447. PassNumbers = '1234567890';
  448. var
  449. MinNumbers,
  450. MinSigns : Integer;
  451. NumNumbers,
  452. NumSigns : Integer;
  453. begin
  454. Result := '';
  455. Randomize;
  456. //fill all alfa
  457. repeat
  458. Result := Result + PassAlpha[Random(Length(PassAlpha))+1];
  459. until (Length(Result) = PasswordLength);
  460. //checks if need include numbers
  461. if pfIncludeNumbers in Complexity then
  462. begin
  463. MinNumbers := Round(PasswordLength / 10 * 2);
  464. NumNumbers := 0;
  465. if MinNumbers = 0 then MinNumbers := 1;
  466. repeat
  467. Result[Random(PasswordLength)+1] := PassNumbers[Random(Length(PassNumbers))+1];
  468. Inc(NumNumbers);
  469. until NumNumbers = MinNumbers;
  470. end;
  471. //checks if need include signs
  472. if pfIncludeSigns in Complexity then
  473. begin
  474. MinSigns := Round(PasswordLength / 10 * 1);
  475. NumSigns := 0;
  476. if MinSigns = 0 then MinSigns := 1;
  477. repeat
  478. Result[Random(PasswordLength)+1] := PassSigns[Random(Length(PassSigns))+1];
  479. Inc(NumSigns);
  480. until NumSigns = MinSigns;
  481. end;
  482. end;
  483. function RandomString(const aLength: Integer) : string;
  484. const
  485. chars : string = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
  486. var
  487. i : Integer;
  488. clong : Integer;
  489. begin
  490. clong := High(chars);
  491. SetLength(Result, aLength);
  492. for i := 1 to aLength do
  493. begin
  494. Result[i] := chars[Random(clong) + 1];
  495. end;
  496. end;
  497. function ExtractFileNameWithoutExt(const FileName: string): string;
  498. begin
  499. Result := TPath.GetFileNameWithoutExtension(FileName);
  500. end;
  501. function UnixToWindowsPath(const UnixPath: string): string;
  502. begin
  503. Result := StringReplace(UnixPath, '/', '\',[rfReplaceAll, rfIgnoreCase]);
  504. end;
  505. function WindowsToUnixPath(const WindowsPath: string): string;
  506. begin
  507. Result := StringReplace(WindowsPath, '\', '/',[rfReplaceAll, rfIgnoreCase]);
  508. end;
  509. function CorrectURLPath(cUrl : string) : string;
  510. var
  511. nurl : string;
  512. begin
  513. nurl := WindowsToUnixPath(cUrl);
  514. nurl := StringReplace(nurl,'//','/',[rfReplaceAll]);
  515. Result := StringReplace(nurl,' ','%20',[rfReplaceAll]);
  516. //TNetEncoding.Url.Encode()
  517. end;
  518. procedure GetEnvironmentPaths;
  519. begin
  520. //gets path
  521. path.EXEPATH := TPath.GetDirectoryName(ParamStr(0));
  522. {$IFDEF MSWINDOWS}
  523. path.WINDOWS := SysUtils.GetEnvironmentVariable('windir');
  524. path.PROGRAMFILES := SysUtils.GetEnvironmentVariable('ProgramFiles');
  525. path.COMMONFILES := SysUtils.GetEnvironmentVariable('CommonProgramFiles(x86)');
  526. path.HOMEDRIVE := SysUtils.GetEnvironmentVariable('SystemDrive');
  527. path.USERPROFILE := SysUtils.GetEnvironmentVariable('USERPROFILE');
  528. path.PROGRAMDATA := SysUtils.GetEnvironmentVariable('ProgramData');
  529. path.ALLUSERSPROFILE := SysUtils.GetEnvironmentVariable('AllUsersProfile');
  530. path.INSTDRIVE := path.HOMEDRIVE;
  531. path.TEMP := SysUtils.GetEnvironmentVariable('TEMP');
  532. //these paths fail if user is SYSTEM
  533. try
  534. path.SYSTEM := GetSpecialFolderPath(CSIDL_SYSTEM);
  535. path.APPDATA := GetSpecialFolderPath(CSIDL_APPDATA);
  536. path.DESKTOP := GetSpecialFolderPath(CSIDL_DESKTOP);
  537. path.DESKTOP_ALLUSERS := GetSpecialFolderPath(CSIDL_COMMON_DESKTOPDIRECTORY);
  538. path.STARTMENU:=GetSpecialFolderPath(CSIDL_PROGRAMS);
  539. path.STARTMENU_ALLUSERS:=GetSpecialFolderPath(CSIDL_COMMON_PROGRAMS);
  540. path.STARTMENU_ALLUSERS := path.STARTMENU;
  541. path.STARTUP:=GetSpecialFolderPath(CSIDL_STARTUP);
  542. except
  543. //
  544. end;
  545. {$ENDIF}
  546. end;
  547. {$IFDEF MSWINDOWS}
  548. function GetSpecialFolderPath(folderID : Integer) : string;
  549. var
  550. ppidl: PItemIdList;
  551. begin
  552. SHGetSpecialFolderLocation(0, folderID, ppidl);
  553. SetLength(Result, MAX_PATH);
  554. if not SHGetPathFromIDList(ppidl,{$IFDEF FPC}PAnsiChar(Result){$ELSE}PChar(Result){$ENDIF}) then
  555. begin
  556. raise EShellError.create(Format('GetSpecialFolderPath: Invalid PIPL (%d)',[folderID]));
  557. end;
  558. SetLength(Result, lStrLen({$IFDEF FPC}PAnsiChar(Result){$ELSE}PChar(Result){$ENDIF}));
  559. end;
  560. function Is64bitOS : Boolean;
  561. begin
  562. {$IFDEF WIN64}
  563. Result := True;
  564. {$ELSE}
  565. Result := False;
  566. {$ENDIF WIN64}
  567. end;
  568. function IsConsole: Boolean;
  569. begin
  570. {$IFDEF CONSOLE}
  571. Result := True;
  572. {$ELSE}
  573. Result := False;
  574. {$ENDIF CONSOLE}
  575. end;
  576. {$ENDIF}
  577. function HasConsoleOutput : Boolean;
  578. {$IFDEF MSWINDOWS}
  579. var
  580. stout : THandle;
  581. begin
  582. try
  583. stout := GetStdHandle(Std_Output_Handle);
  584. Win32Check(stout <> Invalid_Handle_Value);
  585. Result := stout <> 0;
  586. except
  587. Result := False;
  588. end;
  589. end;
  590. {$ELSE}
  591. begin
  592. Result := IsConsole;
  593. end;
  594. {$ENDIF}
  595. function IsDebug: Boolean;
  596. begin
  597. {$IFDEF DEBUG}
  598. Result := True;
  599. {$ELSE}
  600. Result := False;
  601. {$ENDIF DEBUG}
  602. end;
  603. {$IFDEF MSWINDOWS}
  604. function IsService : Boolean;
  605. begin
  606. //only working with my Quick.AppService unit
  607. try
  608. Result := (IsConsole) and (not HasConsoleOutput);
  609. except
  610. Result := False;
  611. end;
  612. end;
  613. function SecondsIdle: DWord;
  614. var
  615. liInfo: TLastInputInfo;
  616. begin
  617. liInfo.cbSize := SizeOf(TLastInputInfo) ;
  618. GetLastInputInfo(liInfo) ;
  619. Result := (GetTickCount - liInfo.dwTime) DIV 1000;
  620. end;
  621. procedure FreeUnusedMem;
  622. begin
  623. if Win32Platform = VER_PLATFORM_WIN32_NT then SetProcessWorkingSetSize(GetCurrentProcess, $FFFFFFFF, $FFFFFFFF);
  624. end;
  625. function SetScreenResolution(Width, Height: integer): Longint;
  626. var
  627. DeviceMode: TDeviceMode;
  628. begin
  629. with DeviceMode do
  630. begin
  631. dmSize := SizeOf(TDeviceMode);
  632. dmPelsWidth := Width;
  633. dmPelsHeight := Height;
  634. dmFields := DM_PELSWIDTH or DM_PELSHEIGHT;
  635. end;
  636. Result := ChangeDisplaySettings(DeviceMode, CDS_UPDATEREGISTRY);
  637. end;
  638. {$ENDIF MSWINDOWS}
  639. function LastDayCurrentMonth: TDateTime;
  640. begin
  641. Result := EncodeDate(YearOf(Now),MonthOf(Now), DaysInMonth(Now));
  642. end;
  643. {$IFDEF FPC}
  644. function DateTimeInRange(ADateTime: TDateTime; AStartDateTime, AEndDateTime: TDateTime; aInclusive: Boolean = True): Boolean;
  645. begin
  646. if aInclusive then
  647. Result := (AStartDateTime <= ADateTime) and (ADateTime <= AEndDateTime)
  648. else
  649. Result := (AStartDateTime < ADateTime) and (ADateTime < AEndDateTime);
  650. end;
  651. {$ENDIF}
  652. function IsSameDay(cBefore, cNow : TDateTime) : Boolean;
  653. begin
  654. //Test: Result := MinutesBetween(cBefore,cNow) < 1;
  655. Result := DateTimeInRange(cNow,StartOfTheDay(cBefore),EndOfTheDay(cBefore),True);
  656. end;
  657. function ChangeTimeOfADay(aDate : TDateTime; aHour, aMinute, aSecond : Word; aMilliSecond : Word = 0) : TDateTime;
  658. var
  659. y, m, d : Word;
  660. begin
  661. DecodeDate(aDate,y,m,d);
  662. Result := EncodeDateTime(y,m,d,aHour,aMinute,aSecond,aMilliSecond);
  663. end;
  664. function ChangeDateOfADay(aDate : TDateTime; aYear, aMonth, aDay : Word) : TDateTime;
  665. var
  666. h, m, s, ms : Word;
  667. begin
  668. DecodeTime(aDate,h,m,s,ms);
  669. Result := EncodeDateTime(aYear,aMonth,aDay,h,m,s,0);
  670. end;
  671. function FillStr(const C : Char; const Count : Integer) : string;
  672. var
  673. i : Integer;
  674. begin
  675. Result := '';
  676. for i := 1 to Count do Result := Result + C;
  677. end;
  678. function StrInArray(const aValue : string; const aInArray : array of string; aCaseSensitive : Boolean = True) : Boolean;
  679. var
  680. s : string;
  681. begin
  682. for s in aInArray do
  683. begin
  684. if aCaseSensitive then
  685. begin
  686. if s = aValue then Exit(True);
  687. end
  688. else
  689. begin
  690. if CompareText(aValue,s) = 0 then Exit(True);
  691. end;
  692. end;
  693. Result := False;
  694. end;
  695. function IntInArray(const aValue : Integer; const aInArray : array of Integer) : Boolean;
  696. var
  697. i : Integer;
  698. begin
  699. for i in aInArray do
  700. begin
  701. if i = aValue then Exit(True);
  702. end;
  703. Result := False;
  704. end;
  705. function IsEmptyArray(aArray : TArray<string>) : Boolean;
  706. begin
  707. Result := Length(aArray) = 0;
  708. end;
  709. function IsEmptyArray(aArray : TArray<Integer>) : Boolean;
  710. begin
  711. Result := Length(aArray) = 0;
  712. end;
  713. function Zeroes(const Number, Len : Int64) : string;
  714. begin
  715. if Len > Length(IntToStr(Number)) then Result := FillStr('0',Len - Length(IntToStr(Number))) + IntToStr(Number)
  716. else Result := IntToStr(Number);
  717. end;
  718. function NumberToStr(const Number : Int64) : string;
  719. begin
  720. try
  721. Result := FormatFloat('0,',Number);
  722. except
  723. Result := '#Error';
  724. end;
  725. end;
  726. function Spaces(const Count : Integer) : string;
  727. begin
  728. Result := FillStr(' ',Count);
  729. end;
  730. function NowStr : string;
  731. begin
  732. Result := DateTimeToStr(Now());
  733. end;
  734. function NewGuidStr : string;
  735. {$IFNDEF DELPHIRX10_UP}
  736. var
  737. guid : TGUID;
  738. {$ENDIF}
  739. begin
  740. {$IFDEF DELPHIRX10_UP}
  741. Result := TGUID.NewGuid.ToString;
  742. {$ELSE}
  743. guid.NewGuid;
  744. Result := guid.ToString
  745. {$ENDIF}
  746. end;
  747. function IsLike(cText, Pattern: string) : Boolean;
  748. var
  749. i, n : Integer;
  750. match : Boolean;
  751. wildcard : Boolean;
  752. CurrentPattern : Char;
  753. begin
  754. Result := False;
  755. wildcard := False;
  756. cText := LowerCase(cText);
  757. Pattern := LowerCase(Pattern);
  758. match := False;
  759. if (Pattern.Length > cText.Length) or (Pattern = '') then Exit;
  760. if Pattern = '*' then
  761. begin
  762. Result := True;
  763. Exit;
  764. end;
  765. for i := 1 to cText.Length do
  766. begin
  767. CurrentPattern := Pattern[i];
  768. if CurrentPattern = '*' then wildcard := True;
  769. if wildcard then
  770. begin
  771. n := Pos(Copy(Pattern,i+1,Pattern.Length),cText);
  772. if (n > i) or (Pattern.Length = i) then
  773. begin
  774. Result := True;
  775. Exit;
  776. end;
  777. end
  778. else
  779. begin
  780. if (cText[i] = CurrentPattern) or (CurrentPattern = '?') then match := True
  781. else match := False;
  782. end;
  783. end;
  784. Result := match;
  785. end;
  786. function Capitalize(s: string): string;
  787. begin
  788. Result := '';
  789. if s.Length = 0 then Exit;
  790. s := LowerCase(s,loUserLocale);
  791. Result := UpperCase(s[1],loUserLocale) + Trim(Copy(s, 2, s.Length));
  792. end;
  793. function CapitalizeWords(s: string): string;
  794. var
  795. cword : string;
  796. begin
  797. Result := '';
  798. if s.Length = 0 then Exit;
  799. s := LowerCase(s,loUserLocale);
  800. for cword in s.Split([' ']) do
  801. begin
  802. if Result = '' then Result := Capitalize(cword)
  803. else Result := Result + ' ' + Capitalize(cword);
  804. end;
  805. end;
  806. function GetLoggedUserName : string;
  807. {$IFDEF MSWINDOWS}
  808. const
  809. cnMaxUserNameLen = 254;
  810. var
  811. sUserName : string;
  812. dwUserNameLen : DWord;
  813. begin
  814. dwUserNameLen := cnMaxUserNameLen-1;
  815. SetLength( sUserName, cnMaxUserNameLen );
  816. GetUserName(PChar( sUserName ),dwUserNameLen );
  817. SetLength( sUserName, dwUserNameLen );
  818. Result := sUserName;
  819. end;
  820. {$ELSE}
  821. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  822. begin
  823. Result := GetEnvironmentVariable('USERNAME');
  824. end;
  825. {$ELSE}
  826. var
  827. {$IFNDEF NEXTGEN}
  828. plogin : PAnsiChar;
  829. {$ELSE}
  830. plogin : MarshaledAString;
  831. {$ENDIF}
  832. begin
  833. {$IFDEF POSIX}
  834. try
  835. plogin := getlogin;
  836. Result := Copy(plogin,1,Length(Trim(plogin)));
  837. except
  838. Result := 'N/A';
  839. end;
  840. {$ELSE}
  841. Result := 'N/A';
  842. {$ENDIF}
  843. //raise ENotImplemented.Create('Not Android GetLoggedUserName implemented!');
  844. end;
  845. {$ENDIF}
  846. {$ENDIF}
  847. {$IFDEF IOS}
  848. function GetDeviceModel : String;
  849. var
  850. size : size_t;
  851. buffer : array of Byte;
  852. begin
  853. sysctlbyname('hw.machine',nil,@size,nil,0);
  854. if size > 0 then
  855. begin
  856. SetLength(buffer, size);
  857. sysctlbyname('hw.machine',@buffer[0],@size,nil,0);
  858. Result := UTF8ToString(MarshaledAString(buffer));
  859. end
  860. else Result := EmptyStr;
  861. end;
  862. {$ENDIF}
  863. function GetComputerName : string;
  864. {$IFDEF MSWINDOWS}
  865. var
  866. dwLength: dword;
  867. begin
  868. dwLength := 253;
  869. SetLength(Result, dwLength+1);
  870. if not Windows.GetComputerName(pchar(result), dwLength) then Result := 'Not detected!';
  871. Result := pchar(result);
  872. end;
  873. {$ELSE}
  874. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  875. begin
  876. Result := GetEnvironmentVariable('COMPUTERNAME');
  877. end;
  878. {$ELSE} //Android gets model name
  879. {$IFDEF NEXTGEN}
  880. begin
  881. {$IFDEF ANDROID}
  882. Result := JStringToString(TJBuild.JavaClass.MODEL);
  883. {$ELSE} //IOS
  884. Result := GetDeviceModel;
  885. {$ENDIF}
  886. end;
  887. {$ELSE}
  888. {$IFDEF DELPHILINUX}
  889. var
  890. phost : PAnsiChar;
  891. begin
  892. try
  893. phost := AllocMem(256);
  894. try
  895. if gethostname(phost,_SC_HOST_NAME_MAX) = 0 then
  896. begin
  897. {$IFDEF DEBUG}
  898. Result := Copy(Trim(phost),1,Length(Trim(phost)));
  899. {$ELSE}
  900. Result := Copy(phost,1,Length(phost));
  901. {$ENDIF}
  902. end
  903. else Result := 'N/A.';
  904. finally
  905. FreeMem(phost);
  906. end;
  907. except
  908. Result := 'N/A';
  909. end;
  910. end;
  911. {$ELSE} //OSX
  912. begin
  913. Result := NSStrToStr(TNSHost.Wrap(TNSHost.OCClass.currentHost).localizedName);
  914. end;
  915. {$ENDIF}
  916. {$ENDIF}
  917. {$ENDIF}
  918. {$ENDIF}
  919. {$IFDEF MSWINDOWS}
  920. function IsRemoteSession : Boolean;
  921. const
  922. SM_REMOTECONTROL = $2001;
  923. SM_REMOTESESSION = $1000;
  924. begin
  925. Result := (GetSystemMetrics(SM_REMOTESESSION) <> 0) or (GetSystemMetrics(SM_REMOTECONTROL) <> 0);
  926. end;
  927. {$ENDIF}
  928. function ExtractDomainAndUser(const aUser : string; out oDomain, oUser : string) : Boolean;
  929. begin
  930. //check if domain specified into username
  931. if aUser.Contains('\') then
  932. begin
  933. oDomain := Copy(aUser,Low(aUser),Pos('\',aUser)-1);
  934. oUser := Copy(aUser,Pos('\',aUser)+1,aUser.Length);
  935. Exit(True);
  936. end
  937. else if aUser.Contains('@') then
  938. begin
  939. oDomain := Copy(aUser,Pos('@',aUser)+1,aUser.Length);
  940. oUser := Copy(aUser,Low(aUser),Pos('@',aUser)-1);
  941. Exit(True);
  942. end;
  943. oDomain := '';
  944. oUser := aUser;
  945. Result := False;
  946. end;
  947. function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
  948. begin
  949. if Delim = '\' then Result := StringReplace(cPath,'/',Delim,[rfReplaceAll])
  950. else Result := StringReplace(cPath,'\',Delim,[rfReplaceAll]);
  951. end;
  952. function CombinePaths(const aFirstPath, aSecondPath: string; aDelim : Char): string;
  953. var
  954. path1 : string;
  955. path2 : string;
  956. begin
  957. path1 := NormalizePathDelim(aFirstPath,aDelim);
  958. path2 := NormalizePathDelim(aSecondPath,aDelim);
  959. if path1.EndsWith(aDelim) then
  960. begin
  961. if path2.StartsWith(aDelim) then Result := path1 + path2.Substring(1)
  962. else Result := path1 + path2;
  963. end
  964. else
  965. begin
  966. if path2.StartsWith(aDelim) then Result := path1 + path2
  967. else result := path1 + aDelim + path2;
  968. end;
  969. end;
  970. function RemoveFirstPathSegment(const cdir : string) : string;
  971. var
  972. posi : Integer;
  973. delim : Char;
  974. dir : string;
  975. StartsWithDelim : Boolean;
  976. begin
  977. if cDir.Contains('\') then delim := '\'
  978. else if cDir.Contains('/') then delim := '/'
  979. else
  980. begin
  981. Exit('');
  982. end;
  983. dir := NormalizePathDelim(cDir,delim);
  984. if dir.StartsWith(delim) then
  985. begin
  986. dir := Copy(dir,2,dir.Length);
  987. StartsWithDelim := True;
  988. end
  989. else StartsWithDelim := False;
  990. if dir.CountChar(delim) = 0 then Exit('')
  991. else posi := Pos(delim,dir)+1;
  992. Result := Copy(dir,posi,dir.Length);
  993. if (not Result.IsEmpty) and (StartsWithDelim) then Result := delim + Result;
  994. end;
  995. function RemoveLastPathSegment(const cDir : string) : string;
  996. var
  997. posi : Integer;
  998. delim : Char;
  999. dir : string;
  1000. EndsWithDelim : Boolean;
  1001. begin
  1002. if cDir.Contains('\') then delim := '\'
  1003. else if cDir.Contains('/') then delim := '/'
  1004. else
  1005. begin
  1006. Exit('');
  1007. end;
  1008. dir := NormalizePathDelim(cDir,delim);
  1009. if dir.EndsWith(delim) then
  1010. begin
  1011. dir := Copy(dir,1,dir.Length-1);
  1012. EndsWithDelim := True;
  1013. end
  1014. else EndsWithDelim := False;
  1015. if dir.CountChar(delim) > 1 then posi := dir.LastDelimiter(delim)
  1016. else posi := Pos(delim,dir)-1;
  1017. if posi = dir.Length then posi := 0;
  1018. Result := Copy(dir,1,posi);
  1019. if (not Result.IsEmpty) and (EndsWithDelim) then Result := Result + delim;
  1020. end;
  1021. function GetPathDelimiter(const aPath : string) : string;
  1022. begin
  1023. if aPath.Contains('/') then Result := '/'
  1024. else if aPath.Contains('\') then Result := '\'
  1025. else Result := '';
  1026. end;
  1027. function GetFirstPathSegment(const aPath : string) : string;
  1028. var
  1029. delimiter : string;
  1030. spath : string;
  1031. begin
  1032. delimiter := GetPathDelimiter(aPath);
  1033. if delimiter.IsEmpty then Exit(aPath);
  1034. if aPath.StartsWith(delimiter) then spath := Copy(aPath,2,aPath.Length)
  1035. else spath := aPath;
  1036. if spath.Contains(delimiter) then Result := Copy(spath,0,spath.IndexOf(delimiter))
  1037. else Result := spath;
  1038. end;
  1039. function GetLastPathSegment(const aPath : string) : string;
  1040. var
  1041. delimiter : string;
  1042. spath : string;
  1043. begin
  1044. delimiter := GetPathDelimiter(aPath);
  1045. if delimiter.IsEmpty then Exit(aPath);
  1046. if aPath.EndsWith(delimiter) then spath := Copy(aPath,0,aPath.Length - 1)
  1047. else spath := aPath;
  1048. Result := spath.Substring(spath.LastDelimiter(delimiter)+1);
  1049. end;
  1050. function ParamFindSwitch(const Switch : string) : Boolean;
  1051. begin
  1052. Result := FindCmdLineSwitch(Switch,['-', '/'],True);
  1053. end;
  1054. {$IFDEF FPC}
  1055. function FindCmdLineSwitch(const Switch: string; var Value: string; IgnoreCase: Boolean = True;
  1056. const SwitchTypes: TCmdLineSwitchTypes = [clstValueNextParam, clstValueAppended]): Boolean; overload;
  1057. type
  1058. TCompareProc = function(const S1, S2: string): Boolean;
  1059. var
  1060. Param: string;
  1061. I, ValueOfs,
  1062. SwitchLen, ParamLen: Integer;
  1063. SameSwitch: TCompareProc;
  1064. begin
  1065. Result := False;
  1066. Value := '';
  1067. if IgnoreCase then
  1068. SameSwitch := SameText else
  1069. SameSwitch := SameStr;
  1070. SwitchLen := Switch.Length;
  1071. for I := 1 to ParamCount do
  1072. begin
  1073. Param := ParamStr(I);
  1074. if CharInSet(Param.Chars[0], SwitchChars) and SameSwitch(Param.SubString(1,SwitchLen), Switch) then
  1075. begin
  1076. ParamLen := Param.Length;
  1077. // Look for an appended value if the param is longer than the switch
  1078. if (ParamLen > SwitchLen + 1) then
  1079. begin
  1080. // If not looking for appended value switches then this is not a matching switch
  1081. if not (clstValueAppended in SwitchTypes) then
  1082. Continue;
  1083. ValueOfs := SwitchLen + 1;
  1084. if Param.Chars[ValueOfs] = ':' then
  1085. Inc(ValueOfs);
  1086. Value := Param.SubString(ValueOfs, MaxInt);
  1087. end
  1088. // If the next param is not a switch, then treat it as the value
  1089. else if (clstValueNextParam in SwitchTypes) and (I < ParamCount) and
  1090. not CharInSet(ParamStr(I+1).Chars[0], SwitchChars) then
  1091. Value := ParamStr(I+1);
  1092. Result := True;
  1093. Break;
  1094. end;
  1095. end;
  1096. end;
  1097. {$ENDIF}
  1098. function ParamGetSwitch(const Switch : string; var cvalue : string) : Boolean;
  1099. begin
  1100. Result := FindCmdLineSwitch(Switch,cvalue,True,[clstValueAppended]);
  1101. end;
  1102. function GetAppName : string;
  1103. begin
  1104. Result := ExtractFilenameWithoutExt(ParamStr(0));
  1105. end;
  1106. function GetAppVersionStr: string;
  1107. {$IFDEF MSWINDOWS}
  1108. var
  1109. Rec: LongRec;
  1110. ver : Cardinal;
  1111. begin
  1112. ver := GetFileVersion(ParamStr(0));
  1113. if ver <> Cardinal(-1) then
  1114. begin
  1115. Rec := LongRec(ver);
  1116. Result := Format('%d.%d', [Rec.Hi, Rec.Lo]);
  1117. end
  1118. else Result := '';
  1119. end;
  1120. {$ELSE}
  1121. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  1122. var
  1123. version : TProgramVersion;
  1124. begin
  1125. if GetProgramVersion(version) then Result := Format('%d.%d', [version.Major, version.Minor])
  1126. else Result := '';
  1127. end;
  1128. {$ELSE}
  1129. {$IFDEF NEXTGEN}
  1130. {$IFDEF ANDROID}
  1131. var
  1132. PkgInfo : JPackageInfo;
  1133. begin
  1134. PkgInfo := SharedActivity.getPackageManager.getPackageInfo(SharedActivity.getPackageName,0);
  1135. Result := IntToStr(PkgInfo.VersionCode);
  1136. end;
  1137. {$ELSE} //IOS
  1138. var
  1139. AppKey: Pointer;
  1140. AppBundle: NSBundle;
  1141. BuildStr : NSString;
  1142. begin
  1143. try
  1144. AppKey := (StrToNSStr('CFBundleVersion') as ILocalObject).GetObjectID;
  1145. AppBundle := TNSBundle.Wrap(TNSBundle.OCClass.mainBundle);
  1146. BuildStr := TNSString.Wrap(AppBundle.infoDictionary.objectForKey(AppKey));
  1147. Result := UTF8ToString(BuildStr.UTF8String);
  1148. except
  1149. Result := '';
  1150. end;
  1151. end;
  1152. {$ENDIF}
  1153. {$ELSE} //OSX
  1154. {$IFDEF OSX}
  1155. var
  1156. AppKey: Pointer;
  1157. AppBundle: NSBundle;
  1158. BuildStr : NSString;
  1159. begin
  1160. try
  1161. AppKey := (StrToNSStr('CFBundleVersion') as ILocalObject).GetObjectID;
  1162. AppBundle := TNSBundle.Wrap(TNSBundle.OCClass.mainBundle);
  1163. BuildStr := TNSString.Wrap(AppBundle.infoDictionary.objectForKey(AppKey));
  1164. Result := UTF8ToString(BuildStr.UTF8String);
  1165. except
  1166. Result := '';
  1167. end;
  1168. end;
  1169. {$ELSE}
  1170. begin
  1171. Result := '';
  1172. end;
  1173. {$ENDIF}
  1174. {$ENDIF}
  1175. {$ENDIF}
  1176. {$ENDIF}
  1177. function GetAppVersionFullStr: string;
  1178. {$IFDEF MSWINDOWS}
  1179. var
  1180. Exe: string;
  1181. Size, Handle: DWORD;
  1182. Buffer: TBytes;
  1183. FixedPtr: PVSFixedFileInfo;
  1184. begin
  1185. Result := '';
  1186. Exe := ParamStr(0);
  1187. Size := GetFileVersionInfoSize(PChar(Exe), Handle);
  1188. if Size = 0 then
  1189. begin
  1190. //RaiseLastOSError;
  1191. //no version info in file
  1192. Exit;
  1193. end;
  1194. SetLength(Buffer, Size);
  1195. if not GetFileVersionInfo(PChar(Exe), Handle, Size, Buffer) then
  1196. RaiseLastOSError;
  1197. if not VerQueryValue(Buffer, '\', Pointer(FixedPtr), Size) then
  1198. RaiseLastOSError;
  1199. if (LongRec(FixedPtr.dwFileVersionLS).Hi = 0) and (LongRec(FixedPtr.dwFileVersionLS).Lo = 0) then
  1200. begin
  1201. Result := Format('%d.%d',
  1202. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  1203. LongRec(FixedPtr.dwFileVersionMS).Lo]); //minor
  1204. end
  1205. else if (LongRec(FixedPtr.dwFileVersionLS).Lo = 0) then
  1206. begin
  1207. Result := Format('%d.%d.%d',
  1208. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  1209. LongRec(FixedPtr.dwFileVersionMS).Lo, //minor
  1210. LongRec(FixedPtr.dwFileVersionLS).Hi]); //release
  1211. end
  1212. else
  1213. begin
  1214. Result := Format('%d.%d.%d.%d',
  1215. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  1216. LongRec(FixedPtr.dwFileVersionMS).Lo, //minor
  1217. LongRec(FixedPtr.dwFileVersionLS).Hi, //release
  1218. LongRec(FixedPtr.dwFileVersionLS).Lo]); //build
  1219. end;
  1220. end;
  1221. {$ELSE}
  1222. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  1223. var
  1224. version : TProgramVersion;
  1225. begin
  1226. if GetProgramVersion(version) then Result := Format('%d.%d.%d.%d', [version.Major, version.Minor, version.Revision, version.Build])
  1227. else Result := '';
  1228. end;
  1229. {$ELSE}
  1230. {$IFDEF NEXTGEN}
  1231. {$IFDEF ANDROID}
  1232. var
  1233. PkgInfo : JPackageInfo;
  1234. begin
  1235. PkgInfo := SharedActivity.getPackageManager.getPackageInfo(SharedActivity.getPackageName,0);
  1236. Result := JStringToString(PkgInfo.versionName);
  1237. end;
  1238. {$ELSE} //IOS
  1239. var
  1240. AppKey: Pointer;
  1241. AppBundle: NSBundle;
  1242. BuildStr : NSString;
  1243. begin
  1244. AppKey := (StrToNSStr('CFBundleVersion') as ILocalObject).GetObjectID;
  1245. AppBundle := TNSBundle.Wrap(TNSBundle.OCClass.mainBundle);
  1246. BuildStr := TNSString.Wrap(AppBundle.infoDictionary.objectForKey(AppKey));
  1247. Result := UTF8ToString(BuildStr.UTF8String);
  1248. end;
  1249. {$ENDIF}
  1250. {$ELSE}
  1251. {$IFDEF OSX}
  1252. var
  1253. AppKey: Pointer;
  1254. AppBundle: NSBundle;
  1255. BuildStr : NSString;
  1256. begin
  1257. AppKey := (StrToNSStr('CFBundleVersion') as ILocalObject).GetObjectID;
  1258. AppBundle := TNSBundle.Wrap(TNSBundle.OCClass.mainBundle);
  1259. BuildStr := TNSString.Wrap(AppBundle.infoDictionary.objectForKey(AppKey));
  1260. Result := UTF8ToString(BuildStr.UTF8String);
  1261. end;
  1262. {$ELSE}
  1263. begin
  1264. Result := '';
  1265. end;
  1266. {$ENDIF}
  1267. {$ENDIF}
  1268. {$ENDIF}
  1269. {$ENDIF}
  1270. function UTCToLocalTime(GMTTime: TDateTime): TDateTime;
  1271. begin
  1272. {$IFDEF FPC}
  1273. Result := LocalTimeToUniversal(GMTTime);
  1274. {$ELSE}
  1275. Result := TTimeZone.Local.ToLocalTime(GMTTime);
  1276. {$ENDIF}
  1277. end;
  1278. function LocalTimeToUTC(LocalTime : TDateTime): TDateTime;
  1279. begin
  1280. {$IFDEF FPC}
  1281. Result := UniversalTimeToLocal(Localtime);
  1282. {$ELSE}
  1283. Result := TTimeZone.Local.ToUniversalTime(LocalTime);
  1284. {$ENDIF}
  1285. end;
  1286. function DateTimeToGMT(aDate : TDateTime) : string;
  1287. var
  1288. FmtSettings : TFormatSettings;
  1289. begin
  1290. FmtSettings.DateSeparator := '-';
  1291. FmtSettings.TimeSeparator := ':';
  1292. FmtSettings.ShortDateFormat := 'YYYY-MM-DD"T"HH:NN:SS.ZZZ" GMT"';
  1293. Result := DateTimeToStr(aDate,FmtSettings).Trim;
  1294. end;
  1295. function GMTToDateTime(aDate : string) : TDateTime;
  1296. var
  1297. FmtSettings : TFormatSettings;
  1298. begin
  1299. FmtSettings.DateSeparator := '-';
  1300. FmtSettings.TimeSeparator := ':';
  1301. FmtSettings.ShortDateFormat := 'YYYY-MM-DD"T"HH:NN:SS.ZZZ" GMT"';
  1302. Result := StrToDateTime(aDate,FmtSettings);
  1303. end;
  1304. function DateTimeToJsonDate(aDateTime : TDateTime) : string;
  1305. {$IFNDEF DELPHIXE7_UP}
  1306. var
  1307. FmtSettings : TFormatSettings;
  1308. {$ENDIF}
  1309. begin
  1310. {$IFDEF DELPHIXE7_UP}
  1311. Result := DateToISO8601(aDateTime);
  1312. {$ELSE}
  1313. FmtSettings.DateSeparator := '-';
  1314. FmtSettings.TimeSeparator := ':';
  1315. FmtSettings.ShortDateFormat := 'YYYY-MM-DD"T"HH:NN:SS.ZZZ"Z"';
  1316. Result := DateTimeToStr(aDateTime,FmtSettings).Trim;
  1317. {$ENDIF}
  1318. end;
  1319. function JsonDateToDateTime(const aJsonDate : string) : TDateTime;
  1320. {$IFNDEF DELPHIXE7_UP}
  1321. var
  1322. FmtSettings : TFormatSettings;
  1323. {$ENDIF}
  1324. {$IFDEF FPC}
  1325. var
  1326. jdate : string;
  1327. {$ENDIF}
  1328. begin
  1329. {$IFDEF DELPHIXE7_UP}
  1330. Result := ISO8601ToDate(aJsonDate);
  1331. {$ELSE}
  1332. FmtSettings.DateSeparator := '-';
  1333. FmtSettings.TimeSeparator := ':';
  1334. FmtSettings.ShortDateFormat := 'YYYY-MM-DD"T"HH:NN:SS.ZZZ"Z"';
  1335. {$IFDEF FPC}
  1336. jdate := StringReplace(aJsondate,'T',' ',[rfIgnoreCase]);
  1337. jdate := Copy(jdate,1,Pos('.',jdate)-1);
  1338. Result := StrToDateTime(jdate,FmtSettings);
  1339. {$ELSE}
  1340. Result := StrToDateTime(aJsonDate,FmtSettings);
  1341. {$ENDIF}
  1342. {$ENDIF}
  1343. end;
  1344. function CountDigits(anInt: Cardinal): Cardinal; inline;
  1345. var
  1346. cmp: Cardinal;
  1347. begin
  1348. cmp := 10;
  1349. Result := 1;
  1350. while (Result < 10) and (cmp <= anInt) do
  1351. begin
  1352. cmp := cmp*10;
  1353. Inc(Result);
  1354. end;
  1355. end;
  1356. function CountStr(const aFindStr, aSourceStr : string) : Integer;
  1357. var
  1358. i : Integer;
  1359. found : Integer;
  1360. findstr : string;
  1361. mainstr : string;
  1362. begin
  1363. findstr := aFindStr.ToLower;
  1364. mainstr := aSourceStr.ToLower;
  1365. Result := 0;
  1366. i := 0;
  1367. while i < mainstr.Length do
  1368. begin
  1369. found := Pos(findstr,mainstr,i);
  1370. if found > 0 then
  1371. begin
  1372. i := found;
  1373. Inc(Result);
  1374. end
  1375. else Break;
  1376. end;
  1377. end;
  1378. procedure SaveStreamToFile(aStream : TStream; const aFileName : string);
  1379. var
  1380. fs : TFileStream;
  1381. begin
  1382. fs := TFileStream.Create(aFileName,fmCreate);
  1383. try
  1384. aStream.Seek(0,soBeginning);
  1385. fs.CopyFrom(aStream,aStream.Size);
  1386. finally
  1387. fs.Free;
  1388. end;
  1389. end;
  1390. function StreamToString(const aStream: TStream; const aEncoding: TEncoding): string;
  1391. var
  1392. sbytes: TBytes;
  1393. begin
  1394. aStream.Position := 0;
  1395. SetLength(sbytes, aStream.Size);
  1396. aStream.ReadBuffer(sbytes,aStream.Size);
  1397. Result := aEncoding.GetString(sbytes);
  1398. end;
  1399. function StreamToStringEx(aStream : TStream) : string;
  1400. var
  1401. ss : TStringStream;
  1402. begin
  1403. aStream.Position := 0;
  1404. if aStream = nil then Exit;
  1405. if aStream is TMemoryStream then
  1406. begin
  1407. SetString(Result, PChar(TMemoryStream(aStream).Memory), TMemoryStream(aStream).Size div SizeOf(Char));
  1408. end
  1409. else if aStream is TStringStream then
  1410. begin
  1411. Result := TStringStream(aStream).DataString;
  1412. end
  1413. else
  1414. begin
  1415. ss := TStringStream.Create;
  1416. try
  1417. aStream.Seek(0,soBeginning);
  1418. ss.CopyFrom(aStream,aStream.Size);
  1419. Result := ss.DataString;
  1420. finally
  1421. ss.Free;
  1422. end;
  1423. end;
  1424. end;
  1425. procedure StringToStream(const aStr : string; aStream : TStream; const aEncoding: TEncoding);
  1426. var
  1427. stream : TStringStream;
  1428. begin
  1429. stream := TStringStream.Create(aStr,aEncoding);
  1430. try
  1431. aStream.CopyFrom(stream,stream.Size);
  1432. finally
  1433. stream.Free;
  1434. end;
  1435. end;
  1436. procedure StringToStreamEx(const aStr : string; aStream : TStream);
  1437. begin
  1438. aStream.Seek(0,soBeginning);
  1439. aStream.WriteBuffer(Pointer(aStr)^,aStr.Length * SizeOf(Char));
  1440. end;
  1441. function CommaText(aList : TStringList) : string;
  1442. var
  1443. value : string;
  1444. sb : TStringBuilder;
  1445. begin
  1446. if aList.Text = '' then Exit;
  1447. sb := TStringBuilder.Create;
  1448. try
  1449. for value in aList do
  1450. begin
  1451. sb.Append(value);
  1452. sb.Append(',');
  1453. end;
  1454. if sb.Length > 1 then Result := sb.ToString(0, sb.Length - 1);
  1455. finally
  1456. sb.Free;
  1457. end;
  1458. end;
  1459. function CommaText(aArray : TArray<string>) : string;
  1460. var
  1461. value : string;
  1462. sb : TStringBuilder;
  1463. begin
  1464. if High(aArray) < 0 then Exit;
  1465. sb := TStringBuilder.Create;
  1466. try
  1467. for value in aArray do
  1468. begin
  1469. sb.Append(value);
  1470. sb.Append(',');
  1471. end;
  1472. if sb.Length > 1 then Result := sb.ToString(0, sb.Length - 1);
  1473. finally
  1474. sb.Free;
  1475. end;
  1476. end;
  1477. function ArrayToString(aArray : TArray<string>) : string;
  1478. var
  1479. value : string;
  1480. sb : TStringBuilder;
  1481. begin
  1482. if High(aArray) < 0 then Exit;
  1483. sb := TStringBuilder.Create;
  1484. try
  1485. for value in aArray do
  1486. begin
  1487. sb.Append(value);
  1488. sb.Append(#10#13);
  1489. end;
  1490. finally
  1491. sb.Free;
  1492. end;
  1493. end;
  1494. function StringsToArray(aStrings : TStrings) : TArray<string>;
  1495. var
  1496. i : Integer;
  1497. begin
  1498. if aStrings.Count = 0 then Exit;
  1499. SetLength(Result,aStrings.Count);
  1500. for i := 0 to aStrings.Count - 1 do
  1501. begin
  1502. Result[i] := aStrings[i];
  1503. end;
  1504. end;
  1505. { TCounter }
  1506. procedure TCounter.Init(aMaxValue : Integer);
  1507. begin
  1508. fMaxValue := aMaxValue;
  1509. fCurrentValue := 0;
  1510. end;
  1511. function TCounter.Count : Integer;
  1512. begin
  1513. Result := fCurrentValue;
  1514. end;
  1515. function TCounter.CountIs(aValue : Integer) : Boolean;
  1516. begin
  1517. Result := fCurrentValue = aValue;
  1518. end;
  1519. function TCounter.Check : Boolean;
  1520. begin
  1521. if fCurrentValue = fMaxValue then
  1522. begin
  1523. Result := True;
  1524. Reset;
  1525. end
  1526. else
  1527. begin
  1528. Result := False;
  1529. Inc(fCurrentValue);
  1530. end;
  1531. end;
  1532. procedure TCounter.Reset;
  1533. begin
  1534. fCurrentValue := fMaxValue;
  1535. end;
  1536. { TimeCounter }
  1537. procedure TTimeCounter.Init(MillisecondsToReach : Integer);
  1538. begin
  1539. fDoneEvery := MillisecondsToReach;
  1540. end;
  1541. function TTimeCounter.Check : Boolean;
  1542. begin
  1543. if MilliSecondsBetween(fCurrentTime,Now) > fDoneEvery then
  1544. begin
  1545. fCurrentTime := Now();
  1546. Result := True;
  1547. end
  1548. else Result := False;
  1549. end;
  1550. procedure TTimeCounter.Reset;
  1551. begin
  1552. fCurrentTime := Now();
  1553. end;
  1554. { TArrayOfStringHelper}
  1555. {$IFNDEF FPC}
  1556. function TArrayOfStringHelper.Any : Boolean;
  1557. begin
  1558. Result := High(Self) >= 0;
  1559. end;
  1560. function TArrayOfStringHelper.Any(const aValue : string) : Boolean;
  1561. begin
  1562. Result := Exists(aValue);
  1563. end;
  1564. function TArrayOfStringHelper.Add(const aValue : string) : Integer;
  1565. begin
  1566. SetLength(Self,Length(Self)+1);
  1567. Self[High(Self)] := aValue;
  1568. Result := High(Self);
  1569. end;
  1570. function TArrayOfStringHelper.AddIfNotExists(const aValue : string; aCaseSense : Boolean = False) : Integer;
  1571. var
  1572. i : Integer;
  1573. begin
  1574. for i := Low(Self) to High(Self) do
  1575. begin
  1576. if aCaseSense then
  1577. begin
  1578. if Self[i] = aValue then Exit(i);
  1579. end
  1580. else
  1581. begin
  1582. if CompareText(Self[i],aValue) = 0 then Exit(i)
  1583. end;
  1584. end;
  1585. //if not exists add it
  1586. Result := Self.Add(aValue);
  1587. end;
  1588. function TArrayOfStringHelper.Remove(const aValue : string) : Boolean;
  1589. var
  1590. i : Integer;
  1591. begin
  1592. for i := Low(Self) to High(Self) do
  1593. begin
  1594. if CompareText(Self[i],aValue) = 0 then
  1595. begin
  1596. {$IFDEF DELPHIXE7_UP}
  1597. System.Delete(Self,i,1);
  1598. {$ELSE}
  1599. TArrayUtil<string>.Delete(Self,i);
  1600. {$ENDIF}
  1601. Exit(True);
  1602. end;
  1603. end;
  1604. Result := False;
  1605. end;
  1606. function TArrayOfStringHelper.Exists(const aValue : string) : Boolean;
  1607. var
  1608. value : string;
  1609. begin
  1610. Result := False;
  1611. for value in Self do
  1612. begin
  1613. if CompareText(value,aValue) = 0 then Exit(True)
  1614. end;
  1615. end;
  1616. function TArrayOfStringHelper.Count : Integer;
  1617. begin
  1618. Result := High(Self) + 1;
  1619. end;
  1620. {$ENDIF}
  1621. { TPairItem }
  1622. constructor TPairItem.Create(const aName, aValue: string);
  1623. begin
  1624. Name := aName;
  1625. Value := aValue;
  1626. end;
  1627. { TPairList }
  1628. function TPairList.GetEnumerator : TPairEnumerator;
  1629. begin
  1630. Result := TPairEnumerator.Create(fItems);
  1631. end;
  1632. function TPairList.Add(aPair: TPairItem): Integer;
  1633. begin
  1634. SetLength(fItems,Length(fItems)+1);
  1635. fItems[High(fItems)] := aPair;
  1636. Result := High(fItems);
  1637. end;
  1638. function TPairList.Add(const aName, aValue: string): Integer;
  1639. begin
  1640. SetLength(fItems,Length(fItems)+1);
  1641. fItems[High(fItems)].Name := aName;
  1642. fItems[High(fItems)].Value := aValue;
  1643. Result := High(fItems);
  1644. end;
  1645. procedure TPairList.AddOrUpdate(const aName, aValue: string);
  1646. var
  1647. i : Integer;
  1648. begin
  1649. for i := Low(fItems) to High(fItems) do
  1650. begin
  1651. if CompareText(fItems[i].Name,aName) = 0 then
  1652. begin
  1653. fItems[i].Value := aValue;
  1654. Exit;
  1655. end;
  1656. end;
  1657. //if not exists add it
  1658. Self.Add(aName,aValue);
  1659. end;
  1660. function TPairList.Count: Integer;
  1661. begin
  1662. Result := High(fItems) + 1;
  1663. end;
  1664. function TPairList.Exists(const aName: string): Boolean;
  1665. var
  1666. i : Integer;
  1667. begin
  1668. Result := False;
  1669. for i := Low(fItems) to High(fItems) do
  1670. begin
  1671. if CompareText(fItems[i].Name,aName) = 0 then Exit(True)
  1672. end;
  1673. end;
  1674. function TPairList.GetPair(const aName: string): TPairItem;
  1675. var
  1676. i : Integer;
  1677. begin
  1678. for i := Low(fItems) to High(fItems) do
  1679. begin
  1680. if CompareText(fItems[i].Name,aName) = 0 then Exit(fItems[i]);
  1681. end;
  1682. end;
  1683. function TPairList.GetValue(const aName: string): string;
  1684. var
  1685. i : Integer;
  1686. begin
  1687. Result := '';
  1688. for i := Low(fItems) to High(fItems) do
  1689. begin
  1690. if CompareText(fItems[i].Name,aName) = 0 then Exit(fItems[i].Value);
  1691. end;
  1692. end;
  1693. function TPairList.Remove(const aName: string): Boolean;
  1694. var
  1695. i : Integer;
  1696. begin
  1697. for i := Low(fItems) to High(fItems) do
  1698. begin
  1699. if CompareText(fItems[i].Name,aName) = 0 then
  1700. begin
  1701. {$IF Defined(DELPHIXE7_UP) OR Defined(FPC)}
  1702. System.Delete(fItems,i,1);
  1703. {$ELSE}
  1704. TArrayUtil<TPairItem>.Delete(fItems,i);
  1705. {$ENDIF}
  1706. Exit(True);
  1707. end;
  1708. end;
  1709. Result := False;
  1710. end;
  1711. function TPairList.ToArray : TArray<TPairItem>;
  1712. begin
  1713. Result := fItems;
  1714. end;
  1715. procedure TPairList.FromArray(aValue : TArray<TPairItem>);
  1716. begin
  1717. fItems := aValue;
  1718. end;
  1719. procedure TPairList.Clear;
  1720. begin
  1721. SetLength(fItems,0);
  1722. end;
  1723. { TPairList.TPairEnumerator}
  1724. constructor TPairList.TPairEnumerator.Create(var aArray: TArray<TPairItem>);
  1725. begin
  1726. fIndex := -1;
  1727. fArray := @aArray;
  1728. end;
  1729. function TPairList.TPairEnumerator.GetCurrent : TPairItem;
  1730. begin
  1731. Result := TArray<TPairItem>(fArray^)[fIndex];
  1732. end;
  1733. function TPairList.TPairEnumerator.MoveNext: Boolean;
  1734. begin
  1735. Inc(fIndex);
  1736. Result := fIndex < High(TArray<TPairItem>(fArray^))+1;
  1737. end;
  1738. {$IFDEF MSWINDOWS}
  1739. procedure ProcessMessages;
  1740. var
  1741. Msg: TMsg;
  1742. begin
  1743. while integer(PeekMessage(Msg, 0, 0, 0, PM_REMOVE)) <> 0 do
  1744. begin
  1745. TranslateMessage(Msg);
  1746. DispatchMessage(Msg);
  1747. end;
  1748. end;
  1749. function GetLastOSError: String;
  1750. begin
  1751. Result := SysErrorMessage(Windows.GetLastError);
  1752. end;
  1753. {$ENDIF}
  1754. function RemoveLastChar(const aText : string) : string;
  1755. begin
  1756. Result := aText.Remove(aText.Length - 1);
  1757. end;
  1758. function DateTimeToSQL(aDateTime : TDateTime) : string;
  1759. begin
  1760. Result := FormatDateTime('YYYYMMDD hh:mm:ss',aDateTime);
  1761. end;
  1762. function IsInteger(const aValue : string) : Boolean;
  1763. var
  1764. i : Integer;
  1765. begin
  1766. Result := TryStrToInt(aValue,i);
  1767. end;
  1768. function IsFloat(const aValue : string) : Boolean;
  1769. var
  1770. e : Extended;
  1771. begin
  1772. Result := TryStrToFloat(aValue,e);
  1773. end;
  1774. function IsBoolean(const aValue : string) : Boolean;
  1775. var
  1776. b : Boolean;
  1777. begin
  1778. Result := TryStrToBool(aValue,b);
  1779. end;
  1780. function ExtractStr(var vSource : string; aIndex : Integer; aCount : Integer) : string;
  1781. begin
  1782. if aIndex > vSource.Length then Exit('');
  1783. Result := Copy(vSource,aIndex,aCount);
  1784. Delete(vSource,aIndex,aCount);
  1785. end;
  1786. function GetSubString(const aSource, aFirstDelimiter, aLastDelimiter : string) : string;
  1787. var
  1788. i : Integer;
  1789. begin
  1790. i := Pos(aFirstDelimiter,aSource);
  1791. if i > -1 then Result := Copy(aSource, i + aFirstDelimiter.Length, Pos(aLastDelimiter, aSource, i + aFirstDelimiter.Length) - i - aFirstDelimiter.Length)
  1792. else Result := '';
  1793. end;
  1794. function DbQuotedStr(const str : string): string;
  1795. var
  1796. i : Integer;
  1797. begin
  1798. Result := str;
  1799. for i := Result.Length - 1 downto 0 do
  1800. begin
  1801. if Result.Chars[i] = '"' then Result := Result.Insert(i, '"');
  1802. end;
  1803. Result := '"' + Result + '"';
  1804. end;
  1805. function UnDbQuotedStr(const str: string) : string;
  1806. begin
  1807. Result := Trim(str);
  1808. if not Result.IsEmpty then
  1809. begin
  1810. if Result.StartsWith('"') then Result := Copy(Result, 2, Result.Length - 2);
  1811. end;
  1812. end;
  1813. function SpQuotedStr(const str : string): string;
  1814. begin
  1815. Result := '''' + str + '''';
  1816. end;
  1817. function UnSpQuotedStr(const str: string) : string;
  1818. begin
  1819. Result := Trim(str);
  1820. if not Result.IsEmpty then
  1821. begin
  1822. if Result.StartsWith('''') then Result := Copy(Result, 2, Result.Length - 2);
  1823. end;
  1824. end;
  1825. function Ifx(aCondition : Boolean; const aIfIsTrue, aIfIsFalse : string) : string;
  1826. begin
  1827. if aCondition then Result := aIfIsTrue else Result := aIfIsFalse;
  1828. end;
  1829. function Ifx(aCondition : Boolean; const aIfIsTrue, aIfIsFalse : Integer) : Integer;
  1830. begin
  1831. if aCondition then Result := aIfIsTrue else Result := aIfIsFalse;
  1832. end;
  1833. function Ifx(aCondition : Boolean; const aIfIsTrue, aIfIsFalse : Extended) : Extended;
  1834. begin
  1835. if aCondition then Result := aIfIsTrue else Result := aIfIsFalse;
  1836. end;
  1837. function Ifx(aCondition : Boolean; const aIfIsTrue, aIfIsFalse : TObject) : TObject;
  1838. begin
  1839. if aCondition then Result := aIfIsTrue else Result := aIfIsFalse;
  1840. end;
  1841. {$IFNDEF FPC}
  1842. {$IFNDEF DELPHIXE7_UP}
  1843. class procedure TArrayUtil<T>.Delete(var aArray : TArray<T>; aIndex : Integer);
  1844. var
  1845. n : Integer;
  1846. len : Integer;
  1847. begin
  1848. len := Length(aArray);
  1849. if (len > 0) and (aIndex < len) then
  1850. begin
  1851. for n := aIndex + 1 to len - 1 do aArray[n - 1] := aArray[n];
  1852. SetLength(aArray, len - 1);
  1853. end;
  1854. end;
  1855. {$ENDIF}
  1856. {$ENDIF}
  1857. {$IFNDEF NEXTGEN}
  1858. initialization
  1859. try
  1860. GetEnvironmentPaths;
  1861. except
  1862. {$IFDEF SHOW_ENVIRONMENTPATH_ERRORS}
  1863. on E : Exception do
  1864. begin
  1865. if not IsService then
  1866. begin
  1867. if HasConsoleOutput then Writeln(Format('[WARN] GetEnvironmentPaths: %s',[E.Message]))
  1868. else MessageBox(0,PWideChar(Format('Get environment path error: %s',[E.Message])),'GetEnvironmentPaths',MB_ICONEXCLAMATION);
  1869. end;
  1870. end;
  1871. {$ENDIF}
  1872. end;
  1873. {$ENDIF}
  1874. end.