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.

738 lines
22 KiB

  1. #include "stdinc.h"
  2. HRESULT
  3. SxspExtractPathPieces(
  4. _bstr_t bstSourceName,
  5. _bstr_t &bstPath,
  6. _bstr_t &bstName
  7. )
  8. {
  9. HRESULT hr = S_OK;
  10. PCWSTR cwsOriginal = static_cast<PCWSTR>(bstSourceName);
  11. PWSTR cwsSlashSpot;
  12. cwsSlashSpot = wcsrchr( cwsOriginal, L'\\' );
  13. if ( cwsSlashSpot )
  14. {
  15. *cwsSlashSpot = L'\0';
  16. bstName = _bstr_t( cwsSlashSpot + 1 );
  17. bstPath = cwsSlashSpot;
  18. }
  19. else
  20. {
  21. bstPath = L"";
  22. bstName = bstSourceName;
  23. }
  24. return hr;
  25. }
  26. HRESULT
  27. SxspSimplifyPutAttribute(
  28. ISXSManifestPtr Document,
  29. ::ATL::CComPtr<IXMLDOMNamedNodeMap> Attributes,
  30. const wstring AttribName,
  31. const wstring Value,
  32. const wstring NamespaceURI
  33. )
  34. {
  35. ::ATL::CComPtr<IXMLDOMNode> pAttribNode;
  36. ::ATL::CComPtr<IXMLDOMAttribute> pAttribActual;
  37. ::ATL::CComPtr<IXMLDOMNode> pTempNode;
  38. HRESULT hr;
  39. //
  40. // Get the attribute from our namespace
  41. //
  42. hr = Attributes->getQualifiedItem(
  43. _bstr_t(AttribName.c_str()),
  44. _bstr_t(NamespaceURI.c_str()),
  45. &pAttribNode);
  46. if ( SUCCEEDED( hr ) )
  47. {
  48. //
  49. // If we had success, but the attribute node is null, then we have to
  50. // go create one, which is tricky.
  51. //
  52. if ( pAttribNode == NULL )
  53. {
  54. VARIANT vt;
  55. vt.vt = VT_INT;
  56. vt.intVal = NODE_ATTRIBUTE;
  57. //
  58. // Do the actual creation part
  59. //
  60. hr = Document->createNode(
  61. vt,
  62. _bstr_t(AttribName.c_str()),
  63. _bstr_t(NamespaceURI.c_str()),
  64. &pTempNode);
  65. if ( FAILED( hr ) )
  66. {
  67. wstringstream ss;
  68. ss << wstring(L"Can't create the new attribute node ") << AttribName;
  69. ReportError( ErrorFatal, ss );
  70. goto lblGetOut;
  71. }
  72. //
  73. // Now we go and put that item into the map.
  74. //
  75. if ( FAILED( hr = Attributes->setNamedItem( pTempNode, &pAttribNode ) ) )
  76. goto lblGetOut;
  77. }
  78. hr = pAttribNode->put_text( _bstr_t(Value.c_str()) );
  79. }
  80. lblGetOut:
  81. // SAFERELEASE( pAttribNode );
  82. // SAFERELEASE( pTempNode );
  83. return hr;
  84. }
  85. HRESULT
  86. SxspSimplifyGetAttribute(
  87. ::ATL::CComPtr<IXMLDOMNamedNodeMap> Attributes,
  88. wstring AttribName,
  89. wstring &Destination,
  90. wstring NamespaceURI
  91. )
  92. {
  93. ::ATL::CComPtr<IXMLDOMNode> NodeValue;
  94. HRESULT hr = S_OK;
  95. BSTR _bst_pretemp;
  96. Destination = L"";
  97. if ( FAILED( hr = Attributes->getNamedItem(
  98. _bstr_t(AttribName.c_str()),
  99. &NodeValue
  100. ) ) )
  101. {
  102. goto lblBopOut;
  103. }
  104. else if ( NodeValue == NULL )
  105. {
  106. goto lblBopOut;
  107. }
  108. else
  109. {
  110. if ( FAILED( hr = NodeValue->get_text( &_bst_pretemp ) ) )
  111. {
  112. goto lblBopOut;
  113. }
  114. Destination = _bstr_t(_bst_pretemp,FALSE);
  115. }
  116. lblBopOut:
  117. return hr;
  118. }
  119. wostream& operator<<(
  120. wostream& ost,
  121. const CPostbuildProcessListEntry& thing
  122. )
  123. {
  124. ost << wstring(L"(path=") << thing.manifestFullPath.c_str()
  125. << wstring(L" name=")<< thing.name.c_str()
  126. << wstring(L" version=") << thing.version.c_str()
  127. << wstring(L" language=") << thing.language.c_str() << wstring(L")");
  128. return ost;
  129. }
  130. bool g_bDisplaySpew = false, g_bDisplayWarnings = true;
  131. bool FileExists( const wstring& str )
  132. {
  133. return (GetFileAttributesW(str.c_str()) != -1) &&
  134. ((GetLastError() == ERROR_FILE_NOT_FOUND) || (GetLastError() == ERROR_PATH_NOT_FOUND));
  135. }
  136. wstring JustifyPath( const wstring& str )
  137. {
  138. vector<WCHAR> vec;
  139. DWORD dwCount = GetLongPathNameW( str.c_str(), NULL, 0 );
  140. if (dwCount == 0)
  141. {
  142. wstringstream ws;
  143. dwCount = ::GetLastError();
  144. ws << wstring(L"Unable to get the length of the 'long name' of ") << str
  145. << wstring(L" error ") << dwCount;
  146. ReportError( ErrorFatal, ws);
  147. exit(1);
  148. }
  149. vec.resize( dwCount );
  150. GetLongPathNameW( str.c_str(), &vec.front(), vec.size() );
  151. return wstring( &vec.front() );
  152. }
  153. void CPostbuildProcessListEntry::setManifestLocation( wstring root, wstring where )
  154. {
  155. manifestFullPath = root + L"\\" + where;
  156. manifestPathOnly = manifestFullPath.substr( 0, manifestFullPath.find_last_of( L'\\' ) );
  157. manifestFileName = manifestFullPath.substr( manifestFullPath.find_last_of( L'\\' ) + 1 );
  158. if ( !FileExists( manifestFullPath ) )
  159. {
  160. wstringstream ss;
  161. ss << wstring(L"Referenced manifest ") << where << wstring(L" does not exist.");
  162. ReportError(ErrorSpew, ss);
  163. }
  164. }
  165. //
  166. // Converts a series of strings, foo=bar chunklets, space-seperated, into a map
  167. // from 'foo' to 'bar'
  168. //
  169. StringStringMap
  170. MapFromDefLine(const wstring& source, wchar_t wchBreakValue)
  171. {
  172. wstring::const_iterator here = source.begin();
  173. StringStringMap rvalue;
  174. //
  175. //
  176. // The tricky bit is that there could be spaces in quoted strings...
  177. //
  178. while ( here != source.end() )
  179. {
  180. wstring tag, value;
  181. wchar_t end_of_value = L' ';
  182. wstring::const_iterator equals;
  183. //
  184. // Look for an equals first
  185. //
  186. equals = find( here, source.end(), L'=' );
  187. //
  188. // If there is no equals sign, stop.
  189. //
  190. if (equals == source.end())
  191. break;
  192. tag.assign( here, equals );
  193. //
  194. // Hop over the equals
  195. //
  196. here = equals;
  197. here++;
  198. //
  199. // If the equals sign was the last character in the wstring, stop.
  200. //
  201. if (here == source.end())
  202. break;
  203. //
  204. // Is 'here' at an open quote? Then extract everything to the next
  205. // quote, remembering to skip this quote as well
  206. //
  207. if ( *here == L'\"' )
  208. {
  209. end_of_value = L'\"';
  210. here++;
  211. //
  212. // If the quote was the last character in the wstring, stop.
  213. //
  214. if (here == source.end())
  215. break;
  216. }
  217. //
  218. // Now go and look for the end of the wstring, or a quote or a space.
  219. //
  220. wstring::const_iterator fullstring = find( here, source.end(), end_of_value );
  221. value.assign( here, fullstring );
  222. //
  223. // If it was a quote or a space, skip it. If end of wstring, stay put.
  224. //
  225. if (fullstring != source.end())
  226. here = fullstring + 1;
  227. rvalue.insert( pair<wstring,wstring>( tag, value ) );
  228. //
  229. // Skip whitespace, but stop if we hit the end of the wstring.
  230. //
  231. while (here != source.end() && (*here == L' ' || *here == L'\t' || *here == '\n' || *here == '\r' || iswspace(*here)))
  232. here++;
  233. }
  234. return rvalue;
  235. }
  236. const wstring c_wsp_usage = wstring(L"-?");
  237. const wstring c_wsp_nologo = wstring(L"-nologo");
  238. const wstring c_wsp_verbose = wstring(L"-verbose");
  239. const wstring c_wsp_manifest = wstring(L"-manifest");
  240. const wstring c_wsp_hashupdate = wstring(L"-hashupdate");
  241. const wstring c_wsp_makecdfs = wstring(L"-makecdfs");
  242. const wstring c_wsp_razzle = wstring(L"-razzle");
  243. const wstring c_wsp_binplacelog = wstring(L"-binplacelog");
  244. const wstring c_wsp_asmsroot = wstring(L"-asmsroot");
  245. const wstring c_wsp_cdfpath = wstring(L"-cdfpath");
  246. const wstring c_wsp_version = wstring(L"-version");
  247. const wstring c_wsp_name = wstring(L"-name");
  248. const wstring c_wsp_language = wstring(L"-language");
  249. const wstring c_wsp_type = wstring(L"-type");
  250. const wstring c_wsp_pkt = wstring(L"-publickeytoken");
  251. const wstring c_wsp_procarch = wstring(L"-processorarchitecture");
  252. const wstring c_wsp_depends = wstring(L"-dependency");
  253. const wstring c_wsp_freshassembly = wstring(L"-freshassembly");
  254. CParameters::CParameters() : m_fVerbose(false), m_fNoLogo(false), m_fUpdateHash(false), m_fUsage(false),
  255. m_fCreateCdfs(false), m_fDuringRazzle(false), m_fSingleItem(false), m_fCreateNewAssembly(false)
  256. {
  257. }
  258. bool
  259. CParameters::ChunkifyParameters(UINT uiP, WCHAR** ppwszParams)
  260. {
  261. for (UINT i = 0; i < uiP; i++)
  262. {
  263. this->m_Parameters.push_back(wstring(ppwszParams[i]));
  264. }
  265. return true;
  266. }
  267. bool
  268. CParameters::ParseDependentString(const wstring & ws, CSimpleIdentity & target)
  269. {
  270. wstring::const_iterator here = ws.begin();
  271. wstring::const_iterator i;
  272. target.wsLanguage = wstring(L"*");
  273. target.wsProcessorArchitecture = wstring(L"*");
  274. target.wsName = target.wsPublicKeyToken = target.wsType = target.wsVersion = wstring(L"");
  275. //
  276. // Find the name part of the identity
  277. //
  278. if ((i = find(ws.begin(), ws.end(), L',')) == ws.end())
  279. return false;
  280. target.wsName = wstring(ws.begin(), i);
  281. here = i + 1;
  282. //
  283. // Now, let's look for the name:namespace= part of the name-value pair
  284. //
  285. while (here != ws.end())
  286. {
  287. std::wstring wsThisAttributePart;
  288. std::wstring wsValueName;
  289. std::wstring wsValueValue;
  290. std::wstring wsValueNamespace;
  291. std::wstring::const_iterator close_quote;
  292. i = std::find(here, ws.end(), L'=');
  293. if (i == ws.end())
  294. return false;
  295. wsThisAttributePart = wstring(here, i++);
  296. //
  297. // The cursor had better not be at the end of the string yet.
  298. //
  299. if (i == ws.end())
  300. return false;
  301. // No namespace thing in this string, so we can skip it
  302. if (find(wsThisAttributePart.begin(), wsThisAttributePart.end(), L':') == wsThisAttributePart.end())
  303. {
  304. wsValueName = wsThisAttributePart;
  305. }
  306. //
  307. // i should be at the quote right after the =. Make sure of that.
  308. //
  309. if (*i++ != L'\'')
  310. return false;
  311. close_quote = find(i, ws.end(), L'\'');
  312. if (close_quote == ws.end())
  313. return false;
  314. wsValueValue = wstring(i, close_quote);
  315. static const std::wstring c_ws_version = wstring(L"version");
  316. static const std::wstring c_ws_language = wstring(L"language");
  317. static const std::wstring c_ws_publicKeyToken = wstring(L"publicKeyToken");
  318. static const std::wstring c_ws_type = wstring(L"type");
  319. static const std::wstring c_ws_processorArchitecture = wstring(L"processorArchitecture");
  320. if (wsValueNamespace.length() == 0)
  321. {
  322. if (wsValueName == c_ws_version) {
  323. target.wsVersion = wsValueValue;
  324. }
  325. else if (wsValueName == c_ws_language) {
  326. target.wsLanguage = wsValueValue;
  327. }
  328. else if (wsValueName == c_ws_publicKeyToken) {
  329. target.wsPublicKeyToken = wsValueValue;
  330. }
  331. else if (wsValueName == c_ws_type) {
  332. target.wsType = wsValueValue;
  333. }
  334. else if (wsValueName == c_ws_processorArchitecture) {
  335. target.wsProcessorArchitecture = wsValueValue;
  336. }
  337. else {
  338. return false;
  339. }
  340. }
  341. else
  342. {
  343. target.OtherValues.push_back(
  344. CSimpleIdentity::CUnknownIdentityThing(
  345. wsValueNamespace,
  346. wsValueName,
  347. wsValueValue));
  348. }
  349. here = close_quote + 1;
  350. if (here == ws.end())
  351. break;
  352. else if (*here != L',')
  353. return false;
  354. here++;
  355. }
  356. return true;
  357. }
  358. CParameters::SetParametersResult
  359. CParameters::SetComandLine(UINT uiParameters, WCHAR** wszParameters)
  360. {
  361. std::vector<wstring>::const_iterator ci;
  362. class CMatching {
  363. public:
  364. const wstring &wsparam;
  365. wstring &wstarget;
  366. CMatching(const wstring& p, wstring &t) : wsparam(p), wstarget(t) { }
  367. };
  368. CMatching SingleParamThings[] = {
  369. CMatching(c_wsp_binplacelog, m_BinplaceLog),
  370. CMatching(c_wsp_cdfpath, m_CdfOutputPath),
  371. CMatching(c_wsp_asmsroot, m_AsmsRoot),
  372. CMatching(c_wsp_manifest, m_SingleEntry.wsManifestPath),
  373. CMatching(c_wsp_version, m_SingleEntry.wsVersion),
  374. CMatching(c_wsp_name, m_SingleEntry.wsName),
  375. CMatching(c_wsp_language, m_SingleEntry.wsLanguage),
  376. CMatching(c_wsp_procarch, m_SingleEntry.wsProcessorArchitecture),
  377. CMatching(c_wsp_type, m_SingleEntry.wsType),
  378. CMatching(c_wsp_pkt, m_SingleEntry.wsPublicKeyToken)
  379. };
  380. if (!ChunkifyParameters(uiParameters, wszParameters))
  381. {
  382. return eCommandLine_usage;
  383. }
  384. for (ci = m_Parameters.begin(); ci != m_Parameters.end(); ci++)
  385. {
  386. wstring ws = *ci;
  387. m_fVerbose |= (*ci == c_wsp_verbose);
  388. m_fNoLogo |= (*ci == c_wsp_nologo);
  389. m_fUpdateHash |= (*ci == c_wsp_hashupdate);
  390. m_fCreateCdfs |= (*ci == c_wsp_makecdfs);
  391. m_fDuringRazzle |= (*ci == c_wsp_razzle);
  392. m_fCreateNewAssembly |= (*ci == c_wsp_freshassembly);
  393. //
  394. // Things that have a single parameter
  395. //
  396. for (int i = 0; i < NUMBER_OF(SingleParamThings); i++)
  397. {
  398. if (SingleParamThings[i].wsparam == *ci)
  399. {
  400. std::vector<wstring>::const_iterator cinext = ci + 1;
  401. if ((cinext == m_Parameters.end()) || ((*cinext).at(0) == L'-'))
  402. {
  403. std::wstringstream wss;
  404. wss << *ci << wstring(L" requires an extra parameter");
  405. ReportError(ErrorFatal, wss);
  406. return eCommandLine_usage;
  407. }
  408. SingleParamThings[i].wstarget = *cinext;
  409. }
  410. }
  411. //
  412. // Injecting a dependency gathers up a 'textual identity' string that's
  413. // turned into an assemblyIdentity statement and added to the dependency
  414. //
  415. if (*ci == c_wsp_depends)
  416. {
  417. CSimpleIdentity Dependent;
  418. if ((ci + 1) == m_Parameters.end() || ((*(ci+1)).at(0) == L'-'))
  419. {
  420. std::wstringstream wss;
  421. wss << *ci << wstring(L" needs a parameter blob");
  422. ReportError(ErrorFatal, wss);
  423. return eCommandLine_usage;
  424. }
  425. // These can be defaulted
  426. Dependent.wsLanguage = Dependent.wsProcessorArchitecture = wstring(L"*");
  427. if (ParseDependentString(*++ci, Dependent))
  428. {
  429. this->m_InjectDependencies.push_back(Dependent);
  430. }
  431. else
  432. {
  433. std::wstringstream wss;
  434. wss << *ci << wstring(L" isn't a valid dependency statement");
  435. ReportError(ErrorFatal, wss);
  436. return eCommandLine_usage;
  437. }
  438. }
  439. }
  440. //
  441. // Was there a single manifestish thing?
  442. //
  443. if (this->m_SingleEntry.wsManifestPath.length() != 0)
  444. {
  445. WCHAR wchBlob[MAX_PATH];
  446. this->m_fSingleItem = TRUE;
  447. GetCurrentDirectoryW(NUMBER_OF(wchBlob), wchBlob);
  448. m_SinglePostbuildItem.setManifestLocation(wstring(wchBlob), m_SingleEntry.wsManifestPath);
  449. m_SinglePostbuildItem.language = m_SingleEntry.wsLanguage;
  450. m_SinglePostbuildItem.version = m_SingleEntry.wsVersion;
  451. m_SinglePostbuildItem.name = m_SingleEntry.wsName;
  452. }
  453. return m_fNoLogo ? eCommandLine_nologo : eCommandLine_normal;
  454. }
  455. std::string ConvertWString(const wstring& src)
  456. {
  457. vector<CHAR> chBuffer;
  458. int iChars;
  459. iChars = WideCharToMultiByte(CP_ACP, 0, src.c_str(), -1, NULL, 0, NULL, NULL);
  460. if (iChars > 0)
  461. {
  462. chBuffer.resize(iChars);
  463. WideCharToMultiByte(CP_ACP, 0, src.c_str(), -1, &chBuffer.front(), chBuffer.size(), NULL, NULL);
  464. }
  465. return std::string(&chBuffer.front());
  466. }
  467. std::wstring ConvertString(const std::string& source)
  468. {
  469. std::vector<WCHAR> wch;
  470. wch.resize( MultiByteToWideChar( CP_ACP, 0, source.data(), source.size(), NULL, 0 ) );
  471. MultiByteToWideChar( CP_ACP, 0, source.data(), source.size(), &wch.front(), wch.size() );
  472. return std::wstring( wch.begin(), wch.end() );
  473. }
  474. bool AllWhitespace(const wstring& ws)
  475. {
  476. return (ws.find_first_not_of(L"\r\n \t") == wstring::npos);
  477. }
  478. //
  479. // Strip out all whitespace
  480. //
  481. HRESULT UglifyXmlNode(::ATL::CComPtr<IXMLDOMNode> Parent)
  482. {
  483. ::ATL::CComPtr<IXMLDOMNode> Iterator;
  484. HRESULT hr;
  485. Parent->get_firstChild(&Iterator);
  486. while (Iterator != NULL)
  487. {
  488. DOMNodeType NodeType;
  489. ::ATL::CComPtr<IXMLDOMNode> ThisNode;
  490. ThisNode = Iterator;
  491. Iterator = NULL;
  492. //
  493. // Move the iterator forward one, but keep ThisNode put
  494. //
  495. if (FAILED(hr = ThisNode->get_nextSibling(&Iterator)))
  496. return hr;
  497. if (FAILED(hr = ThisNode->get_nodeType(&NodeType)))
  498. return hr;
  499. if (NodeType == NODE_TEXT)
  500. {
  501. BSTR bst;
  502. if (FAILED(hr = ThisNode->get_text(&bst)))
  503. return hr;
  504. if (AllWhitespace(wstring(_bstr_t(bst, false))))
  505. {
  506. if (FAILED(hr = Parent->removeChild(ThisNode, NULL)))
  507. return hr;
  508. }
  509. }
  510. else if (NodeType == NODE_ELEMENT)
  511. {
  512. if (FAILED(hr = UglifyXmlNode(ThisNode)))
  513. return hr;
  514. }
  515. }
  516. return S_OK;
  517. }
  518. HRESULT UglifyXmlDocument(ISXSManifestPtr DocumentPtr)
  519. {
  520. ::ATL::CComPtr<IXMLDOMElement> RootElement;
  521. ::ATL::CComPtr<IXMLDOMNode> RootNode;
  522. HRESULT hr;
  523. //
  524. // Clean up all adjacent-whitespace chunklets
  525. //
  526. if (FAILED(hr = DocumentPtr->get_documentElement(&RootElement)))
  527. return hr;
  528. if (FAILED(hr = RootElement->normalize()))
  529. return hr;
  530. if (FAILED(hr = RootElement.QueryInterface(&RootNode)))
  531. return hr;
  532. if (FAILED(hr = UglifyXmlNode(RootNode)))
  533. return hr;
  534. return S_OK;
  535. }
  536. HRESULT PrettyFormatXmlNode(::ATL::CComPtr<IXMLDOMNode> ThisNode, int iLevel)
  537. {
  538. ::ATL::CComPtr<IXMLDOMDocument> Document;
  539. ::ATL::CComPtr<IXMLDOMNode> pIterator;
  540. bool fHasChildren = false;
  541. DOMNodeType NodeType = NODE_INVALID;
  542. HRESULT hr;
  543. if (FAILED(hr = ThisNode->get_ownerDocument(&Document)))
  544. return hr;
  545. ThisNode->get_firstChild(&pIterator);
  546. while (pIterator != NULL)
  547. {
  548. ::ATL::CComPtr<IXMLDOMText> CreatedNode;
  549. ::ATL::CComPtr<IXMLDOMNode> pNext;
  550. fHasChildren = true;
  551. wstring ws = wstring(L"\r\n");
  552. ws.append(iLevel * 2, L' ');
  553. if (FAILED(hr = pIterator->get_nodeType(&NodeType)))
  554. return hr;
  555. if (NodeType != NODE_TEXT)
  556. {
  557. if (FAILED(hr = Document->createTextNode(_bstr_t(ws.c_str()), &CreatedNode)))
  558. return hr;
  559. if (FAILED(hr = ThisNode->insertBefore(CreatedNode, _variant_t(pIterator), NULL)))
  560. return hr;
  561. if (FAILED(PrettyFormatXmlNode(pIterator, iLevel + 1)))
  562. return hr;
  563. if (FAILED(hr = pIterator->get_nextSibling(&pNext)))
  564. return hr;
  565. }
  566. pIterator = pNext;
  567. }
  568. if (fHasChildren && (NodeType != NODE_TEXT))
  569. {
  570. ::ATL::CComPtr<IXMLDOMText> CreatedNode;
  571. wstring ws = wstring(L"\r\n");
  572. ws.append((iLevel - 1) * 2, L' ');
  573. if (FAILED(hr = Document->createTextNode(_bstr_t(ws.c_str()), &CreatedNode)))
  574. return hr;
  575. if (FAILED(hr = ThisNode->appendChild(CreatedNode, NULL)))
  576. return hr;
  577. }
  578. return hr;
  579. }
  580. HRESULT PrettyFormatXmlDocument(ISXSManifestPtr DocumentPtr)
  581. {
  582. ::ATL::CComPtr<IXMLDOMElement> RootElement;
  583. ::ATL::CComPtr<IXMLDOMNode> RootNode;
  584. HRESULT hr;
  585. if (FAILED(hr = DocumentPtr->get_documentElement(&RootElement)))
  586. return hr;
  587. if (FAILED(hr = RootElement.QueryInterface(&RootNode)))
  588. return hr;
  589. if (FAILED(hr = PrettyFormatXmlNode(RootNode, 1)))
  590. return hr;
  591. return hr;
  592. }