Quick.Commons.pas 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441
  1. { ***************************************************************************
  2. Copyright (c) 2016-2019 Kike Pérez
  3. Unit : Quick.Commons
  4. Description : Common functions
  5. Author : Kike Pérez
  6. Version : 1.8
  7. Created : 14/07/2017
  8. Modified : 27/08/2019
  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, etTrace);
  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,etTrace];
  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. {$IFDEF MSWINDOWS}
  81. TEnvironmentPath = record
  82. EXEPATH : string;
  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. end;
  100. {$ENDIF MSWINDOWS}
  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. EEnvironmentPath = class(Exception);
  150. EShellError = class(Exception);
  151. //generates a random password with complexity options
  152. function RandomPassword(const PasswordLength : Integer; Complexity : TPasswordComplexity = [pfIncludeNumbers,pfIncludeSigns]) : string;
  153. //extracts file extension from a filename
  154. function ExtractFileNameWithoutExt(const FileName: string): string;
  155. //converts a Unix path to Windows path
  156. function UnixToWindowsPath(const UnixPath: string): string;
  157. //converts a Windows path to Unix path
  158. function WindowsToUnixPath(const WindowsPath: string): string;
  159. //corrects malformed urls
  160. function CorrectURLPath(cUrl : string) : string;
  161. {$IFDEF MSWINDOWS}
  162. //get typical environment paths as temp, desktop, etc
  163. procedure GetEnvironmentPaths;
  164. function GetSpecialFolderPath(folderID : Integer) : string;
  165. //checks if running on a 64bit OS
  166. function Is64bitOS : Boolean;
  167. //checks if is a console app
  168. function IsConsole : Boolean;
  169. function HasConsoleOutput : Boolean;
  170. //checks if compiled in debug mode
  171. {$ENDIF}
  172. function IsDebug : Boolean;
  173. {$IFDEF MSWINDOWS}
  174. //checks if running as a service
  175. function IsService : Boolean;
  176. //gets number of seconds without user interaction (mouse, keyboard)
  177. function SecondsIdle: DWord;
  178. //frees process memory not needed
  179. procedure FreeUnusedMem;
  180. //changes screen resolution
  181. function SetScreenResolution(Width, Height: integer): Longint;
  182. {$ENDIF MSWINDOWS}
  183. //returns last day of current month
  184. function LastDayCurrentMonth: TDateTime;
  185. {$IFDEF FPC}
  186. function DateTimeInRange(ADateTime: TDateTime; AStartDateTime, AEndDateTime: TDateTime; aInclusive: Boolean = True): Boolean;
  187. {$ENDIF}
  188. //checks if two datetimes are in same day
  189. function IsSameDay(cBefore, cNow : TDateTime) : Boolean;
  190. //change Time of a DateTime
  191. function ChangeTimeOfADay(aDate : TDateTime; aHour, aMinute, aSecond : Word; aMilliSecond : Word = 0) : TDateTime;
  192. //change Date of a DateTime
  193. function ChangeDateOfADay(aDate : TDateTime; aYear, aMonth, aDay : Word) : TDateTime;
  194. //returns n times a char
  195. function FillStr(const C : Char; const Count : Integer) : string;
  196. //checks if string exists in array of string
  197. function StrInArray(const aValue : string; const aInArray : array of string) : Boolean;
  198. //checks if integer exists in array of integer
  199. function IntInArray(const aValue : Integer; const aInArray : array of Integer) : Boolean;
  200. //check if array is empty
  201. function IsEmptyArray(aArray : TArray<string>) : Boolean; overload;
  202. function IsEmptyArray(aArray : TArray<Integer>) : Boolean; overload;
  203. //returns a number leading zero
  204. function Zeroes(const Number, Len : Int64) : string;
  205. //converts a number to thousand delimeter string
  206. function NumberToStr(const Number : Int64) : string;
  207. //returns n spaces
  208. function Spaces(const Count : Integer) : string;
  209. //returns current date as a string
  210. function NowStr : string;
  211. //returns a new GUID as string
  212. function NewGuidStr : string;
  213. //compare a string with a wildcard pattern (? or *)
  214. function IsLike(cText, Pattern: string) : Boolean;
  215. //Upper case for first letter
  216. function Capitalize(s: string): string;
  217. function CapitalizeWords(s: string): string;
  218. //returns current logged user
  219. function GetLoggedUserName : string;
  220. //returns computer name
  221. function GetComputerName : string;
  222. //Changes incorrect delims in path
  223. function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
  224. //Removes last segment of a path
  225. function RemoveLastPathSegment(cDir : string) : string;
  226. //finds swith in commandline params
  227. function ParamFindSwitch(const Switch : string) : Boolean;
  228. //gets value for a switch if exists
  229. function ParamGetSwitch(const Switch : string; var cvalue : string) : Boolean;
  230. //returns app name (filename based)
  231. function GetAppName : string;
  232. //returns app version (major & minor)
  233. function GetAppVersionStr: string;
  234. //returns app version full (major, minor, release & compiled)
  235. function GetAppVersionFullStr: string;
  236. //convert UTC DateTime to Local DateTime
  237. function UTCToLocalTime(GMTTime: TDateTime): TDateTime;
  238. //convert Local DateTime to UTC DateTime
  239. function LocalTimeToUTC(LocalTime : TDateTime): TDateTime;
  240. //convert DateTime to GTM Time string
  241. function DateTimeToGMT(aDate : TDateTime) : string;
  242. //convert GMT Time string to DateTime
  243. function GMTToDateTime(aDate : string) : TDateTime;
  244. //convert DateTime to Json Date format
  245. function DateTimeToJsonDate(aDateTime : TDateTime) : string;
  246. //convert Json Date format to DateTime
  247. function JsonDateToDateTime(const aJsonDate : string) : TDateTime;
  248. //count number of digits of a Integer
  249. function CountDigits(anInt: Cardinal): Cardinal; inline;
  250. //save stream to file
  251. procedure SaveStreamToFile(stream : TStream; const filename : string);
  252. //save stream to string
  253. function StreamToString(stream : TStream) : string;
  254. //returns a real comma separated text from stringlist
  255. function CommaText(aList : TStringList) : string; overload;
  256. //returns a real comma separated text from array of string
  257. function CommaText(aArray : TArray<string>) : string; overload;
  258. //converts TStrings to array
  259. function StringsToArray(aStrings : TStrings) : TArray<string>;
  260. {$IFDEF MSWINDOWS}
  261. //process messages on console applications
  262. procedure ProcessMessages;
  263. //get last error message
  264. function GetLastOSError : String;
  265. {$ENDIF}
  266. {$IF DEFINED(FPC) AND DEFINED(MSWINDOWS)}
  267. function GetLastInputInfo(var plii: TLastInputInfo): BOOL;stdcall; external 'user32' name 'GetLastInputInfo';
  268. {$ENDIF}
  269. function RemoveLastChar(const aText : string) : string;
  270. function DateTimeToSQL(aDateTime : TDateTime) : string;
  271. function IsInteger(const aValue : string) : Boolean;
  272. //extract a substring and deletes from source string
  273. function ExtractStr(var vSource : string; aIndex : Integer; aCount : Integer) : string;
  274. //get first string between string delimiters
  275. function GetSubString(const aSource, aFirstDelimiter, aLastDelimiter : string) : string;
  276. //get double quoted or dequoted string
  277. function DbQuotedStr(const str : string): string;
  278. function UnDbQuotedStr(const str: string) : string;
  279. {$IFDEF MSWINDOWS}
  280. var
  281. path : TEnvironmentPath;
  282. {$ENDIF}
  283. implementation
  284. {TFileHelper}
  285. {$IFNDEF FPC}
  286. {$IFDEF MSWINDOWS}
  287. class function TFileHelper.IsInUse(const FileName : string) : Boolean;
  288. var
  289. HFileRes: HFILE;
  290. begin
  291. Result := False;
  292. if not FileExists(FileName) then Exit;
  293. try
  294. HFileRes := CreateFile(PChar(FileName)
  295. ,GENERIC_READ or GENERIC_WRITE
  296. ,0
  297. ,nil
  298. ,OPEN_EXISTING
  299. ,FILE_ATTRIBUTE_NORMAL
  300. ,0);
  301. Result := (HFileRes = INVALID_HANDLE_VALUE);
  302. if not(Result) then begin
  303. CloseHandle(HFileRes);
  304. end;
  305. except
  306. Result := True;
  307. end;
  308. end;
  309. {$ENDIF}
  310. {$IFDEF DELPHILINUX}
  311. class function TFileHelper.IsInUse(const FileName : string) : Boolean;
  312. var
  313. fs : TFileStream;
  314. begin
  315. try
  316. fs := TFileStream.Create(FileName, fmOpenReadWrite, fmShareExclusive);
  317. Result := True;
  318. fs.Free;
  319. except
  320. Result := False;
  321. end;
  322. end;
  323. {$ENDIF}
  324. {$IFDEF MSWINDOWS}
  325. class function TFileHelper.GetSize(const FileName: String): Int64;
  326. var
  327. info: TWin32FileAttributeData;
  328. begin
  329. Result := -1;
  330. if not GetFileAttributesEx(PWideChar(FileName), GetFileExInfoStandard, @info) then Exit;
  331. Result := Int64(info.nFileSizeLow) or Int64(info.nFileSizeHigh shl 32);
  332. end;
  333. {$ELSE}
  334. class function TFileHelper.GetSize(const FileName: String): Int64;
  335. var
  336. sr : TSearchRec;
  337. begin
  338. if FindFirst(fileName, faAnyFile, sr ) = 0 then Result := sr.Size
  339. else Result := -1;
  340. end;
  341. {$ENDIF}
  342. {TDirectoryHelper}
  343. class function TDirectoryHelper.GetSize(const Path: String): Int64;
  344. var
  345. filename : string;
  346. begin
  347. Result := -1;
  348. for filename in TDirectory.GetFiles(Path) do
  349. begin
  350. Result := Result + TFile.GetSize(filename);
  351. end;
  352. end;
  353. {$ENDIF}
  354. {other functions}
  355. function RandomPassword(const PasswordLength : Integer; Complexity : TPasswordComplexity = [pfIncludeNumbers,pfIncludeSigns]) : string;
  356. const
  357. PassAlpha = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  358. PassSigns = '@!&$';
  359. PassNumbers = '1234567890';
  360. var
  361. MinNumbers,
  362. MinSigns : Integer;
  363. NumNumbers,
  364. NumSigns : Integer;
  365. begin
  366. Result := '';
  367. Randomize;
  368. //fill all alfa
  369. repeat
  370. Result := Result + PassAlpha[Random(Length(PassAlpha))+1];
  371. until (Length(Result) = PasswordLength);
  372. //checks if need include numbers
  373. if pfIncludeNumbers in Complexity then
  374. begin
  375. MinNumbers := Round(PasswordLength / 10 * 2);
  376. NumNumbers := 0;
  377. if MinNumbers = 0 then MinNumbers := 1;
  378. repeat
  379. Result[Random(PasswordLength)+1] := PassNumbers[Random(Length(PassNumbers))+1];
  380. Inc(NumNumbers);
  381. until NumNumbers = MinNumbers;
  382. end;
  383. //checks if need include signs
  384. if pfIncludeNumbers in Complexity then
  385. begin
  386. MinSigns := Round(PasswordLength / 10 * 1);
  387. NumSigns := 0;
  388. if MinSigns = 0 then MinSigns := 1;
  389. repeat
  390. Result[Random(PasswordLength)+1] := PassSigns[Random(Length(PassSigns))+1];
  391. Inc(NumSigns);
  392. until NumSigns = MinSigns;
  393. end;
  394. end;
  395. function ExtractFileNameWithoutExt(const FileName: string): string;
  396. begin
  397. Result := TPath.GetFileNameWithoutExtension(FileName);
  398. end;
  399. function UnixToWindowsPath(const UnixPath: string): string;
  400. begin
  401. Result := StringReplace(UnixPath, '/', '\',[rfReplaceAll, rfIgnoreCase]);
  402. end;
  403. function WindowsToUnixPath(const WindowsPath: string): string;
  404. begin
  405. Result := StringReplace(WindowsPath, '\', '/',[rfReplaceAll, rfIgnoreCase]);
  406. end;
  407. function CorrectURLPath(cUrl : string) : string;
  408. var
  409. nurl : string;
  410. begin
  411. nurl := WindowsToUnixPath(cUrl);
  412. nurl := StringReplace(nurl,'//','/',[rfReplaceAll]);
  413. Result := StringReplace(nurl,' ','%20',[rfReplaceAll]);
  414. //TNetEncoding.Url.Encode()
  415. end;
  416. {$IFDEF MSWINDOWS}
  417. procedure GetEnvironmentPaths;
  418. begin
  419. //gets path
  420. path.EXEPATH := TPath.GetDirectoryName(ParamStr(0));
  421. path.WINDOWS := SysUtils.GetEnvironmentVariable('windir');
  422. path.PROGRAMFILES := SysUtils.GetEnvironmentVariable('ProgramFiles');
  423. path.COMMONFILES := SysUtils.GetEnvironmentVariable('CommonProgramFiles(x86)');
  424. path.HOMEDRIVE := SysUtils.GetEnvironmentVariable('SystemDrive');
  425. path.USERPROFILE := SysUtils.GetEnvironmentVariable('USERPROFILE');
  426. path.PROGRAMDATA := SysUtils.GetEnvironmentVariable('ProgramData');
  427. path.ALLUSERSPROFILE := SysUtils.GetEnvironmentVariable('AllUsersProfile');
  428. path.INSTDRIVE := path.HOMEDRIVE;
  429. path.TEMP := SysUtils.GetEnvironmentVariable('TEMP');
  430. //these paths fail if user is SYSTEM
  431. try
  432. path.SYSTEM := GetSpecialFolderPath(CSIDL_SYSTEM);
  433. path.APPDATA := GetSpecialFolderPath(CSIDL_APPDATA);
  434. path.DESKTOP := GetSpecialFolderPath(CSIDL_DESKTOP);
  435. path.DESKTOP_ALLUSERS := GetSpecialFolderPath(CSIDL_COMMON_DESKTOPDIRECTORY);
  436. path.STARTMENU:=GetSpecialFolderPath(CSIDL_PROGRAMS);
  437. path.STARTMENU_ALLUSERS:=GetSpecialFolderPath(CSIDL_COMMON_PROGRAMS);
  438. path.STARTMENU_ALLUSERS := path.STARTMENU;
  439. path.STARTUP:=GetSpecialFolderPath(CSIDL_STARTUP);
  440. except
  441. //
  442. end;
  443. end;
  444. function GetSpecialFolderPath(folderID : Integer) : string;
  445. var
  446. ppidl: PItemIdList;
  447. begin
  448. SHGetSpecialFolderLocation(0, folderID, ppidl);
  449. SetLength(Result, MAX_PATH);
  450. if not SHGetPathFromIDList(ppidl,{$IFDEF FPC}PAnsiChar(Result){$ELSE}PChar(Result){$ENDIF}) then
  451. begin
  452. raise EShellError.create(Format('GetSpecialFolderPath: Invalid PIPL (%d)',[folderID]));
  453. end;
  454. SetLength(Result, lStrLen({$IFDEF FPC}PAnsiChar(Result){$ELSE}PChar(Result){$ENDIF}));
  455. end;
  456. function Is64bitOS : Boolean;
  457. begin
  458. {$IFDEF WIN64}
  459. Result := True;
  460. {$ELSE}
  461. Result := False;
  462. {$ENDIF WIN64}
  463. end;
  464. function IsConsole: Boolean;
  465. begin
  466. {$IFDEF CONSOLE}
  467. Result := True;
  468. {$ELSE}
  469. Result := False;
  470. {$ENDIF CONSOLE}
  471. end;
  472. {$ENDIF}
  473. function HasConsoleOutput : Boolean;
  474. {$IFDEF MSWINDOWS}
  475. var
  476. stout : THandle;
  477. begin
  478. stout := GetStdHandle(Std_Output_Handle);
  479. Win32Check(stout <> Invalid_Handle_Value);
  480. Result := stout <> 0;
  481. end;
  482. {$ELSE}
  483. begin
  484. Result := IsConsole;
  485. end;
  486. {$ENDIF}
  487. function IsDebug: Boolean;
  488. begin
  489. {$IFDEF DEBUG}
  490. Result := True;
  491. {$ELSE}
  492. Result := False;
  493. {$ENDIF DEBUG}
  494. end;
  495. {$IFDEF MSWINDOWS}
  496. function IsService : Boolean;
  497. begin
  498. //only working with my Quick.AppService unit
  499. try
  500. Result := (IsConsole) and (not HasConsoleOutput);
  501. except
  502. Result := False;
  503. end;
  504. end;
  505. function SecondsIdle: DWord;
  506. var
  507. liInfo: TLastInputInfo;
  508. begin
  509. liInfo.cbSize := SizeOf(TLastInputInfo) ;
  510. GetLastInputInfo(liInfo) ;
  511. Result := (GetTickCount - liInfo.dwTime) DIV 1000;
  512. end;
  513. procedure FreeUnusedMem;
  514. begin
  515. if Win32Platform = VER_PLATFORM_WIN32_NT then SetProcessWorkingSetSize(GetCurrentProcess, $FFFFFFFF, $FFFFFFFF);
  516. end;
  517. function SetScreenResolution(Width, Height: integer): Longint;
  518. var
  519. DeviceMode: TDeviceMode;
  520. begin
  521. with DeviceMode do
  522. begin
  523. dmSize := SizeOf(TDeviceMode);
  524. dmPelsWidth := Width;
  525. dmPelsHeight := Height;
  526. dmFields := DM_PELSWIDTH or DM_PELSHEIGHT;
  527. end;
  528. Result := ChangeDisplaySettings(DeviceMode, CDS_UPDATEREGISTRY);
  529. end;
  530. {$ENDIF MSWINDOWS}
  531. function LastDayCurrentMonth: TDateTime;
  532. begin
  533. Result := EncodeDate(YearOf(Now),MonthOf(Now), DaysInMonth(Now));
  534. end;
  535. {$IFDEF FPC}
  536. function DateTimeInRange(ADateTime: TDateTime; AStartDateTime, AEndDateTime: TDateTime; aInclusive: Boolean = True): Boolean;
  537. begin
  538. if aInclusive then
  539. Result := (AStartDateTime <= ADateTime) and (ADateTime <= AEndDateTime)
  540. else
  541. Result := (AStartDateTime < ADateTime) and (ADateTime < AEndDateTime);
  542. end;
  543. {$ENDIF}
  544. function IsSameDay(cBefore, cNow : TDateTime) : Boolean;
  545. begin
  546. //Test: Result := MinutesBetween(cBefore,cNow) < 1;
  547. Result := DateTimeInRange(cNow,StartOfTheDay(cBefore),EndOfTheDay(cBefore),True);
  548. end;
  549. function ChangeTimeOfADay(aDate : TDateTime; aHour, aMinute, aSecond : Word; aMilliSecond : Word = 0) : TDateTime;
  550. var
  551. y, m, d : Word;
  552. begin
  553. DecodeDate(aDate,y,m,d);
  554. Result := EncodeDateTime(y,m,d,aHour,aMinute,aSecond,aMilliSecond);
  555. end;
  556. function ChangeDateOfADay(aDate : TDateTime; aYear, aMonth, aDay : Word) : TDateTime;
  557. var
  558. h, m, s, ms : Word;
  559. begin
  560. DecodeTime(aDate,h,m,s,ms);
  561. Result := EncodeDateTime(aYear,aMonth,aDay,h,m,s,0);
  562. end;
  563. function FillStr(const C : Char; const Count : Integer) : string;
  564. var
  565. i : Integer;
  566. begin
  567. Result := '';
  568. for i := 1 to Count do Result := Result + C;
  569. end;
  570. function StrInArray(const aValue : string; const aInArray : array of string) : Boolean;
  571. var
  572. s : string;
  573. begin
  574. for s in aInArray do
  575. begin
  576. if s = aValue then Exit(True);
  577. end;
  578. Result := False;
  579. end;
  580. function IntInArray(const aValue : Integer; const aInArray : array of Integer) : Boolean;
  581. var
  582. i : Integer;
  583. begin
  584. for i in aInArray do
  585. begin
  586. if i = aValue then Exit(True);
  587. end;
  588. Result := False;
  589. end;
  590. function IsEmptyArray(aArray : TArray<string>) : Boolean;
  591. begin
  592. Result := Length(aArray) = 0;
  593. end;
  594. function IsEmptyArray(aArray : TArray<Integer>) : Boolean;
  595. begin
  596. Result := Length(aArray) = 0;
  597. end;
  598. function Zeroes(const Number, Len : Int64) : string;
  599. begin
  600. if Len > Length(IntToStr(Number)) then Result := FillStr('0',Len - Length(IntToStr(Number))) + IntToStr(Number)
  601. else Result := IntToStr(Number);
  602. end;
  603. function NumberToStr(const Number : Int64) : string;
  604. begin
  605. try
  606. Result := FormatFloat('0,',Number);
  607. except
  608. Result := '#Error';
  609. end;
  610. end;
  611. function Spaces(const Count : Integer) : string;
  612. begin
  613. Result := FillStr(' ',Count);
  614. end;
  615. function NowStr : string;
  616. begin
  617. Result := DateTimeToStr(Now());
  618. end;
  619. function NewGuidStr : string;
  620. var
  621. guid : TGUID;
  622. begin
  623. guid.NewGuid;
  624. Result := guid.ToString
  625. //GUIDToString(guid);
  626. end;
  627. function IsLike(cText, Pattern: string) : Boolean;
  628. var
  629. i, n : Integer;
  630. match : Boolean;
  631. wildcard : Boolean;
  632. CurrentPattern : Char;
  633. begin
  634. Result := False;
  635. wildcard := False;
  636. cText := LowerCase(cText);
  637. Pattern := LowerCase(Pattern);
  638. match := False;
  639. if (Pattern.Length > cText.Length) or (Pattern = '') then Exit;
  640. if Pattern = '*' then
  641. begin
  642. Result := True;
  643. Exit;
  644. end;
  645. for i := 1 to cText.Length do
  646. begin
  647. CurrentPattern := Pattern[i];
  648. if CurrentPattern = '*' then wildcard := True;
  649. if wildcard then
  650. begin
  651. n := Pos(Copy(Pattern,i+1,Pattern.Length),cText);
  652. if (n > i) or (Pattern.Length = i) then
  653. begin
  654. Result := True;
  655. Exit;
  656. end;
  657. end
  658. else
  659. begin
  660. if (cText[i] = CurrentPattern) or (CurrentPattern = '?') then match := True
  661. else match := False;
  662. end;
  663. end;
  664. Result := match;
  665. end;
  666. function Capitalize(s: string): string;
  667. begin
  668. Result := '';
  669. if s.Length = 0 then Exit;
  670. s := LowerCase(s,loUserLocale);
  671. Result := UpperCase(s[1],loUserLocale) + Trim(Copy(s, 2, s.Length));
  672. end;
  673. function CapitalizeWords(s: string): string;
  674. var
  675. cword : string;
  676. begin
  677. Result := '';
  678. if s.Length = 0 then Exit;
  679. s := LowerCase(s,loUserLocale);
  680. for cword in s.Split([' ']) do
  681. begin
  682. if Result = '' then Result := Capitalize(cword)
  683. else Result := Result + ' ' + Capitalize(cword);
  684. end;
  685. end;
  686. function GetLoggedUserName : string;
  687. {$IFDEF MSWINDOWS}
  688. const
  689. cnMaxUserNameLen = 254;
  690. var
  691. sUserName : string;
  692. dwUserNameLen : DWord;
  693. begin
  694. dwUserNameLen := cnMaxUserNameLen-1;
  695. SetLength( sUserName, cnMaxUserNameLen );
  696. GetUserName(PChar( sUserName ),dwUserNameLen );
  697. SetLength( sUserName, dwUserNameLen );
  698. Result := sUserName;
  699. end;
  700. {$ELSE}
  701. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  702. begin
  703. Result := GetEnvironmentVariable('USERNAME');
  704. end;
  705. {$ELSE}
  706. begin
  707. {$IFDEF POSIX}
  708. Result := string(getlogin);
  709. {$ELSE}
  710. Result := 'N/A';
  711. {$ENDIF}
  712. //raise ENotImplemented.Create('Not Android GetLoggedUserName implemented!');
  713. end;
  714. {$ENDIF}
  715. {$ENDIF}
  716. {$IFDEF IOS}
  717. function GetDeviceModel : String;
  718. var
  719. size : size_t;
  720. buffer : array of Byte;
  721. begin
  722. sysctlbyname('hw.machine',nil,@size,nil,0);
  723. if size > 0 then
  724. begin
  725. SetLength(buffer, size);
  726. sysctlbyname('hw.machine',@buffer[0],@size,nil,0);
  727. Result := UTF8ToString(MarshaledAString(buffer));
  728. end
  729. else Result := EmptyStr;
  730. end;
  731. {$ENDIF}
  732. function GetComputerName : string;
  733. {$IFDEF MSWINDOWS}
  734. var
  735. dwLength: dword;
  736. begin
  737. dwLength := 253;
  738. SetLength(Result, dwLength+1);
  739. if not Windows.GetComputerName(pchar(result), dwLength) then Result := 'Not detected!';
  740. Result := pchar(result);
  741. end;
  742. {$ELSE}
  743. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  744. begin
  745. Result := GetEnvironmentVariable('COMPUTERNAME');
  746. end;
  747. {$ELSE} //Android gets model name
  748. {$IFDEF NEXTGEN}
  749. begin
  750. {$IFDEF ANDROID}
  751. Result := JStringToString(TJBuild.JavaClass.MODEL);
  752. {$ELSE} //IOS
  753. Result := GetDeviceModel;
  754. {$ENDIF}
  755. end;
  756. {$ELSE}
  757. {$IFDEF DELPHILINUX}
  758. var
  759. puser : PAnsiChar;
  760. begin
  761. //puser := '';
  762. try
  763. if gethostname(puser,_SC_HOST_NAME_MAX) = 0 then Result := string(puser)
  764. else Result := 'N/A';
  765. except
  766. Result := 'N/A';
  767. end;
  768. end;
  769. {$ELSE} //OSX
  770. begin
  771. Result := NSStrToStr(TNSHost.Wrap(TNSHost.OCClass.currentHost).localizedName);
  772. end;
  773. {$ENDIF}
  774. {$ENDIF}
  775. {$ENDIF}
  776. {$ENDIF}
  777. function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
  778. begin
  779. if Delim = '\' then Result := StringReplace(cPath,'/',Delim,[rfReplaceAll])
  780. else Result := StringReplace(cPath,'\',Delim,[rfReplaceAll]);
  781. end;
  782. function RemoveLastPathSegment(cDir : string) : string;
  783. var
  784. posi : Integer;
  785. delim : Char;
  786. EndsWithDelim : Boolean;
  787. begin
  788. if cDir.Contains('\') then delim := '\'
  789. else if cDir.Contains('/') then delim := '/'
  790. else
  791. begin
  792. Result := '';
  793. Exit;
  794. end;
  795. NormalizePathDelim(cDir,delim);
  796. if cDir.EndsWith(delim) then
  797. begin
  798. cDir := Copy(cDir,1,cDir.Length-1);
  799. EndsWithDelim := True;
  800. end
  801. else EndsWithDelim := False;
  802. if cDir.CountChar(delim) > 1 then posi := cDir.LastDelimiter(delim)
  803. else posi := Pos(delim,cDir)-1;
  804. if posi = cDir.Length then posi := 0;
  805. Result := Copy(cDir,1,posi);
  806. if (Result <> '') and (EndsWithDelim) then Result := Result + delim;
  807. end;
  808. function ParamFindSwitch(const Switch : string) : Boolean;
  809. begin
  810. Result := FindCmdLineSwitch(Switch,['-', '/'],True);
  811. end;
  812. {$IFDEF FPC}
  813. function FindCmdLineSwitch(const Switch: string; var Value: string; IgnoreCase: Boolean = True;
  814. const SwitchTypes: TCmdLineSwitchTypes = [clstValueNextParam, clstValueAppended]): Boolean; overload;
  815. type
  816. TCompareProc = function(const S1, S2: string): Boolean;
  817. var
  818. Param: string;
  819. I, ValueOfs,
  820. SwitchLen, ParamLen: Integer;
  821. SameSwitch: TCompareProc;
  822. begin
  823. Result := False;
  824. Value := '';
  825. if IgnoreCase then
  826. SameSwitch := SameText else
  827. SameSwitch := SameStr;
  828. SwitchLen := Switch.Length;
  829. for I := 1 to ParamCount do
  830. begin
  831. Param := ParamStr(I);
  832. if CharInSet(Param.Chars[0], SwitchChars) and SameSwitch(Param.SubString(1,SwitchLen), Switch) then
  833. begin
  834. ParamLen := Param.Length;
  835. // Look for an appended value if the param is longer than the switch
  836. if (ParamLen > SwitchLen + 1) then
  837. begin
  838. // If not looking for appended value switches then this is not a matching switch
  839. if not (clstValueAppended in SwitchTypes) then
  840. Continue;
  841. ValueOfs := SwitchLen + 1;
  842. if Param.Chars[ValueOfs] = ':' then
  843. Inc(ValueOfs);
  844. Value := Param.SubString(ValueOfs, MaxInt);
  845. end
  846. // If the next param is not a switch, then treat it as the value
  847. else if (clstValueNextParam in SwitchTypes) and (I < ParamCount) and
  848. not CharInSet(ParamStr(I+1).Chars[0], SwitchChars) then
  849. Value := ParamStr(I+1);
  850. Result := True;
  851. Break;
  852. end;
  853. end;
  854. end;
  855. {$ENDIF}
  856. function ParamGetSwitch(const Switch : string; var cvalue : string) : Boolean;
  857. begin
  858. Result := FindCmdLineSwitch(Switch,cvalue,True,[clstValueAppended]);
  859. end;
  860. function GetAppName : string;
  861. begin
  862. Result := ExtractFilenameWithoutExt(ParamStr(0));
  863. end;
  864. function GetAppVersionStr: string;
  865. {$IFDEF MSWINDOWS}
  866. var
  867. Rec: LongRec;
  868. ver : Cardinal;
  869. begin
  870. ver := GetFileVersion(ParamStr(0));
  871. if ver <> Cardinal(-1) then
  872. begin
  873. Rec := LongRec(ver);
  874. Result := Format('%d.%d', [Rec.Hi, Rec.Lo]);
  875. end
  876. else Result := '';
  877. end;
  878. {$ELSE}
  879. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  880. var
  881. version : TProgramVersion;
  882. begin
  883. if GetProgramVersion(version) then Result := Format('%d.%d', [version.Major, version.Minor])
  884. else Result := '';
  885. end;
  886. {$ELSE}
  887. {$IFDEF NEXTGEN}
  888. {$IFDEF ANDROID}
  889. var
  890. PkgInfo : JPackageInfo;
  891. begin
  892. PkgInfo := SharedActivity.getPackageManager.getPackageInfo(SharedActivity.getPackageName,0);
  893. Result := IntToStr(PkgInfo.VersionCode);
  894. end;
  895. {$ELSE} //IOS
  896. var
  897. AppKey: Pointer;
  898. AppBundle: NSBundle;
  899. BuildStr : NSString;
  900. begin
  901. try
  902. AppKey := (StrToNSStr('CFBundleVersion') as ILocalObject).GetObjectID;
  903. AppBundle := TNSBundle.Wrap(TNSBundle.OCClass.mainBundle);
  904. BuildStr := TNSString.Wrap(AppBundle.infoDictionary.objectForKey(AppKey));
  905. Result := UTF8ToString(BuildStr.UTF8String);
  906. except
  907. Result := '';
  908. end;
  909. end;
  910. {$ENDIF}
  911. {$ELSE} //OSX
  912. {$IFDEF OSX}
  913. var
  914. AppKey: Pointer;
  915. AppBundle: NSBundle;
  916. BuildStr : NSString;
  917. begin
  918. try
  919. AppKey := (StrToNSStr('CFBundleVersion') as ILocalObject).GetObjectID;
  920. AppBundle := TNSBundle.Wrap(TNSBundle.OCClass.mainBundle);
  921. BuildStr := TNSString.Wrap(AppBundle.infoDictionary.objectForKey(AppKey));
  922. Result := UTF8ToString(BuildStr.UTF8String);
  923. except
  924. Result := '';
  925. end;
  926. end;
  927. {$ELSE}
  928. begin
  929. Result := '';
  930. end;
  931. {$ENDIF}
  932. {$ENDIF}
  933. {$ENDIF}
  934. {$ENDIF}
  935. function GetAppVersionFullStr: string;
  936. {$IFDEF MSWINDOWS}
  937. var
  938. Exe: string;
  939. Size, Handle: DWORD;
  940. Buffer: TBytes;
  941. FixedPtr: PVSFixedFileInfo;
  942. begin
  943. Result := '';
  944. Exe := ParamStr(0);
  945. Size := GetFileVersionInfoSize(PChar(Exe), Handle);
  946. if Size = 0 then
  947. begin
  948. //RaiseLastOSError;
  949. //no version info in file
  950. Exit;
  951. end;
  952. SetLength(Buffer, Size);
  953. if not GetFileVersionInfo(PChar(Exe), Handle, Size, Buffer) then
  954. RaiseLastOSError;
  955. if not VerQueryValue(Buffer, '\', Pointer(FixedPtr), Size) then
  956. RaiseLastOSError;
  957. if (LongRec(FixedPtr.dwFileVersionLS).Hi = 0) and (LongRec(FixedPtr.dwFileVersionLS).Lo = 0) then
  958. begin
  959. Result := Format('%d.%d',
  960. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  961. LongRec(FixedPtr.dwFileVersionMS).Lo]); //minor
  962. end
  963. else if (LongRec(FixedPtr.dwFileVersionLS).Lo = 0) then
  964. begin
  965. Result := Format('%d.%d.%d',
  966. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  967. LongRec(FixedPtr.dwFileVersionMS).Lo, //minor
  968. LongRec(FixedPtr.dwFileVersionLS).Hi]); //release
  969. end
  970. else
  971. begin
  972. Result := Format('%d.%d.%d.%d',
  973. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  974. LongRec(FixedPtr.dwFileVersionMS).Lo, //minor
  975. LongRec(FixedPtr.dwFileVersionLS).Hi, //release
  976. LongRec(FixedPtr.dwFileVersionLS).Lo]); //build
  977. end;
  978. end;
  979. {$ELSE}
  980. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  981. var
  982. version : TProgramVersion;
  983. begin
  984. if GetProgramVersion(version) then Result := Format('%d.%d.%d.%d', [version.Major, version.Minor, version.Revision, version.Build])
  985. else Result := '';
  986. end;
  987. {$ELSE}
  988. {$IFDEF NEXTGEN}
  989. {$IFDEF ANDROID}
  990. var
  991. PkgInfo : JPackageInfo;
  992. begin
  993. PkgInfo := SharedActivity.getPackageManager.getPackageInfo(SharedActivity.getPackageName,0);
  994. Result := JStringToString(PkgInfo.versionName);
  995. end;
  996. {$ELSE} //IOS
  997. var
  998. AppKey: Pointer;
  999. AppBundle: NSBundle;
  1000. BuildStr : NSString;
  1001. begin
  1002. AppKey := (StrToNSStr('CFBundleVersion') as ILocalObject).GetObjectID;
  1003. AppBundle := TNSBundle.Wrap(TNSBundle.OCClass.mainBundle);
  1004. BuildStr := TNSString.Wrap(AppBundle.infoDictionary.objectForKey(AppKey));
  1005. Result := UTF8ToString(BuildStr.UTF8String);
  1006. end;
  1007. {$ENDIF}
  1008. {$ELSE}
  1009. {$IFDEF OSX}
  1010. var
  1011. AppKey: Pointer;
  1012. AppBundle: NSBundle;
  1013. BuildStr : NSString;
  1014. begin
  1015. AppKey := (StrToNSStr('CFBundleVersion') as ILocalObject).GetObjectID;
  1016. AppBundle := TNSBundle.Wrap(TNSBundle.OCClass.mainBundle);
  1017. BuildStr := TNSString.Wrap(AppBundle.infoDictionary.objectForKey(AppKey));
  1018. Result := UTF8ToString(BuildStr.UTF8String);
  1019. end;
  1020. {$ELSE}
  1021. begin
  1022. Result := '';
  1023. end;
  1024. {$ENDIF}
  1025. {$ENDIF}
  1026. {$ENDIF}
  1027. {$ENDIF}
  1028. function UTCToLocalTime(GMTTime: TDateTime): TDateTime;
  1029. begin
  1030. {$IFDEF FPC}
  1031. Result := LocalTimeToUniversal(GMTTime);
  1032. {$ELSE}
  1033. Result := TTimeZone.Local.ToLocalTime(GMTTime);
  1034. {$ENDIF}
  1035. end;
  1036. function LocalTimeToUTC(LocalTime : TDateTime): TDateTime;
  1037. begin
  1038. {$IFDEF FPC}
  1039. Result := UniversalTimeToLocal(Localtime);
  1040. {$ELSE}
  1041. Result := TTimeZone.Local.ToUniversalTime(LocalTime);
  1042. {$ENDIF}
  1043. end;
  1044. function DateTimeToGMT(aDate : TDateTime) : string;
  1045. var
  1046. FmtSettings : TFormatSettings;
  1047. begin
  1048. FmtSettings.DateSeparator := '-';
  1049. FmtSettings.TimeSeparator := ':';
  1050. FmtSettings.ShortDateFormat := 'YYYY-MM-DD"T"HH:NN:SS.ZZZ" GMT"';
  1051. Result := DateTimeToStr(aDate,FmtSettings).Trim;
  1052. end;
  1053. function GMTToDateTime(aDate : string) : TDateTime;
  1054. var
  1055. FmtSettings : TFormatSettings;
  1056. begin
  1057. FmtSettings.DateSeparator := '-';
  1058. FmtSettings.TimeSeparator := ':';
  1059. FmtSettings.ShortDateFormat := 'YYYY-MM-DD"T"HH:NN:SS.ZZZ" GMT"';
  1060. Result := StrToDateTime(aDate,FmtSettings);
  1061. end;
  1062. function DateTimeToJsonDate(aDateTime : TDateTime) : string;
  1063. {$IFNDEF DELPHIXE7_UP}
  1064. var
  1065. FmtSettings : TFormatSettings;
  1066. {$ENDIF}
  1067. begin
  1068. {$IFDEF DELPHIXE7_UP}
  1069. Result := DateToISO8601(aDateTime);
  1070. {$ELSE}
  1071. FmtSettings.DateSeparator := '-';
  1072. FmtSettings.TimeSeparator := ':';
  1073. FmtSettings.ShortDateFormat := 'YYYY-MM-DD"T"HH:NN:SS.ZZZ"Z"';
  1074. Result := DateTimeToStr(aDateTime,FmtSettings).Trim;
  1075. {$ENDIF}
  1076. end;
  1077. function JsonDateToDateTime(const aJsonDate : string) : TDateTime;
  1078. {$IFNDEF DELPHIXE7_UP}
  1079. var
  1080. FmtSettings : TFormatSettings;
  1081. {$ENDIF}
  1082. {$IFDEF FPC}
  1083. var
  1084. jdate : string;
  1085. {$ENDIF}
  1086. begin
  1087. {$IFDEF DELPHIXE7_UP}
  1088. Result := ISO8601ToDate(aJsonDate);
  1089. {$ELSE}
  1090. FmtSettings.DateSeparator := '-';
  1091. FmtSettings.TimeSeparator := ':';
  1092. FmtSettings.ShortDateFormat := 'YYYY-MM-DD"T"HH:NN:SS.ZZZ"Z"';
  1093. {$IFDEF FPC}
  1094. jdate := StringReplace(aJsondate,'T',' ',[rfIgnoreCase]);
  1095. jdate := Copy(jdate,1,Pos('.',jdate)-1);
  1096. Result := StrToDateTime(jdate,FmtSettings);
  1097. {$ELSE}
  1098. Result := StrToDateTime(aJsonDate,FmtSettings);
  1099. {$ENDIF}
  1100. {$ENDIF}
  1101. end;
  1102. function CountDigits(anInt: Cardinal): Cardinal; inline;
  1103. var
  1104. cmp: Cardinal;
  1105. begin
  1106. cmp := 10;
  1107. Result := 1;
  1108. while (Result < 10) and (cmp <= anInt) do
  1109. begin
  1110. cmp := cmp*10;
  1111. Inc(Result);
  1112. end;
  1113. end;
  1114. procedure SaveStreamToFile(stream : TStream; const filename : string);
  1115. var
  1116. fs : TFileStream;
  1117. begin
  1118. fs := TFileStream.Create(filename,fmCreate);
  1119. try
  1120. stream.Seek(0,soBeginning);
  1121. fs.CopyFrom(stream,stream.Size);
  1122. finally
  1123. fs.Free;
  1124. end;
  1125. end;
  1126. function StreamToString(stream : TStream) : string;
  1127. var
  1128. ss : TStringStream;
  1129. begin
  1130. if stream = nil then Exit;
  1131. ss := TStringStream.Create;
  1132. try
  1133. stream.Seek(0,soBeginning);
  1134. ss.CopyFrom(stream,stream.Size);
  1135. Result := ss.DataString;
  1136. finally
  1137. ss.Free;
  1138. end;
  1139. end;
  1140. function CommaText(aList : TStringList) : string;
  1141. var
  1142. value : string;
  1143. sb : TStringBuilder;
  1144. begin
  1145. if aList.Text = '' then Exit;
  1146. sb := TStringBuilder.Create;
  1147. try
  1148. for value in aList do
  1149. begin
  1150. sb.Append(value);
  1151. sb.Append(',');
  1152. end;
  1153. if sb.Length > 1 then Result := sb.ToString(0, sb.Length - 1);
  1154. finally
  1155. sb.Free;
  1156. end;
  1157. end;
  1158. function CommaText(aArray : TArray<string>) : string;
  1159. var
  1160. value : string;
  1161. sb : TStringBuilder;
  1162. begin
  1163. if High(aArray) < 0 then Exit;
  1164. sb := TStringBuilder.Create;
  1165. try
  1166. for value in aArray do
  1167. begin
  1168. sb.Append(value);
  1169. sb.Append(',');
  1170. end;
  1171. if sb.Length > 1 then Result := sb.ToString(0, sb.Length - 1);
  1172. finally
  1173. sb.Free;
  1174. end;
  1175. end;
  1176. function StringsToArray(aStrings : TStrings) : TArray<string>;
  1177. var
  1178. i : Integer;
  1179. begin
  1180. if aStrings.Count = 0 then Exit;
  1181. SetLength(Result,aStrings.Count);
  1182. for i := 0 to aStrings.Count - 1 do
  1183. begin
  1184. Result[i] := aStrings[i];
  1185. end;
  1186. end;
  1187. { TCounter }
  1188. procedure TCounter.Init(aMaxValue : Integer);
  1189. begin
  1190. fMaxValue := aMaxValue;
  1191. fCurrentValue := 0;
  1192. end;
  1193. function TCounter.Count : Integer;
  1194. begin
  1195. Result := fCurrentValue;
  1196. end;
  1197. function TCounter.CountIs(aValue : Integer) : Boolean;
  1198. begin
  1199. Result := fCurrentValue = aValue;
  1200. end;
  1201. function TCounter.Check : Boolean;
  1202. begin
  1203. if fCurrentValue = fMaxValue then
  1204. begin
  1205. Result := True;
  1206. Reset;
  1207. end
  1208. else
  1209. begin
  1210. Result := False;
  1211. Inc(fCurrentValue);
  1212. end;
  1213. end;
  1214. procedure TCounter.Reset;
  1215. begin
  1216. fCurrentValue := fMaxValue;
  1217. end;
  1218. { TimeCounter }
  1219. procedure TTimeCounter.Init(MillisecondsToReach : Integer);
  1220. begin
  1221. fDoneEvery := MillisecondsToReach;
  1222. end;
  1223. function TTimeCounter.Check : Boolean;
  1224. begin
  1225. if MilliSecondsBetween(fCurrentTime,Now) > fDoneEvery then
  1226. begin
  1227. fCurrentTime := Now();
  1228. Result := True;
  1229. end
  1230. else Result := False;
  1231. end;
  1232. procedure TTimeCounter.Reset;
  1233. begin
  1234. fCurrentTime := Now();
  1235. end;
  1236. {$IFDEF MSWINDOWS}
  1237. procedure ProcessMessages;
  1238. var
  1239. Msg: TMsg;
  1240. begin
  1241. while integer(PeekMessage(Msg, 0, 0, 0, PM_REMOVE)) <> 0 do
  1242. begin
  1243. TranslateMessage(Msg);
  1244. DispatchMessage(Msg);
  1245. end;
  1246. end;
  1247. function GetLastOSError: String;
  1248. begin
  1249. Result := SysErrorMessage(Windows.GetLastError);
  1250. end;
  1251. {$ENDIF}
  1252. function RemoveLastChar(const aText : string) : string;
  1253. begin
  1254. Result := aText.Remove(aText.Length - 1);
  1255. end;
  1256. function DateTimeToSQL(aDateTime : TDateTime) : string;
  1257. begin
  1258. Result := FormatDateTime('YYYYMMDD hh:mm:ss',aDateTime);
  1259. end;
  1260. function IsInteger(const aValue : string) : Boolean;
  1261. var
  1262. i : Integer;
  1263. begin
  1264. Result := TryStrToInt(aValue,i);
  1265. end;
  1266. function ExtractStr(var vSource : string; aIndex : Integer; aCount : Integer) : string;
  1267. begin
  1268. if aIndex > vSource.Length then Exit('');
  1269. Result := Copy(vSource,aIndex,aCount);
  1270. Delete(vSource,aIndex,aCount);
  1271. end;
  1272. function GetSubString(const aSource, aFirstDelimiter, aLastDelimiter : string) : string;
  1273. var
  1274. i : Integer;
  1275. begin
  1276. i := Pos(aFirstDelimiter,aSource);
  1277. if i > -1 then Result := Copy(aSource, i + aFirstDelimiter.Length, Pos(aLastDelimiter, aSource, i + aFirstDelimiter.Length) - i - aFirstDelimiter.Length)
  1278. else Result := '';
  1279. end;
  1280. function DbQuotedStr(const str : string): string;
  1281. var
  1282. i : Integer;
  1283. begin
  1284. Result := str;
  1285. for i := Result.Length - 1 downto 0 do
  1286. begin
  1287. if Result.Chars[i] = '"' then Result := Result.Insert(i, '"');
  1288. end;
  1289. Result := '"' + Result + '"';
  1290. end;
  1291. function UnDbQuotedStr(const str: string) : string;
  1292. begin
  1293. Result := Trim(str);
  1294. if not Result.IsEmpty then
  1295. begin
  1296. if Result.StartsWith('"') then Result := Copy(Result, 2, Result.Length - 2);
  1297. end;
  1298. end;
  1299. {$IFDEF MSWINDOWS}
  1300. initialization
  1301. try
  1302. GetEnvironmentPaths;
  1303. except
  1304. {$IFDEF SHOW_ENVIRONMENTPATH_ERRORS}
  1305. on E : Exception do
  1306. begin
  1307. if not IsService then
  1308. begin
  1309. if HasConsoleOutput then Writeln(Format('[WARN] GetEnvironmentPaths: %s',[E.Message]))
  1310. else MessageBox(0,PWideChar(Format('Get environment path error: %s',[E.Message])),'GetEnvironmentPaths',MB_ICONEXCLAMATION);
  1311. end;
  1312. end;
  1313. {$ENDIF}
  1314. end;
  1315. {$ENDIF}
  1316. end.