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.

2028 lines
41 KiB

  1. /*++
  2. Copyright (c) 1995-2001 Microsoft Corporation
  3. Module Name:
  4. string.c
  5. Abstract:
  6. Domain Name System (DNS) Library
  7. DNS string routines.
  8. Author:
  9. Jim Gilroy (jamesg) October 1995
  10. Revision History:
  11. jamesg Jan 1997 UTF-8, Unicode conversions
  12. --*/
  13. #include "local.h"
  14. PSTR
  15. Dns_CreateStringCopy(
  16. IN PCHAR pchString,
  17. IN DWORD cchString
  18. )
  19. /*++
  20. Routine Description:
  21. Create copy of string.
  22. Arguments:
  23. pchString -- ptr to string to copy
  24. cchString -- length of string, if unknown; if NOT given, then pchString
  25. MUST be NULL terminated
  26. Return Value:
  27. Ptr to string copy, if successful
  28. NULL on failure.
  29. --*/
  30. {
  31. LPSTR pstringNew;
  32. DNSDBG( TRACE, ( "Dns_CreateStringCopy()\n" ));
  33. if ( !pchString )
  34. {
  35. SetLastError( ERROR_INVALID_PARAMETER );
  36. return( NULL );
  37. }
  38. // determine string length, if not given
  39. if ( !cchString )
  40. {
  41. cchString = strlen( pchString );
  42. }
  43. // allocate memory
  44. pstringNew = (LPSTR) ALLOCATE_HEAP( cchString+1 );
  45. if ( !pstringNew )
  46. {
  47. SetLastError( DNS_ERROR_NO_MEMORY );
  48. return( NULL );
  49. }
  50. // copy and NULL terminate
  51. RtlCopyMemory(
  52. pstringNew,
  53. pchString,
  54. cchString );
  55. pstringNew[cchString] = 0;
  56. return( pstringNew );
  57. }
  58. DWORD
  59. Dns_GetBufferLengthForStringCopy(
  60. IN PCHAR pchString,
  61. IN DWORD cchString,
  62. IN DNS_CHARSET CharSetIn,
  63. IN DNS_CHARSET CharSetOut
  64. )
  65. /*++
  66. Routine Description:
  67. Determing length required for copy of string.
  68. Arguments:
  69. pchString -- ptr to string to get buffer length for
  70. cchString -- length of string, if known;
  71. - if CharSetIn is unicode, then this is length in wide characters
  72. - if NOT given, then pchString MUST be NULL terminated
  73. CharSetIn -- incoming character set
  74. CharSetOut -- result character set
  75. Return Value:
  76. Buffer length (bytes) required for string, includes space for terminating NULL.
  77. Zero on invalid\unconvertible string. GetLastError() set to ERROR_INVALID_DATA.
  78. --*/
  79. {
  80. INT length;
  81. DNSDBG( TRACE, ( "Dns_GetBufferLengthForStringCopy()\n" ));
  82. if ( !pchString )
  83. {
  84. SetLastError( ERROR_INVALID_PARAMETER );
  85. return( 0 );
  86. }
  87. //
  88. // incoming Unicode
  89. //
  90. if ( CharSetIn == DnsCharSetUnicode )
  91. {
  92. if ( !cchString )
  93. {
  94. cchString = (WORD) wcslen( (PWCHAR)pchString );
  95. }
  96. // unicode to unicode
  97. if ( CharSetOut == DnsCharSetUnicode )
  98. {
  99. return( (cchString+1) * 2 );
  100. }
  101. // unicode to UTF8
  102. //
  103. // use private unicode\utf8 conversion functions
  104. // - superior to public ones (faster, more robust)
  105. // - Win95 does not support CP_UTF8
  106. //
  107. // for unicode-UTF8 there's no invalid string possible
  108. else if ( CharSetOut == DnsCharSetUtf8 )
  109. {
  110. #if 0
  111. length = WideCharToMultiByte(
  112. CP_UTF8,
  113. 0, // no flags
  114. (PWCHAR) pchString,
  115. (INT) cchString,
  116. NULL,
  117. 0, // call determines required buffer length
  118. NULL,
  119. NULL );
  120. #endif
  121. length = Dns_UnicodeToUtf8(
  122. (PWCHAR) pchString,
  123. (INT) cchString,
  124. NULL,
  125. 0
  126. );
  127. ASSERT( length != 0 || cchString == 0 );
  128. return( length + 1 );
  129. }
  130. // unicode to ANSI
  131. // - some chars will NOT convert
  132. else if ( CharSetOut == DnsCharSetAnsi )
  133. {
  134. length = WideCharToMultiByte(
  135. CP_ACP,
  136. 0, // no flags
  137. (PWCHAR) pchString,
  138. (INT) cchString,
  139. NULL,
  140. 0, // call determines required buffer length
  141. NULL,
  142. NULL
  143. );
  144. if ( length == 0 && cchString != 0 )
  145. {
  146. goto Failed;
  147. }
  148. return( length + 1 );
  149. }
  150. // bad CharSetOut drops to Failed
  151. }
  152. //
  153. // incoming UTF8
  154. //
  155. else if ( CharSetIn == DnsCharSetUtf8 )
  156. {
  157. if ( !cchString )
  158. {
  159. cchString = strlen( pchString );
  160. }
  161. // UTF8 to UTF8
  162. if ( CharSetOut == DnsCharSetUtf8 )
  163. {
  164. return( cchString + 1 );
  165. }
  166. // UTF8 to unicode
  167. //
  168. // use private unicode\utf8 conversion functions
  169. // - superior to public ones (faster, more robust)
  170. // - Win95 does not support CP_UTF8
  171. //
  172. // for UTF8 string can be invalid, catch and return error
  173. else if ( CharSetOut == DnsCharSetUnicode )
  174. {
  175. #if 0
  176. length = MultiByteToWideChar(
  177. CP_UTF8,
  178. 0, // no flags
  179. pchString,
  180. (INT) cchString,
  181. NULL,
  182. 0 // call determines required buffer length
  183. );
  184. #endif
  185. length = Dns_Utf8ToUnicode(
  186. pchString,
  187. (INT) cchString,
  188. NULL,
  189. 0
  190. );
  191. if ( length == 0 && cchString != 0 )
  192. {
  193. ASSERT( GetLastError() == ERROR_INVALID_DATA );
  194. return( 0 );
  195. }
  196. return( (length+1)*2 );
  197. }
  198. // UTF8 to ANSI
  199. // - note, result length here is actually buffer length
  200. else if ( CharSetOut == DnsCharSetAnsi )
  201. {
  202. return Dns_Utf8ToAnsi(
  203. pchString,
  204. cchString,
  205. NULL,
  206. 0 );
  207. }
  208. // bad CharSetOut drops to Failed
  209. }
  210. //
  211. // incoming ANSI
  212. //
  213. else if ( CharSetIn == DnsCharSetAnsi )
  214. {
  215. if ( !cchString )
  216. {
  217. cchString = strlen( pchString );
  218. }
  219. // ANSI to ANSI
  220. if ( CharSetOut == DnsCharSetAnsi )
  221. {
  222. return( cchString + 1 );
  223. }
  224. // ANSI to unicode
  225. // - should always succeed
  226. else if ( CharSetOut == DnsCharSetUnicode )
  227. {
  228. length = MultiByteToWideChar(
  229. CP_ACP,
  230. 0, // no flags
  231. pchString,
  232. (INT) cchString,
  233. NULL,
  234. 0 // call determines required buffer length
  235. );
  236. if ( length == 0 && cchString )
  237. {
  238. ASSERT( FALSE );
  239. ASSERT( GetLastError() == ERROR_INVALID_DATA );
  240. goto Failed;
  241. }
  242. return( (length+1) * 2 );
  243. }
  244. // ANSI to UTF8
  245. // - note, result length here is actually buffer length
  246. else if ( CharSetOut == DnsCharSetUtf8 )
  247. {
  248. return Dns_AnsiToUtf8(
  249. pchString,
  250. cchString,
  251. NULL,
  252. 0 );
  253. }
  254. // bad CharSetOut drops to Failed
  255. }
  256. // all unhandled cases are failures
  257. Failed:
  258. DNSDBG( ANY, (
  259. "ERROR: Dns_GetBufferLengthForStringCopy() failed!\n"
  260. "\tpchString = %p (%*s)\n"
  261. "\tcchString = %d\n"
  262. "\tCharSetIn = %d\n"
  263. "\tCharSetOut = %d\n",
  264. pchString,
  265. cchString, pchString,
  266. cchString,
  267. CharSetIn,
  268. CharSetOut ));
  269. SetLastError( ERROR_INVALID_DATA );
  270. return( 0 );
  271. }
  272. DWORD
  273. Dns_StringCopy(
  274. OUT PBYTE pBuffer,
  275. IN OUT PDWORD pdwBufLength,
  276. IN PCHAR pchString,
  277. IN DWORD cchString,
  278. IN DNS_CHARSET CharSetIn,
  279. IN DNS_CHARSET CharSetOut
  280. )
  281. /*++
  282. Routine Description:
  283. Create copy of DNS string.
  284. Arguments:
  285. pBuffer -- buffer to copy to
  286. pdwBufLength -- ptr to length of buffer in bytes;
  287. if NULL, buffer MUST have adequate length
  288. if exists, then copy only completed if *pdwBufLength is adequate
  289. to hold converted result
  290. pchString -- ptr to string to copy
  291. cchString -- length of string, if known;
  292. - if CharSetIn is unicode, then this is length in wide characters
  293. - if NOT given, then pchString MUST be NULL terminated
  294. CharSetIn -- incoming character set
  295. CharSetOut -- result character set
  296. Return Value:
  297. Count of bytes written to buffer (includes terminating NULL).
  298. Zero on error. GetLastError() for status.
  299. --*/
  300. {
  301. INT length;
  302. DWORD bufLength;
  303. DNSDBG( TRACE, ( "Dns_StringCopy()\n" ));
  304. DNSDBG( STRING, (
  305. "Dns_StringCopy()\n"
  306. "\tpBuffer = %p\n"
  307. "\tpdwBufLen = %p\n"
  308. "\tbuf length = %d\n"
  309. "\tpchString = %p\n"
  310. "\tcchString = %d\n"
  311. "\tCharSetIn = %d\n"
  312. "\tCharSetOut = %d\n",
  313. pBuffer,
  314. pdwBufLength,
  315. pdwBufLength ? *pdwBufLength : 0,
  316. pchString,
  317. cchString,
  318. CharSetIn,
  319. CharSetOut ));
  320. if ( !pchString )
  321. {
  322. DNS_ASSERT( FALSE );
  323. SetLastError( ERROR_INVALID_PARAMETER );
  324. return( 0 );
  325. }
  326. //
  327. // find string length
  328. // do this here so don't do it twice if must calculate required buffer length
  329. //
  330. if ( cchString == 0 )
  331. {
  332. if ( CharSetIn == DnsCharSetUnicode )
  333. {
  334. cchString = (WORD) wcslen( (PWCHAR)pchString );
  335. }
  336. else
  337. {
  338. cchString = strlen( pchString );
  339. }
  340. }
  341. //
  342. // verify adequate buffer length
  343. //
  344. // DCR_PERF: ideally make direct copy to buffer and fail if
  345. // over length, rather than effectively having to convert
  346. // twice
  347. //
  348. if ( pdwBufLength )
  349. {
  350. bufLength = Dns_GetBufferLengthForStringCopy(
  351. pchString,
  352. cchString,
  353. CharSetIn,
  354. CharSetOut );
  355. if ( bufLength == 0 )
  356. {
  357. SetLastError( ERROR_INVALID_DATA );
  358. *pdwBufLength = 0;
  359. return( 0 );
  360. }
  361. if ( bufLength > *pdwBufLength )
  362. {
  363. SetLastError( ERROR_MORE_DATA );
  364. *pdwBufLength = bufLength;
  365. return( 0 );
  366. }
  367. *pdwBufLength = bufLength;
  368. }
  369. //
  370. // incoming unicode string
  371. //
  372. if ( CharSetIn == DnsCharSetUnicode )
  373. {
  374. // unicode to unicode straight copy
  375. // - correct for length in wide characters
  376. if ( CharSetOut == DnsCharSetUnicode )
  377. {
  378. ((PWORD)pBuffer)[ cchString ] = 0;
  379. cchString *= 2;
  380. RtlCopyMemory(
  381. pBuffer,
  382. pchString,
  383. cchString );
  384. return( cchString+2 );
  385. }
  386. // unicode => UTF8
  387. //
  388. // use private unicode\utf8 conversion functions
  389. // - superior to public ones (faster, more robust)
  390. // - Win95 does not support CP_UTF8
  391. //
  392. // for unicode-UTF8 there's no invalid string possible
  393. else if ( CharSetOut == DnsCharSetUtf8 )
  394. {
  395. #if 0
  396. length = WideCharToMultiByte(
  397. CP_UTF8,
  398. 0, // no flags
  399. (PWCHAR) pchString,
  400. (INT) cchString,
  401. pBuffer,
  402. MAXWORD, // assuming adequate length
  403. NULL,
  404. NULL );
  405. #endif
  406. length = Dns_UnicodeToUtf8(
  407. (LPWSTR) pchString,
  408. cchString,
  409. pBuffer,
  410. MAXWORD // assuming adequate length
  411. );
  412. ASSERT( length != 0 || cchString == 0 );
  413. pBuffer[ length ] = 0;
  414. return( length + 1 );
  415. }
  416. // unicode => ANSI
  417. // - this conversion can fail
  418. else if ( CharSetOut == DnsCharSetAnsi )
  419. {
  420. length = WideCharToMultiByte(
  421. CP_ACP,
  422. 0, // no flags
  423. (PWCHAR) pchString,
  424. (INT) cchString,
  425. pBuffer,
  426. MAXWORD, // assuming adequate length
  427. NULL,
  428. NULL );
  429. if ( length == 0 && cchString != 0 )
  430. {
  431. goto Failed;
  432. }
  433. pBuffer[ length ] = 0;
  434. return( length + 1 );
  435. }
  436. // bad CharSetOut drops to Failed
  437. }
  438. //
  439. // incoming UTF8
  440. //
  441. if ( CharSetIn == DnsCharSetUtf8 )
  442. {
  443. // UTF8 to UTF8 straight copy
  444. if ( CharSetOut == DnsCharSetUtf8 )
  445. {
  446. memcpy(
  447. pBuffer,
  448. pchString,
  449. cchString );
  450. pBuffer[cchString] = 0;
  451. return( cchString + 1 );
  452. }
  453. // UTF8 to unicode conversion
  454. //
  455. // use private unicode\utf8 conversion functions
  456. // - superior to public ones (faster, more robust)
  457. // - Win95 does not support CP_UTF8
  458. //
  459. // UTF8 strings can be invalid, and since sending in "infinite"
  460. // buffer, this is only possible error
  461. else if ( CharSetOut == DnsCharSetUnicode )
  462. {
  463. #if 0
  464. length = MultiByteToWideChar(
  465. CP_UTF8,
  466. 0, // no flags
  467. (PCHAR) pchString,
  468. (INT) cchString,
  469. (PWCHAR) pBuffer,
  470. MAXWORD // assuming adequate length
  471. );
  472. #endif
  473. length = Dns_Utf8ToUnicode(
  474. pchString,
  475. cchString,
  476. (LPWSTR) pBuffer,
  477. MAXWORD
  478. );
  479. if ( length == 0 && cchString != 0 )
  480. {
  481. ASSERT( GetLastError() == ERROR_INVALID_DATA );
  482. goto Failed;
  483. }
  484. ((PWORD)pBuffer)[length] = 0;
  485. return( (length+1) * 2 );
  486. }
  487. // UTF8 to ANSI
  488. // - note, result length here is actually buffer length
  489. else if ( CharSetOut == DnsCharSetAnsi )
  490. {
  491. length = Dns_Utf8ToAnsi(
  492. pchString,
  493. cchString,
  494. pBuffer,
  495. MAXWORD );
  496. if ( length == 0 )
  497. {
  498. goto Failed;
  499. }
  500. return( length );
  501. }
  502. // bad CharSetOut drops to Failed
  503. }
  504. //
  505. // incoming ANSI
  506. //
  507. if ( CharSetIn == DnsCharSetAnsi )
  508. {
  509. // ANSI to ANSI straight copy
  510. if ( CharSetOut == DnsCharSetAnsi )
  511. {
  512. memcpy(
  513. pBuffer,
  514. pchString,
  515. cchString );
  516. pBuffer[cchString] = 0;
  517. return( cchString + 1 );
  518. }
  519. // ANSI to unicode conversion
  520. // - ANSI to unicode should not fail
  521. else if ( CharSetOut == DnsCharSetUnicode )
  522. {
  523. length = MultiByteToWideChar(
  524. CP_ACP,
  525. 0, // no flags
  526. (PCHAR) pchString,
  527. (INT) cchString,
  528. (PWCHAR) pBuffer,
  529. MAXWORD // assuming adequate length
  530. );
  531. if ( length == 0 && cchString )
  532. {
  533. ASSERT( FALSE );
  534. ASSERT( GetLastError() == ERROR_INVALID_DATA );
  535. goto Failed;
  536. }
  537. ((PWORD)pBuffer)[length] = 0;
  538. return( (length+1) * 2 );
  539. }
  540. // ANSI to UTF8
  541. // - note, result length here is actually buffer length
  542. else if ( CharSetOut == DnsCharSetUtf8 )
  543. {
  544. length = Dns_AnsiToUtf8(
  545. pchString,
  546. cchString,
  547. pBuffer,
  548. MAXWORD );
  549. if ( length == 0 )
  550. {
  551. goto Failed;
  552. }
  553. return( length );
  554. }
  555. // bad CharSetOut drops to Failed
  556. }
  557. // all unhandled cases are failures
  558. Failed:
  559. DNSDBG( ANY, (
  560. "ERROR: Dns_StringCopy() failed!\n"
  561. "\tpBuffer = %p\n"
  562. "\tpdwBufLen = %p\n"
  563. "\tbuf length = %d\n"
  564. "\tpchString = %p (%*s)\n"
  565. "\tcchString = %d\n"
  566. "\tCharSetIn = %d\n"
  567. "\tCharSetOut = %d\n",
  568. pBuffer,
  569. pdwBufLength,
  570. pdwBufLength ? *pdwBufLength : 0,
  571. pchString,
  572. cchString, pchString,
  573. cchString,
  574. CharSetIn,
  575. CharSetOut ));
  576. SetLastError( ERROR_INVALID_DATA );
  577. return( 0 );
  578. }
  579. PVOID
  580. Dns_StringCopyAllocate(
  581. IN PCHAR pchString,
  582. IN DWORD cchString,
  583. IN DNS_CHARSET CharSetIn,
  584. IN DNS_CHARSET CharSetOut
  585. )
  586. /*++
  587. Routine Description:
  588. Create copy of DNS string
  589. Arguments:
  590. pchString -- ptr to string to copy
  591. cchString -- length of string, if known;
  592. - if CharSetIn, then this is length in wide characters
  593. - if NOT given, then pchString MUST be NULL terminated
  594. CharSetIn -- flag indicates incoming string is unicode
  595. CharSetOut -- flag indicates copy will be in unicode format
  596. Return Value:
  597. Ptr to string copy, if successful
  598. NULL on failure.
  599. --*/
  600. {
  601. PCHAR pnew;
  602. DWORD length;
  603. DNSDBG( TRACE, ( "Dns_StringCopyAllocate()\n" ));
  604. DNSDBG( STRING, (
  605. "Dns_StringCopyAllocate( %.*s )\n"
  606. "\tpchString = %p\n"
  607. "\tcchString = %d\n"
  608. "\tUnicodeIn = %d\n"
  609. "\tUnicodeOut = %d\n",
  610. cchString,
  611. pchString,
  612. pchString,
  613. cchString,
  614. CharSetIn,
  615. CharSetOut ));
  616. if ( !pchString )
  617. {
  618. // For parity with other string routines, do not treat NULL argument
  619. // as an event worth of assert.
  620. // DNS_ASSERT( FALSE );
  621. SetLastError( ERROR_INVALID_PARAMETER );
  622. return( NULL );
  623. }
  624. //
  625. // determine incoming string length
  626. // do this explicitly to avoid doing string length operations twice
  627. //
  628. if ( !cchString )
  629. {
  630. if ( CharSetIn == DnsCharSetUnicode )
  631. {
  632. cchString = (WORD) wcslen( (PWCHAR)pchString );
  633. }
  634. else
  635. {
  636. cchString = strlen( pchString );
  637. }
  638. }
  639. //
  640. // determine required buffer length and allocate
  641. //
  642. length = Dns_GetBufferLengthForStringCopy(
  643. pchString,
  644. cchString,
  645. CharSetIn,
  646. CharSetOut );
  647. if ( length == 0 )
  648. {
  649. ASSERT( CharSetIn && CharSetOut && GetLastError() == ERROR_INVALID_DATA );
  650. SetLastError( ERROR_INVALID_DATA );
  651. return( NULL );
  652. }
  653. pnew = (PVOID) ALLOCATE_HEAP( length );
  654. if ( !pnew )
  655. {
  656. SetLastError( DNS_ERROR_NO_MEMORY );
  657. return( NULL );
  658. }
  659. //
  660. // copy \ convert string
  661. // - can fail if conversion not valid
  662. // (ex. bogus UTF8 string, or attempting
  663. // conversion from ANSI to UTF8)
  664. //
  665. if ( ! Dns_StringCopy(
  666. pnew,
  667. NULL,
  668. pchString,
  669. cchString,
  670. CharSetIn,
  671. CharSetOut ) )
  672. {
  673. FREE_HEAP( pnew );
  674. return( NULL );
  675. }
  676. return( pnew );
  677. }
  678. //
  679. // Simple create string copy utilities.
  680. //
  681. PSTR
  682. Dns_CreateStringCopy_A(
  683. IN PCSTR pszString
  684. )
  685. /*++
  686. Routine Description:
  687. Create copy of string.
  688. Simple wrapper to handle
  689. - sizing
  690. - memory allocation
  691. - copy of string
  692. Arguments:
  693. pszString -- ptr to string to copy
  694. Return Value:
  695. Ptr to string copy, if successful
  696. NULL on failure.
  697. --*/
  698. {
  699. PSTR pnew;
  700. DWORD length;
  701. DNSDBG( TRACE, ( "Dns_CreateStringCopy_A( %s )\n", pszString ));
  702. if ( !pszString )
  703. {
  704. SetLastError( ERROR_INVALID_PARAMETER );
  705. return( NULL );
  706. }
  707. // determine string length, if not given
  708. length = strlen( pszString ) + 1;
  709. // allocate memory
  710. pnew = (LPSTR) ALLOCATE_HEAP( length );
  711. if ( !pnew )
  712. {
  713. SetLastError( DNS_ERROR_NO_MEMORY );
  714. return( NULL );
  715. }
  716. // copy and NULL terminate
  717. RtlCopyMemory(
  718. pnew,
  719. pszString,
  720. length );
  721. return( pnew );
  722. }
  723. PWSTR
  724. Dns_CreateStringCopy_W(
  725. IN PCWSTR pwsString
  726. )
  727. {
  728. PWSTR pnew;
  729. DWORD length;
  730. DNSDBG( TRACE, ( "Dns_CreateStringCopy_W( %S )\n", pwsString ));
  731. if ( !pwsString )
  732. {
  733. SetLastError( ERROR_INVALID_PARAMETER );
  734. return( NULL );
  735. }
  736. // allocate memory
  737. length = (wcslen( pwsString ) + 1) * sizeof(WCHAR);
  738. pnew = (PWSTR) ALLOCATE_HEAP( length );
  739. if ( !pnew )
  740. {
  741. SetLastError( DNS_ERROR_NO_MEMORY );
  742. return( NULL );
  743. }
  744. // copy and NULL terminate
  745. RtlCopyMemory(
  746. pnew,
  747. pwsString,
  748. length );
  749. return( pnew );
  750. }
  751. PWSTR
  752. Dns_CreateConcatenatedString_W(
  753. IN PCWSTR * pStringArray
  754. )
  755. /*++
  756. Routine Description:
  757. Create concatenated string.
  758. Arguments:
  759. pStringArray -- array of string pointers to concat
  760. NULL pointer terminates array
  761. Return Value:
  762. Ptr to concantenated string copy, if successful
  763. NULL on failure.
  764. --*/
  765. {
  766. PWSTR pnew;
  767. PCWSTR pwstr;
  768. DWORD length;
  769. DWORD iter;
  770. DNSDBG( TRACE, ( "Dns_CreateConcatenatedString_W()\n" ));
  771. if ( !pStringArray )
  772. {
  773. SetLastError( ERROR_INVALID_PARAMETER );
  774. return( NULL );
  775. }
  776. //
  777. // loop determining required length
  778. //
  779. length = 1;
  780. iter = 0;
  781. while ( pwstr = pStringArray[iter++] )
  782. {
  783. length += wcslen( pwstr );
  784. }
  785. //
  786. // allocate
  787. //
  788. pnew = (PWSTR) ALLOCATE_HEAP( length*sizeof(WCHAR) );
  789. if ( !pnew )
  790. {
  791. SetLastError( DNS_ERROR_NO_MEMORY );
  792. return NULL;
  793. }
  794. //
  795. // write concatented string
  796. //
  797. pnew[0] = 0;
  798. iter = 0;
  799. while ( pwstr = pStringArray[iter++] )
  800. {
  801. wcscat( pnew, pwstr );
  802. }
  803. DNSDBG( TRACE, ( "Concatented string = %S\n", pnew ));
  804. return pnew;
  805. }
  806. //
  807. // MULTI_SZ routines
  808. //
  809. DWORD
  810. MultiSz_Size_A(
  811. IN PCSTR pmszString
  812. )
  813. /*++
  814. Routine Description:
  815. Determine length (size) of MULTI_SZ string.
  816. Arguments:
  817. pmszString -- ptr to string to size
  818. Return Value:
  819. Size of MULTI_SZ string (in bytes).
  820. Includes terminating double NULL.
  821. --*/
  822. {
  823. PSTR pnext;
  824. DWORD lengthTotal = 0;
  825. DWORD length;
  826. DNSDBG( TRACE, ( "MultiSz_Size_A( %s )\n", pmszString ));
  827. //
  828. // loop until read at end of strings
  829. //
  830. // when we reach the end, we'll be pointing at the second
  831. // zero in the double null terminator; strlen() will return
  832. // zero, and we'll add that to our count as 1 and exit
  833. //
  834. pnext = (PSTR) pmszString;
  835. while ( pnext )
  836. {
  837. length = strlen( pnext ) + 1;
  838. lengthTotal += length;
  839. if ( length == 1 )
  840. {
  841. break;
  842. }
  843. pnext += length;
  844. }
  845. return lengthTotal;
  846. }
  847. PSTR
  848. MultiSz_NextString_A(
  849. IN PCSTR pmszString
  850. )
  851. /*++
  852. Routine Description:
  853. Find next string in MULTI_SZ string
  854. Arguments:
  855. pmszString -- ptr to multi string
  856. Return Value:
  857. Next string in MULTI_SZ string.
  858. NULL if no strings left.
  859. --*/
  860. {
  861. PSTR pnext;
  862. DWORD length;
  863. DNSDBG( TRACE, ( "MultiSz_NextString_A( %s )\n", pmszString ));
  864. //
  865. // find next string in multi-string
  866. // - find length of current string
  867. // - hop over it (inc. null)
  868. // - if pointing at terminating double-null return
  869. // NULL to signal end
  870. //
  871. pnext = (PSTR) pmszString;
  872. if ( !pnext )
  873. {
  874. return NULL;
  875. }
  876. length = strlen( pnext );
  877. if ( length == 0 )
  878. {
  879. DNSDBG( ANY, (
  880. "ERROR: MultiSz_Next(%p) called on terminator!\n",
  881. pmszString ));
  882. return NULL;
  883. }
  884. pnext += length + 1;
  885. if ( *pnext == 0 )
  886. {
  887. return NULL;
  888. }
  889. return pnext;
  890. }
  891. PSTR
  892. MultiSz_Copy_A(
  893. IN PCSTR pmszString
  894. )
  895. /*++
  896. Routine Description:
  897. Create copy of MULTI_SZ string.
  898. Simple wrapper to handle
  899. - sizing
  900. - memory allocation
  901. - copy of string
  902. Arguments:
  903. pmszString -- ptr to string to copy
  904. Return Value:
  905. Ptr to string copy, if successful
  906. NULL on failure.
  907. --*/
  908. {
  909. PSTR pnew;
  910. DWORD length;
  911. DNSDBG( TRACE, ( "MultiSz_Copy_A( %s )\n", pmszString ));
  912. if ( !pmszString )
  913. {
  914. SetLastError( ERROR_INVALID_PARAMETER );
  915. return( NULL );
  916. }
  917. // determine string length, if not given
  918. length = MultiSz_Size_A( pmszString );
  919. // allocate memory
  920. pnew = (LPSTR) ALLOCATE_HEAP( length );
  921. if ( !pnew )
  922. {
  923. SetLastError( DNS_ERROR_NO_MEMORY );
  924. return( NULL );
  925. }
  926. // copy and NULL terminate
  927. RtlCopyMemory(
  928. pnew,
  929. pmszString,
  930. length );
  931. return( pnew );
  932. }
  933. BOOL
  934. MultiSz_Equal_A(
  935. IN PCSTR pmszString1,
  936. IN PCSTR pmszString2
  937. )
  938. /*++
  939. Routine Description:
  940. Compare two MULTI_SZ strings.
  941. Arguments:
  942. pmszString1 -- ptr to string
  943. pmszString2 -- ptr to string
  944. Return Value:
  945. TRUE -- if strings equal
  946. FALSE -- if strings different
  947. --*/
  948. {
  949. DWORD length1;
  950. DWORD length2;
  951. DNSDBG( TRACE, (
  952. "MultiSz_Equal_A( %s, %s )\n",
  953. pmszString1,
  954. pmszString2
  955. ));
  956. //
  957. // non-existence cases
  958. //
  959. if ( !pmszString1 )
  960. {
  961. return !pmszString2;
  962. }
  963. if ( !pmszString2 )
  964. {
  965. return !pmszString1;
  966. }
  967. //
  968. // length check
  969. //
  970. length1 = MultiSz_Size_A( pmszString1 );
  971. length2 = MultiSz_Size_A( pmszString2 );
  972. if ( length1 != length2 )
  973. {
  974. return FALSE;
  975. }
  976. //
  977. // memory check
  978. //
  979. return RtlEqualMemory(
  980. pmszString1,
  981. pmszString2,
  982. length1 );
  983. }
  984. //
  985. // MULTI_SZ routines -- in wide char
  986. //
  987. DWORD
  988. MultiSz_Size_W(
  989. IN PCWSTR pmszString
  990. )
  991. /*++
  992. Routine Description:
  993. Determine size of MULTI_SZ string.
  994. Arguments:
  995. pmszString -- ptr to string to size
  996. Return Value:
  997. Size of MULTI_SZ string (in bytes).
  998. Includes terminating double NULL.
  999. --*/
  1000. {
  1001. PWSTR pnext;
  1002. DWORD lengthTotal = 0;
  1003. DWORD length;
  1004. DNSDBG( TRACE, ( "MultiSz_Size_W( %S )\n", pmszString ));
  1005. //
  1006. // loop until read at end of strings
  1007. //
  1008. // when we reach the end, we'll be pointing at the second
  1009. // zero in the double null terminator; strlen() will return
  1010. // zero, and we'll add that to our count as 1 and exit
  1011. //
  1012. pnext = (PWSTR) pmszString;
  1013. while ( pnext )
  1014. {
  1015. length = wcslen( pnext ) + 1;
  1016. lengthTotal += length;
  1017. if ( length == 1 )
  1018. {
  1019. break;
  1020. }
  1021. pnext += length;
  1022. }
  1023. return lengthTotal * sizeof(WCHAR);
  1024. }
  1025. PWSTR
  1026. MultiSz_NextString_W(
  1027. IN PCWSTR pmszString
  1028. )
  1029. /*++
  1030. Routine Description:
  1031. Find next string in MULTI_SZ string
  1032. Arguments:
  1033. pmszString -- ptr to multi string
  1034. Return Value:
  1035. Next string in MULTI_SZ string.
  1036. NULL if no strings left.
  1037. --*/
  1038. {
  1039. PWSTR pnext;
  1040. DWORD length;
  1041. DNSDBG( TRACE, ( "MultiSz_NextString_W( %S )\n", pmszString ));
  1042. //
  1043. // find next string in multi-string
  1044. // - find length of current string
  1045. // - hop over it (inc. null)
  1046. // - if pointing at terminating double-null return
  1047. // NULL to signal end
  1048. //
  1049. pnext = (PWSTR) pmszString;
  1050. if ( !pnext )
  1051. {
  1052. return NULL;
  1053. }
  1054. length = wcslen( pnext );
  1055. if ( length == 0 )
  1056. {
  1057. DNSDBG( ANY, (
  1058. "ERROR: MultiSz_Next(%p) called on terminator!\n",
  1059. pmszString ));
  1060. return NULL;
  1061. }
  1062. pnext += length + 1;
  1063. if ( *pnext == 0 )
  1064. {
  1065. return NULL;
  1066. }
  1067. return pnext;
  1068. }
  1069. PWSTR
  1070. MultiSz_Copy_W(
  1071. IN PCWSTR pmszString
  1072. )
  1073. /*++
  1074. Routine Description:
  1075. Create copy of MULTI_SZ string.
  1076. Simple wrapper to handle
  1077. - sizing
  1078. - memory allocation
  1079. - copy of string
  1080. Arguments:
  1081. pmszString -- ptr to string to copy
  1082. Return Value:
  1083. Ptr to string copy, if successful
  1084. NULL on failure.
  1085. --*/
  1086. {
  1087. PWSTR pnew;
  1088. DWORD length;
  1089. DNSDBG( TRACE, ( "MultiSz_Copy_W( %S )\n", pmszString ));
  1090. if ( !pmszString )
  1091. {
  1092. SetLastError( ERROR_INVALID_PARAMETER );
  1093. return( NULL );
  1094. }
  1095. // determine string length, if not given
  1096. length = MultiSz_Size_W( pmszString );
  1097. // allocate memory
  1098. pnew = (PWSTR) ALLOCATE_HEAP( length );
  1099. if ( !pnew )
  1100. {
  1101. SetLastError( DNS_ERROR_NO_MEMORY );
  1102. return( NULL );
  1103. }
  1104. // copy and NULL terminate
  1105. RtlCopyMemory(
  1106. pnew,
  1107. pmszString,
  1108. length );
  1109. return( pnew );
  1110. }
  1111. BOOL
  1112. MultiSz_Equal_W(
  1113. IN PCWSTR pmszString1,
  1114. IN PCWSTR pmszString2
  1115. )
  1116. /*++
  1117. Routine Description:
  1118. Compare two MULTI_SZ strings.
  1119. Arguments:
  1120. pmszString1 -- ptr to string
  1121. pmszString2 -- ptr to string
  1122. Return Value:
  1123. TRUE -- if strings equal
  1124. FALSE -- if strings different
  1125. --*/
  1126. {
  1127. DWORD length1;
  1128. DWORD length2;
  1129. DNSDBG( TRACE, (
  1130. "MultiSz_Equal_W( %s, %s )\n",
  1131. pmszString1,
  1132. pmszString2
  1133. ));
  1134. //
  1135. // non-existence cases
  1136. //
  1137. if ( !pmszString1 )
  1138. {
  1139. return !pmszString2;
  1140. }
  1141. if ( !pmszString2 )
  1142. {
  1143. return !pmszString1;
  1144. }
  1145. //
  1146. // length check
  1147. //
  1148. length1 = MultiSz_Size_W( pmszString1 );
  1149. length2 = MultiSz_Size_W( pmszString2 );
  1150. if ( length1 != length2 )
  1151. {
  1152. return FALSE;
  1153. }
  1154. //
  1155. // memory check
  1156. //
  1157. return RtlEqualMemory(
  1158. pmszString1,
  1159. pmszString2,
  1160. length1 );
  1161. }
  1162. BOOL
  1163. MultiSz_ContainsName_W(
  1164. IN PCWSTR pmszString,
  1165. IN PCWSTR pString
  1166. )
  1167. /*++
  1168. Routine Description:
  1169. Check if MULTISZ string contains a string.
  1170. Arguments:
  1171. pmszString -- multisz string
  1172. pString -- string to check
  1173. Return Value:
  1174. TRUE if string is in multisz.
  1175. FALSE otherwise.
  1176. --*/
  1177. {
  1178. PCWSTR pstr = pmszString;
  1179. //
  1180. // check each string
  1181. //
  1182. while ( pstr )
  1183. {
  1184. if ( Dns_NameCompare_W(
  1185. pstr,
  1186. pString ) )
  1187. {
  1188. return TRUE;
  1189. }
  1190. pstr = MultiSz_NextString_W( pstr );
  1191. }
  1192. return FALSE;
  1193. }
  1194. //
  1195. // Random
  1196. //
  1197. INT
  1198. wcsicmp_ThatWorks(
  1199. IN PWSTR pString1,
  1200. IN PWSTR pString2
  1201. )
  1202. /*++
  1203. Routine Description:
  1204. A version of wcsicmp that actually works.
  1205. This is just a wrapped on CompareStringW, to hide all the detail
  1206. and give an interface identical to wcsicmp().
  1207. It uses US English to standardize the comparison.
  1208. Arguments:
  1209. pString1 -- first string; must be NULL terminated
  1210. pString2 -- first second; must be NULL terminated
  1211. Return Value:
  1212. -1 -- if string 1 less than string 2
  1213. 0 -- strings are equal
  1214. 1 -- if string 1 greater than string 2
  1215. --*/
  1216. {
  1217. INT result;
  1218. //
  1219. // compare
  1220. // - case conversion done in default DNS locale -- US English
  1221. // this locale correctly matches most non-locale sensitive
  1222. // upper-lower characters
  1223. //
  1224. result = CompareStringW(
  1225. DNS_DEFAULT_LOCALE,
  1226. NORM_IGNORECASE,
  1227. pString1,
  1228. (-1), // NULL terminated
  1229. pString2,
  1230. (-1) // NULL terminated
  1231. );
  1232. if ( result == CSTR_EQUAL )
  1233. {
  1234. result = 0;
  1235. }
  1236. else if ( result == CSTR_LESS_THAN )
  1237. {
  1238. result = -1;
  1239. }
  1240. else // greater than or error
  1241. {
  1242. result = 1;
  1243. }
  1244. return( result );
  1245. }
  1246. LPWSTR
  1247. Dns_GetResourceString(
  1248. IN DWORD dwStringId,
  1249. IN OUT LPWSTR pwszBuffer,
  1250. IN DWORD cbBuffer
  1251. )
  1252. /*++
  1253. Routine Description:
  1254. Loads a string (defined in dnsmsg.mc) from current module
  1255. Arguments:
  1256. dwStringId -- The ID of the string to be fetched
  1257. Return Value:
  1258. DCR: kill off eyal function
  1259. DEVNOTE: don't understand the value of this return
  1260. -- it's essentially a BOOL, we already know what the ptr is
  1261. it's the buffer passed in
  1262. -- ptr to next byte is useful in continuous write situation
  1263. (ugly and useless in others)
  1264. -- better would just be the same return as LoadString, so we
  1265. both get the success\failure indication and also know
  1266. how many bytes forward we must push our buffer ptr if
  1267. we want to write more
  1268. Error: NULL
  1269. Success: a pointer to the loaded string
  1270. --*/
  1271. {
  1272. LPWSTR pStr = NULL;
  1273. DWORD status;
  1274. HANDLE hMod;
  1275. DNSDBG( TRACE, (
  1276. "Dns_GetStringResource()\n" ));
  1277. // Get module handle-- No need to close handle, it is just a ptr w/o increment on ref count.
  1278. hMod = GetModuleHandle( NULL );
  1279. if ( !hMod )
  1280. {
  1281. ASSERT( hMod );
  1282. return NULL;
  1283. }
  1284. status = LoadStringW(
  1285. hMod,
  1286. dwStringId,
  1287. pwszBuffer,
  1288. cbBuffer );
  1289. if ( status != 0 )
  1290. {
  1291. pStr = pwszBuffer;
  1292. }
  1293. ELSE
  1294. {
  1295. // LoadString returns # of bytes loaded, convert to error.
  1296. status = GetLastError();
  1297. DNSDBG( TRACE, (
  1298. "Error <%lu>: Failed to load string %d\n",
  1299. status, dwStringId ));
  1300. ASSERT ( FALSE );
  1301. }
  1302. DNSDBG( TRACE, (
  1303. "Exit <0x%p> Dns_GetStringResource\n",
  1304. pStr ));
  1305. return pStr;
  1306. }
  1307. DWORD
  1308. String_ReplaceCharW(
  1309. IN OUT PWSTR pString,
  1310. IN WCHAR TargetChar,
  1311. IN WCHAR ReplaceChar
  1312. )
  1313. /*++
  1314. Routine Description:
  1315. Replace a characater in the string with another character.
  1316. Arguments:
  1317. pString -- string
  1318. TargetChar -- character to replace
  1319. ReplaceChar -- character that replaces TargetChar
  1320. Return Value:
  1321. Count of replacements.
  1322. --*/
  1323. {
  1324. PWCHAR pch;
  1325. WCHAR ch;
  1326. DWORD countReplace= 0;
  1327. //
  1328. // loop matching and replacing TargetChar
  1329. //
  1330. pch = pString - 1;
  1331. while ( ch = *++pch )
  1332. {
  1333. if ( ch == TargetChar )
  1334. {
  1335. *pch = ReplaceChar;
  1336. countReplace++;
  1337. }
  1338. }
  1339. return countReplace;
  1340. }
  1341. DWORD
  1342. String_ReplaceCharA(
  1343. IN OUT PSTR pString,
  1344. IN CHAR TargetChar,
  1345. IN CHAR ReplaceChar
  1346. )
  1347. /*++
  1348. Routine Description:
  1349. Replace a characater in the string with another character.
  1350. Arguments:
  1351. pString -- string
  1352. TargetChar -- character to replace
  1353. ReplaceChar -- character that replaces TargetChar
  1354. Return Value:
  1355. Count of replacements.
  1356. --*/
  1357. {
  1358. PCHAR pch;
  1359. CHAR ch;
  1360. DWORD countReplace= 0;
  1361. //
  1362. // loop matching and replacing TargetChar
  1363. //
  1364. pch = pString - 1;
  1365. while ( ch = *++pch )
  1366. {
  1367. if ( ch == TargetChar )
  1368. {
  1369. *pch = ReplaceChar;
  1370. countReplace++;
  1371. }
  1372. }
  1373. return countReplace;
  1374. }
  1375. DWORD
  1376. Dns_TokenizeStringA(
  1377. IN OUT PSTR pBuffer,
  1378. OUT PCHAR * Argv,
  1379. IN DWORD MaxArgs
  1380. )
  1381. /*++
  1382. Routine Description:
  1383. Tokenize buffer Argv/Argc form.
  1384. Arguments:
  1385. pBuffer -- string buffer to tokenize
  1386. Argv -- argv array
  1387. MaxArgs -- max size of Argv array
  1388. Return Value:
  1389. Response code corresponding to status, if found.
  1390. Zero otherwise.
  1391. --*/
  1392. {
  1393. DWORD count = 0;
  1394. PCHAR pstring = pBuffer;
  1395. //
  1396. // tokenize string
  1397. // - note that after the first call strtok
  1398. // takes NULL ptr to continue tokening same string
  1399. //
  1400. while ( count < MaxArgs )
  1401. {
  1402. PCHAR pch;
  1403. pch = strtok( pstring, " \t\r\n" );
  1404. if ( !pch )
  1405. {
  1406. break;
  1407. }
  1408. Argv[ count++ ] = pch;
  1409. pstring = NULL;
  1410. }
  1411. return count;
  1412. }
  1413. DWORD
  1414. Dns_TokenizeStringW(
  1415. IN OUT PWSTR pBuffer,
  1416. OUT PWCHAR * Argv,
  1417. IN DWORD MaxArgs
  1418. )
  1419. /*++
  1420. Routine Description:
  1421. Tokenize buffer Argv/Argc form.
  1422. Arguments:
  1423. pBuffer -- string buffer to tokenize
  1424. Argv -- argv array
  1425. MaxArgs -- max size of Argv array
  1426. Return Value:
  1427. Response code corresponding to status, if found.
  1428. Zero otherwise.
  1429. --*/
  1430. {
  1431. DWORD count = 0;
  1432. PWCHAR pstring = pBuffer;
  1433. //
  1434. // tokenize string
  1435. // - note that after the first call strtok
  1436. // takes NULL ptr to continue tokening same string
  1437. //
  1438. while ( count < MaxArgs )
  1439. {
  1440. PWCHAR pch;
  1441. pch = wcstok( pstring, L" \t\r\n" );
  1442. if ( !pch )
  1443. {
  1444. break;
  1445. }
  1446. Argv[ count++ ] = pch;
  1447. pstring = NULL;
  1448. }
  1449. return count;
  1450. }
  1451. PSTR *
  1452. Argv_CopyEx(
  1453. IN DWORD Argc,
  1454. IN PCHAR * Argv,
  1455. IN DNS_CHARSET CharSetIn,
  1456. IN DNS_CHARSET CharSetOut
  1457. )
  1458. /*++
  1459. Routine Description:
  1460. Convert reate ANSI argv from unicode argv.
  1461. Arguments:
  1462. Argc -- argc
  1463. Argv -- argv array
  1464. CharSetIn -- char set of existing Argv
  1465. CharSetOut -- char set of desired argv copy
  1466. Return Value:
  1467. Ptr to argv. User can cast appropriately.
  1468. --*/
  1469. {
  1470. PCHAR * argvCopy;
  1471. //
  1472. // allocate Argv
  1473. //
  1474. argvCopy = (PCHAR *) ALLOCATE_HEAP( (Argc+1) * sizeof(PCHAR) );
  1475. if ( !argvCopy )
  1476. {
  1477. return NULL;
  1478. }
  1479. //
  1480. // tokenize string
  1481. // - note that after the first call strtok
  1482. // takes NULL ptr to continue tokening same string
  1483. //
  1484. argvCopy[ Argc ] = NULL;
  1485. while ( Argc-- )
  1486. {
  1487. argvCopy[ Argc ] = Dns_StringCopyAllocate(
  1488. Argv[ Argc ],
  1489. 0, // null terminated
  1490. CharSetIn,
  1491. CharSetOut
  1492. );
  1493. }
  1494. return argvCopy;
  1495. }
  1496. VOID
  1497. Argv_Free(
  1498. IN OUT PSTR * Argv
  1499. )
  1500. /*++
  1501. Routine Description:
  1502. Free allocated Argv.
  1503. Arguments:
  1504. Argv -- argv array
  1505. Return Value:
  1506. None
  1507. --*/
  1508. {
  1509. DWORD i = 0;
  1510. PCHAR parg;
  1511. // free Argv strings
  1512. while ( parg = Argv[i++] )
  1513. {
  1514. FREE_HEAP( parg );
  1515. }
  1516. // free Argv itself
  1517. FREE_HEAP( parg );
  1518. }
  1519. //
  1520. // End string.c
  1521. //