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.

466 lines
13 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. pcmwriter.cpp
  5. Abstract:
  6. implementation of Precompiled manifest writer
  7. Author:
  8. Xiaoyu Wu (xiaoyuw) June 2000
  9. Revision History:
  10. --*/
  11. #include "stdinc.h"
  12. #include "pcm.h"
  13. #include "nodefactory.h"
  14. //helper APIs
  15. HRESULT CPrecompiledManifestWriter::SetFactory(IXMLNodeFactory *pNodeFactory)
  16. {
  17. if (! pNodeFactory)
  18. return E_INVALIDARG;
  19. m_pNodeFactory = pNodeFactory;
  20. return NOERROR;
  21. }
  22. HRESULT CPrecompiledManifestWriter::Close()
  23. {
  24. HRESULT hr = NOERROR;
  25. if (m_pFileStream)
  26. hr = m_pFileStream->Close(m_ulRecordCount, m_usMaxNodeCount);
  27. return hr;
  28. }
  29. HRESULT CPrecompiledManifestWriter::Initialize(PCWSTR pcmFileName)
  30. {
  31. HRESULT hr = NOERROR;
  32. CStringBuffer buffFileName;
  33. if ( ! pcmFileName )
  34. return E_INVALIDARG;
  35. hr = buffFileName.Assign(pcmFileName, ::wcslen(pcmFileName));
  36. if (FAILED(hr))
  37. return hr;
  38. // Initialize() is assumed to be called only once
  39. if (m_pFileStream != NULL){
  40. ::FusionpDbgPrintEx(
  41. FUSION_DBG_LEVEL_ERROR,
  42. "SXS.DLL: %S is called more than once\n", __FUNCTION__);
  43. return E_UNEXPECTED;
  44. }
  45. m_pFileStream = new CPrecompiledManifestWriterStream;
  46. if ( !m_pFileStream )
  47. return E_OUTOFMEMORY;
  48. hr = m_pFileStream->SetSink(buffFileName);
  49. if (FAILED(hr))
  50. goto Exit;
  51. hr = WritePCMHeader();
  52. if ( FAILED(hr))
  53. goto Exit;
  54. hr= NOERROR;
  55. Exit:
  56. return hr;
  57. }
  58. // we assume that this pStream is initialized by using SetSink....
  59. HRESULT CPrecompiledManifestWriter::SetWriterStream(CPrecompiledManifestWriterStream * pSinkedStream)
  60. {
  61. if ( ! pSinkedStream )
  62. return E_INVALIDARG;
  63. ASSERT(pSinkedStream->IsSinkedStream() == TRUE);
  64. m_pFileStream = pSinkedStream;
  65. return NOERROR;
  66. }
  67. // write helper APIs
  68. HRESULT CPrecompiledManifestWriter::GetPCMRecordSize(XML_NODE_INFO ** ppNodeInfo, USHORT iNodeCount, ULONG * pSize)
  69. {
  70. ULONG ulSize = 0 ;
  71. XML_NODE_INFO *pNode = NULL;
  72. USHORT i = 0 ;
  73. ULONG ulSingleRecordSize = offsetof(XML_NODE_INFO, pNode);
  74. HRESULT hr = NOERROR;
  75. if ( pSize)
  76. *pSize = 0 ;
  77. if ((!pSize) || (!ppNodeInfo) || (!*ppNodeInfo))
  78. return E_INVALIDARG;
  79. // validate ppNodeInfo
  80. for (i=0;i<iNodeCount;i++)
  81. if (!ppNodeInfo[i])
  82. return E_INVALIDARG;
  83. *pSize = 0;
  84. for ( i=0; i < iNodeCount; i++){
  85. pNode = ppNodeInfo[i];
  86. ASSERT(pNode);
  87. //ulSize += ulSingleRecordSize = sizeof(XML_NODE_INFO)- sizeof(PVOID) - sizeof(PVOID);
  88. ulSize += ulSingleRecordSize = offsetof(XML_NODE_INFO, pNode);
  89. ulSize += pNode->ulLen * sizeof(WCHAR);
  90. }
  91. if ( pSize)
  92. *pSize = ulSize;
  93. return hr;
  94. }
  95. HRESULT CPrecompiledManifestWriter::WritePCMHeader()
  96. {
  97. HRESULT hr = NOERROR;
  98. PCMHeader pcmHeader;
  99. pcmHeader.iVersion = 1;
  100. pcmHeader.ulRecordCount = 0 ;
  101. pcmHeader.usMaxNodeCount = 0 ;
  102. hr = m_pFileStream->WriteWithDelay((PVOID)&(pcmHeader), sizeof(PCMHeader), NULL);
  103. if (FAILED(hr))
  104. goto Exit;
  105. hr = NOERROR;
  106. Exit:
  107. return hr;
  108. }
  109. HRESULT CPrecompiledManifestWriter::WritePCMRecordHeader(PCM_RecordHeader * pHeader)
  110. {
  111. HRESULT hr = NOERROR;
  112. ASSERT(m_pFileStream);
  113. if ( ! pHeader)
  114. return E_INVALIDARG;
  115. hr = m_pFileStream->WriteWithDelay((PVOID)(pHeader), sizeof(PCM_RecordHeader), NULL);
  116. if ( FAILED(hr))
  117. goto Exit;
  118. hr = NOERROR;
  119. Exit:
  120. return hr;
  121. }
  122. inline void FromXMLNodeToPCMXMLNode(PCM_XML_NODE_INFO *pPCMNode, XML_NODE_INFO *pNode)
  123. {
  124. ASSERT(pPCMNode && pNode);
  125. pPCMNode->dwSize = pNode->dwSize;
  126. pPCMNode->dwType = pNode->dwType ;
  127. pPCMNode->dwSubType = pNode->dwSubType ;
  128. pPCMNode->fTerminal = pNode->fTerminal ;
  129. pPCMNode->ulLen = pNode->ulLen ;
  130. pPCMNode->ulNsPrefixLen = pNode->ulNsPrefixLen ;
  131. pPCMNode->offset = 0 ;
  132. return;
  133. }
  134. HRESULT CPrecompiledManifestWriter::WritePCMXmlNodeInfo(XML_NODE_INFO ** ppNodeInfo, USHORT iNodeCount, RECORD_TYPE_PRECOMP_MANIFEST typeID, PVOID param)
  135. {
  136. HRESULT hr = NOERROR;
  137. ULONG offset ;
  138. USHORT i;
  139. PCM_XML_NODE_INFO pcmNode;
  140. XML_NODE_INFO * pNode = NULL ;
  141. USHORT uTextAddr;
  142. USHORT uTextOffset;
  143. ULONG cbWritten;
  144. LPWSTR *ppText = NULL;
  145. ULONG *pcbLen = NULL;
  146. LPWSTR pstr;
  147. ULONG ulLen;
  148. if ((!ppNodeInfo) || (!*ppNodeInfo))
  149. return E_INVALIDARG;
  150. if (!((typeID == ENDCHILDREN_PRECOMP_MANIFEST) || (typeID == BEGINCHILDREN_PRECOMP_MANIFEST) ||
  151. (typeID == CREATENODE_PRECOMP_MANIFEST)))
  152. return E_INVALIDARG;
  153. if (!m_pFileStream)
  154. return E_UNEXPECTED;
  155. //uTextAddr = sizeof(PCM_RecordHeader) + NodeCount * sizeof(PCM_XML_NODE_INFO);
  156. // RecordHeader is read before the boby(XML_NODE_INFO) is read
  157. uTextAddr = iNodeCount * sizeof(PCM_XML_NODE_INFO);
  158. uTextOffset = 0;
  159. if (typeID == ENDCHILDREN_PRECOMP_MANIFEST) // param1 is fEmpty;
  160. uTextAddr += sizeof(BOOL);
  161. else if (typeID == CREATENODE_PRECOMP_MANIFEST) // param1 = linenumber
  162. uTextAddr += sizeof(ULONG);
  163. if ( iNodeCount == 1) { // for BeginChildren and EndChildren
  164. ppText = &pstr;
  165. pcbLen = &ulLen;
  166. }
  167. else
  168. {
  169. ppText = FUSION_NEW_ARRAY(LPWSTR, iNodeCount);
  170. if (!ppText) {
  171. hr = E_OUTOFMEMORY;
  172. goto Exit;
  173. }
  174. pcbLen = FUSION_NEW_ARRAY(ULONG, iNodeCount);
  175. if (!pcbLen ){
  176. hr = E_OUTOFMEMORY;
  177. goto Exit;
  178. }
  179. }
  180. // write all records
  181. for (i=0; i<iNodeCount; i++) {
  182. pNode = ppNodeInfo[i];
  183. if (!pNode) {
  184. hr = E_FAIL;
  185. goto Exit;
  186. }
  187. ppText[i] = (LPWSTR)(pNode->pwcText) ;
  188. pcbLen[i] = pNode->ulLen * sizeof(WCHAR);
  189. //pPCMNode = static_cast<PCM_XML_NODE_INFO *>(pNode);
  190. FromXMLNodeToPCMXMLNode(&pcmNode, pNode); // void function
  191. pcmNode.offset = uTextAddr + uTextOffset;
  192. uTextAddr = uTextAddr + uTextOffset;
  193. uTextOffset = (USHORT)pcmNode.ulLen * sizeof(WCHAR) ;
  194. hr = m_pFileStream->WriteWithDelay((PVOID)&pcmNode, sizeof(PCM_XML_NODE_INFO), &cbWritten);
  195. if ( FAILED(hr))
  196. goto Exit;
  197. }
  198. if ( typeID == ENDCHILDREN_PRECOMP_MANIFEST) // write fEmpty into the file
  199. hr = m_pFileStream->WriteWithDelay(param, sizeof(BOOL), &cbWritten);
  200. else if ( typeID == CREATENODE_PRECOMP_MANIFEST)
  201. hr = m_pFileStream->WriteWithDelay(param, sizeof(ULONG), &cbWritten);
  202. // write texts in all records
  203. for (i=0; i<iNodeCount; i++) {
  204. hr = m_pFileStream->WriteWithDelay((PVOID)ppText[i], (ULONG)pcbLen[i], &cbWritten);
  205. if ( FAILED(hr))
  206. goto Exit;
  207. }
  208. Exit :
  209. if ((ppText) && (ppText != &pstr))
  210. FUSION_DELETE_ARRAY(ppText);
  211. if ( (pcbLen) && ( pcbLen != &ulLen))
  212. FUSION_DELETE_ARRAY(pcbLen);
  213. return hr;
  214. }
  215. // write APIs
  216. HRESULT CPrecompiledManifestWriter::WritePrecompiledManifestRecord(RECORD_TYPE_PRECOMP_MANIFEST typeID,
  217. PVOID pData, USHORT NodeCount, PVOID param)
  218. {
  219. HRESULT hr=NOERROR;
  220. PCM_RecordHeader pcmHeader;
  221. XML_NODE_INFO ** apNodeInfo = NULL ;
  222. if (!pData)
  223. return E_INVALIDARG;
  224. // validate typeID and param
  225. if ((typeID == ENDCHILDREN_PRECOMP_MANIFEST) || (typeID == CREATENODE_PRECOMP_MANIFEST)){
  226. if (!param)
  227. return E_INVALIDARG;
  228. }else if (typeID != BEGINCHILDREN_PRECOMP_MANIFEST)
  229. return E_INVALIDARG;
  230. apNodeInfo = (XML_NODE_INFO **)pData;
  231. pcmHeader.typeID = typeID;
  232. hr = GetPCMRecordSize(apNodeInfo, NodeCount, &pcmHeader.RecordSize) ; // the size contains each string's length
  233. if (FAILED(hr))
  234. goto Exit;
  235. if (typeID == ENDCHILDREN_PRECOMP_MANIFEST) // param1 is fEmpty;
  236. pcmHeader.RecordSize += sizeof(BOOL);
  237. else if (typeID == CREATENODE_PRECOMP_MANIFEST) // param1 is Current Line number
  238. pcmHeader.RecordSize += sizeof(ULONG);
  239. pcmHeader.NodeCount = NodeCount;
  240. hr = WritePCMRecordHeader(&pcmHeader);
  241. if (FAILED(hr))
  242. goto Exit;
  243. hr = WritePCMXmlNodeInfo(apNodeInfo, NodeCount, typeID, param);
  244. if (FAILED(hr))
  245. goto Exit;
  246. m_ulRecordCount ++ ;
  247. if ( NodeCount > m_usMaxNodeCount )
  248. m_usMaxNodeCount = NodeCount;
  249. hr = NOERROR;
  250. Exit:
  251. return hr;
  252. }
  253. // IUnknown
  254. ULONG CPrecompiledManifestWriter::AddRef()
  255. {
  256. return ::SxspInterlockedIncrement(&m_cRef);
  257. }
  258. ULONG CPrecompiledManifestWriter::Release()
  259. {
  260. ULONG lRet = ::SxspInterlockedDecrement(&m_cRef);
  261. if (!lRet)
  262. FUSION_DELETE_SINGLETON(this);
  263. return lRet;
  264. }
  265. HRESULT CPrecompiledManifestWriter::QueryInterface(REFIID riid, LPVOID *ppv)
  266. {
  267. if (riid == __uuidof(this))
  268. {
  269. *ppv = this;
  270. }
  271. else if (riid == IID_IUnknown
  272. || riid == IID_IXMLNodeFactory)
  273. {
  274. *ppv = static_cast<IXMLNodeFactory*> (this);
  275. }
  276. else
  277. {
  278. *ppv = NULL;
  279. return E_NOINTERFACE;
  280. }
  281. AddRef();
  282. return S_OK;
  283. }
  284. // IXMLNodeFactory methods:
  285. HRESULT CPrecompiledManifestWriter::NotifyEvent(IXMLNodeSource *pSource, XML_NODEFACTORY_EVENT iEvt)
  286. {
  287. ASSERT(m_pNodeFactory);
  288. // no hr-canonicalization is needed because these two nodefactories are supposed to return the correct range of values
  289. return m_pNodeFactory->NotifyEvent(pSource, iEvt);
  290. }
  291. HRESULT CPrecompiledManifestWriter::BeginChildren(IXMLNodeSource *pSource, XML_NODE_INFO *pNodeInfo)
  292. {
  293. HRESULT hr = NOERROR;
  294. ASSERT(m_pNodeFactory);
  295. hr = m_pNodeFactory->BeginChildren(pSource, pNodeInfo);
  296. if ( FAILED(hr))
  297. goto Exit;
  298. // write pcm file
  299. hr = WritePrecompiledManifestRecord(BEGINCHILDREN_PRECOMP_MANIFEST,
  300. &pNodeInfo, 1, NULL);
  301. if ( FAILED(hr))
  302. goto Exit;
  303. hr = NOERROR;
  304. Exit:
  305. return hr;
  306. }
  307. HRESULT CPrecompiledManifestWriter::EndChildren(IXMLNodeSource *pSource, BOOL fEmpty, XML_NODE_INFO *pNodeInfo)
  308. {
  309. HRESULT hr = NOERROR;
  310. ASSERT(m_pNodeFactory);
  311. hr = m_pNodeFactory->EndChildren(pSource, fEmpty, pNodeInfo);
  312. if ( FAILED(hr))
  313. goto Exit;
  314. // write pcm file
  315. hr = WritePrecompiledManifestRecord(ENDCHILDREN_PRECOMP_MANIFEST, &pNodeInfo, 1, &fEmpty);
  316. if ( FAILED(hr))
  317. goto Exit;
  318. hr = NOERROR;
  319. Exit:
  320. return hr;
  321. }
  322. HRESULT CPrecompiledManifestWriter::Error(IXMLNodeSource *pSource, HRESULT hrErrorCode, USHORT cNumRecs, XML_NODE_INFO **apNodeInfo)
  323. {
  324. ASSERT(m_pNodeFactory);
  325. // no hr-canonicalization is needed because these two nodefactories are supposed to return the correct range of values
  326. return m_pNodeFactory->Error(pSource, hrErrorCode, cNumRecs, apNodeInfo);
  327. }
  328. HRESULT CPrecompiledManifestWriter::CreateNode(IXMLNodeSource *pSource, PVOID pNodeParent, USHORT cNumRecs, XML_NODE_INFO **apNodeInfo)
  329. {
  330. ULONG ulLineNumber ;
  331. HRESULT hr = NOERROR;
  332. ASSERT(m_pNodeFactory);
  333. if ( ! m_pNodeFactory)
  334. return E_UNEXPECTED;
  335. hr = m_pNodeFactory->CreateNode(pSource, pNodeParent, cNumRecs, apNodeInfo);
  336. if ( FAILED(hr))
  337. goto Exit;
  338. ulLineNumber = pSource->GetLineNumber();
  339. hr = WritePrecompiledManifestRecord(CREATENODE_PRECOMP_MANIFEST,
  340. apNodeInfo, cNumRecs, &ulLineNumber);
  341. if ( FAILED(hr))
  342. goto Exit;
  343. hr = NOERROR;
  344. Exit:
  345. return hr;
  346. }
  347. HRESULT CPrecompiledManifestWriter::Initialize(PACTCTXGENCTX ActCtxGenCtx, PASSEMBLY Assembly,
  348. PACTCTXCTB_ASSEMBLY_CONTEXT AssemblyContext)
  349. {
  350. HRESULT hr = NOERROR;
  351. FN_TRACE_HR(hr);
  352. CSmartRef<CNodeFactory> pNodeFactory;
  353. if (! m_pNodeFactory) {
  354. pNodeFactory = new CNodeFactory;
  355. if (!pNodeFactory) {
  356. return E_OUTOFMEMORY;
  357. }
  358. m_pNodeFactory = pNodeFactory;
  359. }
  360. else {
  361. hr = pNodeFactory.QueryInterfaceFrom(m_pNodeFactory);
  362. ASSERT(SUCCEEDED(hr));
  363. }
  364. IFW32FALSE_EXIT(pNodeFactory->Initialize(ActCtxGenCtx, Assembly, AssemblyContext));
  365. IFCOMFAILED_EXIT(this->SetWriterStream(reinterpret_cast<CPrecompiledManifestWriterStream*>(AssemblyContext->pcmWriterStream));
  366. // this must be called in order for later use
  367. IFCOMFAILED_EXIT(this->WritePCMHeader());
  368. FN_EPILOG
  369. }