Quick.Commons.pas 30 KB

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