system.ioutils.pp 89 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738
  1. unit System.IOUtils;
  2. {
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2022 the Free Pascal development team
  5. FPC/Lazarus Replacement for IOUtils from Delphi 10.4
  6. Initially written 2022 by Dirk Jansen, completed by Michael Van Canneyt
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. }
  13. {$MODE OBJFPC}
  14. {$H+}
  15. { $IFDEF VER_3_2}
  16. {$modeswitch nestedprocvars}
  17. { $ELSE}
  18. {$modeswitch functionreferences}
  19. {$modeswitch anonymousfunctions}
  20. { $ENDIF}
  21. {$modeswitch arrayoperators}
  22. {$SCOPEDENUMS ON}
  23. interface
  24. {$IFDEF FPC_DOTTEDUNITS}
  25. uses
  26. System.Classes, System.SysUtils, System.Types, Fcl.Streams.Extra;
  27. {$ELSE FPC_DOTTEDUNITS}
  28. uses
  29. Classes, SysUtils, Types, streamex;
  30. {$ENDIF FPC_DOTTEDUNITS}
  31. type
  32. TPathPrefixType = (pptNoPrefix, pptExtended, pptExtendedUNC);
  33. TSearchOption = (soTopDirectoryOnly, soAllDirectories);
  34. TFileMode = (fmCreateNew, fmCreate, fmOpen, fmOpenOrCreate,
  35. fmTruncate, fmAppend);
  36. TFileAccess = (faRead, faWrite, faReadWrite);
  37. TFileShare = (fsNone, fsRead, fsWrite, fsReadWrite);
  38. {$IF DEFINED(WINDOWS)}
  39. TFileAttribute = (faReadOnly, faHidden, faSystem, faDirectory, faArchive,
  40. faDevice, faNormal, faTemporary, faSparseFile,
  41. faReparsePoint, faCompressed, faOffline,
  42. faNotContentIndexed, faEncrypted, faSymLink) ;
  43. {$ELSEIF DEFINED(UNIX)}
  44. TFileAttribute = (faNamedPipe, faCharacterDevice, faDirectory, faBlockDevice,
  45. faNormal, faSymLink, faSocket, faWhiteout,
  46. faOwnerRead, faOwnerWrite, faOwnerExecute,
  47. faGroupRead, faGroupWrite, faGroupExecute,
  48. faOthersRead, faOthersWrite, faOthersExecute,
  49. faUserIDExecution, faGroupIDExecution, faStickyBit);
  50. {$ELSE}
  51. TFileAttribute = (faReadOnly, faHidden, faSystem, faDirectory, faArchive,
  52. faNormal, faSymLink);
  53. {$ENDIF}
  54. TFileAttributes = set of TFileAttribute;
  55. TFilterPredicate = function(const aPath: string; const SearchRec: TSearchRec): Boolean;
  56. {$IFDEF VER3_2}
  57. TFilterPredicateLocal = function(const aPath: string; const SearchRec: TSearchRec): Boolean is nested;
  58. {$ELSE}
  59. TFilterPredicateLocal = reference to function(const aPath: string; const SearchRec: TSearchRec): Boolean;
  60. {$ENDIF}
  61. TFilterPredicateObject = function(const aPath: string; const SearchRec: TSearchRec): Boolean of object;
  62. { TDirectory }
  63. type
  64. TDirectory = class
  65. protected
  66. class function GetFilesAndDirectories(const aPath, aSearchPattern: string;
  67. const aSearchOption: TSearchOption; const SearchAttributes: TFileAttributes;
  68. const aPredicate: TFilterPredicateLocal): TStringDynArray; static;
  69. public
  70. class procedure Copy(const SourceDirName, DestDirName: string); static;
  71. class procedure CreateDirectory(const aPath: string); static;
  72. class procedure Delete(const aPath: string); overload; static;
  73. class procedure Delete(const aPath: string; const Recursive: Boolean); overload; static;
  74. class function Exists(const aPath: string; FollowLink: Boolean = True): Boolean; static;
  75. class function GetAttributes(const aPath: string; FollowLink: Boolean = True): TFileAttributes; static;
  76. class function GetCurrentDirectory: string; static;
  77. class procedure SetCurrentDirectory(const aPath: string); static;
  78. class function GetLogicalDrives: TStringDynArray; static;
  79. //class function GetCreationTime(const aPath: string): TDateTime;
  80. //class function GetCreationTimeUtc(const aPath: string): TDateTime;
  81. //class function GetLastAccessTime(const aPath: string): TDateTime;
  82. //class function GetLastAccessTimeUtc(const aPath: string): TDateTime;
  83. //class function GetLastWriteTime(const aPath: string): TDateTime;
  84. //class function GetLastWriteTimeUtc(const aPath: string): TDateTime;
  85. class procedure SetAttributes(const aPath: string; const Attributes: TFileAttributes); static;
  86. //class procedure SetCreationTime(const aPath: string; const CreationTime: TDateTime);
  87. //class procedure SetCreationTimeUtc(const aPath: string; const CreationTime: TDateTime);
  88. //class procedure SetLastAccessTime(const aPath: string; const LastAccessTime: TDateTime);
  89. //class procedure SetLastAccessTimeUtc(const aPath: string; const LastAccessTime: TDateTime);
  90. //class procedure SetLastWriteTime(const aPath: string; const LastWriteTime: TDateTime);
  91. //class procedure SetLastWriteTimeUtc(const aPath: string; const LastWriteTime: TDateTime);
  92. class function GetParent(const aPath: string): string; static;
  93. class function GetDirectories(const aPath: string): TStringDynArray; overload; static;
  94. class function GetDirectories(const aPath: string; const aPredicate: TFilterPredicateLocal): TStringDynArray; overload; static;
  95. class function GetDirectories(const aPath: string; const aPredicate: TFilterPredicateObject): TStringDynArray; overload; static;
  96. class function GetDirectories(const aPath: string; const aPredicate: TFilterPredicate): TStringDynArray; overload; static;
  97. class function GetDirectories(const aPath, aSearchPattern: string): TStringDynArray; overload; static;
  98. class function GetDirectories(const aPath, aSearchPattern: string; const aPredicate: TFilterPredicateLocal): TStringDynArray; overload; static;
  99. class function GetDirectories(const aPath, aSearchPattern: string; const aPredicate: TFilterPredicateObject): TStringDynArray; overload; static;
  100. class function GetDirectories(const aPath, aSearchPattern: string; const aPredicate: TFilterPredicate): TStringDynArray; overload; static;
  101. class function GetDirectories(const aPath, aSearchPattern: string; const aSearchOption: TSearchOption): TStringDynArray; overload; static;
  102. class function GetDirectories(const aPath, aSearchPattern: string; const aSearchOption: TSearchOption; const aPredicate: TFilterPredicateLocal): TStringDynArray; overload; static;
  103. class function GetDirectories(const aPath, aSearchPattern: string; const aSearchOption: TSearchOption; const aPredicate: TFilterPredicateObject): TStringDynArray; overload; static;
  104. class function GetDirectories(const aPath, aSearchPattern: string; const aSearchOption: TSearchOption; const aPredicate: TFilterPredicate): TStringDynArray; overload; static;
  105. class function GetDirectories(const aPath: string; const aSearchOption: TSearchOption; const aPredicate: TFilterPredicateLocal): TStringDynArray; overload; static;
  106. class function GetDirectories(const aPath: string; const aSearchOption: TSearchOption; const aPredicate: TFilterPredicateObject): TStringDynArray; overload; static;
  107. class function GetDirectories(const aPath: string; const aSearchOption: TSearchOption; const aPredicate: TFilterPredicate): TStringDynArray; overload; static;
  108. //class function GetDirectoryRoot(const aPath: string): string; { TODO -odj : UNC => \\Servername\Freigabe, sonst c:\, d:\ usw. }
  109. class function GetFiles(const aPath: string): TStringDynArray; overload; static;
  110. class function GetFiles(const aPath: string; const aPredicate: TFilterPredicateLocal): TStringDynArray; overload; static;
  111. class function GetFiles(const aPath: string; const aPredicate: TFilterPredicateObject): TStringDynArray; overload; static;
  112. class function GetFiles(const aPath: string; const aPredicate: TFilterPredicate): TStringDynArray; overload; static;
  113. class function GetFiles(const aPath, aSearchPattern: string): TStringDynArray; overload; static;
  114. class function GetFiles(const aPath, aSearchPattern: string; const aPredicate: TFilterPredicateLocal): TStringDynArray; overload; static;
  115. class function GetFiles(const aPath, aSearchPattern: string; const aPredicate: TFilterPredicateObject): TStringDynArray; overload; static;
  116. class function GetFiles(const aPath, aSearchPattern: string; const aPredicate: TFilterPredicate): TStringDynArray; overload; static;
  117. class function GetFiles(const aPath, aSearchPattern: string; const aSearchOption: TSearchOption): TStringDynArray; overload; static;
  118. class function GetFiles(const aPath, aSearchPattern: string;const aSearchOption: TSearchOption;const aPredicate: TFilterPredicateLocal): TStringDynArray; overload; static;
  119. class function GetFiles(const aPath, aSearchPattern: string;const aSearchOption: TSearchOption;const aPredicate: TFilterPredicateObject): TStringDynArray; overload; static;
  120. class function GetFiles(const aPath, aSearchPattern: string;const aSearchOption: TSearchOption;const aPredicate: TFilterPredicate): TStringDynArray; overload; static;
  121. class function GetFiles(const aPath: string;const aSearchOption: TSearchOption;const aPredicate: TFilterPredicateLocal): TStringDynArray; overload; static;
  122. class function GetFiles(const aPath: string;const aSearchOption: TSearchOption;const aPredicate: TFilterPredicateObject): TStringDynArray; overload; static;
  123. class function GetFiles(const aPath: string;const aSearchOption: TSearchOption;const aPredicate: TFilterPredicate): TStringDynArray; overload; static;
  124. class function GetFileSystemEntries(const aPath: string): TStringDynArray;overload; static;
  125. class function GetFileSystemEntries(const aPath: string; const aPredicate: TFilterPredicateLocal): TStringDynArray; overload; static;
  126. class function GetFileSystemEntries(const aPath: string; const aPredicate: TFilterPredicateObject): TStringDynArray; overload; static;
  127. class function GetFileSystemEntries(const aPath: string; const aPredicate: TFilterPredicate): TStringDynArray; overload; static;
  128. class function GetFileSystemEntries(const aPath, aSearchPattern: string): TStringDynArray; overload; static;
  129. class function GetFileSystemEntries(const aPath, aSearchPattern: string; const aPredicate: TFilterPredicateLocal): TStringDynArray; overload; static;
  130. class function GetFileSystemEntries(const aPath, aSearchPattern: string; const aPredicate: TFilterPredicateObject): TStringDynArray; overload; static;
  131. class function GetFileSystemEntries(const aPath, aSearchPattern: string; const aPredicate: TFilterPredicate): TStringDynArray; overload; static;
  132. class function GetFileSystemEntries(const aPath: string; const aSearchOption: TSearchOption; const aPredicate: TFilterPredicateLocal): TStringDynArray; overload; static;
  133. class function GetFileSystemEntries(const aPath: string; const aSearchOption: TSearchOption; const aPredicate: TFilterPredicateObject): TStringDynArray; overload; static;
  134. class function GetFileSystemEntries(const aPath: string; const aSearchOption: TSearchOption; const aPredicate: TFilterPredicate): TStringDynArray; overload; static;
  135. Class Procedure ForAllEntries(const aPath, aPattern: string; const aBefore, aAfter: TFilterPredicateLocal; aRecursive: Boolean); static;
  136. class function IsEmpty(const aPath: string): Boolean; static;
  137. class function IsRelativePath(const aPath: string): Boolean; static;
  138. class procedure Move(const SourceDirName, DestDirName: string); static;
  139. end;
  140. { TPath }
  141. TPath = class
  142. private
  143. class var FAltDirectorySeparatorChar: Char;
  144. class var FDirectorySeparatorChar: Char;
  145. class var FExtensionSeparatorChar: Char;
  146. class var FPathSeparator: Char;
  147. class var FVolumeSeparatorChar: Char;
  148. class var FInvalidPathChars : TCharArray;
  149. class var FinvalidFileNameChars : TCharArray;
  150. // FNMatch is case sensitive!
  151. class function FNMatch(const Pattern, Name: string): Boolean; static;
  152. class function IntGetPathRoot(const aPath: string): string; static;
  153. // Return position of first char after \\?\(UNC). Optionally return prefixtype.
  154. class function SkipExtendedPrefix(const aPath: string; out Prefix: TPathPrefixType): SizeInt; static;
  155. class function SkipExtendedPrefix(const aPath: String): SizeInt; static;
  156. {$ifdef mswindows}
  157. class function SkipRoot(const aPath: string): SizeInt; static;
  158. {$endif}
  159. public
  160. class constructor Create;
  161. class function IsValidPathChar(const AChar: Char): Boolean; static;
  162. class function IsValidFileNameChar(const AChar: Char): Boolean; static;
  163. class function HasValidPathChars(const aPath: string; const UseWildcards: Boolean = false): Boolean; inline; static;
  164. class function HasValidPathChars(const aPath: string; out Index: Integer; const UseWildcards: Boolean = false): Boolean; static;
  165. class function HasValidFileNameChars(const FileName: string; const UseWildcards: Boolean = False): Boolean; inline; static;
  166. class function HasValidFileNameChars(const FileName: string; out Index: Integer; const UseWildcards: Boolean = False): Boolean; static;
  167. class function GetExtendedPrefix(const aPath: string): TPathPrefixType; static;
  168. class function IsDriveRooted(const aPath: string): Boolean; static;
  169. class function IsExtendedPrefixed(const aPath: string): Boolean; static;
  170. class function IsRelativePath(const aPath: string): Boolean; static;
  171. class function IsUNCPath(const aPath: string): Boolean; static;
  172. class function IsUNCRooted(const aPath: string): Boolean; static;
  173. class function GetGUIDFileName(const UseSeparator: Boolean = False): string; static;
  174. class function DriveExists(const aPath: string): Boolean; static;
  175. class function MatchesPattern(const FileName, Pattern: string; const CaseSensitive: Boolean): Boolean; static;
  176. class function ChangeExtension(const aPath, Extension: string): string; static;
  177. class function Combine(const Path1, Path2: string; const ValidateParams: Boolean = True): string; static;
  178. class function Combine(const Path1, Path2, Path3: string; const ValidateParams: Boolean = True): string; static;
  179. class function Combine(const Path1, Path2, Path3, Path4: string; const ValidateParams: Boolean = True): string; static;
  180. class function Combine(const Paths: array of string; const ValidateParams: Boolean = True): string; static;
  181. class function GetDirectoryName(FileName: string): string; static;
  182. class function GetExtension(const FileName: string): string; static;
  183. class function GetFileName(const FileName: string): string; static;
  184. class function GetFileNameWithoutExtension(const FileName: string): string; static;
  185. class function GetFullPath(const aPath: string): string; static;
  186. class function GetInvalidFileNameChars: TCharArray; static;
  187. class function GetInvalidPathChars: TCharArray; static;
  188. class function GetPathRoot(const aPath: string): string; static;
  189. class function GetRandomFileName: string; static;
  190. class function GetTempFileName: string; static;
  191. class function GetTempPath: string; static;
  192. class function GetHomePath: string; static;
  193. class function GetDocumentsPath: string; static;
  194. class function GetDesktopPath: string; static;
  195. class function GetSharedDocumentsPath: string; static;
  196. class function GetLibraryPath: string; static;
  197. class function GetAppPath: string; static;
  198. class function GetCachePath: string; static;
  199. class function GetPublicPath: string; static;
  200. class function GetPicturesPath: string; static;
  201. class function GetSharedPicturesPath: string; static;
  202. class function GetCameraPath: string; static;
  203. class function GetSharedCameraPath: string; static;
  204. class function GetMusicPath: string; static;
  205. class function GetSharedMusicPath: string; static;
  206. class function GetMoviesPath: string; static;
  207. class function GetSharedMoviesPath: string; static;
  208. class function GetAlarmsPath: string; static;
  209. class function GetSharedAlarmsPath: string; static;
  210. class function GetDownloadsPath: string; static;
  211. class function GetSharedDownloadsPath: string; static;
  212. class function GetRingtonesPath: string; static;
  213. class function GetSharedRingtonesPath: string; static;
  214. class function GetTemplatesPath: string;
  215. class function GetAttributes(const aPath: string; aFollowLink: Boolean = True): TFileAttributes; static;
  216. class procedure SetAttributes(const aPath: string; const aAttributes: TFileAttributes); static;
  217. class function HasExtension(const aPath: string): Boolean; static;
  218. class function IsPathRooted(const aPath: string): Boolean; static;
  219. class property ExtensionSeparatorChar: Char read FExtensionSeparatorChar;
  220. class property AltDirectorySeparatorChar: Char read FAltDirectorySeparatorChar;
  221. class property DirectorySeparatorChar: Char read FDirectorySeparatorChar;
  222. class property PathSeparator: Char read FPathSeparator;
  223. class property VolumeSeparatorChar: Char read FVolumeSeparatorChar;
  224. end;
  225. { TFile }
  226. TFile = class
  227. private
  228. class function DetectFileEncoding(const aPath: String; out BOMLength: Integer): TEncoding; static;
  229. class procedure GetFileTimestamps(const aFilename: TFileName; var aCreate, aWrite, aAccess: TDateTime; IsUTC : Boolean); static;
  230. public
  231. class function IntegerToFileAttributes(const Attributes: Integer): TFileAttributes; static;
  232. class function FileAttributesToInteger(const Attributes: TFileAttributes): Integer; static;
  233. class function Create(const aPath: string): TFileStream; overload; static;
  234. class function Create(const aPath: string; const BufferSize: Integer): TFileStream; overload; static;
  235. Class function OpenOrCreate(const aPath: string) : TFileStream; static;
  236. class procedure AppendAllText(const aPath, aContents: string); overload; static;
  237. class procedure AppendAllText(const aPath, Contents: string; const Encoding: TEncoding); overload; static;
  238. class function AppendText(const aPath: string): TStreamWriter; static;
  239. class procedure Copy(const SourceFileName, DestFileName: string); overload; static;
  240. class procedure Copy(const SourceFileName, DestFileName: string; const Overwrite: Boolean); overload; static;
  241. class function CreateSymLink(const Link, Target: string): Boolean; static;
  242. class function CreateText(const aPath: string): TStreamWriter; static;
  243. class procedure Delete(const aPath: string); static;
  244. //{$IFDEF MSWINDOWS}
  245. // class procedure Decrypt(const aPath: string);
  246. // class procedure Encrypt(const aPath: string);
  247. //{$ENDIF MSWINDOWS}
  248. class function Exists(const aPath: string; FollowLink: Boolean = True): Boolean; static;
  249. class function GetAttributes(const aPath: string; FollowLink: Boolean = True): TFileAttributes; static;
  250. class function GetCreationTime(const aPath: string): TDateTime; static;
  251. class function GetCreationTimeUtc(const aPath: string): TDateTime; static;
  252. class function GetLastAccessTime(const aPath: string): TDateTime; static;
  253. class function GetLastAccessTimeUtc(const aPath: string): TDateTime; static;
  254. class function GetLastWriteTime(const aPath: string): TDateTime; static;
  255. class function GetLastWriteTimeUtc(const aPath: string): TDateTime; static;
  256. class function GetSymLinkTarget(const aFileName: string; var SymLinkRec: TSymLinkRec): Boolean; overload; static;
  257. class function GetSymLinkTarget(const aFileName: string; var TargetName: RawByteString): Boolean; overload; static;
  258. class function GetSymLinkTarget(const aFileName: Unicodestring; var TargetName: UnicodeString): Boolean; overload; static;
  259. class procedure Move(SourceFileName, DestFileName: string); static;
  260. class function Open(const aPath: string; const aMode: TFileMode): TFileStream; overload; static;
  261. class function Open(const aPath: string; const aMode: TFileMode; const aAccess: TFileAccess): TFileStream; overload; static;
  262. class function Open(const aPath: string; const aMode: TFileMode; const aAccess: TFileAccess; const aShare: TFileShare): TFileStream; overload; static;
  263. class function OpenRead(const aPath: string): TFileStream; static;
  264. class function OpenText(const aPath: string): TStreamReader; static;
  265. class function OpenWrite(const aPath: string): TFileStream; static;
  266. class function ReadAllBytes(const aPath: string): TBytes; static;
  267. class function ReadAllLines(const aPath: string): TStringDynArray; overload; static;
  268. class function ReadAllLines(const aPath: string; const aEncoding: TEncoding): TStringDynArray; overload; static;
  269. class function ReadAllText(const aPath: string): string; overload; static;
  270. class function ReadAllText(const aPath: string; const aEncoding: TEncoding): string; overload; static;
  271. class procedure Replace(const aSource, aDestination, aBackup: string); overload; static;
  272. {$IFDEF MSWINDOWS}
  273. class procedure Replace(const aSource, aDestination, aBackup: string; const aIgnoreMetadataErrors: Boolean); overload; static;
  274. {$ENDIF MSWINDOWS}
  275. class procedure SetAttributes(const aPath: string; const aAttributes: TFileAttributes); static;
  276. // class procedure SetCreationTime(const aPath: string; const CreationTime: TDateTime);
  277. // class procedure SetCreationTimeUtc(const aPath: string; const CreationTime: TDateTime);
  278. // class procedure SetLastAccessTime(const aPath: string; const LastAccessTime: TDateTime);
  279. // class procedure SetLastAccessTimeUtc(const aPath: string; const LastAccessTime: TDateTime);
  280. // class procedure SetLastWriteTime(const aPath: string; const LastWriteTime: TDateTime);
  281. // class procedure SetLastWriteTimeUtc(const aPath: string; const LastWriteTime: TDateTime);
  282. class procedure WriteAllBytes(const aPath: string; const aBytes: TBytes); static;
  283. class procedure WriteAllLines(const aPath: string; const aContents: TStringDynArray); overload; static;
  284. class procedure WriteAllLines(const aPath: string; const aContents: TStringDynArray; const aEncoding: TEncoding); overload; static;
  285. class procedure WriteAllText(const aPath, aContents: string); overload; static;
  286. class procedure WriteAllText(const aPath, aContents: string; const aEncoding: TEncoding); overload; static;
  287. end;
  288. implementation
  289. {$IFDEF FPC_DOTTEDUNITS}
  290. uses
  291. {$IfDef MSWINDOWS}
  292. WinApi.Windows, WinApi.WinDirs,
  293. {$EndIf}
  294. {$IfDef WINCE}
  295. WinApi.Windows,
  296. {$EndIf}
  297. {$IfDef Unix}
  298. UnixApi.Base,
  299. {$EndIf}
  300. System.DateUtils
  301. ;
  302. {$ELSE FPC_DOTTEDUNITS}
  303. uses
  304. {$IfDef MSWINDOWS}
  305. windows, WinDirs,
  306. {$EndIf}
  307. {$IfDef WINCE}
  308. windows,
  309. {$EndIf}
  310. {$IfDef UNIX}
  311. BaseUnix,
  312. {$EndIf}
  313. DateUtils
  314. ;
  315. {$ENDIF FPC_DOTTEDUNITS}
  316. ResourceString
  317. SErrFileExists = 'File "%s" already exists';
  318. SErrFileNotFound = 'File "%s" does not exist';
  319. SErrInvalidCharsInPath = 'Filename "%s" contains invalid characters.' ;
  320. SErrEmptyPath = 'Error: aPath is empty.' ;
  321. {$IfDef Unix}
  322. errStatFailed = 'Fstat for %a failed. Err.No.: %d';
  323. {$EndIf}
  324. {$IFDEF MSWINDOWS}
  325. Const
  326. WinAttrs : Array[TFileAttribute] of Integer =
  327. (FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_SYSTEM,
  328. FILE_ATTRIBUTE_DIRECTORY,FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_DEVICE,
  329. FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_TEMPORARY,FILE_ATTRIBUTE_SPARSE_FILE,
  330. FILE_ATTRIBUTE_REPARSE_POINT, FILE_ATTRIBUTE_COMPRESSED, FILE_ATTRIBUTE_OFFLINE,
  331. FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, FILE_ATTRIBUTE_ENCRYPTED,FILE_ATTRIBUTE_REPARSE_POINT);
  332. {$ENDIF}
  333. {$IFDEF WINCE}
  334. { Missing attributes are put to zero }
  335. Const
  336. WinAttrs : Array[TFileAttribute] of Integer =
  337. (FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_SYSTEM,
  338. FILE_ATTRIBUTE_DIRECTORY,FILE_ATTRIBUTE_ARCHIVE, 0{FILE_ATTRIBUTE_DEVICE},
  339. FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_TEMPORARY,FILE_ATTRIBUTE_SPARSE_FILE,
  340. FILE_ATTRIBUTE_REPARSE_POINT, FILE_ATTRIBUTE_COMPRESSED, FILE_ATTRIBUTE_OFFLINE,
  341. FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, FILE_ATTRIBUTE_ENCRYPTED,FILE_ATTRIBUTE_REPARSE_POINT);
  342. {$ENDIF}
  343. {$IFDEF WINDOWS}
  344. function FileAttributesToFlags(const Attributes: TFileAttributes): Integer;
  345. var
  346. A : TFileAttribute;
  347. begin
  348. Result:=0;
  349. For a in TFileAttributes do
  350. if a in Attributes then
  351. Result:=Result+WinAttrs[a];
  352. end;
  353. function FlagsToFileAttributes(const Flags : Integer) : TFileAttributes;
  354. var
  355. A : TFileAttribute;
  356. begin
  357. Result:=[];
  358. For a in TFileAttributes do
  359. if (Flags and WinAttrs[a])<>0 then
  360. Include(Result,a);
  361. end;
  362. {$ENDIF}
  363. {$IFDEF unix}
  364. Const
  365. UnixModes : Array[TFileAttribute] of Integer =
  366. (
  367. 0,0,0,0, // 0 means it can't be set
  368. 0,0,0,0,
  369. S_IRUSR, S_IWUSR,S_IXUSR,
  370. S_IRGRP,S_IWGRP, S_IXGRP,
  371. S_IROTH,S_IWOTH,S_IXOTH,
  372. S_ISUID,S_ISGID,0 {S_IVTX}
  373. );
  374. function FileAttributesToMode(const Attributes: TFileAttributes): Integer;
  375. var
  376. A : TFileAttribute;
  377. begin
  378. Result:=0;
  379. For a in TFileAttributes do
  380. if a in Attributes then
  381. Result:=Result+UnixModes[a];
  382. end;
  383. function ModeToFileAttributes(const Flags : Integer) : TFileAttributes;
  384. var
  385. A : TFileAttribute;
  386. begin
  387. Result:=[];
  388. For a in TFileAttributes do
  389. if (Flags and UnixModes[a])<>0 then
  390. Include(Result,a);
  391. end;
  392. {$ENDIF}
  393. function UTCtoLocal(const UTCDateTime: TDateTime): TDateTime;
  394. begin
  395. Result:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.UniversalTimeToLocal(UTCDateTime,GetLocalTimeOffset);
  396. end;
  397. { TPath }
  398. class constructor TPath.Create;
  399. var
  400. C : Char;
  401. begin
  402. FAltDirectorySeparatorChar:=#0;
  403. For C in AllowDirectorySeparators do
  404. if (C<>System.DirectorySeparator) and (FAltDirectorySeparatorChar=#0) then
  405. FAltDirectorySeparatorChar:=C;
  406. FExtensionSeparatorChar := System.ExtensionSeparator;
  407. FDirectorySeparatorChar := System.DirectorySeparator;
  408. FPathSeparator := System.PathSeparator;
  409. if Length(DriveSeparator)>0 then
  410. begin
  411. {$if defined(UNIX) or defined(WASI)}
  412. FVolumeSeparatorChar := DriveSeparator[1]
  413. {$else}
  414. FVolumeSeparatorChar := DriveSeparator
  415. {$endif}
  416. end
  417. else
  418. FVolumeSeparatorChar :=#0;
  419. end;
  420. class function TPath.IsValidPathChar(const AChar: Char): Boolean;
  421. begin
  422. Result:=(Ord(aChar)<32);
  423. {$IFNDEF UNIX}
  424. Result:=Result or CharInSet(aChar,[ '"', '<', '>', '|']);
  425. {$ENDIF}
  426. Result:=Not Result;
  427. end;
  428. class function TPath.IsValidFileNameChar(const AChar: Char): Boolean;
  429. begin
  430. Result:=(Ord(aChar)<32);
  431. {$IFNDEF UNIX}
  432. Result:=Result or CharInSet(aChar,[ '"', '*', '/', ':', '<', '>', '?', '\', '|']);
  433. {$ELSE}
  434. Result:=Result or CharInSet(aChar,[ '/', '~']) ;
  435. {$ENDIF}
  436. Result:=Not Result;
  437. end;
  438. class function TPath.SkipExtendedPrefix(const aPath: String): SizeInt;
  439. Var
  440. P : TPathPrefixType;
  441. begin
  442. Result:=SkipExtendedPrefix(aPath,P);
  443. end;
  444. class function TPath.SkipExtendedPrefix(const aPath: string; out Prefix: TPathPrefixType): SizeInt;
  445. Const
  446. pPrefix = '\\?\';
  447. UNCPrefix = pPrefix +'UNC\';
  448. LenPrefix = Length(pPrefix);
  449. lenUNCPrefix = Length(UNCPrefix);
  450. begin
  451. Prefix:=GetExtendedPrefix(aPath);
  452. case Prefix of
  453. TPathPrefixType.pptExtended:
  454. Result:=LenPrefix+1;
  455. TPathPrefixType.pptExtendedUNC:
  456. Result:=LenUNCPrefix+1;
  457. else
  458. Result:=1;
  459. end;
  460. end;
  461. {$ifdef mswindows}
  462. class function TPath.SkipRoot(const aPath: string): SizeInt;
  463. var
  464. P, Start: PChar;
  465. Skip: SizeInt;
  466. begin
  467. P := PChar(aPath); // Guarantee terminating #0 to avoid explicit length checks.
  468. if P[0] in AllowDirectorySeparators then
  469. if P[1] in AllowDirectorySeparators then
  470. begin
  471. Start := P;
  472. Inc(P, 2);
  473. // UNC: \\server\share, \\?\UNC\server\share, \\.\UNC\server\share. Devices: \\.\devicе, \\?\device.
  474. if (P[0] in ['.', '?']) and (P[1] in AllowDirectorySeparators) and
  475. (P[2] in ['u', 'U']) and (P[3] in ['n', 'N']) and (P[4] in ['c', 'C']) and (P[5] in AllowDirectorySeparators) then
  476. Inc(P, 6);
  477. // Skip two slash-delimited components. For UNC — server (P points to) and share, for devices — point/question mark (P points to) and device name.
  478. for Skip := 0 to 1 do
  479. repeat
  480. if P^ = #0 then break;
  481. Inc(P); // Includes the slash.
  482. until P[-1] in AllowDirectorySeparators; // Breaks on slash.
  483. Result := SizeUint(Pointer(P) - Pointer(Start)) div sizeof(Char);
  484. end else
  485. Result := 1 // One slash.
  486. else if (P[0] in ['a' .. 'z', 'A' .. 'Z']) and (P[1] = ':') then
  487. Result := 2 + ord(P[2] in AllowDirectorySeparators) // Drive plus maybe slash.
  488. else
  489. Result := 0;
  490. end;
  491. {$endif}
  492. class function TPath.HasValidPathChars(const aPath: string;
  493. const UseWildcards: Boolean): Boolean;
  494. var
  495. dummy: Integer;
  496. begin
  497. Result:=TPath.HasValidPathChars(aPath, dummy, UseWildcards);
  498. end;
  499. class function TPath.HasValidPathChars(const aPath: string;
  500. out Index: integer; const UseWildcards: Boolean): Boolean;
  501. var
  502. P: PChar;
  503. S,I,Len: Integer;
  504. C : Char;
  505. CheckWC : Boolean;
  506. begin
  507. Len:=Length(aPath);
  508. if Len=0 then
  509. Exit(True);
  510. Result:=False;
  511. CheckWC:=not UseWildcards;
  512. P:=PChar(aPath);
  513. S:=SkipExtendedPrefix(aPath);
  514. Inc(P,S-1);
  515. for I:=S to Len do
  516. begin
  517. Index:=i;
  518. C:=P^;
  519. if CheckWC and (CharInSet(C,['?','*'])) then
  520. exit;
  521. if not IsValidPathChar(C) then
  522. exit;
  523. Inc(P);
  524. end;
  525. Result:=True;
  526. end;
  527. class function TPath.HasValidFileNameChars(const FileName: string;
  528. const UseWildcards: Boolean): Boolean;
  529. var
  530. dummy: Integer;
  531. begin
  532. Result:=HasValidFileNameChars(FileName, dummy, UseWildCards);
  533. end;
  534. class function TPath.HasValidFileNameChars(const FileName: string;
  535. out Index: Integer; const UseWildcards: Boolean): Boolean;
  536. var
  537. P: PChar;
  538. S,I,Len: Integer;
  539. C : Char;
  540. CheckWC : Boolean;
  541. begin
  542. Len:=Length(FileName);
  543. if Len=0 then
  544. Exit(True);
  545. Result:=False;
  546. CheckWC:=not UseWildcards;
  547. P:=PChar(FileName);
  548. S:=SkipExtendedPrefix(FileName);
  549. Inc(P,S-1);
  550. for I:=S to Len do
  551. begin
  552. Index:=I;
  553. C:=P^;
  554. if CheckWC and (CharInSet(C,['?','*'])) then
  555. exit;
  556. if not IsValidFileNameChar(C) then
  557. exit;
  558. Inc(P);
  559. end;
  560. Result:=True;
  561. end;
  562. class function TPath.GetExtendedPrefix(const aPath: string): TPathPrefixType;
  563. begin
  564. Result:=TPathPrefixType.pptNoPrefix;
  565. {$IFDEF MSWINDOWS}
  566. if aPath.ToUpper.StartsWith(PathDelim + PathDelim + '?' + PathDelim + 'UNC' + PathDelim) then
  567. Result:=TPathPrefixType.pptExtendedUNC
  568. else if aPath.StartsWith(PathDelim + PathDelim + '?' + PathDelim) then
  569. Result:=TPathPrefixType.pptExtended
  570. {$ENDIF}
  571. end;
  572. class function TPath.IsDriveRooted(const aPath: string): Boolean;
  573. begin
  574. {$IfDef MSWINDOWS}
  575. Result:=(Length(aPath) > 1) and
  576. (aPath[1] in ['a'..'z', 'A'..'Z']) and
  577. (aPath[2] = ':');
  578. {$Else}
  579. Result:=False;
  580. {$EndIf}
  581. end;
  582. class function TPath.IsExtendedPrefixed(const aPath: string): Boolean;
  583. begin
  584. {$IfDef MSWINDOWS}
  585. Result:=aPath.StartsWith(PathSeparator + PathSeparator + '?' + PathDelim);
  586. {$Else}
  587. Result:=False;
  588. {$EndIf}
  589. end;
  590. class function TPath.IsRelativePath(const aPath: string): Boolean;
  591. begin
  592. Result:=(not aPath.StartsWith(PathDelim)) and
  593. (not TPath.IsDriveRooted(aPath)) and
  594. (not TPath.IsUNCRooted(aPath));
  595. end;
  596. class function TPath.IsUNCPath(const aPath: string): Boolean;
  597. begin
  598. {$IfDef MSWINDOWS}
  599. Result:=IsUNCRooted(aPath) and HasValidPathChars(aPath,False)
  600. {$Else}
  601. Result:=False;
  602. {$EndIf}
  603. end;
  604. class function TPath.IsUNCRooted(const aPath: string): Boolean;
  605. begin
  606. {$IfDef MSWINDOWS}
  607. Result:=False;
  608. if (Length(aPath)>=3) and (Copy(aPath,1,2)='//') then
  609. If (aPath[3]='?') then
  610. Result:=GetExtendedPrefix(aPath) = TPathPrefixType.pptExtendedUNC
  611. else
  612. Result:=IsValidPathChar(aPath[3]);
  613. {$Else}
  614. Result:=False;
  615. {$EndIf}
  616. end;
  617. class function TPath.GetGUIDFileName(const UseSeparator: Boolean): string;
  618. var
  619. Guid: TGUID;
  620. begin
  621. CreateGUID(Guid);
  622. Result:=GUIDToString(Guid);
  623. if not UseSeparator then
  624. Result:=StringReplace(Result, '-', '', [rfReplaceAll]);
  625. Result:=Copy(Result, 2, Length(Result) - 2);
  626. end;
  627. class function TPath.DriveExists(const aPath: string): Boolean;
  628. begin
  629. Result:=False;
  630. {$IfDef MSWINDOWS}
  631. try
  632. case GetDriveType(PAnsiChar(ExtractFileDrive(aPath))) of
  633. DRIVE_REMOVABLE,
  634. DRIVE_FIXED,
  635. DRIVE_REMOTE,
  636. DRIVE_CDROM,
  637. DRIVE_RAMDISK: Result:=True;
  638. end;
  639. except
  640. { no exception }
  641. end;
  642. {$EndIf}
  643. end;
  644. { assumes that pattern and name have the same code page }
  645. class function TPath.FNMatch(const Pattern, Name: string): Boolean;
  646. Var
  647. LenPat,LenName : longint;
  648. function NameUtf8CodePointLen(index: longint): longint;
  649. var
  650. MaxLookAhead: longint;
  651. begin
  652. MaxLookAhead:=LenName-Index+1;
  653. { abs so that in case of an invalid sequence, we count this as one
  654. codepoint }
  655. NameUtf8CodePointLen:=abs(Utf8CodePointLen(pansichar(@Name[index]),MaxLookAhead,true));
  656. { if the sequence was incomplete, use the incomplete sequence as
  657. codepoint }
  658. if NameUtf8CodePointLen=0 then
  659. NameUtf8CodePointLen:=MaxLookAhead;
  660. end;
  661. procedure GoToLastByteOfUtf8CodePoint(var j: longint);
  662. begin
  663. inc(j,NameUtf8CodePointLen(j)-1);
  664. end;
  665. { input:
  666. i: current position in pattern (start of utf-8 code point)
  667. j: current position in name (start of utf-8 code point)
  668. update_i_j: should i and j be changed by the routine or not
  669. output:
  670. i: if update_i_j, then position of last matching part of code point in
  671. pattern, or first non-matching code point in pattern. Otherwise the
  672. same value as on input.
  673. j: if update_i_j, then position of last matching part of code point in
  674. name, or first non-matching code point in name. Otherwise the
  675. same value as on input.
  676. result: true if match, false if no match
  677. }
  678. function CompareUtf8CodePoint(var i,j: longint; update_i_j: boolean): Boolean;
  679. var
  680. bytes,
  681. new_i,
  682. new_j: longint;
  683. begin
  684. bytes:=NameUtf8CodePointLen(j);
  685. new_i:=i;
  686. new_j:=j;
  687. { ensure that a part of an UTF-8 codepoint isn't interpreted
  688. as '*' or '?' }
  689. repeat
  690. dec(bytes);
  691. Result:=
  692. (new_j<=LenName) and
  693. (new_i<=LenPat) and
  694. (Pattern[new_i]=Name[new_j]);
  695. inc(new_i);
  696. inc(new_j);
  697. until not(Result) or
  698. (bytes=0);
  699. if update_i_j then
  700. begin
  701. i:=new_i;
  702. j:=new_j;
  703. end;
  704. end;
  705. Function DoFNMatch(i,j:longint):Boolean;
  706. Var
  707. UTF8, Found : boolean;
  708. Begin
  709. Found:=true;
  710. { ensure that we don't skip partial characters in UTF-8-encoded strings }
  711. UTF8:=StringCodePage(Name)=CP_UTF8;
  712. While Found and (i<=LenPat) Do
  713. Begin
  714. Case Pattern[i] of
  715. '?' :
  716. begin
  717. Found:=(j<=LenName);
  718. if UTF8 then
  719. GoToLastByteOfUtf8CodePoint(j);
  720. end;
  721. '*' : Begin
  722. {find the next character in pattern, different of ? and *}
  723. while Found do
  724. begin
  725. inc(i);
  726. if i>LenPat then
  727. Break;
  728. case Pattern[i] of
  729. '*' : ;
  730. '?' : begin
  731. if j>LenName then
  732. begin
  733. DoFNMatch:=false;
  734. Exit;
  735. end;
  736. if UTF8 then
  737. GoToLastByteOfUtf8CodePoint(j);
  738. inc(j);
  739. end;
  740. else
  741. Found:=false;
  742. end;
  743. end;
  744. Assert((i>LenPat) or ( (Pattern[i]<>'*') and (Pattern[i]<>'?') ));
  745. { Now, find in name the character which i points to, if the * or
  746. ? wasn't the last character in the pattern, else, use up all
  747. the chars in name }
  748. Found:=false;
  749. if (i<=LenPat) then
  750. begin
  751. repeat
  752. {find a letter (not only first !) which maches pattern[i]}
  753. if UTF8 then
  754. begin
  755. while (j<=LenName) and
  756. ((name[j]<>pattern[i]) or
  757. not CompareUtf8CodePoint(i,j,false)) do
  758. begin
  759. GoToLastByteOfUtf8CodePoint(j);
  760. inc(j);
  761. end;
  762. end
  763. else
  764. begin
  765. while (j<=LenName) and (name[j]<>pattern[i]) do
  766. inc (j);
  767. end;
  768. if (j<LenName) then
  769. begin
  770. { while positions i/j have already been checked, in
  771. case of UTF-8 we have to ensure that we don't split
  772. a code point. Otherwise we can skip over comparing
  773. the same characters twice }
  774. if DoFnMatch(i+ord(not UTF8),j+ord(not UTF8)) then
  775. begin
  776. i:=LenPat;
  777. j:=LenName;{we can stop}
  778. Found:=true;
  779. Break;
  780. end
  781. { We didn't find one, need to look further }
  782. else
  783. begin
  784. if UTF8 then
  785. GoToLastByteOfUtf8CodePoint(j);
  786. inc(j);
  787. end;
  788. end
  789. else if j=LenName then
  790. begin
  791. Found:=true;
  792. Break;
  793. end;
  794. { This 'until' condition must be j>LenName, not j>=LenName.
  795. That's because when we 'need to look further' and
  796. j = LenName then loop must not terminate. }
  797. until (j>LenName);
  798. end
  799. else
  800. begin
  801. j:=LenName;{we can stop}
  802. Found:=true;
  803. end;
  804. end;
  805. #128..#255:
  806. begin
  807. Found:=(j<=LenName) and (pattern[i]=name[j]);
  808. if Found and UTF8 then
  809. begin
  810. { ensure that a part of an UTF-8 codepoint isn't matched with
  811. '*' or '?' }
  812. Found:=CompareUtf8CodePoint(i,j,true);
  813. { at this point, either Found is false (and we'll stop), or
  814. both pattern[i] and name[j] are the end of the current code
  815. point and equal }
  816. end
  817. end
  818. else {not a wildcard character in pattern}
  819. Found:=(j<=LenName) and (pattern[i]=name[j]);
  820. end;
  821. inc(i);
  822. inc(j);
  823. end;
  824. DoFnMatch:=Found and (j>LenName);
  825. end;
  826. Begin {start FNMatch}
  827. LenPat:=Length(Pattern);
  828. LenName:=Length(Name);
  829. FNMatch:=DoFNMatch(1,1);
  830. End;
  831. class function TPath.MatchesPattern(const FileName, Pattern: string;
  832. const CaseSensitive: Boolean): Boolean;
  833. Var
  834. lFile,lPattern : String;
  835. begin
  836. lFile:=FileName;
  837. lPattern:=Pattern;
  838. if not CaseSensitive then
  839. begin
  840. lFile:=LowerCase(lFile);
  841. lPattern:=LowerCase(lPattern);
  842. end;
  843. if not HasValidFileNameChars(FileName, False) then
  844. raise EArgumentException.CreateFmt(SErrInvalidCharsInPath, [FileName]);
  845. Result:=(Pattern=AllFilesMask) or FNMatch(lPattern,lFile);
  846. end;
  847. class function TPath.ChangeExtension(const aPath, Extension: string): string;
  848. begin
  849. Result:=ChangeFileExt(aPath, Extension);
  850. end;
  851. class function TPath.Combine(const Path1, Path2: string; const ValidateParams : Boolean = True): string;
  852. begin
  853. Result:=TPath.Combine([Path1,Path2],ValidateParams)
  854. end;
  855. class function TPath.Combine(const Path1, Path2, Path3 : string; const ValidateParams : Boolean = True): string;
  856. begin
  857. Result:=Combine([Path1,Path2,Path3],ValidateParams);
  858. end;
  859. class function TPath.Combine(const Path1, Path2, Path3,Path4 : string; const ValidateParams : Boolean = True): string;
  860. begin
  861. Result:=Combine([Path1,Path2,Path3,Path4],ValidateParams);
  862. end;
  863. function AppendPathDelim(const Path: string): string;
  864. begin
  865. if (Path = '') or (Path[Length(Path)] in AllowDirectorySeparators)
  866. {$ifdef mswindows}
  867. //don't add a PathDelim to e.g. 'C:'
  868. or ((Length(Path) = 2) and (Path[2] = ':') and (UpCase(Path[1]) in ['A'..'Z']))
  869. {$endif}
  870. then
  871. Result:=Path
  872. else
  873. Result:=Path + DirectorySeparator;
  874. end;
  875. class function TPath.Combine(const Paths: array of string; const ValidateParams: Boolean = True): string;
  876. var
  877. {$ifdef mswindows} nRoot : SizeInt; {$endif}
  878. Path: String;
  879. begin
  880. Result := '';
  881. for Path in Paths do
  882. begin
  883. if Path = '' then
  884. continue;
  885. if ValidateParams and not TPath.HasValidPathChars(Path, False) then
  886. Raise EInOutArgumentException.CreateFmt(SErrInvalidCharsInPath,[Path],Path);
  887. {$ifdef mswindows}
  888. // Path starts with one \: root-relative.
  889. if (Path[1] in AllowDirectorySeparators) and ((Length(Path) < 2) or not (Path[2] in AllowDirectorySeparators)) then
  890. begin
  891. nRoot := SkipRoot(Result);
  892. if (nRoot > 0) and (Result[nRoot] in AllowDirectorySeparators) then
  893. dec(nRoot); // Skip trailing \ if present, as Path already starts with a separator.
  894. Result := Copy(Result, 1, nRoot) + Path;
  895. end else
  896. {$endif}
  897. if TPath.IsRelativePath(Path) then
  898. Result := AppendPathDelim(Result) + Path
  899. else
  900. Result := Path;
  901. end;
  902. end;
  903. class function TPath.GetDirectoryName(FileName: string): string;
  904. begin
  905. Result:=ExcludeTrailingPathDelimiter(ExtractFileDir(FileName));
  906. end;
  907. class function TPath.GetExtension(const FileName: string): string;
  908. begin
  909. Result:=ExtractFileExt(FileName);
  910. end;
  911. class function TPath.GetFileName(const FileName: string): string;
  912. begin
  913. Result:=ExtractFileName(FileName);
  914. end;
  915. class function TPath.GetFileNameWithoutExtension(const FileName: string
  916. ): string;
  917. begin
  918. Result:=ChangeFileExt(ExtractFileName(FileName), '');
  919. end;
  920. class function TPath.GetFullPath(const aPath: string): string;
  921. begin
  922. Result:=ExpandFileName(aPath);
  923. end;
  924. class function TPath.GetInvalidFileNameChars: TCharArray;
  925. Const
  926. ExtraChars : Array of Char
  927. {$IFNDEF UNIX}
  928. = ('"', '*', '/', ':', '<', '>', '?', '\', '|');
  929. {$ELSE}
  930. = ( '/', '~');
  931. {$ENDIF}
  932. Var
  933. I : Integer;
  934. begin
  935. if Length(FInvalidFileNameChars)=0 then
  936. begin
  937. SetLength(FInvalidFileNameChars,32+Length(ExtraChars));
  938. For I:=0 to 31 do
  939. FInvalidFileNameChars[i]:=Char(I);
  940. For I:=0 to Length(ExtraCHars)-1 do
  941. FInvalidFileNameChars[32+I]:=ExtraChars[i];
  942. end;
  943. Result:=FInvalidFilenameChars;
  944. end;
  945. class function TPath.GetInvalidPathChars: TCharArray;
  946. Const
  947. {$IFDEF UNIX}
  948. ExtraChars : Array of Char = ( '"', '<', '>', '|' );
  949. {$ELSE}
  950. ExtraChars : Array of Char = ();
  951. {$ENDIF}
  952. Var
  953. I : Integer;
  954. begin
  955. if Length(FInvalidPathChars)=0 then
  956. begin
  957. SetLength(FInvalidPathChars,32+Length(ExtraChars));
  958. For I:=0 to 31 do
  959. FInvalidPathChars[i]:=Char(I);
  960. For I:=0 to Length(ExtraCHars)-1 do
  961. FInvalidPathChars[32+I]:=ExtraChars[i];
  962. end;
  963. Result:=FInvalidPathChars;
  964. end;
  965. class function TPath.GetPathRoot(const aPath: string): string;
  966. begin
  967. if Trim(aPath) = '' then
  968. raise EInOutError.Create(SErrEmptyPath);
  969. if not HasValidPathChars(aPath, True) then
  970. raise EInOutError.CreateFmt(SErrInvalidCharsInPath, [aPath]);
  971. Result:=IntGetPathRoot(aPath);
  972. end;
  973. {$IF DEFINED(Unix)}
  974. class function TPath.IntGetPathRoot(const aPath: string): string;
  975. begin
  976. if (aPath <> '') and (aPath.Chars[0] = PathDelim) then
  977. Result:=PathDelim
  978. else
  979. Result:='';
  980. end;
  981. {$ELSEIF DEFINED(WINDOWS)}
  982. class function TPath.IntGetPathRoot(const aPath: string): string;
  983. var
  984. lPath: string;
  985. NeedSeparator: Boolean;
  986. aPos, ResLen, len: Integer;
  987. PPT: TPathPrefixType;
  988. begin
  989. lPath:=SetDirSeparators(aPath);
  990. len:=Length(lPath);
  991. NeedSeparator:=False;
  992. aPos:=SkipExtendedPrefix(lPath, PPT);
  993. ResLen:=0;
  994. if IsDriveRooted(lPath) then // Drive letter
  995. begin
  996. ResLen:=aPos+1;
  997. NeedSeparator:=(Len > 2) and (lPath[aPos]=PathDelim);
  998. if NeedSeparator and (PPT in [TPathPrefixType.pptExtended, TPathPrefixType.pptExtendedUNC]) then
  999. NeedSeparator:=False;
  1000. end
  1001. else if IsUNCRooted(aPath) then // UNC aPath
  1002. begin
  1003. aPos:=Pos(PathDelim,lPath,3);
  1004. if aPos > 0 then
  1005. begin
  1006. ResLen:=apos;
  1007. aPos:=Pos(PathDelim,aPath,aPos+1);
  1008. if aPos>0 then
  1009. ResLen:=aPos-1
  1010. end
  1011. else
  1012. ResLen:=Len;
  1013. end
  1014. else if aPos<=Len then
  1015. begin
  1016. ResLen:= Ord(lPath[aPos]=PathDelim);
  1017. if aPos<Len then
  1018. ResLen:=ResLen+Ord(lPath[aPos+1]=PathDelim);
  1019. end;
  1020. Result:=Copy(lPath,1,ResLen);
  1021. if NeedSeparator then
  1022. Result:=Result+PathDelim;
  1023. end;
  1024. {$ELSEIF DEFINED(HASAMIGA)}
  1025. class function TPath.IntGetPathRoot(const aPath: string): string;
  1026. begin
  1027. if Pos(DriveSeparator, aPath) > 0 then
  1028. Result := Copy(aPath, 1, Pos(DriveSeparator, aPath))
  1029. else
  1030. Result := '';
  1031. end;
  1032. {$ELSE}
  1033. class function TPath.IntGetPathRoot(const aPath: string): string;
  1034. begin
  1035. Result:='';
  1036. end;
  1037. {$ENDIF}
  1038. class function TPath.GetRandomFileName: string;
  1039. Const
  1040. SDigits = '01234567890';
  1041. SUppers = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  1042. SLowers = 'abcdefghijklmnopqrstuvwxyz';
  1043. SelectChars : Array[0..2] of string = (SDigits,SUppers,SLowers);
  1044. SelectLengths : Array[0..2] of integer = (Length(SDigits),Length(SUppers),Length(SLowers));
  1045. FNLen = 12;
  1046. ExtLen = 3;
  1047. DotAt = FNLen-ExtLen;
  1048. var
  1049. C,I: Byte;
  1050. begin
  1051. Result:=''; // DO NOT LOCALIZE
  1052. SetLength(Result,FNLen);
  1053. for i:=1 to FNLen do
  1054. if i <> DotAt then
  1055. begin
  1056. C:=Random(3);
  1057. Result[I]:=SelectChars[C][1+Random(SelectLengths[C])];
  1058. end
  1059. else
  1060. Result[i]:=ExtensionSeparatorChar;
  1061. end;
  1062. class function TPath.GetTempFileName: string;
  1063. begin
  1064. Result:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.GetTempFileName;
  1065. end;
  1066. class function TPath.GetTempPath: string;
  1067. begin
  1068. Result:=IncludeTrailingPathDelimiter({$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.GetTempDir);
  1069. end;
  1070. class function TPath.GetHomePath: string;
  1071. begin
  1072. Result:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.GetUserDir;
  1073. end;
  1074. {$ifdef UNIX}
  1075. type
  1076. TSpecialDir = (sdDesktop, sdDocuments, sdDownloads, sdMusic, sdPictures, sdPublic, sdTemplates, sdVideos);
  1077. {$IFNDEF darwin}
  1078. function GetSpecialDir(const AType: TSpecialDir): string;
  1079. const
  1080. Names : array[TSpecialDir] of string
  1081. = ('DESKTOP', 'DOCUMENTS', 'DOWNLOAD', 'MUSIC', 'PICTURES', 'PUBLICSHARE', 'TEMPLATES', 'VIDEOS');
  1082. var
  1083. cfg,varname: string;
  1084. L: TStringList;
  1085. begin
  1086. Result := '';
  1087. // XDG variable name
  1088. varName:=Format('XDG_%s_DIR',[Names[AType]]);
  1089. Cfg:=GetEnvironmentVariable('XDG_CONFIG_HOME');
  1090. if (Cfg='') then
  1091. Cfg:=GetUserDir+'.config/user-dirs.dirs'
  1092. else
  1093. CFG:=CFG+'user-dirs.dirs';
  1094. if not FileExists(Cfg) then
  1095. Exit;
  1096. L:=TStringList.Create;
  1097. try
  1098. L.LoadFromFile(Cfg);
  1099. Result:=AnsiDequotedStr(L.Values[VarName],'"');
  1100. finally
  1101. FreeAndNil(L);
  1102. end;
  1103. Result:=StringReplace(Result,'$HOME', ExcludeTrailingPathDelimiter(GetUserDir), [rfIgnoreCase]);
  1104. end;
  1105. {$else}
  1106. function GetSpecialDir(const AType: TSpecialDir): string;
  1107. begin
  1108. // Todo
  1109. Result:='';
  1110. end;
  1111. {$endif}
  1112. {$endif}
  1113. class function TPath.GetDocumentsPath: string;
  1114. begin
  1115. Result:='';
  1116. {$IfDef MSWINDOWS}
  1117. Result:=GetWindowsSpecialDir(CSIDL_PERSONAL, False);
  1118. {$ELSE}
  1119. {$IFDEF UNIX}
  1120. Result:=GetSpecialDir(TSpecialDir.sdDocuments);
  1121. {$ELSE}
  1122. Result:=GetUserDir;
  1123. {$ENDIF}
  1124. {$ENDIF}
  1125. end;
  1126. class function TPath.GetDesktopPath: string;
  1127. begin
  1128. Result:='';
  1129. {$IfDef MSWINDOWS}
  1130. Result:=GetWindowsSpecialDir(CSIDL_DESKTOPDIRECTORY, False);
  1131. {$ELSE}
  1132. {$IFDEF UNIX}
  1133. Result:=GetSpecialDir(TSpecialDir.sdDesktop);
  1134. {$ELSE}
  1135. Result:=GetUserDir;
  1136. {$ENDIF}
  1137. {$EndIf}
  1138. end;
  1139. class function TPath.GetSharedDocumentsPath: string;
  1140. begin
  1141. Result:='';
  1142. {$IfDef MSWINDOWS}
  1143. Result:=GetWindowsSpecialDir(CSIDL_COMMON_DOCUMENTS, False);
  1144. {$ELSE}
  1145. {$IFDEF UNIX}
  1146. Result:=GetSpecialDir(TSpecialDir.sdPublic);
  1147. {$ELSE}
  1148. Result:=GetUserDir;
  1149. {$ENDIF}
  1150. {$EndIf}
  1151. end;
  1152. class function TPath.GetLibraryPath: string;
  1153. begin
  1154. {$IFDEF UNIX}
  1155. Result := GetCurrentDir;
  1156. {$ELSE}
  1157. Result:=ExtractFilePath(ParamStr(0));
  1158. {$ENDIF}
  1159. end;
  1160. class function TPath.GetAppPath: string;
  1161. begin
  1162. Result:=ExtractFilePath(ParamStr(0));
  1163. end;
  1164. class function TPath.GetCachePath: string;
  1165. begin
  1166. {$IfDef MSWINDOWS}
  1167. Result:=GetWindowsSpecialDir(CSIDL_LOCAL_APPDATA, False);
  1168. {$ELSE}
  1169. {$IFDEF UNIX}
  1170. Result:=GetUserDir+'.cache'; // Check darwin
  1171. {$ELSE}
  1172. Result:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.GetTempDir;
  1173. {$ENDIF}
  1174. {$EndIf}
  1175. end;
  1176. class function TPath.GetPublicPath: string;
  1177. begin
  1178. Result:='';
  1179. {$IfDef MSWINDOWS}
  1180. Result:=GetWindowsSpecialDir(CSIDL_COMMON_APPDATA, False);
  1181. {$ELSE}
  1182. {$IFDEF UNIX}
  1183. Result:=GetSpecialDir(TSpecialDir.sdPublic);
  1184. {$ELSE}
  1185. Result:=GetUserDir;
  1186. {$ENDIF}
  1187. {$EndIf}
  1188. end;
  1189. class function TPath.GetPicturesPath: string;
  1190. begin
  1191. Result:='';
  1192. {$IfDef MSWINDOWS}
  1193. Result:=GetWindowsSpecialDir(CSIDL_MYPICTURES, False);
  1194. {$ELSE}
  1195. {$IFDEF UNIX}
  1196. Result:=GetSpecialDir(TSpecialDir.sdPictures);
  1197. {$ELSE}
  1198. Result:=GetUserDir;
  1199. {$ENDIF}
  1200. {$EndIf}
  1201. end;
  1202. class function TPath.GetSharedPicturesPath: string;
  1203. begin
  1204. Result:='';
  1205. {$IfDef MSWINDOWS}
  1206. Result:=GetWindowsSpecialDir(CSIDL_COMMON_PICTURES, False);
  1207. {$ELSE}
  1208. {$IFDEF UNIX}
  1209. Result:=GetSpecialDir(TSpecialDir.sdPublic);
  1210. {$ELSE}
  1211. Result:=GetUserDir;
  1212. {$ENDIF}
  1213. {$EndIf}
  1214. end;
  1215. class function TPath.GetCameraPath: string;
  1216. begin
  1217. Result:='';
  1218. {$IfDef MSWINDOWS}
  1219. Result:=GetWindowsSpecialDir(CSIDL_MYPICTURES, False);
  1220. {$EndIf}
  1221. end;
  1222. class function TPath.GetSharedCameraPath: string;
  1223. begin
  1224. Result:='';
  1225. {$IfDef MSWINDOWS}
  1226. Result:=GetWindowsSpecialDir(CSIDL_COMMON_PICTURES, False);
  1227. {$ELSE}
  1228. {$IFDEF UNIX}
  1229. Result:=GetSpecialDir(TSpecialDir.sdPublic);
  1230. {$ELSE}
  1231. Result:=GetUserDir;
  1232. {$ENDIF}
  1233. {$EndIf}
  1234. end;
  1235. class function TPath.GetMusicPath: string;
  1236. begin
  1237. Result:='';
  1238. {$IfDef MSWINDOWS}
  1239. Result:=GetWindowsSpecialDir(CSIDL_MYMUSIC, False);
  1240. {$ELSE}
  1241. {$IFDEF UNIX}
  1242. Result:=GetSpecialDir(TSpecialDir.sdMusic);
  1243. {$ELSE}
  1244. Result:=GetUserDir;
  1245. {$ENDIF}
  1246. {$EndIf}
  1247. end;
  1248. class function TPath.GetSharedMusicPath: string;
  1249. begin
  1250. Result:='';
  1251. {$IfDef MSWINDOWS}
  1252. Result:=GetWindowsSpecialDir(CSIDL_COMMON_MUSIC, False);
  1253. {$ELSE}
  1254. {$IFDEF UNIX}
  1255. Result:=GetSpecialDir(TSpecialDir.sdPublic);
  1256. {$ELSE}
  1257. Result:=GetUserDir;
  1258. {$ENDIF}
  1259. {$EndIf}
  1260. end;
  1261. class function TPath.GetMoviesPath: string;
  1262. begin
  1263. Result:='';
  1264. {$IfDef MSWINDOWS}
  1265. Result:=GetWindowsSpecialDir(CSIDL_MYVIDEO, False);
  1266. {$ELSE}
  1267. {$IFDEF UNIX}
  1268. Result:=GetSpecialDir(TSpecialDir.sdVideos);
  1269. {$ELSE}
  1270. Result:=GetUserDir;
  1271. {$ENDIF}
  1272. {$EndIf}
  1273. end;
  1274. class function TPath.GetSharedMoviesPath: string;
  1275. begin
  1276. Result:='';
  1277. {$IfDef MSWINDOWS}
  1278. Result:=GetWindowsSpecialDir(CSIDL_COMMON_VIDEO, False);
  1279. {$ELSE}
  1280. {$IFDEF UNIX}
  1281. Result:=GetSpecialDir(TSpecialDir.sdPublic);
  1282. {$ELSE}
  1283. Result:=GetUserDir;
  1284. {$ENDIF}
  1285. {$EndIf}
  1286. end;
  1287. class function TPath.GetAlarmsPath: string;
  1288. begin
  1289. Result:='';
  1290. {$IfDef MSWINDOWS}
  1291. Result:=GetWindowsSpecialDir(CSIDL_MYMUSIC, False);
  1292. {$ELSE}
  1293. {$IFDEF UNIX}
  1294. Result:=GetSpecialDir(TSpecialDir.sdMusic);
  1295. {$ELSE}
  1296. Result:=GetUserDir;
  1297. {$ENDIF}
  1298. {$EndIf}
  1299. end;
  1300. class function TPath.GetSharedAlarmsPath: string;
  1301. begin
  1302. Result:='';
  1303. {$IfDef MSWINDOWS}
  1304. Result:=GetWindowsSpecialDir(CSIDL_COMMON_MUSIC, False);
  1305. {$ELSE}
  1306. {$IFDEF UNIX}
  1307. Result:=GetSpecialDir(TSpecialDir.sdPublic);
  1308. {$ELSE}
  1309. Result:=GetUserDir;
  1310. {$ENDIF}
  1311. {$EndIf}
  1312. end;
  1313. class function TPath.GetDownloadsPath: string;
  1314. begin
  1315. Result:='';
  1316. {$IfDef MSWINDOWS}
  1317. Result:=GetWindowsSpecialDir(CSIDL_LOCAL_APPDATA, False);
  1318. {$ELSE}
  1319. {$IFDEF UNIX}
  1320. Result:=GetSpecialDir(TSpecialDir.sdDownloads);
  1321. {$ELSE}
  1322. Result:=GetUserDir;
  1323. {$ENDIF}
  1324. {$EndIf}
  1325. end;
  1326. class function TPath.GetSharedDownloadsPath: string;
  1327. begin
  1328. Result:='';
  1329. {$IfDef MSWINDOWS}
  1330. Result:=GetWindowsSpecialDir(CSIDL_COMMON_APPDATA, False);
  1331. {$ELSE}
  1332. {$IFDEF UNIX}
  1333. Result:=GetSpecialDir(TSpecialDir.sdPublic);
  1334. {$ELSE}
  1335. Result:=GetUserDir;
  1336. {$ENDIF}
  1337. {$EndIf}
  1338. end;
  1339. class function TPath.GetRingtonesPath: string;
  1340. begin
  1341. Result:='';
  1342. {$IfDef MSWINDOWS}
  1343. Result:=GetWindowsSpecialDir(CSIDL_MYMUSIC, False);
  1344. {$ELSE}
  1345. {$IFDEF UNIX}
  1346. Result:=GetSpecialDir(TSpecialDir.sdMusic);
  1347. {$ELSE}
  1348. Result:=GetUserDir;
  1349. {$ENDIF}
  1350. {$EndIf}
  1351. end;
  1352. class function TPath.GetSharedRingtonesPath: string;
  1353. begin
  1354. Result:='';
  1355. {$IfDef MSWINDOWS}
  1356. Result:=GetWindowsSpecialDir(CSIDL_COMMON_MUSIC, False);
  1357. {$ELSE}
  1358. {$IFDEF UNIX}
  1359. Result:=GetSpecialDir(TSpecialDir.sdPublic);
  1360. {$ELSE}
  1361. Result:=GetUserDir;
  1362. {$ENDIF}
  1363. {$EndIf}
  1364. end;
  1365. class function TPath.GetTemplatesPath: string;
  1366. begin
  1367. Result:='';
  1368. {$IfDef MSWINDOWS}
  1369. Result:=GetWindowsSpecialDir(CSIDL_PERSONAL, False);
  1370. {$ELSE}
  1371. {$IFDEF UNIX}
  1372. Result:=GetSpecialDir(TSpecialDir.sdTemplates);
  1373. {$ELSE}
  1374. Result:=GetUserDir;
  1375. {$ENDIF}
  1376. {$EndIf}
  1377. end;
  1378. class function TPath.GetAttributes(const aPath: string; aFollowLink: Boolean
  1379. ): TFileAttributes;
  1380. begin
  1381. Result:=TFile.GetAttributes(aPath, aFollowLink);
  1382. end;
  1383. class procedure TPath.SetAttributes(const aPath: string;
  1384. const aAttributes: TFileAttributes);
  1385. begin
  1386. TFile.SetAttributes(aPath, aAttributes);
  1387. end;
  1388. class function TPath.HasExtension(const aPath: string): Boolean;
  1389. begin
  1390. Result:=not (aPath = ChangeFileExt(aPath, ''));
  1391. end;
  1392. class function TPath.IsPathRooted(const aPath: string): Boolean;
  1393. begin
  1394. Result:=aPath.StartsWith(PathSeparator) or TPath.IsDriveRooted(aPath);
  1395. end;
  1396. { TFile }
  1397. class procedure TFile.GetFileTimestamps(const aFilename: TFileName; var aCreate, aWrite, aAccess: TDateTime; IsUTC: Boolean);
  1398. var
  1399. DateTime: TDateTimeInfoRec;
  1400. begin
  1401. if FileGetDateTimeInfo(aFileName,DateTime) then
  1402. begin
  1403. aCreate:=DateTime.CreationTime;
  1404. aWrite:=DateTime.TimeStamp;
  1405. aAccess:=DateTime.LastAccessTime;
  1406. if isUTC then
  1407. begin
  1408. aCreate:=LocalTimeToUniversal(aCreate);
  1409. aWrite:=LocalTimeToUniversal(aWrite);
  1410. aAccess:=LocalTimeToUniversal(aAccess);
  1411. end;
  1412. end
  1413. else
  1414. raise EInOutError.CreateFmt(SErrFileNotFound, [aFileName]);
  1415. end;
  1416. class function TFile.IntegerToFileAttributes(const Attributes: Integer
  1417. ): TFileAttributes;
  1418. procedure AddIfSet(var FileAttribs: TFileAttributes; const BitValue: Integer; FileAttrib: TFileAttribute);
  1419. begin
  1420. if (Attributes and BitValue) = BitValue then
  1421. FileAttribs:=FileAttribs + [FileAttrib];
  1422. end;
  1423. begin
  1424. {$If Defined(UNIX)}
  1425. // Assume full mode
  1426. Result:=ModeToFileAttributes(Attributes);
  1427. {$ElseIf Defined(WINDOWS)}
  1428. // Assume all flags
  1429. Result:=FlagsToFileAttributes(Attributes);
  1430. {$Else}
  1431. { Attributes supported by TSearchRec}
  1432. Result:=[];
  1433. AddIfSet(Result, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faDirectory, TFileAttribute.faDirectory);
  1434. AddIfSet(Result, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faSymLink{%H-}, TFileAttribute.faSymLink);
  1435. AddIfSet(Result, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faNormal, TFileAttribute.faNormal);
  1436. AddIfSet(Result, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faDirectory, TFileAttribute.faDirectory);
  1437. AddIfSet(Result, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faSymLink{%H-}, TFileAttribute.faSymLink);
  1438. AddIfSet(Result, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faHidden{%H-}, TFileAttribute.faHidden);
  1439. AddIfSet(Result, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faSysFile{%H-}, TFileAttribute.faSystem);
  1440. AddIfSet(Result, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faArchive, TFileAttribute.faArchive);
  1441. {$EndIf}
  1442. end;
  1443. {$IFDEF UNIX}
  1444. // We need full mode here, not just what TSearchRec has to offer
  1445. function FileGetAttr(const FN: string; FollowLink: Boolean): Integer;
  1446. var
  1447. st: tstat;
  1448. Res : Integer;
  1449. begin
  1450. Result:=0;
  1451. if FollowLink then
  1452. Res:=fpstat(FN,st)
  1453. else
  1454. Res:=fplstat(FN, st);
  1455. if Res=0 then
  1456. Result := st.st_mode
  1457. end;
  1458. {$ENDIF UNIX}
  1459. class function TFile.FileAttributesToInteger(const Attributes: TFileAttributes
  1460. ): Integer;
  1461. procedure AddIfSet(var AttribValue: Integer; const BitValue: Integer; FileAttrib: TFileAttribute);
  1462. begin
  1463. if FileAttrib in Attributes then
  1464. AttribValue:=AttribValue or BitValue;
  1465. end;
  1466. begin
  1467. Result:=0;
  1468. {$IFDEF UNIX}
  1469. // Assume full mode
  1470. Result:=FileAttributesToMode(Attributes);
  1471. {$ELSE}
  1472. {$IFDEF WINDOWS}
  1473. // Assume all flags
  1474. Result:=FileAttributesToFlags(Attributes);
  1475. {$ELSE}
  1476. // Assume attrs as in TSearchRec
  1477. AddIfSet(Result, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faDirectory, TFileAttribute.faDirectory);
  1478. AddIfSet(Result, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faSymLink{%H-}, TFileAttribute.faSymLink);
  1479. AddIfSet(Result, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faNormal, TFileAttribute.faNormal);
  1480. AddIfSet(Result, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faReadOnly, TFileAttribute.faReadOnly);
  1481. AddIfSet(Result, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faHidden{%H-}, TFileAttribute.faHidden);
  1482. AddIfSet(Result, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faSysFile{%H-}, TFileAttribute.faSystem);
  1483. AddIfSet(Result, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faArchive, TFileAttribute.faArchive);
  1484. {$EndIf}
  1485. {$EndIf}
  1486. end;
  1487. class function TFile.Create(const aPath: string): TFileStream;
  1488. begin
  1489. Result:=Create(aPath,0);
  1490. end;
  1491. class function TFile.Create(const aPath: string; const BufferSize: Integer
  1492. ): TFileStream;
  1493. begin
  1494. Result:=TFileStream.Create(aPath,{$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}Classes.fmCreate);
  1495. end;
  1496. class function TFile.OpenOrCreate(const aPath: string): TFileStream;
  1497. begin
  1498. If Exists(aPath) then
  1499. Result:=Open(aPath,TfileMode.fmOpen)
  1500. else
  1501. Result:=Create(aPath);
  1502. end;
  1503. class function TFile.DetectFileEncoding(const aPath: String; out
  1504. BOMLength: Integer): TEncoding;
  1505. Var
  1506. B : TBytes;
  1507. begin
  1508. B:=[];
  1509. Result:=TEncoding.Default;
  1510. With TFileStream.Create(aPath,fmOpenRead or fmShareDenyWrite) do
  1511. try
  1512. SetLength(B,4);
  1513. if Read(B[0],4)<2 then
  1514. Exit;
  1515. BOMLength:=TEncoding.GetBufferEncoding(B, Result);
  1516. finally
  1517. Free;
  1518. end;
  1519. end;
  1520. class procedure TFile.AppendAllText(const aPath, aContents: string);
  1521. Var
  1522. Encoding : TEncoding;
  1523. BOMLength : Integer;
  1524. begin
  1525. if FileExists(aPath) then
  1526. Encoding:=DetectFileEncoding(aPath,BOMlength)
  1527. else
  1528. Encoding:=TENcoding.Default;
  1529. AppendAllText(aPath,aContents,Encoding);
  1530. end;
  1531. class procedure TFile.AppendAllText(const aPath, Contents: string;
  1532. const Encoding: TEncoding);
  1533. Var
  1534. B : TBytes;
  1535. F : TFileStream;
  1536. begin
  1537. F:=OpenOrCreate(aPath);
  1538. try
  1539. {$IF SIZEOF(CHAR)=1}
  1540. B:=Encoding.GetAnsiBytes(Contents);
  1541. {$ELSE}
  1542. B:=Encoding.GetBytes(Contents);
  1543. {$ENDIF}
  1544. F.Seek(0,soEnd);
  1545. F.WriteBuffer(B[0],Length(B));
  1546. finally
  1547. F.Free;
  1548. end;
  1549. end;
  1550. class function TFile.AppendText(const aPath: string): TStreamWriter;
  1551. begin
  1552. Result:=TStreamWriter.Create(aPath,True)
  1553. end;
  1554. type
  1555. TCopyFileFlag = (
  1556. cffOverwriteFile,
  1557. cffCreateDestDirectory,
  1558. cffPreserveTime
  1559. );
  1560. TCopyFileFlags = set of TCopyFileFlag;
  1561. function CopyFile(const SrcFilename, DestFilename: string; Flags: TCopyFileFlags; ExceptionOnError: Boolean): boolean;
  1562. var
  1563. SrcHandle: THandle;
  1564. DestHandle: THandle;
  1565. Buffer: array[1..4096] of byte;
  1566. ReadCount, WriteCount, TryCount: LongInt;
  1567. begin
  1568. Result:=False;
  1569. // check overwrite
  1570. if (not (TCopyFileFlag.cffOverwriteFile in Flags)) and FileExists(DestFileName) then
  1571. exit;
  1572. // check directory
  1573. if (TCopyFileFlag.cffCreateDestDirectory in Flags)
  1574. and (not DirectoryExists(ExtractFilePath(DestFileName)))
  1575. and (not ForceDirectories(ExtractFilePath(DestFileName))) then
  1576. exit;
  1577. TryCount:=0;
  1578. While TryCount <> 3 Do Begin
  1579. SrcHandle:=FileOpen(SrcFilename, fmOpenRead or fmShareDenyWrite);
  1580. if THandle(SrcHandle)=feInvalidHandle then Begin
  1581. Inc(TryCount);
  1582. Sleep(10);
  1583. End
  1584. Else Begin
  1585. TryCount:=0;
  1586. Break;
  1587. End;
  1588. End;
  1589. If TryCount > 0 Then
  1590. begin
  1591. if ExceptionOnError then
  1592. raise EFOpenError.CreateFmt({SFOpenError}'Unable to open file "%s"', [SrcFilename])
  1593. else
  1594. exit;
  1595. end;
  1596. try
  1597. DestHandle:=FileCreate(DestFileName);
  1598. if (THandle(DestHandle)=feInvalidHandle) then
  1599. begin
  1600. if ExceptionOnError then
  1601. raise EFCreateError.CreateFmt({SFCreateError}'Unable to create file "%s"',[DestFileName])
  1602. else
  1603. Exit;
  1604. end;
  1605. try
  1606. repeat
  1607. ReadCount:=FileRead(SrcHandle,Buffer[1],High(Buffer));
  1608. if ReadCount<=0 then break;
  1609. WriteCount:=FileWrite(DestHandle,Buffer[1],ReadCount);
  1610. if WriteCount<ReadCount then
  1611. begin
  1612. if ExceptionOnError then
  1613. raise EWriteError.CreateFmt({SFCreateError}'Unable to write to file "%s"',[DestFileName])
  1614. else
  1615. Exit;
  1616. end;
  1617. until false;
  1618. finally
  1619. FileClose(DestHandle);
  1620. end;
  1621. if (TCopyFileFlag.cffPreserveTime in Flags) then
  1622. FileSetDate(DestFilename, FileGetDate(SrcHandle));
  1623. Result:=True;
  1624. finally
  1625. FileClose(SrcHandle);
  1626. end;
  1627. end;
  1628. class procedure TFile.Copy(const SourceFileName, DestFileName: string);
  1629. begin
  1630. CopyFile(SourceFileName, DestFileName, [TCopyFileFlag.cffPreserveTime],True);
  1631. end;
  1632. class procedure TFile.Copy(const SourceFileName, DestFileName: string;
  1633. const Overwrite: Boolean);
  1634. begin
  1635. if Overwrite then
  1636. CopyFile(SourceFileName, DestFileName, [TCopyFileFlag.cffOverwriteFile, TCopyFileFlag.cffPreserveTime],True)
  1637. else
  1638. CopyFile(SourceFileName, DestFileName, [TCopyFileFlag.cffPreserveTime],True);
  1639. end;
  1640. class function TFile.CreateSymLink(const Link, Target: string): Boolean;
  1641. begin
  1642. {$IFDEF UNIX}
  1643. Result:=fpLink(Target,Link)=0;
  1644. {$ELSE}
  1645. Result:=False;
  1646. {$ENDIF}
  1647. end;
  1648. class function TFile.CreateText(const aPath: string): TStreamWriter;
  1649. begin
  1650. Result:=TStreamWriter.Create(aPath,False);
  1651. end;
  1652. class procedure TFile.Delete(const aPath: string);
  1653. begin
  1654. {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.DeleteFile(aPath);
  1655. end;
  1656. class function TFile.Exists(const aPath: string; FollowLink: Boolean): Boolean;
  1657. begin
  1658. Result:=FileExists(aPath, FollowLink);
  1659. end;
  1660. class function TFile.GetAttributes(const aPath: string; FollowLink: Boolean
  1661. ): TFileAttributes;
  1662. begin
  1663. Result:=IntegerToFileAttributes(FileGetAttr(aPath{$ifdef unix},Followlink{$endif}));
  1664. end;
  1665. class function TFile.GetCreationTime(const aPath: string): TDateTime;
  1666. var
  1667. Dummy1, Dummy2: TDateTime;
  1668. begin
  1669. Result:=MinDateTime;
  1670. Dummy1:=MinDateTime;
  1671. Dummy2:=MinDateTime;
  1672. GetFileTimestamps(aPath, Result, Dummy1, Dummy2, False);
  1673. end;
  1674. class function TFile.GetCreationTimeUtc(const aPath: string): TDateTime;
  1675. var
  1676. Dummy1, Dummy2: TDateTime;
  1677. begin
  1678. Result:=MinDateTime;
  1679. Dummy1:=MinDateTime;
  1680. Dummy2:=MinDateTime;
  1681. GetFileTimestamps(aPath, Result, Dummy1, Dummy2, True);
  1682. end;
  1683. class function TFile.GetLastAccessTime(const aPath: string): TDateTime;
  1684. var
  1685. Dummy1, Dummy2: TDateTime;
  1686. begin
  1687. Result:=MinDateTime;
  1688. Dummy1:=MinDateTime;
  1689. Dummy2:=MinDateTime;
  1690. GetFileTimestamps(aPath, Dummy1, Dummy2, Result, False);
  1691. end;
  1692. class function TFile.GetLastAccessTimeUtc(const aPath: string): TDateTime;
  1693. var
  1694. Dummy1, Dummy2: TDateTime;
  1695. begin
  1696. Result:=MinDateTime;
  1697. Dummy1:=MinDateTime;
  1698. Dummy2:=MinDateTime;
  1699. GetFileTimestamps(aPath, Dummy1, Dummy2, Result,True);
  1700. end;
  1701. class function TFile.GetLastWriteTime(const aPath: string): TDateTime;
  1702. var
  1703. Dummy1, Dummy2: TDateTime;
  1704. begin
  1705. Result:=MinDateTime;
  1706. Dummy1:=MinDateTime;
  1707. Dummy2:=MinDateTime;
  1708. GetFileTimestamps(aPath, Dummy1, Result, Dummy2, False);
  1709. end;
  1710. class function TFile.GetLastWriteTimeUtc(const aPath: string): TDateTime;
  1711. var
  1712. Dummy1, Dummy2: TDateTime;
  1713. begin
  1714. Result:=MinDateTime;
  1715. Dummy1:=MinDateTime;
  1716. Dummy2:=MinDateTime;
  1717. GetFileTimestamps(aPath, Dummy1, Result, Dummy2,True);
  1718. end;
  1719. class function TFile.GetSymLinkTarget(const aFileName: string;
  1720. var SymLinkRec: TSymLinkRec): Boolean;
  1721. begin
  1722. Result:=FileGetSymLinkTarget(aFileName,SymLinkRec);
  1723. end;
  1724. class function TFile.GetSymLinkTarget(const aFileName: string;
  1725. var TargetName: RawByteString): Boolean;
  1726. begin
  1727. Result:=FileGetSymLinkTarget(aFileName,TargetName);
  1728. end;
  1729. class function TFile.GetSymLinkTarget(const aFileName: Unicodestring;
  1730. var TargetName: UnicodeString): Boolean;
  1731. begin
  1732. Result:=FileGetSymLinkTarget(aFileName,TargetName);
  1733. end;
  1734. class procedure TFile.Move(SourceFileName, DestFileName: string);
  1735. begin
  1736. if FileExists(DestFileName) then
  1737. raise EInOutError.CreateFmt(SerrFileExists, [DestFileName]);
  1738. if RenameFile(SourceFileName, DestFileName) then
  1739. Exit;
  1740. Copy(SourceFileName, DestFileName);
  1741. if FileExists(DestFileName) and FileExists(SourceFileName) then
  1742. Delete(SourceFileName);
  1743. end;
  1744. class function TFile.Open(const aPath: string; const aMode: TFileMode
  1745. ): TFileStream;
  1746. begin
  1747. Result:=Open(aPath,aMode,TFileAccess.faReadWrite)
  1748. end;
  1749. class function TFile.Open(const aPath: string; const aMode: TFileMode;
  1750. const aAccess: TFileAccess): TFileStream;
  1751. begin
  1752. Result:=Open(aPath, aMode, aAccess, TFileShare.fsNone);
  1753. end;
  1754. class function TFile.Open(const aPath: string; const aMode: TFileMode;
  1755. const aAccess: TFileAccess; const aShare: TFileShare): TFileStream;
  1756. Const
  1757. // faRead, faWrite, faReadWrite
  1758. AccessModes : Array[TFileAccess] of Word = ({$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.fmOpenRead, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.fmOpenWrite,fmOpenReadWrite) ;
  1759. // fsNone, fsRead, fsWrite, fsReadWrite
  1760. ShareModes : Array[TFileShare] of word = (fmShareExclusive, fmShareDenyRead, fmShareDenyWrite,fmShareDenyNone);
  1761. Var
  1762. acMode,sMode,fMode : Word;
  1763. begin
  1764. acMode:=AccessModes[aAccess];
  1765. sMode:=ShareModes[aShare];
  1766. fMode:=acMode or sMode;
  1767. case aMode of
  1768. TFileMode.fmCreateNew :
  1769. begin
  1770. if Exists(aPath) then
  1771. Raise EInOutError.CreateFmt(SErrFileExists,[aPath]);
  1772. Result:=TFileStream.Create(aPath,fMode);
  1773. end;
  1774. TFileMode.fmCreate:
  1775. Result:=TFileStream.Create(aPath, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}Classes.fmCreate or sMode);
  1776. TFileMode.fmOpen:
  1777. begin
  1778. if Exists(aPath) then
  1779. Raise EInOutError.CreateFmt(SErrFileNotFound,[aPath]);
  1780. Result:=TFileStream.Create(aPath,fMode);
  1781. end;
  1782. TFileMode.fmOpenOrCreate:
  1783. begin
  1784. if Exists(aPath) then
  1785. Result:=TFileStream.Create(aPath,fMode)
  1786. else
  1787. Result:=TFileStream.Create(aPath,{$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}Classes.fmCreate or sMode);
  1788. end;
  1789. TFileMode.fmTruncate:
  1790. begin
  1791. if not Exists(aPath) then
  1792. raise EInoutError.CreateFmt(SErrFileNotFound, [aPath]);
  1793. Result:=TFileStream.Create(aPath,fMode);
  1794. Result.Size:=0;
  1795. end;
  1796. TFileMode.fmAppend:
  1797. begin
  1798. if Exists(aPath) then
  1799. begin
  1800. Result:=TFileStream.Create(aPath, fMode);
  1801. Result.Seek(0,soEnd);
  1802. end
  1803. else
  1804. Result:=TFileStream.Create(aPath, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}Classes.fmCreate or sMode);
  1805. end;
  1806. end;
  1807. end;
  1808. class function TFile.OpenRead(const aPath: string): TFileStream;
  1809. begin
  1810. Result:=TFileStream.Create(aPath, fmOpenRead or fmShareDenyWrite);
  1811. end;
  1812. class function TFile.OpenText(const aPath: string): TStreamReader;
  1813. var
  1814. F : TFileStream;
  1815. begin
  1816. Result:=Nil;
  1817. F:=TFilestream.Create(aPath,fmOpenRead or fmShareDenyWrite);
  1818. try
  1819. Result := TStreamReader.Create(F,BUFFER_SIZE,True);
  1820. except
  1821. F.Free;
  1822. Raise;
  1823. end
  1824. end;
  1825. class function TFile.OpenWrite(const aPath: string): TFileStream;
  1826. begin
  1827. Result:=TFileStream.Create(aPath,fmOpenWrite);
  1828. end;
  1829. class function TFile.ReadAllBytes(const aPath: string): TBytes;
  1830. begin
  1831. Result:=[];
  1832. With OpenRead(aPath) do
  1833. try
  1834. SetLength(Result,Size);
  1835. ReadBuffer(Result,Size);
  1836. finally
  1837. Free;
  1838. end;
  1839. end;
  1840. class function TFile.ReadAllLines(const aPath: string): TStringDynArray;
  1841. Var
  1842. aBOMLength : Integer;
  1843. begin
  1844. Result:=ReadAllLines(aPath,DetectFileEncoding(aPath,aBomLength));
  1845. end;
  1846. class function TFile.ReadAllLines(const aPath: string; const aEncoding: TEncoding
  1847. ): TStringDynArray;
  1848. begin
  1849. With TStringList.Create do
  1850. try
  1851. LoadFromFile(aPath,aEncoding);
  1852. Result:=ToStringArray;
  1853. finally
  1854. Free;
  1855. end;
  1856. end;
  1857. class function TFile.ReadAllText(const aPath: string): string;
  1858. var
  1859. aBOMLength : Integer;
  1860. begin
  1861. Result:=ReadAllText(aPath,DetectFIleEncoding(aPath,aBOMLength));
  1862. end;
  1863. class function TFile.ReadAllText(const aPath: string; const aEncoding: TEncoding
  1864. ): string;
  1865. Var
  1866. B : TBytes;
  1867. begin
  1868. B:=ReadAllBytes(aPath);
  1869. {$if sizeof(char)=1}
  1870. Result:=aEncoding.GetAnsiString(B);
  1871. {$else}
  1872. Result:=aEncoding.GetString(B);
  1873. {$endif}
  1874. end;
  1875. {$IFDEF MSWINDOWS}
  1876. function ReplaceFileA(lpReplacedFileName, lpReplacementFileName, lpBackupFileName: LPCSTR; dwReplaceFlags: DWORD; lpExclude: LPVOID; lpReserved: LPVOID): BOOL; stdcall; external 'kernel32' name 'ReplaceFileA';
  1877. function ReplaceFileW(lpReplacedFileName, lpReplacementFileName, lpBackupFileName: LPCWSTR; dwReplaceFlags: DWORD; lpExclude: LPVOID; lpReserved: LPVOID): BOOL; stdcall; external 'kernel32' name 'ReplaceFileW';
  1878. class procedure TFile.Replace(const aSource, aDestination, aBackup: string; const aIgnoreMetadataErrors: Boolean); overload;
  1879. var
  1880. lBackup,lDest,lSrc : String;
  1881. ReplaceFlags : DWord;
  1882. begin
  1883. lDest:=ExpandFileName(aDestination);
  1884. lSrc:=ExpandFileName(aSource);
  1885. lBackup:=ExpandFileName(aBackup);
  1886. ReplaceFlags:=REPLACEFILE_WRITE_THROUGH;
  1887. if aIgnoreMetadataErrors then
  1888. ReplaceFlags:=ReplaceFlags or REPLACEFILE_IGNORE_MERGE_ERRORS;
  1889. ReplaceFileA(PAnsiChar(lDest),PAnsiChar(lSrc),PAnsiChar(lBackup),ReplaceFlags,nil,nil);
  1890. end;
  1891. {$ENDIF MSWINDOWS}
  1892. class procedure TFile.Replace(const aSource, aDestination,
  1893. aBackup: string);
  1894. var
  1895. lBackup,lDest,lSrc : String;
  1896. begin
  1897. lDest:=ExpandFileName(aDestination);
  1898. lSrc:=ExpandFileName(aSource);
  1899. lBackup:=ExpandFileName(aBackup);
  1900. if CopyFile(lDest,lBackup,[],False) then
  1901. if CopyFile(lSrc,lDest,[TCopyFileFlag.cffOverwriteFile],False) then
  1902. Delete(lSrc);
  1903. end;
  1904. class procedure TFile.SetAttributes(const aPath: string;
  1905. const aAttributes: TFileAttributes);
  1906. begin
  1907. {$ifdef unix}
  1908. fpCHmod(aPath,FileAttributesToInteger(aAttributes));
  1909. {$else}
  1910. {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.FileSetAttr(aPath, FileAttributesToInteger(aAttributes));
  1911. {$endif}
  1912. end;
  1913. class procedure TFile.WriteAllBytes(const aPath: string; const aBytes: TBytes);
  1914. begin
  1915. With Create(aPath) do
  1916. try
  1917. WriteBuffer(aBytes,Length(aBytes));
  1918. finally
  1919. Free
  1920. end;
  1921. end;
  1922. class procedure TFile.WriteAllLines(const aPath: string;
  1923. const aContents: TStringDynArray);
  1924. begin
  1925. WriteAllLines(aPath,aContents,TEncoding.UTF8);
  1926. end;
  1927. class procedure TFile.WriteAllLines(const aPath: string;
  1928. const aContents: TStringDynArray; const aEncoding: TEncoding);
  1929. var
  1930. L : TStringList;
  1931. begin
  1932. L:=TStringList.Create;
  1933. try
  1934. L.SetStrings(aContents);
  1935. L.SaveToFile(aPath,aEncoding);
  1936. finally
  1937. L.Free;
  1938. end;
  1939. end;
  1940. class procedure TFile.WriteAllText(const aPath, aContents: string);
  1941. begin
  1942. WriteAllText(aPath,aContents,TEncoding.UTF8);
  1943. end;
  1944. class procedure TFile.WriteAllText(const aPath, aContents: string;
  1945. const aEncoding: TEncoding);
  1946. begin
  1947. {$IF SIZEOF(CHAR)=1}
  1948. WriteAllBytes(aPath,aEncoding.GetAnsiBytes(aContents));
  1949. {$ELSE}
  1950. WriteAllBytes(aPath,aEncoding.GetBytes(aContents));
  1951. {$ENDIF}
  1952. end;
  1953. { TDirectory }
  1954. class function TDirectory.GetFilesAndDirectories(const aPath,
  1955. aSearchPattern: string; const aSearchOption: TSearchOption;
  1956. const SearchAttributes: TFileAttributes;
  1957. const aPredicate: TFilterPredicateLocal): TStringDynArray;
  1958. function FilterPredicate(const aPath: string; const SearchRec: TSearchRec): Boolean;
  1959. begin
  1960. Result:=(SearchRec.Name <> '.') and (SearchRec.Name <> '..');
  1961. if Result and Assigned(aPredicate) then
  1962. Result:=aPredicate(aPath, SearchRec);
  1963. end;
  1964. var
  1965. SearchRec: TSearchRec;
  1966. IntPath: TFileName;
  1967. begin
  1968. IntPath :=IncludeTrailingPathDelimiter(aPath);
  1969. Result :=[];
  1970. if (FindFirst(IntPath + aSearchPattern, TFile.FileAttributesToInteger(SearchAttributes), SearchRec) = 0) then
  1971. repeat
  1972. if (aSearchOption = TSearchOption.soAllDirectories) and ((SearchRec.Attr and {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faDirectory) <> 0)
  1973. and (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then
  1974. Result:=Result + GetFilesAndDirectories(IntPath + SearchRec.Name, aSearchPattern, aSearchOption, SearchAttributes, aPredicate)
  1975. else if FilterPredicate(aPath, SearchRec) then
  1976. Result:=Result + [IntPath + SearchRec.Name];
  1977. until FindNext(SearchRec) <> 0;
  1978. {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.FindClose(SearchRec);
  1979. end;
  1980. class procedure TDirectory.Copy(const SourceDirName, DestDirName: string);
  1981. begin
  1982. CopyFile(SourceDirName, DestDirName,[],True);
  1983. end;
  1984. class procedure TDirectory.CreateDirectory(const aPath: string);
  1985. begin
  1986. ForceDirectories(aPath);
  1987. end;
  1988. function DeleteDirectory(const DirectoryName: string; OnlyChildren: boolean): boolean;
  1989. const
  1990. //Don't follow symlinks on *nix, just delete them
  1991. DeleteMask = faAnyFile {$ifdef unix} or {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}sysutils.faSymLink{%H-} {$endif unix};
  1992. var
  1993. FileInfo: TSearchRec;
  1994. CurSrcDir: String;
  1995. CurFilename: String;
  1996. begin
  1997. Result:=false;
  1998. CurSrcDir:=ExpandFileName(DirectoryName);
  1999. CurSrcDir:=IncludeTrailingPathDelimiter(CurSrcDir);
  2000. if FindFirst(CurSrcDir+AllFilesMask,DeleteMask,FileInfo)=0 then
  2001. Try
  2002. repeat
  2003. // check if special file
  2004. if (FileInfo.Name='.') or (FileInfo.Name='..') or (FileInfo.Name='') then
  2005. continue;
  2006. CurFilename:=CurSrcDir+FileInfo.Name;
  2007. if ((FileInfo.Attr and {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}sysutils.faDirectory)>0)
  2008. {$ifdef unix} and ((FileInfo.Attr and {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}sysutils.faSymLink{%H-})=0) {$endif unix} then begin
  2009. if not DeleteDirectory(CurFilename,false) then exit;
  2010. end else begin
  2011. if not {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.DeleteFile(CurFilename) then exit;
  2012. end;
  2013. until {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.FindNext(FileInfo)<>0;
  2014. finally
  2015. {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.FindClose(FileInfo);
  2016. end;
  2017. if (not OnlyChildren) and (not RemoveDir(CurSrcDir)) then exit;
  2018. Result:=true;
  2019. end;
  2020. class procedure TDirectory.Delete(const aPath: string);
  2021. begin
  2022. RemoveDir(aPath);
  2023. end;
  2024. class procedure TDirectory.Delete(const aPath: string; const Recursive: Boolean);
  2025. begin
  2026. if Recursive then
  2027. DeleteDirectory(aPath, False)
  2028. else
  2029. TDirectory.Delete(aPath);
  2030. end;
  2031. class function TDirectory.Exists(const aPath: string; FollowLink: Boolean
  2032. ): Boolean;
  2033. begin
  2034. Result:=DirectoryExists(aPath, FollowLink);
  2035. end;
  2036. class function TDirectory.GetAttributes(const aPath: string; FollowLink: Boolean
  2037. ): TFileAttributes;
  2038. begin
  2039. Result:=TFile.GetAttributes(aPath, FollowLink);
  2040. end;
  2041. class function TDirectory.GetCurrentDirectory: string;
  2042. begin
  2043. Result:=GetCurrentDir;
  2044. end;
  2045. class procedure TDirectory.SetCurrentDirectory(const aPath: string);
  2046. begin
  2047. ChDir(aPath);
  2048. end;
  2049. class function TDirectory.GetLogicalDrives: TStringDynArray;
  2050. {$IfDef WINDOWS}
  2051. var
  2052. i: Char;
  2053. {$EndIf}
  2054. begin
  2055. Result:=[];
  2056. {$IfDef WINDOWS}
  2057. for i:='A' to 'Z' do
  2058. if DirectoryExists(i + ':\') then
  2059. Result:=Result + [i + ':\'];
  2060. {$EndIf}
  2061. end;
  2062. class procedure TDirectory.SetAttributes(const aPath: string;
  2063. const Attributes: TFileAttributes);
  2064. begin
  2065. TFile.SetAttributes(aPath, Attributes);
  2066. end;
  2067. class function TDirectory.GetParent(const aPath: string): string;
  2068. begin
  2069. Result:=ExpandFileName(IncludeTrailingPathDelimiter(aPath) + '..');
  2070. end;
  2071. class function TDirectory.GetDirectories(const aPath: string): TStringDynArray;
  2072. begin
  2073. Result:=GetDirectories(aPath, '*');
  2074. end;
  2075. class function TDirectory.GetDirectories(const aPath: string;
  2076. const aPredicate: TFilterPredicateLocal): TStringDynArray;
  2077. begin
  2078. Result:=GetDirectories(aPath, '*', aPredicate);
  2079. end;
  2080. class function TDirectory.GetDirectories(const aPath: string;
  2081. const aPredicate: TFilterPredicateObject): TStringDynArray;
  2082. begin
  2083. Result:=GetDirectories(aPath, '*', aPredicate);
  2084. end;
  2085. class function TDirectory.GetDirectories(const aPath: string;
  2086. const aPredicate: TFilterPredicate): TStringDynArray;
  2087. begin
  2088. Result:=GetDirectories(aPath, '*', aPredicate);
  2089. end;
  2090. class function TDirectory.GetDirectories(const aPath, aSearchPattern: string
  2091. ): TStringDynArray;
  2092. begin
  2093. Result:=GetDirectories(aPath, aSearchPattern, TFilterPredicateLocal(nil));
  2094. end;
  2095. class function TDirectory.GetDirectories(const aPath, aSearchPattern: string;
  2096. const aPredicate: TFilterPredicateLocal): TStringDynArray;
  2097. begin
  2098. Result:=GetDirectories(aPath, aSearchPattern, TSearchOption.soTopDirectoryOnly, aPredicate);
  2099. end;
  2100. class function TDirectory.GetDirectories(const aPath, aSearchPattern: string;
  2101. const aPredicate: TFilterPredicateObject): TStringDynArray;
  2102. begin
  2103. Result:=GetDirectories(aPath, aSearchPattern, TSearchOption.soTopDirectoryOnly, aPredicate);
  2104. end;
  2105. class function TDirectory.GetDirectories(const aPath, aSearchPattern: string;
  2106. const aPredicate: TFilterPredicate): TStringDynArray;
  2107. begin
  2108. Result:=GetDirectories(aPath, aSearchPattern, TSearchOption.soTopDirectoryOnly, aPredicate);
  2109. end;
  2110. class function TDirectory.GetDirectories(const aPath, aSearchPattern: string;
  2111. const aSearchOption: TSearchOption): TStringDynArray;
  2112. begin
  2113. Result:=GetDirectories(aPath, aSearchPattern, aSearchOption, TFilterPredicateLocal(nil));
  2114. end;
  2115. class function TDirectory.GetDirectories(const aPath, aSearchPattern: string;
  2116. const aSearchOption: TSearchOption; const aPredicate: TFilterPredicateLocal
  2117. ): TStringDynArray;
  2118. begin
  2119. Result:=GetFilesAndDirectories(aPath, aSearchPattern,
  2120. aSearchOption, TFile.IntegerToFileAttributes(faAnyFile),
  2121. function(const aPath: string; const SearchRec: TSearchRec): Boolean
  2122. begin
  2123. Result :=
  2124. (SearchRec.Attr and {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faDirectory <> 0) and
  2125. (SearchRec.Name <> '.') and (SearchRec.Name <> '..');
  2126. if Result and Assigned(aPredicate) then
  2127. Result := aPredicate(aPath, SearchRec);
  2128. end);
  2129. end;
  2130. class function TDirectory.GetDirectories(const aPath, aSearchPattern: string;
  2131. const aSearchOption: TSearchOption; const aPredicate: TFilterPredicateObject
  2132. ): TStringDynArray;
  2133. begin
  2134. Result:=GetDirectories(aPath, aSearchPattern, aSearchOption,
  2135. function(const aPath: string; const SearchRec: TSearchRec): Boolean
  2136. begin
  2137. Result := aPredicate(aPath, SearchRec);
  2138. end);
  2139. end;
  2140. class function TDirectory.GetDirectories(const aPath, aSearchPattern: string;
  2141. const aSearchOption: TSearchOption; const aPredicate: TFilterPredicate
  2142. ): TStringDynArray;
  2143. begin
  2144. Result:=GetDirectories(aPath, aSearchPattern, aSearchOption,
  2145. function(const aPath: string; const SearchRec: TSearchRec): Boolean
  2146. begin
  2147. Result := aPredicate(aPath, SearchRec);
  2148. end);
  2149. end;
  2150. class function TDirectory.GetDirectories(const aPath: string;
  2151. const aSearchOption: TSearchOption; const aPredicate: TFilterPredicateLocal
  2152. ): TStringDynArray;
  2153. begin
  2154. Result:=GetDirectories(aPath, '*', aSearchOption, aPredicate);
  2155. end;
  2156. class function TDirectory.GetDirectories(const aPath: string;
  2157. const aSearchOption: TSearchOption; const aPredicate: TFilterPredicateObject
  2158. ): TStringDynArray;
  2159. begin
  2160. Result:=GetDirectories(aPath, '*', aSearchOption, aPredicate);
  2161. end;
  2162. class function TDirectory.GetDirectories(const aPath: string;
  2163. const aSearchOption: TSearchOption; const aPredicate: TFilterPredicate
  2164. ): TStringDynArray;
  2165. begin
  2166. Result:=GetDirectories(aPath, '*', aSearchOption, aPredicate);
  2167. end;
  2168. class function TDirectory.GetFiles(const aPath: string): TStringDynArray;
  2169. begin
  2170. Result:=GetFiles(aPath, '*');
  2171. end;
  2172. class function TDirectory.GetFiles(const aPath: string;
  2173. const aPredicate: TFilterPredicateLocal): TStringDynArray;
  2174. begin
  2175. Result:=GetFiles(aPath, '*', TSearchOption.soTopDirectoryOnly, aPredicate);
  2176. end;
  2177. class function TDirectory.GetFiles(const aPath: string;
  2178. const aPredicate: TFilterPredicateObject): TStringDynArray;
  2179. begin
  2180. Result:=GetFiles(aPath, '*', TSearchOption.soTopDirectoryOnly, aPredicate);
  2181. end;
  2182. class function TDirectory.GetFiles(const aPath: string;
  2183. const aPredicate: TFilterPredicate): TStringDynArray;
  2184. begin
  2185. Result:=GetFiles(aPath, '*', TSearchOption.soTopDirectoryOnly, aPredicate);
  2186. end;
  2187. class function TDirectory.GetFiles(const aPath, aSearchPattern: string
  2188. ): TStringDynArray;
  2189. begin
  2190. Result:=GetFiles(aPath, aSearchPattern, TSearchOption.soTopDirectoryOnly, TFilterPredicateLocal(nil));
  2191. end;
  2192. class function TDirectory.GetFiles(const aPath, aSearchPattern: string;
  2193. const aPredicate: TFilterPredicateLocal): TStringDynArray;
  2194. begin
  2195. Result:=GetFiles(aPath, aSearchPattern, TSearchOption.soTopDirectoryOnly, aPredicate);
  2196. end;
  2197. class function TDirectory.GetFiles(const aPath, aSearchPattern: string;
  2198. const aPredicate: TFilterPredicateObject): TStringDynArray;
  2199. begin
  2200. Result:=GetFiles(aPath, aSearchPattern, TSearchOption.soTopDirectoryOnly, aPredicate);
  2201. end;
  2202. class function TDirectory.GetFiles(const aPath, aSearchPattern: string;
  2203. const aPredicate: TFilterPredicate): TStringDynArray;
  2204. begin
  2205. Result:=GetFiles(aPath, aSearchPattern, TSearchOption.soTopDirectoryOnly, aPredicate);
  2206. end;
  2207. class function TDirectory.GetFiles(const aPath, aSearchPattern: string;
  2208. const aSearchOption: TSearchOption): TStringDynArray;
  2209. begin
  2210. Result:=GetFiles(aPath, aSearchPattern, aSearchOption, TFilterPredicateLocal(nil));
  2211. end;
  2212. class function TDirectory.GetFiles(const aPath, aSearchPattern: string;
  2213. const aSearchOption: TSearchOption; const aPredicate: TFilterPredicateLocal
  2214. ): TStringDynArray;
  2215. begin
  2216. Result:=GetFilesAndDirectories(aPath, aSearchPattern, aSearchOption,
  2217. TFile.IntegerToFileAttributes(faAnyFile) - [TFileAttribute.faDirectory],
  2218. function(const aPath: string; const SearchRec: TSearchRec): Boolean
  2219. begin
  2220. Result := SearchRec.Attr and {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faDirectory = 0;
  2221. if Result and Assigned(aPredicate) then
  2222. Result := aPredicate(aPath, SearchRec);
  2223. end);
  2224. end;
  2225. class function TDirectory.GetFiles(const aPath, aSearchPattern: string;
  2226. const aSearchOption: TSearchOption; const aPredicate: TFilterPredicateObject
  2227. ): TStringDynArray;
  2228. begin
  2229. Result:=GetFiles(aPath, aSearchPattern, aSearchOption,
  2230. function(const aPath: string; const SearchRec: TSearchRec): Boolean
  2231. begin
  2232. Result := aPredicate(aPath, SearchRec);
  2233. end);
  2234. end;
  2235. class function TDirectory.GetFiles(const aPath, aSearchPattern: string;
  2236. const aSearchOption: TSearchOption; const aPredicate: TFilterPredicate
  2237. ): TStringDynArray;
  2238. begin
  2239. Result:=GetFiles(aPath, aSearchPattern, aSearchOption,
  2240. function(const aPath: string; const SearchRec: TSearchRec): Boolean
  2241. begin
  2242. Result := aPredicate(aPath, SearchRec);
  2243. end);
  2244. end;
  2245. class function TDirectory.GetFiles(const aPath: string;
  2246. const aSearchOption: TSearchOption; const aPredicate: TFilterPredicateLocal
  2247. ): TStringDynArray;
  2248. begin
  2249. Result:=GetFiles(aPath, '*', aSearchOption, aPredicate);
  2250. end;
  2251. class function TDirectory.GetFiles(const aPath: string;
  2252. const aSearchOption: TSearchOption; const aPredicate: TFilterPredicateObject
  2253. ): TStringDynArray;
  2254. begin
  2255. Result:=GetFiles(aPath, '*', aSearchOption, aPredicate);
  2256. end;
  2257. class function TDirectory.GetFiles(const aPath: string;
  2258. const aSearchOption: TSearchOption; const aPredicate: TFilterPredicate
  2259. ): TStringDynArray;
  2260. begin
  2261. Result:=GetFiles(aPath, '*', aSearchOption, aPredicate);
  2262. end;
  2263. class function TDirectory.GetFileSystemEntries(const aPath: string
  2264. ): TStringDynArray;
  2265. begin
  2266. Result:=GetFileSystemEntries(aPath, '*');
  2267. end;
  2268. class function TDirectory.GetFileSystemEntries(const aPath: string;
  2269. const aPredicate: TFilterPredicateLocal): TStringDynArray;
  2270. begin
  2271. Result:=GetFileSystemEntries(aPath, '*', aPredicate);
  2272. end;
  2273. class function TDirectory.GetFileSystemEntries(const aPath: string;
  2274. const aPredicate: TFilterPredicateObject): TStringDynArray;
  2275. begin
  2276. Result:=GetFileSystemEntries(aPath, '*', aPredicate);
  2277. end;
  2278. class function TDirectory.GetFileSystemEntries(const aPath: string;
  2279. const aPredicate: TFilterPredicate): TStringDynArray;
  2280. begin
  2281. Result:=GetFileSystemEntries(aPath, '*', aPredicate);
  2282. end;
  2283. class function TDirectory.GetFileSystemEntries(const aPath, aSearchPattern: string
  2284. ): TStringDynArray;
  2285. begin
  2286. Result:=GetFileSystemEntries(aPath, aSearchPattern, TFilterPredicateLocal(nil));
  2287. end;
  2288. class function TDirectory.GetFileSystemEntries(const aPath,
  2289. aSearchPattern: string; const aPredicate: TFilterPredicateLocal
  2290. ): TStringDynArray;
  2291. begin
  2292. Result:=GetFilesAndDirectories(aPath, aSearchPattern, TSearchOption.soTopDirectoryOnly, TFile.IntegerToFileAttributes(faAnyFile), aPredicate);
  2293. end;
  2294. class function TDirectory.GetFileSystemEntries(const aPath,
  2295. aSearchPattern: string; const aPredicate: TFilterPredicateObject
  2296. ): TStringDynArray;
  2297. begin
  2298. Result:=GetFilesAndDirectories(aPath, aSearchPattern,
  2299. TSearchOption.soTopDirectoryOnly, TFile.IntegerToFileAttributes(faAnyFile),
  2300. function(const aPath: string; const SearchRec: TSearchRec): Boolean
  2301. begin
  2302. Result := aPredicate(aPath, SearchRec);
  2303. end);
  2304. end;
  2305. class function TDirectory.GetFileSystemEntries(const aPath,
  2306. aSearchPattern: string; const aPredicate: TFilterPredicate): TStringDynArray;
  2307. begin
  2308. Result:=GetFilesAndDirectories(aPath, aSearchPattern,
  2309. TSearchOption.soTopDirectoryOnly, TFile.IntegerToFileAttributes(faAnyFile),
  2310. function(const aPath: string; const SearchRec: TSearchRec): Boolean
  2311. begin
  2312. Result := aPredicate(aPath, SearchRec);
  2313. end);
  2314. end;
  2315. class function TDirectory.GetFileSystemEntries(const aPath: string;
  2316. const aSearchOption: TSearchOption; const aPredicate: TFilterPredicateLocal
  2317. ): TStringDynArray;
  2318. begin
  2319. Result:=GetFilesAndDirectories(aPath, '*', aSearchOption, TFile.IntegerToFileAttributes(faAnyFile),aPredicate);
  2320. end;
  2321. class function TDirectory.GetFileSystemEntries(const aPath: string;
  2322. const aSearchOption: TSearchOption; const aPredicate: TFilterPredicateObject
  2323. ): TStringDynArray;
  2324. begin
  2325. Result:=GetFilesAndDirectories(aPath, '*', aSearchOption, TFile.IntegerToFileAttributes(faAnyFile),
  2326. function(const aPath: string; const SearchRec: TSearchRec): Boolean
  2327. begin
  2328. Result := aPredicate(aPath, SearchRec);
  2329. end);
  2330. end;
  2331. class function TDirectory.GetFileSystemEntries(const aPath: string;
  2332. const aSearchOption: TSearchOption; const aPredicate: TFilterPredicate
  2333. ): TStringDynArray;
  2334. begin
  2335. Result:=GetFilesAndDirectories(aPath, '*', aSearchOption, TFile.IntegerToFileAttributes(faAnyFile),
  2336. function(const aPath: string; const SearchRec: TSearchRec): Boolean
  2337. begin
  2338. Result := aPredicate(aPath, SearchRec);
  2339. end);
  2340. end;
  2341. class procedure TDirectory.ForAllEntries(const aPath, aPattern: string; const aBefore, aAfter: TFilterPredicateLocal; aRecursive: Boolean);
  2342. var
  2343. Handle: Boolean;
  2344. Continue: Boolean;
  2345. Info: TSearchRec;
  2346. lPath : String;
  2347. begin
  2348. Handle:=True;
  2349. lPath:=IncludeTrailingPathDelimiter(aPath);
  2350. if FindFirst(lPath+AllFilesMask,faAnyFile,Info)<>0 then
  2351. exit;
  2352. try
  2353. repeat
  2354. Handle:=TPath.MatchesPattern(Info.Name,aPattern,System.FileNameCaseSensitive);
  2355. if Handle and Assigned(aBefore) then
  2356. Continue:=aBefore(aPath,Info);
  2357. if Continue then
  2358. begin
  2359. if aRecursive and Info.IsDirectory and not Info.IsCurrentOrParentDir then
  2360. ForAllEntries(lPath+Info.Name,aPattern,aBefore,aAfter,aRecursive);
  2361. if Handle and Assigned(aAfter) then
  2362. Continue:=aAfter(lPath,Info);
  2363. end;
  2364. until ({$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.FindNext(Info)<>0) or not Continue;
  2365. finally
  2366. {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.FindClose(Info);
  2367. end;
  2368. end;
  2369. class function TDirectory.IsEmpty(const aPath: string): Boolean;
  2370. var
  2371. sr: TSearchRec;
  2372. begin
  2373. Result:=True;
  2374. if (FindFirst(aPath, faAnyFile, sr) = 0) then
  2375. repeat
  2376. Result:=(sr.Name = '.') or (sr.Name = '..');
  2377. until Result and (FindNext(sr) = 0);
  2378. {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.FindClose(sr);
  2379. end;
  2380. class function TDirectory.IsRelativePath(const aPath: string): Boolean;
  2381. begin
  2382. Result:=TPath.IsRelativePath(aPath);
  2383. end;
  2384. Function SpecialDir(Const Info : TSearchRec) : Boolean;
  2385. begin
  2386. Result:=(Info.Attr and {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faDirectory <> 0) and (Info.Name='.') or (Info.Name='..');
  2387. end;
  2388. class procedure TDirectory.Move(const SourceDirName, DestDirName: string);
  2389. Var
  2390. lSource,lDest : String;
  2391. function DoCreateDestDir(const aPath: string; const aInfo: TSearchRec): Boolean;
  2392. var
  2393. lPath: string;
  2394. begin
  2395. Result:=True;
  2396. if (Not aInfo.IsDirectory) or aInfo.IsCurrentOrParentDir then
  2397. exit;
  2398. lPath:=lDest;
  2399. if SameFileName(aPath,SourceDirName) then
  2400. lPath:=IncludeTrailingPathDelimiter(lPath+ExtractRelativePath(lSource,aPath));
  2401. lPath:=lPath+aInfo.Name;
  2402. CreateDir(lPath);
  2403. end;
  2404. function DoMoveSrcToDest(const aPath: string; const aInfo: TSearchRec): Boolean;
  2405. var
  2406. lSrc,lDestF: string;
  2407. begin
  2408. Result:=True;
  2409. if aInfo.IsCurrentOrParentDir then
  2410. exit;
  2411. if aInfo.IsDirectory then
  2412. begin
  2413. lSrc:=TPath.Combine(aPath,aInfo.Name);
  2414. {$IFDEF WINDOWS}
  2415. FileSetAttr(lSrc,{$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faNormal);
  2416. {$ENDIF}
  2417. RemoveDir(lSrc);
  2418. end
  2419. else
  2420. begin
  2421. lSrc:=TPath.Combine(aPath, aInfo.Name);
  2422. lDestF:=lDest;
  2423. if SameFileName(aPath,SourceDirName) then
  2424. lDestF:=IncludeTrailingPathDelimiter(lDestF+ExtractRelativePath(lSource,aPath));
  2425. lDestF:=lDest+aInfo.Name;
  2426. {$IFDEF WINDOWS}
  2427. FileSetAttr(lSrc,{$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.faNormal);
  2428. {$ENDIF WINDOWS}
  2429. RenameFile(lSrc,lDestF);
  2430. {$IFDEF WINDOWS}
  2431. FileSetAttr(lDestf,aInfo.Attr);
  2432. {$ENDIF WINDOWS}
  2433. end;
  2434. end;
  2435. begin
  2436. lSource:=IncludeTrailingPathDelimiter(SourceDirName);
  2437. lDest:=IncludeTrailingPathDelimiter(DestDirName);
  2438. ForceDirectories(DestDirName);
  2439. ForAllEntries(lSource,allFilesMask,@DoCreateDestDir,@DoMoveSrcToDest,True);
  2440. RemoveDir(SourceDirName);
  2441. end;
  2442. end.