BaseUtils.pas 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. unit BaseUtils;
  2. {==================================================================
  3. Basic file handling utilities / Version 1.2 / 11.1999
  4. ========================================================
  5. Description:
  6. ============
  7. Basic utilities useful for handling files or directories.
  8. Used by the components TDriveView and TDirView.
  9. Author:
  10. =======
  11. (c) Ingo Eckel 5/1998
  12. Sodener Weg 38
  13. 65812 Bad Soden
  14. Germany
  15. Modifications (for WinSCP):
  16. ===========================
  17. (c) Martin Prikryl 2001, 2002
  18. {==================================================================}
  19. interface
  20. uses
  21. SysUtils, Windows, Forms, ShlObj, PIDL, Classes, Controls;
  22. type
  23. TDateTimePrecision = (tpNone, tpDay, tpMinute, tpSecond, tpMillisecond);
  24. // order choosen so that for previous bool value, false maps to fbNone,
  25. // and true maps to new default fbKilobytes, although functionaly it is fbShort
  26. TFormatBytesStyle = (fbNone, fbKilobytes, fbShort);
  27. function CheckFileExists(FileName: string): Boolean;
  28. function DirExists(Dir: string): Boolean; overload;
  29. function DirExists(Dir: string; var Attrs: Integer): Boolean; overload;
  30. function ExtractFileNameOnly(Name: string): string;
  31. function FileOrDirExists(FileName: string): Boolean;
  32. function FormatBytes(Bytes: Int64; Style: TFormatBytesStyle = fbShort; UseUnitsForBytes: Boolean = True): string;
  33. function FormatPanelBytes(Bytes: Int64; Style: TFormatBytesStyle): string;
  34. procedure FreePIDL(var PIDL: PItemIDList);
  35. function StrContains(Str1, Str2: string): Boolean;
  36. procedure StrTranslate(var Str: string; Code: string);
  37. function IsUncPath(Path: string): Boolean;
  38. function AnyValidPath: string;
  39. procedure ReduceDateTimePrecision(var DateTime: TDateTime;
  40. Precision: TDateTimePrecision);
  41. function SpecialFolderLocation(Folder: Integer; var Path: string;
  42. var PIDL: PItemIDList): Boolean; overload;
  43. function SpecialFolderLocation(Folder: Integer; var Path: string): Boolean; overload;
  44. function FormatLastOSError(Message: string): string;
  45. resourcestring
  46. SNoValidPath = 'Can''t find any valid path.';
  47. SUcpPathsNotSupported = 'UNC paths are not supported.';
  48. SByte = 'B';
  49. SKiloByte = 'KB';
  50. SMegaByte = 'MB';
  51. SGigaByte = 'GB';
  52. implementation
  53. uses
  54. IEDriveInfo, DateUtils, ShellApi, SysConst, PasTools, Math;
  55. function AnyValidPath: string;
  56. var
  57. Drive: TDrive;
  58. begin
  59. for Drive := 'C' to 'Z' do
  60. if DriveInfo[Drive].Valid and
  61. (DriveInfo[Drive].DriveType = DRIVE_FIXED) and
  62. DirectoryExists(ApiPath(Drive + ':\')) then
  63. begin
  64. Result := Drive + ':\';
  65. Exit;
  66. end;
  67. for Drive := 'C' to 'Z' do
  68. if DriveInfo[Drive].Valid and
  69. (DriveInfo[Drive].DriveType = DRIVE_REMOTE) and
  70. DirectoryExists(ApiPath(Drive + ':\')) then
  71. begin
  72. Result := Drive + ':\';
  73. Exit;
  74. end;
  75. raise Exception.Create(SNoValidPath);
  76. end;
  77. function IsUncPath(Path: string): Boolean;
  78. begin
  79. Result := (Copy(Path, 1, 2) = '\\') or (Copy(Path, 1, 2) = '//');
  80. end;
  81. procedure StrTranslate(var Str: string; Code: string);
  82. var
  83. Index: Integer;
  84. begin
  85. if (Length(Code) > 0) and (Length(Code) mod 2 = 0) then
  86. for Index := 1 to Length(Code) div 2 do
  87. while Pos(Code[Index*2-1], Str) <> 0 do
  88. Str[Pos(Code[Index*2-1], Str)] := Code[Index*2];
  89. end; {StrTranslate}
  90. function StrContains(Str1, Str2: string): Boolean;
  91. var
  92. Index: Integer;
  93. begin
  94. for Index := 1 to Length(Str1) do
  95. if Pos(Str1[Index], Str2) <> 0 then
  96. begin
  97. Result := True;
  98. Exit;
  99. end;
  100. Result := False;
  101. end; {StringCountains}
  102. function FileOrDirExists(FileName: string): Boolean;
  103. var
  104. SRec : TSearchRec;
  105. begin
  106. if Length(FileName) = 0 then Result := False
  107. else
  108. begin
  109. Result := (FindFirst(ApiPath(FileName), faAnyFile, SRec) = 0);
  110. SysUtils.FindCLose(SRec);
  111. end;
  112. end; {FileOrDirExists}
  113. function CheckFileExists(FileName: string): Boolean;
  114. var
  115. SaveFileMode : Integer;
  116. F: file;
  117. begin
  118. SaveFileMode := System.FileMode;
  119. System.FileMode := 0;
  120. try
  121. AssignFile(F, ApiPath(FileName));
  122. Reset(F, 1);
  123. Result := IOResult = 0;
  124. if Result then
  125. CloseFile(F);
  126. finally
  127. System.FileMode := SaveFileMode;
  128. end;
  129. end; {CheckFileExists}
  130. function DirExists(Dir: string; var Attrs: Integer): Boolean;
  131. var
  132. SRec: TSearchRec;
  133. begin
  134. Result := ((Length(Dir) <= 3) and (Length(Dir) >= 2)) and (Dir[2] = ':');
  135. if Result then Attrs := 0
  136. else
  137. begin
  138. if FindFirst(ApiPath(Dir), faAnyFile, SRec) = 0 then
  139. begin
  140. Result := (SRec.Attr and faDirectory <> 0);
  141. Attrs := SRec.Attr;
  142. end;
  143. SysUtils.FindClose(SRec);
  144. end;
  145. end; {DirExists}
  146. function DirExists(Dir: string): Boolean;
  147. var
  148. Dummy: Integer;
  149. begin
  150. Result := DirExists(Dir, Dummy);
  151. end; {DirExists}
  152. function ExtractFileNameOnly(Name: string): string;
  153. var
  154. Ext: string;
  155. begin
  156. Result := ExtractFileName(Name);
  157. Ext := ExtractFileExt(Name);
  158. if Ext <> '' then
  159. Delete(Result, Length(Result)-Length(Ext)+1, Length(Ext));
  160. end; {ExtractFileNameOnly}
  161. // Windows Explorer size formatting
  162. // size properties/status bar size column
  163. // 1023 1023 bytes 1 KB
  164. // 1 KB 1,00 KB 1 KB
  165. // 2 KB 2,00 KB 2 KB
  166. // 2 KB + 1 B 2,00 KB 3 KB
  167. // 2 KB + 12 B 2,01 KB 3 KB
  168. // 10 KB - 1B 9,99 KB 10 KB
  169. // 10 KB 10,0 KB 10 KB
  170. // 12 KB 12,0 KB 12 KB
  171. // 12 KB + 1 B 12,0 KB 13 KB
  172. // 12 KB + 12 B 12,0 KB 13 KB
  173. // 12 KB + 128 B 12,1 KB 13 KB
  174. // 100 KB 100 KB 100 KB
  175. // 100 KB + 1 B 100 KB 101 KB
  176. // 500 KB 500 KB 500 KB
  177. // 1000 KB - 1 B 999 KB 1 000 KB
  178. // 1000 KB 0,97 MB 1 000 KB
  179. // 1 MB 1,00 MB 1 024 KB
  180. // 1000 MB - 1 B 999 MB 1 024 000 KB
  181. // 1000 MB 0,97 GB 1 024 000 KB
  182. // 1 GB - 1 0,99 GB 1 048 576 KB
  183. // 1 GB 1,00 GB 1 048 576 KB
  184. // 1 GB + 10 MB 1,00 GB 1 058 816 KB
  185. // 1 GB + 12 MB 1,01 GB 1 060 864 KB
  186. function FormatBytes(Bytes: Int64; Style: TFormatBytesStyle; UseUnitsForBytes: Boolean): string;
  187. var
  188. SizeUnit: string;
  189. Value: Int64;
  190. Order: Int64;
  191. EValue: Extended;
  192. Format: string;
  193. begin
  194. if (Style = fbNone) or ((Style = fbShort) and (Bytes < Int64(1024))) then
  195. begin
  196. EValue := Bytes;
  197. Format := '#,##0';
  198. if UseUnitsForBytes then
  199. Format := Format + ' "' + SByte + '"';
  200. end
  201. else
  202. if Style = fbKilobytes then
  203. begin
  204. Value := Bytes div 1024;
  205. if (Bytes mod 1024) > 0 then
  206. Inc(Value);
  207. EValue := Value;
  208. Format := '#,##0 "' + SKiloByte + '"';
  209. end
  210. else
  211. begin
  212. if Bytes < Int64(1000*1024) then
  213. begin
  214. Order := 1024;
  215. SizeUnit := SKiloByte;
  216. end
  217. else
  218. if Bytes < Int64(1000*1024*1024) then
  219. begin
  220. Order := 1024*1024;
  221. SizeUnit := SMegaByte;
  222. end
  223. else
  224. begin
  225. Order := 1024*1024*1024;
  226. SizeUnit := SGigaByte;
  227. end;
  228. EValue := Bytes / Order;
  229. if EValue >= 100 then
  230. begin
  231. EValue := Floor(EValue);
  232. Format := '#,##0';
  233. end
  234. else
  235. if EValue >= 10 then
  236. begin
  237. EValue := Floor(EValue * 10) / 10;
  238. Format := '#0.0';
  239. end
  240. else
  241. begin
  242. EValue := Floor(EValue * 100) / 100;
  243. Format := '0.00';
  244. end;
  245. Format := Format + ' "' + SizeUnit + '"';
  246. end;
  247. Result := FormatFloat(Format, EValue);
  248. end;
  249. function FormatPanelBytes(Bytes: Int64; Style: TFormatBytesStyle): string;
  250. begin
  251. Result := FormatBytes(Bytes, Style, (Style <> fbNone));
  252. end;
  253. procedure FreePIDL(var PIDL: PItemIDList);
  254. begin
  255. if PIDL <> nil then
  256. begin
  257. try
  258. ShellMalloc.Free(PIDL);
  259. PIDL := NIL;
  260. except
  261. PIDL := NIL;
  262. end;
  263. end;
  264. end; {FreePIDL}
  265. // duplicated in RemoteFiles.cpp
  266. procedure ReduceDateTimePrecision(var DateTime: TDateTime;
  267. Precision: TDateTimePrecision);
  268. var
  269. Y, M, D, H, N, S, MS: Word;
  270. begin
  271. if Precision = tpNone then DateTime := 0
  272. else
  273. if Precision <> tpMillisecond then
  274. begin
  275. DecodeDateTime(DateTime, Y, M, D, H, N, S, MS);
  276. case Precision of
  277. tpDay:
  278. begin
  279. H := 0;
  280. N := 0;
  281. S := 0;
  282. MS := 0;
  283. end;
  284. tpMinute:
  285. begin
  286. S := 0;
  287. MS := 0;
  288. end;
  289. tpSecond:
  290. begin
  291. MS := 0;
  292. end;
  293. end;
  294. DateTime := EncodeDate(Y, M, D) + EncodeTime(H, N, S, MS);
  295. end;
  296. end;
  297. function SpecialFolderLocation(Folder: Integer; var Path: string;
  298. var PIDL: PItemIDList): Boolean;
  299. begin
  300. SetLength(Path, MAX_PATH);
  301. Result :=
  302. (not Failed(SHGetSpecialFolderLocation(Application.Handle, Folder, PIDL))) and
  303. SHGetPathFromIDList(PIDL, PChar(Path));
  304. if Result then
  305. begin
  306. SetLength(Path, StrLen(PChar(Path)));
  307. end
  308. else
  309. begin
  310. Path := '';
  311. end;
  312. end;
  313. function SpecialFolderLocation(Folder: Integer; var Path: string): Boolean;
  314. var
  315. PIDL: PItemIDList;
  316. begin
  317. Result := SpecialFolderLocation(Folder, Path, PIDL);
  318. end;
  319. function FormatLastOSError(Message: string): string;
  320. var
  321. LastError: Integer;
  322. begin
  323. Result := Message;
  324. LastError := GetLastError;
  325. if LastError <> 0 then
  326. Result := Result + #13#10 + #13#10 + Format(SOSError, [LastError, SysErrorMessage(LastError), '']);
  327. end;
  328. initialization
  329. end.