Quick.Commons.pas 55 KB

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