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.

326 lines
11 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: winstl/filesystem/path_functions.hpp
  3. *
  4. * Purpose: Helper functions for file handling
  5. *
  6. * Created: 6th June 2006
  7. * Updated: 2nd April 2010
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 2006-2010, Matthew Wilson and Synesis Software
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions are met:
  16. *
  17. * - Redistributions of source code must retain the above copyright notice, this
  18. * list of conditions and the following disclaimer.
  19. * - Redistributions in binary form must reproduce the above copyright notice,
  20. * this list of conditions and the following disclaimer in the documentation
  21. * and/or other materials provided with the distribution.
  22. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  23. * any contributors may be used to endorse or promote products derived from
  24. * this software without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. * ////////////////////////////////////////////////////////////////////// */
  39. /** \file winstl/filesystem/path_functions.hpp
  40. *
  41. * \brief [C++ only] Helper functions for (text) file handling
  42. * (\ref group__library__filesystem "File System" Library).
  43. */
  44. #ifndef WINSTL_INCL_WINSTL_FILESYSTEM_HPP_PATH_FUNCTIONS
  45. #define WINSTL_INCL_WINSTL_FILESYSTEM_HPP_PATH_FUNCTIONS
  46. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  47. # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_PATH_FUNCTIONS_MAJOR 1
  48. # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_PATH_FUNCTIONS_MINOR 1
  49. # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_PATH_FUNCTIONS_REVISION 3
  50. # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_PATH_FUNCTIONS_EDIT 17
  51. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  52. /* /////////////////////////////////////////////////////////////////////////
  53. * Includes
  54. */
  55. #ifndef WINSTL_INCL_WINSTL_H_WINSTL
  56. # include <winstl/winstl.h>
  57. #endif /* !WINSTL_INCL_WINSTL_H_WINSTL */
  58. #ifndef WINSTL_INCL_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS
  59. # include <winstl/filesystem/filesystem_traits.hpp>
  60. #endif /* !WINSTL_INCL_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS */
  61. #ifndef WINSTL_INCL_WINSTL_FILESYSTEM_HPP_PATH
  62. # include <winstl/filesystem/path.hpp>
  63. #endif /* !WINSTL_INCL_WINSTL_FILESYSTEM_HPP_PATH */
  64. #ifndef STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING
  65. # include <stlsoft/shims/access/string.hpp>
  66. #endif /* !STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING */
  67. #ifdef STLSOFT_UNITTEST
  68. #endif // STLSOFT_UNITTEST
  69. /* /////////////////////////////////////////////////////////////////////////
  70. * Namespace
  71. */
  72. #ifndef _WINSTL_NO_NAMESPACE
  73. # if defined(_STLSOFT_NO_NAMESPACE) || \
  74. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  75. /* There is no stlsoft namespace, so must define ::winstl */
  76. namespace winstl
  77. {
  78. # else
  79. /* Define stlsoft::winstl_project */
  80. namespace stlsoft
  81. {
  82. namespace winstl_project
  83. {
  84. # endif /* _STLSOFT_NO_NAMESPACE */
  85. #endif /* !_WINSTL_NO_NAMESPACE */
  86. /* /////////////////////////////////////////////////////////////////////////
  87. * Helper Functions
  88. */
  89. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  90. template <ss_typename_param_k C>
  91. ws_size_t path_squeeze_impl(
  92. C const* path
  93. , ws_size_t pathLen
  94. , C* buffer
  95. , ws_size_t cchBuffer
  96. )
  97. {
  98. typedef C char_t;
  99. typedef filesystem_traits<C> traits_t;
  100. typedef ws_size_t size_t;
  101. if(NULL == buffer)
  102. {
  103. cchBuffer = pathLen + 1u;
  104. }
  105. else if(0 != cchBuffer)
  106. {
  107. basic_path<char_t> p(path, pathLen);
  108. char_t const* file_ptr = p.get_file();
  109. char_t const* path_ptr = p.c_str();
  110. const size_t fileLen = p.size() - (file_ptr - path_ptr);
  111. if(cchBuffer > pathLen)
  112. {
  113. // Room for all
  114. traits_t::char_copy(buffer, path_ptr, pathLen);
  115. buffer[pathLen] = '\0';
  116. cchBuffer = pathLen + 1u;
  117. }
  118. else
  119. {
  120. size_t rootLen;
  121. // Need to handle:
  122. //
  123. // 1. UNC
  124. // 2. drive
  125. // 3. rooted - begins with \ or /
  126. // 4. non-rooted
  127. if(p.is_rooted())
  128. {
  129. if(p.is_absolute())
  130. {
  131. if(traits_t::is_path_UNC(path_ptr))
  132. {
  133. // 1. UNC
  134. char_t const* p1 = traits_t::str_chr(path_ptr + 2, '\\');
  135. if(NULL == p1)
  136. {
  137. // badly formed UNC, so treat as no-root
  138. rootLen = 0;
  139. }
  140. else
  141. {
  142. rootLen = 1 + static_cast<size_t>(p1 - path_ptr);
  143. }
  144. }
  145. else
  146. {
  147. // 2. drive
  148. rootLen = 3;
  149. }
  150. }
  151. else
  152. {
  153. // 3. rooted - begins with \ or /
  154. rootLen = 1;
  155. }
  156. }
  157. else
  158. {
  159. // 4. non-rooted
  160. rootLen = 0;
  161. }
  162. if(cchBuffer < 5 + 1)
  163. {
  164. traits_t::char_copy(buffer, file_ptr, cchBuffer - 1);
  165. buffer[cchBuffer - 1] = '\0';
  166. if(cchBuffer > fileLen)
  167. {
  168. cchBuffer = fileLen + 1;
  169. }
  170. }
  171. else if(cchBuffer < fileLen + 1)
  172. {
  173. // Squeezing just file+ext
  174. size_t leftLen = (cchBuffer - 3 - 1) / 2;
  175. size_t rightLen = (cchBuffer - 3 - 1) - leftLen;
  176. traits_t::char_copy(buffer, file_ptr, leftLen);
  177. buffer[leftLen + 0] = '.';
  178. buffer[leftLen + 1] = '.';
  179. buffer[leftLen + 2] = '.';
  180. traits_t::char_copy(buffer + leftLen + 3, file_ptr + (fileLen - rightLen), rightLen);
  181. buffer[leftLen + 3 + rightLen] = '\0';
  182. }
  183. else if(cchBuffer < rootLen + 3 + 1 + fileLen + 1)
  184. {
  185. // File (name + ext) only
  186. traits_t::char_copy(buffer, file_ptr, fileLen);
  187. buffer[fileLen] = '\0';
  188. if(cchBuffer > fileLen)
  189. {
  190. cchBuffer = fileLen + 1;
  191. }
  192. }
  193. else
  194. {
  195. WINSTL_ASSERT(cchBuffer < pathLen + 1);
  196. // Squeezing
  197. size_t rightLen = 1 + fileLen;
  198. size_t leftLen = (cchBuffer - 3 - 1) - rightLen;
  199. traits_t::char_copy(buffer, path_ptr, leftLen);
  200. buffer[leftLen + 0] = '.';
  201. buffer[leftLen + 1] = '.';
  202. buffer[leftLen + 2] = '.';
  203. traits_t::char_copy(buffer + leftLen + 3, file_ptr - 1, rightLen);
  204. buffer[leftLen + 3 + rightLen] = '\0';
  205. }
  206. }
  207. }
  208. return cchBuffer;
  209. }
  210. template<ss_typename_param_k S>
  211. ws_size_t path_squeeze_impl2(S const& path, ws_char_a_t* buffer, ws_size_t cchBuffer)
  212. {
  213. return path_squeeze_impl(stlsoft_ns_qual(c_str_ptr_a)(path), stlsoft_ns_qual(c_str_len)(path), buffer, cchBuffer);
  214. }
  215. template<ss_typename_param_k S>
  216. ws_size_t path_squeeze_impl2(S const& path, ws_char_w_t* buffer, ws_size_t cchBuffer)
  217. {
  218. return path_squeeze_impl(stlsoft_ns_qual(c_str_ptr_w)(path), stlsoft_ns_qual(c_str_len)(path), buffer, cchBuffer);
  219. }
  220. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  221. #if 0
  222. template <ss_typename_param_k C>
  223. ws_size_t path_squeeze(C const* path, C* buffer, ws_size_t cchBuffer)
  224. {
  225. typedef filesystem_traits<C> traits_t;
  226. return path_squeeze_impl(path, traits_t::str_len(path), buffer, cchBuffer);
  227. }
  228. #endif /* 0 */
  229. /* /////////////////////////////////////////////////////////////////////////
  230. * API Functions
  231. */
  232. /** Squeezes a path into a fixed length character buffer
  233. *
  234. * \ingroup group__library__filesystem
  235. *
  236. * \param path The path
  237. * \param buffer Pointer to the buffer into which the sqeezed path will be
  238. * written. If NULL, function returns required size (=== len(path) + 1)
  239. * \param cchBuffer The number of available characters inc buffer. This
  240. * value in inclusive of the required nul-terminator
  241. *
  242. * \return The number of characters required (if buffer is NULL), or the
  243. * number of characters written (if buffer is non-NULL). In both cases, it
  244. * includes the one required for the nul-terminator
  245. *
  246. * \remarks The squeeze algorithm is as follows. The path is split into
  247. * volume+directory and file+ext. If the buffer is too small to fit the
  248. * file+ext, then the result will be a squeezed form of file+ext. If the
  249. * buffer is too small to fit the volume+...+file+ext, then the result
  250. * will be file+ext. If the buffer is too small to fit the entire path,
  251. * then the result will be volume+part_of_directory+...+file+ext.
  252. * Otherwise the result will be the full path.
  253. */
  254. template< ss_typename_param_k S
  255. , ss_typename_param_k C
  256. >
  257. ws_size_t path_squeeze(S const& path, C* buffer, ws_size_t cchBuffer)
  258. {
  259. return path_squeeze_impl2(path, buffer, cchBuffer);
  260. }
  261. /* /////////////////////////////////////////////////////////////////////////
  262. * Unit-testing
  263. */
  264. #ifdef STLSOFT_UNITTEST
  265. # include "./unittest/path_functions_unittest_.h"
  266. #endif /* STLSOFT_UNITTEST */
  267. /* ////////////////////////////////////////////////////////////////////// */
  268. #ifndef _WINSTL_NO_NAMESPACE
  269. # if defined(_STLSOFT_NO_NAMESPACE) || \
  270. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  271. } // namespace winstl
  272. # else
  273. } // namespace winstl_project
  274. } // namespace stlsoft
  275. # endif /* _STLSOFT_NO_NAMESPACE */
  276. #endif /* !_WINSTL_NO_NAMESPACE */
  277. /* ////////////////////////////////////////////////////////////////////// */
  278. #endif /* !WINSTL_INCL_WINSTL_FILESYSTEM_HPP_PATH_FUNCTIONS */
  279. /* ///////////////////////////// end of file //////////////////////////// */