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.

968 lines
26 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: comstl/string/bstr.hpp (originally MOBStr.h/.cpp, ::SynesisCom)
  3. *
  4. * Purpose: bstr class.
  5. *
  6. * Created: 20th December 1996
  7. * Updated: 5th March 2011
  8. *
  9. * Thanks: To Gabor Fischer for requesting attach().
  10. *
  11. * Home: http://stlsoft.org/
  12. *
  13. * Copyright (c) 1996-2011, Matthew Wilson and Synesis Software
  14. * All rights reserved.
  15. *
  16. * Redistribution and use in source and binary forms, with or without
  17. * modification, are permitted provided that the following conditions are met:
  18. *
  19. * - Redistributions of source code must retain the above copyright notice, this
  20. * list of conditions and the following disclaimer.
  21. * - Redistributions in binary form must reproduce the above copyright notice,
  22. * this list of conditions and the following disclaimer in the documentation
  23. * and/or other materials provided with the distribution.
  24. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  25. * any contributors may be used to endorse or promote products derived from
  26. * this software without specific prior written permission.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  29. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  30. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  31. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  34. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  35. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  36. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  37. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  38. * POSSIBILITY OF SUCH DAMAGE.
  39. *
  40. * ////////////////////////////////////////////////////////////////////// */
  41. /** \file comstl/string/bstr.hpp
  42. *
  43. * \brief [C++ only; requires COM] Definition of the comstl::bstr class
  44. * (\ref group__library__utility__com "COM Utility" Library).
  45. */
  46. #ifndef COMSTL_INCL_COMSTL_STRING_HPP_BSTR
  47. #define COMSTL_INCL_COMSTL_STRING_HPP_BSTR
  48. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  49. # define _COMSTL_VER_COMSTL_STRING_HPP_BSTR_MAJOR 2
  50. # define _COMSTL_VER_COMSTL_STRING_HPP_BSTR_MINOR 8
  51. # define _COMSTL_VER_COMSTL_STRING_HPP_BSTR_REVISION 4
  52. # define _COMSTL_VER_COMSTL_STRING_HPP_BSTR_EDIT 62
  53. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  54. /* /////////////////////////////////////////////////////////////////////////
  55. * Includes
  56. */
  57. #ifndef COMSTL_INCL_COMSTL_H_COMSTL
  58. # include <comstl/comstl.h>
  59. #endif /* !COMSTL_INCL_COMSTL_H_COMSTL */
  60. //#ifndef COMSTL_INCL_COMSTL_SHIMS_ACCESS_HPP_STRING
  61. //# include <comstl/shims/access/string.hpp>
  62. //#endif /* !COMSTL_INCL_COMSTL_SHIMS_ACCESS_HPP_STRING */
  63. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  64. # ifndef COMSTL_INCL_COMSTL_ERROR_HPP_EXCEPTIONS
  65. # include <comstl/error/exceptions.hpp>
  66. # endif /* !COMSTL_INCL_COMSTL_ERROR_HPP_EXCEPTIONS */
  67. #endif /* !STLSOFT_CF_EXCEPTION_SUPPORT */
  68. #ifndef COMSTL_INCL_COMSTL_STRING_H_BSTR_FUNCTIONS
  69. # include <comstl/string/BSTR_functions.h>
  70. #endif /* !COMSTL_INCL_COMSTL_STRING_H_BSTR_FUNCTIONS */
  71. #ifndef STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING
  72. # include <stlsoft/shims/access/string.hpp>
  73. #endif /* !STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING */
  74. #ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_TRAITS_FWD
  75. # include <stlsoft/string/string_traits_fwd.hpp>
  76. #endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_TRAITS_FWD */
  77. #ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER
  78. # include <stlsoft/util/std/iterator_helper.hpp>
  79. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER */
  80. #ifndef STLSOFT_INCL_STLSOFT_UTIL_HPP_STD_SWAP
  81. # include <stlsoft/util/std_swap.hpp>
  82. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_HPP_STD_SWAP */
  83. #ifndef STLSOFT_INCL_STLSOFT_INTERNAL_H_SAFESTR
  84. # include <stlsoft/internal/safestr.h>
  85. #endif /* !STLSOFT_INCL_STLSOFT_INTERNAL_H_SAFESTR */
  86. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  87. # include <stdexcept>
  88. #endif /* !STLSOFT_CF_EXCEPTION_SUPPORT */
  89. /* /////////////////////////////////////////////////////////////////////////
  90. * Namespace
  91. */
  92. #ifndef _COMSTL_NO_NAMESPACE
  93. # if defined(_STLSOFT_NO_NAMESPACE) || \
  94. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  95. /* There is no stlsoft namespace, so must define ::comstl */
  96. namespace comstl
  97. {
  98. # else
  99. /* Define stlsoft::comstl_project */
  100. namespace stlsoft
  101. {
  102. namespace comstl_project
  103. {
  104. # endif /* _STLSOFT_NO_NAMESPACE */
  105. #endif /* !_COMSTL_NO_NAMESPACE */
  106. /* /////////////////////////////////////////////////////////////////////////
  107. * Classes
  108. */
  109. /** \brief Facade for the COM BSTR type
  110. *
  111. * \ingroup group__library__utility__com
  112. */
  113. class bstr
  114. {
  115. /// \name Member Types
  116. /// @{
  117. public:
  118. typedef bstr class_type;
  119. typedef cs_char_o_t char_type;
  120. typedef char_type value_type;
  121. typedef char_type* pointer;
  122. typedef char_type const* const_pointer;
  123. typedef char_type& reference;
  124. typedef char_type const& const_reference;
  125. typedef cs_ptrdiff_t difference_type;
  126. typedef cs_size_t size_type;
  127. typedef cs_ptrdiff_t ssize_type;
  128. typedef cs_bool_t bool_type;
  129. typedef pointer iterator;
  130. typedef const_pointer const_iterator;
  131. #if defined(STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT)
  132. typedef stlsoft_ns_qual(reverse_iterator_base)<
  133. iterator
  134. , value_type
  135. , reference
  136. , pointer
  137. , difference_type
  138. > reverse_iterator;
  139. typedef stlsoft_ns_qual(const_reverse_iterator_base)<
  140. const_iterator
  141. , value_type const
  142. , const_reference
  143. , const_pointer
  144. , difference_type
  145. > const_reverse_iterator;
  146. #endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  147. typedef BSTR resource_type;
  148. /// @}
  149. /// \name Construction
  150. /// @{
  151. public:
  152. bstr();
  153. ss_explicit_k bstr(cs_char_a_t const* s, ssize_type len = -1);
  154. ss_explicit_k bstr(cs_char_w_t const* s, ssize_type len = -1);
  155. bstr(size_type n, char_type ch);
  156. /// \brief Copy constructor
  157. bstr(class_type const& rhs);
  158. bstr(class_type const& rhs, size_type pos, size_type len);
  159. ~bstr() stlsoft_throw_0();
  160. /// \brief Copies the given instance
  161. class_type& operator =(class_type const& rhs);
  162. class_type& assign(cs_char_a_t const* s, ssize_type len = -1);
  163. class_type& assign(cs_char_w_t const* s, ssize_type len = -1);
  164. class_type& assign(const_iterator from, const_iterator to);
  165. class_type& operator =(cs_char_a_t const* s);
  166. class_type& operator =(cs_char_w_t const* s);
  167. class_type& attach(BSTR bstr);
  168. BSTR detach();
  169. void clear();
  170. /// @}
  171. /// \name Operations
  172. /// @{
  173. public:
  174. class_type& append(class_type const& s, ssize_type len = -1);
  175. class_type& append(cs_char_w_t const* s, ssize_type len = -1);
  176. class_type& operator +=(class_type const& s);
  177. class_type& operator +=(cs_char_w_t const* s);
  178. /// @}
  179. /// \name Accessors
  180. /// @{
  181. public:
  182. const_pointer data() const;
  183. const_pointer c_str() const;
  184. size_type length() const;
  185. size_type size() const;
  186. bool_type empty() const;
  187. BSTR get() const;
  188. reference operator [](size_type);
  189. const_reference operator [](size_type) const;
  190. const_pointer *NonDestructiveAddress() const;
  191. BSTR *NonDestructiveAddress();
  192. BSTR *DestructiveAddress();
  193. /// @}
  194. /// \name Iteration
  195. /// @{
  196. public:
  197. /// Begins the iteration
  198. ///
  199. /// \return An iterator representing the start of the sequence
  200. iterator begin();
  201. /// Ends the iteration
  202. ///
  203. /// \return An iterator representing the end of the sequence
  204. iterator end();
  205. /// Begins the iteration
  206. ///
  207. /// \return A non-mutable (const) iterator representing the start of the sequence
  208. const_iterator begin() const;
  209. /// Ends the iteration
  210. ///
  211. /// \return A non-mutable (const) iterator representing the end of the sequence
  212. const_iterator end() const;
  213. #if defined(STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT)
  214. /// Begins the reverse iteration
  215. ///
  216. /// \return A non-mutable (const) iterator representing the start of the reverse sequence
  217. const_reverse_iterator rbegin() const;
  218. /// Ends the reverse iteration
  219. ///
  220. /// \return A non-mutable (const) iterator representing the end of the reverse sequence
  221. const_reverse_iterator rend() const;
  222. /// Begins the reverse iteration
  223. ///
  224. /// \return An iterator representing the start of the reverse sequence
  225. reverse_iterator rbegin();
  226. /// Ends the reverse iteration
  227. ///
  228. /// \return An iterator representing the end of the reverse sequence
  229. reverse_iterator rend();
  230. #endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  231. /// @}
  232. /// \name Comparison
  233. /// @{
  234. public:
  235. /// \brief Evaluates whether the value is equivalent to the given argument
  236. bool_type equal(class_type const& rhs) const;
  237. /// \brief Evaluates whether the value is equivalent to the given argument
  238. bool_type equal(BSTR const& rhs) const;
  239. /// @}
  240. /// \name Operations
  241. /// @{
  242. public:
  243. /// \brief Swaps the contents with the given instance
  244. void swap(class_type& rhs) stlsoft_throw_0();
  245. /// \brief Swaps the contents with the given BSTR
  246. void swap(BSTR& rhs) stlsoft_throw_0();
  247. /// @}
  248. /// \name Members
  249. /// @{
  250. private:
  251. BSTR m_bstr;
  252. /// @}
  253. };
  254. /* /////////////////////////////////////////////////////////////////////////
  255. * String access shims
  256. */
  257. /** \brief \ref group__concept__shim__string_access__c_str_data for comstl::bstr
  258. *
  259. * \ingroup group__concept__shim__string_access
  260. */
  261. inline bstr::const_pointer c_str_data(comstl_ns_qual(bstr) const& b)
  262. {
  263. return b.data();
  264. }
  265. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  266. inline bstr::const_pointer c_str_data_w(comstl_ns_qual(bstr) const& b)
  267. {
  268. return b.data();
  269. }
  270. inline bstr::const_pointer c_str_data_o(comstl_ns_qual(bstr) const& b)
  271. {
  272. return b.data();
  273. }
  274. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  275. /** \brief \ref group__concept__shim__string_access__c_str_len for comstl::bstr
  276. *
  277. * \ingroup group__concept__shim__string_access
  278. */
  279. inline cs_size_t c_str_len(comstl_ns_qual(bstr) const& b)
  280. {
  281. return b.length();
  282. }
  283. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  284. inline cs_size_t c_str_len_w(comstl_ns_qual(bstr) const& b)
  285. {
  286. return b.length();
  287. }
  288. inline cs_size_t c_str_len_o(comstl_ns_qual(bstr) const& b)
  289. {
  290. return b.length();
  291. }
  292. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  293. /** \brief \ref group__concept__shim__string_access__c_str_ptr for comstl::bstr
  294. *
  295. * \ingroup group__concept__shim__string_access
  296. */
  297. inline bstr::const_pointer c_str_ptr(comstl_ns_qual(bstr) const& b)
  298. {
  299. return b.c_str();
  300. }
  301. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  302. inline bstr::const_pointer c_str_ptr_w(comstl_ns_qual(bstr) const& b)
  303. {
  304. return b.c_str();
  305. }
  306. inline bstr::const_pointer c_str_ptr_o(comstl_ns_qual(bstr) const& b)
  307. {
  308. return b.c_str();
  309. }
  310. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  311. /** \brief \ref group__concept__shim__string_access__c_str_ptr_null for comstl::bstr
  312. *
  313. * \ingroup group__concept__shim__string_access
  314. */
  315. inline bstr::const_pointer c_str_ptr_null(comstl_ns_qual(bstr) const& b)
  316. {
  317. return stlsoft_ns_qual(c_str_ptr_null)(b.c_str());
  318. }
  319. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  320. inline bstr::const_pointer c_str_ptr_null_w(comstl_ns_qual(bstr) const& b)
  321. {
  322. return stlsoft_ns_qual(c_str_ptr_null_w)(b.c_str());
  323. }
  324. inline bstr::const_pointer c_str_ptr_null_o(comstl_ns_qual(bstr) const& b)
  325. {
  326. return stlsoft_ns_qual(c_str_ptr_null)(b.c_str());
  327. }
  328. /** \brief \ref group__concept__shim__stream_insertion "stream insertion shim" for comstl::bstr
  329. *
  330. * \ingroup group__concept__shim__stream_insertion
  331. */
  332. template< ss_typename_param_k S
  333. >
  334. inline S& operator <<(S& stm, comstl_ns_qual(bstr) const& str)
  335. {
  336. STLSOFT_STATIC_ASSERT(sizeof(OLECHAR) == sizeof(ss_typename_type_k S::char_type));
  337. stm << str.c_str();
  338. return stm;
  339. }
  340. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  341. /* /////////////////////////////////////////////////////////////////////////
  342. * Operators
  343. */
  344. inline cs_bool_t operator ==(bstr const& lhs, bstr const& rhs)
  345. {
  346. return lhs.equal(rhs);
  347. }
  348. inline cs_bool_t operator !=(bstr const& lhs, bstr const& rhs)
  349. {
  350. return !operator ==(lhs, rhs);
  351. }
  352. inline cs_bool_t operator ==(bstr const& lhs, BSTR const& rhs)
  353. {
  354. return lhs.equal(rhs);
  355. }
  356. inline cs_bool_t operator !=(bstr const& lhs, BSTR const& rhs)
  357. {
  358. return !operator ==(lhs, rhs);
  359. }
  360. inline cs_bool_t operator ==(BSTR const& lhs, bstr const& rhs)
  361. {
  362. return rhs.equal(lhs);
  363. }
  364. inline cs_bool_t operator !=(BSTR const& lhs, bstr const& rhs)
  365. {
  366. return !operator ==(lhs, rhs);
  367. }
  368. ////////////////////////////////////////////////////////////////////////////
  369. // Unit-testing
  370. #ifdef STLSOFT_UNITTEST
  371. # include "./unittest/bstr_unittest_.h"
  372. #endif /* STLSOFT_UNITTEST */
  373. /* /////////////////////////////////////////////////////////////////////////
  374. * Implementation
  375. */
  376. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  377. // Construction
  378. inline bstr::bstr()
  379. : m_bstr(NULL)
  380. {}
  381. inline /* explicit */ bstr::bstr(cs_char_a_t const* s, ssize_type len /* = -1 */)
  382. {
  383. // Precondition tests
  384. COMSTL_MESSAGE_ASSERT("Default length must be specified by -1. No other -ve value allowed", (len >= 0 || len == -1));
  385. COMSTL_MESSAGE_ASSERT("Cannot pass in NULL pointer and -1 (default) length", (NULL != s || len >= 0));
  386. // There's a potential problem here (which has actually occurred!):
  387. //
  388. // If s is non-NULL and len is non-negative, it's possible for
  389. // the underlying SysAllocStringLen() to walk into invalid
  390. // memory while searching s.
  391. ssize_type actualLen = static_cast<ssize_type>(stlsoft_ns_qual(c_str_len)(s));
  392. if( NULL != s &&
  393. len > actualLen)
  394. {
  395. m_bstr = bstr_create(static_cast<cs_char_w_t const*>(NULL), static_cast<cs_size_t>(len));
  396. if(NULL != m_bstr)
  397. {
  398. # ifdef _WIN64
  399. int buffLen = static_cast<int>(actualLen + 1);
  400. # else /* ? _WIN64 */
  401. int buffLen = actualLen + 1;
  402. # endif /* _WIN64 */
  403. ::MultiByteToWideChar(0, 0, s, buffLen, m_bstr, buffLen);
  404. }
  405. }
  406. else
  407. {
  408. if(-1 == len)
  409. {
  410. len = actualLen;
  411. }
  412. m_bstr = bstr_create(s, static_cast<cs_size_t>(len));
  413. }
  414. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  415. if( NULL == m_bstr &&
  416. NULL != s &&
  417. 0 != len &&
  418. '\0' != 0[s])
  419. {
  420. STLSOFT_THROW_X(com_exception("failed to allocate string", HRESULT_FROM_WIN32(::GetLastError())));
  421. }
  422. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  423. }
  424. inline /* explicit */ bstr::bstr(cs_char_w_t const* s, ssize_type len /* = -1 */)
  425. {
  426. // Precondition tests
  427. COMSTL_MESSAGE_ASSERT("Default length must be specified by -1. No other -ve value allowed", (len >= 0 || len == -1));
  428. COMSTL_MESSAGE_ASSERT("Cannot pass in NULL pointer and -1 (default) length", (NULL != s || len >= 0));
  429. // There's a potential problem here (which has actually occurred!):
  430. //
  431. // If s is non-NULL and len is non-negative, it's possible for
  432. // the underlying SysAllocStringLen() to walk into invalid
  433. // memory while searching s.
  434. ssize_type actualLen = static_cast<ssize_type>(stlsoft_ns_qual(c_str_len)(s));
  435. if( NULL != s &&
  436. len > actualLen)
  437. {
  438. m_bstr = bstr_create(static_cast<cs_char_w_t const*>(NULL), static_cast<cs_size_t>(len));
  439. if(NULL != m_bstr)
  440. {
  441. #ifdef STLSOFT_USING_SAFE_STR_FUNCTIONS
  442. ::wcscpy_s(m_bstr, static_cast<cs_size_t>(actualLen), s);
  443. #else /* ? STLSOFT_USING_SAFE_STR_FUNCTIONS */
  444. ::wcscpy(m_bstr, s);
  445. #endif /* STLSOFT_USING_SAFE_STR_FUNCTIONS */
  446. }
  447. }
  448. else
  449. {
  450. if(-1 == len)
  451. {
  452. len = actualLen;
  453. }
  454. m_bstr = bstr_create(s, static_cast<cs_size_t>(len));
  455. }
  456. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  457. if( NULL == m_bstr &&
  458. NULL != s &&
  459. 0 != len &&
  460. '\0' != 0[s])
  461. {
  462. STLSOFT_THROW_X(com_exception("failed to allocate string", HRESULT_FROM_WIN32(::GetLastError())));
  463. }
  464. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  465. }
  466. inline bstr::bstr(bstr::size_type n, bstr::char_type ch)
  467. : m_bstr(bstr_create_w(NULL, n))
  468. {
  469. if(NULL == m_bstr)
  470. {
  471. if(0 != n)
  472. {
  473. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  474. STLSOFT_THROW_X(com_exception("failed to allocate string", HRESULT_FROM_WIN32(::GetLastError())));
  475. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  476. }
  477. }
  478. else
  479. {
  480. { for(size_type i = 0; i < n; ++i)
  481. {
  482. m_bstr[i] = ch;
  483. }}
  484. }
  485. }
  486. inline bstr::bstr(bstr::class_type const& rhs)
  487. : m_bstr(bstr_dup(rhs.m_bstr))
  488. {
  489. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  490. if( NULL == m_bstr &&
  491. !rhs.empty())
  492. {
  493. STLSOFT_THROW_X(com_exception("failed to allocate string", HRESULT_FROM_WIN32(::GetLastError())));
  494. }
  495. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  496. }
  497. inline bstr::bstr(bstr::class_type const& rhs, bstr::size_type pos, bstr::size_type len)
  498. : m_bstr(NULL)
  499. {
  500. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  501. if(pos > rhs.size())
  502. {
  503. STLSOFT_THROW_X(stlsoft_ns_qual_std(out_of_range)("Position out of range"));
  504. }
  505. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  506. COMSTL_MESSAGE_ASSERT("Position out of range", pos <= rhs.size());
  507. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  508. if(pos + len > rhs.size())
  509. {
  510. len = rhs.size() - pos;
  511. }
  512. m_bstr = bstr_create(rhs.data() + pos, len);
  513. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  514. if( NULL == m_bstr &&
  515. !rhs.empty())
  516. {
  517. STLSOFT_THROW_X(com_exception("failed to allocate string", HRESULT_FROM_WIN32(::GetLastError())));
  518. }
  519. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  520. }
  521. inline bstr::~bstr() stlsoft_throw_0()
  522. {
  523. ::SysFreeString(m_bstr);
  524. }
  525. inline bstr::class_type& bstr::operator =(bstr::class_type const& rhs)
  526. {
  527. class_type t(rhs);
  528. t.swap(*this);
  529. return *this;
  530. }
  531. inline bstr::class_type& bstr::assign(cs_char_a_t const* s, ssize_type len /* = -1 */)
  532. {
  533. class_type t(s, len);
  534. t.swap(*this);
  535. return *this;
  536. }
  537. inline bstr::class_type& bstr::assign(cs_char_w_t const* s, ssize_type len /* = -1 */)
  538. {
  539. class_type t(s, len);
  540. t.swap(*this);
  541. return *this;
  542. }
  543. inline bstr::class_type& bstr::assign(bstr::const_iterator from, bstr::const_iterator to)
  544. {
  545. return assign(from, to - from);
  546. }
  547. inline bstr::class_type& bstr::operator =(cs_char_a_t const* s)
  548. {
  549. return assign(s);
  550. }
  551. inline bstr::class_type& bstr::operator =(cs_char_w_t const* s)
  552. {
  553. return assign(s);
  554. }
  555. inline bstr::class_type& bstr::attach(BSTR bstr)
  556. {
  557. *DestructiveAddress() = bstr;
  558. return *this;
  559. }
  560. inline BSTR bstr::detach()
  561. {
  562. BSTR str = m_bstr;
  563. m_bstr = NULL;
  564. return str;
  565. }
  566. inline void bstr::clear()
  567. {
  568. ::SysFreeString(m_bstr);
  569. m_bstr = NULL;
  570. }
  571. inline bstr::class_type& bstr::append(bstr::class_type const& s, ssize_type len /* = -1 */)
  572. {
  573. return append(s.data(), len);
  574. }
  575. inline bstr::class_type& bstr::append(cs_char_w_t const* s, ssize_type len /* = -1 */)
  576. {
  577. if(empty())
  578. {
  579. bstr rhs(s, len);
  580. rhs.swap(*this);
  581. }
  582. else
  583. {
  584. if(len < 0)
  585. {
  586. len = (NULL == s) ? 0 : static_cast<ssize_type>(::wcslen(s));
  587. }
  588. if(0 != len)
  589. {
  590. size_type totalLen = size() + len;
  591. bstr rhs(data(), static_cast<ssize_type>(totalLen));
  592. #ifdef STLSOFT_USING_SAFE_STR_FUNCTIONS
  593. ::wcsncpy_s(&rhs[0] + size(), static_cast<cs_size_t>(totalLen), s, static_cast<cs_size_t>(len));
  594. #else /* ? STLSOFT_USING_SAFE_STR_FUNCTIONS */
  595. ::wcsncpy(&rhs[0] + size(), s, static_cast<cs_size_t>(len));
  596. #endif /* STLSOFT_USING_SAFE_STR_FUNCTIONS */
  597. rhs.swap(*this);
  598. }
  599. }
  600. return *this;
  601. }
  602. inline bstr::class_type& bstr::operator +=(bstr::class_type const& s)
  603. {
  604. return append(s);
  605. }
  606. inline bstr::class_type& bstr::operator +=(cs_char_w_t const* s)
  607. {
  608. return append(s);
  609. }
  610. // Operations
  611. // Accessors
  612. inline bstr::const_pointer bstr::data() const
  613. {
  614. return this->c_str();
  615. }
  616. inline bstr::const_pointer bstr::c_str() const
  617. {
  618. return (NULL == m_bstr) ? L"" : m_bstr;
  619. }
  620. inline bstr::size_type bstr::length() const
  621. {
  622. return static_cast<size_type>(::SysStringLen(m_bstr));
  623. }
  624. inline bstr::size_type bstr::size() const
  625. {
  626. return this->length();
  627. }
  628. inline bstr::bool_type bstr::empty() const
  629. {
  630. return 0 == this->size();
  631. }
  632. inline BSTR bstr::get() const
  633. {
  634. return m_bstr;
  635. }
  636. inline bstr::reference bstr::operator [](bstr::size_type index)
  637. {
  638. COMSTL_MESSAGE_ASSERT("invalid index", index < size());
  639. return index[m_bstr];
  640. }
  641. inline bstr::const_reference bstr::operator [](bstr::size_type index) const
  642. {
  643. COMSTL_MESSAGE_ASSERT("invalid index", index <= size());
  644. return index[data()];
  645. }
  646. inline bstr::const_pointer *bstr::NonDestructiveAddress() const
  647. {
  648. return const_cast<const_pointer*>(&m_bstr);
  649. }
  650. inline BSTR* bstr::NonDestructiveAddress()
  651. {
  652. return &m_bstr;
  653. }
  654. inline BSTR* bstr::DestructiveAddress()
  655. {
  656. clear();
  657. return &m_bstr;
  658. }
  659. inline bstr::iterator bstr::begin()
  660. {
  661. return get();
  662. }
  663. inline bstr::iterator bstr::end()
  664. {
  665. return get() + size();
  666. }
  667. inline bstr::const_iterator bstr::begin() const
  668. {
  669. return get();
  670. }
  671. inline bstr::const_iterator bstr::end() const
  672. {
  673. return get() + size();
  674. }
  675. #if defined(STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT)
  676. inline bstr::const_reverse_iterator bstr::rbegin() const
  677. {
  678. return const_reverse_iterator(end());
  679. }
  680. inline bstr::const_reverse_iterator bstr::rend() const
  681. {
  682. return const_reverse_iterator(begin());
  683. }
  684. inline bstr::reverse_iterator bstr::rbegin()
  685. {
  686. return reverse_iterator(end());
  687. }
  688. inline bstr::reverse_iterator bstr::rend()
  689. {
  690. return reverse_iterator(begin());
  691. }
  692. #endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  693. inline bstr::bool_type bstr::equal(bstr::class_type const& rhs) const
  694. {
  695. return 0 == bstr_compare(this->get(), rhs.get());
  696. }
  697. inline bstr::bool_type bstr::equal(BSTR const& rhs) const
  698. {
  699. return 0 == bstr_compare(this->get(), rhs);
  700. }
  701. // Operations
  702. inline void bstr::swap(bstr::class_type& rhs) stlsoft_throw_0()
  703. {
  704. std_swap(m_bstr, rhs.m_bstr);
  705. }
  706. inline void bstr::swap(BSTR& rhs) stlsoft_throw_0()
  707. {
  708. std_swap(m_bstr, rhs);
  709. }
  710. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  711. /* ////////////////////////////////////////////////////////////////////// */
  712. #ifndef _COMSTL_NO_NAMESPACE
  713. # if defined(_STLSOFT_NO_NAMESPACE) || \
  714. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  715. } // namespace comstl
  716. # else
  717. } // namespace stlsoft::comstl_project
  718. } // namespace stlsoft
  719. # endif /* _STLSOFT_NO_NAMESPACE */
  720. #endif /* !_COMSTL_NO_NAMESPACE */
  721. /* /////////////////////////////////////////////////////////////////////////
  722. * Namespace
  723. *
  724. * The string access shims exist either in the stlsoft namespace, or in the
  725. * global namespace. This is required by the lookup rules.
  726. *
  727. */
  728. #ifndef _COMSTL_NO_NAMESPACE
  729. # if !defined(_STLSOFT_NO_NAMESPACE) && \
  730. !defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  731. namespace stlsoft
  732. {
  733. # else /* ? _STLSOFT_NO_NAMESPACE */
  734. /* There is no stlsoft namespace, so must define in the global namespace */
  735. # endif /* !_STLSOFT_NO_NAMESPACE */
  736. using ::comstl::c_str_data;
  737. using ::comstl::c_str_data_w;
  738. using ::comstl::c_str_data_o;
  739. using ::comstl::c_str_len;
  740. using ::comstl::c_str_len_w;
  741. using ::comstl::c_str_len_o;
  742. using ::comstl::c_str_ptr;
  743. using ::comstl::c_str_ptr_w;
  744. using ::comstl::c_str_ptr_o;
  745. using ::comstl::c_str_ptr_null;
  746. using ::comstl::c_str_ptr_null_w;
  747. using ::comstl::c_str_ptr_null_o;
  748. /* /////////////////////////////////////////////////////////////////////////
  749. * Traits
  750. */
  751. /** Specialisation for comstl::bstr
  752. */
  753. STLSOFT_TEMPLATE_SPECIALISATION
  754. struct string_traits< ::comstl::bstr>
  755. {
  756. typedef ::comstl::bstr value_type;
  757. typedef ::comstl::bstr::value_type char_type; // NOTE: Can't use value_type::value_type here, because of BC++ 5.5.1
  758. typedef value_type::size_type size_type;
  759. typedef char_type const const_char_type;
  760. typedef value_type string_type;
  761. typedef string_type::pointer pointer;
  762. typedef string_type::const_pointer const_pointer;
  763. typedef string_type::iterator iterator;
  764. typedef string_type::const_iterator const_iterator;
  765. #if defined(STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT)
  766. typedef string_type::reverse_iterator reverse_iterator;
  767. typedef string_type::const_reverse_iterator const_reverse_iterator;
  768. #endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  769. enum
  770. {
  771. is_pointer = false
  772. , is_pointer_to_const = false
  773. , char_type_size = sizeof(char_type)
  774. };
  775. static string_type empty_string()
  776. {
  777. return string_type();
  778. }
  779. static string_type construct(string_type const& src, size_type pos, size_type len)
  780. {
  781. return string_type(src, pos, len);
  782. }
  783. # ifdef STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT
  784. template <ss_typename_param_k I>
  785. static string_type& assign_inplace(string_type& str, I first, I last)
  786. # else /* ? STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT */
  787. static string_type& assign_inplace(string_type& str, const_iterator first, const_iterator last)
  788. # endif /* STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT */
  789. {
  790. // comstl::bstr cannot assign in-place
  791. return (str = string_type(first, last - first), str);
  792. }
  793. };
  794. # if !defined(_STLSOFT_NO_NAMESPACE) && \
  795. !defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  796. } // namespace stlsoft
  797. # else /* ? _STLSOFT_NO_NAMESPACE */
  798. /* There is no stlsoft namespace, so must define in the global namespace */
  799. # endif /* !_STLSOFT_NO_NAMESPACE */
  800. #endif /* !_COMSTL_NO_NAMESPACE */
  801. /* ////////////////////////////////////////////////////////////////////// */
  802. #endif /* !COMSTL_INCL_COMSTL_STRING_HPP_BSTR */
  803. /* ///////////////////////////// end of file //////////////////////////// */