Source code of Windows XP (NT5)
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.

676 lines
14 KiB

  1. /*
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. sdpbstrl.cpp
  5. Abstract:
  6. Author:
  7. */
  8. #include "sdppch.h"
  9. #include "sdpbstrl.h"
  10. #include <basetyps.h>
  11. #include <oleauto.h>
  12. #include <winsock2.h>
  13. #include <wchar.h>
  14. SDP_ARRAY_BSTR::~SDP_ARRAY_BSTR(
  15. )
  16. {
  17. int Size = (int)GetSize();
  18. if ( 0 < Size )
  19. {
  20. for ( int i=0; i < Size; i++ )
  21. {
  22. BSTR Member = GetAt(i);
  23. ASSERT(NULL != Member);
  24. if ( NULL == Member )
  25. {
  26. return;
  27. }
  28. SysFreeString(Member);
  29. }
  30. }
  31. RemoveAll();
  32. }
  33. void
  34. SDP_BSTRING::Reset(
  35. )
  36. {
  37. // perform the destructor actions (freeing ptrs) and the constructor actions (initializing
  38. // member variables to starting values)
  39. // if there is a bstr, free it
  40. if ( NULL != m_Bstr )
  41. {
  42. SysFreeString(m_Bstr);
  43. }
  44. m_Bstr = NULL;
  45. m_CharacterSet = CS_UTF8;
  46. m_CodePage = CP_UTF8;
  47. // call the base class Reset
  48. SDP_CHAR_STRING::Reset();
  49. }
  50. BOOL
  51. SDP_BSTRING::ConvertToBstr(
  52. )
  53. {
  54. // ZoltanS bugfix:
  55. // MutliByteToWideChar always fails if its input string is empty.
  56. // Therefore, we must special-case a zero-length string.
  57. DWORD dwOriginalLength = GetLength();
  58. if ( 0 == dwOriginalLength )
  59. {
  60. // Shrink the member BSTR
  61. if ( !SysReAllocStringLen(&m_Bstr, NULL, dwOriginalLength) )
  62. {
  63. return FALSE;
  64. }
  65. // Make sure the member BSTR is emptied
  66. m_Bstr[0] = L'\0';
  67. }
  68. else // we have a nonzero-length string to convert
  69. {
  70. // get the size of bstr needed to store the unicode representation
  71. // cast the const char * returned from GetCharacterString to CHAR * because MultiByteToWideChar
  72. // doesn't accept const char * (although thats what the parameter should be)
  73. int BstrSize = MultiByteToWideChar(m_CodePage, 0, (CHAR *)GetCharacterString(),
  74. dwOriginalLength, NULL, 0
  75. );
  76. // Check if the token can be converted to an appropriate bstr.
  77. if (0 == BstrSize)
  78. {
  79. return FALSE;
  80. }
  81. // re-allocate bstr for the unicode representation
  82. if ( !SysReAllocStringLen(&m_Bstr, NULL, BstrSize) )
  83. {
  84. return FALSE;
  85. }
  86. // convert character string to bstr
  87. // cast the const char * returned from GetCharacterString to CHAR * because MultiByteToWideChar
  88. // doesn't accept const char * (although thats what the parameter should be)
  89. if ( BstrSize != MultiByteToWideChar(
  90. m_CodePage, 0, (CHAR *)GetCharacterString(),
  91. dwOriginalLength, m_Bstr, BstrSize
  92. ) )
  93. {
  94. return FALSE;
  95. }
  96. }
  97. return TRUE;
  98. }
  99. HRESULT
  100. SDP_BSTRING::GetBstr(
  101. IN BSTR *pBstr
  102. )
  103. {
  104. // ZoltanS
  105. ASSERT( ! IsBadWritePtr(pBstr, sizeof(BSTR)) );
  106. if ( !IsValid() )
  107. {
  108. return HRESULT_FROM_ERROR_CODE(ERROR_INVALID_DATA);
  109. }
  110. *pBstr = m_Bstr;
  111. return S_OK;
  112. }
  113. HRESULT
  114. SDP_BSTRING::GetBstrCopy(
  115. IN BSTR * pBstr
  116. )
  117. {
  118. // ZoltanS
  119. if ( IsBadWritePtr(pBstr, sizeof(BSTR)) )
  120. {
  121. return E_POINTER;
  122. }
  123. BSTR LocalPtr = NULL;
  124. HRESULT HResult = GetBstr(&LocalPtr);
  125. if ( FAILED(HResult) )
  126. {
  127. return HResult;
  128. }
  129. if ( (*pBstr = SysAllocString(LocalPtr)) == NULL )
  130. {
  131. return E_OUTOFMEMORY;
  132. }
  133. return S_OK;
  134. }
  135. HRESULT
  136. SDP_BSTRING::SetBstr(
  137. IN BSTR Bstr
  138. )
  139. {
  140. if ( NULL == Bstr )
  141. {
  142. return E_INVALIDARG;
  143. }
  144. DWORD BstrLen = lstrlenW(Bstr);
  145. BOOL DefaultUsed = FALSE;
  146. // determine length of character string buffer
  147. // If the codepage is UTF8 the last argument should be NULL
  148. // if the caracterset is ASCII then we need to determine if the
  149. // WideCharToMultiByte methods nneds replacment characters
  150. int BufferSize = WideCharToMultiByte(
  151. m_CodePage, 0, Bstr, BstrLen+1,
  152. NULL, 0, NULL,
  153. (m_CharacterSet == CS_ASCII ) ? &DefaultUsed : NULL
  154. );
  155. if ( 0 == BufferSize )
  156. {
  157. return HRESULT_FROM_ERROR_CODE(GetLastError());
  158. }
  159. if ( DefaultUsed )
  160. {
  161. return HRESULT_FROM_ERROR_CODE(SDP_INVALID_VALUE);
  162. }
  163. // now conversion cannot fail because the previous call made sure that
  164. // the bstr can be converted to this multibyte string
  165. // since failure is not possible, we do not need any code to restore
  166. // the previous character string and it may be freed
  167. if ( !ReAllocCharacterString(BufferSize) )
  168. {
  169. return HRESULT_FROM_ERROR_CODE(GetLastError());
  170. }
  171. // since the char string has been reallocated, the modifiable string must exist
  172. // (i.e. the char string should not be by reference at this point)
  173. ASSERT(NULL != GetModifiableCharString());
  174. // convert to multibyte string
  175. if ( BufferSize != WideCharToMultiByte(
  176. m_CodePage, 0, Bstr, BstrLen+1,
  177. GetModifiableCharString(), BufferSize, NULL, NULL
  178. ) )
  179. {
  180. ASSERT(FALSE);
  181. return HRESULT_FROM_ERROR_CODE(GetLastError());
  182. }
  183. // reallocate memory and copy bstr
  184. if ( !SysReAllocStringLen(&m_Bstr, Bstr, BstrLen) )
  185. {
  186. return HRESULT_FROM_ERROR_CODE(GetLastError());
  187. }
  188. IsValid(TRUE);
  189. IsModified(TRUE);
  190. return S_OK;
  191. }
  192. BOOL
  193. SDP_BSTRING::InternalSetCharStrByRef(
  194. IN CHAR *CharacterStringByReference,
  195. IN DWORD Length
  196. )
  197. {
  198. if ( !SDP_CHAR_STRING::InternalSetCharStrByRef(CharacterStringByReference, Length) )
  199. {
  200. return FALSE;
  201. }
  202. if ( !ConvertToBstr() )
  203. {
  204. return FALSE;
  205. }
  206. return TRUE;
  207. }
  208. BOOL
  209. SDP_BSTRING::InternalSetCharStrByCopy(
  210. IN const CHAR *CharacterStringByCopy,
  211. IN DWORD Length
  212. )
  213. {
  214. if ( !SDP_CHAR_STRING::InternalSetCharStrByCopy(CharacterStringByCopy, Length) )
  215. {
  216. return FALSE;
  217. }
  218. if ( !ConvertToBstr() )
  219. {
  220. return FALSE;
  221. }
  222. return TRUE;
  223. }
  224. BOOL
  225. SDP_BSTRING::InternalParseToken(
  226. IN CHAR *Token
  227. )
  228. {
  229. UINT CodePage;
  230. // parse the token using the base class parsing method
  231. if ( !SDP_CHAR_STRING::InternalParseToken(Token) )
  232. {
  233. return FALSE;
  234. }
  235. if ( !ConvertToBstr() )
  236. {
  237. return FALSE;
  238. }
  239. return TRUE;
  240. }
  241. SDP_BSTRING::~SDP_BSTRING()
  242. {
  243. if ( NULL != m_Bstr )
  244. {
  245. SysFreeString(m_Bstr);
  246. }
  247. }
  248. void
  249. SDP_OPTIONAL_BSTRING::Reset(
  250. )
  251. {
  252. // perform the destructor actions (freeing ptrs) and the constructor actions (initializing
  253. // member variables to starting values)
  254. m_IsBstrCreated = FALSE;
  255. // call the base class Reset
  256. SDP_BSTRING::Reset();
  257. }
  258. // returns the bstr for the character string
  259. // creates a bstr if required
  260. HRESULT
  261. SDP_OPTIONAL_BSTRING::GetBstr(
  262. IN BSTR * pBstr
  263. )
  264. {
  265. // ZoltanS
  266. ASSERT( ! IsBadWritePtr(pBstr, sizeof(BSTR)) );
  267. if ( !IsValid() )
  268. {
  269. return HRESULT_FROM_ERROR_CODE(ERROR_INVALID_DATA);
  270. }
  271. if ( !m_IsBstrCreated )
  272. {
  273. if ( !ConvertToBstr() )
  274. {
  275. return HRESULT_FROM_ERROR_CODE(GetLastError());
  276. }
  277. m_IsBstrCreated = TRUE;
  278. }
  279. *pBstr = m_Bstr;
  280. return S_OK;
  281. }
  282. HRESULT
  283. SDP_OPTIONAL_BSTRING::SetBstr(
  284. IN BSTR Bstr
  285. )
  286. {
  287. HRESULT HResult = SDP_BSTRING::SetBstr(Bstr);
  288. if ( FAILED(HResult) )
  289. {
  290. return HResult;
  291. }
  292. m_IsBstrCreated = TRUE;
  293. ASSERT(S_OK == HResult);
  294. return HResult;
  295. }
  296. BOOL
  297. SDP_OPTIONAL_BSTRING::InternalSetCharStrByRef(
  298. IN CHAR *CharacterStringByReference,
  299. IN DWORD Length
  300. )
  301. {
  302. if ( !SDP_CHAR_STRING::InternalSetCharStrByRef(CharacterStringByReference, Length) )
  303. {
  304. return FALSE;
  305. }
  306. m_IsBstrCreated = FALSE;
  307. return TRUE;
  308. }
  309. BOOL
  310. SDP_OPTIONAL_BSTRING::InternalSetCharStrByCopy(
  311. IN const CHAR *CharacterStringByCopy,
  312. IN DWORD Length
  313. )
  314. {
  315. if ( !SDP_CHAR_STRING::InternalSetCharStrByCopy(CharacterStringByCopy, Length) )
  316. {
  317. return FALSE;
  318. }
  319. m_IsBstrCreated = FALSE;
  320. return TRUE;
  321. }
  322. // since the bstr must only be created on demand, parsing must
  323. // be over-ridden such that the bstr is not created during parsing
  324. BOOL
  325. SDP_OPTIONAL_BSTRING::InternalParseToken(
  326. IN CHAR *Token
  327. )
  328. {
  329. return SDP_CHAR_STRING::InternalParseToken(Token);
  330. }
  331. HRESULT
  332. SDP_BSTRING_LINE::GetBstrCopy(
  333. IN BSTR *pBstr
  334. )
  335. {
  336. // ZoltanS
  337. if ( IsBadWritePtr(pBstr, sizeof(BSTR)) )
  338. {
  339. return E_POINTER;
  340. }
  341. // if no elements in the field array, then the instance is invalid
  342. if ( 0 >= m_FieldArray.GetSize() )
  343. {
  344. // ZoltanS fix: return a valid empty string! Otherwise we aren't
  345. // conforming to Bstr semantics.
  346. *pBstr = SysAllocString(L"");
  347. if ( (*pBstr) == NULL )
  348. {
  349. return E_OUTOFMEMORY;
  350. }
  351. return S_OK;
  352. }
  353. return GetBstring().GetBstrCopy(pBstr);
  354. }
  355. HRESULT
  356. SDP_BSTRING_LINE::SetBstr(
  357. IN BSTR Bstr
  358. )
  359. {
  360. BAIL_ON_FAILURE(GetBstring().SetBstr(Bstr));
  361. try
  362. {
  363. // set the field and separator char array
  364. m_FieldArray.SetAtGrow(0, &GetBstring());
  365. m_SeparatorCharArray.SetAtGrow(0, CHAR_NEWLINE);
  366. }
  367. catch(...)
  368. {
  369. m_FieldArray.RemoveAll();
  370. m_SeparatorCharArray.RemoveAll();
  371. return E_OUTOFMEMORY;
  372. }
  373. return S_OK;
  374. }
  375. void
  376. SDP_REQD_BSTRING_LINE::InternalReset(
  377. )
  378. {
  379. m_Bstring.Reset();
  380. }
  381. void
  382. SDP_CHAR_STRING_LINE::InternalReset(
  383. )
  384. {
  385. m_SdpOptionalBstring.Reset();
  386. }
  387. HRESULT
  388. SDP_LIMITED_CHAR_STRING::SetLimitedCharString(
  389. IN CHAR *String
  390. )
  391. {
  392. // check if the string is a legal string
  393. // check if the token is one of the legal strings
  394. for(UINT i=0; i < m_NumStrings; i++)
  395. {
  396. if ( !strcmp(m_LegalStrings[i], String) )
  397. {
  398. // parse the string using the base class parsing method
  399. if ( !SDP_CHAR_STRING::InternalParseToken(String) )
  400. {
  401. return HRESULT_FROM_ERROR_CODE(GetLastError());
  402. }
  403. return S_OK;
  404. }
  405. }
  406. // no matching legal string
  407. return HRESULT_FROM_ERROR_CODE(ERROR_INVALID_DATA);
  408. }
  409. BOOL
  410. SDP_LIMITED_CHAR_STRING::InternalParseToken(
  411. IN CHAR *Token
  412. )
  413. {
  414. // check if the token is one of the legal strings
  415. for(UINT i=0; i < m_NumStrings; i++)
  416. {
  417. if ( !strcmp(m_LegalStrings[i], Token) )
  418. {
  419. // parse the token using the base class parsing method
  420. if ( !SDP_CHAR_STRING::InternalParseToken(Token) )
  421. {
  422. return FALSE;
  423. }
  424. return TRUE;
  425. }
  426. }
  427. // the token does not match any of the legal strings
  428. SetLastError(SDP_INVALID_FORMAT);
  429. return FALSE;
  430. }
  431. BOOL
  432. SDP_ADDRESS::IsValidIP4Address(
  433. IN CHAR *Address,
  434. OUT ULONG &Ip4AddressValue
  435. )
  436. {
  437. ASSERT(NULL != Address);
  438. // check if there are atleast 3 CHAR_DOTs in the address string
  439. // inet_addr accepts 3,2,1 or even no dots
  440. CHAR *CurrentChar = Address;
  441. BYTE NumDots = 0;
  442. while (EOS != *CurrentChar)
  443. {
  444. if (CHAR_DOT == *CurrentChar)
  445. {
  446. NumDots++;
  447. if (3 == NumDots)
  448. {
  449. break;
  450. }
  451. }
  452. // advance the ptr to the next char
  453. CurrentChar++;
  454. }
  455. // check for the number of dots
  456. if (3 != NumDots)
  457. {
  458. SetLastError(SDP_INVALID_ADDRESS);
  459. return FALSE;
  460. }
  461. // currently only ip4 is supported
  462. Ip4AddressValue = inet_addr(Address);
  463. // check if the address is a valid IP4 address
  464. if ( (ULONG)INADDR_NONE == Ip4AddressValue )
  465. {
  466. SetLastError(SDP_INVALID_ADDRESS);
  467. return FALSE;
  468. }
  469. return TRUE;
  470. }
  471. HRESULT
  472. SDP_ADDRESS::SetAddress(
  473. IN BSTR Address
  474. )
  475. {
  476. // SetBstr also sets the is modified and is valid flags on success
  477. HRESULT ToReturn = SDP_OPTIONAL_BSTRING::SetBstr(Address);
  478. if ( FAILED(ToReturn) )
  479. {
  480. return ToReturn;
  481. }
  482. // get the ip address
  483. ULONG Ip4AddressValue;
  484. // check if the token is a valid IP4 address
  485. if ( !IsValidIP4Address(GetCharacterString(), Ip4AddressValue) )
  486. {
  487. IsModified(FALSE);
  488. IsValid(FALSE);
  489. return HRESULT_FROM_ERROR_CODE(GetLastError());
  490. }
  491. m_IsMulticastFlag = IN_MULTICAST(ntohl(Ip4AddressValue));
  492. // the grammar requires that a multicast address be either an administratively scoped
  493. // address "239.*" or out of the internet multicast conferencing range "224.2.*"
  494. // we won't check that here as that may be overly restrictive
  495. return S_OK;
  496. }
  497. HRESULT
  498. SDP_ADDRESS::SetBstr(
  499. IN BSTR Bstr
  500. )
  501. {
  502. return SetAddress(Bstr);
  503. }
  504. BOOL
  505. SDP_ADDRESS::InternalParseToken(
  506. IN CHAR *Token
  507. )
  508. {
  509. ULONG Ip4AddressValue;
  510. // check if the token is a valid IP4 address
  511. if ( !IsValidIP4Address(Token, Ip4AddressValue) )
  512. {
  513. return FALSE;
  514. }
  515. // check if the address(unicast or multicast) is same as whats expected
  516. if ( IN_MULTICAST(ntohl(Ip4AddressValue)) != m_IsMulticastFlag )
  517. {
  518. SetLastError(SDP_INVALID_ADDRESS);
  519. return FALSE;
  520. }
  521. // the grammar requires that a multicast address be either an administratively scoped
  522. // address "239.*" or out of the internet multicast conferencing range "224.2.*"
  523. // we won't check that here as that may be overly restrictive
  524. // call the base class parse token method
  525. if ( !SDP_CHAR_STRING::InternalParseToken(Token) )
  526. {
  527. return FALSE;
  528. }
  529. return TRUE;
  530. }