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.

1562 lines
32 KiB

  1. /*++
  2. Copyright (c) 1992-2000 Microsoft Corporation
  3. Module Name:
  4. wstring.cxx
  5. --*/
  6. #include <pch.cxx>
  7. #define _NTAPI_ULIB_
  8. #define _ULIB_MEMBER_
  9. #include "ulib.hxx"
  10. #include "wstring.hxx"
  11. #if !defined( _EFICHECK_ )
  12. #include <stdio.h>
  13. #include <wchar.h>
  14. #endif
  15. BOOLEAN WSTRING::_UseAnsiConversions = FALSE;
  16. BOOLEAN WSTRING::_UseConsoleConversions = FALSE;
  17. #if defined FE_SB
  18. BOOLEAN WSTRING::_UseAnsiConversionsPrev = FALSE;
  19. BOOLEAN WSTRING::_UseConsoleConversionsPrev = FALSE;
  20. #endif
  21. // Helper functions for OEM/Unicode conversion. Note that these
  22. // are abstracted to private functions to make it easier to set
  23. // them up for various environments.
  24. //
  25. INLINE
  26. BOOLEAN
  27. WSTRING::ConvertOemToUnicodeN(
  28. PWSTR UnicodeString,
  29. ULONG MaxBytesInUnicodeString,
  30. PULONG BytesInUnicodeString,
  31. PCHAR OemString,
  32. ULONG BytesInOemString
  33. )
  34. {
  35. UINT32 i;
  36. // BUGBUG this is a big hack.
  37. if( MaxBytesInUnicodeString == 0 ) {
  38. *BytesInUnicodeString = 2*BytesInOemString;
  39. return TRUE;
  40. }
  41. if( MaxBytesInUnicodeString < 2*BytesInOemString ) {
  42. *BytesInUnicodeString = 2*BytesInOemString;
  43. return FALSE;
  44. }
  45. memset(UnicodeString,0,MaxBytesInUnicodeString);
  46. for (i=0; i<BytesInOemString;i++) {
  47. UnicodeString[i] = (WCHAR)(OemString[i]);
  48. }
  49. *BytesInUnicodeString = BytesInOemString*2;
  50. return TRUE;
  51. }
  52. INLINE
  53. BOOLEAN
  54. WSTRING::ConvertUnicodeToOemN(
  55. PCHAR OemString,
  56. ULONG MaxBytesInOemString,
  57. PULONG BytesInOemString,
  58. PWSTR UnicodeString,
  59. ULONG BytesInUnicodeString
  60. )
  61. {
  62. INT32 len = (INT32)StrLen(UnicodeString);
  63. INT32 i;
  64. UCHAR a;
  65. // BUGBUG this is a big hack. I just discard any non-ANSI unicode character.
  66. if( MaxBytesInOemString == 0 ) {
  67. *BytesInOemString = len;
  68. return TRUE;
  69. }
  70. if( MaxBytesInOemString < (ULONG)len ) {
  71. *BytesInOemString = len;
  72. return FALSE;
  73. }
  74. for( i=0; i<len; i++ ) {
  75. if( HIBYTE(UnicodeString[i] != 0 )){
  76. a = '?';
  77. } else {
  78. a = LOBYTE(UnicodeString[i]);
  79. }
  80. OemString[i] = a;
  81. }
  82. *BytesInOemString = len;
  83. return TRUE;
  84. }
  85. INLINE
  86. VOID
  87. WSTRING::Construct(
  88. )
  89. {
  90. _s = NULL;
  91. _l = 0;
  92. }
  93. DEFINE_CONSTRUCTOR( WSTRING, OBJECT );
  94. BOOLEAN
  95. WSTRING::Initialize(
  96. IN PCWSTRING InitialString,
  97. IN CHNUM Position,
  98. IN CHNUM Length
  99. )
  100. /*++
  101. Routine Description:
  102. This routine initializes the current string by copying the contents
  103. of the given string.
  104. Arguments:
  105. InitialString - Supplies the initial string.
  106. Position - Supplies the position in the given string to start at.
  107. Length - Supplies the length of the string.
  108. Return Value:
  109. FALSE - Failure.
  110. TRUE - Success.
  111. --*/
  112. {
  113. DebugAssert(Position <= InitialString->_l);
  114. Length = min(Length, InitialString->_l - Position);
  115. if (!NewBuf(Length)) {
  116. return FALSE;
  117. }
  118. memcpy(_s, InitialString->_s + Position, (UINT) Length*sizeof(WCHAR));
  119. return TRUE;
  120. }
  121. BOOLEAN
  122. WSTRING::Initialize(
  123. IN PCWSTR InitialString,
  124. IN CHNUM StringLength
  125. )
  126. /*++
  127. Routine Description:
  128. This routine initializes the current string by copying the contents
  129. of the given string.
  130. Arguments:
  131. InitialString - Supplies the initial string.
  132. Return Value:
  133. FALSE - Failure.
  134. TRUE - Success.
  135. --*/
  136. {
  137. if (StringLength == TO_END) {
  138. StringLength = wcslen(InitialString);
  139. }
  140. if (!NewBuf(StringLength)) {
  141. return FALSE;
  142. }
  143. memcpy(_s, InitialString, (UINT) StringLength*sizeof(WCHAR));
  144. return TRUE;
  145. }
  146. BOOLEAN
  147. WSTRING::Initialize(
  148. IN PCSTR InitialString,
  149. IN CHNUM StringLength
  150. )
  151. /*++
  152. Routine Description:
  153. This routine initializes the current string by copying the contents
  154. of the given string.
  155. Arguments:
  156. InitialString - Supplies the initial string.
  157. Return Value:
  158. FALSE - Failure.
  159. TRUE - Success.
  160. --*/
  161. {
  162. CHNUM length=0;
  163. BOOLEAN status;
  164. if (StringLength == TO_END) {
  165. StringLength = strlen(InitialString);
  166. }
  167. if (!StringLength) {
  168. return Resize(0);
  169. }
  170. // We want to avoid making two calls to RtlOemToUnicodeN so
  171. // try to guess an adequate size for the buffer.
  172. if (!NewBuf(StringLength)) {
  173. return FALSE;
  174. }
  175. status = ConvertOemToUnicodeN(_s, _l*sizeof(WCHAR),
  176. &length, (PSTR) InitialString,
  177. StringLength);
  178. length /= sizeof(WCHAR);
  179. if (status) {
  180. return Resize(length);
  181. }
  182. // We didn't manage to make in one try so ask exactly how much
  183. // we need and then make the call.
  184. status = ConvertOemToUnicodeN(NULL, 0, &length, (PSTR) InitialString,
  185. StringLength);
  186. length /= sizeof(WCHAR);
  187. if (!status || !NewBuf(length)) {
  188. return FALSE;
  189. }
  190. status = ConvertOemToUnicodeN(_s, _l*sizeof(WCHAR),
  191. &length, (PSTR) InitialString, StringLength);
  192. if (!status) {
  193. return FALSE;
  194. }
  195. DebugAssert(length == _l*sizeof(WCHAR));
  196. return TRUE;
  197. }
  198. BOOLEAN
  199. WSTRING::Initialize(
  200. IN LONG Number
  201. )
  202. /*++
  203. Routine Description:
  204. This routine initializes the current string by copying the contents
  205. of the given string.
  206. Arguments:
  207. Number - Supplies the number to initialize the string to.
  208. Return Value:
  209. FALSE - Failure.
  210. TRUE - Success.
  211. --*/
  212. {
  213. WCHAR tmp[64];
  214. SPrint(tmp, 64, TEXT("%d"), Number);
  215. return Initialize(tmp);
  216. }
  217. NONVIRTUAL
  218. PWSTRING
  219. WSTRING::QueryString(
  220. IN CHNUM Position,
  221. IN CHNUM Length
  222. ) CONST
  223. /*++
  224. Routine Description:
  225. This routine returns a copy of this string from the specified
  226. coordinates.
  227. Arguments:
  228. Position - Supplies the initialize position of the string.
  229. Length - Supplies the length of the string.
  230. Return Value:
  231. A pointer to a string or NULL.
  232. --*/
  233. {
  234. PWSTRING p;
  235. if (!(p = NEW DSTRING) ||
  236. !p->Initialize(this, Position, Length)) {
  237. DELETE(p);
  238. }
  239. return p;
  240. }
  241. BOOLEAN
  242. WSTRING::QueryNumber(
  243. OUT PLONG Number,
  244. IN CHNUM Position,
  245. IN CHNUM Length
  246. ) CONST
  247. /*++
  248. Routine Description:
  249. This routine queries a number from the string.
  250. Arguments:
  251. Number - Returns the number parsed out of the string.
  252. Position - Supplies the position of the number.
  253. Length - Supplies the length of the number.
  254. Return Value:
  255. FALSE - Failure.
  256. TRUE - Success.
  257. --*/
  258. {
  259. FSTRING String;
  260. PSTR p;
  261. CHNUM spn;
  262. if (Position >= _l) {
  263. return FALSE;
  264. }
  265. Length = min(Length, _l - Position);
  266. //
  267. // Note that 123+123 will be a number!
  268. //
  269. String.Initialize((PWSTR) L"1234567890+-");
  270. spn = Strspn(&String, Position);
  271. if ((spn == INVALID_CHNUM || spn >= Position + Length) &&
  272. (p = QuerySTR(Position, Length))) {
  273. *Number = atol(p);
  274. DELETE(p);
  275. return TRUE;
  276. }
  277. return FALSE;
  278. }
  279. VOID
  280. WSTRING::DeleteChAt(
  281. IN CHNUM Position,
  282. IN CHNUM Length
  283. )
  284. /*++
  285. Routine Description:
  286. This routine removes the character at the given position.
  287. Arguments:
  288. Position - Supplies the position of the character to remove.
  289. Length - Supplies the number of characters to remove.
  290. Return Value:
  291. FALSE - Failure.
  292. TRUE - Success.
  293. --*/
  294. {
  295. DebugAssert(Position <= _l);
  296. Length = min(Length, _l - Position);
  297. memmove(_s + Position, _s + Position + Length,
  298. (UINT) (_l - Position - Length)*sizeof(WCHAR));
  299. Resize(_l - Length);
  300. }
  301. NONVIRTUAL
  302. BOOLEAN
  303. WSTRING::InsertString(
  304. IN CHNUM AtPosition,
  305. IN PCWSTRING String,
  306. IN CHNUM FromPosition,
  307. IN CHNUM FromLength
  308. )
  309. /*++
  310. Routine Description:
  311. This routine inserts the given string at the given position in
  312. this string.
  313. Arguments:
  314. AtPosition - Supplies the position at which to insert the string.
  315. String - Supplies the string to insert.
  316. Return Value:
  317. FALSE - Failure.
  318. TRUE - Success.
  319. --*/
  320. {
  321. CHNUM old_length;
  322. DebugAssert(AtPosition <= _l);
  323. DebugAssert(FromPosition <= String->_l);
  324. FromLength = min(FromLength, String->_l - FromPosition);
  325. old_length = _l;
  326. if (!Resize(_l + FromLength)) {
  327. return FALSE;
  328. }
  329. memmove(_s + AtPosition + FromLength, _s + AtPosition,
  330. (UINT) (old_length - AtPosition)*sizeof(WCHAR));
  331. memcpy(_s + AtPosition, String->_s + FromPosition,
  332. (UINT) FromLength*sizeof(WCHAR));
  333. return TRUE;
  334. }
  335. NONVIRTUAL
  336. BOOLEAN
  337. WSTRING::Replace(
  338. IN CHNUM AtPosition,
  339. IN CHNUM AtLength,
  340. IN PCWSTRING String,
  341. IN CHNUM FromPosition,
  342. IN CHNUM FromLength
  343. )
  344. /*++
  345. Routine Description:
  346. This routine replaces the contents of this string from
  347. 'Position' to 'Length' with the contents of 'String2'
  348. from 'Position2' to 'Length2'.
  349. Arguments:
  350. AtPosition - Supplies the position to replace at.
  351. AtLength - Supplies the length to replace at.
  352. String - Supplies the string to replace with.
  353. FromPosition - Supplies the position to replace from in String2.
  354. FromLength - Supplies the position to replace from in String2.
  355. Return Value:
  356. FALSE - Failure.
  357. TRUE - Success.
  358. --*/
  359. {
  360. CHNUM old_length;
  361. DebugAssert(AtPosition <= _l);
  362. DebugAssert(FromPosition <= String->_l);
  363. AtLength = min(AtLength, _l - AtPosition);
  364. FromLength = min(FromLength, String->_l - FromPosition);
  365. // Make sure up front that we have the room but don't disturb
  366. // the string.
  367. if (FromLength > AtLength) {
  368. old_length = _l;
  369. if (!Resize(_l + FromLength - AtLength)) {
  370. return FALSE;
  371. }
  372. Resize(old_length);
  373. }
  374. DeleteChAt(AtPosition, AtLength);
  375. if (!InsertString(AtPosition, String, FromPosition, FromLength)) {
  376. DebugAbort("This absolutely can never happen\n");
  377. return FALSE;
  378. }
  379. return TRUE;
  380. }
  381. NONVIRTUAL
  382. BOOLEAN
  383. WSTRING::ReplaceWithChars(
  384. IN CHNUM AtPosition,
  385. IN CHNUM AtLength,
  386. IN WCHAR Character,
  387. IN CHNUM FromLength
  388. )
  389. /*++
  390. Routine Description:
  391. This routine replaces the contents of this string from
  392. AtPosition of AtLength with the string formed by Character
  393. of FromLength.
  394. Arguments:
  395. AtPosition - Supplies the position to replace at.
  396. AtLength - Supplies the length to replace at.
  397. Character - Supplies the character to replace with.
  398. FromLength - Supplies the total number of new characters to replace the old one with.
  399. Return Value:
  400. FALSE - Failure.
  401. TRUE - Success.
  402. --*/
  403. {
  404. CHNUM old_length;
  405. PWCHAR currptr, endptr;
  406. DebugAssert(AtPosition <= _l);
  407. AtLength = min(AtLength, _l - AtPosition);
  408. // Make sure up front that we have the room but don't disturb
  409. // the string.
  410. if (FromLength > AtLength) {
  411. old_length = _l;
  412. if (!Resize(_l + FromLength - AtLength)) {
  413. return FALSE;
  414. }
  415. Resize(old_length);
  416. }
  417. DeleteChAt(AtPosition, AtLength);
  418. old_length = _l;
  419. if (!Resize(_l + FromLength)) {
  420. DebugPrint("This should not fail\n");
  421. return FALSE;
  422. }
  423. memmove(_s + AtPosition + FromLength, _s + AtPosition,
  424. (UINT) (old_length - AtPosition)*sizeof(WCHAR));
  425. for (currptr = _s + AtPosition, endptr = currptr + FromLength;
  426. currptr < endptr;
  427. currptr++) {
  428. *currptr = Character;
  429. }
  430. return TRUE;
  431. }
  432. PWSTR
  433. WSTRING::QueryWSTR(
  434. IN CHNUM Position,
  435. IN CHNUM Length,
  436. OUT PWSTR Buffer,
  437. IN CHNUM BufferLength,
  438. IN BOOLEAN ForceNull
  439. ) CONST
  440. /*++
  441. Routine Description:
  442. This routine makes a copy of this string into the provided
  443. buffer. If this string is not provided then a buffer is
  444. allocated on the heap.
  445. Arguments:
  446. Position - Supplies the position within this string.
  447. Length - Supplies the length of this string to take.
  448. Buffer - Supplies the buffer to copy to.
  449. BufferLength - Supplies the number of characters in the buffer.
  450. ForceNull - Specifies whether or not to force the final character
  451. of the buffer to be NULL in the case when there
  452. isn't enough room for the whole string including
  453. the NULL.
  454. Return Value:
  455. A pointer to a NULL terminated string.
  456. --*/
  457. {
  458. DebugAssert(Position <= _l);
  459. Length = min(Length, _l - Position);
  460. if (!Buffer) {
  461. BufferLength = Length + 1;
  462. if (!(Buffer = (PWCHAR) MALLOC(BufferLength*sizeof(WCHAR)))) {
  463. return NULL;
  464. }
  465. }
  466. if (BufferLength > Length) {
  467. memcpy(Buffer, _s + Position, (UINT) Length*sizeof(WCHAR));
  468. Buffer[Length] = 0;
  469. } else {
  470. memcpy(Buffer, _s + Position, (UINT) BufferLength*sizeof(WCHAR));
  471. if (ForceNull) {
  472. Buffer[BufferLength - 1] = 0;
  473. }
  474. }
  475. return Buffer;
  476. }
  477. PSTR
  478. WSTRING::QuerySTR(
  479. IN CHNUM Position,
  480. IN CHNUM Length,
  481. OUT PSTR Buffer,
  482. IN CHNUM BufferLength,
  483. IN BOOLEAN ForceNull
  484. ) CONST
  485. /*++
  486. Routine Description:
  487. This routine computes a multi-byte version of the current
  488. unicode string. If the buffer is not supplied then it
  489. will be allocated by this routine.
  490. Arguments:
  491. Position - Supplies the position within this string.
  492. Length - Supplies the length of this string to take.
  493. Buffer - Supplies the buffer to convert into.
  494. BufferLength - Supplies the number of characters in this buffer.
  495. ForceNull - Specifies whether or not to force a NULL even
  496. when the buffer is too small for the string.
  497. Return Value:
  498. A pointer to a NULL terminated multi byte string.
  499. --*/
  500. {
  501. ULONG ansi_length;
  502. DebugAssert(Position <= _l);
  503. Length = min(Length, _l - Position);
  504. // First special case the empty result.
  505. if (!Length) {
  506. if (!Buffer) {
  507. if (!(Buffer = (PSTR) MALLOC(1))) {
  508. return NULL;
  509. }
  510. } else if (!BufferLength) {
  511. return NULL;
  512. }
  513. Buffer[0] = 0;
  514. return Buffer;
  515. }
  516. // Next case is that the buffer is not provided and thus
  517. // we have to figure out what size it should be.
  518. if (!Buffer) {
  519. // We want to avoid too many calls to RtlUnicodeToOemN
  520. // so we'll estimate a correct size for the buffer and
  521. // hope that that works.
  522. BufferLength = 2*Length + 1;
  523. if (!(Buffer = (PSTR) MALLOC(BufferLength))) {
  524. return NULL;
  525. }
  526. if (ConvertUnicodeToOemN(Buffer, BufferLength - 1,
  527. &ansi_length, _s + Position,
  528. Length*sizeof(WCHAR))) {
  529. Buffer[ansi_length] = 0;
  530. return Buffer;
  531. }
  532. // We failed to estimate the necessary size of the buffer.
  533. // So ask the correct size and try again.
  534. FREE(Buffer);
  535. if (!ConvertUnicodeToOemN(NULL, 0, &ansi_length,
  536. _s + Position, Length*sizeof(WCHAR))) {
  537. return NULL;
  538. }
  539. BufferLength = ansi_length + 1;
  540. if (!(Buffer = (PSTR) MALLOC(BufferLength))) {
  541. return NULL;
  542. }
  543. }
  544. if (!ConvertUnicodeToOemN(Buffer, BufferLength, &ansi_length,
  545. _s + Position, Length*sizeof(WCHAR))) {
  546. return NULL;
  547. }
  548. if (BufferLength > ansi_length) {
  549. Buffer[ansi_length] = 0;
  550. } else {
  551. if (ForceNull) {
  552. Buffer[BufferLength - 1] = 0;
  553. }
  554. }
  555. return Buffer;
  556. }
  557. BOOLEAN
  558. WSTRING::Strcat(
  559. IN PCWSTRING String
  560. )
  561. /*++
  562. Routine Description:
  563. This routine concatenates the given string onto this one.
  564. Arguments:
  565. String - Supplies the string to concatenate to this one.
  566. Return Value:
  567. FALSE - Failure.
  568. TRUE - Success.
  569. --*/
  570. {
  571. CHNUM old_length;
  572. old_length = _l;
  573. if (!Resize(_l + String->_l)) {
  574. return FALSE;
  575. }
  576. memcpy(_s + old_length, String->_s, (UINT) String->_l*sizeof(WCHAR));
  577. return TRUE;
  578. }
  579. NONVIRTUAL
  580. PWSTRING
  581. WSTRING::Strupr(
  582. IN CHNUM StartPosition,
  583. IN CHNUM Length
  584. )
  585. /*++
  586. Routine Description:
  587. This routine upcases a portion of this string.
  588. Arguments:
  589. StartPosition - Supplies the start position of the substring to upcase.
  590. Length - Supplies the length of the substring to upscase.
  591. Return Value:
  592. A pointer to this string.
  593. --*/
  594. {
  595. WCHAR c;
  596. DebugAssert(StartPosition <= _l);
  597. Length = min(Length, _l - StartPosition);
  598. c = _s[StartPosition + Length];
  599. _s[StartPosition + Length] = 0;
  600. // BUGBUG don't have an upcase function in EFI.
  601. // _wcsupr(_s + StartPosition);
  602. _s[StartPosition + Length] = c;
  603. return this;
  604. }
  605. NONVIRTUAL
  606. PWSTRING
  607. WSTRING::Strlwr(
  608. IN CHNUM StartPosition,
  609. IN CHNUM Length
  610. )
  611. /*++
  612. Routine Description:
  613. This routine lowercases a portion of this string.
  614. Arguments:
  615. StartPosition - Supplies the start position of the substring to lowercase.
  616. Length - Supplies the length of the substring to lowercase.
  617. Return Value:
  618. A pointer to this string.
  619. --*/
  620. {
  621. WCHAR c;
  622. DebugAssert(StartPosition <= _l);
  623. Length = min(Length, _l - StartPosition);
  624. c = _s[StartPosition + Length];
  625. _s[StartPosition + Length] = 0;
  626. // BUGBUG we don't have a lowercase function in EFI
  627. // _wcslwr(_s + StartPosition);
  628. _s[StartPosition + Length] = c;
  629. return this;
  630. }
  631. NONVIRTUAL
  632. LONG
  633. WSTRING::Strcmp(
  634. IN PCWSTRING String,
  635. IN CHNUM LeftPosition,
  636. IN CHNUM LeftLength,
  637. IN CHNUM RightPosition,
  638. IN CHNUM RightLength
  639. ) CONST
  640. /*++
  641. Routine Description:
  642. This routine compares two substrings.
  643. Arguments:
  644. String - Supplies the string to compare this one to.
  645. LeftPosition - Supplies the postion for the left substring.
  646. LeftLength - Supplies the length of the left substring.
  647. LeftPosition - Supplies the postion for the left substring.
  648. LeftLength - Supplies the length of the left substring.
  649. Return Value:
  650. <0 - Left substring is less than right substring.
  651. 0 - Left and Right substrings are equal
  652. >0 - Left substring is greater than right substring.
  653. --*/
  654. {
  655. WCHAR c, d;
  656. LONG r;
  657. DebugAssert(LeftPosition <= _l);
  658. DebugAssert(RightPosition <= String->_l);
  659. LeftLength = min(LeftLength, _l - LeftPosition);
  660. RightLength = min(RightLength, String->_l - RightPosition);
  661. c = _s[LeftPosition + LeftLength];
  662. d = String->_s[RightPosition + RightLength];
  663. _s[LeftPosition + LeftLength] = 0;
  664. String->_s[RightPosition + RightLength] = 0;
  665. r = wcscmp(_s + LeftPosition, String->_s + RightPosition);
  666. _s[LeftPosition + LeftLength] = c;
  667. String->_s[RightPosition + RightLength] = d;
  668. return r;
  669. }
  670. NONVIRTUAL
  671. LONG
  672. WSTRING::Stricmp(
  673. IN PCWSTRING String,
  674. IN CHNUM LeftPosition,
  675. IN CHNUM LeftLength,
  676. IN CHNUM RightPosition,
  677. IN CHNUM RightLength
  678. ) CONST
  679. /*++
  680. Routine Description:
  681. This routine compares two substrings insensitive of case.
  682. Arguments:
  683. String - Supplies the string to compare this one to.
  684. LeftPosition - Supplies the postion for the left substring.
  685. LeftLength - Supplies the length of the left substring.
  686. LeftPosition - Supplies the postion for the left substring.
  687. LeftLength - Supplies the length of the left substring.
  688. Return Value:
  689. <0 - Left substring is less than right substring.
  690. 0 - Left and Right substrings are equal
  691. >0 - Left substring is greater than right substring.
  692. --*/
  693. {
  694. WCHAR c, d;
  695. LONG r;
  696. DebugAssert(LeftPosition <= _l);
  697. DebugAssert(RightPosition <= String->_l);
  698. LeftLength = min(LeftLength, _l - LeftPosition);
  699. RightLength = min(RightLength, String->_l - RightPosition);
  700. c = _s[LeftPosition + LeftLength];
  701. d = String->_s[RightPosition + RightLength];
  702. _s[LeftPosition + LeftLength] = 0;
  703. String->_s[RightPosition + RightLength] = 0;
  704. #if !defined _AUTOCHECK_ && !defined _EFICHECK_
  705. // This works around a bug in the libc version of wcsicoll, where
  706. // it doesn't specify STRINGSORT to CompareString(). To reproduce the
  707. // bug, try sorting 1 and -1. (-1 should sort before 1.)
  708. //
  709. r = CompareString(GetUserDefaultLCID(),
  710. NORM_IGNORECASE | SORT_STRINGSORT,
  711. _s + LeftPosition,
  712. -1,
  713. String->_s + RightPosition,
  714. -1
  715. );
  716. if (r >= 1) {
  717. //
  718. // return codes 1, 2, and 3 map to -1, 0, and 1.
  719. //
  720. _s[LeftPosition + LeftLength] = c;
  721. String->_s[RightPosition + RightLength] = d;
  722. return r - 2;
  723. }
  724. // If 'r' is 0, this indicates failure and we'll fall through and
  725. // call wcsicoll.
  726. //
  727. #endif // _AUTOCHECK_
  728. r = _wcsicmp(_s + LeftPosition, String->_s + RightPosition);
  729. _s[LeftPosition + LeftLength] = c;
  730. String->_s[RightPosition + RightLength] = d;
  731. return r;
  732. }
  733. PWSTR
  734. WSTRING::SkipWhite(
  735. IN PWSTR p
  736. )
  737. {
  738. #ifdef FE_SB
  739. while (*p) {
  740. if (iswspace(*p))
  741. p++;
  742. else if ( *p == 0x3000 )
  743. {
  744. *p++ = TEXT(' ');
  745. }
  746. else
  747. break;
  748. }
  749. #else
  750. while (iswspace(*p)) {
  751. p++;
  752. }
  753. #endif
  754. return p;
  755. }
  756. /**************************************************************************/
  757. /* Compare two strings, ignoring white space, case is significant, return */
  758. /* 0 if identical, <>0 otherwise. Leading and trailing white space is */
  759. /* ignored, internal white space is treated as single characters. */
  760. /**************************************************************************/
  761. INT
  762. WSTRING::Strcmps (
  763. IN PWSTR p1,
  764. IN PWSTR p2
  765. )
  766. {
  767. WCHAR *q;
  768. p1 = WSTRING::SkipWhite(p1); /* skip any leading white space */
  769. p2 = WSTRING::SkipWhite(p2);
  770. while (TRUE)
  771. {
  772. if (*p1 == *p2)
  773. {
  774. if (*p1++ == 0) /* quit if at the end */
  775. return (0);
  776. else
  777. p2++;
  778. #ifdef FE_SB
  779. if (CheckSpace(p1))
  780. #else
  781. if (iswspace(*p1)) /* compress multiple spaces */
  782. #endif
  783. {
  784. q = WSTRING::SkipWhite(p1);
  785. p1 = (*q == 0) ? q : q - 1;
  786. }
  787. #ifdef FE_SB
  788. if (CheckSpace(p2))
  789. #else
  790. if (iswspace(*p2))
  791. #endif
  792. {
  793. q = WSTRING::SkipWhite(p2);
  794. p2 = (*q == 0) ? q : q - 1;
  795. }
  796. }
  797. else
  798. return *p1-*p2;
  799. }
  800. }
  801. /**************************************************************************/
  802. /* Compare two strings, ignoring white space, case is not significant, */
  803. /* return 0 if identical, <>0 otherwise. Leading and trailing white */
  804. /* space is ignored, internal white space is treated as single characters.*/
  805. /**************************************************************************/
  806. INT
  807. WSTRING::Strcmpis (
  808. IN PWSTR p1,
  809. IN PWSTR p2
  810. )
  811. {
  812. WCHAR *q;
  813. #ifdef FE_SB
  814. WCHAR c1,c2;
  815. #endif
  816. p1 = WSTRING::SkipWhite(p1); /* skip any leading white space */
  817. p2 = WSTRING::SkipWhite(p2);
  818. while (TRUE)
  819. {
  820. if (towupper(*p1) == towupper(*p2))
  821. {
  822. if (*p1++ == 0) /* quit if at the end */
  823. return (0);
  824. else
  825. p2++;
  826. #ifdef FE_SB
  827. if (CheckSpace(p1))
  828. #else
  829. if (iswspace(*p1)) /* compress multiple spaces */
  830. #endif
  831. {
  832. q = SkipWhite(p1);
  833. p1 = (*q == 0) ? q : q - 1;
  834. }
  835. #ifdef FE_SB
  836. if (CheckSpace(p2))
  837. #else
  838. if (iswspace(*p2))
  839. #endif
  840. {
  841. q = WSTRING::SkipWhite(p2);
  842. p2 = (*q == 0) ? q : q - 1;
  843. }
  844. }
  845. else
  846. return *p1-*p2;
  847. }
  848. }
  849. #ifdef FE_SB
  850. /**************************************************************************/
  851. /* Routine: CheckSpace */
  852. /* Arguments: an arbitrary string */
  853. /* Function: Determine whether there is a space in the string. */
  854. /* Side effects: none */
  855. /**************************************************************************/
  856. INT
  857. WSTRING::CheckSpace(
  858. IN PWSTR s
  859. )
  860. {
  861. if (iswspace(*s) || *s == 0x3000 )
  862. return (TRUE);
  863. else
  864. return (FALSE);
  865. }
  866. #endif
  867. #define DUMMY_ULIB_EXPORT
  868. DEFINE_EXPORTED_CONSTRUCTOR( FSTRING, WSTRING, DUMMY_ULIB_EXPORT );
  869. BOOLEAN
  870. FSTRING::Resize(
  871. IN CHNUM NewStringLength
  872. )
  873. /*++
  874. Routine Description:
  875. This routine implements the WSTRING Resize routine by using
  876. the buffer supplied at initialization time.
  877. Arguments:
  878. NewStringLength - Supplies the new length of the string.
  879. Return Value:
  880. FALSE - Failure.
  881. TRUE - Success.
  882. --*/
  883. {
  884. return NewBuf(NewStringLength);
  885. }
  886. BOOLEAN
  887. FSTRING::NewBuf(
  888. IN CHNUM NewStringLength
  889. )
  890. /*++
  891. Routine Description:
  892. This routine implements the WSTRING NewBuf routine by using
  893. the buffer supplied at initialization time.
  894. Arguments:
  895. NewStringLength - Supplies the new length of the string.
  896. Return Value:
  897. FALSE - Failure.
  898. TRUE - Success.
  899. --*/
  900. {
  901. if (NewStringLength >= _buffer_length) {
  902. return FALSE;
  903. }
  904. PutString((PWSTR) GetWSTR(), NewStringLength);
  905. return TRUE;
  906. }
  907. INLINE
  908. VOID
  909. DSTRING::Construct(
  910. )
  911. /*++
  912. Routine Description:
  913. This routine initializes the string to a valid initial state.
  914. Arguments:
  915. None.
  916. Return Value:
  917. None.
  918. --*/
  919. {
  920. _buf = NULL;
  921. _length = 0;
  922. }
  923. DEFINE_EXPORTED_CONSTRUCTOR( DSTRING, WSTRING, DUMMY_ULIB_EXPORT );
  924. DSTRING::~DSTRING(
  925. )
  926. /*++
  927. Routine Description:
  928. Destructor for DSTRING.
  929. Arguments:
  930. None.
  931. Return Value:
  932. None.
  933. --*/
  934. {
  935. FREE(_buf);
  936. }
  937. BOOLEAN
  938. DSTRING::Resize(
  939. IN CHNUM NewStringLength
  940. )
  941. /*++
  942. Routine Description:
  943. This routine resizes this string to the specified new size.
  944. Arguments:
  945. NewStringLength - Supplies the new length of the string.
  946. Return Value:
  947. FALSE - Failure.
  948. TRUE - Success.
  949. --*/
  950. {
  951. PWSTR new_buf;
  952. if (NewStringLength >= _length) {
  953. if (_buf) {
  954. #if !defined( _EFICHECK_ )
  955. if (!(new_buf = (PWSTR)
  956. REALLOC(_buf, (NewStringLength + 1)*sizeof(WCHAR)))) {
  957. return FALSE;
  958. }
  959. #else
  960. new_buf = (PWSTR) ReallocatePool( _buf,
  961. _length * sizeof(WCHAR),
  962. (NewStringLength + 1)*sizeof(WCHAR) );
  963. if ( new_buf == NULL ) {
  964. return FALSE;
  965. }
  966. #endif
  967. } else {
  968. if (!(new_buf = (PWSTR)
  969. MALLOC((NewStringLength + 1)*sizeof(WCHAR)))) {
  970. return FALSE;
  971. }
  972. }
  973. _buf = new_buf;
  974. _length = NewStringLength + 1;
  975. }
  976. PutString(_buf, NewStringLength);
  977. return TRUE;
  978. }
  979. BOOLEAN
  980. DSTRING::NewBuf(
  981. IN CHNUM NewStringLength
  982. )
  983. /*++
  984. Routine Description:
  985. This routine resizes this string to the specified new size.
  986. Arguments:
  987. NewStringLength - Supplies the new length of the string.
  988. Return Value:
  989. FALSE - Failure.
  990. TRUE - Success.
  991. --*/
  992. {
  993. PWSTR new_buf;
  994. if (NewStringLength >= _length) {
  995. if (!(new_buf = (PWSTR)
  996. MALLOC((NewStringLength + 1)*sizeof(WCHAR)))) {
  997. return FALSE;
  998. }
  999. if (_buf) {
  1000. FREE(_buf);
  1001. }
  1002. _buf = new_buf;
  1003. _length = NewStringLength + 1;
  1004. }
  1005. PutString(_buf, NewStringLength);
  1006. return TRUE;
  1007. }
  1008. #if defined FE_SB
  1009. VOID
  1010. WSTRING::ResetConversions(
  1011. )
  1012. {
  1013. _UseAnsiConversions = _UseAnsiConversionsPrev;
  1014. _UseConsoleConversions = _UseConsoleConversionsPrev;
  1015. }
  1016. #endif
  1017. VOID
  1018. WSTRING::SetAnsiConversions(
  1019. )
  1020. /*++
  1021. Routine Description:
  1022. This routine declares that all conversions from multi byte
  1023. to unicode will take place using the ANSI code page. Note
  1024. that this is a STATIC method. Therefore this switch affects
  1025. *all* WSTRINGs.
  1026. Arguments:
  1027. None.
  1028. Return Value:
  1029. None.
  1030. --*/
  1031. {
  1032. #if defined FE_SB
  1033. _UseAnsiConversionsPrev = _UseAnsiConversions;
  1034. _UseConsoleConversionsPrev = _UseConsoleConversions;
  1035. #endif
  1036. _UseAnsiConversions = TRUE;
  1037. _UseConsoleConversions = FALSE;
  1038. }
  1039. VOID
  1040. WSTRING::SetOemConversions(
  1041. )
  1042. /*++
  1043. Routine Description:
  1044. This routine declares that all conversions from multi byte
  1045. to unicode will take place using the OEM code page. Note
  1046. that this is a STATIC method. Therefore this switch affects
  1047. *all* WSTRINGs.
  1048. This is the default if neither this nor the above function is
  1049. called.
  1050. Arguments:
  1051. None.
  1052. Return Value:
  1053. None.
  1054. --*/
  1055. {
  1056. #if defined FE_SB
  1057. _UseAnsiConversionsPrev = _UseAnsiConversions;
  1058. _UseConsoleConversionsPrev = _UseConsoleConversions;
  1059. #endif
  1060. _UseAnsiConversions = FALSE;
  1061. _UseConsoleConversions = FALSE;
  1062. }
  1063. VOID
  1064. WSTRING::SetConsoleConversions(
  1065. )
  1066. /*++
  1067. Routine Description:
  1068. This routine declares that all conversions from multi byte
  1069. to unicode will take place using the current console code page.
  1070. Note that this is a STATIC method. Therefore this switch
  1071. affects *all* WSTRINGs.
  1072. Arguments:
  1073. None.
  1074. Return Value:
  1075. None.
  1076. --*/
  1077. {
  1078. #if defined FE_SB
  1079. _UseAnsiConversionsPrev = _UseAnsiConversions;
  1080. _UseConsoleConversionsPrev = _UseConsoleConversions;
  1081. #endif
  1082. _UseAnsiConversions = FALSE;
  1083. _UseConsoleConversions = TRUE;
  1084. }
  1085. #if defined FE_SB
  1086. CHNUM
  1087. WSTRING::QueryByteCount(
  1088. ) CONST
  1089. /*++
  1090. Routine Description:
  1091. This routine returns the number of ANSI bytes the UNICODE string
  1092. consists of.
  1093. Arguments:
  1094. None.
  1095. Return Value:
  1096. Number of ANSI bytes the UNICODE string is made from, or INVALID_CHNUM
  1097. on error.
  1098. --*/
  1099. {
  1100. ULONG ansi_length;
  1101. ULONG BufferLen = _l * sizeof(WCHAR) + 1;
  1102. PSTR Buffer;
  1103. BOOLEAN success;
  1104. if ( !_l ) {
  1105. return( (CHNUM)0 );
  1106. }
  1107. if (NULL == (Buffer = (PSTR)MALLOC( BufferLen ))) {
  1108. return( INVALID_CHNUM );
  1109. }
  1110. success = ConvertUnicodeToOemN( Buffer, BufferLen - 1, &ansi_length,
  1111. _s, BufferLen - 1 );
  1112. FREE( Buffer );
  1113. if (!success) {
  1114. return INVALID_CHNUM;
  1115. }
  1116. return ansi_length;
  1117. }
  1118. #endif