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.

1540 lines
34 KiB

  1. //--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996
  5. //
  6. // File: parse.cxx
  7. //
  8. // Contents: LDAP Pathname Parser
  9. //
  10. // The Pathname Parser is a key component in ADs providers. It checks for
  11. // syntactic validity of an ADs pathname that has been passed to this
  12. // provider. If the syntax is valid, then an OBJECTINFO structure is
  13. // constructed. This OBJECTINFO structure contains a componentized version
  14. // of the ADs pathname for this object.
  15. //
  16. // Note all that is being done is a syntax check. Rather than special-case
  17. // every single new nuance to pathnames, all path checking must conform to
  18. // the grammar rules laid out by the parser.
  19. //
  20. //
  21. //
  22. // History:
  23. //----------------------------------------------------------------------------
  24. #include <stdlib.h>
  25. #include "ldapc.hxx"
  26. #pragma hdrstop
  27. // Object -> PathName, Type, eos
  28. // Object -> PathName, eos
  29. KWDLIST KeywordList[] =
  30. {
  31. { TOKEN_DOMAIN, DOMAIN_CLASS_NAME },
  32. { TOKEN_USER, USER_CLASS_NAME },
  33. { TOKEN_GROUP, GROUP_CLASS_NAME },
  34. { TOKEN_COMPUTER, COMPUTER_CLASS_NAME },
  35. { TOKEN_PRINTER, PRINTER_CLASS_NAME },
  36. { TOKEN_SERVICE, SERVICE_CLASS_NAME },
  37. { TOKEN_FILESERVICE, FILESERVICE_CLASS_NAME },
  38. { TOKEN_FILESHARE, FILESHARE_CLASS_NAME },
  39. { TOKEN_SCHEMA, SCHEMA_CLASS_NAME },
  40. { TOKEN_CLASS, CLASS_CLASS_NAME },
  41. { TOKEN_PROPERTY, PROPERTY_CLASS_NAME },
  42. { TOKEN_SYNTAX, SYNTAX_CLASS_NAME },
  43. { TOKEN_LOCALITY, LOCALITY_CLASS_NAME },
  44. { TOKEN_ORGANIZATION, ORGANIZATION_CLASS_NAME },
  45. { TOKEN_ORGANIZATIONUNIT, ORGANIZATIONUNIT_CLASS_NAME },
  46. { TOKEN_COUNTRY, COUNTRY_CLASS_NAME },
  47. { TOKEN_ROOTDSE, ROOTDSE_CLASS_NAME}
  48. };
  49. DWORD gdwKeywordListSize = sizeof(KeywordList)/sizeof(KWDLIST);
  50. HRESULT
  51. InitObjectInfo(
  52. LPWSTR pszADsPathName,
  53. POBJECTINFO pObjectInfo
  54. )
  55. {
  56. DWORD dwLen = 0;
  57. HRESULT hr = S_OK;
  58. ADsAssert(pObjectInfo);
  59. ADsAssert(pszADsPathName);
  60. memset(pObjectInfo, 0x0, sizeof(OBJECTINFO));
  61. dwLen = wcslen(pszADsPathName) * sizeof(WCHAR) * 3;
  62. if( dwLen ) {
  63. pObjectInfo->szStrBuf = (LPWSTR) AllocADsMem(dwLen);
  64. pObjectInfo->szDisplayStrBuf = (LPWSTR) AllocADsMem(dwLen);
  65. if (!pObjectInfo->szStrBuf || !pObjectInfo->szDisplayStrBuf) {
  66. RRETURN(E_OUTOFMEMORY);
  67. }
  68. pObjectInfo->szStrBufPtr = pObjectInfo->szStrBuf;
  69. pObjectInfo->szDisplayStrBufPtr = pObjectInfo->szDisplayStrBuf;
  70. }
  71. RRETURN(hr);
  72. }
  73. VOID
  74. FreeObjectInfo(
  75. POBJECTINFO pObjectInfo
  76. )
  77. {
  78. if ( !pObjectInfo )
  79. return;
  80. if (pObjectInfo->szStrBuf) {
  81. FreeADsStr( pObjectInfo->szStrBuf );
  82. }
  83. if (pObjectInfo->szDisplayStrBuf) {
  84. FreeADsStr( pObjectInfo->szDisplayStrBuf );
  85. }
  86. }
  87. HRESULT
  88. ADsObject(
  89. LPWSTR pszADsPathName,
  90. POBJECTINFO pObjectInfo
  91. )
  92. {
  93. HRESULT hr = S_OK;
  94. CLexer Lexer(pszADsPathName);
  95. hr = InitObjectInfo(pszADsPathName, pObjectInfo);
  96. BAIL_ON_FAILURE(hr);
  97. pObjectInfo->ObjectType = TOKEN_LDAPOBJECT;
  98. hr = ADsObjectParse(&Lexer, pObjectInfo);
  99. error:
  100. RRETURN(hr);
  101. }
  102. HRESULT
  103. GetNextToken(
  104. CLexer *pTokenizer,
  105. POBJECTINFO pObjectInfo,
  106. LPWSTR *ppszToken,
  107. LPWSTR *ppszDisplayToken,
  108. DWORD *pdwToken
  109. )
  110. {
  111. HRESULT hr = S_OK;
  112. ADsAssert(ppszToken);
  113. *ppszToken = NULL;
  114. if (ppszDisplayToken) {
  115. *ppszDisplayToken = NULL;
  116. }
  117. hr = pTokenizer->GetNextToken(
  118. pObjectInfo->szStrBufPtr,
  119. pObjectInfo->szDisplayStrBufPtr,
  120. pdwToken
  121. );
  122. BAIL_ON_FAILURE(hr);
  123. *ppszToken = pObjectInfo->szStrBufPtr;
  124. if (ppszDisplayToken) {
  125. *ppszDisplayToken = pObjectInfo->szDisplayStrBufPtr;
  126. }
  127. pObjectInfo->szStrBufPtr += wcslen(pObjectInfo->szStrBufPtr) + 1;
  128. pObjectInfo->szDisplayStrBufPtr += wcslen(pObjectInfo->szDisplayStrBufPtr) + 1;
  129. error:
  130. RRETURN (hr);
  131. }
  132. HRESULT
  133. GetNextToken(
  134. CLexer *pTokenizer,
  135. POBJECTINFO pObjectInfo,
  136. LPWSTR *ppszToken,
  137. DWORD *pdwToken
  138. )
  139. {
  140. return (GetNextToken(
  141. pTokenizer,
  142. pObjectInfo,
  143. ppszToken,
  144. NULL,
  145. pdwToken
  146. ));
  147. }
  148. //+---------------------------------------------------------------------------
  149. // Function: ADsObject
  150. //
  151. // Synopsis: parses an ADs pathname passed to this provider. This function
  152. // parses the following grammar rules
  153. //
  154. // <ADsObject> -> <ProviderName> <LDAPObject>
  155. //
  156. //
  157. // Arguments: [CLexer * pTokenizer] - a lexical analyzer object
  158. // [POBJECTINFO pObjectInfo] - a pointer to an OBJECTINFO structure
  159. //
  160. // Returns: [HRESULT] 0 if successful, error HRESULT if not
  161. //
  162. // Modifies: pTokenizer (consumes the input buffer)
  163. //
  164. // History: 11-3-95 krishnag Created.
  165. //
  166. //----------------------------------------------------------------------------
  167. HRESULT
  168. ADsObjectParse(CLexer * pTokenizer, POBJECTINFO pObjectInfo)
  169. {
  170. LPWSTR szToken = NULL;
  171. DWORD dwToken;
  172. HRESULT hr;
  173. hr = ProviderName(pTokenizer, pObjectInfo);
  174. BAIL_IF_ERROR(hr);
  175. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  176. BAIL_IF_ERROR(hr);
  177. switch ( dwToken ) {
  178. case TOKEN_END:
  179. RRETURN(S_OK);
  180. default:
  181. hr = pTokenizer->PushBackToken();
  182. BAIL_IF_ERROR(hr);
  183. hr = LDAPObject(pTokenizer, pObjectInfo);
  184. BAIL_IF_ERROR(hr);
  185. break;
  186. }
  187. cleanup:
  188. RRETURN(hr);
  189. }
  190. //+---------------------------------------------------------------------------
  191. // Function: LDAPObject
  192. //
  193. // Synopsis: parses an ADs pathname passed to this provider. This function
  194. // parses the following grammar rules
  195. //
  196. // <LDAPObject> -> "\\""identifier""\" <LDAPObject>
  197. //
  198. //
  199. // Arguments: [CLexer * pTokenizer] - a lexical analyzer object
  200. // [POBJECTINFO pObjectInfo] - a pointer to an OBJECTINFO structure
  201. //
  202. // Returns: [HRESULT] 0 if successful, error HRESULT if not
  203. //
  204. // Modifies: pTokenizer (consumes the input buffer)
  205. //
  206. // History: 11-3-95 krishnag Created.
  207. //
  208. //----------------------------------------------------------------------------
  209. HRESULT
  210. LDAPObject(CLexer * pTokenizer, POBJECTINFO pObjectInfo)
  211. {
  212. LPWSTR szToken = NULL;
  213. LPWSTR szDisplayToken;
  214. DWORD dwToken, dwPort;
  215. HRESULT hr;
  216. WCHAR c = L'\0';
  217. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  218. BAIL_IF_ERROR(hr);
  219. if (dwToken != TOKEN_FSLASH) {
  220. RRETURN(E_ADS_BAD_PATHNAME);
  221. }
  222. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  223. BAIL_IF_ERROR(hr);
  224. if (dwToken != TOKEN_FSLASH) {
  225. RRETURN(E_ADS_BAD_PATHNAME);
  226. }
  227. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &szDisplayToken, &dwToken);
  228. BAIL_IF_ERROR(hr);
  229. if (dwToken != TOKEN_IDENTIFIER) {
  230. RRETURN(E_ADS_BAD_PATHNAME);
  231. }
  232. if (!_wcsicmp(szToken, L"schema")) {
  233. hr = pTokenizer->PushBackToken(); // push back the identifier
  234. BAIL_IF_ERROR(hr);
  235. pObjectInfo->dwServerPresent = FALSE;
  236. hr = PathName(pTokenizer, pObjectInfo);
  237. BAIL_IF_ERROR(hr);
  238. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  239. BAIL_IF_ERROR(hr);
  240. } else if (!_wcsicmp(szToken, L"rootdse")) {
  241. hr = pTokenizer->PushBackToken(); // push back the identifier
  242. BAIL_IF_ERROR(hr);
  243. pObjectInfo->dwServerPresent = FALSE;
  244. hr = PathName(pTokenizer, pObjectInfo);
  245. BAIL_IF_ERROR(hr);
  246. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  247. BAIL_IF_ERROR(hr);
  248. } else if (((c = (CHAR)pTokenizer->NextChar()) == TEXT('=')) || (c == TEXT(',')) || (c == TEXT(';')))
  249. {
  250. pTokenizer->PushbackChar(); // push back =
  251. hr = pTokenizer->PushBackToken(); // push back the identifier
  252. BAIL_IF_ERROR(hr);
  253. pObjectInfo->dwServerPresent = FALSE;
  254. hr = PathName(pTokenizer, pObjectInfo);
  255. BAIL_IF_ERROR(hr);
  256. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  257. BAIL_IF_ERROR(hr);
  258. }
  259. else
  260. {
  261. pTokenizer->PushbackChar();
  262. hr = AddTreeName(pObjectInfo, szToken, szDisplayToken);
  263. BAIL_IF_ERROR(hr);
  264. pObjectInfo->dwServerPresent = TRUE;
  265. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  266. BAIL_IF_ERROR(hr);
  267. //
  268. // Check if we have an explicit port number
  269. //
  270. if ( dwToken == TOKEN_COLON) {
  271. //
  272. // Get the port number and set it in the ObjectInfo structure
  273. //
  274. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  275. BAIL_IF_ERROR(hr);
  276. if (dwToken == TOKEN_END) {
  277. RRETURN(E_ADS_BAD_PATHNAME);
  278. }
  279. dwPort = _wtoi(szToken);
  280. if (dwPort == 0) {
  281. RRETURN(E_ADS_BAD_PATHNAME);
  282. }
  283. AddPortNumber(pObjectInfo, dwPort);
  284. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  285. BAIL_IF_ERROR(hr);
  286. }
  287. //
  288. // If we get an TOKEN_END, then we have a tree name only \\<tree_name>
  289. //
  290. if (dwToken == TOKEN_END) {
  291. RRETURN(S_OK);
  292. }
  293. if (dwToken == TOKEN_FSLASH) {
  294. hr = PathName(pTokenizer, pObjectInfo);
  295. BAIL_IF_ERROR(hr);
  296. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  297. BAIL_IF_ERROR(hr);
  298. } else if ( dwToken == TOKEN_COMMA || dwToken == TOKEN_SEMICOLON ) {
  299. // do nothing here
  300. } else {
  301. RRETURN(E_ADS_BAD_PATHNAME);
  302. }
  303. }
  304. switch (dwToken) {
  305. case TOKEN_END:
  306. RRETURN(S_OK);
  307. default:
  308. RRETURN(E_ADS_BAD_PATHNAME);
  309. }
  310. cleanup:
  311. RRETURN(hr);
  312. }
  313. HRESULT
  314. ProviderName(CLexer * pTokenizer, POBJECTINFO pObjectInfo)
  315. {
  316. LPWSTR szToken = NULL;
  317. DWORD dwToken;
  318. HRESULT hr;
  319. DWORD dwPort;
  320. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  321. BAIL_IF_ERROR(hr);
  322. if (dwToken == TOKEN_ATSIGN) {
  323. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  324. BAIL_IF_ERROR(hr);
  325. if (dwToken != TOKEN_IDENTIFIER) {
  326. RRETURN(E_ADS_BAD_PATHNAME);
  327. }
  328. hr = AddProviderName(pObjectInfo, szToken);
  329. hr = AddNamespaceName(pObjectInfo, szToken);
  330. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  331. BAIL_IF_ERROR(hr);
  332. if (dwToken != TOKEN_EXCLAMATION) {
  333. RRETURN(E_ADS_BAD_PATHNAME);
  334. }
  335. }else if (dwToken == TOKEN_IDENTIFIER) {
  336. hr = AddProviderName(pObjectInfo, szToken);
  337. hr = AddNamespaceName(pObjectInfo, szToken);
  338. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  339. BAIL_IF_ERROR(hr);
  340. if (dwToken != TOKEN_COLON) {
  341. RRETURN(E_ADS_BAD_PATHNAME);
  342. }
  343. }else {
  344. RRETURN(E_ADS_BAD_PATHNAME);
  345. }
  346. //
  347. // Add the default port number depending on the namespace.
  348. // If an explicit port number is specified, that will override
  349. //
  350. if ( _wcsicmp( pObjectInfo->NamespaceName, szGCNamespaceName) == 0 ) {
  351. dwPort = (DWORD) USE_DEFAULT_GC_PORT;
  352. }
  353. else {
  354. dwPort = (DWORD) USE_DEFAULT_LDAP_PORT;
  355. }
  356. AddPortNumber(pObjectInfo, dwPort);
  357. //
  358. // You can now disable the processing for "@" and "!" treat them
  359. // as ordinary characters.
  360. //
  361. pTokenizer->SetAtDisabler(TRUE);
  362. RRETURN(S_OK);
  363. cleanup:
  364. RRETURN(hr);
  365. }
  366. // PathName -> Component \\ PathName
  367. // PathName -> Component
  368. HRESULT
  369. DsPathName(CLexer * pTokenizer, POBJECTINFO pObjectInfo)
  370. {
  371. LPWSTR szToken = NULL;
  372. DWORD dwToken;
  373. HRESULT hr;
  374. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  375. BAIL_IF_ERROR(hr);
  376. if (dwToken != TOKEN_FSLASH) {
  377. RRETURN(E_ADS_BAD_PATHNAME);
  378. }
  379. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  380. BAIL_IF_ERROR(hr);
  381. if (dwToken != TOKEN_FSLASH) {
  382. RRETURN(E_ADS_BAD_PATHNAME);
  383. }
  384. hr = PathName(pTokenizer, pObjectInfo);
  385. BAIL_IF_ERROR(hr);
  386. RRETURN(S_OK);
  387. cleanup:
  388. RRETURN(hr);
  389. }
  390. //+---------------------------------------------------------------------------
  391. // Function:
  392. //
  393. // Synopsis:
  394. //
  395. // Arguments:
  396. //
  397. // Returns:
  398. //
  399. // Modifies:
  400. //
  401. // History: 11-3-95 krishnag Created.
  402. //
  403. //----------------------------------------------------------------------------
  404. HRESULT
  405. PathName(CLexer * pTokenizer, POBJECTINFO pObjectInfo)
  406. {
  407. HRESULT hr;
  408. LPWSTR szToken = NULL;
  409. DWORD dwToken;
  410. hr = Component(pTokenizer, pObjectInfo);
  411. BAIL_IF_ERROR(hr);
  412. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  413. BAIL_IF_ERROR(hr);
  414. if (!pObjectInfo->dwPathType) {
  415. if (dwToken == TOKEN_FSLASH) {
  416. pObjectInfo->dwPathType = PATHTYPE_WINDOWS;
  417. RRETURN (PathName(pTokenizer, pObjectInfo));
  418. }else if (dwToken == TOKEN_COMMA || dwToken == TOKEN_SEMICOLON){
  419. pObjectInfo->dwPathType = PATHTYPE_X500;
  420. RRETURN (PathName(pTokenizer, pObjectInfo));
  421. }else{
  422. hr = pTokenizer->PushBackToken();
  423. RRETURN (S_OK);
  424. }
  425. }else if (pObjectInfo->dwPathType == PATHTYPE_WINDOWS){
  426. if (dwToken == TOKEN_FSLASH) {
  427. RRETURN (PathName(pTokenizer, pObjectInfo));
  428. }else{
  429. hr = pTokenizer->PushBackToken();
  430. RRETURN (S_OK);
  431. }
  432. }else if (pObjectInfo->dwPathType == PATHTYPE_X500){
  433. if (dwToken == TOKEN_COMMA || dwToken == TOKEN_SEMICOLON) {
  434. RRETURN (PathName(pTokenizer, pObjectInfo));
  435. }else{
  436. hr = pTokenizer->PushBackToken();
  437. RRETURN (S_OK);
  438. }
  439. }else {
  440. //
  441. // We should never hit this point
  442. //
  443. hr = E_FAIL;
  444. }
  445. cleanup:
  446. RRETURN(hr);
  447. }
  448. //+---------------------------------------------------------------------------
  449. // Function:
  450. //
  451. // Synopsis: Component -> <identifier>
  452. //
  453. // Arguments:
  454. //
  455. // Returns:
  456. //
  457. // Modifies:
  458. //
  459. // History: 11-3-95 krishnag Created.
  460. //
  461. //----------------------------------------------------------------------------
  462. HRESULT
  463. Component(CLexer * pTokenizer, POBJECTINFO pObjectInfo)
  464. {
  465. LPWSTR szValue = NULL;
  466. LPWSTR szDisplayValue = NULL;
  467. LPWSTR szEqual = NULL;
  468. LPWSTR szComponent = NULL;
  469. LPWSTR szDisplayComponent = NULL;
  470. DWORD dwToken;
  471. HRESULT hr = S_OK;
  472. hr = GetNextToken(pTokenizer, pObjectInfo, &szComponent, &szDisplayComponent, &dwToken);
  473. BAIL_IF_ERROR(hr);
  474. if (dwToken != TOKEN_IDENTIFIER) {
  475. BAIL_IF_ERROR( hr = E_ADS_BAD_PATHNAME);
  476. }
  477. hr = GetNextToken(pTokenizer, pObjectInfo, &szEqual, &dwToken);
  478. BAIL_IF_ERROR(hr);
  479. if (dwToken == TOKEN_EQUAL) {
  480. hr = GetNextToken(pTokenizer, pObjectInfo, &szValue, &szDisplayValue, &dwToken);
  481. BAIL_IF_ERROR(hr);
  482. if (dwToken != TOKEN_IDENTIFIER) {
  483. BAIL_IF_ERROR(hr = E_ADS_BAD_PATHNAME);
  484. }
  485. hr = AddComponent(pObjectInfo, szComponent, szValue, szDisplayComponent, szDisplayValue);
  486. BAIL_IF_ERROR(hr);
  487. }else {
  488. hr = AddComponent(pObjectInfo, szComponent, NULL, szDisplayComponent, NULL);
  489. BAIL_IF_ERROR(hr);
  490. hr = pTokenizer->PushBackToken();
  491. BAIL_IF_ERROR(hr);
  492. }
  493. cleanup:
  494. RRETURN(hr);
  495. }
  496. //+---------------------------------------------------------------------------
  497. // Function: Type
  498. //
  499. // Synopsis: Parses Type-> "user" | "group" etc
  500. //
  501. // Arguments: [CLexer * pTokenizer]
  502. // [POBJECTINFo pObjectInfo]
  503. //
  504. // Returns: HRESULT
  505. //
  506. // Modifies: -
  507. //
  508. // History: 11-3-95 krishnag Created.
  509. //
  510. //----------------------------------------------------------------------------
  511. HRESULT
  512. Type(CLexer * pTokenizer, POBJECTINFO pObjectInfo)
  513. {
  514. LPWSTR szToken = NULL;
  515. DWORD dwToken;
  516. HRESULT hr;
  517. hr = GetNextToken(pTokenizer, pObjectInfo, &szToken, &dwToken);
  518. BAIL_IF_ERROR(hr);
  519. if (dwToken == TOKEN_IDENTIFIER ) {
  520. if (pTokenizer->IsKeyword(szToken, &dwToken)) {
  521. hr = SetType(pObjectInfo, dwToken);
  522. BAIL_IF_ERROR(hr);
  523. }
  524. pObjectInfo->ObjectClass = szToken;
  525. }
  526. cleanup:
  527. RRETURN(hr);
  528. }
  529. //+---------------------------------------------------------------------------
  530. // Function:
  531. //
  532. // Synopsis:
  533. //
  534. // Arguments:
  535. //
  536. // Returns:
  537. //
  538. // Modifies:
  539. //
  540. // History: 11-3-95 krishnag Created.
  541. //
  542. //----------------------------------------------------------------------------
  543. __declspec(dllexport)
  544. CLexer::CLexer(LPTSTR szBuffer):
  545. _ptr(NULL),
  546. _Buffer(NULL),
  547. _dwLastTokenLength(0),
  548. _dwLastToken(0),
  549. _dwEndofString(0),
  550. _bAtDisabled(FALSE),
  551. _bFSlashDisabled(FALSE),
  552. _bExclaimDisabled(FALSE)
  553. {
  554. if (!szBuffer || !*szBuffer) {
  555. return;
  556. }
  557. _Buffer = AllocADsStr(szBuffer);
  558. _ptr = _Buffer;
  559. }
  560. //+---------------------------------------------------------------------------
  561. // Function:
  562. //
  563. // Synopsis:
  564. //
  565. // Arguments:
  566. //
  567. // Returns:
  568. //
  569. // Modifies:
  570. //
  571. // History: 08-12-96 t-danal Created.
  572. //
  573. //----------------------------------------------------------------------------
  574. __declspec(dllexport)
  575. CLexer::~CLexer()
  576. {
  577. FreeADsStr(_Buffer);
  578. }
  579. //+---------------------------------------------------------------------------
  580. // Function:
  581. //
  582. // Synopsis:
  583. //
  584. // Arguments:
  585. //
  586. // Returns:
  587. //
  588. // Modifies:
  589. //
  590. // History: 11-3-95 krishnag Created.
  591. //
  592. //----------------------------------------------------------------------------
  593. HRESULT
  594. CLexer::GetNextToken(LPTSTR szToken, LPTSTR szDisplayToken, LPDWORD pdwToken)
  595. {
  596. TCHAR c, cnext;
  597. DWORD state = 0;
  598. LPTSTR pch = szToken;
  599. LPTSTR pDisplayCh = szDisplayToken;
  600. BOOL fEscapeOn = FALSE, fQuotingOn = FALSE;
  601. if (!szToken) {
  602. RRETURN(E_ADS_BAD_PATHNAME);
  603. }
  604. _dwLastTokenLength = 0;
  605. while (1) {
  606. c = NextChar();
  607. switch (state) {
  608. case 0:
  609. *pch++ = c;
  610. _dwLastTokenLength++;
  611. switch (c) {
  612. case TEXT('"') :
  613. //
  614. // Quoting;
  615. //
  616. fQuotingOn = TRUE;
  617. state = 1;
  618. break;
  619. case TEXT('\\') :
  620. //
  621. // Escaping; Ignore the '\' in the token and check to make
  622. // sure that the next character exists
  623. //
  624. cnext = NextChar();
  625. if (cnext == TEXT('/')) {
  626. pch--;
  627. }
  628. PushbackChar();
  629. fEscapeOn = TRUE;
  630. state = 1;
  631. break;
  632. case TEXT('/') :
  633. if (!_bFSlashDisabled) {
  634. *pdwToken = TOKEN_FSLASH;
  635. _dwLastToken = *pdwToken;
  636. RRETURN(S_OK);
  637. }
  638. else {
  639. state = 1;
  640. }
  641. break;
  642. case TEXT(',') :
  643. *pdwToken = TOKEN_COMMA;
  644. _dwLastToken = *pdwToken;
  645. RRETURN(S_OK);
  646. break;
  647. case TEXT(';') :
  648. *pdwToken = TOKEN_SEMICOLON;
  649. _dwLastToken = *pdwToken;
  650. RRETURN(S_OK);
  651. break;
  652. case TEXT('=') :
  653. *pdwToken = TOKEN_EQUAL;
  654. _dwLastToken = *pdwToken;
  655. RRETURN(S_OK);
  656. break;
  657. case TEXT(':') :
  658. if (!_bAtDisabled && !_bExclaimDisabled) {
  659. *pdwToken = TOKEN_COLON;
  660. _dwLastToken = *pdwToken;
  661. RRETURN(S_OK);
  662. }else {
  663. state = 1;
  664. }
  665. break;
  666. case TEXT('\0') :
  667. *pdwToken = TOKEN_END;
  668. _dwLastToken = *pdwToken;
  669. RRETURN(S_OK);
  670. break;
  671. case TEXT('@') :
  672. if (!_bAtDisabled) {
  673. *pdwToken = TOKEN_ATSIGN;
  674. _dwLastToken = *pdwToken;
  675. RRETURN(S_OK);
  676. }else {
  677. state = 1;
  678. }
  679. break;
  680. case TEXT('!') :
  681. if (!_bAtDisabled && !_bExclaimDisabled) {
  682. *pdwToken = TOKEN_EXCLAMATION;
  683. _dwLastToken = *pdwToken;
  684. RRETURN(S_OK);
  685. }else {
  686. state = 1;
  687. }
  688. break;
  689. case TEXT(' ') :
  690. pch--;
  691. _dwLastTokenLength--;
  692. break;
  693. default:
  694. state = 1;
  695. break;
  696. }
  697. break;
  698. case 1:
  699. if ((fEscapeOn || fQuotingOn) && c == TEXT('\0') ) {
  700. RRETURN(E_ADS_BAD_PATHNAME);
  701. }
  702. else if (fEscapeOn) {
  703. fEscapeOn = FALSE;
  704. *pch++ = c;
  705. _dwLastTokenLength++;
  706. state = 1;
  707. break;
  708. }
  709. else if (fQuotingOn) {
  710. if (c == TEXT('"')) {
  711. fQuotingOn = FALSE;
  712. }
  713. else if (c == TEXT('\\')) {
  714. //
  715. // This is a special case, where a \ is
  716. // being passed in to escape something inside
  717. // quotes.
  718. //
  719. fEscapeOn = TRUE;
  720. _dwLastTokenLength++;
  721. *pch++ = c;
  722. cnext = NextChar();
  723. if (cnext == '/') {
  724. pch--;
  725. }
  726. PushbackChar();
  727. state = 1;
  728. break;
  729. }
  730. *pch++ = c;
  731. _dwLastTokenLength++;
  732. break;
  733. }
  734. //
  735. // Ok to put a switch here as all have breaks above.
  736. //
  737. switch (c) {
  738. case TEXT('\\') :
  739. fEscapeOn = TRUE;
  740. _dwLastTokenLength++;
  741. *pch++ = c;
  742. cnext = NextChar();
  743. if (cnext == '/') {
  744. pch--;
  745. }
  746. PushbackChar();
  747. break;
  748. case TEXT('"') :
  749. fQuotingOn = TRUE;
  750. *pch++ = c;
  751. _dwLastTokenLength++;
  752. break;
  753. case TEXT('\0'):
  754. case TEXT(',') :
  755. case TEXT('=') :
  756. case TEXT(';') :
  757. PushbackChar();
  758. *pdwToken = TOKEN_IDENTIFIER;
  759. _dwLastToken = *pdwToken;
  760. RRETURN (S_OK);
  761. break;
  762. case TEXT('/') :
  763. if (!_bFSlashDisabled) {
  764. PushbackChar();
  765. *pdwToken = TOKEN_IDENTIFIER;
  766. _dwLastToken = *pdwToken;
  767. RRETURN(S_OK);
  768. }
  769. else {
  770. *pch++ = c;
  771. _dwLastTokenLength++;
  772. state = 1;
  773. }
  774. break;
  775. case TEXT('!') :
  776. case TEXT(':') :
  777. if (!_bAtDisabled && !_bExclaimDisabled) {
  778. PushbackChar();
  779. *pdwToken = TOKEN_IDENTIFIER;
  780. _dwLastToken = *pdwToken;
  781. RRETURN(S_OK);
  782. }else {
  783. *pch++ = c;
  784. _dwLastTokenLength++;
  785. state = 1;
  786. break;
  787. }
  788. case TEXT('@') :
  789. if (!_bAtDisabled) {
  790. PushbackChar();
  791. *pdwToken = TOKEN_IDENTIFIER;
  792. _dwLastToken = *pdwToken;
  793. RRETURN(S_OK);
  794. }else {
  795. *pch++ = c;
  796. _dwLastTokenLength++;
  797. state = 1;
  798. break;
  799. }
  800. default :
  801. *pch++ = c;
  802. _dwLastTokenLength++;
  803. state = 1;
  804. break;
  805. }
  806. break;
  807. default:
  808. RRETURN(E_ADS_BAD_PATHNAME);
  809. }
  810. if (pDisplayCh) {
  811. *pDisplayCh++ = c;
  812. }
  813. }
  814. }
  815. __declspec(dllexport)
  816. HRESULT
  817. CLexer::GetNextToken(LPTSTR szToken, LPDWORD pdwToken)
  818. {
  819. RRETURN (GetNextToken(szToken, NULL, pdwToken));
  820. }
  821. //+---------------------------------------------------------------------------
  822. // Function:
  823. //
  824. // Synopsis:
  825. //
  826. // Arguments:
  827. //
  828. // Returns:
  829. //
  830. // Modifies:
  831. //
  832. // History: 11-3-95 krishnag Created.
  833. //
  834. //----------------------------------------------------------------------------
  835. TCHAR
  836. CLexer::NextChar()
  837. {
  838. if (_ptr == NULL || *_ptr == TEXT('\0')) {
  839. _dwEndofString = TRUE;
  840. return(TEXT('\0'));
  841. }
  842. return(*_ptr++);
  843. }
  844. //+---------------------------------------------------------------------------
  845. // Function:
  846. //
  847. // Synopsis:
  848. //
  849. // Arguments:
  850. //
  851. // Returns:
  852. //
  853. // Modifies:
  854. //
  855. // History: 11-3-95 krishnag Created.
  856. //
  857. //----------------------------------------------------------------------------
  858. HRESULT
  859. CLexer::PushBackToken()
  860. {
  861. if (_dwLastToken == TOKEN_END) {
  862. RRETURN(S_OK);
  863. }
  864. _ptr -= _dwLastTokenLength;
  865. RRETURN(S_OK);
  866. }
  867. //+---------------------------------------------------------------------------
  868. // Function:
  869. //
  870. // Synopsis:
  871. //
  872. // Arguments:
  873. //
  874. // Returns:
  875. //
  876. // Modifies:
  877. //
  878. // History: 11-3-95 krishnag Created.
  879. //
  880. //----------------------------------------------------------------------------
  881. void
  882. CLexer::PushbackChar()
  883. {
  884. if (_dwEndofString) {
  885. return;
  886. }
  887. _ptr--;
  888. }
  889. //+---------------------------------------------------------------------------
  890. // Function:
  891. //
  892. // Synopsis:
  893. //
  894. // Arguments:
  895. //
  896. // Returns:
  897. //
  898. // Modifies:
  899. //
  900. // History: 11-3-95 krishnag Created.
  901. //
  902. //----------------------------------------------------------------------------
  903. BOOL
  904. CLexer::IsKeyword(LPTSTR szToken, LPDWORD pdwToken)
  905. {
  906. DWORD i = 0;
  907. for (i = 0; i < gdwKeywordListSize; i++) {
  908. if (!_tcsicmp(szToken, KeywordList[i].Keyword)) {
  909. *pdwToken = KeywordList[i].dwTokenId;
  910. return(TRUE);
  911. }
  912. }
  913. *pdwToken = 0;
  914. return(FALSE);
  915. }
  916. //+---------------------------------------------------------------------------
  917. //Function:
  918. //
  919. //Synopsis:
  920. //
  921. //Arguments:
  922. //
  923. //Returns:
  924. //
  925. //Modifies:
  926. //
  927. //History: 11-3-95 krishnag Created.
  928. //
  929. //----------------------------------------------------------------------------
  930. HRESULT
  931. AddComponent(POBJECTINFO pObjectInfo,
  932. LPTSTR szComponent,
  933. LPTSTR szValue,
  934. LPTSTR szDisplayComponent,
  935. LPTSTR szDisplayValue
  936. )
  937. {
  938. if (!szComponent || !*szComponent || !szDisplayComponent || !*szDisplayComponent) {
  939. RRETURN(E_FAIL);
  940. }
  941. if ( pObjectInfo->NumComponents < MAXCOMPONENTS ) {
  942. pObjectInfo->ComponentArray[pObjectInfo->NumComponents].szComponent =
  943. szComponent;
  944. pObjectInfo->ComponentArray[pObjectInfo->NumComponents].szValue =
  945. szValue;
  946. pObjectInfo->DisplayComponentArray[pObjectInfo->NumComponents].szComponent =
  947. szDisplayComponent;
  948. pObjectInfo->DisplayComponentArray[pObjectInfo->NumComponents].szValue =
  949. szDisplayValue;
  950. pObjectInfo->NumComponents++;
  951. RRETURN(S_OK);
  952. } else {
  953. RRETURN(E_ADS_BAD_PATHNAME);
  954. }
  955. }
  956. HRESULT
  957. AddProviderName(POBJECTINFO pObjectInfo, LPTSTR szToken)
  958. {
  959. if (!szToken || !*szToken) {
  960. RRETURN(E_FAIL);
  961. }
  962. if (_tcscmp(szToken, szLDAPNamespaceName) == 0 ||
  963. _tcscmp(szToken, szGCNamespaceName) == 0) {
  964. //
  965. // szProviderName is the provider name for both LDAP and GC namespaces
  966. //
  967. pObjectInfo->ProviderName = szProviderName;
  968. }
  969. else {
  970. //
  971. // Not one of the namespaces we handle, just copy
  972. //
  973. pObjectInfo->ProviderName = szToken;
  974. }
  975. RRETURN(S_OK);
  976. }
  977. HRESULT
  978. AddNamespaceName(POBJECTINFO pObjectInfo, LPTSTR szToken)
  979. {
  980. if (!szToken || !*szToken) {
  981. RRETURN(E_FAIL);
  982. }
  983. pObjectInfo->NamespaceName = szToken;
  984. RRETURN(S_OK);
  985. }
  986. HRESULT
  987. AddTreeName(POBJECTINFO pObjectInfo, LPTSTR szToken, LPWSTR szDisplayToken)
  988. {
  989. if (!szToken || !*szToken || !szDisplayToken || !*szDisplayToken) {
  990. RRETURN(E_FAIL);
  991. }
  992. pObjectInfo->TreeName = szToken;
  993. pObjectInfo->DisplayTreeName = szDisplayToken;
  994. RRETURN(S_OK);
  995. }
  996. HRESULT
  997. AddPortNumber(POBJECTINFO pObjectInfo, DWORD dwPort)
  998. {
  999. pObjectInfo->PortNumber = dwPort;
  1000. RRETURN(S_OK);
  1001. }
  1002. //+---------------------------------------------------------------------------
  1003. // Function:
  1004. //
  1005. // Synopsis:
  1006. //
  1007. // Arguments:
  1008. //
  1009. // Returns:
  1010. //
  1011. // Modifies:
  1012. //
  1013. // History: 11-3-95 krishnag Created.
  1014. //
  1015. //----------------------------------------------------------------------------
  1016. HRESULT
  1017. SetType(POBJECTINFO pObjectInfo, DWORD dwToken)
  1018. {
  1019. pObjectInfo->ObjectType = dwToken;
  1020. RRETURN(S_OK);
  1021. }
  1022. void
  1023. CLexer::SetAtDisabler(
  1024. BOOL bFlag
  1025. )
  1026. {
  1027. _bAtDisabled = bFlag;
  1028. }
  1029. BOOL
  1030. CLexer::GetAtDisabler()
  1031. {
  1032. return(_bAtDisabled);
  1033. }
  1034. void
  1035. CLexer::SetFSlashDisabler(
  1036. BOOL bFlag
  1037. )
  1038. {
  1039. _bFSlashDisabled = bFlag;
  1040. }
  1041. BOOL
  1042. CLexer::GetFSlashDisabler()
  1043. {
  1044. return(_bFSlashDisabled);
  1045. }
  1046. void
  1047. CLexer::SetExclaimnationDisabler(
  1048. BOOL bFlag
  1049. )
  1050. {
  1051. _bExclaimDisabled = bFlag;
  1052. }
  1053. BOOL
  1054. CLexer::GetExclaimnationDisabler()
  1055. {
  1056. return(_bExclaimDisabled);
  1057. }
  1058. HRESULT
  1059. GetDisplayName(
  1060. LPWSTR szName,
  1061. LPWSTR *ppszDisplayName
  1062. )
  1063. {
  1064. HRESULT hr = S_OK;
  1065. DWORD len = 0;
  1066. LPWSTR pch = szName;
  1067. LPWSTR pszDisplayCh = NULL, pszDisplay = NULL;
  1068. BOOL fQuoteMode = FALSE; // TRUE means we're processing between
  1069. // quotation marks
  1070. BOOL fEscaped = FALSE; // TRUE means next one char to be
  1071. // processed should be treated as literal
  1072. if (!ppszDisplayName ) {
  1073. RRETURN (E_INVALIDARG);
  1074. }
  1075. *ppszDisplayName = NULL;
  1076. if (!szName) {
  1077. RRETURN (S_OK);
  1078. }
  1079. pch = szName;
  1080. //
  1081. // Parsing Algorithm:
  1082. //
  1083. // If this char follows an unescaped backslash:
  1084. // Treat as literal, treat next char regularly (set fEscaped = FALSE)
  1085. // Else, if we're between quotation marks:
  1086. // If we see a quotation mark, leave quote mode
  1087. // Else, treat as literal
  1088. // Else, if we're not between quote marks, and we see a quote mark:
  1089. // Enter quote mode
  1090. // Else, if we see a backslash (and we're not already in escape or quote
  1091. // mode):
  1092. // Treat next char as literal (set fEscaped = TRUE)
  1093. // Else, if we see a forward-slash (and we're not in escape or quote mode):
  1094. // We need to escape it by prefixing with a backslash
  1095. // Else:
  1096. // Do nothing, just a plain old character
  1097. // Go on to next character, and repeat
  1098. //
  1099. // Backslashes inside quotation marks are always treated as literals,
  1100. // since that is the definition of being inside quotation marks
  1101. //
  1102. while (*pch) {
  1103. if (fEscaped) {
  1104. fEscaped = FALSE;
  1105. }
  1106. else if (fQuoteMode) {
  1107. if (*pch == L'"') {
  1108. fQuoteMode = FALSE;
  1109. }
  1110. }
  1111. else if (*pch == L'"') {
  1112. fQuoteMode = TRUE;
  1113. }
  1114. else if (*pch == L'\\') {
  1115. fEscaped = TRUE;
  1116. }
  1117. else if (*pch == L'/') {
  1118. //
  1119. // include space for the escape char
  1120. // we'll need to add
  1121. //
  1122. len++;
  1123. }
  1124. len++;
  1125. pch++;
  1126. }
  1127. pszDisplay = (LPWSTR) AllocADsMem((len+1) * sizeof(WCHAR));
  1128. if (!pszDisplay) {
  1129. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1130. }
  1131. pch = szName;
  1132. pszDisplayCh = pszDisplay;
  1133. fEscaped = FALSE;
  1134. fQuoteMode = FALSE;
  1135. while (*pch) {
  1136. if (fEscaped) {
  1137. fEscaped = FALSE;
  1138. }
  1139. else if (fQuoteMode) {
  1140. if (*pch == L'"') {
  1141. fQuoteMode = FALSE;
  1142. }
  1143. }
  1144. else if (*pch == L'"') {
  1145. fQuoteMode = TRUE;
  1146. }
  1147. else if (*pch == L'\\') {
  1148. fEscaped = TRUE;
  1149. }
  1150. else if (*pch == L'/') {
  1151. //
  1152. // unescaped forward slash needs to get escaped
  1153. //
  1154. *pszDisplayCh++ = L'\\';
  1155. }
  1156. *pszDisplayCh++ = *pch;
  1157. pch++;
  1158. }
  1159. *pszDisplayCh = L'\0';
  1160. *ppszDisplayName = pszDisplay;
  1161. error:
  1162. RRETURN(hr);
  1163. }
  1164. //
  1165. // Convert an ADs path to LDAP path
  1166. //
  1167. HRESULT
  1168. GetLDAPTypeName(
  1169. LPWSTR szName,
  1170. LPWSTR *ppszDisplayName
  1171. )
  1172. {
  1173. HRESULT hr = S_OK;
  1174. DWORD len = 0;
  1175. LPWSTR pch = NULL;
  1176. LPWSTR pszDisplayCh = NULL;
  1177. LPWSTR pszDisplay = NULL;
  1178. if (!ppszDisplayName ) {
  1179. RRETURN(E_ADS_BAD_PATHNAME);
  1180. }
  1181. *ppszDisplayName = NULL;
  1182. if (!szName) {
  1183. RRETURN (E_ADS_BAD_PATHNAME);
  1184. }
  1185. pch = szName;
  1186. //
  1187. // Parsing algorithm
  1188. // if this character is an escaped back slash
  1189. // if next character is a forward slash (we know this is a kind of ADsPath)
  1190. // we will remove the back slash
  1191. // accepts the current character
  1192. // goes on to process the next character
  1193. //
  1194. while (*pch) {
  1195. if(*pch == L'\\') {
  1196. pch++;
  1197. //
  1198. // If next character is /, we need to remove the escape character
  1199. //
  1200. if(*pch != L'/') {
  1201. len++;
  1202. }
  1203. }
  1204. if(*pch) {
  1205. len++;
  1206. pch++;
  1207. }
  1208. }
  1209. pszDisplay = (LPWSTR) AllocADsMem((len+1) * sizeof(WCHAR));
  1210. if (!pszDisplay) {
  1211. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1212. }
  1213. pch = szName;
  1214. pszDisplayCh = pszDisplay;
  1215. while (*pch) {
  1216. if(*pch == L'\\') {
  1217. //
  1218. // If next character is /, we need to remove the escape character
  1219. //
  1220. pch++;
  1221. if(*pch != L'/') {
  1222. *pszDisplayCh++ = L'\\';
  1223. }
  1224. }
  1225. if(*pch) {
  1226. *pszDisplayCh++ = *pch;
  1227. pch++;
  1228. }
  1229. }
  1230. *pszDisplayCh = L'\0';
  1231. *ppszDisplayName = pszDisplay;
  1232. error:
  1233. RRETURN(hr);
  1234. }