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.

608 lines
13 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: ClassFac.cpp
  6. * Content: Parsing engine
  7. *@@BEGIN_MSINTERNAL
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 02/04/2000 rmt Created
  12. * 02/17/2000 rmt Parameter validation work
  13. * 02/21/2000 rmt Updated to make core Unicode and remove ANSI calls
  14. * 03/21/2000 rmt Renamed all DirectPlayAddress8's to DirectPlay8Addresses
  15. * 07/21/2000 rmt Bug #39940 - Addressing library doesn't properly parse stopbits in URLs
  16. *@@END_MSINTERNAL
  17. *
  18. ***************************************************************************/
  19. #include "dnaddri.h"
  20. #undef DPF_MODNAME
  21. #define DPF_MODNAME "DP8ADDRESSPARSE::DP8ADDRESSPARSE"
  22. DP8ADDRESSPARSE::DP8ADDRESSPARSE(
  23. ): m_pwszCurrentLocation(NULL),
  24. m_pwszCurrentKey(NULL),
  25. m_pwszCurrentValue(NULL),
  26. m_pbUserData(NULL),
  27. m_dwUserDataSize(0),
  28. m_dp8State(DP8AP_IDLE),
  29. m_dwLenURL(0)
  30. {
  31. }
  32. #undef DPF_MODNAME
  33. #define DPF_MODNAME "DP8ADDRESSPARSE::~DP8ADDRESSPARSE"
  34. DP8ADDRESSPARSE::~DP8ADDRESSPARSE()
  35. {
  36. if( m_pwszCurrentKey != NULL )
  37. {
  38. delete [] m_pwszCurrentKey;
  39. }
  40. if( m_pwszCurrentValue != NULL )
  41. {
  42. delete [] m_pwszCurrentValue;
  43. }
  44. if ( m_pbUserData != NULL )
  45. {
  46. delete [] m_pbUserData;
  47. }
  48. }
  49. #undef DPF_MODNAME
  50. #define DPF_MODNAME "DP8ADDRESSPARSE::ParseURL"
  51. HRESULT DP8ADDRESSPARSE::ParseURL( DP8ADDRESSOBJECT *dp8aObject, WCHAR *pstrURL )
  52. {
  53. HRESULT hr;
  54. if( m_pwszCurrentKey != NULL )
  55. {
  56. delete [] m_pwszCurrentKey;
  57. m_pwszCurrentKey = NULL;
  58. }
  59. if( m_pwszCurrentValue != NULL )
  60. {
  61. delete [] m_pwszCurrentValue;
  62. m_pwszCurrentValue = NULL;
  63. }
  64. if( m_pbUserData != NULL )
  65. {
  66. delete [] m_pbUserData;
  67. m_pbUserData = NULL;
  68. }
  69. m_dwUserDataSize = 0;
  70. m_pwszCurrentLocation = pstrURL;
  71. m_dwLenURL = wcslen(pstrURL);
  72. if( m_dwLenURL < wcslen( DPNA_HEADER ) )
  73. {
  74. DPFX(DPFPREP, 0, "Invalid URL" );
  75. return DPNERR_INVALIDURL;
  76. }
  77. if( wcsncmp( pstrURL, DPNA_HEADER, wcslen(DPNA_HEADER) ) != 0 )
  78. {
  79. DPFX(DPFPREP, 0, "No header, invalid URL" );
  80. return DPNERR_INVALIDURL;
  81. }
  82. m_pwszCurrentLocation += wcslen( DPNA_HEADER );
  83. m_pwszCurrentKey = new WCHAR[m_dwLenURL+1];
  84. if( !m_pwszCurrentKey )
  85. {
  86. DPFX(DPFPREP, 0, "Error allocating memory" );
  87. return DPNERR_OUTOFMEMORY;
  88. }
  89. m_pwszCurrentValue = new WCHAR[m_dwLenURL+1];
  90. if( !m_pwszCurrentValue )
  91. {
  92. delete [] m_pwszCurrentKey;
  93. m_pwszCurrentKey = NULL;
  94. DPFX(DPFPREP, 0, "Error allocating memory" );
  95. return DPNERR_OUTOFMEMORY;
  96. }
  97. m_pbUserData = new BYTE[m_dwLenURL+1];
  98. if( !m_pbUserData )
  99. {
  100. delete [] m_pwszCurrentKey;
  101. delete [] m_pwszCurrentValue;
  102. m_pwszCurrentKey = NULL;
  103. m_pwszCurrentValue = NULL;
  104. DPFX(DPFPREP, 0, "Error allocating memory" );
  105. return DPNERR_OUTOFMEMORY;
  106. }
  107. m_dp8State = DP8AP_IDLE;
  108. // Loop until the string is done
  109. while( *m_pwszCurrentLocation != L'\0' )
  110. {
  111. switch( m_dp8State )
  112. {
  113. case DP8AP_IDLE:
  114. if( *m_pwszCurrentLocation == DPNA_SEPARATOR_USERDATA )
  115. {
  116. m_dp8State = DP8AP_USERDATA;
  117. m_pwszCurrentLocation++;
  118. }
  119. else
  120. {
  121. m_dp8State = DP8AP_KEY;
  122. }
  123. break;
  124. case DP8AP_KEY:
  125. if( *m_pwszCurrentLocation == DPNA_SEPARATOR_USERDATA )
  126. {
  127. m_dp8State = DP8AP_USERDATA;
  128. m_pwszCurrentLocation++;
  129. break;
  130. }
  131. hr = FSM_Key();
  132. if( FAILED( hr ) )
  133. {
  134. DPFX(DPFPREP, 0, "Error parsing key hr = 0x%x", hr );
  135. return hr;
  136. }
  137. // Parse ended with an equals
  138. if( *m_pwszCurrentLocation == DPNA_SEPARATOR_KEYVALUE )
  139. {
  140. m_dp8State = DP8AP_VALUE;
  141. m_pwszCurrentLocation++;
  142. }
  143. else
  144. {
  145. DPFX(DPFPREP, 0, "keyname without associated value hr=0x%x", hr );
  146. return DPNERR_INVALIDURL;
  147. }
  148. break;
  149. case DP8AP_VALUE:
  150. hr = FSM_Value();
  151. if( FAILED( hr ) )
  152. {
  153. DPFX(DPFPREP, 0, "Error parsing value hr=0x%x", hr );
  154. return hr;
  155. }
  156. // Parse ended with an equals
  157. if( *m_pwszCurrentLocation == DPNA_SEPARATOR_COMPONENT )
  158. {
  159. m_dp8State = DP8AP_KEY;
  160. m_pwszCurrentLocation++;
  161. }
  162. else if( *m_pwszCurrentLocation == DPNA_SEPARATOR_USERDATA )
  163. {
  164. m_dp8State = DP8AP_USERDATA;
  165. m_pwszCurrentLocation++;
  166. }
  167. else if( *m_pwszCurrentLocation == L'\0' )
  168. {
  169. m_dp8State = DP8AP_IDLE;
  170. }
  171. else
  172. {
  173. DPFX(DPFPREP, 0, "Error parsing next key" );
  174. hr = DPNERR_INVALIDURL;
  175. return hr;
  176. }
  177. hr = FSM_CommitEntry(dp8aObject);
  178. if( hr == DPNERR_INVALIDPARAM )
  179. {
  180. DPFX(DPFPREP, 0, "Invalid value specified in URL hr=0x%x", hr );
  181. hr = DPNERR_INVALIDURL;
  182. return hr;
  183. }
  184. else if( FAILED( hr ) )
  185. {
  186. DPFX(DPFPREP, 0, "Error commiting entry hr=0x%x", hr );
  187. return hr;
  188. }
  189. break;
  190. case DP8AP_USERDATA:
  191. hr = FSM_UserData();
  192. if( FAILED( hr ) )
  193. {
  194. DPFX(DPFPREP, 0, "Error parsing user data hr=0x%x", hr );
  195. return hr;
  196. }
  197. hr = dp8aObject->SetUserData( m_pbUserData, m_dwUserDataSize );
  198. if( FAILED( hr ) )
  199. {
  200. DPFX(DPFPREP, 0, "Error setting user data hr=0x%x", hr );
  201. return hr;
  202. }
  203. break;
  204. }
  205. }
  206. if( m_dp8State != DP8AP_IDLE &&
  207. m_dp8State != DP8AP_USERDATA )
  208. {
  209. DPFX(DPFPREP, 0, "Parsing error hr=0x%x", hr );
  210. hr = DPNERR_INVALIDURL;
  211. return hr;
  212. }
  213. return DPN_OK;
  214. }
  215. #undef DPF_MODNAME
  216. #define DPF_MODNAME "DP8ADDRESSPARSE::IsValidKeyChar"
  217. BOOL DP8ADDRESSPARSE::IsValidKeyChar( WCHAR ch )
  218. {
  219. if( ch >= L'A' && ch <= L'Z' )
  220. return TRUE;
  221. if( ch >= L'a' && ch <= L'z' )
  222. return TRUE;
  223. if( ch >= L'0' && ch <= L'9' )
  224. return TRUE;
  225. if( ch == L'-' || ch == L'?' || ch == L'.' ||
  226. ch == L',' || ch == L'+' || ch == L'_' )
  227. return TRUE;
  228. return FALSE;
  229. }
  230. #undef DPF_MODNAME
  231. #define DPF_MODNAME "DP8ADDRESSPARSE::IsValidKeyTerminator"
  232. BOOL DP8ADDRESSPARSE::IsValidKeyTerminator( WCHAR ch )
  233. {
  234. if( ch == 0 )
  235. return TRUE;
  236. if( ch == DPNA_SEPARATOR_USERDATA )
  237. return TRUE;
  238. if( ch == DPNA_SEPARATOR_COMPONENT )
  239. return TRUE;
  240. if( ch == DPNA_SEPARATOR_KEYVALUE )
  241. return TRUE;
  242. return FALSE;
  243. }
  244. #undef DPF_MODNAME
  245. #define DPF_MODNAME "DP8ADDRESSPARSE::FSM_Key"
  246. // FSM_Key
  247. //
  248. // Parse a keyname, or return an error on error
  249. //
  250. HRESULT DP8ADDRESSPARSE::FSM_Key()
  251. {
  252. DWORD dwKeyLoc = 0;
  253. m_pwszCurrentKey[0] = 0;
  254. HRESULT hr = DPN_OK;
  255. while( 1 )
  256. {
  257. if( IsValidKeyChar(*m_pwszCurrentLocation) )
  258. {
  259. m_pwszCurrentKey[dwKeyLoc] = *m_pwszCurrentLocation;
  260. }
  261. else if( IsValidKeyTerminator(*m_pwszCurrentLocation) )
  262. {
  263. m_pwszCurrentKey[dwKeyLoc] = 0;
  264. break;
  265. }
  266. else
  267. {
  268. m_pwszCurrentKey[dwKeyLoc] = 0;
  269. hr = DPNERR_INVALIDURL;
  270. break;
  271. }
  272. dwKeyLoc++;
  273. m_pwszCurrentLocation++;
  274. }
  275. return hr;
  276. }
  277. #undef DPF_MODNAME
  278. #define DPF_MODNAME "DP8ADDRESSPARSE::IsValidNumber"
  279. BOOL DP8ADDRESSPARSE::IsValidNumber( WCHAR ch )
  280. {
  281. if( ch < L'0' ||
  282. ch > L'9' )
  283. {
  284. return FALSE;
  285. }
  286. else
  287. {
  288. return TRUE;
  289. }
  290. }
  291. #undef DPF_MODNAME
  292. #define DPF_MODNAME "DP8ADDRESSPARSE::IsValidHex"
  293. BOOL DP8ADDRESSPARSE::IsValidHex( WCHAR ch )
  294. {
  295. if( IsValidNumber( ch ) )
  296. return TRUE;
  297. if( ch >= L'A' || ch <= L'F' )
  298. return TRUE;
  299. if( ch >= L'a' || ch <= L'f' )
  300. return TRUE;
  301. return FALSE;
  302. }
  303. #undef DPF_MODNAME
  304. #define DPF_MODNAME "DP8ADDRESSPARSE::HexToChar"
  305. WCHAR DP8ADDRESSPARSE::HexToChar( WCHAR *sz )
  306. {
  307. WCHAR chResult = sz[0];
  308. // First digit
  309. if( sz[0] >= L'0' && sz[0] <= L'9' )
  310. chResult = sz[0]-L'0';
  311. if( sz[0] >= L'A' && sz[0] <= L'F' )
  312. chResult = sz[0]-L'A'+10;
  313. if( sz[0] >= L'a' && sz[0] <= L'f' )
  314. chResult = sz[0]-L'a'+10;
  315. chResult <<= 4;
  316. // Second digit
  317. if( sz[1] >= L'0' && sz[1] <= L'9' )
  318. chResult += sz[1]-'0';
  319. if( sz[1] >= L'A' && sz[1] <= L'F' )
  320. chResult += sz[1]-L'A'+10;
  321. if( sz[1] >= L'a' && sz[1] <= L'f' )
  322. chResult += sz[1]-L'a'+10;
  323. return chResult;
  324. }
  325. #undef DPF_MODNAME
  326. #define DPF_MODNAME "DP8ADDRESSPARSE::FSM_Value"
  327. HRESULT DP8ADDRESSPARSE::FSM_Value()
  328. {
  329. m_fNonNumeric = FALSE;
  330. m_pwszCurrentValue[0] = 0;
  331. HRESULT hr = DPN_OK;
  332. m_dwValueLen = 0;
  333. while( 1 )
  334. {
  335. // Just add it
  336. if( IsValidKeyChar( *m_pwszCurrentLocation ) )
  337. {
  338. m_pwszCurrentValue[m_dwValueLen] = *m_pwszCurrentLocation;
  339. if( !IsValidNumber( *m_pwszCurrentLocation ) )
  340. {
  341. m_fNonNumeric = TRUE;
  342. }
  343. }
  344. // ESCAPE SEQUENCE
  345. else if( *m_pwszCurrentLocation == DPNA_ESCAPECHAR )
  346. {
  347. m_fNonNumeric = TRUE;
  348. if( *(m_pwszCurrentLocation+1) == DPNA_ESCAPECHAR )
  349. {
  350. m_pwszCurrentValue[m_dwValueLen] = DPNA_ESCAPECHAR;
  351. m_pwszCurrentLocation += 2;
  352. }
  353. if( wcslen( m_pwszCurrentLocation ) < 3 )
  354. {
  355. DPFX(DPFPREP, 0, "Unexpected end in escape sequence" );
  356. hr = DPNERR_INVALIDURL;
  357. break;
  358. }
  359. if( !IsValidHex( *(m_pwszCurrentLocation+1) ) ||
  360. !IsValidHex( *(m_pwszCurrentLocation+2) ) )
  361. {
  362. DPFX(DPFPREP, 0, "Invalid escape sequence" );
  363. hr = DPNERR_INVALIDURL;
  364. break;
  365. }
  366. m_pwszCurrentLocation ++;
  367. m_pwszCurrentValue[m_dwValueLen] = HexToChar(m_pwszCurrentLocation);
  368. m_pwszCurrentLocation ++;
  369. }
  370. else if( IsValidKeyTerminator(*m_pwszCurrentLocation) )
  371. {
  372. m_pwszCurrentValue[m_dwValueLen] = 0;
  373. break;
  374. }
  375. else
  376. {
  377. m_pwszCurrentValue[m_dwValueLen] = 0;
  378. DPFX(DPFPREP, 0, "Unexpected character in URL" );
  379. hr = DPNERR_INVALIDURL;
  380. break;
  381. }
  382. m_dwValueLen++;
  383. m_pwszCurrentLocation++;
  384. }
  385. if( m_dwValueLen < 1 )
  386. {
  387. DPFX(DPFPREP, DP8A_ERRORLEVEL, "0 length value" );
  388. return DPNERR_INVALIDURL;
  389. }
  390. return hr;
  391. }
  392. #undef DPF_MODNAME
  393. #define DPF_MODNAME "DP8ADDRESSPARSE::FSM_UserData"
  394. HRESULT DP8ADDRESSPARSE::FSM_UserData()
  395. {
  396. m_pwszCurrentValue[0] = 0;
  397. HRESULT hr = DPN_OK;
  398. DWORD dwValueLoc = 0;
  399. while( 1 )
  400. {
  401. // Just add it
  402. if( IsValidKeyChar( *m_pwszCurrentLocation ) )
  403. {
  404. m_pbUserData[dwValueLoc] = (CHAR) *m_pwszCurrentLocation;
  405. }
  406. // ESCAPE SEQUENCE
  407. else if( *m_pwszCurrentLocation == DPNA_ESCAPECHAR )
  408. {
  409. if( *(m_pwszCurrentLocation+1) == DPNA_ESCAPECHAR )
  410. {
  411. m_pbUserData[dwValueLoc] = DPNA_ESCAPECHAR;
  412. m_pwszCurrentLocation += 2;
  413. }
  414. if( wcslen( m_pwszCurrentLocation ) < 3 )
  415. {
  416. DPFX(DPFPREP, 0, "Unexpected end in escape sequence" );
  417. hr = DPNERR_INVALIDURL;
  418. break;
  419. }
  420. if( !IsValidHex( *(m_pwszCurrentLocation+1) ) ||
  421. !IsValidHex( *(m_pwszCurrentLocation+2) ) )
  422. {
  423. DPFX(DPFPREP, 0, "Invalid escape sequence" );
  424. hr = DPNERR_INVALIDURL;
  425. break;
  426. }
  427. m_pwszCurrentLocation ++;
  428. m_pbUserData[dwValueLoc] = (CHAR) HexToChar(m_pwszCurrentLocation);
  429. m_pwszCurrentLocation ++;
  430. }
  431. else if( IsValidKeyTerminator(*m_pwszCurrentLocation) )
  432. {
  433. m_pwszCurrentValue[dwValueLoc] = 0;
  434. break;
  435. }
  436. else
  437. {
  438. m_pwszCurrentValue[dwValueLoc] = 0;
  439. hr = DPNERR_INVALIDURL;
  440. break;
  441. }
  442. dwValueLoc++;
  443. m_pwszCurrentLocation++;
  444. }
  445. m_dwUserDataSize = dwValueLoc;
  446. return hr;
  447. }
  448. #undef DPF_MODNAME
  449. #define DPF_MODNAME "DP8ADDRESSPARSE::FSM_CommitEntry"
  450. HRESULT DP8ADDRESSPARSE::FSM_CommitEntry(DP8ADDRESSOBJECT *pdp8aObject)
  451. {
  452. DWORD dwDataType = 0xFFFFFFFF;
  453. // Ensure that datatype is correct in case the key is a reserved key
  454. for( DWORD dwIndex = 0; dwIndex < c_dwNumBaseStrings; dwIndex++ )
  455. {
  456. if( _wcsicmp( szBaseStrings[dwIndex], m_pwszCurrentKey ) == 0 )
  457. {
  458. dwDataType = dwBaseRequiredTypes[dwIndex] ;
  459. break;
  460. }
  461. }
  462. // If it's numeric
  463. if( (dwDataType == DPNA_DATATYPE_DWORD || dwDataType == 0xFFFFFFFF) && !m_fNonNumeric && wcslen(m_pwszCurrentValue)<=10)
  464. {
  465. DWORD dwTmpValue;
  466. dwTmpValue = _wtol( m_pwszCurrentValue );
  467. return pdp8aObject->SetElement( m_pwszCurrentKey, &dwTmpValue, sizeof(DWORD), DPNA_DATATYPE_DWORD );
  468. }
  469. UINT aiTmp[11];
  470. // We've read a GUID
  471. if( (dwDataType == DPNA_DATATYPE_GUID || dwDataType == 0xFFFFFFFF) && wcslen( m_pwszCurrentValue ) == 38 && swscanf( m_pwszCurrentValue, L"{%8X-%4X-%4X-%2X%2X-%2X%2X%2X%2X%2X%2X}" ,
  472. &aiTmp[0],
  473. &aiTmp[1], &aiTmp[2],
  474. &aiTmp[3], &aiTmp[4],
  475. &aiTmp[5], &aiTmp[6],
  476. &aiTmp[7], &aiTmp[8],
  477. &aiTmp[9], &aiTmp[10]) == 11)
  478. {
  479. GUID guidValue;
  480. guidValue.Data1 = (ULONG) aiTmp[0];
  481. guidValue.Data2 = (USHORT) aiTmp[1];
  482. guidValue.Data3 = (USHORT) aiTmp[2];
  483. guidValue.Data4[0] = (BYTE) aiTmp[3];
  484. guidValue.Data4[1] = (BYTE) aiTmp[4];
  485. guidValue.Data4[2] = (BYTE) aiTmp[5];
  486. guidValue.Data4[3] = (BYTE) aiTmp[6];
  487. guidValue.Data4[4] = (BYTE) aiTmp[7];
  488. guidValue.Data4[5] = (BYTE) aiTmp[8];
  489. guidValue.Data4[6] = (BYTE) aiTmp[9];
  490. guidValue.Data4[7] = (BYTE) aiTmp[10];
  491. return pdp8aObject->SetElement( m_pwszCurrentKey, &guidValue, sizeof(GUID), DPNA_DATATYPE_GUID );
  492. }
  493. // If there are no NULLs it's probably a string
  494. if( (dwDataType == DPNA_DATATYPE_STRING || dwDataType == 0xFFFFFFFF || wcscmp(DPNA_KEY_PROVIDER,m_pwszCurrentKey)==0 ) && wcslen( m_pwszCurrentValue ) == m_dwValueLen )
  495. {
  496. // Otherwise it's a string
  497. return pdp8aObject->SetElement( m_pwszCurrentKey, m_pwszCurrentValue, (wcslen(m_pwszCurrentValue)+1)*sizeof(WCHAR), DPNA_DATATYPE_STRING );
  498. }
  499. // Otherwise it's a binary (although the bytes were extended into WORDs/WCHARs.
  500. return pdp8aObject->SetElement( m_pwszCurrentKey, m_pwszCurrentValue, (m_dwValueLen * sizeof(WCHAR)), DPNA_DATATYPE_BINARY );
  501. }