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.

924 lines
25 KiB

  1. /*****************************************************************************/
  2. /** Microsoft LAN Manager **/
  3. /** Copyright(c) Microsoft Corp., 1987-1999 **/
  4. /*****************************************************************************/
  5. /*****************************************************************************
  6. File : attrnode.cxx
  7. Title : attribute node routines
  8. History :
  9. 04-Aug-1991 VibhasC Created
  10. *****************************************************************************/
  11. #pragma warning ( disable : 4514 4710 )
  12. /****************************************************************************
  13. local defines and includes
  14. ****************************************************************************/
  15. #include "nulldefs.h"
  16. extern "C"
  17. {
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <ctype.h>
  22. }
  23. #include "allnodes.hxx"
  24. #include "cmdana.hxx"
  25. #include "buffer.hxx"
  26. #include "mbcs.hxx"
  27. #define W_CHAR_T_STRLEN_NAME ("MIDL_wchar_strlen")
  28. #define CHAR_STRLEN_NAME ("MIDL_ascii_strlen")
  29. /****************************************************************************
  30. external data
  31. ****************************************************************************/
  32. extern CMD_ARG * pCommand;
  33. extern SymTable * pBaseSymTbl;
  34. /****************************************************************************
  35. external procedures
  36. ****************************************************************************/
  37. extern void ParseError( STATUS_T, char *);
  38. extern int HexCheck(char *);
  39. extern node_skl * pBaseImplicitHandle;
  40. /****************************************************************************/
  41. /****************************************************************************
  42. node_base_attr:
  43. ****************************************************************************/
  44. const char * const AttrNodeNameArray[ ACF_ATTR_END ] =
  45. {
  46. "[none]"
  47. ,"[first_is]"
  48. ,"[last_is]"
  49. ,"[length_is]"
  50. ,"[min_is]"
  51. ,"[max_is]"
  52. ,"[size_is]"
  53. ,"[range]"
  54. ,"[case]"
  55. ,"[funcdescattr]"
  56. ,"[idldescattr]"
  57. ,"[typedescattr]"
  58. ,"[vardescattr]"
  59. ,"[type attribute]"
  60. ,"[member attribute]"
  61. ,"[id]"
  62. ,"[helpcontext]"
  63. ,"[helpstringcontext]"
  64. ,"[lcid]" // ATTR_LCID - applied to libraries - associated with an LCID constant
  65. ,"[dllname]"
  66. ,"[helpstring]"
  67. ,"[helpfile]"
  68. ,"[helpstringdll]"
  69. ,"[entry]"
  70. ,"[uuid]"
  71. ,"[async_uuid]"
  72. ,"[version]"
  73. ,"[switch_is]"
  74. ,"[iid_is]"
  75. ,"[defaultvalue]"
  76. ,"[transmit_as]"
  77. ,"[wire_marshal]"
  78. ,"[represent_as]"
  79. ,"[call_as]" // last attribute that may not appear more than once
  80. ,"[custom]"
  81. ,"[switch_type]"
  82. ,"[handle]"
  83. ,"[user_marshal]"
  84. ,"[ms_union]"
  85. ,"[ms_conf_struct]"
  86. ,"[v1_enum]"
  87. ,"[lcid]" // ATTR_FLCID - applied to parameters - bit attribute
  88. ,"[hidden]"
  89. ,"[ptr kind]"
  90. ,"[string]"
  91. ,"[bstring]"
  92. ,"[endpoint]"
  93. ,"[local]"
  94. ,"[object]"
  95. ,"[ignore]"
  96. ,"[opaque]"
  97. ,"[idempotent]"
  98. ,"[broadcast]"
  99. ,"[maybe]"
  100. ,"[async]"
  101. ,"[input_sync]"
  102. ,"[byte_count]"
  103. ,"[callback]"
  104. ,"[message]"
  105. ,"[in]"
  106. ,"[out]"
  107. ,"[partial_ignore]"
  108. ,"[default]"
  109. ,"[context_handle]"
  110. ,"[code]"
  111. ,"[nocode]"
  112. ,"[optimize]"
  113. ,"[comm_status]"
  114. ,"[fault_status]"
  115. ,"[allocate]"
  116. ,"[heap]"
  117. ,"[implicit_handle]"
  118. ,"[explicit_handle]"
  119. ,"[auto_handle]"
  120. ,"[ptrsize]"
  121. ,"[notify]"
  122. ,"[notify_flag]"
  123. ,"[enable_allocate]"
  124. ,"[encode]"
  125. ,"[decode]"
  126. ,"[strict_context_handle]"
  127. ,"[context_handle_noserialize]"
  128. ,"[context_handle_serialize]"
  129. ,"[force_allocate]"
  130. ,"[cs_drtag]"
  131. ,"[cs_rtag]"
  132. ,"[cs_stag]"
  133. ,"[cs_char]"
  134. ,"[cs_tag_rtn]"
  135. };
  136. const char * PtrKindArray[] =
  137. {
  138. "",
  139. "[ref]",
  140. "[unique]",
  141. "[full]"
  142. };
  143. const char * TypeAttrArray[] =
  144. {
  145. "[public]",
  146. "[appobject]",
  147. "[control]",
  148. "[dual]",
  149. "[licensed]",
  150. "[nonextensible]",
  151. "[oleautomation]",
  152. "[noncreatable]",
  153. "[aggregatable]",
  154. "[proxy]"
  155. };
  156. const char * MemberAttrArray[] =
  157. {
  158. "[readonly]",
  159. "[source]",
  160. "[bindable]",
  161. "[displaybind]",
  162. "[defaultbind]",
  163. "[requestedit]",
  164. "[propget]",
  165. "[propput]",
  166. "[propputref]",
  167. "[restricted]",
  168. "[optional]",
  169. "[retval]",
  170. "[vararg]",
  171. "[predeclid]",
  172. "[uidefault]",
  173. "[nonbrowsable]",
  174. "[defaultcollelem]",
  175. "[defaultvtable]",
  176. "[immediatebind]",
  177. "[usesgetlasterror]",
  178. "[replaceable]"
  179. };
  180. char *
  181. node_base_attr::GetNodeNameString()
  182. {
  183. int At = (int) GetAttrID();
  184. MIDL_ASSERT ( At < sizeof(AttrNodeNameArray)/sizeof(char *) );
  185. if ( At == ATTR_PTR_KIND )
  186. return (char *) PtrKindArray[ ((node_ptr_attr *)this)->GetPtrKind() ];
  187. if ( At == ATTR_TYPE )
  188. return (char *) TypeAttrArray[ ((node_type_attr *)this)->GetAttr() - TATTR_BEGIN];
  189. if ( At == ATTR_MEMBER )
  190. return (char *) MemberAttrArray[ ((node_member_attr *)this)->GetAttr() - MATTR_BEGIN];
  191. return (char *) AttrNodeNameArray[ (int) At ];
  192. }
  193. /****************************************************************************
  194. ATTRLIST::Merge
  195. Merge two ATTRLISTs -- singly linked linear lists - insert at head
  196. ****************************************************************************/
  197. void
  198. ATTRLIST::Merge(ATTRLIST & MoreAttrs )
  199. {
  200. node_base_attr * pCur = MoreAttrs.pHead;
  201. if (pCur == NULL)
  202. {
  203. return;
  204. }
  205. while (pCur->pNext)
  206. {
  207. pCur = pCur->pNext;
  208. }
  209. pCur->pNext = pHead;
  210. pHead = MoreAttrs.pHead;
  211. };
  212. /****************************************************************************
  213. ATTRLIST::Reverse
  214. Reverse an ATTRLIST -- singly linked linear list
  215. ****************************************************************************/
  216. void
  217. ATTRLIST::Reverse()
  218. {
  219. node_base_attr * pCur = pHead;
  220. node_base_attr * pNext;
  221. node_base_attr * pPrev = NULL;
  222. while (pCur)
  223. {
  224. pNext = pCur->pNext;
  225. pCur->pNext = pPrev;
  226. // advance to the next node
  227. pPrev = pCur;
  228. pCur = pNext;
  229. }
  230. pHead = pPrev;
  231. };
  232. /****************************************************************************
  233. ATTRLIST::FInSummary
  234. Search for matching attribute -- singly linked linear lists
  235. ****************************************************************************/
  236. BOOL
  237. ATTRLIST::FInSummary(ATTR_T flag )
  238. {
  239. node_base_attr * pCur = pHead;
  240. while (pCur)
  241. {
  242. if ( pCur->AttrID == flag )
  243. {
  244. return TRUE;
  245. };
  246. pCur = pCur->pNext;
  247. }
  248. return FALSE;
  249. };
  250. /****************************************************************************
  251. ATTRLIST::FMATTRInSummary
  252. Search for matching MEMEBER attribute -- singly linked linear lists
  253. ****************************************************************************/
  254. BOOL
  255. ATTRLIST::FMATTRInSummary(MATTR_T flag)
  256. {
  257. node_base_attr * pCur = pHead;
  258. while (pCur)
  259. {
  260. if ( pCur->AttrID == ATTR_MEMBER)
  261. {
  262. if (((node_member_attr *)pCur)->GetAttr() == flag)
  263. return TRUE;
  264. };
  265. pCur = pCur->pNext;
  266. }
  267. return FALSE;
  268. };
  269. /****************************************************************************
  270. ATTRLIST::FTATTRInSummary
  271. Search for matching MEMEBER attribute -- singly linked linear lists
  272. ****************************************************************************/
  273. BOOL
  274. ATTRLIST::FTATTRInSummary(TATTR_T flag)
  275. {
  276. node_base_attr * pCur = pHead;
  277. while (pCur)
  278. {
  279. if ( pCur->AttrID == ATTR_TYPE)
  280. {
  281. if (((node_member_attr *)pCur)->GetAttr() == flag)
  282. return TRUE;
  283. };
  284. pCur = pCur->pNext;
  285. }
  286. return FALSE;
  287. };
  288. /****************************************************************************
  289. ATTRLIST::GetAttribute
  290. Search for matching attribute -- singly linked linear lists
  291. ****************************************************************************/
  292. node_base_attr *
  293. ATTRLIST::GetAttribute(ATTR_T flag )
  294. {
  295. node_base_attr * pCur = pHead;
  296. while (pCur)
  297. {
  298. if ( pCur->AttrID == flag )
  299. {
  300. return pCur;
  301. }
  302. pCur = pCur->pNext;
  303. }
  304. return NULL;
  305. };
  306. /****************************************************************************
  307. ATTRLIST::Remove
  308. ****************************************************************************/
  309. void
  310. ATTRLIST::Remove( ATTR_T flag )
  311. {
  312. node_base_attr* pCur = pHead;
  313. node_base_attr* pPrev = 0;
  314. while (pCur)
  315. {
  316. if ( pCur->AttrID == flag )
  317. {
  318. if ( pPrev )
  319. {
  320. pPrev->pNext = pCur->pNext;
  321. }
  322. else
  323. {
  324. pHead = pHead->pNext;
  325. }
  326. delete pCur;
  327. }
  328. pPrev = pCur;
  329. pCur = pCur->pNext;
  330. }
  331. }
  332. /****************************************************************************
  333. ATTRLIST::GetAttributeList
  334. Return entire attribute list
  335. ****************************************************************************/
  336. STATUS_T
  337. ATTRLIST::GetAttributeList(type_node_list * pTNList )
  338. {
  339. node_base_attr * pCur = pHead;
  340. while (pCur)
  341. {
  342. pTNList->SetPeer( (node_skl *)pCur );
  343. pCur = pCur->pNext;
  344. }
  345. return (pHead) ? STATUS_OK: I_ERR_NO_MEMBER;
  346. };
  347. /****************************************************************************
  348. ATTRLIST::Clone
  349. Return an attribute list with all new attribute nodes
  350. ****************************************************************************/
  351. ATTRLIST
  352. ATTRLIST::Clone()
  353. {
  354. node_base_attr * pCur = pHead;
  355. ATTRLIST NewList;
  356. NewList.MakeAttrList();
  357. while (pCur)
  358. {
  359. // gaj - does this reverse the list ?? and if so is it OK?
  360. NewList.Add( pCur->Clone() );
  361. pCur = pCur->pNext;
  362. }
  363. return NewList;
  364. };
  365. /****************************************************************************
  366. ATTRLIST::Dump
  367. Dump all attributes on list
  368. ****************************************************************************/
  369. void
  370. ATTRLIST::Dump( ISTREAM* pStream)
  371. {
  372. node_base_attr * pCur = pHead;
  373. while (pCur)
  374. {
  375. int At = (int) pCur->GetAttrID();
  376. if ( At == ATTR_CASE )
  377. {
  378. pStream->Write( "[case(" );
  379. /*
  380. I removed this section just before check in for midl 3.00.12
  381. as it somehow was messing up with the print type's Buffer
  382. at the typedef level for an upper struct, when the
  383. expression had a (DWORD) cast in it.
  384. repro: test10, problem from spoolss. Rkk.
  385. expr_list * pExprList;
  386. expr_node * pExpr;
  387. BOOL fFirstExpr = TRUE;
  388. pExprList = ((node_case *)pCur)->GetExprList();
  389. pExprList->Init();
  390. while (( pExprList->GetPeer( &pExpr ) == STATUS_OK ))
  391. {
  392. if ( fFirstExpr )
  393. fFirstExpr = FALSE;
  394. else
  395. pStream->Write( "," );
  396. if ( pExpr )
  397. pExpr->Print( pStream );
  398. }
  399. */
  400. pStream->Write( ")]" );
  401. }
  402. else
  403. {
  404. // returns a "[attrname]" string
  405. pStream->Write( pCur->GetNodeNameString() );
  406. }
  407. pCur = pCur->pNext;
  408. }
  409. };
  410. /****************************************************************************
  411. miscellaneous attributes
  412. ****************************************************************************/
  413. inline unsigned long
  414. HexToULong( const char * pStr)
  415. {
  416. unsigned long Cumulative = 0;
  417. for ( ; *pStr; pStr++ )
  418. {
  419. Cumulative <<= 4;
  420. // add in another nibble
  421. Cumulative += ( *pStr >= 'a' ) ? ( *pStr - 'a' + 10 )
  422. : ( *pStr >= 'A' ) ? ( *pStr - 'A' + 10 )
  423. : ( *pStr - '0' );
  424. }
  425. return Cumulative;
  426. }
  427. #define GUID_STRING_1_SIZE 8
  428. #define GUID_STRING_2_SIZE 4
  429. #define GUID_STRING_3_SIZE 4
  430. #define GUID_STRING_4_SIZE 4
  431. #define GUID_STRING_5_SIZE 12
  432. void
  433. GUID_STRS::SetValue()
  434. {
  435. char buffer[GUID_STRING_5_SIZE + 2];
  436. int i,j;
  437. Value.Data1 = HexToULong( str1 );
  438. Value.Data2 = (unsigned short) HexToULong( str2 );
  439. Value.Data3 = (unsigned short) HexToULong( str3 );
  440. // go through the last strings backwards, advancing the null
  441. // byte as we go.
  442. // compute bytes 1 and 0
  443. strncpy( buffer, str4, GUID_STRING_4_SIZE+1 );
  444. for ( i = GUID_STRING_4_SIZE/2 - 1, j=GUID_STRING_4_SIZE-2 ; i >=0 ; i--, j-=2 )
  445. {
  446. Value.Data4[i] = (unsigned char) HexToULong( &buffer[j] );
  447. buffer[j] = '\0';
  448. }
  449. // compute bytes 7 to 2
  450. strncpy( buffer, str5, GUID_STRING_5_SIZE+1 );
  451. for ( i = GUID_STRING_5_SIZE/2 + 1, j=GUID_STRING_5_SIZE-2 ; i >=2 ; i--, j-=2 )
  452. {
  453. Value.Data4[i] = (unsigned char) HexToULong( &buffer[j] );
  454. buffer[j] = '\0';
  455. }
  456. }
  457. node_guid::node_guid(char* pIn, ATTR_T At ) : ma( At )
  458. {
  459. char * p1 = pIn,
  460. * p2 = (p1) ? (strchr( p1+1 , '-')) : 0,
  461. * p3 = (p2) ? (strchr( p2+1 , '-')) : 0,
  462. * p4 = (p3) ? (strchr( p3+1 , '-')) : 0,
  463. * p5 = (p4) ? (strchr( p4+1 , '-')) : 0;
  464. if( p1 && p2 && p3 && p4 && p5 )
  465. {
  466. *p2++ = *p3++ = *p4++ = *p5++ = '\0';
  467. CheckAndSetGuid( p1, p2, p3, p4, p5 );
  468. }
  469. else
  470. ParseError( UUID_FORMAT, (char *)0 );
  471. }
  472. node_guid::node_guid (
  473. char * pStr1,
  474. char * pStr2,
  475. char * pStr3,
  476. char * pStr4,
  477. char * pStr5,
  478. ATTR_T At ) : ma( At )
  479. {
  480. CheckAndSetGuid( pStr1, pStr2, pStr3, pStr4, pStr5 );
  481. }
  482. void
  483. node_guid::GetStrs (
  484. char ** pStr1,
  485. char ** pStr2,
  486. char ** pStr3,
  487. char ** pStr4,
  488. char ** pStr5 )
  489. {
  490. *pStr1 = cStrs.str1;
  491. *pStr2 = cStrs.str2;
  492. *pStr3 = cStrs.str3;
  493. *pStr4 = cStrs.str4;
  494. *pStr5 = cStrs.str5;
  495. };
  496. void
  497. node_guid::CheckAndSetGuid(
  498. char * pStr1,
  499. char * pStr2,
  500. char * pStr3,
  501. char * pStr4,
  502. char * pStr5 )
  503. {
  504. cStrs.SetStrs( pStr1, pStr2, pStr3, pStr4, pStr5 );
  505. int Len1 = (int) strlen(pStr1);
  506. int Len2 = (int) strlen(pStr2);
  507. int Len3 = (int) strlen(pStr3);
  508. int Len4 = (int) strlen(pStr4);
  509. int Len5 = (int) strlen(pStr5);
  510. if( (Len1 == GUID_STRING_1_SIZE) &&
  511. (Len2 == GUID_STRING_2_SIZE) &&
  512. (Len3 == GUID_STRING_3_SIZE) &&
  513. (Len4 == GUID_STRING_4_SIZE) &&
  514. (Len5 == GUID_STRING_5_SIZE) )
  515. {
  516. if( !HexCheck(pStr1) ||
  517. !HexCheck(pStr2) ||
  518. !HexCheck(pStr3) ||
  519. !HexCheck(pStr4) ||
  520. !HexCheck(pStr5) )
  521. {
  522. ParseError(UUID_NOT_HEX, (char *)NULL);
  523. }
  524. else
  525. {
  526. guidstr = new char[ Len1 + Len2 + Len3 + Len4 + Len5 + 5 ];
  527. strcpy(guidstr, pStr1);
  528. strcat(guidstr, "-");
  529. strcat(guidstr, pStr2);
  530. strcat(guidstr, "-");
  531. strcat(guidstr, pStr3);
  532. strcat(guidstr, "-");
  533. strcat(guidstr, pStr4);
  534. strcat(guidstr, "-");
  535. strcat(guidstr, pStr5);
  536. }
  537. }
  538. else
  539. {
  540. ParseError(UUID_FORMAT, (char *)NULL);
  541. }
  542. }
  543. node_version::node_version(
  544. unsigned long vMajor,
  545. unsigned long vMinor ) : nbattr( ATTR_VERSION )
  546. {
  547. major = vMajor;
  548. minor = vMinor;
  549. if( (major > 0x0000ffff ) || (minor > 0x0000ffff))
  550. ParseError( VERSION_FORMAT, (char *)0);
  551. }
  552. node_version::node_version(char * pV ) : nbattr(ATTR_VERSION)
  553. {
  554. char * pMinor;
  555. char * pMajor = pV;
  556. BOOL fError = TRUE;
  557. major = minor = 0;
  558. if( pMajor && *pMajor )
  559. {
  560. if( ( pMinor = strchr( pMajor, '.' ) ) != 0 )
  561. {
  562. fError = TRUE;
  563. if( *(++pMinor) )
  564. {
  565. minor = strtoul( pMinor, &pMinor, 10 );
  566. if( ! *pMinor )
  567. fError = FALSE;
  568. }
  569. }
  570. else
  571. fError = FALSE;
  572. if( fError == FALSE )
  573. {
  574. //use pMinor to save pMajor value;
  575. major = strtoul( pMinor = pMajor, &pMajor, 10 );
  576. if( (*pMajor && (*pMajor != '.' )) || (pMajor == pMinor) )
  577. fError = TRUE;
  578. }
  579. }
  580. if( (fError == TRUE ) ||
  581. (major > (unsigned long )0x0000ffff) ||
  582. (minor > (unsigned long )0x0000ffff) )
  583. {
  584. ParseError( VERSION_FORMAT, (char *)0 );
  585. }
  586. }
  587. STATUS_T
  588. node_version::GetVersion(
  589. unsigned short *pMajor,
  590. unsigned short *pMinor )
  591. {
  592. *pMajor = (unsigned short) major;
  593. *pMinor = (unsigned short) minor;
  594. return STATUS_OK;
  595. }
  596. node_endpoint::node_endpoint(char * pEndPointString ) : nbattr( ATTR_ENDPOINT )
  597. {
  598. SetEndPointString( pEndPointString );
  599. }
  600. void
  601. node_endpoint::SetEndPointString(
  602. char * pString )
  603. {
  604. ENDPT_PAIR * pEntry = new ENDPT_PAIR;
  605. char * p1 = pString;
  606. char * p2 = 0;
  607. char * pTemp;
  608. short Len;
  609. STATUS_T Status = ENDPOINT_SYNTAX;
  610. //
  611. // Parse the string. Note that we can assume that the string is at least
  612. // a null string, because it came from the parser. If it wasnt a string,
  613. // the parser would have barfed anyhow.
  614. //
  615. // Firstly, the string must have a ':' separator. Also, it must have
  616. // at least 1 character before the :.
  617. //
  618. if( pString && (pTemp = strchr( pString , ':' ) ) != 0 && ((pTemp - pString) > 0) )
  619. {
  620. //
  621. // pick up the first part of the string.
  622. //
  623. Len = short( pTemp - pString );
  624. p1 = new char [ Len + 1 ]; // one for null.
  625. strncpy( p1, pString, Len );
  626. p1[ Len ] = '\0';
  627. //
  628. // pick up the last part of the string. Skip beyond the :. There can be
  629. // some characters after the : and before the '['. This is the server
  630. // name. Then follows the port within the []. The actual string will
  631. // not have the [].
  632. //
  633. // skip the :
  634. pTemp += 1;
  635. // find out the total length of the string. Allocate 2 less than that
  636. // 'cause we dont need the '[' and ']'. The string must be more than
  637. // 2 characters 'cause it must have the brackets anyhow.
  638. Len = (short) strlen( pTemp );
  639. if( (Len > 2 ) &&
  640. (strchr( pTemp, '[' )) &&
  641. (pTemp[ Len - 1] == ']'))
  642. {
  643. char *p2Cur;
  644. while( *pTemp != '[' )
  645. {
  646. pTemp++;
  647. Len--;
  648. }
  649. //
  650. // in the second half of the parse, just get the whole string till
  651. // the null. Now the user could be perverted, he could have a
  652. // ] embedded within the string, in addition to the last ]. To
  653. // ensure that he gets what he deserves, transfer till the end
  654. // except the last character which must be ']'.
  655. pTemp++; Len--;
  656. p2Cur = p2 = new char[ Len ]; // Yes, not Len + 1 'cause we are
  657. // going to re-use the last char
  658. // which is ] for the null.
  659. strncpy( p2Cur, pTemp, --Len );
  660. p2Cur[ Len ] = '\0';
  661. Status = STATUS_OK;
  662. }
  663. else
  664. {
  665. delete p1;
  666. }
  667. }
  668. if( Status != STATUS_OK )
  669. {
  670. ParseError( Status, pString );
  671. p1 = p2 = 0;
  672. }
  673. //
  674. // set up the pair.
  675. //
  676. pEntry->pString1 = p1;
  677. pEntry->pString2 = p2;
  678. EndPointStringList.Insert( pEntry );
  679. }
  680. ITERATOR &
  681. node_endpoint::GetEndPointPairs()
  682. {
  683. EndPointStringList.Init();
  684. return EndPointStringList;
  685. }
  686. /****************************************************************************
  687. utility routines
  688. ****************************************************************************/
  689. int
  690. HexCheck(char *pStr)
  691. {
  692. if(pStr && *pStr)
  693. {
  694. while(*pStr)
  695. {
  696. if(! isxdigit(*pStr)) return 0;
  697. pStr++;
  698. }
  699. return 1;
  700. }
  701. return 0;
  702. }
  703. //+---------------------------------------------------------------------------
  704. //
  705. // Function: TranslateEscapeSequences
  706. //
  707. // Purpose: Replaces a string's escape sequences with the appropriate
  708. // ASCII characters.
  709. //
  710. // NOTE: this can be done in place because the resulting string
  711. // length will always be shorter than or equal to the input string
  712. // length.
  713. //
  714. // Assumes: The string is NULL terminated and in writable memory.
  715. //
  716. //----------------------------------------------------------------------------
  717. #define ESCAPE_CHARACTER '\\'
  718. void TranslateEscapeSequences(char * sz)
  719. {
  720. char * pchNextOut = sz;
  721. char ch;
  722. while (0 != (ch = *sz))
  723. {
  724. if ((char)ESCAPE_CHARACTER == ch)
  725. {
  726. ch = *(++sz);
  727. switch ((char)tolower(ch))
  728. {
  729. case '0': // octal sequence
  730. case '1':
  731. case '2':
  732. case '3':
  733. case '4':
  734. case '5':
  735. case '6':
  736. case '7':
  737. {
  738. char count = 3;
  739. unsigned char value = 0;
  740. do
  741. {
  742. value *= 8;
  743. value = unsigned char( value + ch - '0' );
  744. ch = *(++sz);
  745. count--;
  746. }
  747. while (ch <= '8' && ch >= '0' && count);
  748. sz--;
  749. ch = (char) value;
  750. break;
  751. }
  752. case 'x': // hex sequence
  753. {
  754. unsigned char value = 0;
  755. ch = (char)tolower(*(++sz));
  756. if ((ch <= '8' && ch >= '0') || (ch <= 'f' && ch >= 'a'))
  757. {
  758. do
  759. {
  760. value *= 16;
  761. if (ch < 'a')
  762. value = unsigned char(value + ch - '0');
  763. else
  764. value = unsigned char(value + ch - 'a' + 10);
  765. ch = (char)tolower(*(++sz));
  766. }
  767. while ((ch <= '8' && ch >= '0') || (ch <= 'f' && ch >= 'a'));
  768. sz--;
  769. ch = (char) value;
  770. }
  771. else // "\x" with no trailing hex digits is treated as an "x"
  772. {
  773. ch = *(--sz);
  774. }
  775. break;
  776. }
  777. case 'n': // newline
  778. ch = (char) '\n';
  779. break;
  780. case 't': // tab
  781. ch = (char) '\t';
  782. break;
  783. case 'v': // vertical tab
  784. ch = (char) '\v';
  785. break;
  786. case 'b': // backspace
  787. ch = (char) '\b';
  788. break;
  789. case 'r': // carriage return
  790. ch = (char) '\r';
  791. break;
  792. case 'f': // formfeed
  793. ch = (char) '\f';
  794. break;
  795. case 'a': // alert
  796. ch = (char) '\a';
  797. break;
  798. case 0: // just in case the last character in the string is an escape character
  799. ch = (char) ESCAPE_CHARACTER;
  800. sz--;
  801. break;
  802. default:
  803. break;
  804. }
  805. }
  806. *(pchNextOut++) = ch;
  807. ++sz;
  808. if (CurrentCharSet.IsMbcsLeadByte(ch))
  809. *(pchNextOut++) = *(sz++);
  810. }
  811. *(pchNextOut++) = ch;
  812. }