Leaked source code of windows server 2003
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.

1059 lines
21 KiB

  1. // Copyright (c) 1997-1999 Microsoft Corporation
  2. //
  3. // string class
  4. //
  5. // 8-14-97 sburns
  6. #include "headers.hxx"
  7. String::String(PCSTR lpsz)
  8. :
  9. base()
  10. {
  11. // ISSUE-2002/03/06-sburns consider strsafe function
  12. size_t len = lpsz ? static_cast<size_t>(lstrlenA(lpsz)) : 0;
  13. if (len)
  14. {
  15. assignFromAnsi(lpsz, len);
  16. }
  17. }
  18. String::String(const AnsiString& s)
  19. :
  20. base()
  21. {
  22. size_t len = s.length();
  23. if (len)
  24. {
  25. assignFromAnsi(s.data(), len);
  26. }
  27. }
  28. void
  29. String::assignFromAnsi(PCSTR lpsz, size_t len)
  30. {
  31. ASSERT(lpsz);
  32. ASSERT(len);
  33. // add 1 to allow for trailing null
  34. wchar_t* buf = new wchar_t[len + 1];
  35. // REVIEWED-2002/03/06-sburns correct byte count passed
  36. ::ZeroMemory(buf, (len + 1) * sizeof wchar_t);
  37. size_t result =
  38. static_cast<size_t>(
  39. // REVIEWED-2002/03/06-sburns correct byte/char counts
  40. ::MultiByteToWideChar(
  41. CP_ACP,
  42. 0,
  43. lpsz,
  44. // len bytes in the source ansi string (not incl trailing null)
  45. static_cast<int>(len),
  46. buf,
  47. // len characters in the result wide string (not incl trailing
  48. // null)
  49. static_cast<int>(len)));
  50. if (result)
  51. {
  52. ASSERT(result <= len);
  53. assign(buf);
  54. }
  55. delete[] buf;
  56. }
  57. HRESULT
  58. String::as_OLESTR(LPOLESTR& oleString) const
  59. {
  60. size_t len = length();
  61. oleString =
  62. reinterpret_cast<LPOLESTR>(
  63. ::CoTaskMemAlloc((len + 1) * sizeof(wchar_t)));
  64. if (oleString)
  65. {
  66. copy(oleString, len);
  67. oleString[len] = 0;
  68. return S_OK;
  69. }
  70. return E_OUTOFMEMORY;
  71. }
  72. String
  73. String::load(unsigned resID, HINSTANCE hInstance)
  74. {
  75. if (!hInstance)
  76. {
  77. hInstance = GetResourceModuleHandle();
  78. }
  79. #ifdef DBG
  80. // pick a silly small buffer size to make sure our resize logic gets
  81. // exercised.
  82. static const int TEMP_LEN = 7;
  83. #else
  84. static const int TEMP_LEN = 512;
  85. #endif
  86. wchar_t temp[TEMP_LEN];
  87. // ISSUE-2002/02/25-sburns why is tempLen needed? just use TEMP_LEN?
  88. int tempLen = TEMP_LEN;
  89. // REVIEWED-2002/03/06-sburns correct character count passed
  90. int len = ::LoadString(hInstance, resID, temp, tempLen);
  91. // we expect that if the caller is loading a string, the string is non-
  92. // empty. An empty string probably indicates something is broken in the
  93. // caller's program. It is legal, but silly, to put empty strings in a
  94. // resource table.
  95. ASSERT(len);
  96. if (len == 0)
  97. {
  98. return String();
  99. }
  100. if (tempLen - len > 1)
  101. {
  102. // the string fit into the temp buffer with at least 1 character to
  103. // spare. If the load failed, len == 0, and we return the empty
  104. // string.
  105. return String(temp);
  106. }
  107. // the string did not fit. Try larger buffer sizes until the string does
  108. // fit with at least 1 character to spare
  109. int newLen = tempLen;
  110. wchar_t* newTemp = 0;
  111. do
  112. {
  113. delete[] newTemp;
  114. newLen += TEMP_LEN;
  115. newTemp = new wchar_t[static_cast<size_t>(newLen)];
  116. // REVIEWED-2002/03/06-sburns correct character count passed
  117. len = ::LoadString(hInstance, resID, newTemp, newLen);
  118. }
  119. // ISSUE-2002/02/25-sburns growth is unbounded here...
  120. while (newLen - len <= 1); // repeat until at least 1 char to spare
  121. String r(newTemp);
  122. delete[] newTemp;
  123. return r;
  124. }
  125. String&
  126. String::replace(const String& from, const String& to)
  127. {
  128. if (from.empty())
  129. {
  130. return *this;
  131. }
  132. _copy();
  133. String::size_type i = 0;
  134. String::size_type fl = from.length();
  135. String::size_type tl = to.length();
  136. String::size_type len = length();
  137. const wchar_t* td = to.data();
  138. do
  139. {
  140. i = find(from, i);
  141. if (i == String::npos)
  142. {
  143. return *this;
  144. }
  145. base::replace(i, fl, td, tl);
  146. i += tl;
  147. }
  148. while (i <= len);
  149. return *this;
  150. }
  151. String&
  152. String::replace_each_of(const String& from, const String& to)
  153. {
  154. if (from.empty())
  155. {
  156. return *this;
  157. }
  158. _copy();
  159. String::size_type i = 0;
  160. String::size_type fl = from.length();
  161. String::size_type tl = to.length();
  162. String::size_type len = length();
  163. const wchar_t* td = to.data();
  164. do
  165. {
  166. i = find_first_of(from, i);
  167. if (i == String::npos)
  168. {
  169. return *this;
  170. }
  171. base::replace(i, 1, td, tl);
  172. i += tl;
  173. }
  174. while (i <= len);
  175. return *this;
  176. }
  177. String&
  178. String::strip(StripType type, wchar_t charToStrip)
  179. {
  180. String::size_type start = 0;
  181. String::size_type stop = length();
  182. const wchar_t* p = data();
  183. if (type & LEADING)
  184. {
  185. while (start < stop && p[start] == charToStrip)
  186. {
  187. ++start;
  188. }
  189. }
  190. if (type & TRAILING)
  191. {
  192. while (start < stop && p[stop - 1] == charToStrip)
  193. {
  194. --stop;
  195. }
  196. }
  197. if (stop == start)
  198. {
  199. assign(String());
  200. }
  201. else
  202. {
  203. // this goofiness due to a bug in basic_string where you can't assign
  204. // a piece of yourself, because you delete yourself before you copy!
  205. // assign(p + start, stop - start);
  206. String s(p + start, stop - start);
  207. assign(s);
  208. }
  209. return *this;
  210. }
  211. String&
  212. String::to_lower()
  213. {
  214. if (length())
  215. {
  216. _copy();
  217. // ISSUE-2002/03/06-sburns consider strsafe function
  218. _wcslwr(const_cast<wchar_t*>(c_str()));
  219. }
  220. return *this;
  221. }
  222. String&
  223. String::to_upper()
  224. {
  225. if (length())
  226. {
  227. _copy();
  228. // ISSUE-2002/03/06-sburns consider strsafe function
  229. _wcsupr(const_cast<wchar_t*>(c_str()));
  230. }
  231. return *this;
  232. }
  233. void
  234. String::_copy()
  235. {
  236. size_type len = length();
  237. if (len)
  238. {
  239. value_type* buf = new value_type[len + 1];
  240. copy(buf, len);
  241. buf[len] = 0;
  242. assign(buf);
  243. delete[] buf;
  244. }
  245. }
  246. //
  247. // static functions
  248. //
  249. #if defined(ALPHA) || defined(IA64)
  250. String __cdecl
  251. String::format(
  252. const String& qqfmt,
  253. ...)
  254. #else
  255. // the x86 compiler won't allow the first parameter to be a reference
  256. // type. This is a compiler bug.
  257. String __cdecl
  258. String::format(
  259. const String qqfmt,
  260. ...)
  261. #endif
  262. {
  263. // ISSUE-2002/03/06-sburns should assert that qqfmt is not empty (I'd
  264. // just add it now, but I'm not entirely confident it wouldn't hose the
  265. // varargs
  266. // ASSERT(!qqfmt.empty());
  267. String result;
  268. va_list argList;
  269. va_start(argList, qqfmt);
  270. PTSTR temp = 0;
  271. PCTSTR f = qqfmt.c_str();
  272. if (
  273. // REVIEWED-2002/03/06-sburns no char/byte or buffer size issues: we ask
  274. // the API to allocate for us.
  275. // REVIEWED-2002/03/29-sburns no unbounded allocation error here.
  276. // If I pass nSize = 0 and FORMAT_MESSAGE_ALLOCATE_BUFFER in dwFlags,
  277. // the max result size is 32K - 1 characters. Looking at the code in
  278. // message.c, it looks like the reserve space is whatever the user asked
  279. // as a maximum rounded up to the nearest 64K. That makes sense given my
  280. // test, since 32K chars = 64K bytes. Experimentally, even if I ask for
  281. // a max buffer size > 0x87FFF chars, it looks like the most I can get
  282. // is 0x87FFE chars.
  283. ::FormatMessage(
  284. FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  285. f,
  286. 0,
  287. 0,
  288. reinterpret_cast<PTSTR>(&temp),
  289. 0,
  290. &argList))
  291. {
  292. result = temp;
  293. ::LocalFree(temp);
  294. }
  295. va_end(argList);
  296. return result;
  297. }
  298. String __cdecl
  299. String::format(
  300. const wchar_t* qqfmt,
  301. ...)
  302. {
  303. ASSERT(qqfmt);
  304. String result;
  305. va_list argList;
  306. va_start(argList, qqfmt);
  307. PTSTR temp = 0;
  308. if (
  309. // REVIEWED-2002/03/06-sburns no char/byte or buffer size issues: we ask
  310. // the API to allocate for us.
  311. ::FormatMessage(
  312. FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  313. qqfmt,
  314. 0,
  315. 0,
  316. reinterpret_cast<PTSTR>(&temp),
  317. 0,
  318. &argList))
  319. {
  320. result = temp;
  321. ::LocalFree(temp);
  322. }
  323. va_end(argList);
  324. return result;
  325. }
  326. String __cdecl
  327. String::format(unsigned formatResID, ...)
  328. {
  329. String fmt = String::load(formatResID);
  330. String result;
  331. va_list argList;
  332. va_start(argList, formatResID);
  333. PTSTR temp = 0;
  334. if (
  335. // REVIEWED-2002/03/06-sburns no char/byte or buffer size issues: we ask
  336. // the API to allocate for us.
  337. // REVIEWED-2002/03/29-sburns no unbounded allocation error here.
  338. // If I pass nSize = 0 and FORMAT_MESSAGE_ALLOCATE_BUFFER in dwFlags,
  339. // the max result size is 32K - 1 characters. Looking at the code in
  340. // message.c, it looks like the reserve space is whatever the user asked
  341. // as a maximum rounded up to the nearest 64K. That makes sense given my
  342. // test, since 32K chars = 64K bytes. Experimentally, even if I ask for
  343. // a max buffer size > 0x87FFF chars, it looks like the most I can get
  344. // is 0x87FFE chars.
  345. ::FormatMessage(
  346. FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  347. fmt.c_str(),
  348. 0,
  349. 0,
  350. reinterpret_cast<PTSTR>(&temp),
  351. 0,
  352. &argList))
  353. {
  354. result = temp;
  355. ::LocalFree(temp);
  356. }
  357. va_end(argList);
  358. return result;
  359. }
  360. String __cdecl
  361. String::format(int formatResID, ...)
  362. {
  363. String fmt = String::load(formatResID);
  364. va_list argList;
  365. va_start(argList, formatResID);
  366. PTSTR temp = 0;
  367. if (
  368. // REVIEWED-2002/03/06-sburns no char/byte or buffer size issues: we ask
  369. // the API to allocate for us.
  370. // REVIEWED-2002/03/29-sburns no unbounded allocation error here.
  371. // If I pass nSize = 0 and FORMAT_MESSAGE_ALLOCATE_BUFFER in dwFlags,
  372. // the max result size is 32K - 1 characters. Looking at the code in
  373. // message.c, it looks like the reserve space is whatever the user asked
  374. // as a maximum rounded up to the nearest 64K. That makes sense given my
  375. // test, since 32K chars = 64K bytes. Experimentally, even if I ask for
  376. // a max buffer size > 0x87FFF chars, it looks like the most I can get
  377. // is 0x87FFE chars.
  378. ::FormatMessage(
  379. FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  380. fmt.c_str(),
  381. 0,
  382. 0,
  383. reinterpret_cast<PTSTR>(&temp),
  384. 0,
  385. &argList))
  386. {
  387. String retval(temp);
  388. ::LocalFree(temp);
  389. va_end(argList);
  390. return retval;
  391. }
  392. va_end(argList);
  393. return String();
  394. }
  395. int
  396. String::icompare(const String& str) const
  397. {
  398. int i =
  399. ::CompareString(
  400. LOCALE_USER_DEFAULT,
  401. NORM_IGNORECASE
  402. // these flags necessary for Japanese strings
  403. | NORM_IGNOREKANATYPE
  404. | NORM_IGNOREWIDTH,
  405. c_str(),
  406. static_cast<int>(length()),
  407. str.c_str(),
  408. static_cast<int>(str.length()));
  409. if (i)
  410. {
  411. // convert to < 0, == 0, > 0 C runtime convention
  412. return i - 2;
  413. }
  414. // this will be wrong, but what option do we have?
  415. return i;
  416. }
  417. HRESULT
  418. WideCharToMultiByteHelper(
  419. UINT codePage,
  420. DWORD flags,
  421. const String& str,
  422. char* buffer,
  423. size_t bufferSizeInBytes,
  424. size_t& result)
  425. {
  426. ASSERT(!str.empty());
  427. result = 0;
  428. HRESULT hr = S_OK;
  429. int r =
  430. // REVIEWED-2002/03/06-sburns correct character/byte counts passed.
  431. ::WideCharToMultiByte(
  432. codePage,
  433. flags,
  434. str.c_str(),
  435. // the character count count
  436. static_cast<int>(str.length()),
  437. buffer,
  438. // the buffer size in bytes
  439. static_cast<int>(bufferSizeInBytes),
  440. 0,
  441. 0);
  442. if (!r)
  443. {
  444. hr = Win32ToHresult(::GetLastError());
  445. }
  446. ASSERT(SUCCEEDED(hr));
  447. result = static_cast<size_t>(r);
  448. return hr;
  449. }
  450. String::ConvertResult
  451. String::convert(AnsiString& ansi, UINT codePage) const
  452. {
  453. ansi.erase();
  454. ConvertResult result = CONVERT_FAILED;
  455. do
  456. {
  457. if (empty())
  458. {
  459. // nothing else to do.
  460. result = CONVERT_SUCCESSFUL;
  461. break;
  462. }
  463. // determine the size of the buffer required to hold the ANSI string
  464. const wchar_t* wide = c_str();
  465. size_t bufferSizeInBytes = 0;
  466. HRESULT hr =
  467. ::WideCharToMultiByteHelper(
  468. codePage,
  469. 0,
  470. wide,
  471. 0,
  472. 0,
  473. // REVIEWED-2002/03/06-sburns correct byte count passed.
  474. bufferSizeInBytes);
  475. BREAK_ON_FAILED_HRESULT(hr);
  476. if (bufferSizeInBytes > 0)
  477. {
  478. // +1 for extra null-termination paranoia
  479. AnsiString a(bufferSizeInBytes + 1, 0);
  480. char* p = const_cast<char*>(a.c_str());
  481. size_t r = 0;
  482. hr =
  483. ::WideCharToMultiByteHelper(
  484. codePage,
  485. 0,
  486. wide,
  487. p,
  488. // REVIEWED-2002/03/06-sburns correct byte count passed.
  489. bufferSizeInBytes,
  490. r);
  491. BREAK_ON_FAILED_HRESULT(hr);
  492. ansi = a;
  493. result = CONVERT_SUCCESSFUL;
  494. }
  495. }
  496. while (0);
  497. return result;
  498. }
  499. template<class UnsignedType>
  500. class UnsignedConvertHelper
  501. {
  502. public:
  503. // at first glance, one might think that this is a job for a template
  504. // member function. That's what I thought. Unfortunately, the combination
  505. // of freely convertible integer types and the binding rules for resolving
  506. // function templates results in ambiguity. Using a static class method,
  507. // though, allows the caller to specify the template parameter types, and
  508. // avoid the abiguity.
  509. static
  510. String::ConvertResult
  511. doit(const String& s, UnsignedType& u, int radix, UnsignedType maxval)
  512. {
  513. // call the long version, then truncate as appropriate
  514. unsigned long ul = 0;
  515. u = 0;
  516. String::ConvertResult result = s.convert(ul, radix);
  517. if (result == String::CONVERT_SUCCESSFUL)
  518. {
  519. if (ul <= maxval)
  520. {
  521. // ul will fit into an unsigned int.
  522. u = static_cast<UnsignedType>(ul);
  523. }
  524. else
  525. {
  526. result = String::CONVERT_OVERFLOW;
  527. }
  528. }
  529. return result;
  530. }
  531. };
  532. template<class IntType>
  533. class IntegerConvertHelper
  534. {
  535. public:
  536. static
  537. String::ConvertResult
  538. doit(const String& s, IntType& u, int radix, IntType minval, IntType maxval)
  539. {
  540. long l = 0;
  541. u = 0;
  542. String::ConvertResult result = s.convert(l, radix);
  543. if (result == String::CONVERT_SUCCESSFUL)
  544. {
  545. if (l <= maxval)
  546. {
  547. if (l >= minval)
  548. {
  549. // l will fit into an IntType.
  550. u = static_cast<IntType>(l);
  551. }
  552. else
  553. {
  554. result = String::CONVERT_UNDERFLOW;
  555. }
  556. }
  557. else
  558. {
  559. result = String::CONVERT_OVERFLOW;
  560. }
  561. }
  562. return result;
  563. }
  564. };
  565. String::ConvertResult
  566. String::convert(short& s, int radix) const
  567. {
  568. return
  569. IntegerConvertHelper<short>::doit(*this, s, radix, SHRT_MIN, SHRT_MAX);
  570. }
  571. String::ConvertResult
  572. String::convert(int& i, int radix) const
  573. {
  574. return
  575. IntegerConvertHelper<int>::doit(*this, i, radix, INT_MIN, INT_MAX);
  576. }
  577. String::ConvertResult
  578. String::convert(unsigned short& us, int radix) const
  579. {
  580. return
  581. UnsignedConvertHelper<unsigned short>::doit(
  582. *this,
  583. us,
  584. radix,
  585. USHRT_MAX);
  586. }
  587. String::ConvertResult
  588. String::convert(unsigned& ui, int radix) const
  589. {
  590. return
  591. UnsignedConvertHelper<unsigned int>::doit(
  592. *this,
  593. ui,
  594. radix,
  595. UINT_MAX);
  596. }
  597. String::ConvertResult
  598. String::convert(long& l, int radix) const
  599. {
  600. l = 0;
  601. if (radix != 0 && (radix < 2 || radix > 36))
  602. {
  603. ASSERT(false);
  604. return CONVERT_BAD_RADIX;
  605. }
  606. String::const_pointer begptr = c_str();
  607. String::pointer endptr = 0;
  608. errno = 0;
  609. long result = wcstol(begptr, &endptr, radix);
  610. if (errno == ERANGE)
  611. {
  612. return result == LONG_MAX ? CONVERT_OVERFLOW : CONVERT_UNDERFLOW;
  613. }
  614. if (begptr == endptr)
  615. {
  616. // no valid characters found
  617. return CONVERT_BAD_INPUT;
  618. }
  619. if (endptr)
  620. {
  621. if (*endptr != 0)
  622. {
  623. // the conversion stopped before the null terminator => bad
  624. // characters in input
  625. return CONVERT_BAD_INPUT;
  626. }
  627. }
  628. else
  629. {
  630. // I doubt this is reachable
  631. return CONVERT_FAILED;
  632. }
  633. l = result;
  634. return CONVERT_SUCCESSFUL;
  635. }
  636. String::ConvertResult
  637. String::convert(unsigned long& ul, int radix) const
  638. {
  639. ul = 0;
  640. if (radix != 0 && (radix < 2 || radix > 36))
  641. {
  642. ASSERT(false);
  643. return CONVERT_BAD_RADIX;
  644. }
  645. String::const_pointer begptr = c_str();
  646. String::pointer endptr = 0;
  647. errno = 0;
  648. unsigned long result = wcstoul(begptr, &endptr, radix);
  649. if (errno == ERANGE)
  650. {
  651. // overflow is the only possible range error for an unsigned type.
  652. return CONVERT_OVERFLOW;
  653. }
  654. if (begptr == endptr)
  655. {
  656. // no valid characters found
  657. return CONVERT_BAD_INPUT;
  658. }
  659. if (endptr)
  660. {
  661. if (*endptr != 0)
  662. {
  663. // the conversion stopped before the null terminator => bad
  664. // characters in input
  665. return CONVERT_BAD_INPUT;
  666. }
  667. }
  668. else
  669. {
  670. // I doubt this is reachable
  671. return CONVERT_FAILED;
  672. }
  673. ul = result;
  674. return CONVERT_SUCCESSFUL;
  675. }
  676. String::ConvertResult
  677. String::convert(double& d) const
  678. {
  679. d = 0.0;
  680. String::const_pointer begptr = c_str();
  681. String::pointer endptr = 0;
  682. errno = 0;
  683. double result = wcstod(begptr, &endptr);
  684. if (errno == ERANGE)
  685. {
  686. // result is +/-HUGE_VAL on overflow, 0 on underflow.
  687. return result ? CONVERT_OVERFLOW : CONVERT_UNDERFLOW;
  688. }
  689. if (begptr == endptr)
  690. {
  691. // no valid characters found
  692. return CONVERT_BAD_INPUT;
  693. }
  694. if (endptr)
  695. {
  696. if (*endptr != 0)
  697. {
  698. // the conversion stopped before the null terminator => bad
  699. // characters in input
  700. return CONVERT_BAD_INPUT;
  701. }
  702. }
  703. else
  704. {
  705. // I doubt this is reachable
  706. return CONVERT_FAILED;
  707. }
  708. d = result;
  709. return CONVERT_SUCCESSFUL;
  710. }
  711. /* This was commented out because it is no longer in use. If
  712. it is to be used it must be fixed to work with non Arabic
  713. digits
  714. #define MAX_DECIMAL_STRING_LENGTH_FOR_LARGE_INTEGER 20
  715. String::ConvertResult
  716. String::convert(LARGE_INTEGER& li) const
  717. {
  718. li.QuadPart = 0;
  719. if (size() > MAX_DECIMAL_STRING_LENGTH_FOR_LARGE_INTEGER)
  720. {
  721. // string is too long
  722. return CONVERT_OVERFLOW;
  723. }
  724. String::const_pointer begptr = c_str();
  725. String::const_pointer endptr = begptr;
  726. errno = 0;
  727. BOOL bNeg = FALSE;
  728. if (*endptr == L'-')
  729. {
  730. bNeg = TRUE;
  731. endptr++;
  732. }
  733. while (*endptr != L'\0')
  734. {
  735. if (!iswctype(*endptr,_DIGIT))
  736. {
  737. return CONVERT_BAD_INPUT;
  738. }
  739. li.QuadPart = 10 * li.QuadPart + (*endptr-L'0');
  740. endptr++;
  741. }
  742. if (bNeg)
  743. {
  744. li.QuadPart *= -1;
  745. }
  746. if (begptr == endptr)
  747. {
  748. // no valid characters found
  749. li.QuadPart = 0;
  750. return CONVERT_BAD_INPUT;
  751. }
  752. if (endptr)
  753. {
  754. if (*endptr != 0)
  755. {
  756. // the conversion stopped before the null terminator => bad
  757. // characters in input
  758. li.QuadPart = 0;
  759. return CONVERT_BAD_INPUT;
  760. }
  761. }
  762. else
  763. {
  764. // I doubt this is reachable
  765. li.QuadPart = 0;
  766. return CONVERT_FAILED;
  767. }
  768. return CONVERT_SUCCESSFUL;
  769. }
  770. */
  771. bool
  772. String::is_numeric() const
  773. {
  774. if (empty())
  775. {
  776. return false;
  777. }
  778. size_t len = length();
  779. WORD* charTypeInfo = new WORD[len];
  780. // REVIEWED-2002/03/06-sburns correct byte count passed
  781. ::ZeroMemory(charTypeInfo, len * sizeof WORD);
  782. bool result = false;
  783. do
  784. {
  785. BOOL success =
  786. ::GetStringTypeEx(
  787. LOCALE_USER_DEFAULT,
  788. CT_CTYPE1,
  789. c_str(),
  790. static_cast<int>(length()),
  791. charTypeInfo);
  792. ASSERT(success);
  793. if (!success)
  794. {
  795. break;
  796. }
  797. // look thru the type info array, ensure that all chars are digits.
  798. bool nonDigitFound = false;
  799. for (size_t i = 0; i < len; ++i)
  800. {
  801. // We only consider decimal digits, not C2_EUROPENUMBER and
  802. // C2_ARABICNUMBER. I wonder if that is correct?
  803. if (!(charTypeInfo[i] & C1_DIGIT))
  804. {
  805. nonDigitFound = true;
  806. break;
  807. }
  808. }
  809. // a string is numeric if no non-digit characters are found.
  810. result = !nonDigitFound;
  811. }
  812. while (0);
  813. delete[] charTypeInfo;
  814. charTypeInfo = 0;
  815. return result;
  816. }