BaseUtils.pas 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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 ExtractFileNameOnly(Name: string): string;
  28. function FileOrDirExists(FileName: string): Boolean;
  29. function FormatBytes(Bytes: Int64; Style: TFormatBytesStyle = fbShort; UseUnitsForBytes: Boolean = True): string;
  30. function FormatPanelBytes(Bytes: Int64; Style: TFormatBytesStyle): string;
  31. procedure FreePIDL(var PIDL: PItemIDList);
  32. function StrContains(Str1, Str2: string): Boolean;
  33. function IsUncPath(Path: string): Boolean;
  34. function AnyValidPath: string;
  35. procedure ReduceDateTimePrecision(var DateTime: TDateTime;
  36. Precision: TDateTimePrecision);
  37. function SpecialFolderLocation(Folder: Integer; var Path: string;
  38. var PIDL: PItemIDList): Boolean; overload;
  39. function SpecialFolderLocation(Folder: Integer; var Path: string): Boolean; overload;
  40. function FormatLastOSError(Message: string): string;
  41. resourcestring
  42. SNoValidPath = 'Can''t find any valid path.';
  43. SUcpPathsNotSupported = 'UNC paths are not supported.';
  44. SByte = 'B';
  45. SKiloByte = 'KB';
  46. SMegaByte = 'MB';
  47. SGigaByte = 'GB';
  48. implementation
  49. uses
  50. IEDriveInfo, DateUtils, ShellApi, SysConst, PasTools, Math;
  51. function AnyValidPath: string;
  52. var
  53. Drive: TDrive;
  54. begin
  55. for Drive := 'C' to 'Z' do
  56. if DriveInfo[Drive].Valid and
  57. (DriveInfo[Drive].DriveType = DRIVE_FIXED) and
  58. DirectoryExists(ApiPath(Drive + ':\')) then
  59. begin
  60. Result := Drive + ':\';
  61. Exit;
  62. end;
  63. for Drive := 'C' to 'Z' do
  64. if DriveInfo[Drive].Valid and
  65. (DriveInfo[Drive].DriveType = DRIVE_REMOTE) and
  66. DirectoryExists(ApiPath(Drive + ':\')) then
  67. begin
  68. Result := Drive + ':\';
  69. Exit;
  70. end;
  71. raise Exception.Create(SNoValidPath);
  72. end;
  73. function IsUncPath(Path: string): Boolean;
  74. begin
  75. Result := (Copy(Path, 1, 2) = '\\') or (Copy(Path, 1, 2) = '//');
  76. end;
  77. function StrContains(Str1, Str2: string): Boolean;
  78. var
  79. Index: Integer;
  80. begin
  81. for Index := 1 to Length(Str1) do
  82. if Pos(Str1[Index], Str2) <> 0 then
  83. begin
  84. Result := True;
  85. Exit;
  86. end;
  87. Result := False;
  88. end; {StringCountains}
  89. function FileOrDirExists(FileName: string): Boolean;
  90. begin
  91. Result := FileExists(FileName) or DirectoryExists(FileName);
  92. end; {FileOrDirExists}
  93. function ExtractFileNameOnly(Name: string): string;
  94. var
  95. Ext: string;
  96. begin
  97. Result := ExtractFileName(Name);
  98. Ext := ExtractFileExt(Name);
  99. if Ext <> '' then
  100. Delete(Result, Length(Result)-Length(Ext)+1, Length(Ext));
  101. end; {ExtractFileNameOnly}
  102. // Windows Explorer size formatting
  103. // size properties/status bar size column
  104. // 1023 1023 bytes 1 KB
  105. // 1 KB 1,00 KB 1 KB
  106. // 2 KB 2,00 KB 2 KB
  107. // 2 KB + 1 B 2,00 KB 3 KB
  108. // 2 KB + 12 B 2,01 KB 3 KB
  109. // 10 KB - 1B 9,99 KB 10 KB
  110. // 10 KB 10,0 KB 10 KB
  111. // 12 KB 12,0 KB 12 KB
  112. // 12 KB + 1 B 12,0 KB 13 KB
  113. // 12 KB + 12 B 12,0 KB 13 KB
  114. // 12 KB + 128 B 12,1 KB 13 KB
  115. // 100 KB 100 KB 100 KB
  116. // 100 KB + 1 B 100 KB 101 KB
  117. // 500 KB 500 KB 500 KB
  118. // 1000 KB - 1 B 999 KB 1 000 KB
  119. // 1000 KB 0,97 MB 1 000 KB
  120. // 1 MB 1,00 MB 1 024 KB
  121. // 1000 MB - 1 B 999 MB 1 024 000 KB
  122. // 1000 MB 0,97 GB 1 024 000 KB
  123. // 1 GB - 1 0,99 GB 1 048 576 KB
  124. // 1 GB 1,00 GB 1 048 576 KB
  125. // 1 GB + 10 MB 1,00 GB 1 058 816 KB
  126. // 1 GB + 12 MB 1,01 GB 1 060 864 KB
  127. function FormatBytes(Bytes: Int64; Style: TFormatBytesStyle; UseUnitsForBytes: Boolean): string;
  128. var
  129. SizeUnit: string;
  130. Value: Int64;
  131. Order: Int64;
  132. EValue: Extended;
  133. Format: string;
  134. begin
  135. if (Style = fbNone) or ((Style = fbShort) and (Bytes < Int64(1024))) then
  136. begin
  137. EValue := Bytes;
  138. Format := '#,##0';
  139. if UseUnitsForBytes then
  140. Format := Format + ' "' + SByte + '"';
  141. end
  142. else
  143. if Style = fbKilobytes then
  144. begin
  145. Value := Bytes div 1024;
  146. if (Bytes mod 1024) > 0 then
  147. Inc(Value);
  148. EValue := Value;
  149. Format := '#,##0 "' + SKiloByte + '"';
  150. end
  151. else
  152. begin
  153. if Bytes < Int64(1000*1024) then
  154. begin
  155. Order := 1024;
  156. SizeUnit := SKiloByte;
  157. end
  158. else
  159. if Bytes < Int64(1000*1024*1024) then
  160. begin
  161. Order := 1024*1024;
  162. SizeUnit := SMegaByte;
  163. end
  164. else
  165. begin
  166. Order := 1024*1024*1024;
  167. SizeUnit := SGigaByte;
  168. end;
  169. EValue := Bytes / Order;
  170. if EValue >= 100 then
  171. begin
  172. EValue := Floor(EValue);
  173. Format := '#,##0';
  174. end
  175. else
  176. if EValue >= 10 then
  177. begin
  178. EValue := Floor(EValue * 10) / 10;
  179. Format := '#0.0';
  180. end
  181. else
  182. begin
  183. EValue := Floor(EValue * 100) / 100;
  184. Format := '0.00';
  185. end;
  186. Format := Format + ' "' + SizeUnit + '"';
  187. end;
  188. Result := FormatFloat(Format, EValue);
  189. end;
  190. function FormatPanelBytes(Bytes: Int64; Style: TFormatBytesStyle): string;
  191. begin
  192. Result := FormatBytes(Bytes, Style, (Style <> fbNone));
  193. end;
  194. procedure FreePIDL(var PIDL: PItemIDList);
  195. begin
  196. if PIDL <> nil then
  197. begin
  198. try
  199. ShellMalloc.Free(PIDL);
  200. PIDL := NIL;
  201. except
  202. PIDL := NIL;
  203. end;
  204. end;
  205. end; {FreePIDL}
  206. // duplicated in RemoteFiles.cpp
  207. procedure ReduceDateTimePrecision(var DateTime: TDateTime;
  208. Precision: TDateTimePrecision);
  209. var
  210. Y, M, D, H, N, S, MS: Word;
  211. begin
  212. if Precision = tpNone then DateTime := 0
  213. else
  214. if Precision <> tpMillisecond then
  215. begin
  216. DecodeDateTime(DateTime, Y, M, D, H, N, S, MS);
  217. case Precision of
  218. tpDay:
  219. begin
  220. H := 0;
  221. N := 0;
  222. S := 0;
  223. MS := 0;
  224. end;
  225. tpMinute:
  226. begin
  227. S := 0;
  228. MS := 0;
  229. end;
  230. tpSecond:
  231. begin
  232. MS := 0;
  233. end;
  234. end;
  235. DateTime := EncodeDate(Y, M, D) + EncodeTime(H, N, S, MS);
  236. end;
  237. end;
  238. function SpecialFolderLocation(Folder: Integer; var Path: string;
  239. var PIDL: PItemIDList): Boolean;
  240. begin
  241. SetLength(Path, MAX_PATH);
  242. Result :=
  243. (not Failed(SHGetSpecialFolderLocation(Application.Handle, Folder, PIDL))) and
  244. SHGetPathFromIDList(PIDL, PChar(Path));
  245. if Result then
  246. begin
  247. SetLength(Path, StrLen(PChar(Path)));
  248. end
  249. else
  250. begin
  251. Path := '';
  252. end;
  253. end;
  254. function SpecialFolderLocation(Folder: Integer; var Path: string): Boolean;
  255. var
  256. PIDL: PItemIDList;
  257. begin
  258. Result := SpecialFolderLocation(Folder, Path, PIDL);
  259. end;
  260. function FormatLastOSError(Message: string): string;
  261. var
  262. LastError: Integer;
  263. begin
  264. Result := Message;
  265. LastError := GetLastError;
  266. if LastError <> 0 then
  267. Result := Result + #13#10 + #13#10 + Format(SOSError, [LastError, SysErrorMessage(LastError), '']);
  268. end;
  269. initialization
  270. end.