You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1069 lines
36 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: inetstl/filesystem/filesystem_traits.hpp (originally MInetEnm.h)
  3. *
  4. * Purpose: Contains the filesystem_traits template class, and ANSI and
  5. * Unicode specialisations thereof.
  6. *
  7. * Created: 30th April 1999
  8. * Updated: 16th June 2010
  9. *
  10. * Home: http://stlsoft.org/
  11. *
  12. * Copyright (c) 1999-2010, Matthew Wilson and Synesis Software
  13. * All rights reserved.
  14. *
  15. * Redistribution and use in source and binary forms, with or without
  16. * modification, are permitted provided that the following conditions are met:
  17. *
  18. * - Redistributions of source code must retain the above copyright notice, this
  19. * list of conditions and the following disclaimer.
  20. * - Redistributions in binary form must reproduce the above copyright notice,
  21. * this list of conditions and the following disclaimer in the documentation
  22. * and/or other materials provided with the distribution.
  23. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  24. * any contributors may be used to endorse or promote products derived from
  25. * this software without specific prior written permission.
  26. *
  27. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  28. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  31. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  33. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  35. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  36. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37. * POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. * ////////////////////////////////////////////////////////////////////// */
  40. /** \file inetstl/filesystem/filesystem_traits.hpp
  41. *
  42. * \brief [C++ only] Definition of the inetstl::filesystem_traits
  43. * traits class template
  44. * (\ref group__library__filesystem "File System" Library).
  45. */
  46. #ifndef INETSTL_INCL_INETSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS
  47. #define INETSTL_INCL_INETSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS
  48. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  49. # define INETSTL_VER_INETSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_MAJOR 4
  50. # define INETSTL_VER_INETSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_MINOR 2
  51. # define INETSTL_VER_INETSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_REVISION 2
  52. # define INETSTL_VER_INETSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_EDIT 76
  53. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  54. /* /////////////////////////////////////////////////////////////////////////
  55. * Includes
  56. */
  57. #ifndef INETSTL_INCL_INETSTL_H_INETSTL
  58. # include <inetstl/inetstl.h>
  59. #endif /* !INETSTL_INCL_INETSTL_H_INETSTL */
  60. #ifndef INETSTL_OS_IS_WINDOWS
  61. # error This file is currently compatible only with the Win32/Win64 API
  62. #endif /* !INETSTL_OS_IS_WINDOWS */
  63. #ifndef STLSOFT_INCL_STLSOFT_CONVERSION_HPP_SAP_CAST
  64. # include <stlsoft/conversion/sap_cast.hpp>
  65. #endif /* !STLSOFT_INCL_STLSOFT_CONVERSION_HPP_SAP_CAST */
  66. #ifndef STLSOFT_INCL_STLSOFT_CONVERSION_HPP_ANY_CAST
  67. # include <stlsoft/conversion/any_cast.hpp>
  68. #endif /* !STLSOFT_INCL_STLSOFT_CONVERSION_HPP_ANY_CAST */
  69. #ifndef STLSOFT_INCL_STLSOFT_INTERNAL_H_SAFESTR
  70. # include <stlsoft/internal/safestr.h>
  71. #endif /* !STLSOFT_INCL_STLSOFT_INTERNAL_H_SAFESTR */
  72. #ifndef STLSOFT_INCL_H_STRING
  73. # define STLSOFT_INCL_H_STRING
  74. # include <string.h>
  75. #endif /* !STLSOFT_INCL_H_STRING */
  76. #ifndef STLSOFT_INCL_H_WCHAR
  77. # define STLSOFT_INCL_H_WCHAR
  78. # include <wchar.h>
  79. #endif /* !STLSOFT_INCL_H_WCHAR */
  80. /* /////////////////////////////////////////////////////////////////////////
  81. * Namespace
  82. */
  83. #ifndef _INETSTL_NO_NAMESPACE
  84. # if defined(_STLSOFT_NO_NAMESPACE) || \
  85. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  86. /* There is no stlsoft namespace, so must define ::inetstl */
  87. namespace inetstl
  88. {
  89. # else
  90. /* Define stlsoft::inetstl_project */
  91. namespace stlsoft
  92. {
  93. namespace inetstl_project
  94. {
  95. # endif /* _STLSOFT_NO_NAMESPACE */
  96. #endif /* !_INETSTL_NO_NAMESPACE */
  97. /* /////////////////////////////////////////////////////////////////////////
  98. * Classes
  99. */
  100. #ifdef STLSOFT_DOCUMENTATION_SKIP_SECTION
  101. /** \brief Traits for accessing the correct file-system functions for a given character type
  102. *
  103. * \ingroup group__library__filesystem
  104. *
  105. * filesystem_traits is a traits class for determining the correct file-system
  106. * structures and functions for a given character type.
  107. *
  108. * \param C The character type
  109. */
  110. template <ss_typename_param_k C>
  111. struct filesystem_traits
  112. {
  113. /// \name Member Types
  114. /// @{
  115. public:
  116. /// The character type
  117. typedef C char_type;
  118. /// The size type
  119. typedef is_size_t size_type;
  120. /// The difference type
  121. typedef is_ptrdiff_t difference_type;
  122. /// The find data type
  123. typedef WIN32_FIND_DATA find_data_type;
  124. /// The stat data type
  125. typedef WIN32_FIND_DATA stat_data_type;
  126. /// The current instantion of the type
  127. typedef filesystem_traits<C> class_type;
  128. /// The (signed) integer type
  129. typedef is_int_t int_type;
  130. /// The Boolean type
  131. typedef is_bool_t bool_type;
  132. /// The type of system error codes
  133. typedef DWORD error_type;
  134. /// @}
  135. /// \name General string handling
  136. /// @{
  137. public:
  138. /// Copies a specific number of characters from the source to the destination
  139. static char_type* char_copy(char_type* dest, char_type const* src, size_type n);
  140. #if !defined(STLSOFT_USING_SAFE_STR_FUNCTIONS) || \
  141. defined(_CRT_SECURE_NO_DEPRECATE)
  142. /// Copies the contents of \c src to \c dest
  143. static char_type* str_copy(char_type* dest, char_type const* src);
  144. /// Copies the contents of \c src to \c dest, up to cch \c characters
  145. static char_type* str_n_copy(char_type* dest, char_type const* src, is_size_t cch);
  146. /// Appends the contents of \c src to \c dest
  147. static char_type* str_cat(char_type* dest, char_type const* src);
  148. #endif /* !STLSOFT_USING_SAFE_STR_FUNCTIONS || _CRT_SECURE_NO_DEPRECATE */
  149. /// Compares the contents of \c src and \c dest
  150. static int_type str_compare(char_type const* s1, char_type const* s2);
  151. /// Compares the contents of \c src and \c dest in a case-insensitive fashion
  152. static int_type str_compare_no_case(char_type const* s1, char_type const* s2);
  153. /// Compares the contents of \c src and \c dest up to \c cch characters
  154. static int_type str_n_compare(char_type const* s1, char_type const* s2, size_type cch);
  155. /// Evaluates the length of \c src
  156. static size_type str_len(char_type const* src);
  157. /// Finds the given character \c ch in \c s
  158. static char_type* str_chr(char_type const* s, char_type ch);
  159. /// Finds the rightmost instance \c ch in \c s
  160. static char_type* str_rchr(char_type const* s, char_type ch);
  161. /// Finds the given substring \c sub in \c s
  162. static char_type* str_str(char_type const* s, char_type const* sub);
  163. /// @}
  164. /// \name File-system entry names
  165. /// @{
  166. public:
  167. /// Appends a path name separator to \c dir if one does not exist
  168. ///
  169. /// \see \link #path_name_separator path_name_separator() \endlink
  170. static char_type* ensure_dir_end(char_type* dir);
  171. /// Removes the path name separator from the end of \c dir, if it has it
  172. ///
  173. /// \see \link #path_name_separator path_name_separator() \endlink
  174. static char_type* remove_dir_end(char_type* dir);
  175. /// Returns \c true if \c dir has trailing path name separator
  176. ///
  177. /// \see \link #path_name_separator path_name_separator() \endlink
  178. static bool_type has_dir_end(char_type const* dir);
  179. /// Returns \c true if dir is \c "." or \c ".."
  180. static bool_type is_dots(char_type const* dir);
  181. /// Returns \c true if path is rooted
  182. static bool_type is_path_rooted(char_type const* path);
  183. /// Returns \c true if path is an absolute path
  184. static bool_type is_path_absolute(char_type const* path);
  185. /// \brief Returns \c true if the character is a path-name separator
  186. ///
  187. /// \note Both \c / and \c \\ are interpreted as a path name separator
  188. static bool_type is_path_name_separator(char_type ch);
  189. /// Returns the path separator
  190. ///
  191. /// This is the separator that is used to separate multiple paths on the operating system. On UNIX it is ':'
  192. static char_type path_separator();
  193. /// Returns the path name separator
  194. ///
  195. /// This is the separator that is used to separate parts of a path on the operating system. On UNIX it is '/'
  196. static char_type path_name_separator();
  197. /// Returns the wildcard pattern that represents all possible matches
  198. ///
  199. /// \note It is '*'
  200. static char_type const* pattern_all();
  201. /// Gets the full path name into the given buffer, returning a pointer to the file-part
  202. static size_type get_full_path_name(HINTERNET hconn, char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile);
  203. /// Gets the full path name into the given buffer
  204. static size_type get_full_path_name(HINTERNET hconn, char_type const* fileName, size_type cchBuffer, char_type* buffer);
  205. /// @}
  206. /// \name Internet connectivity
  207. /// @{
  208. public:
  209. /// Opens a WinInet session
  210. static HINTERNET internet_open(char_type const* agent, is_dword_t accessType, char_type const* proxy, char_type const* proxyBypass, is_dword_t flags);
  211. /// Makes a connection to a FTP or HTTP site
  212. static HINTERNET internet_connect(HINTERNET hsess, char_type const* server, INTERNET_PORT port, char_type const* userName, char_type const* password, is_dword_t service, is_dword_t flags, is_dword_t context);
  213. /// Closes the connection to the FTP or HTTP site
  214. static void close_connection(HINTERNET hconn);
  215. /// @}
  216. /// \name File-system enumeration
  217. /// @{
  218. public:
  219. /// Initiate a file-system search
  220. static HINTERNET find_first_file(HINTERNET hconn, char_type const* spec, find_data_type *findData, is_dword_t flags = 0, is_dword_t context = 0);
  221. /// Advance a given file-system search
  222. static bool_type find_next_file(HANDLE h, find_data_type *findData);
  223. /// Closes the file-search
  224. static void find_close(HINTERNET hfind);
  225. /// @}
  226. /// \name File-system state
  227. /// @{
  228. public:
  229. /// Sets the current directory to \c dir
  230. static bool_type set_current_directory(HINTERNET hconn, char_type const* dir);
  231. /// Retrieves the name of the current directory into \c buffer up to a maximum of \c cchBuffer characters
  232. static bool_type get_current_directory(HINTERNET hconn, is_size_t &cchBuffer, char_type* buffer);
  233. /// Returns whether a file exists or not
  234. static bool_type file_exists(HINTERNET hconn, char_type const* fileName);
  235. /// Returns whether the given path represents a file
  236. static bool_type is_file(HINTERNET hconn, char_type const* path);
  237. /// Returns whether the given path represents a directory
  238. static bool_type is_directory(HINTERNET hconn, char_type const* path);
  239. /// Gets the information for a particular file system entry
  240. static bool_type stat(HINTERNET hconn, char_type const* path, stat_data_type *stat_data);
  241. /// Returns whether the given stat info represents a file
  242. static bool_type is_file(stat_data_type const* stat_data);
  243. /// Returns whether the given stat info represents a directory
  244. static bool_type is_directory(stat_data_type const* stat_data);
  245. /// Returns whether the given stat info represents a link
  246. static bool_type is_link(stat_data_type const* stat_data);
  247. /// Returns whether the given stat info represents a read-only entry
  248. static bool_type is_readonly(stat_data_type const* stat_data);
  249. /// @}
  250. /// \name File-system control
  251. /// @{
  252. public:
  253. /// Creates a directory
  254. static bool_type create_directory(HINTERNET hconn, char_type const* dir);
  255. /// Deletes a directory
  256. static bool_type remove_directory(HINTERNET hconn, char_type const* dir);
  257. /// Delete a file
  258. static bool_type delete_file(HINTERNET hconn, char_type const* file);
  259. /// Rename a file
  260. static bool_type rename_file(HINTERNET hconn, char_type const* currentName, char_type const* newName);
  261. /// @}
  262. };
  263. #else /* ? STLSOFT_DOCUMENTATION_SKIP_SECTION */
  264. template <ss_typename_param_k C>
  265. struct filesystem_traits;
  266. STLSOFT_TEMPLATE_SPECIALISATION
  267. struct filesystem_traits<is_char_a_t>
  268. {
  269. public:
  270. typedef is_char_a_t char_type;
  271. typedef is_size_t size_type;
  272. typedef is_ptrdiff_t difference_type;
  273. typedef WIN32_FIND_DATAA find_data_type;
  274. typedef WIN32_FIND_DATAA stat_data_type;
  275. typedef filesystem_traits<is_char_a_t> class_type;
  276. typedef is_int_t int_type;
  277. typedef is_bool_t bool_type;
  278. typedef DWORD error_type;
  279. public:
  280. static char_type* char_copy(char_type* dest, char_type const* src, size_type n)
  281. {
  282. INETSTL_ASSERT(NULL != dest);
  283. INETSTL_ASSERT(0 == n || NULL != src);
  284. return static_cast<char_type*>(::memcpy(dest, src, sizeof(char_type) * n));
  285. }
  286. // General string handling
  287. #if !defined(STLSOFT_USING_SAFE_STR_FUNCTIONS) || \
  288. defined(_CRT_SECURE_NO_DEPRECATE)
  289. static char_type* str_copy(char_type* dest, char_type const* src)
  290. {
  291. INETSTL_ASSERT(NULL != dest);
  292. INETSTL_ASSERT(NULL != src);
  293. # ifdef STLSOFT_MIN_CRT
  294. return ::lstrcpyA(dest, src);
  295. # else /*? STLSOFT_MIN_CRT */
  296. return ::strcpy(dest, src);
  297. # endif /* STLSOFT_MIN_CRT */
  298. }
  299. static char_type* str_n_copy(char_type* dest, char_type const* src, is_size_t cch)
  300. {
  301. INETSTL_ASSERT(NULL != dest);
  302. INETSTL_ASSERT(0 == cch || NULL != src);
  303. return ::strncpy(dest, src, cch);
  304. }
  305. static char_type* str_cat(char_type* dest, char_type const* src)
  306. {
  307. INETSTL_ASSERT(NULL != dest);
  308. INETSTL_ASSERT(NULL != src);
  309. # ifdef STLSOFT_MIN_CRT
  310. return ::lstrcatA(dest, src);
  311. # else /*? STLSOFT_MIN_CRT */
  312. return ::strcat(dest, src);
  313. # endif /* STLSOFT_MIN_CRT */
  314. }
  315. #endif /* !STLSOFT_USING_SAFE_STR_FUNCTIONS || _CRT_SECURE_NO_DEPRECATE */
  316. static int_type str_compare(char_type const* s1, char_type const* s2)
  317. {
  318. INETSTL_ASSERT(NULL != s1);
  319. INETSTL_ASSERT(NULL != s2);
  320. #ifdef STLSOFT_MIN_CRT
  321. return ::lstrcmpA(s1, s2);
  322. #else /*? STLSOFT_MIN_CRT */
  323. return ::strcmp(s1, s2);
  324. #endif /* STLSOFT_MIN_CRT */
  325. }
  326. static int_type str_compare_no_case(char_type const* s1, char_type const* s2)
  327. {
  328. INETSTL_ASSERT(NULL != s1);
  329. INETSTL_ASSERT(NULL != s2);
  330. return ::lstrcmpiA(s1, s2);
  331. }
  332. static int_type str_n_compare(char_type const* s1, char_type const* s2, size_type cch)
  333. {
  334. INETSTL_ASSERT(NULL != s1);
  335. INETSTL_ASSERT(NULL != s2);
  336. return ::strncmp(s1, s2, cch);
  337. }
  338. static size_type str_len(char_type const* src)
  339. {
  340. #ifdef STLSOFT_MIN_CRT
  341. return static_cast<size_type>(::lstrlenA(src));
  342. #else /*? STLSOFT_MIN_CRT */
  343. return ::strlen(src);
  344. #endif /* STLSOFT_MIN_CRT */
  345. }
  346. static char_type* str_chr(char_type const* s, char_type ch)
  347. {
  348. return const_cast<char_type*>(::strchr(s, ch));
  349. }
  350. static char_type* str_rchr(char_type const* s, char_type ch)
  351. {
  352. return const_cast<char_type*>(::strrchr(s, ch));
  353. }
  354. static char_type* str_str(char_type const* s, char_type const* sub)
  355. {
  356. return const_cast<char_type*>(::strstr(s, sub));
  357. }
  358. // File-system entry names
  359. static char_type* ensure_dir_end(char_type* dir)
  360. {
  361. char_type *end;
  362. char_type const separator = (NULL == str_chr(dir, '/') && NULL != str_chr(dir, '\\')) ? '\\' : '/';
  363. for(end = dir; *end != '\0'; ++end)
  364. {}
  365. if( dir < end &&
  366. *(end - 1) != separator)
  367. {
  368. *end = separator;
  369. *(end + 1) = '\0';
  370. }
  371. return dir;
  372. }
  373. static char_type* remove_dir_end(char_type* dir)
  374. {
  375. char_type *end;
  376. for(end = dir; *end != '\0'; ++end)
  377. {}
  378. if( dir < end &&
  379. *(end - 1) == path_name_separator())
  380. {
  381. *(end - 1) = '\0';
  382. }
  383. return dir;
  384. }
  385. static bool_type has_dir_end(char_type const* dir)
  386. {
  387. is_size_t len = str_len(dir);
  388. return (0 < len) && path_name_separator() == dir[len - 1];
  389. }
  390. static bool_type is_dots(char_type const* dir)
  391. {
  392. return dir != 0 &&
  393. dir[0] == '.' &&
  394. ( dir[1] == '\0' ||
  395. ( dir[1] == '.' &&
  396. dir[2] == '\0'));
  397. }
  398. static bool_type is_path_rooted(char_type const* path)
  399. {
  400. INETSTL_ASSERT(NULL != path);
  401. return '/' == *path;
  402. }
  403. static bool_type is_path_absolute(char_type const* path)
  404. {
  405. return is_path_rooted(path);
  406. }
  407. static bool_type is_path_name_separator(char_type ch)
  408. {
  409. return '/' == ch;
  410. }
  411. static char_type path_separator()
  412. {
  413. return ';';
  414. }
  415. static char_type path_name_separator()
  416. {
  417. return '/';
  418. }
  419. static char_type const* pattern_all()
  420. {
  421. return "*";
  422. }
  423. static size_type get_full_path_name(HINTERNET hconn, char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile)
  424. {
  425. INETSTL_ASSERT(0 == cchBuffer || NULL != buffer);
  426. INETSTL_ASSERT(NULL == buffer || 0 != cchBuffer);
  427. INETSTL_ASSERT(NULL != fileName);
  428. // Deduce the separator
  429. char_type const separator = (NULL == str_chr(fileName, '/') && NULL != str_chr(fileName, '\\')) ? '\\' : '/';
  430. char_type fullPath[1 + _MAX_PATH];
  431. size_type len = str_len(fileName);
  432. // If we're not rooted, then get the current directory and concatenate
  433. if(separator != *fileName)
  434. {
  435. is_size_t cchBuffer = STLSOFT_NUM_ELEMENTS(fullPath);
  436. const int isDot = '.' == 0[fileName] && '\0' == 0[fileName];
  437. #ifdef __SYNSOFT_DBS_COMPILER_SUPPORTS_PRAGMA_MESSAGE
  438. # pragma message(_sscomp_fileline_message("This looks a bit dodgy. Better to use an auto_buffer, and cycle the size, testing the return value from get_current_directory"))
  439. #endif /* __SYNSOFT_DBS_COMPILER_SUPPORTS_PRAGMA_MESSAGE */
  440. if(!get_current_directory(hconn, cchBuffer, fullPath))
  441. {
  442. fullPath[0] = '\0';
  443. }
  444. size_type cchFullPath = str_len(fullPath);
  445. if(!isDot)
  446. {
  447. if(!has_dir_end(fullPath))
  448. {
  449. ensure_dir_end(fullPath);
  450. ++cchFullPath;
  451. }
  452. char_copy(&fullPath[0] + cchFullPath, fileName, 1 + len);
  453. }
  454. fileName = fullPath;
  455. len += cchFullPath;
  456. }
  457. if(NULL != buffer)
  458. {
  459. if(cchBuffer < len)
  460. {
  461. len = cchBuffer;
  462. }
  463. char_copy(buffer, fileName, cchBuffer);
  464. if(NULL != ppFile)
  465. {
  466. char_type const* pRSlash = str_rchr(buffer, '/');
  467. char_type const* pRBackSlash = str_rchr(buffer, '\\');
  468. if(pRSlash < pRBackSlash)
  469. {
  470. pRSlash = pRBackSlash;
  471. }
  472. if(NULL == pRSlash)
  473. {
  474. *ppFile = NULL;
  475. }
  476. else
  477. {
  478. *ppFile = const_cast<char_type*>(pRSlash) + 1;
  479. }
  480. }
  481. }
  482. return len;
  483. }
  484. static size_type get_full_path_name(HINTERNET hconn, char_type const* fileName, size_type cchBuffer, char_type* buffer)
  485. {
  486. char_type* pFile;
  487. return get_full_path_name(hconn, fileName, cchBuffer, buffer, &pFile);
  488. }
  489. // Internet connectivity
  490. static HINTERNET internet_open(char_type const* agent, is_dword_t accessType, char_type const* proxy, char_type const* proxyBypass, is_dword_t flags)
  491. {
  492. return ::InternetOpenA(agent, accessType, proxy, proxyBypass, flags);
  493. }
  494. static HINTERNET internet_connect(HINTERNET hsess, char_type const* server, INTERNET_PORT port, char_type const* userName, char_type const* password, is_dword_t service, is_dword_t flags, is_dword_t context)
  495. {
  496. return ::InternetConnectA(hsess, server, port, userName, password, service, flags, context);
  497. }
  498. static void close_connection(HINTERNET hconn)
  499. {
  500. INETSTL_ASSERT(NULL != hconn);
  501. ::InternetCloseHandle(hconn);
  502. }
  503. // FindFile() API
  504. static HINTERNET find_first_file(HINTERNET hconn, char_type const* spec, find_data_type *findData, is_dword_t flags = 0, is_dword_t context = 0)
  505. {
  506. HINTERNET hfind = ::FtpFindFirstFileA(hconn, spec, stlsoft_ns_qual(any_caster)<find_data_type*, LPWIN32_FIND_DATAA, LPWIN32_FIND_DATAW>(findData), flags, context);
  507. #if 0
  508. if(NULL == hfind)
  509. {
  510. findData->cFileName[0] = '\0';
  511. }
  512. printf("find_first_file(0x%08x, %s => %s)\n", hfind, spec, findData->cFileName);
  513. #endif /* 0 */
  514. return hfind;
  515. }
  516. static bool_type find_next_file(HANDLE h, find_data_type *findData)
  517. {
  518. return FALSE != ::InternetFindNextFileA(h, findData);
  519. }
  520. static void find_close(HINTERNET hfind)
  521. {
  522. INETSTL_ASSERT(NULL != hfind);
  523. ::InternetCloseHandle(hfind);
  524. }
  525. // File system state
  526. static bool_type set_current_directory(HINTERNET hconn, char_type const* dir)
  527. {
  528. return ::FtpSetCurrentDirectoryA(hconn, dir) != FALSE;
  529. }
  530. static bool_type get_current_directory(HINTERNET hconn, is_size_t &cchBuffer, char_type* buffer)
  531. {
  532. return FALSE != ::FtpGetCurrentDirectoryA(hconn, buffer, sap_cast<unsigned long*>(&cchBuffer));
  533. }
  534. static bool_type file_exists(HINTERNET hconn, char_type const* fileName)
  535. {
  536. find_data_type data;
  537. HINTERNET hfind = find_first_file(hconn, fileName, &data);
  538. return (NULL == hfind) ? false : (find_close(hfind), true);
  539. }
  540. #if 0
  541. static bool_type is_file(HINTERNET hconn, char_type const* path);
  542. static bool_type is_directory(HINTERNET hconn, char_type const* path);
  543. static bool_type stat(HINTERNET hconn, char_type const* path, stat_data_type *stat_data);
  544. #endif /* 0 */
  545. static bool_type is_file(stat_data_type const* stat_data)
  546. {
  547. return FILE_ATTRIBUTE_DIRECTORY != (stat_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  548. }
  549. static bool_type is_directory(stat_data_type const* stat_data)
  550. {
  551. return FILE_ATTRIBUTE_DIRECTORY == (stat_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  552. }
  553. static bool_type is_link(stat_data_type const* stat_data);
  554. static bool_type is_readonly(stat_data_type const* stat_data)
  555. {
  556. return FILE_ATTRIBUTE_READONLY == (stat_data->dwFileAttributes & FILE_ATTRIBUTE_READONLY);
  557. }
  558. // File system control
  559. static bool_type create_directory(HINTERNET hconn, char_type const* dir)
  560. {
  561. return FALSE != ::FtpCreateDirectoryA(hconn, dir);
  562. }
  563. static bool_type remove_directory(HINTERNET hconn, char_type const* dir)
  564. {
  565. return FALSE != ::FtpRemoveDirectoryA(hconn, dir);
  566. }
  567. static bool_type delete_file(HINTERNET hconn, char_type const* file)
  568. {
  569. return FALSE != ::FtpDeleteFileA(hconn, file);
  570. }
  571. static bool_type rename_file(HINTERNET hconn, char_type const* currentName, char_type const* newName)
  572. {
  573. return FALSE != ::FtpRenameFileA(hconn, currentName, newName);
  574. }
  575. };
  576. STLSOFT_TEMPLATE_SPECIALISATION
  577. struct filesystem_traits<is_char_w_t>
  578. {
  579. public:
  580. typedef is_char_w_t char_type;
  581. typedef is_size_t size_type;
  582. typedef is_ptrdiff_t difference_type;
  583. typedef WIN32_FIND_DATAW find_data_type;
  584. typedef WIN32_FIND_DATAW stat_data_type;
  585. typedef filesystem_traits<is_char_w_t> class_type;
  586. typedef is_int_t int_type;
  587. typedef is_bool_t bool_type;
  588. typedef DWORD error_type;
  589. public:
  590. static char_type* char_copy(char_type* dest, char_type const* src, size_type n)
  591. {
  592. INETSTL_ASSERT(NULL != dest);
  593. INETSTL_ASSERT(0 == n || NULL != src);
  594. return static_cast<char_type*>(::memcpy(dest, src, sizeof(char_type) * n));
  595. }
  596. // General string handling
  597. #if !defined(STLSOFT_USING_SAFE_STR_FUNCTIONS) || \
  598. defined(_CRT_SECURE_NO_DEPRECATE)
  599. static char_type* str_copy(char_type* dest, char_type const* src)
  600. {
  601. INETSTL_ASSERT(NULL != dest);
  602. INETSTL_ASSERT(NULL != src);
  603. # ifdef STLSOFT_MIN_CRT
  604. return ::lstrcpyW(dest, src);
  605. # else /*? STLSOFT_MIN_CRT */
  606. return ::wcscpy(dest, src);
  607. # endif /* STLSOFT_MIN_CRT */
  608. }
  609. static char_type* str_n_copy(char_type* dest, char_type const* src, is_size_t cch)
  610. {
  611. INETSTL_ASSERT(NULL != dest);
  612. INETSTL_ASSERT(0 == cch || NULL != src);
  613. return ::wcsncpy(dest, src, cch);
  614. }
  615. static char_type* str_cat(char_type* dest, char_type const* src)
  616. {
  617. INETSTL_ASSERT(NULL != dest);
  618. INETSTL_ASSERT(NULL != src);
  619. # ifdef STLSOFT_MIN_CRT
  620. return ::lstrcatW(dest, src);
  621. # else /*? STLSOFT_MIN_CRT */
  622. return ::wcscat(dest, src);
  623. # endif /* STLSOFT_MIN_CRT */
  624. }
  625. #endif /* !STLSOFT_USING_SAFE_STR_FUNCTIONS || _CRT_SECURE_NO_DEPRECATE */
  626. static int_type str_compare(char_type const* s1, char_type const* s2)
  627. {
  628. INETSTL_ASSERT(NULL != s1);
  629. INETSTL_ASSERT(NULL != s2);
  630. #ifdef STLSOFT_MIN_CRT
  631. return ::lstrcmpW(s1, s2);
  632. #else /*? STLSOFT_MIN_CRT */
  633. return ::wcscmp(s1, s2);
  634. #endif /* STLSOFT_MIN_CRT */
  635. }
  636. static int_type str_compare_no_case(char_type const* s1, char_type const* s2)
  637. {
  638. INETSTL_ASSERT(NULL != s1);
  639. INETSTL_ASSERT(NULL != s2);
  640. return ::lstrcmpiW(s1, s2);
  641. }
  642. static int_type str_n_compare(char_type const* s1, char_type const* s2, size_type cch)
  643. {
  644. INETSTL_ASSERT(NULL != s1);
  645. INETSTL_ASSERT(NULL != s2);
  646. return ::wcsncmp(s1, s2, cch);
  647. }
  648. static size_type str_len(char_type const* src)
  649. {
  650. #ifdef STLSOFT_MIN_CRT
  651. return static_cast<size_type>(::lstrlenW(src));
  652. #else /*? STLSOFT_MIN_CRT */
  653. return ::wcslen(src);
  654. #endif /* STLSOFT_MIN_CRT */
  655. }
  656. static char_type* str_chr(char_type const* s, char_type ch)
  657. {
  658. return const_cast<char_type*>(::wcschr(s, ch));
  659. }
  660. static char_type* str_rchr(char_type const* s, char_type ch)
  661. {
  662. return const_cast<char_type*>(::wcsrchr(s, ch));
  663. }
  664. static char_type* str_str(char_type const* s, char_type const* sub)
  665. {
  666. return const_cast<char_type*>(::wcsstr(s, sub));
  667. }
  668. // File-system entry names
  669. static char_type* ensure_dir_end(char_type* dir)
  670. {
  671. char_type *end;
  672. char_type const separator = (NULL == str_chr(dir, L'/') && NULL != str_chr(dir, L'\\')) ? L'\\' : L'/';
  673. for(end = dir; *end != L'\0'; ++end)
  674. {}
  675. if( dir < end &&
  676. *(end - 1) != separator)
  677. {
  678. *end = separator;
  679. *(end + 1) = L'\0';
  680. }
  681. return dir;
  682. }
  683. static char_type* remove_dir_end(char_type* dir)
  684. {
  685. char_type *end;
  686. for(end = dir; *end != '\0'; ++end)
  687. {}
  688. if( dir < end &&
  689. *(end - 1) == path_name_separator())
  690. {
  691. *(end - 1) = '\0';
  692. }
  693. return dir;
  694. }
  695. static bool_type has_dir_end(char_type const* dir)
  696. {
  697. is_size_t len = str_len(dir);
  698. return (0 < len) && path_name_separator() == dir[len - 1];
  699. }
  700. static bool_type is_dots(char_type const* dir)
  701. {
  702. return dir != 0 &&
  703. dir[0] == '.' &&
  704. ( dir[1] == L'\0' ||
  705. ( dir[1] == L'.' &&
  706. dir[2] == L'\0'));
  707. }
  708. static bool_type is_path_rooted(char_type const* path)
  709. {
  710. INETSTL_ASSERT(NULL != path);
  711. return L'/' == *path;
  712. }
  713. static bool_type is_path_absolute(char_type const* path)
  714. {
  715. return is_path_rooted(path);
  716. }
  717. static bool_type is_path_name_separator(char_type ch)
  718. {
  719. return L'/' == ch;
  720. }
  721. static char_type path_separator()
  722. {
  723. return L';';
  724. }
  725. static char_type path_name_separator()
  726. {
  727. return L'/';
  728. }
  729. static char_type const* pattern_all()
  730. {
  731. return L"*";
  732. }
  733. static size_type get_full_path_name(HINTERNET hconn, char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile)
  734. {
  735. INETSTL_ASSERT(0 == cchBuffer || NULL != buffer);
  736. INETSTL_ASSERT(NULL == buffer || 0 != cchBuffer);
  737. INETSTL_ASSERT(NULL != fileName);
  738. // Deduce the separator
  739. char_type const separator = (NULL == str_chr(fileName, L'/') && NULL != str_chr(fileName, L'\\')) ? L'\\' : L'/';
  740. char_type fullPath[1 + _MAX_PATH];
  741. size_type len = str_len(fileName);
  742. // If we're not rooted, then get the current directory and concatenate
  743. if(separator != *fileName)
  744. {
  745. is_size_t cchBuffer = STLSOFT_NUM_ELEMENTS(fullPath);
  746. const int isDot = L'.' == 0[fileName] && L'\0' == 0[fileName];
  747. #ifdef __SYNSOFT_DBS_COMPILER_SUPPORTS_PRAGMA_MESSAGE
  748. # pragma message(_sscomp_fileline_message("This looks a bit dodgy. Better to use an auto_buffer, and cycle the size, testing the return value from get_current_directory"))
  749. #endif /* __SYNSOFT_DBS_COMPILER_SUPPORTS_PRAGMA_MESSAGE */
  750. if(!get_current_directory(hconn, cchBuffer, fullPath))
  751. {
  752. fullPath[0] = L'\0';
  753. }
  754. size_type cchFullPath = str_len(fullPath);
  755. if(!isDot)
  756. {
  757. if(!has_dir_end(fullPath))
  758. {
  759. ensure_dir_end(fullPath);
  760. ++cchFullPath;
  761. }
  762. char_copy(&fullPath[0] + cchFullPath, fileName, 1 + len);
  763. }
  764. fileName = fullPath;
  765. len += cchFullPath;
  766. }
  767. if(NULL != buffer)
  768. {
  769. if(cchBuffer < len)
  770. {
  771. len = cchBuffer;
  772. }
  773. char_copy(buffer, fileName, cchBuffer);
  774. if(NULL != ppFile)
  775. {
  776. char_type const* pRSlash = str_rchr(buffer, L'/');
  777. char_type const* pRBackSlash = str_rchr(buffer, L'\\');
  778. if(pRSlash < pRBackSlash)
  779. {
  780. pRSlash = pRBackSlash;
  781. }
  782. if(NULL == pRSlash)
  783. {
  784. *ppFile = NULL;
  785. }
  786. else
  787. {
  788. *ppFile = const_cast<char_type*>(pRSlash) + 1;
  789. }
  790. }
  791. }
  792. return len;
  793. }
  794. static size_type get_full_path_name(HINTERNET hconn, char_type const* fileName, size_type cchBuffer, char_type* buffer)
  795. {
  796. char_type* pFile;
  797. return get_full_path_name(hconn, fileName, cchBuffer, buffer, &pFile);
  798. }
  799. // Internet connectivity
  800. static HINTERNET internet_open(char_type const* agent, is_dword_t accessType, char_type const* proxy, char_type const* proxyBypass, is_dword_t flags)
  801. {
  802. return ::InternetOpenW(agent, accessType, proxy, proxyBypass, flags);
  803. }
  804. static HINTERNET internet_connect(HINTERNET hsess, char_type const* server, INTERNET_PORT port, char_type const* userName, char_type const* password, is_dword_t service, is_dword_t flags, is_dword_t context)
  805. {
  806. return ::InternetConnectW(hsess, server, port, userName, password, service, flags, context);
  807. }
  808. static void close_connection(HINTERNET hconn)
  809. {
  810. INETSTL_ASSERT(NULL != hconn);
  811. ::InternetCloseHandle(hconn);
  812. }
  813. // FindFile() API
  814. static HINTERNET find_first_file(HINTERNET hconn, char_type const* spec, find_data_type *findData, is_dword_t flags = 0, is_dword_t context = 0)
  815. {
  816. return ::FtpFindFirstFileW(hconn, spec, stlsoft_ns_qual(any_caster)<find_data_type*, LPWIN32_FIND_DATAA, LPWIN32_FIND_DATAW>(findData), flags, context);
  817. }
  818. static bool_type find_next_file(HANDLE h, find_data_type *findData)
  819. {
  820. return FALSE != ::InternetFindNextFileW(h, findData);
  821. }
  822. static void find_close(HINTERNET hfind)
  823. {
  824. INETSTL_ASSERT(NULL != hfind);
  825. ::InternetCloseHandle(hfind);
  826. }
  827. // File system state
  828. static bool_type set_current_directory(HINTERNET hconn, char_type const* dir)
  829. {
  830. return ::FtpSetCurrentDirectoryW(hconn, dir) != FALSE;
  831. }
  832. static bool_type get_current_directory(HINTERNET hconn, is_size_t &cchBuffer, char_type* buffer)
  833. {
  834. return FALSE != ::FtpGetCurrentDirectoryW(hconn, buffer, sap_cast<unsigned long*>(&cchBuffer));
  835. }
  836. /// Returns whether a file exists or not
  837. static bool_type file_exists(HINTERNET hconn, char_type const* fileName)
  838. {
  839. find_data_type data;
  840. HINTERNET hfind = find_first_file(hconn, fileName, &data);
  841. return (NULL == hfind) ? false : (find_close(hfind), true);
  842. }
  843. #if 0
  844. static bool_type is_file(HINTERNET hconn, char_type const* path);
  845. static bool_type is_directory(HINTERNET hconn, char_type const* path);
  846. static bool_type stat(HINTERNET hconn, char_type const* path, stat_data_type *stat_data);
  847. #endif /* 0 */
  848. static bool_type is_file(stat_data_type const* stat_data)
  849. {
  850. return FILE_ATTRIBUTE_DIRECTORY != (stat_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  851. }
  852. static bool_type is_directory(stat_data_type const* stat_data)
  853. {
  854. return FILE_ATTRIBUTE_DIRECTORY == (stat_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  855. }
  856. static bool_type is_link(stat_data_type const* stat_data);
  857. static bool_type is_readonly(stat_data_type const* stat_data)
  858. {
  859. return FILE_ATTRIBUTE_READONLY == (stat_data->dwFileAttributes & FILE_ATTRIBUTE_READONLY);
  860. }
  861. // File system control
  862. static bool_type create_directory(HINTERNET hconn, char_type const* dir)
  863. {
  864. return FALSE != ::FtpCreateDirectoryW(hconn, dir);
  865. }
  866. static bool_type remove_directory(HINTERNET hconn, char_type const* dir)
  867. {
  868. return FALSE != ::FtpRemoveDirectoryW(hconn, dir);
  869. }
  870. static bool_type delete_file(HINTERNET hconn, char_type const* file)
  871. {
  872. return FALSE != ::FtpDeleteFileW(hconn, file);
  873. }
  874. static bool_type rename_file(HINTERNET hconn, char_type const* currentName, char_type const* newName)
  875. {
  876. return FALSE != ::FtpRenameFileW(hconn, currentName, newName);
  877. }
  878. };
  879. #endif /* STLSOFT_DOCUMENTATION_SKIP_SECTION */
  880. /* ////////////////////////////////////////////////////////////////////// */
  881. #ifndef _INETSTL_NO_NAMESPACE
  882. # if defined(_STLSOFT_NO_NAMESPACE) || \
  883. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  884. } // namespace inetstl
  885. # else
  886. } // namespace inetstl_project
  887. } // namespace stlsoft
  888. # endif /* _STLSOFT_NO_NAMESPACE */
  889. #endif /* !_INETSTL_NO_NAMESPACE */
  890. /* ////////////////////////////////////////////////////////////////////// */
  891. #endif /* INETSTL_INCL_INETSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS */
  892. /* ///////////////////////////// end of file //////////////////////////// */