Quick.Commons.pas 56 KB

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