#include "pch.h" #pragma hdrstop #include "modset.h" #include "modtree.h" #include "ncstl.h" struct GMBCONTEXT { // The tree to reference for generating the set. // IN const CModuleTree* pTree; // The module to start with when generating the set. // IN const CModule* pSourceMod; // INS_FLAGS to use when adding DepChain to the set. // IN DWORD dwFlags; // The module list set to generate based on pSourceMod. // IN OUT CModuleListSet* pSet; // The result of the operation. // OUT HRESULT hr; // This module list is built up via recursion. It is // temporary. It represents a depenedency chain sourced // at pSourceMod. It is added to the set when the depth // of the chain (or a circular reference) is detected. // CModuleList DepChain; }; VOID GetModuleBindings ( IN const CModule* pMod, IN OUT GMBCONTEXT* pCtx) { BOOL fFoundOne = FALSE; const CModuleTreeEntry* pScan; Assert (pCtx); Assert (pCtx->pSourceMod); Assert (pCtx->pSet); Assert (pCtx->pTree); // Append this module to te end of the context's working // dependency chain. // pCtx->hr = pCtx->DepChain.HrInsertModule (pMod, INS_ASSERT_IF_DUP | INS_APPEND); if (S_OK != pCtx->hr) { return; } // For all rows in the tree where the module is the one passed in... // for (pScan = pCtx->pTree->PFindFirstEntryWithModule (pMod); (pScan != pCtx->pTree->end()) && (pScan->m_pModule == pMod); pScan++) { fFoundOne = TRUE; // Detect circular import chains. // if (pCtx->DepChain.FLinearFindModuleByPointer (pScan->m_pImportModule)) { pCtx->DepChain.m_fCircular = TRUE; continue; } GetModuleBindings (pScan->m_pImportModule, pCtx); if (S_OK != pCtx->hr) { return; } } // If we didnt find any rows with pMod as a module, it means we // hit the depth of the dependency chain. Time to add it to the set // unless this is the original module we were asked to find the // set for. // if (!fFoundOne && (pMod != pCtx->pSourceMod)) { CHAR pszBuf [4096]; ULONG cch = celems(pszBuf); pCtx->DepChain.FDumpToString (pszBuf, &cch); strcat(pszBuf, "\n"); printf(pszBuf); pCtx->hr = pCtx->pSet->HrAddModuleList (&pCtx->DepChain, INS_APPEND | pCtx->dwFlags); } const CModule* pRemoved; pRemoved = pCtx->DepChain.RemoveLastModule(); // This should be the component we appened above. // Assert (pRemoved == pMod); } CModuleTree::~CModuleTree () { FreeCollectionAndItem (Modules); } HRESULT CModuleTree::HrAddEntry ( IN CModule* pMod, IN CModule* pImport, IN DWORD dwFlags) { HRESULT hr; iterator InsertPosition = NULL; CModuleTreeEntry* pEntry; Assert (pMod); Assert (pImport); if (size() == capacity()) { //fprintf(stderr, "growing module tree buffer\n"); __try { reserve (size() + 16384); } __except(EXCEPTION_EXECUTE_HANDLER) { return E_OUTOFMEMORY; } } hr = S_OK; //pEntry = PFindFirstEntryAfterModuleGroup (pMod); pEntry = PBinarySearchEntryByModule (pMod, &InsertPosition); if (pEntry != end()) { Assert (pEntry); CModuleTreeEntry* pScan; // Found an entry with a matching module. Need to scan backwards // in the module group looking for a duplicate. If not found, // Scan to the end looking for a duplicate and if we reach the // end of the group, we can insert this entry there. // pScan = pEntry; while (pScan != begin()) { pScan--; if (pScan->m_pModule != pMod) { // Left the group without finding a dupliate. // break; } if (pScan->m_pImportModule == pImport) { // Don't insert duplicate entries. // return S_OK; } } Assert (pMod == pEntry->m_pModule); while (pEntry != end() && pEntry->m_pModule == pMod) { // Don't insert duplicate entries. // if (pEntry->m_pImportModule == pImport) { return S_OK; } pEntry++; } // Looks like we'll be inserting it. // InsertPosition = pEntry; } else { // InsertPosition is the correct insertion point. // Assert (InsertPosition); } __try { CModuleTreeEntry Entry; Entry.m_pModule = pMod; Entry.m_pImportModule = pImport; Entry.m_dwFlags = dwFlags; Assert (InsertPosition); insert (InsertPosition, Entry); Assert (S_OK == hr); DbgVerifySorted(); } __except(EXCEPTION_EXECUTE_HANDLER) { hr = E_OUTOFMEMORY; } return hr; } HRESULT CModuleTree::HrGetModuleBindings ( IN const CModule* pMod, IN DWORD dwFlags /* GMB_FLAGS */, OUT CModuleListSet* pSet) const { GMBCONTEXT Ctx; Assert (pMod); Assert (dwFlags); Assert (pSet); // Initialize the output parameter. // if (!(dwFlags & GMBF_ADD_TO_MLSET)) { pSet->clear(); } // Initialize members of the context structure for recursion. // ZeroMemory (&Ctx, sizeof(Ctx)); Ctx.pTree = this; Ctx.pSourceMod = pMod; Ctx.dwFlags = (dwFlags & GMBF_ADD_TO_MLSET) ? INS_IGNORE_IF_DUP : INS_ASSERT_IF_DUP; Ctx.pSet = pSet; GetModuleBindings (pMod, &Ctx); return Ctx.hr; } CModuleTreeEntry* CModuleTree::PBinarySearchEntryByModule ( IN const CModule* pMod, OUT CModuleTreeEntry** pInsertPosition OPTIONAL) const { Assert (pMod); // Find the module using a binary search. // if (size()) { LONG Lo; LONG Hi; LONG Mid; INT Result; const CModuleTreeEntry* pScan; PCSTR pszFileName = pMod->m_pszFileName; Lo = 0; Hi = size() - 1; while (Hi >= Lo) { Mid = (Lo + Hi) / 2; Assert ((UINT)Mid < size()); pScan = (begin() + Mid); Result = strcmp (pszFileName, pScan->m_pModule->m_pszFileName); if (Result < 0) { Hi = Mid - 1; } else if (Result > 0) { Lo = Mid + 1; } else { Assert (pMod == pScan->m_pModule); return const_cast(pScan); } } // If we make it to here, the module was not found. // if (pInsertPosition) { CModule* pGroupMod; const CModuleTreeEntry* pPrev; // Seek to the beginning of this group. We need to insert // before the entire group, not just the one item we last found. // pScan = begin() + Lo; if (pScan != begin()) { pGroupMod = pScan->m_pModule; do { pPrev = pScan - 1; if (pPrev->m_pModule == pGroupMod) { pScan = pPrev; } else { break; } } while (pPrev != begin()); } *pInsertPosition = const_cast(pScan); Assert (*pInsertPosition >= begin()); Assert (*pInsertPosition <= end()); } } else if (pInsertPosition) { // Empty collection. Insert position is at the beginning. // *pInsertPosition = const_cast(begin()); } return const_cast(end()); } CModuleTreeEntry* CModuleTree::PFindFirstEntryWithModule ( IN const CModule* pMod) const { CModuleTreeEntry* pEntry; Assert (pMod); pEntry = PBinarySearchEntryByModule (pMod, NULL); if (pEntry != end()) { Assert (pEntry); if (pEntry != begin()) { CModuleTreeEntry* pPrev; Assert (pMod == pEntry->m_pModule); while (1) { pPrev = pEntry - 1; if (pPrev->m_pModule == pMod) { pEntry = pPrev; } else { break; } if (pPrev == begin()) { break; } } } } return pEntry; } CModuleTreeEntry* CModuleTree::PFindFirstEntryAfterModuleGroup ( IN const CModule* pMod) const { CModuleTreeEntry* pEntry; Assert (pMod); pEntry = PBinarySearchEntryByModule (pMod, NULL); if (pEntry != end()) { Assert (pEntry); Assert (pMod == pEntry->m_pModule); while (pEntry != end() && pEntry->m_pModule == pMod) { pEntry++; } } return pEntry; } CModuleTreeEntry* CModuleTree::PBinarySearchEntry ( IN const CModule* pMod, IN const CModule* pImport, OUT CModuleTreeEntry** pInsertPosition OPTIONAL) const { CModuleTreeEntry* pEntry; Assert (this); Assert (pMod); Assert (pImport); pEntry = PBinarySearchEntryByModule (pMod, pInsertPosition); if (pEntry != end()) { Assert (pEntry); const CModuleTreeEntry* pScan; // Found an entry with a matching module. Need to scan backwards // in the module group looking for a match. If not found, // Scan to the end looking for a match and if we reach the // end of the group, that will be the insert position (if specified). // pScan = pEntry; while (pScan != begin()) { pScan--; if (pScan->m_pModule != pMod) { // Left the group without finding a dupliate. // break; } if (pScan->m_pImportModule == pImport) { Assert (pScan->m_pModule == pMod); return const_cast(pScan); } } pScan = pEntry; Assert (pMod == pScan->m_pModule); while (pScan != end() && pScan->m_pModule == pMod) { if (pScan->m_pImportModule == pImport) { Assert (pScan->m_pModule == pMod); return const_cast(pScan); } pScan++; } if (pInsertPosition) { *pInsertPosition = const_cast(pScan); } // No match. pEntry = const_cast(end()); } return pEntry; } #if DBG VOID CModuleTree::DbgVerifySorted () { CModuleTreeEntry* pScan; CModuleTreeEntry* pPrev = NULL; if (size() > 1) { for (pPrev = begin(), pScan = begin() + 1; pScan != end(); pScan++) { Assert (strcmp(pPrev->m_pModule->m_pszFileName, pScan->m_pModule->m_pszFileName) <= 0); pPrev = pScan; } } } #endif