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.

2147 lines
39 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. strings.c
  5. Abstract:
  6. String routines
  7. Author:
  8. Jim Schmidt (jimschm) 03-Aug-2001
  9. Revision History:
  10. <alias> <date> <comments>
  11. --*/
  12. #include "pch.h"
  13. #include "commonp.h"
  14. PSTR
  15. SzCopyA (
  16. OUT PSTR Destination,
  17. IN PCSTR Source
  18. )
  19. {
  20. while (*Source) {
  21. *Destination++ = *Source++;
  22. }
  23. *Destination = 0;
  24. return Destination;
  25. }
  26. PWSTR
  27. SzCopyW (
  28. OUT PWSTR Destination,
  29. IN PCWSTR Source
  30. )
  31. {
  32. while (*Source) {
  33. *Destination++ = *Source++;
  34. }
  35. *Destination = 0;
  36. return Destination;
  37. }
  38. PSTR
  39. SzNextCharA (
  40. IN PCSTR CurrentPointer
  41. )
  42. {
  43. PCSTR next;
  44. next = _mbsinc (CurrentPointer);
  45. switch (next - CurrentPointer) {
  46. case 3:
  47. if (CurrentPointer[2] == 0) {
  48. next = CurrentPointer + 2;
  49. break;
  50. }
  51. case 2:
  52. if (CurrentPointer[1] == 0) {
  53. next = CurrentPointer + 1;
  54. }
  55. break;
  56. }
  57. return (PSTR) next;
  58. }
  59. PSTR
  60. SzCopyBytesA (
  61. OUT PSTR Destination,
  62. IN PCSTR Source,
  63. IN UINT MaxBytesToCopyIncNul
  64. )
  65. {
  66. PCSTR maxEnd;
  67. PCSTR sourceEndPlusOne;
  68. PCSTR sourceEnd;
  69. UINT_PTR bytes;
  70. if (!MaxBytesToCopyIncNul) {
  71. //
  72. // Buffer can't fit anything
  73. //
  74. return Destination;
  75. }
  76. //
  77. // Find the nul terminator, or the last character that
  78. // will fit in the buffer.
  79. //
  80. maxEnd = (PCSTR) ((PBYTE) Source + MaxBytesToCopyIncNul);
  81. sourceEndPlusOne = Source;
  82. do {
  83. sourceEnd = sourceEndPlusOne;
  84. if (!(*sourceEndPlusOne)) {
  85. break;
  86. }
  87. sourceEndPlusOne = SzNextCharA (sourceEndPlusOne);
  88. } while (sourceEndPlusOne < maxEnd);
  89. bytes = (PBYTE) sourceEnd - (PBYTE) Source;
  90. CopyMemory (Destination, Source, bytes);
  91. Destination = (PSTR) ((PBYTE) Destination + bytes);
  92. *Destination = 0;
  93. return Destination;
  94. }
  95. PWSTR
  96. SzCopyBytesW (
  97. OUT PWSTR Destination,
  98. IN PCWSTR Source,
  99. IN UINT MaxBytesToCopyIncNul
  100. )
  101. {
  102. PCWSTR sourceMax;
  103. PCWSTR sourceEnd;
  104. UINT_PTR bytes;
  105. if (MaxBytesToCopyIncNul < sizeof (WCHAR)) {
  106. //
  107. // Buffer can't fit anything
  108. //
  109. return Destination;
  110. }
  111. sourceMax = (PCWSTR) ((PBYTE) Source + (MaxBytesToCopyIncNul & (~1)) - sizeof (WCHAR));
  112. sourceEnd = Source;
  113. do {
  114. if (!(*sourceEnd)) {
  115. break;
  116. }
  117. sourceEnd++;
  118. } while (sourceEnd < sourceMax);
  119. bytes = (PBYTE) sourceEnd - (PBYTE) Source;
  120. CopyMemory (Destination, Source, bytes);
  121. Destination = (PWSTR) ((PBYTE) Destination + bytes);
  122. *Destination = 0;
  123. return Destination;
  124. }
  125. PSTR
  126. SzCopyBytesABA (
  127. OUT PSTR Destination,
  128. IN PCSTR Start,
  129. IN PCSTR End,
  130. IN UINT MaxBytesToCopyIncNul
  131. )
  132. {
  133. UINT width;
  134. width = ((PBYTE) End - (PBYTE) Start) + sizeof (CHAR);
  135. return SzCopyBytesA (Destination, Start, min (width, MaxBytesToCopyIncNul));
  136. }
  137. PWSTR
  138. SzCopyBytesABW (
  139. OUT PWSTR Destination,
  140. IN PCWSTR Start,
  141. IN PCWSTR End,
  142. IN UINT MaxBytesToCopyIncNul
  143. )
  144. {
  145. UINT width;
  146. width = ((PBYTE) End - (PBYTE) Start) + sizeof (WCHAR);
  147. return SzCopyBytesW (Destination, Start, min (width, MaxBytesToCopyIncNul));
  148. }
  149. PSTR
  150. SzCatA (
  151. OUT PSTR Destination,
  152. IN PCSTR Source
  153. )
  154. {
  155. Destination = SzGetEndA (Destination);
  156. return SzCopyA (Destination, Source);
  157. }
  158. PWSTR
  159. SzCatW (
  160. OUT PWSTR Destination,
  161. IN PCWSTR Source
  162. )
  163. {
  164. Destination = SzGetEndW (Destination);
  165. return SzCopyW (Destination, Source);
  166. }
  167. BOOL
  168. SzMatchA (
  169. IN PCSTR String1,
  170. IN PCSTR String2
  171. )
  172. {
  173. while (*String1) {
  174. if (*String1++ != *String2++) {
  175. return FALSE;
  176. }
  177. }
  178. return *String2 == 0;
  179. }
  180. BOOL
  181. SzMemMatchA (
  182. IN PCSTR Buffer1,
  183. IN PCSTR Buffer2,
  184. IN SIZE_T ByteCount
  185. )
  186. {
  187. SIZE_T u;
  188. PCSTR end;
  189. end = (PCSTR) ((PBYTE) Buffer1 + ByteCount);
  190. while (Buffer1 < end) {
  191. if (*Buffer1 != *Buffer2++) {
  192. return FALSE;
  193. }
  194. if (*Buffer1++ == 0) {
  195. return TRUE;
  196. }
  197. }
  198. return TRUE;
  199. }
  200. BOOL
  201. SzMemMatchW (
  202. IN PCWSTR Buffer1,
  203. IN PCWSTR Buffer2,
  204. IN SIZE_T ByteCount
  205. )
  206. {
  207. SIZE_T u;
  208. PCWSTR end;
  209. end = (PCWSTR) ((PBYTE) Buffer1 + ByteCount);
  210. while (Buffer1 < end) {
  211. if (*Buffer1 != *Buffer2++) {
  212. return FALSE;
  213. }
  214. if (*Buffer1++ == 0) {
  215. return TRUE;
  216. }
  217. }
  218. return TRUE;
  219. }
  220. INT
  221. SzCompareBytesA (
  222. IN PCSTR String1,
  223. IN PCSTR String2,
  224. IN SIZE_T ByteCount
  225. )
  226. {
  227. PCSTR end;
  228. INT bytesLeft;
  229. INT thisCharBytes;
  230. UINT ch1;
  231. UINT ch2;
  232. PCSTR maxString1;
  233. PCSTR maxString2;
  234. if (!ByteCount) {
  235. return 0;
  236. }
  237. bytesLeft = (INT) ByteCount;
  238. MYASSERT ((SIZE_T) bytesLeft == ByteCount);
  239. maxString1 = (PCSTR) ((PBYTE) String1 + ByteCount);
  240. maxString2 = (PCSTR) ((PBYTE) String2 + ByteCount);
  241. do {
  242. //
  243. // Compute ch1. We use this code instead of _mbsnextc, so we can
  244. // support mismatched code pages.
  245. //
  246. end = SzNextCharA (String1);
  247. if (end > maxString1) {
  248. end = maxString1;
  249. }
  250. ch1 = 0;
  251. do {
  252. ch1 = (ch1 << 8) | *String1++;
  253. } while (String1 < end);
  254. //
  255. // Compute ch2.
  256. //
  257. end = SzNextCharA (String2);
  258. if (end > maxString2) {
  259. end = maxString2;
  260. }
  261. ch2 = 0;
  262. do {
  263. ch2 = (ch2 << 8) | *String2++;
  264. } while (String2 < end);
  265. //
  266. // Compare
  267. //
  268. if (ch1 != ch2) {
  269. return (INT) ch1 - (INT) ch2;
  270. }
  271. } while (String1 < maxString1 && String2 < maxString2);
  272. //
  273. // One or both strings terminated
  274. //
  275. if (String1 < maxString1) {
  276. return -1;
  277. }
  278. if (String2 < maxString2) {
  279. return 1;
  280. }
  281. return 0;
  282. }
  283. INT
  284. SzICompareBytesA (
  285. IN PCSTR String1,
  286. IN PCSTR String2,
  287. IN SIZE_T ByteCount
  288. )
  289. {
  290. PCSTR end;
  291. INT bytesLeft;
  292. INT thisCharBytes;
  293. UINT ch1;
  294. UINT ch2;
  295. PCSTR maxString1;
  296. PCSTR maxString2;
  297. if (!ByteCount) {
  298. return 0;
  299. }
  300. bytesLeft = (INT) ByteCount;
  301. MYASSERT ((SIZE_T) bytesLeft == ByteCount);
  302. maxString1 = (PCSTR) ((PBYTE) String1 + ByteCount);
  303. maxString2 = (PCSTR) ((PBYTE) String2 + ByteCount);
  304. do {
  305. //
  306. // Compute ch1. We use this code instead of _mbsnextc, so we can
  307. // support mismatched code pages.
  308. //
  309. end = SzNextCharA (String1);
  310. if (end > maxString1) {
  311. end = maxString1;
  312. }
  313. ch1 = 0;
  314. do {
  315. ch1 = (ch1 << 8) | (*String1++);
  316. } while (String1 < end);
  317. ch1 = tolower (ch1);
  318. //
  319. // Compute ch2.
  320. //
  321. end = SzNextCharA (String2);
  322. if (end > maxString2) {
  323. end = maxString2;
  324. }
  325. ch2 = 0;
  326. do {
  327. ch2 = (ch2 << 8) | (*String2++);
  328. } while (String2 < end);
  329. ch2 = tolower (ch2);
  330. //
  331. // Compare
  332. //
  333. if (ch1 != ch2) {
  334. return (INT) ch1 - (INT) ch2;
  335. }
  336. //
  337. // If this is the end of the string, then we're done
  338. //
  339. if (!ch1) {
  340. return 0;
  341. }
  342. } while (String1 < maxString1 && String2 < maxString2);
  343. //
  344. // One or both strings terminated
  345. //
  346. if (String1 < maxString1) {
  347. return -1;
  348. }
  349. if (String2 < maxString2) {
  350. return 1;
  351. }
  352. return 0;
  353. }
  354. PSTR
  355. SzUnsignedToHexA (
  356. IN ULONG_PTR Number,
  357. OUT PSTR String
  358. )
  359. {
  360. PSTR p;
  361. *String++ = '0';
  362. *String++ = 'x';
  363. p = String + (sizeof (Number) * 2);
  364. *p = 0;
  365. while (p > String) {
  366. p--;
  367. *p = ((CHAR) Number & 0x0F) + '0';
  368. if (*p > '9') {
  369. *p += 'A' - ('9' + 1);
  370. }
  371. Number >>= 4;
  372. }
  373. return String + (sizeof (Number) * 2);
  374. }
  375. PWSTR
  376. SzUnsignedToHexW (
  377. IN ULONG_PTR Number,
  378. OUT PWSTR String
  379. )
  380. {
  381. PWSTR p;
  382. *String++ = L'0';
  383. *String++ = L'x';
  384. p = String + (sizeof (Number) * 2);
  385. *p = 0;
  386. while (p > String) {
  387. p--;
  388. *p = ((WCHAR) Number & 0x0F) + L'0';
  389. if (*p > L'9') {
  390. *p += L'A' - (L'9' + 1);
  391. }
  392. Number >>= 4;
  393. }
  394. return String + (sizeof (Number) * 2);
  395. }
  396. PSTR
  397. SzUnsignedToDecA (
  398. IN ULONG_PTR Number,
  399. OUT PSTR String
  400. )
  401. {
  402. UINT digits;
  403. ULONG_PTR temp;
  404. PSTR p;
  405. temp = Number;
  406. digits = 1;
  407. while (temp > 9) {
  408. digits++;
  409. temp /= 10;
  410. }
  411. p = String + digits;
  412. *p = 0;
  413. while (p > String) {
  414. p--;
  415. *p = (CHAR) (Number % 10) + '0';
  416. Number /= 10;
  417. }
  418. return String + digits;
  419. }
  420. PWSTR
  421. SzUnsignedToDecW (
  422. IN ULONG_PTR Number,
  423. OUT PWSTR String
  424. )
  425. {
  426. UINT digits;
  427. ULONG_PTR temp;
  428. PWSTR p;
  429. temp = Number;
  430. digits = 1;
  431. while (temp > 9) {
  432. digits++;
  433. temp /= 10;
  434. }
  435. p = String + digits;
  436. *p = 0;
  437. while (p > String) {
  438. p--;
  439. *p = (WCHAR) (Number % 10) + L'0';
  440. Number /= 10;
  441. }
  442. return String + digits;
  443. }
  444. PSTR
  445. SzSignedToDecA (
  446. IN LONG_PTR Number,
  447. OUT PSTR String
  448. )
  449. {
  450. if (Number < 0) {
  451. *String++ = '-';
  452. Number = -Number;
  453. }
  454. return SzUnsignedToDecA (Number, String);
  455. }
  456. PWSTR
  457. SzSignedToDecW (
  458. IN LONG_PTR Number,
  459. OUT PWSTR String
  460. )
  461. {
  462. if (Number < 0) {
  463. *String++ = L'-';
  464. Number = -Number;
  465. }
  466. return SzUnsignedToDecW (Number, String);
  467. }
  468. PSTR
  469. SzFindPrevCharA (
  470. IN PCSTR StartStr,
  471. IN PCSTR CurrPtr,
  472. IN MBCHAR SearchChar
  473. )
  474. {
  475. PCSTR ptr = CurrPtr;
  476. while (ptr > StartStr) {
  477. ptr = _mbsdec (StartStr, ptr);
  478. if (!ptr) {
  479. ptr = StartStr;
  480. }
  481. if (_mbsnextc (ptr) == SearchChar) {
  482. return (PSTR) ptr;
  483. }
  484. }
  485. return NULL;
  486. }
  487. PWSTR
  488. SzFindPrevCharW (
  489. IN PCWSTR StartStr,
  490. IN PCWSTR CurrPtr,
  491. IN WCHAR SearchChar
  492. )
  493. {
  494. PCWSTR ptr = CurrPtr;
  495. while (ptr > StartStr) {
  496. ptr--;
  497. if (*ptr == SearchChar) {
  498. return (PWSTR) ptr;
  499. }
  500. }
  501. return NULL;
  502. }
  503. INT
  504. pGetHexDigit (
  505. IN INT c
  506. )
  507. {
  508. if (c >= '0' && c <= '9') {
  509. return (c - '0');
  510. }
  511. if (c >= 'a' && c <= 'f') {
  512. return (c - 'a' + 10);
  513. }
  514. if (c >= 'A' && c <= 'F') {
  515. return (c - 'A' + 10);
  516. }
  517. return -1;
  518. }
  519. ULONG
  520. SzToNumberA (
  521. IN PCSTR String,
  522. OUT PCSTR *EndOfNumber OPTIONAL
  523. )
  524. {
  525. ULONG d = 0;
  526. INT v;
  527. if (_mbsnextc (String) == '0' &&
  528. tolower (_mbsnextc (SzNextCharA (String))) == 'x'
  529. ) {
  530. //
  531. // Get hex value
  532. //
  533. String = SzNextCharA (String);
  534. String = SzNextCharA (String);
  535. for (;;) {
  536. v = pGetHexDigit ((INT) _mbsnextc (String));
  537. if (v == -1) {
  538. break;
  539. }
  540. d = (d * 16) + v;
  541. String = SzNextCharA (String);
  542. }
  543. } else {
  544. //
  545. // Get decimal value
  546. //
  547. while (_mbsnextc (String) >= '0' && _mbsnextc (String) <= '9') {
  548. d = (d * 10) + (_mbsnextc (String) - '0');
  549. String = SzNextCharA (String);
  550. }
  551. }
  552. if (EndOfNumber) {
  553. *EndOfNumber = String;
  554. }
  555. return d;
  556. }
  557. ULONG
  558. SzToNumberW (
  559. IN PCWSTR String,
  560. OUT PCWSTR *EndOfNumber OPTIONAL
  561. )
  562. {
  563. ULONG d = 0;
  564. INT v;
  565. if (String[0] == L'0' && towlower (String[1]) == L'x') {
  566. //
  567. // Get hex value
  568. //
  569. String += 2;
  570. for (;;) {
  571. v = pGetHexDigit ((INT) (*String));
  572. if (v == -1) {
  573. break;
  574. }
  575. d = (d * 16) + v;
  576. String++;
  577. }
  578. } else {
  579. //
  580. // Get decimal value
  581. //
  582. while (*String >= L'0' && *String <= L'9') {
  583. d = (d * 10) + (*String - L'0');
  584. String++;
  585. }
  586. }
  587. if (EndOfNumber) {
  588. *EndOfNumber = String;
  589. }
  590. return d;
  591. }
  592. ULONGLONG
  593. SzToULongLongA (
  594. IN PCSTR String,
  595. OUT PCSTR *EndOfNumber OPTIONAL
  596. )
  597. {
  598. ULONGLONG d = 0;
  599. INT v;
  600. if (_mbsnextc (String) == '0' &&
  601. tolower (_mbsnextc (SzNextCharA (String))) == 'x'
  602. ) {
  603. //
  604. // Get hex value
  605. //
  606. String = SzNextCharA (String);
  607. String = SzNextCharA (String);
  608. for (;;) {
  609. v = pGetHexDigit ((INT) _mbsnextc (String));
  610. if (v == -1) {
  611. break;
  612. }
  613. d = (d * 16) + (ULONGLONG) v;
  614. String = SzNextCharA (String);
  615. }
  616. } else {
  617. //
  618. // Get decimal value
  619. //
  620. while (_mbsnextc (String) >= '0' && _mbsnextc (String) <= '9') {
  621. d = (d * 10) + (ULONGLONG) (_mbsnextc (String) - '0');
  622. String = SzNextCharA (String);
  623. }
  624. }
  625. if (EndOfNumber) {
  626. *EndOfNumber = String;
  627. }
  628. return d;
  629. }
  630. ULONGLONG
  631. SzToULongLongW (
  632. IN PCWSTR String,
  633. OUT PCWSTR *EndOfNumber OPTIONAL
  634. )
  635. {
  636. ULONGLONG d = 0;
  637. INT v;
  638. if (String[0] == L'0' && tolower (String[1]) == L'x') {
  639. //
  640. // Get hex value
  641. //
  642. String += 2;
  643. for (;;) {
  644. v = pGetHexDigit ((INT) (*String));
  645. if (v == -1) {
  646. break;
  647. }
  648. d = (d * 16) + (ULONGLONG) v;
  649. String++;
  650. }
  651. } else {
  652. //
  653. // Get decimal value
  654. //
  655. while (*String >= L'0' && *String <= L'9') {
  656. d = (d * 10) + (ULONGLONG) (*String - L'0');
  657. String++;
  658. }
  659. }
  660. if (EndOfNumber) {
  661. *EndOfNumber = String;
  662. }
  663. return d;
  664. }
  665. LONGLONG
  666. SzToLongLongA (
  667. IN PCSTR String,
  668. OUT PCSTR *EndOfNumber OPTIONAL
  669. )
  670. {
  671. LONGLONG l;
  672. if (_mbsnextc (String) == '-') {
  673. String = SzNextCharA (String);
  674. //
  675. // Get decimal value
  676. //
  677. l = 0;
  678. while (_mbsnextc (String) >= '0' && _mbsnextc (String) <= '9') {
  679. l = (l * 10) + (LONGLONG) (_mbsnextc (String) - '0');
  680. String = SzNextCharA (String);
  681. }
  682. l = -l;
  683. if (EndOfNumber) {
  684. *EndOfNumber = String;
  685. }
  686. return l;
  687. } else {
  688. return (LONGLONG) SzToULongLongA (String, EndOfNumber);
  689. }
  690. }
  691. LONGLONG
  692. SzToLongLongW (
  693. IN PCWSTR String,
  694. OUT PCWSTR *EndOfNumber OPTIONAL
  695. )
  696. {
  697. LONGLONG l;
  698. if (*String == L'-') {
  699. String++;
  700. //
  701. // Get decimal value
  702. //
  703. l = 0;
  704. while (*String >= L'0' && *String <= L'9') {
  705. l = (l * 10) + (LONGLONG) (*String - L'0');
  706. String++;
  707. }
  708. l = -l;
  709. if (EndOfNumber) {
  710. *EndOfNumber = String;
  711. }
  712. return l;
  713. } else {
  714. return (LONGLONG) SzToULongLongW (String, EndOfNumber);
  715. }
  716. }
  717. PSTR
  718. SzCopyNextCharA (
  719. OUT PSTR Dest,
  720. IN PCSTR Source
  721. )
  722. {
  723. PCSTR nextSrc;
  724. nextSrc = SzNextCharA (Source);
  725. switch (nextSrc - Source) {
  726. case 3:
  727. *Dest++ = *Source++;
  728. case 2:
  729. *Dest++ = *Source++;
  730. case 1:
  731. *Dest++ = *Source;
  732. break;
  733. }
  734. return Dest;
  735. }
  736. PSTR
  737. SzTrimLastCharA (
  738. IN OUT PSTR String,
  739. IN MBCHAR LogChar
  740. )
  741. {
  742. PSTR end;
  743. end = SzGetEndA (String);
  744. end = _mbsdec (String, end);
  745. if ((end >= String) && (_mbsnextc (end) == LogChar)) {
  746. do {
  747. *end = 0;
  748. end = _mbsdec (String, end);
  749. } while ((end >= String) && (_mbsnextc (end) == LogChar));
  750. return end < String ? String : end;
  751. }
  752. return NULL;
  753. }
  754. PWSTR
  755. SzTrimLastCharW (
  756. IN OUT PWSTR String,
  757. IN WCHAR LogChar
  758. )
  759. {
  760. PWSTR end;
  761. end = SzGetEndW (String);
  762. end--;
  763. if ((end >= String) && (*end == LogChar)) {
  764. do {
  765. *end = 0;
  766. end--;
  767. } while ((end >= String) && (*end == LogChar));
  768. return end < String ? String : end;
  769. }
  770. return NULL;
  771. }
  772. PSTR
  773. SzAppendWackA (
  774. IN PSTR String
  775. )
  776. {
  777. PCSTR last;
  778. if (!String) {
  779. return NULL;
  780. }
  781. last = String;
  782. while (*String) {
  783. last = String;
  784. String = SzNextCharA (String);
  785. }
  786. if (_mbsnextc (last) != '\\') {
  787. *String = '\\';
  788. String++;
  789. *String = 0;
  790. }
  791. return String;
  792. }
  793. PWSTR
  794. SzAppendWackW (
  795. IN PWSTR String
  796. )
  797. {
  798. PCWSTR last;
  799. if (!String) {
  800. return NULL;
  801. }
  802. if (*String) {
  803. String = SzGetEndW (String);
  804. last = String - 1;
  805. } else {
  806. last = String;
  807. }
  808. if (*last != '\\') {
  809. *String = L'\\';
  810. String++;
  811. *String = 0;
  812. }
  813. return String;
  814. }
  815. PCSTR
  816. SzGetFileNameFromPathA (
  817. IN PCSTR Path
  818. )
  819. {
  820. PCSTR p;
  821. p = _mbsrchr (Path, '\\');
  822. if (p) {
  823. p = SzNextCharA (p);
  824. } else {
  825. p = Path;
  826. }
  827. return p;
  828. }
  829. PCWSTR
  830. SzGetFileNameFromPathW (
  831. IN PCWSTR Path
  832. )
  833. {
  834. PCWSTR p;
  835. p = wcsrchr (Path, L'\\');
  836. if (p) {
  837. p++;
  838. } else {
  839. p = Path;
  840. }
  841. return p;
  842. }
  843. PCSTR
  844. SzGetFileExtensionFromPathA (
  845. IN PCSTR Path
  846. )
  847. {
  848. PCSTR p;
  849. MBCHAR ch;
  850. PCSTR returnPtr = NULL;
  851. p = Path;
  852. while (*p) {
  853. ch = _mbsnextc (p);
  854. if (ch == '.') {
  855. returnPtr = SzNextCharA (p);
  856. } else if (ch == '\\') {
  857. returnPtr = NULL;
  858. }
  859. p = SzNextCharA (p);
  860. }
  861. return returnPtr;
  862. }
  863. PCWSTR
  864. SzGetFileExtensionFromPathW (
  865. IN PCWSTR Path
  866. )
  867. {
  868. PCWSTR p;
  869. PCWSTR returnPtr = NULL;
  870. p = Path;
  871. while (*p) {
  872. if (*p == L'.') {
  873. returnPtr = p + 1;
  874. } else if (*p == L'\\') {
  875. returnPtr = NULL;
  876. }
  877. p++;
  878. }
  879. return returnPtr;
  880. }
  881. PCSTR
  882. SzGetDotExtensionFromPathA (
  883. IN PCSTR Path
  884. )
  885. {
  886. PCSTR p;
  887. MBCHAR ch;
  888. PCSTR returnPtr = NULL;
  889. p = Path;
  890. while (*p) {
  891. ch = _mbsnextc (p);
  892. if (ch == '.') {
  893. returnPtr = p;
  894. } else if (ch == '\\') {
  895. returnPtr = NULL;
  896. }
  897. p = SzNextCharA (p);
  898. }
  899. if (!returnPtr) {
  900. return p;
  901. }
  902. return returnPtr;
  903. }
  904. PCWSTR
  905. SzGetDotExtensionFromPathW (
  906. IN PCWSTR Path
  907. )
  908. {
  909. PCWSTR p;
  910. PCWSTR returnPtr = NULL;
  911. p = Path;
  912. while (*p) {
  913. if (*p == L'.') {
  914. returnPtr = p;
  915. } else if (*p == L'\\') {
  916. returnPtr = NULL;
  917. }
  918. p++;
  919. }
  920. if (!returnPtr) {
  921. return p;
  922. }
  923. return returnPtr;
  924. }
  925. PCSTR
  926. SzSkipSpaceA (
  927. IN PCSTR String
  928. )
  929. {
  930. if (!String) {
  931. return NULL;
  932. }
  933. while (_ismbcspace (_mbsnextc (String))) {
  934. String = SzNextCharA (String);
  935. }
  936. return String;
  937. }
  938. PCWSTR
  939. SzSkipSpaceW (
  940. IN PCWSTR String
  941. )
  942. {
  943. if (!String) {
  944. return NULL;
  945. }
  946. while (iswspace (*String)) {
  947. String++;
  948. }
  949. return String;
  950. }
  951. PCSTR
  952. SzSkipSpaceRA (
  953. IN PCSTR BaseString,
  954. IN PCSTR String OPTIONAL
  955. )
  956. {
  957. if (!String) {
  958. String = SzGetEndA (BaseString);
  959. }
  960. if (*String == 0) {
  961. String = _mbsdec (BaseString, String);
  962. }
  963. while (String >= BaseString) {
  964. if (!_ismbcspace (_mbsnextc (String))) {
  965. return String;
  966. }
  967. String = _mbsdec (BaseString, String);
  968. }
  969. return NULL;
  970. }
  971. PCWSTR
  972. SzSkipSpaceRW (
  973. IN PCWSTR BaseString,
  974. IN PCWSTR String // can be any char along BaseString
  975. )
  976. {
  977. if (!String) {
  978. String = SzGetEndW (BaseString);
  979. }
  980. if (*String == 0) {
  981. String--;
  982. }
  983. while (String >= BaseString) {
  984. if (!iswspace (*String)) {
  985. return String;
  986. }
  987. String--;
  988. }
  989. return NULL;
  990. }
  991. PSTR
  992. SzTruncateTrailingSpaceA (
  993. IN OUT PSTR String
  994. )
  995. {
  996. PSTR end;
  997. MBCHAR ch;
  998. end = String;
  999. while (*String) {
  1000. ch = _mbsnextc (String);
  1001. String = SzNextCharA (String);
  1002. if (!_ismbcspace (ch)) {
  1003. end = String;
  1004. }
  1005. }
  1006. *end = 0;
  1007. return end;
  1008. }
  1009. PWSTR
  1010. SzTruncateTrailingSpaceW (
  1011. IN OUT PWSTR String
  1012. )
  1013. {
  1014. PWSTR end;
  1015. WCHAR ch;
  1016. end = String;
  1017. while (*String) {
  1018. ch = *String++;
  1019. if (!iswspace (ch)) {
  1020. end = String;
  1021. }
  1022. }
  1023. *end = 0;
  1024. return end;
  1025. }
  1026. BOOL
  1027. SzIsPrintA (
  1028. IN PCSTR String
  1029. )
  1030. {
  1031. while (*String && _ismbcprint (_mbsnextc (String))) {
  1032. String = SzNextCharA (String);
  1033. }
  1034. return *String == 0;
  1035. }
  1036. BOOL
  1037. SzIsPrintW (
  1038. IN PCWSTR String
  1039. )
  1040. {
  1041. while (*String && iswprint (*String)) {
  1042. String++;
  1043. }
  1044. return *String == 0;
  1045. }
  1046. PCSTR
  1047. SzIFindSubStringA (
  1048. IN PCSTR String,
  1049. IN PCSTR SubString
  1050. )
  1051. {
  1052. PCSTR start;
  1053. PCSTR middle;
  1054. PCSTR subStrMiddle;
  1055. PCSTR end;
  1056. end = (PSTR) ((PBYTE) String + SzByteCountA (String) - SzByteCountA (SubString));
  1057. for (start = String ; start <= end ; start = SzNextCharA (start)) {
  1058. middle = start;
  1059. subStrMiddle = SubString;
  1060. while (*subStrMiddle &&
  1061. _mbctolower (_mbsnextc (subStrMiddle)) == _mbctolower (_mbsnextc (middle))
  1062. ) {
  1063. middle = SzNextCharA (middle);
  1064. subStrMiddle = SzNextCharA (subStrMiddle);
  1065. }
  1066. if (!(*subStrMiddle)) {
  1067. return start;
  1068. }
  1069. }
  1070. return NULL;
  1071. }
  1072. PCWSTR
  1073. SzIFindSubStringW (
  1074. IN PCWSTR String,
  1075. IN PCWSTR SubString
  1076. )
  1077. {
  1078. PCWSTR start;
  1079. PCWSTR middle;
  1080. PCWSTR subStrMiddle;
  1081. PCWSTR end;
  1082. end = (PWSTR) ((PBYTE) String + SzByteCountW (String) - SzByteCountW (SubString));
  1083. for (start = String ; start <= end ; start++) {
  1084. middle = start;
  1085. subStrMiddle = SubString;
  1086. while (*subStrMiddle && (towlower (*subStrMiddle) == towlower (*middle))) {
  1087. middle++;
  1088. subStrMiddle++;
  1089. }
  1090. if (!(*subStrMiddle)) {
  1091. return start;
  1092. }
  1093. }
  1094. return NULL;
  1095. }
  1096. UINT
  1097. SzCountInstancesOfLcharA (
  1098. IN PCSTR String,
  1099. IN MBCHAR LogChar
  1100. )
  1101. {
  1102. UINT count;
  1103. if (!String) {
  1104. return 0;
  1105. }
  1106. count = 0;
  1107. while (*String) {
  1108. if (_mbsnextc (String) == LogChar) {
  1109. count++;
  1110. }
  1111. String = SzNextCharA (String);
  1112. }
  1113. return count;
  1114. }
  1115. UINT
  1116. SzCountInstancesOfLcharW (
  1117. IN PCWSTR String,
  1118. IN WCHAR LogChar
  1119. )
  1120. {
  1121. UINT count;
  1122. if (!String) {
  1123. return 0;
  1124. }
  1125. count = 0;
  1126. while (*String) {
  1127. if (*String == LogChar) {
  1128. count++;
  1129. }
  1130. String++;
  1131. }
  1132. return count;
  1133. }
  1134. UINT
  1135. SzICountInstancesOfLcharA (
  1136. IN PCSTR String,
  1137. IN MBCHAR LogChar
  1138. )
  1139. {
  1140. UINT count;
  1141. if (!String) {
  1142. return 0;
  1143. }
  1144. LogChar = _mbctolower (LogChar);
  1145. count = 0;
  1146. while (*String) {
  1147. if (_mbctolower (_mbsnextc (String)) == LogChar) {
  1148. count++;
  1149. }
  1150. String = SzNextCharA (String);
  1151. }
  1152. return count;
  1153. }
  1154. UINT
  1155. SzICountInstancesOfLcharW (
  1156. IN PCWSTR String,
  1157. IN WCHAR LogChar
  1158. )
  1159. {
  1160. UINT count;
  1161. if (!String) {
  1162. return 0;
  1163. }
  1164. LogChar = towlower (LogChar);
  1165. count = 0;
  1166. while (*String) {
  1167. if (towlower (*String) == LogChar) {
  1168. count++;
  1169. }
  1170. String++;
  1171. }
  1172. return count;
  1173. }
  1174. BOOL
  1175. SzReplaceA (
  1176. IN OUT PSTR Buffer,
  1177. IN SIZE_T MaxSize,
  1178. IN PSTR ReplaceStartPos, // within Buffer
  1179. IN PSTR ReplaceEndPos,
  1180. IN PCSTR NewString
  1181. )
  1182. {
  1183. BOOL result = FALSE;
  1184. SIZE_T oldSubStringLength;
  1185. SIZE_T newSubStringLength;
  1186. SIZE_T currentStringLength;
  1187. SIZE_T offset;
  1188. SIZE_T bytesToMove;
  1189. //
  1190. // Check assumptions.
  1191. //
  1192. MYASSERT(Buffer);
  1193. MYASSERT(ReplaceStartPos && ReplaceStartPos >= Buffer);
  1194. MYASSERT(ReplaceEndPos && ReplaceEndPos >= ReplaceStartPos); //lint !e613
  1195. MYASSERT(ReplaceEndPos <= Buffer + MaxSize); //lint !e613
  1196. MYASSERT(NewString);
  1197. //
  1198. // Compute sizes.
  1199. //
  1200. oldSubStringLength = (PBYTE) ReplaceEndPos - (PBYTE) ReplaceStartPos;
  1201. newSubStringLength = SzByteCountA (NewString);
  1202. currentStringLength = SzSizeA (Buffer);
  1203. offset = newSubStringLength - oldSubStringLength;
  1204. //
  1205. // Make sure there is enough room in the buffer to perform the replace
  1206. // operation.
  1207. //
  1208. if (currentStringLength + offset > MaxSize) {
  1209. DEBUGMSG((DBG_WARNING, "ERROR: Buffer to small to perform string replacement."));
  1210. } else {
  1211. //
  1212. // Shift the rest of the buffer to adjust it to the size of the new string.
  1213. //
  1214. if (offset != 0) {
  1215. //
  1216. // Shift right side of string to make room for new data.
  1217. //
  1218. bytesToMove = currentStringLength;
  1219. bytesToMove -= (PBYTE) ReplaceEndPos - (PBYTE) Buffer;
  1220. MoveMemory (
  1221. (PBYTE) ReplaceEndPos + offset,
  1222. (PBYTE) ReplaceEndPos,
  1223. bytesToMove
  1224. );
  1225. }
  1226. //
  1227. // Now, copy in the string.
  1228. //
  1229. CopyMemory (ReplaceStartPos, NewString, newSubStringLength); //lint !e668
  1230. //
  1231. // String replacement completed successfully.
  1232. //
  1233. result = TRUE;
  1234. }
  1235. return result;
  1236. }
  1237. BOOL
  1238. SzReplaceW (
  1239. IN OUT PWSTR Buffer,
  1240. IN SIZE_T MaxSize,
  1241. IN PWSTR ReplaceStartPos, // within Buffer
  1242. IN PWSTR ReplaceEndPos,
  1243. IN PCWSTR NewString
  1244. )
  1245. {
  1246. BOOL result = FALSE;
  1247. SIZE_T oldSubStringLength;
  1248. SIZE_T newSubStringLength;
  1249. SIZE_T currentStringLength;
  1250. SIZE_T offset;
  1251. SIZE_T bytesToMove;
  1252. //
  1253. // Check assumptions.
  1254. //
  1255. MYASSERT(Buffer);
  1256. MYASSERT(ReplaceStartPos && ReplaceStartPos >= Buffer);
  1257. MYASSERT(ReplaceEndPos && ReplaceEndPos >= ReplaceStartPos); //lint !e613
  1258. MYASSERT(ReplaceEndPos <= Buffer + MaxSize); //lint !e613
  1259. MYASSERT(NewString);
  1260. //
  1261. // Compute sizes.
  1262. //
  1263. oldSubStringLength = (PBYTE) ReplaceEndPos - (PBYTE) ReplaceStartPos;
  1264. newSubStringLength = SzByteCountW (NewString);
  1265. currentStringLength = SzSizeW (Buffer);
  1266. offset = newSubStringLength - oldSubStringLength;
  1267. //
  1268. // Make sure there is enough room in the buffer to perform the replace
  1269. // operation.
  1270. //
  1271. if (currentStringLength + offset > MaxSize) {
  1272. DEBUGMSG((DBG_WARNING, "ERROR: Buffer to small to perform string replacement."));
  1273. } else {
  1274. //
  1275. // Shift the rest of the buffer to adjust it to the size of the new string.
  1276. //
  1277. if (offset != 0) {
  1278. //
  1279. // Shift right side of string to make room for new data.
  1280. //
  1281. bytesToMove = currentStringLength;
  1282. bytesToMove -= (PBYTE) ReplaceEndPos - (PBYTE) Buffer;
  1283. MoveMemory (
  1284. (PBYTE) ReplaceEndPos + offset,
  1285. (PBYTE) ReplaceEndPos,
  1286. bytesToMove
  1287. );
  1288. }
  1289. //
  1290. // Now, copy in the string.
  1291. //
  1292. CopyMemory (ReplaceStartPos, NewString, newSubStringLength); //lint !e668
  1293. //
  1294. // String replacement completed successfully.
  1295. //
  1296. result = TRUE;
  1297. }
  1298. return result;
  1299. }
  1300. UINT
  1301. SzCountInstancesOfSubStringA (
  1302. IN PCSTR SourceString,
  1303. IN PCSTR SearchString
  1304. )
  1305. {
  1306. PCSTR p;
  1307. UINT count;
  1308. UINT searchTchars;
  1309. count = 0;
  1310. p = SourceString;
  1311. searchTchars = SzTcharCountA (SearchString);
  1312. if (!searchTchars) {
  1313. return 0;
  1314. }
  1315. while (p = SzFindSubStringA (p, SearchString)) { //lint !e720
  1316. count++;
  1317. p += searchTchars;
  1318. }
  1319. return count;
  1320. }
  1321. UINT
  1322. SzCountInstancesOfSubStringW (
  1323. IN PCWSTR SourceString,
  1324. IN PCWSTR SearchString
  1325. )
  1326. {
  1327. PCWSTR p;
  1328. UINT count;
  1329. UINT searchTchars;
  1330. count = 0;
  1331. p = SourceString;
  1332. searchTchars = SzTcharCountW (SearchString);
  1333. if (!searchTchars) {
  1334. return 0;
  1335. }
  1336. while (p = SzFindSubStringW (p, SearchString)) { //lint !e720
  1337. count++;
  1338. p += searchTchars;
  1339. }
  1340. return count;
  1341. }
  1342. UINT
  1343. SzICountInstancesOfSubStringA (
  1344. IN PCSTR SourceString,
  1345. IN PCSTR SearchString
  1346. )
  1347. {
  1348. PCSTR p;
  1349. UINT count;
  1350. UINT searchTchars;
  1351. count = 0;
  1352. p = SourceString;
  1353. searchTchars = SzTcharCountA (SearchString);
  1354. if (!searchTchars) {
  1355. return 0;
  1356. }
  1357. while (p = SzIFindSubStringA (p, SearchString)) { //lint !e720
  1358. count++;
  1359. p += searchTchars;
  1360. }
  1361. return count;
  1362. }
  1363. UINT
  1364. SzICountInstancesOfSubStringW (
  1365. IN PCWSTR SourceString,
  1366. IN PCWSTR SearchString
  1367. )
  1368. {
  1369. PCWSTR p;
  1370. UINT count;
  1371. UINT searchTchars;
  1372. count = 0;
  1373. p = SourceString;
  1374. searchTchars = SzTcharCountW (SearchString);
  1375. if (!searchTchars) {
  1376. return 0;
  1377. }
  1378. while (p = SzIFindSubStringW (p, SearchString)) { //lint !e720
  1379. count++;
  1380. p += searchTchars;
  1381. }
  1382. return count;
  1383. }
  1384. BOOL
  1385. MszEnumFirstA (
  1386. OUT PMULTISZ_ENUMA MultiSzEnum,
  1387. IN PCSTR MultiSzStr
  1388. )
  1389. {
  1390. ZeroMemory (MultiSzEnum, sizeof (MULTISZ_ENUMA));
  1391. MultiSzEnum->Buffer = MultiSzStr;
  1392. if ((MultiSzStr == NULL) || (MultiSzStr [0] == 0)) {
  1393. return FALSE;
  1394. }
  1395. MultiSzEnum->CurrentString = MultiSzStr;
  1396. return TRUE;
  1397. }
  1398. BOOL
  1399. MszEnumFirstW (
  1400. OUT PMULTISZ_ENUMW MultiSzEnum,
  1401. IN PCWSTR MultiSzStr
  1402. )
  1403. {
  1404. ZeroMemory (MultiSzEnum, sizeof (MULTISZ_ENUMA));
  1405. MultiSzEnum->Buffer = MultiSzStr;
  1406. if ((MultiSzStr == NULL) || (MultiSzStr [0] == 0)) {
  1407. return FALSE;
  1408. }
  1409. MultiSzEnum->CurrentString = MultiSzStr;
  1410. return TRUE;
  1411. }
  1412. BOOL
  1413. MszEnumNextA (
  1414. IN OUT PMULTISZ_ENUMA MultiSzEnum
  1415. )
  1416. {
  1417. BOOL result = FALSE;
  1418. if (MultiSzEnum->CurrentString && (*MultiSzEnum->CurrentString)) {
  1419. MultiSzEnum->CurrentString = SzGetEndA (MultiSzEnum->CurrentString) + 1;
  1420. result = (MultiSzEnum->CurrentString [0] != 0);
  1421. if (!result) {
  1422. MultiSzEnum->CurrentString = NULL;
  1423. }
  1424. }
  1425. return result;
  1426. }
  1427. BOOL
  1428. MszEnumNextW (
  1429. IN OUT PMULTISZ_ENUMW MultiSzEnum
  1430. )
  1431. {
  1432. BOOL result = FALSE;
  1433. if (MultiSzEnum->CurrentString && (*MultiSzEnum->CurrentString)) {
  1434. MultiSzEnum->CurrentString = SzGetEndW (MultiSzEnum->CurrentString) + 1;
  1435. result = (MultiSzEnum->CurrentString [0] != 0);
  1436. if (!result) {
  1437. MultiSzEnum->CurrentString = NULL;
  1438. }
  1439. }
  1440. return result;
  1441. }
  1442. PCSTR
  1443. MszFindStringA (
  1444. IN PCSTR MultiSz,
  1445. IN PCSTR String
  1446. )
  1447. {
  1448. MULTISZ_ENUMA multiSzEnum;
  1449. ZeroMemory (&multiSzEnum, sizeof (multiSzEnum));
  1450. if (!String || *String == 0) {
  1451. return NULL;
  1452. }
  1453. if (MszEnumFirstA (&multiSzEnum, MultiSz)) {
  1454. do {
  1455. if (SzMatchA (String, multiSzEnum.CurrentString)) {
  1456. break;
  1457. }
  1458. } while (MszEnumNextA (&multiSzEnum));
  1459. }
  1460. return multiSzEnum.CurrentString;
  1461. }
  1462. PCWSTR
  1463. MszFindStringW (
  1464. IN PCWSTR MultiSz,
  1465. IN PCWSTR String
  1466. )
  1467. {
  1468. MULTISZ_ENUMW multiSzEnum;
  1469. ZeroMemory (&multiSzEnum, sizeof (multiSzEnum));
  1470. if (!String || *String == 0) {
  1471. return NULL;
  1472. }
  1473. if (MszEnumFirstW (&multiSzEnum, MultiSz)) {
  1474. do {
  1475. if (SzMatchW (String, multiSzEnum.CurrentString)) {
  1476. break;
  1477. }
  1478. } while (MszEnumNextW (&multiSzEnum));
  1479. }
  1480. return multiSzEnum.CurrentString;
  1481. }
  1482. PCSTR
  1483. MszIFindStringA (
  1484. IN PCSTR MultiSz,
  1485. IN PCSTR String
  1486. )
  1487. {
  1488. MULTISZ_ENUMA multiSzEnum;
  1489. ZeroMemory (&multiSzEnum, sizeof (multiSzEnum));
  1490. if (!String || *String == 0) {
  1491. return NULL;
  1492. }
  1493. if (MszEnumFirstA (&multiSzEnum, MultiSz)) {
  1494. do {
  1495. if (SzIMatchA (String, multiSzEnum.CurrentString)) {
  1496. break;
  1497. }
  1498. } while (MszEnumNextA (&multiSzEnum));
  1499. }
  1500. return multiSzEnum.CurrentString;
  1501. }
  1502. PCWSTR
  1503. MszIFindStringW (
  1504. IN PCWSTR MultiSz,
  1505. IN PCWSTR String
  1506. )
  1507. {
  1508. MULTISZ_ENUMW multiSzEnum;
  1509. ZeroMemory (&multiSzEnum, sizeof (multiSzEnum));
  1510. if (!String || *String == 0) {
  1511. return NULL;
  1512. }
  1513. if (MszEnumFirstW (&multiSzEnum, MultiSz)) {
  1514. do {
  1515. if (SzIMatchW (String, multiSzEnum.CurrentString)) {
  1516. break;
  1517. }
  1518. } while (MszEnumNextW (&multiSzEnum));
  1519. }
  1520. return multiSzEnum.CurrentString;
  1521. }
  1522. PCSTR
  1523. SzConcatenatePathsA (
  1524. IN OUT PSTR PathBuffer,
  1525. IN PCSTR PathSuffix, OPTIONAL
  1526. IN UINT BufferTchars
  1527. )
  1528. /*++
  1529. Routine Description:
  1530. Concatenate two path strings together, supplying a path separator character
  1531. (\) if necessary between the two parts.
  1532. Arguments:
  1533. PathBuffer - Specifies the base path, which can end with a backslash.
  1534. Receives the joined path.
  1535. PathSuffix - Specifies the suffix to concatinate to the base path
  1536. specified by PathBuffer. It can start with a backslash. If NULL is
  1537. specified, then PathBuffer will be terminated with a backslash.
  1538. BufferTchars - Specifies the size, in CHARs (ANSI) or WCHARs (Unicode), of
  1539. PathBuffer. The inbound PathBuffer string must fit within this size.
  1540. If the result is truncated, it will fill the buffer as much as
  1541. possible.
  1542. Return Value:
  1543. A pointer to the end of the string in PathBuffer.
  1544. --*/
  1545. {
  1546. PSTR p;
  1547. PSTR q;
  1548. PSTR end;
  1549. PSTR lastChar;
  1550. PCSTR srcEnd;
  1551. PCSTR nextChar;
  1552. PCSTR srcMax;
  1553. if (!PathBuffer || !BufferTchars) {
  1554. return NULL;
  1555. }
  1556. MYASSERT (BufferTchars > 128); // BUGBUG -- temporary porting aide
  1557. p = SzGetEndA (PathBuffer);
  1558. end = PathBuffer + BufferTchars;
  1559. MYASSERT (p < end); // inbound string must always fit in the buffer
  1560. end--;
  1561. if (p == end) {
  1562. return p; // inbound path fills buffer completely
  1563. }
  1564. lastChar = _mbsdec (PathBuffer, p);
  1565. if ((lastChar < PathBuffer) || (*lastChar != '\\')) {
  1566. *p++ = '\\';
  1567. }
  1568. if (PathSuffix) {
  1569. if (*PathSuffix == '\\') {
  1570. PathSuffix++;
  1571. }
  1572. srcEnd = PathSuffix;
  1573. srcMax = PathSuffix + (end - p);
  1574. while (*srcEnd) {
  1575. nextChar = SzNextCharA (srcEnd);
  1576. if (nextChar > srcMax) {
  1577. break;
  1578. }
  1579. srcEnd = nextChar;
  1580. }
  1581. while (PathSuffix < srcEnd) {
  1582. *p++ = *PathSuffix++;
  1583. }
  1584. }
  1585. *p = 0;
  1586. return p;
  1587. }
  1588. PCWSTR
  1589. SzConcatenatePathsW (
  1590. IN OUT PWSTR PathBuffer,
  1591. IN PCWSTR PathSuffix, OPTIONAL
  1592. IN UINT BufferTchars
  1593. )
  1594. /*++
  1595. Routine Description:
  1596. Concatenate two path strings together, supplying a path separator character
  1597. (\) if necessary between the two parts.
  1598. Arguments:
  1599. PathBuffer - Specifies the base path, which can end with a backslash.
  1600. Receives the joined path.
  1601. PathSuffix - Specifies the suffix to concatinate to the base path
  1602. specified by PathBuffer. It can start with a backslash. If NULL is
  1603. specified, then PathBuffer will be terminated with a backslash.
  1604. BufferTchars - Specifies the size, in CHARs (ANSI) or WCHARs (Unicode), of
  1605. PathBuffer. The inbound PathBuffer string must fit within this size.
  1606. If the result is truncated, it will fill the buffer as much as
  1607. possible.
  1608. Return Value:
  1609. A pointer to the end of the string in PathBuffer.
  1610. --*/
  1611. {
  1612. PWSTR p;
  1613. PWSTR q;
  1614. PWSTR end;
  1615. PWSTR lastChar;
  1616. PCWSTR srcEnd;
  1617. PCWSTR srcMax;
  1618. if (!PathBuffer || !BufferTchars) {
  1619. return NULL;
  1620. }
  1621. MYASSERT (BufferTchars > 128); // BUGBUG -- temporary porting aide
  1622. p = SzGetEndW (PathBuffer);
  1623. end = PathBuffer + BufferTchars;
  1624. MYASSERT (p < end); // inbound string must always fit in the buffer
  1625. end--;
  1626. if (p == end) {
  1627. return p; // inbound path fills buffer completely
  1628. }
  1629. lastChar = p - 1;
  1630. if ((lastChar < PathBuffer) || (*lastChar != L'\\')) {
  1631. *p++ = L'\\';
  1632. }
  1633. if (PathSuffix) {
  1634. if (*PathSuffix == L'\\') {
  1635. PathSuffix++;
  1636. }
  1637. srcEnd = SzGetEndW (PathSuffix);
  1638. srcMax = PathSuffix + (end - p);
  1639. srcEnd = min (srcEnd, srcMax);
  1640. while (PathSuffix < srcEnd) {
  1641. *p++ = *PathSuffix++;
  1642. }
  1643. }
  1644. *p = 0;
  1645. return p;
  1646. }