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.

746 lines
19 KiB

  1. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Copyright (c) 1993-1999 Microsoft Corporation
  3. Module Name:
  4. unionndr.hxx
  5. Abstract:
  6. Contains routines for the generation of the new NDR format strings for
  7. unions, and the new NDR marshalling and unmarshalling calls.
  8. Notes:
  9. History:
  10. DKays Nov-1993 Created.
  11. ----------------------------------------------------------------------------*/
  12. #include "becls.hxx"
  13. #pragma hdrstop
  14. void
  15. CG_ENCAPSULATED_STRUCT::GenNdrFormat( CCB * pCCB )
  16. /*++
  17. Routine Description :
  18. Generates the format string for an encapsulated union.
  19. Arguments :
  20. pCCB - pointer to the code control block
  21. Return :
  22. None.
  23. --*/
  24. {
  25. FORMAT_STRING * pFormatString;
  26. CG_BASETYPE * pSwitchIsNode;
  27. CG_UNION * pUnion;
  28. unsigned long SwitchType;
  29. if ( GetFormatStringOffset() != -1 )
  30. return;
  31. pFormatString = pCCB->GetFormatString();
  32. //
  33. // The child of the struct's first field node is the switch_is node.
  34. //
  35. pSwitchIsNode = (CG_BASETYPE *) GetChild()->GetChild();
  36. //
  37. // The child of the struct's second field node is the union node.
  38. //
  39. pUnion = (CG_UNION *) GetChild()->GetSibling()->GetChild();
  40. SetFormatStringOffset( pFormatString->GetCurrentOffset() );
  41. pFormatString->PushFormatChar( FC_ENCAPSULATED_UNION );
  42. //
  43. // The switch type field in the format string has the size of the switch_is
  44. // field (including any needed pading) in the upper four bits and the
  45. // actual switch_is type in the lower four bits.
  46. //
  47. //
  48. // Get the amount to increment the memory pointer to the encapsulated
  49. // union's struct to get to the actual union. This is the total struct
  50. // size minus the union's size (this may not simply be the size of the
  51. // switch_is member because of possible padding).
  52. //
  53. CG_FIELD * pSwitchField;
  54. CG_FIELD * pUnionField;
  55. pSwitchField = (CG_FIELD *) GetChild();
  56. pUnionField = (CG_FIELD *) pSwitchField->GetSibling();
  57. //
  58. // Set the memory increment part of the SwitchType field.
  59. //
  60. SwitchType = ( pUnionField->GetMemOffset() - pSwitchField->GetMemOffset() )
  61. << 4;
  62. if ( pSwitchIsNode->GetFormatChar() == FC_ENUM16 )
  63. SwitchType |= FC_ENUM16;
  64. else
  65. SwitchType |= pSwitchIsNode->GetSignedFormatChar();
  66. pFormatString->PushByte( SwitchType );
  67. pUnion->GenNdrSizeAndArmDescriptions( pCCB );
  68. SetFormatStringEndOffset( pFormatString->GetCurrentOffset() );
  69. // SetFormatStringOffset( pFormatString->OptimizeFragment( this ) );
  70. }
  71. void
  72. CG_UNION::GenNdrFormat( CCB * pCCB )
  73. /*++
  74. Routine Description :
  75. Generates the format string for a non-encapsulated union.
  76. Arguments :
  77. pCCB - pointer to the code control block
  78. Return :
  79. None.
  80. --*/
  81. {
  82. FORMAT_STRING * pFormatString;
  83. long Offset;
  84. SetCCB( pCCB );
  85. if ( GetFormatStringOffset() != -1 )
  86. return;
  87. pFormatString = pCCB->GetFormatString();
  88. SetFormatStringOffset( pFormatString->GetCurrentOffset() );
  89. pFormatString->PushFormatChar( FC_NON_ENCAPSULATED_UNION );
  90. if ( ((CG_BASETYPE *)pCGSwitchType)->GetFormatChar() == FC_ENUM16 )
  91. pFormatString->PushFormatChar( FC_ENUM16 );
  92. else
  93. {
  94. FORMAT_CHARACTER SwitchTypeFc;
  95. // Note that we take the signed format character this time.
  96. SwitchTypeFc = ((CG_BASETYPE *)pCGSwitchType)->GetSignedFormatChar();
  97. #if defined(TARGET_RKK)
  98. if ( pCommand->GetTargetSystem() == NT35 &&
  99. SwitchTypeFc == FC_USMALL )
  100. {
  101. // The NT 807 NDR engine doesn't know about usmall.
  102. pFormatString->PushFormatChar( FC_BYTE );
  103. pFormatString->PushFormatChar( FC_SMALL );
  104. }
  105. else
  106. #endif
  107. pFormatString->PushFormatChar( SwitchTypeFc );
  108. }
  109. GenNdrSwitchIsDescription( pCCB );
  110. Offset = pFormatString->GetCurrentOffset();
  111. pFormatString->PushShortOffset( 0 );
  112. GenNdrSizeAndArmDescriptions( pCCB );
  113. pFormatString->PushShortOffset( GetNdrSizeAndArmDescriptionOffset() - Offset,
  114. Offset );
  115. SetFormatStringEndOffset( pFormatString->GetCurrentOffset() );
  116. // SetFormatStringOffset( pFormatString->OptimizeFragment( this ) );
  117. }
  118. void
  119. CG_UNION::GenNdrFormatArms( CCB * pCCB )
  120. /*++
  121. Routine Description :
  122. Generates the format string for the arms of an encapsulated or a
  123. non-encapsulated union.
  124. Arguments :
  125. pCCB - pointer to the code control block
  126. Return :
  127. None.
  128. --*/
  129. {
  130. CG_ITERATOR Iterator;
  131. CG_CASE * pCase;
  132. CG_NDR * pNdr;
  133. GetMembers( Iterator );
  134. while ( ITERATOR_GETNEXT( Iterator, pCase ) )
  135. {
  136. if ( ! pCase->GetChild() )
  137. continue;
  138. //
  139. // The child of the CG_CASE is a CG_FIELD.
  140. // The child of the CG_FIELD is the actual NDR entity.
  141. //
  142. pNdr = (CG_NDR *) pCase->GetChild()->GetChild();
  143. if ( ! pNdr )
  144. continue;
  145. if ( pNdr && ( ! pNdr->IsSimpleType() || pNdr->GetRangeAttribute() ) )
  146. pNdr->GenNdrFormat( pCCB );
  147. }
  148. }
  149. void
  150. CG_UNION::GenNdrSizeAndArmDescriptions( CCB * pCCB )
  151. /*++
  152. Routine Description :
  153. Generates the memory size and arm description portion of the format
  154. string for an encapsulated or a non-encapsulated union.
  155. Arguments :
  156. pCCB - pointer to the code control block
  157. Return :
  158. None.
  159. --*/
  160. {
  161. FORMAT_STRING * pFormatString;
  162. unsigned short UnionArms;
  163. long FormatOffset;
  164. if ( GetNdrSizeAndArmDescriptionOffset() != -1 )
  165. return;
  166. pFormatString = pCCB->GetFormatString();
  167. SetNdrSizeAndArmDescriptionOffset( pFormatString->GetCurrentOffset() );
  168. #ifdef DUMP_UNION_INFO
  169. FILE * fUnionLog = NULL;
  170. fUnionLog = fopen("c:\\unioninfo.log", "a+t");
  171. if (fUnionLog)
  172. {
  173. char *pName = GetSymName();
  174. unsigned long UnionArms = GetNumberOfArms();
  175. char *pUnionKind = NULL;
  176. unsigned long UnionFlavor = GetUnionFlavor();
  177. char *pFileName = "Unknown";
  178. char *pEnv = pCommand->Is64BitEnv() ? ("64") : ("32");
  179. switch(UnionFlavor)
  180. {
  181. case UNION_UNKNOWN:
  182. pUnionKind = "Union_Unknown";
  183. break;
  184. case UNION_ENCAP:
  185. pUnionKind = "Union_Encap";
  186. break;
  187. case UNION_NONENCAP_DCE:
  188. pUnionKind = "Union_NonEncap_DCE";
  189. break;
  190. case UNION_NONENCAP_MS:
  191. pUnionKind = "Union_NonEncap_MS";
  192. break;
  193. default:
  194. pUnionKind = "Unknown";
  195. break;
  196. }
  197. node_file * pFile = GetType()->GetDefiningFile();
  198. if (pFile && pFile->GetSymName())
  199. pFileName = pFile->GetSymName();
  200. fprintf(fUnionLog, "* %s FileName: %s, Symbol: %s, Kind %u(%s), Arms: %u \n",
  201. pEnv, pFileName, pName, UnionFlavor, pUnionKind, UnionArms);
  202. }
  203. #endif
  204. //
  205. // Set aside the space for the union's description. Then we generate
  206. // the format string description for all the union's arms, and then
  207. // we go back and patch up the the union's description to have the
  208. // proper offsets. This must be done to handle self referencing union
  209. // types.
  210. //
  211. // Memory size.
  212. pFormatString->PushShort( (short) GetMemorySize() );
  213. //
  214. // union_arms<2>
  215. //
  216. UnionArms = (unsigned short) GetNumberOfArms();
  217. if ( GetUnionFlavor() == UNION_NONENCAP_MS )
  218. {
  219. //
  220. // Microsoft union support.
  221. // Set the upper four bits of the union_arm<2> field with the
  222. // the alignment of the largest aligned union arm.
  223. //
  224. UnionArms |= (GetWireAlignment() - 1) << 12;
  225. }
  226. pFormatString->PushShort( (short) UnionArms );
  227. // Get union arms again since we may have just munged it.
  228. UnionArms = (short) GetNumberOfArms();
  229. // The arms.
  230. for ( ; UnionArms-- > 0; )
  231. {
  232. pFormatString->PushLong( 0 );
  233. pFormatString->PushShortOffset( 0 );
  234. }
  235. // default_arm_description<2>
  236. pFormatString->PushShortOffset( 0 );
  237. //
  238. // Generate the format string descriptions of the arms.
  239. //
  240. GenNdrFormatArms( pCCB );
  241. // Find out where the arms' descriptions begin.
  242. FormatOffset = GetNdrSizeAndArmDescriptionOffset() + 4;
  243. CG_ITERATOR Iterator;
  244. CG_CASE * pCase;
  245. CG_NDR * pNdr;
  246. CG_NDR * pNdrDefaultCase;
  247. BOOL DefaultCaseFound;
  248. GetMembers( Iterator );
  249. pNdrDefaultCase = NULL;
  250. DefaultCaseFound = FALSE;
  251. while ( ITERATOR_GETNEXT( Iterator, pCase ) )
  252. {
  253. //
  254. // Check for the default case first.
  255. //
  256. if ( pCase->GetCGID() == ID_CG_DEFAULT_CASE )
  257. {
  258. pNdrDefaultCase = pCase->GetChild() ?
  259. (CG_NDR *) pCase->GetChild()->GetChild() : 0;
  260. DefaultCaseFound = TRUE;
  261. #ifdef DUMP_UNION_INFO
  262. if (fUnionLog)
  263. {
  264. fprintf(fUnionLog, "DEFAULT\n");
  265. }
  266. #endif
  267. continue;
  268. }
  269. //
  270. // Fill in the arm's case value.
  271. //
  272. if (NULL == pCase->GetExpr())
  273. {
  274. RpcError(NULL, 0, NO_CASE_EXPR, GetSymName());
  275. exit(NO_CASE_EXPR);
  276. }
  277. #ifdef DUMP_UNION_INFO
  278. if (fUnionLog)
  279. fprintf(fUnionLog, "%d \n", (long)pCase->GetExpr()->GetValue());
  280. #endif
  281. pFormatString->PushLong( (long)pCase->GetExpr()->GetValue(), FormatOffset );
  282. FormatOffset += 4;
  283. //
  284. // Check for a non-default case with an empty (;) arm.
  285. //
  286. if ( ! pCase->GetChild() || ! pCase->GetChild()->GetChild() )
  287. {
  288. //
  289. // Increment the FormatOffset past the arm description, which
  290. // simply remains zero.
  291. //
  292. FormatOffset += 2;
  293. continue;
  294. }
  295. //
  296. // Else it's a regular case with a valid arm.
  297. //
  298. pNdr = (CG_NDR *) pCase->GetChild()->GetChild();
  299. // Emit a short with type or offset representation.
  300. // For simple types we push <0x80><type>, for others we push offset<2>.
  301. // The engine checks if the first byte is 0x80 to decide how it should
  302. // treat the short, hence the offset range is from 0x8100 to 7fff, i.e.
  303. // the offset of 0x80xx is invalid.
  304. if ( pNdr && pNdr->IsSimpleType() )
  305. {
  306. short s;
  307. //
  308. // The offset in this case is the actual format character for
  309. // the base type, but with a 1 in the upper bit of the short, to
  310. // make it look negative.
  311. //
  312. s = (short) ((CG_BASETYPE *)pNdr)->GetFormatChar();
  313. s |= MAGIC_UNION_SHORT;
  314. pFormatString->PushMagicUnionShort( s, FormatOffset );
  315. }
  316. else
  317. {
  318. //
  319. // The offset pushed here is the usual relative offset, except
  320. // as explained above, it has to be >= 0x8100.
  321. //
  322. pFormatString->PushShortOffset( pNdr->GetFormatStringOffset() -
  323. FormatOffset,
  324. FormatOffset );
  325. }
  326. FormatOffset += 2;
  327. }
  328. //
  329. // Finally, handle the default case.
  330. //
  331. if ( ! DefaultCaseFound )
  332. {
  333. // We push an offset here for easier stub reading as this is an offset..
  334. // However, this would prevent union optimization if we switched it on,
  335. // so at that stage an FS_ marker is needed to generate a comment.
  336. //
  337. pFormatString->PushShortOffset( -1, FormatOffset );
  338. }
  339. else
  340. {
  341. if ( ! pNdrDefaultCase )
  342. pFormatString->PushShortOffset( 0, FormatOffset );
  343. else
  344. {
  345. if ( pNdrDefaultCase->IsSimpleType() )
  346. {
  347. short s;
  348. s = (short) ((CG_BASETYPE *)pNdrDefaultCase)->GetFormatChar();
  349. s |= MAGIC_UNION_SHORT;
  350. pFormatString->PushMagicUnionShort( s, FormatOffset );
  351. }
  352. else
  353. pFormatString->PushShortOffset(
  354. pNdrDefaultCase->GetFormatStringOffset() - FormatOffset,
  355. FormatOffset );
  356. }
  357. }
  358. #ifdef DUMP_UNION_INFO
  359. if (fUnionLog)
  360. {
  361. fprintf(fUnionLog, "+\n");
  362. fprintf(fUnionLog, "\n");
  363. fclose(fUnionLog);
  364. }
  365. #endif
  366. }
  367. BOOL
  368. CG_UNION::CanUseBuffer()
  369. {
  370. CG_ITERATOR Iterator;
  371. CG_CASE * pCase;
  372. CG_NDR * pNdr;
  373. unsigned long Size;
  374. long Align;
  375. long TempBufAlign;
  376. //
  377. // We will be very strict, since there is not much room for
  378. // leeway. Only return TRUE if all arms have the same size, the same
  379. // wire alignment, and matching wire/memory alignments & sizes.
  380. //
  381. // The real scenario we're after is a union with all pointer arms or
  382. // longs. This is fairly common in NT.
  383. //
  384. GetMembers( Iterator );
  385. Size = 0;
  386. Align = 0;
  387. while ( ITERATOR_GETNEXT( Iterator, pCase ) )
  388. {
  389. if ( ! pCase->GetChild() ||
  390. (pNdr = (CG_NDR *) pCase->GetChild()->GetChild()) == 0 )
  391. continue;
  392. TempBufAlign = pNdr->GetWireAlignment();
  393. if ( (pNdr->GetWireSize() != pNdr->GetMemorySize()) ||
  394. (pNdr->GetMemoryAlignment() != TempBufAlign) )
  395. return FALSE;
  396. if ( ! Size )
  397. {
  398. Size = pNdr->GetWireSize();
  399. Align = TempBufAlign;
  400. continue;
  401. }
  402. if ( (Size != pNdr->GetWireSize()) || (Align != TempBufAlign) )
  403. return FALSE;
  404. }
  405. return TRUE;
  406. }
  407. void
  408. CG_UNION::GenNdrSwitchIsDescription( CCB * pCCB )
  409. /*++
  410. Routine Description :
  411. This routine generates the switch_type<1> and switch_is_description<4>
  412. field for a non-encapsulated union.
  413. Arguments :
  414. pCCB - pointer to the code control block
  415. Return :
  416. None.
  417. --*/
  418. {
  419. CG_NDR * pParamOrField;
  420. CG_FIELD * pField;
  421. expr_node * pSwitchExpr;
  422. BOOL IsPointer;
  423. pParamOrField = pCCB->GetLastPlaceholderClass();
  424. //
  425. // Get the switch is expression.
  426. //
  427. switch ( pParamOrField->GetCGID() )
  428. {
  429. case ID_CG_PARAM :
  430. pSwitchExpr = ((CG_PARAM *)pParamOrField)->GetSwitchExpr();
  431. // If it's top level param then this flag doesn't matter.
  432. IsPointer = FALSE;
  433. break;
  434. case ID_CG_FIELD :
  435. pField = (CG_FIELD *) pParamOrField;
  436. pSwitchExpr = pField->GetSwitchExpr();
  437. // Check if the field is actually a pointer to a union.
  438. IsPointer = ((CG_NDR *)pField->GetChild())->IsPointer();
  439. break;
  440. default :
  441. MIDL_ASSERT(0);
  442. }
  443. GenNdrFormatAttributeDescription( pCCB,
  444. NULL,
  445. pSwitchExpr,
  446. IsPointer,
  447. TRUE,
  448. FALSE,
  449. FALSE,
  450. pCommand->IsSwitchDefined( SWITCH_ROBUST ) );
  451. }
  452. void
  453. CG_UNION::SetFormatStringOffset( long Offset )
  454. {
  455. CCB * pCCB;
  456. CG_NDR * pParamOrFieldNode;
  457. pCCB = GetCCB();
  458. pParamOrFieldNode = pCCB->GetLastPlaceholderClass();
  459. if ( pParamOrFieldNode->GetCGID() == ID_CG_PARAM )
  460. ((CG_PARAM *)pParamOrFieldNode)->SetUnionFormatStringOffset( Offset );
  461. else
  462. ((CG_FIELD *)pParamOrFieldNode)->SetUnionFormatStringOffset( Offset );
  463. }
  464. long
  465. CG_UNION::GetFormatStringOffset()
  466. {
  467. CCB * pCCB;
  468. CG_NDR * pParamOrFieldNode;
  469. pCCB = GetCCB();
  470. pParamOrFieldNode = pCCB->GetLastPlaceholderClass();
  471. if ( pParamOrFieldNode->GetCGID() == ID_CG_PARAM )
  472. return ((CG_PARAM *)pParamOrFieldNode)->GetUnionFormatStringOffset();
  473. else
  474. return ((CG_FIELD *)pParamOrFieldNode)->GetUnionFormatStringOffset();
  475. }
  476. void
  477. CG_ENCAPSULATED_STRUCT::GenNdrPointerFixUp( CCB * pCCB,
  478. CG_STRUCT * pStruct )
  479. {
  480. //
  481. // For an encapsulated struct, call this method on the actual union.
  482. // Remember that the encap struct's child is a CG_FIELD whose sibling's
  483. // child will be the actual union.
  484. //
  485. ((CG_UNION*)(GetChild()->GetSibling()->GetChild()))->
  486. GenNdrPointerFixUp( pCCB, pStruct );
  487. }
  488. void
  489. CG_UNION::GenNdrPointerFixUp( CCB * pCCB,
  490. CG_STRUCT * pStruct )
  491. {
  492. CG_ITERATOR Iterator;
  493. CG_NDR * pMember;
  494. CG_NDR * pNdr;
  495. long OffsetOffset;
  496. if ( IsInFixUp() )
  497. return;
  498. SetFixUpLock( TRUE );
  499. OffsetOffset = GetNdrSizeAndArmDescriptionOffset() + 4;
  500. GetMembers( Iterator );
  501. while ( ITERATOR_GETNEXT( Iterator, pMember ) )
  502. {
  503. if ( ! pMember->GetChild() ||
  504. ! pMember->GetChild()->GetChild() )
  505. {
  506. OffsetOffset += 6;
  507. continue;
  508. }
  509. //
  510. // Child of the case is a CG_FIELD - get it's child to get the
  511. // actual Ndr entity.
  512. //
  513. pNdr = (CG_NDR *) pMember->GetChild()->GetChild();
  514. if ( pNdr == pStruct )
  515. {
  516. //
  517. // Patch up the offset.
  518. //
  519. OffsetOffset += 4;
  520. pCCB->GetFormatString()->PushShortOffset(
  521. pStruct->GetFormatStringOffset() - OffsetOffset,
  522. OffsetOffset );
  523. OffsetOffset += 2;
  524. continue;
  525. }
  526. if ( (pNdr->GetCGID() == ID_CG_PTR) ||
  527. (pNdr->GetCGID() == ID_CG_SIZE_PTR) ||
  528. (pNdr->GetCGID() == ID_CG_SIZE_LENGTH_PTR) )
  529. {
  530. CG_POINTER * pPointer = (CG_POINTER *) pNdr;
  531. //
  532. // Check if we're ready for this guy yet.
  533. //
  534. if ( pPointer->GetFormatStringOffset() == -1 )
  535. continue;
  536. // Get the pointee.
  537. pNdr = (CG_NDR *) pNdr->GetChild();
  538. //
  539. // If the pointer's pointee is the struct we're checking for,
  540. // then patch up the pointer's offset_to_description<2> field.
  541. //
  542. if ( pNdr == pStruct )
  543. {
  544. long PointerOffset;
  545. //
  546. // Get the offset in the format string where the
  547. // offset_to_description<2> field of the pointer is.
  548. //
  549. PointerOffset = pPointer->GetFormatStringOffset() + 2;
  550. pCCB->GetFormatString()->PushShortOffset(
  551. pStruct->GetFormatStringOffset() - PointerOffset,
  552. PointerOffset );
  553. OffsetOffset += 6;
  554. continue;
  555. }
  556. }
  557. //
  558. // Continue the chase if necessary.
  559. //
  560. if ( pNdr->IsStruct() || pNdr->IsUnion() || pNdr->IsArray() )
  561. pNdr->GenNdrPointerFixUp( pCCB, pStruct );
  562. OffsetOffset += 6;
  563. }
  564. SetFixUpLock( FALSE );
  565. }