Quick.Commons.pas 30 KB

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