Quick.Commons.pas 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180
  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.5
  7. Created : 14/07/2017
  8. Modified : 18/01/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. Registry,
  32. {$ENDIF MSWINDOWS}
  33. {$IFDEF FPC}
  34. Quick.Files,
  35. {$IFDEF LINUX}
  36. FileInfo,
  37. {$ENDIF}
  38. {$ELSE}
  39. IOUtils,
  40. {$ENDIF}
  41. {$IFDEF ANDROID}
  42. Androidapi.JNI.Os,
  43. Androidapi.Helpers,
  44. Androidapi.JNI.JavaTypes,
  45. Androidapi.JNI.GraphicsContentViewText,
  46. {$ENDIF}
  47. DateUtils;
  48. type
  49. TLogEventType = (etInfo, etSuccess, etWarning, etError, etDebug, etTrace);
  50. TLogVerbose = set of TLogEventType;
  51. const
  52. LOG_ONLYERRORS = [etInfo,etError];
  53. LOG_ERRORSANDWARNINGS = [etInfo,etWarning,etError];
  54. LOG_TRACE = [etInfo,etError,etWarning,etTrace];
  55. LOG_ALL = [etInfo,etSuccess,etWarning,etError,etTrace];
  56. LOG_DEBUG = [etInfo,etSuccess,etWarning,etError,etDebug];
  57. {$IFDEF DELPHIXE7_UP}
  58. EventStr : array of string = ['INFO','SUCC','WARN','ERROR','DEBUG','TRACE'];
  59. {$ELSE}
  60. EventStr : array[0..5] of string = ('INFO','SUCC','WARN','ERROR','DEBUG','TRACE');
  61. {$ENDIF}
  62. type
  63. TPasswordComplexity = set of (pfIncludeNumbers,pfIncludeSigns);
  64. {$IFDEF MSWINDOWS}
  65. TEnvironmentPath = record
  66. EXEPATH : string;
  67. WINDOWS : string;
  68. SYSTEM : string;
  69. PROGRAMFILES : string;
  70. COMMONFILES : string;
  71. HOMEDRIVE : string;
  72. TEMP : string;
  73. USERPROFILE : string;
  74. INSTDRIVE : string;
  75. DESKTOP : string;
  76. STARTMENU : string;
  77. DESKTOP_ALLUSERS : string;
  78. STARTMENU_ALLUSERS : string;
  79. STARTUP : string;
  80. APPDATA : String;
  81. PROGRAMDATA : string;
  82. ALLUSERSPROFILE : string;
  83. end;
  84. {$ENDIF MSWINDOWS}
  85. {$IFNDEF FPC}
  86. TFileHelper = record helper for TFile
  87. {$IF DEFINED(MSWINDOWS) OR DEFINED(DELPHILINUX)}
  88. class function IsInUse(const FileName : string) : Boolean; static;
  89. {$ENDIF}
  90. class function GetSize(const FileName: String): Int64; static;
  91. end;
  92. TDirectoryHelper = record helper for TDirectory
  93. class function GetSize(const Path: String): Int64; static;
  94. end;
  95. {$ENDIF}
  96. {$IFDEF FPC}
  97. {$IFDEF LINUX}
  98. UINT = cardinal;
  99. {$ENDIF}
  100. PLASTINPUTINFO = ^LASTINPUTINFO;
  101. tagLASTINPUTINFO = record
  102. cbSize: UINT;
  103. dwTime: DWORD;
  104. end;
  105. LASTINPUTINFO = tagLASTINPUTINFO;
  106. TLastInputInfo = LASTINPUTINFO;
  107. type
  108. TCmdLineSwitchType = (clstValueNextParam, clstValueAppended);
  109. TCmdLineSwitchTypes = set of TCmdLineSwitchType;
  110. {$ENDIF}
  111. TCounter = record
  112. private
  113. fMaxValue : Integer;
  114. fCurrentValue : Integer;
  115. public
  116. property MaxValue : Integer read fMaxValue;
  117. procedure Init(aMaxValue : Integer);
  118. function Count : Integer;
  119. function CountIs(aValue : Integer) : Boolean;
  120. function Check : Boolean;
  121. procedure Reset;
  122. end;
  123. TTimeCounter = record
  124. private
  125. fCurrentTime : TDateTime;
  126. fDoneEvery : Integer;
  127. public
  128. property DoneEvery : Integer read fDoneEvery;
  129. procedure Init(MillisecondsToReach : Integer);
  130. function Check : Boolean;
  131. procedure Reset;
  132. end;
  133. EEnvironmentPath = class(Exception);
  134. EShellError = class(Exception);
  135. //generates a random password with complexity options
  136. function RandomPassword(const PasswordLength : Integer; Complexity : TPasswordComplexity = [pfIncludeNumbers,pfIncludeSigns]) : string;
  137. //extracts file extension from a filename
  138. function ExtractFileNameWithoutExt(const FileName: string): string;
  139. //converts a Unix path to Windows path
  140. function UnixToWindowsPath(const UnixPath: string): string;
  141. //converts a Windows path to Unix path
  142. function WindowsToUnixPath(const WindowsPath: string): string;
  143. //corrects malformed urls
  144. function CorrectURLPath(cUrl : string) : string;
  145. {$IFDEF MSWINDOWS}
  146. //get typical environment paths as temp, desktop, etc
  147. procedure GetEnvironmentPaths;
  148. function GetSpecialFolderPath(folderID : Integer) : string;
  149. //checks if running on a 64bit OS
  150. function Is64bitOS : Boolean;
  151. //checks if is a console app
  152. function IsConsole : Boolean;
  153. //checks if compiled in debug mode
  154. {$ENDIF}
  155. function IsDebug : Boolean;
  156. {$IFDEF MSWINDOWS}
  157. //checks if running as a service
  158. function IsService : Boolean;
  159. //gets number of seconds without user interaction (mouse, keyboard)
  160. function SecondsIdle: DWord;
  161. //frees process memory not needed
  162. procedure FreeUnusedMem;
  163. //changes screen resolution
  164. function SetScreenResolution(Width, Height: integer): Longint;
  165. {$ENDIF MSWINDOWS}
  166. //returns last day of current month
  167. function LastDayCurrentMonth: TDateTime;
  168. {$IFDEF FPC}
  169. function DateTimeInRange(ADateTime: TDateTime; AStartDateTime, AEndDateTime: TDateTime; aInclusive: Boolean = True): Boolean;
  170. {$ENDIF}
  171. //checks if two datetimes are in same day
  172. function IsSameDay(cBefore, cNow : TDateTime) : Boolean;
  173. //change Time of a DateTime
  174. function ChangeTimeOfADay(aDate : TDateTime; aHour, aMinute, aSecond : Word; aMilliSecond : Word = 0) : TDateTime;
  175. //change Date of a DateTime
  176. function ChangeDateOfADay(aDate : TDateTime; aYear, aMonth, aDay : Word) : TDateTime;
  177. //returns n times a char
  178. function FillStr(const C : Char; const Count : Byte) : string;
  179. //checks if string exists in array of string
  180. function StrInArray(const aValue : string; const aInArray : array of string) : Boolean;
  181. //checks if integer exists in array of integer
  182. function IntInArray(const aValue : Integer; const aInArray : array of Integer) : Boolean;
  183. //returns a number leading zero
  184. function Zeroes(const Number, Len : Int64) : string;
  185. //converts a number to thousand delimeter string
  186. function NumberToStr(const Number : Int64) : string;
  187. //returns n spaces
  188. function Spaces(const Count : Integer) : string;
  189. //returns current date as a string
  190. function NowStr : string;
  191. //returns a new GUID as string
  192. function NewGuidStr : string;
  193. //compare a string with a wildcard pattern (? or *)
  194. function IsLike(cText, Pattern: string) : Boolean;
  195. //Upper case for first letter
  196. function Capitalize(s: string): string;
  197. function CapitalizeWords(s: string): string;
  198. //returns current logged user
  199. function GetLoggedUserName : string;
  200. //returns computer name
  201. function GetComputerName : string;
  202. //Changes incorrect delims in path
  203. function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
  204. //Removes last segment of a path
  205. function RemoveLastPathSegment(cDir : string) : string;
  206. //finds swith in commandline params
  207. function ParamFindSwitch(const Switch : string) : Boolean;
  208. //gets value for a switch if exists
  209. function ParamGetSwitch(const Switch : string; var cvalue : string) : Boolean;
  210. //returns app name (filename based)
  211. function GetAppName : string;
  212. //returns app version (major & minor)
  213. function GetAppVersionStr: string;
  214. //returns app version full (major, minor, release & compiled)
  215. function GetAppVersionFullStr: string;
  216. //convert UTC DateTime to Local DateTime
  217. function UTCToLocalTime(GMTTime: TDateTime): TDateTime;
  218. //convert Local DateTime to UTC DateTime
  219. function LocalTimeToUTC(LocalTime : TDateTime): TDateTime;
  220. //convert DateTime to GTM Time string
  221. function DateTimeToGMT(aDate : TDateTime) : string;
  222. //convert GMT Time string to DateTime
  223. function GMTToDateTime(aDate : string) : TDateTime;
  224. //convert DateTime to Json Date format
  225. function DateTimeToJsonDate(aDateTime : TDateTime) : string;
  226. //convert Json Date format to DateTime
  227. function JsonDateToDateTime(const aJsonDate : string) : TDateTime;
  228. //count number of digits of a Integer
  229. function CountDigits(anInt: Cardinal): Cardinal; inline;
  230. //save stream to file
  231. procedure SaveStreamToFile(stream : TStream; const filename : string);
  232. //returns a real comma separated text from stringlist
  233. function CommaText(aList : TStringList) : string;
  234. {$IFDEF MSWINDOWS}
  235. //process messages on console applications
  236. procedure ProcessMessages;
  237. //get last error message
  238. function GetLastOSError : String;
  239. {$ENDIF}
  240. {$IF DEFINED(FPC) AND DEFINED(MSWINDOWS)}
  241. function GetLastInputInfo(var plii: TLastInputInfo): BOOL;stdcall; external 'user32' name 'GetLastInputInfo';
  242. {$ENDIF}
  243. function RemoveLastChar(const aText : string) : string;
  244. function DateTimeToSQL(aDateTime : TDateTime) : string;
  245. {$IFDEF MSWINDOWS}
  246. var
  247. path : TEnvironmentPath;
  248. {$ENDIF}
  249. implementation
  250. {TFileHelper}
  251. {$IFNDEF FPC}
  252. {$IFDEF MSWINDOWS}
  253. class function TFileHelper.IsInUse(const FileName : string) : Boolean;
  254. var
  255. HFileRes: HFILE;
  256. begin
  257. Result := False;
  258. if not FileExists(FileName) then Exit;
  259. try
  260. HFileRes := CreateFile(PChar(FileName)
  261. ,GENERIC_READ or GENERIC_WRITE
  262. ,0
  263. ,nil
  264. ,OPEN_EXISTING
  265. ,FILE_ATTRIBUTE_NORMAL
  266. ,0);
  267. Result := (HFileRes = INVALID_HANDLE_VALUE);
  268. if not(Result) then begin
  269. CloseHandle(HFileRes);
  270. end;
  271. except
  272. Result := True;
  273. end;
  274. end;
  275. {$ENDIF}
  276. {$IFDEF DELPHILINUX}
  277. class function TFileHelper.IsInUse(const FileName : string) : Boolean;
  278. var
  279. fs : TFileStream;
  280. begin
  281. try
  282. fs := TFileStream.Create(FileName, fmOpenReadWrite, fmShareExclusive);
  283. Result := True;
  284. fs.Free;
  285. except
  286. Result := False;
  287. end;
  288. end;
  289. {$ENDIF}
  290. {$IFDEF MSWINDOWS}
  291. class function TFileHelper.GetSize(const FileName: String): Int64;
  292. var
  293. info: TWin32FileAttributeData;
  294. begin
  295. Result := -1;
  296. if not GetFileAttributesEx(PWideChar(FileName), GetFileExInfoStandard, @info) then Exit;
  297. Result := Int64(info.nFileSizeLow) or Int64(info.nFileSizeHigh shl 32);
  298. end;
  299. {$ELSE}
  300. class function TFileHelper.GetSize(const FileName: String): Int64;
  301. var
  302. sr : TSearchRec;
  303. begin
  304. if FindFirst(fileName, faAnyFile, sr ) = 0 then Result := sr.Size
  305. else Result := -1;
  306. end;
  307. {$ENDIF}
  308. {TDirectoryHelper}
  309. class function TDirectoryHelper.GetSize(const Path: String): Int64;
  310. var
  311. filename : string;
  312. begin
  313. Result := -1;
  314. for filename in TDirectory.GetFiles(Path) do
  315. begin
  316. Result := Result + TFile.GetSize(filename);
  317. end;
  318. end;
  319. {$ENDIF}
  320. {other functions}
  321. function RandomPassword(const PasswordLength : Integer; Complexity : TPasswordComplexity = [pfIncludeNumbers,pfIncludeSigns]) : string;
  322. const
  323. PassAlpha = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  324. PassSigns = '@!&$';
  325. PassNumbers = '1234567890';
  326. var
  327. MinNumbers,
  328. MinSigns : Integer;
  329. NumNumbers,
  330. NumSigns : Integer;
  331. begin
  332. Result := '';
  333. Randomize;
  334. //fill all alfa
  335. repeat
  336. Result := Result + PassAlpha[Random(Length(PassAlpha))+1];
  337. until (Length(Result) = PasswordLength);
  338. //checks if need include numbers
  339. if pfIncludeNumbers in Complexity then
  340. begin
  341. MinNumbers := Round(PasswordLength / 10 * 2);
  342. NumNumbers := 0;
  343. if MinNumbers = 0 then MinNumbers := 1;
  344. repeat
  345. Result[Random(PasswordLength)+1] := PassNumbers[Random(Length(PassNumbers))+1];
  346. Inc(NumNumbers);
  347. until NumNumbers = MinNumbers;
  348. end;
  349. //checks if need include signs
  350. if pfIncludeNumbers in Complexity then
  351. begin
  352. MinSigns := Round(PasswordLength / 10 * 1);
  353. NumSigns := 0;
  354. if MinSigns = 0 then MinSigns := 1;
  355. repeat
  356. Result[Random(PasswordLength)+1] := PassSigns[Random(Length(PassSigns))+1];
  357. Inc(NumSigns);
  358. until NumSigns = MinSigns;
  359. end;
  360. end;
  361. function ExtractFileNameWithoutExt(const FileName: string): string;
  362. begin
  363. Result := TPath.GetFileNameWithoutExtension(FileName);
  364. end;
  365. function UnixToWindowsPath(const UnixPath: string): string;
  366. begin
  367. Result := StringReplace(UnixPath, '/', '\',[rfReplaceAll, rfIgnoreCase]);
  368. end;
  369. function WindowsToUnixPath(const WindowsPath: string): string;
  370. begin
  371. Result := StringReplace(WindowsPath, '\', '/',[rfReplaceAll, rfIgnoreCase]);
  372. end;
  373. function CorrectURLPath(cUrl : string) : string;
  374. var
  375. nurl : string;
  376. begin
  377. nurl := WindowsToUnixPath(cUrl);
  378. nurl := StringReplace(nurl,'//','/',[rfReplaceAll]);
  379. Result := StringReplace(nurl,' ','%20',[rfReplaceAll]);
  380. //TNetEncoding.Url.Encode()
  381. end;
  382. {$IFDEF MSWINDOWS}
  383. procedure GetEnvironmentPaths;
  384. begin
  385. //gets path
  386. path.EXEPATH := TPath.GetDirectoryName(ParamStr(0));
  387. path.WINDOWS := SysUtils.GetEnvironmentVariable('windir');
  388. path.PROGRAMFILES := SysUtils.GetEnvironmentVariable('ProgramFiles');
  389. path.COMMONFILES := SysUtils.GetEnvironmentVariable('CommonProgramFiles(x86)');
  390. path.HOMEDRIVE := SysUtils.GetEnvironmentVariable('SystemDrive');
  391. path.USERPROFILE := SysUtils.GetEnvironmentVariable('USERPROFILE');
  392. path.PROGRAMDATA := SysUtils.GetEnvironmentVariable('ProgramData');
  393. path.ALLUSERSPROFILE := SysUtils.GetEnvironmentVariable('AllUsersProfile');
  394. path.INSTDRIVE := path.HOMEDRIVE;
  395. path.TEMP := SysUtils.GetEnvironmentVariable('TEMP');
  396. path.SYSTEM := GetSpecialFolderPath(CSIDL_SYSTEM);
  397. path.APPDATA:=GetSpecialFolderPath(CSIDL_APPDATA);
  398. //these paths fail if user is SYSTEM
  399. try
  400. path.DESKTOP := GetSpecialFolderPath(CSIDL_DESKTOP);
  401. path.DESKTOP_ALLUSERS := GetSpecialFolderPath(CSIDL_COMMON_DESKTOPDIRECTORY);
  402. path.STARTMENU:=GetSpecialFolderPath(CSIDL_PROGRAMS);
  403. path.STARTMENU_ALLUSERS:=GetSpecialFolderPath(CSIDL_COMMON_PROGRAMS);
  404. path.STARTMENU_ALLUSERS := path.STARTMENU;
  405. path.STARTUP:=GetSpecialFolderPath(CSIDL_STARTUP);
  406. except
  407. //
  408. end;
  409. end;
  410. function GetSpecialFolderPath(folderID : Integer) : string;
  411. var
  412. ppidl: PItemIdList;
  413. begin
  414. SHGetSpecialFolderLocation(0, folderID, ppidl);
  415. SetLength(Result, MAX_PATH);
  416. if not SHGetPathFromIDList(ppidl,{$IFDEF FPC}PAnsiChar(Result){$ELSE}PChar(Result){$ENDIF}) then
  417. begin
  418. raise EShellError.create(Format('GetSpecialFolderPath: Invalid PIPL (%d)',[folderID]));
  419. end;
  420. SetLength(Result, lStrLen({$IFDEF FPC}PAnsiChar(Result){$ELSE}PChar(Result){$ENDIF}));
  421. end;
  422. function Is64bitOS : Boolean;
  423. begin
  424. {$IFDEF WIN64}
  425. Result := True;
  426. {$ELSE}
  427. Result := False;
  428. {$ENDIF WIN64}
  429. end;
  430. function IsConsole: Boolean;
  431. begin
  432. {$IFDEF CONSOLE}
  433. Result := True;
  434. {$ELSE}
  435. Result := False;
  436. {$ENDIF CONSOLE}
  437. end;
  438. {$ENDIF}
  439. function IsDebug: Boolean;
  440. begin
  441. {$IFDEF DEBUG}
  442. Result := True;
  443. {$ELSE}
  444. Result := False;
  445. {$ENDIF DEBUG}
  446. end;
  447. {$IFDEF MSWINDOWS}
  448. function IsService : Boolean;
  449. begin
  450. //only working with my Quick.AppService unit
  451. try
  452. Result := (IsConsole) and (GetStdHandle(STD_OUTPUT_HANDLE) = 0);
  453. except
  454. Result := False;
  455. end;
  456. end;
  457. function SecondsIdle: DWord;
  458. var
  459. liInfo: TLastInputInfo;
  460. begin
  461. liInfo.cbSize := SizeOf(TLastInputInfo) ;
  462. GetLastInputInfo(liInfo) ;
  463. Result := (GetTickCount - liInfo.dwTime) DIV 1000;
  464. end;
  465. procedure FreeUnusedMem;
  466. begin
  467. if Win32Platform = VER_PLATFORM_WIN32_NT then SetProcessWorkingSetSize(GetCurrentProcess, $FFFFFFFF, $FFFFFFFF);
  468. end;
  469. function SetScreenResolution(Width, Height: integer): Longint;
  470. var
  471. DeviceMode: TDeviceMode;
  472. begin
  473. with DeviceMode do
  474. begin
  475. dmSize := SizeOf(TDeviceMode);
  476. dmPelsWidth := Width;
  477. dmPelsHeight := Height;
  478. dmFields := DM_PELSWIDTH or DM_PELSHEIGHT;
  479. end;
  480. Result := ChangeDisplaySettings(DeviceMode, CDS_UPDATEREGISTRY);
  481. end;
  482. {$ENDIF MSWINDOWS}
  483. function LastDayCurrentMonth: TDateTime;
  484. begin
  485. Result := EncodeDate(YearOf(Now),MonthOf(Now), DaysInMonth(Now));
  486. end;
  487. {$IFDEF FPC}
  488. function DateTimeInRange(ADateTime: TDateTime; AStartDateTime, AEndDateTime: TDateTime; aInclusive: Boolean = True): Boolean;
  489. begin
  490. if aInclusive then
  491. Result := (AStartDateTime <= ADateTime) and (ADateTime <= AEndDateTime)
  492. else
  493. Result := (AStartDateTime < ADateTime) and (ADateTime < AEndDateTime);
  494. end;
  495. {$ENDIF}
  496. function IsSameDay(cBefore, cNow : TDateTime) : Boolean;
  497. begin
  498. //Test: Result := MinutesBetween(cBefore,cNow) < 1;
  499. Result := DateTimeInRange(cNow,StartOfTheDay(cBefore),EndOfTheDay(cBefore),True);
  500. end;
  501. function ChangeTimeOfADay(aDate : TDateTime; aHour, aMinute, aSecond : Word; aMilliSecond : Word = 0) : TDateTime;
  502. var
  503. y, m, d : Word;
  504. begin
  505. DecodeDate(aDate,y,m,d);
  506. Result := EncodeDateTime(y,m,d,aHour,aMinute,aSecond,aMilliSecond);
  507. end;
  508. function ChangeDateOfADay(aDate : TDateTime; aYear, aMonth, aDay : Word) : TDateTime;
  509. var
  510. h, m, s, ms : Word;
  511. begin
  512. DecodeTime(aDate,h,m,s,ms);
  513. Result := EncodeDateTime(aYear,aMonth,aDay,h,m,s,0);
  514. end;
  515. function FillStr(const C : Char; const Count : Byte) : string;
  516. var
  517. i : Byte;
  518. begin
  519. Result := '';
  520. for i := 1 to Count do Result := Result + C;
  521. end;
  522. function StrInArray(const aValue : string; const aInArray : array of string) : Boolean;
  523. var
  524. s : string;
  525. begin
  526. for s in aInArray do
  527. begin
  528. if s = aValue then Exit(True);
  529. end;
  530. Result := False;
  531. end;
  532. function IntInArray(const aValue : Integer; const aInArray : array of Integer) : Boolean;
  533. var
  534. i : Integer;
  535. begin
  536. for i in aInArray do
  537. begin
  538. if i = aValue then Exit(True);
  539. end;
  540. Result := False;
  541. end;
  542. function Zeroes(const Number, Len : Int64) : string;
  543. begin
  544. if Len > Length(IntToStr(Number)) then Result := FillStr('0',Len - Length(IntToStr(Number))) + IntToStr(Number)
  545. else Result := IntToStr(Number);
  546. end;
  547. function NumberToStr(const Number : Int64) : string;
  548. begin
  549. try
  550. Result := FormatFloat('0,',Number);
  551. except
  552. Result := '#Error';
  553. end;
  554. end;
  555. function Spaces(const Count : Integer) : string;
  556. begin
  557. Result := FillStr(' ',Count);
  558. end;
  559. function NowStr : string;
  560. begin
  561. Result := DateTimeToStr(Now());
  562. end;
  563. function NewGuidStr : string;
  564. var
  565. guid : TGUID;
  566. begin
  567. guid.NewGuid;
  568. Result := guid.ToString
  569. //GUIDToString(guid);
  570. end;
  571. function IsLike(cText, Pattern: string) : Boolean;
  572. var
  573. i, n : Integer;
  574. match : Boolean;
  575. wildcard : Boolean;
  576. CurrentPattern : Char;
  577. begin
  578. Result := False;
  579. wildcard := False;
  580. cText := LowerCase(cText);
  581. Pattern := LowerCase(Pattern);
  582. match := False;
  583. if (Pattern.Length > cText.Length) or (Pattern = '') then Exit;
  584. if Pattern = '*' then
  585. begin
  586. Result := True;
  587. Exit;
  588. end;
  589. for i := 1 to cText.Length do
  590. begin
  591. CurrentPattern := Pattern[i];
  592. if CurrentPattern = '*' then wildcard := True;
  593. if wildcard then
  594. begin
  595. n := Pos(Copy(Pattern,i+1,Pattern.Length),cText);
  596. if (n > i) or (Pattern.Length = i) then
  597. begin
  598. Result := True;
  599. Exit;
  600. end;
  601. end
  602. else
  603. begin
  604. if (cText[i] = CurrentPattern) or (CurrentPattern = '?') then match := True
  605. else match := False;
  606. end;
  607. end;
  608. Result := match;
  609. end;
  610. function Capitalize(s: string): string;
  611. begin
  612. Result := '';
  613. if s.Length = 0 then Exit;
  614. s := LowerCase(s,loUserLocale);
  615. Result := UpperCase(s[1],loUserLocale) + Trim(Copy(s, 2, s.Length));
  616. end;
  617. function CapitalizeWords(s: string): string;
  618. var
  619. cword : string;
  620. begin
  621. Result := '';
  622. if s.Length = 0 then Exit;
  623. s := LowerCase(s,loUserLocale);
  624. for cword in s.Split([' ']) do
  625. begin
  626. if Result = '' then Result := Capitalize(cword)
  627. else Result := Result + ' ' + Capitalize(cword);
  628. end;
  629. end;
  630. function GetLoggedUserName : string;
  631. {$IFDEF MSWINDOWS}
  632. const
  633. cnMaxUserNameLen = 254;
  634. var
  635. sUserName : string;
  636. dwUserNameLen : DWord;
  637. begin
  638. dwUserNameLen := cnMaxUserNameLen-1;
  639. SetLength( sUserName, cnMaxUserNameLen );
  640. GetUserName(PChar( sUserName ),dwUserNameLen );
  641. SetLength( sUserName, dwUserNameLen );
  642. Result := sUserName;
  643. end;
  644. {$ELSE}
  645. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  646. begin
  647. Result := GetEnvironmentVariable('USERNAME');
  648. end;
  649. {$ELSE}
  650. begin
  651. Result := 'N/A';
  652. //raise ENotImplemented.Create('Not Android GetLoggedUserName implemented!');
  653. end;
  654. {$ENDIF}
  655. {$ENDIF}
  656. function GetComputerName : string;
  657. {$IFDEF MSWINDOWS}
  658. var
  659. dwLength: dword;
  660. begin
  661. dwLength := 253;
  662. SetLength(Result, dwLength+1);
  663. if not Windows.GetComputerName(pchar(result), dwLength) then Result := 'Not detected!';
  664. Result := pchar(result);
  665. end;
  666. {$ELSE}
  667. {$IF DEFINED(FPC) OR DEFINED(LINUX)}
  668. begin
  669. Result := GetEnvironmentVariable('COMPUTERNAME');
  670. end;
  671. {$ELSE} //Android gets model name
  672. begin
  673. Result := JStringToString(TJBuild.JavaClass.MODEL);
  674. end;
  675. {$ENDIF}
  676. {$ENDIF}
  677. function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
  678. begin
  679. if Delim = '\' then Result := StringReplace(cPath,'/',Delim,[rfReplaceAll])
  680. else Result := StringReplace(cPath,'\',Delim,[rfReplaceAll]);
  681. end;
  682. function RemoveLastPathSegment(cDir : string) : string;
  683. var
  684. posi : Integer;
  685. delim : Char;
  686. EndsWithDelim : Boolean;
  687. begin
  688. if cDir.Contains('\') then delim := '\'
  689. else if cDir.Contains('/') then delim := '/'
  690. else
  691. begin
  692. Result := '';
  693. Exit;
  694. end;
  695. NormalizePathDelim(cDir,delim);
  696. if cDir.EndsWith(delim) then
  697. begin
  698. cDir := Copy(cDir,1,cDir.Length-1);
  699. EndsWithDelim := True;
  700. end
  701. else EndsWithDelim := False;
  702. if cDir.CountChar(delim) > 1 then posi := cDir.LastDelimiter(delim)
  703. else posi := Pos(delim,cDir)-1;
  704. if posi = cDir.Length then posi := 0;
  705. Result := Copy(cDir,1,posi);
  706. if (Result <> '') and (EndsWithDelim) then Result := Result + delim;
  707. end;
  708. function ParamFindSwitch(const Switch : string) : Boolean;
  709. begin
  710. Result := FindCmdLineSwitch(Switch,['-', '/'],True);
  711. end;
  712. {$IFDEF FPC}
  713. function FindCmdLineSwitch(const Switch: string; var Value: string; IgnoreCase: Boolean = True;
  714. const SwitchTypes: TCmdLineSwitchTypes = [clstValueNextParam, clstValueAppended]): Boolean; overload;
  715. type
  716. TCompareProc = function(const S1, S2: string): Boolean;
  717. var
  718. Param: string;
  719. I, ValueOfs,
  720. SwitchLen, ParamLen: Integer;
  721. SameSwitch: TCompareProc;
  722. begin
  723. Result := False;
  724. Value := '';
  725. if IgnoreCase then
  726. SameSwitch := SameText else
  727. SameSwitch := SameStr;
  728. SwitchLen := Switch.Length;
  729. for I := 1 to ParamCount do
  730. begin
  731. Param := ParamStr(I);
  732. if CharInSet(Param.Chars[0], SwitchChars) and SameSwitch(Param.SubString(1,SwitchLen), Switch) then
  733. begin
  734. ParamLen := Param.Length;
  735. // Look for an appended value if the param is longer than the switch
  736. if (ParamLen > SwitchLen + 1) then
  737. begin
  738. // If not looking for appended value switches then this is not a matching switch
  739. if not (clstValueAppended in SwitchTypes) then
  740. Continue;
  741. ValueOfs := SwitchLen + 1;
  742. if Param.Chars[ValueOfs] = ':' then
  743. Inc(ValueOfs);
  744. Value := Param.SubString(ValueOfs, MaxInt);
  745. end
  746. // If the next param is not a switch, then treat it as the value
  747. else if (clstValueNextParam in SwitchTypes) and (I < ParamCount) and
  748. not CharInSet(ParamStr(I+1).Chars[0], SwitchChars) then
  749. Value := ParamStr(I+1);
  750. Result := True;
  751. Break;
  752. end;
  753. end;
  754. end;
  755. {$ENDIF}
  756. function ParamGetSwitch(const Switch : string; var cvalue : string) : Boolean;
  757. begin
  758. Result := FindCmdLineSwitch(Switch,cvalue,True,[clstValueAppended]);
  759. end;
  760. function GetAppName : string;
  761. begin
  762. Result := ExtractFilenameWithoutExt(ParamStr(0));
  763. end;
  764. function GetAppVersionStr: string;
  765. {$IFDEF MSWINDOWS}
  766. var
  767. Rec: LongRec;
  768. ver : Cardinal;
  769. begin
  770. ver := GetFileVersion(ParamStr(0));
  771. if ver <> Cardinal(-1) then
  772. begin
  773. Rec := LongRec(ver);
  774. Result := Format('%d.%d', [Rec.Hi, Rec.Lo]);
  775. end
  776. else Result := '';
  777. end;
  778. {$ELSE}
  779. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  780. var
  781. version : TProgramVersion;
  782. begin
  783. if GetProgramVersion(version) then Result := Format('%d.%d', [version.Major, version.Minor])
  784. else Result := '';
  785. end;
  786. {$ELSE}
  787. {$IFDEF NEXTGEN}
  788. var
  789. PkgInfo : JPackageInfo;
  790. begin
  791. PkgInfo := SharedActivity.getPackageManager.getPackageInfo(SharedActivity.getPackageName,0);
  792. Result := IntToStr(PkgInfo.VersionCode);
  793. end;
  794. {$ELSE}
  795. begin
  796. Result := 'N/A';
  797. end;
  798. {$ENDIF}
  799. {$ENDIF}
  800. {$ENDIF}
  801. function GetAppVersionFullStr: string;
  802. {$IFDEF MSWINDOWS}
  803. var
  804. Exe: string;
  805. Size, Handle: DWORD;
  806. Buffer: TBytes;
  807. FixedPtr: PVSFixedFileInfo;
  808. begin
  809. Result := '';
  810. Exe := ParamStr(0);
  811. Size := GetFileVersionInfoSize(PChar(Exe), Handle);
  812. if Size = 0 then
  813. begin
  814. //RaiseLastOSError;
  815. //no version info in file
  816. Exit;
  817. end;
  818. SetLength(Buffer, Size);
  819. if not GetFileVersionInfo(PChar(Exe), Handle, Size, Buffer) then
  820. RaiseLastOSError;
  821. if not VerQueryValue(Buffer, '\', Pointer(FixedPtr), Size) then
  822. RaiseLastOSError;
  823. if (LongRec(FixedPtr.dwFileVersionLS).Hi = 0) and (LongRec(FixedPtr.dwFileVersionLS).Lo = 0) then
  824. begin
  825. Result := Format('%d.%d',
  826. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  827. LongRec(FixedPtr.dwFileVersionMS).Lo]); //minor
  828. end
  829. else if (LongRec(FixedPtr.dwFileVersionLS).Lo = 0) then
  830. begin
  831. Result := Format('%d.%d.%d',
  832. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  833. LongRec(FixedPtr.dwFileVersionMS).Lo, //minor
  834. LongRec(FixedPtr.dwFileVersionLS).Hi]); //release
  835. end
  836. else
  837. begin
  838. Result := Format('%d.%d.%d.%d',
  839. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  840. LongRec(FixedPtr.dwFileVersionMS).Lo, //minor
  841. LongRec(FixedPtr.dwFileVersionLS).Hi, //release
  842. LongRec(FixedPtr.dwFileVersionLS).Lo]); //build
  843. end;
  844. end;
  845. {$ELSE}
  846. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  847. var
  848. version : TProgramVersion;
  849. begin
  850. if GetProgramVersion(version) then Result := Format('%d.%d.%d.%d', [version.Major, version.Minor, version.Revision, version.Build])
  851. else Result := '';
  852. end;
  853. {$ELSE}
  854. {$IFDEF NEXTGEN}
  855. var
  856. PkgInfo : JPackageInfo;
  857. begin
  858. PkgInfo := SharedActivity.getPackageManager.getPackageInfo(SharedActivity.getPackageName,0);
  859. Result := JStringToString(PkgInfo.versionName);
  860. end;
  861. {$ELSE}
  862. begin
  863. Result := 'N/A';
  864. end;
  865. {$ENDIF}
  866. {$ENDIF}
  867. {$ENDIF}
  868. function UTCToLocalTime(GMTTime: TDateTime): TDateTime;
  869. begin
  870. {$IFDEF FPC}
  871. Result := LocalTimeToUniversal(GMTTime);
  872. {$ELSE}
  873. Result := TTimeZone.Local.ToLocalTime(GMTTime);
  874. {$ENDIF}
  875. end;
  876. function LocalTimeToUTC(LocalTime : TDateTime): TDateTime;
  877. begin
  878. {$IFDEF FPC}
  879. Result := UniversalTimeToLocal(Localtime);
  880. {$ELSE}
  881. Result := TTimeZone.Local.ToUniversalTime(LocalTime);
  882. {$ENDIF}
  883. end;
  884. function DateTimeToGMT(aDate : TDateTime) : string;
  885. var
  886. FmtSettings : TFormatSettings;
  887. begin
  888. FmtSettings.DateSeparator := '-';
  889. FmtSettings.TimeSeparator := ':';
  890. FmtSettings.ShortDateFormat := 'YYYY-MM-DD"T"HH:NN:SS.ZZZ" GMT"';
  891. Result := DateTimeToStr(aDate,FmtSettings);
  892. end;
  893. function GMTToDateTime(aDate : string) : TDateTime;
  894. var
  895. FmtSettings : TFormatSettings;
  896. begin
  897. FmtSettings.DateSeparator := '-';
  898. FmtSettings.TimeSeparator := ':';
  899. FmtSettings.ShortDateFormat := 'YYYY-MM-DD"T"HH:NN:SS.ZZZ" GMT"';
  900. Result := StrToDateTime(aDate,FmtSettings);
  901. end;
  902. function DateTimeToJsonDate(aDateTime : TDateTime) : string;
  903. {$IFNDEF DELPHIXE7_UP}
  904. var
  905. FmtSettings : TFormatSettings;
  906. {$ENDIF}
  907. begin
  908. {$IFDEF DELPHIXE7_UP}
  909. Result := DateToISO8601(aDateTime);
  910. {$ELSE}
  911. FmtSettings.DateSeparator := '-';
  912. FmtSettings.TimeSeparator := ':';
  913. FmtSettings.ShortDateFormat := 'YYYY-MM-DD"T"HH:NN:SS.ZZZ"Z"';
  914. Result := DateTimeToStr(aDateTime,FmtSettings);
  915. {$ENDIF}
  916. end;
  917. function JsonDateToDateTime(const aJsonDate : string) : TDateTime;
  918. {$IFNDEF DELPHIXE7_UP}
  919. var
  920. FmtSettings : TFormatSettings;
  921. {$ENDIF}
  922. {$IFDEF FPC}
  923. var
  924. jdate : string;
  925. {$ENDIF}
  926. begin
  927. {$IFDEF DELPHIXE7_UP}
  928. Result := ISO8601ToDate(aJsonDate);
  929. {$ELSE}
  930. FmtSettings.DateSeparator := '-';
  931. FmtSettings.TimeSeparator := ':';
  932. FmtSettings.ShortDateFormat := 'YYYY-MM-DD"T"HH:NN:SS.ZZZ"Z"';
  933. {$IFDEF FPC}
  934. jdate := StringReplace(aJsondate,'T',' ',[rfIgnoreCase]);
  935. jdate := Copy(jdate,1,Pos('.',jdate)-1);
  936. Result := StrToDateTime(jdate,FmtSettings);
  937. {$ELSE}
  938. Result := StrToDateTime(aJsonDate,FmtSettings);
  939. {$ENDIF}
  940. {$ENDIF}
  941. end;
  942. function CountDigits(anInt: Cardinal): Cardinal; inline;
  943. var
  944. cmp: Cardinal;
  945. begin
  946. cmp := 10;
  947. Result := 1;
  948. while (Result < 10) and (cmp <= anInt) do
  949. begin
  950. cmp := cmp*10;
  951. Inc(Result);
  952. end;
  953. end;
  954. procedure SaveStreamToFile(stream : TStream; const filename : string);
  955. var
  956. fs : TFileStream;
  957. begin
  958. fs := TFileStream.Create(filename,fmCreate);
  959. try
  960. stream.Seek(0,soBeginning);
  961. fs.CopyFrom(stream,stream.Size);
  962. finally
  963. fs.Free;
  964. end;
  965. end;
  966. function CommaText(aList : TStringList) : string;
  967. var
  968. value : string;
  969. sb : TStringBuilder;
  970. begin
  971. if aList.Text = '' then Exit;
  972. sb := TStringBuilder.Create;
  973. try
  974. for value in aList do
  975. begin
  976. sb.Append(value);
  977. sb.Append(',');
  978. end;
  979. if sb.Length > 1 then Result := sb.ToString(0, sb.Length - 1);
  980. finally
  981. sb.Free;
  982. end;
  983. end;
  984. { TCounter }
  985. procedure TCounter.Init(aMaxValue : Integer);
  986. begin
  987. fMaxValue := aMaxValue;
  988. fCurrentValue := 0;
  989. end;
  990. function TCounter.Count : Integer;
  991. begin
  992. Result := fCurrentValue;
  993. end;
  994. function TCounter.CountIs(aValue : Integer) : Boolean;
  995. begin
  996. Result := fCurrentValue = aValue;
  997. end;
  998. function TCounter.Check : Boolean;
  999. begin
  1000. if fCurrentValue = fMaxValue then
  1001. begin
  1002. Result := True;
  1003. Reset;
  1004. end
  1005. else
  1006. begin
  1007. Result := False;
  1008. Inc(fCurrentValue);
  1009. end;
  1010. end;
  1011. procedure TCounter.Reset;
  1012. begin
  1013. fCurrentValue := fMaxValue;
  1014. end;
  1015. { TimeCounter }
  1016. procedure TTimeCounter.Init(MillisecondsToReach : Integer);
  1017. begin
  1018. fDoneEvery := MillisecondsToReach;
  1019. end;
  1020. function TTimeCounter.Check : Boolean;
  1021. begin
  1022. if MilliSecondsBetween(fCurrentTime,Now) > fDoneEvery then
  1023. begin
  1024. fCurrentTime := Now();
  1025. Result := True;
  1026. end
  1027. else Result := False;
  1028. end;
  1029. procedure TTimeCounter.Reset;
  1030. begin
  1031. fCurrentTime := Now();
  1032. end;
  1033. {$IFDEF MSWINDOWS}
  1034. procedure ProcessMessages;
  1035. var
  1036. Msg: TMsg;
  1037. begin
  1038. while integer(PeekMessage(Msg, 0, 0, 0, PM_REMOVE)) <> 0 do
  1039. begin
  1040. TranslateMessage(Msg);
  1041. DispatchMessage(Msg);
  1042. end;
  1043. end;
  1044. function GetLastOSError: String;
  1045. begin
  1046. Result := SysErrorMessage(Windows.GetLastError);
  1047. end;
  1048. {$ENDIF}
  1049. function RemoveLastChar(const aText : string) : string;
  1050. begin
  1051. Result := aText.Remove(aText.Length - 1);
  1052. end;
  1053. function DateTimeToSQL(aDateTime : TDateTime) : string;
  1054. begin
  1055. Result := FormatDateTime('YYYYMMDD hh:mm:ss',aDateTime);
  1056. end;
  1057. {$IFDEF MSWINDOWS}
  1058. initialization
  1059. try
  1060. GetEnvironmentPaths;
  1061. except
  1062. on E : Exception do
  1063. begin
  1064. if not IsService then
  1065. begin
  1066. if IsConsole then Writeln(Format('[WARN] GetEnvironmentPaths: %s',[E.Message]))
  1067. else raise EEnvironmentPath.Create(Format('Get environment path error: %s',[E.Message]));
  1068. end;
  1069. end;
  1070. end;
  1071. {$ENDIF}
  1072. end.