Exemple #1
0
//*****************************************************************************
// Search the cached RegMetas for a given scope.
//*****************************************************************************
HRESULT LOADEDMODULES::FindCachedReadOnlyEntry(
    LPCWSTR    szName,      // Name of the desired file.
    DWORD      dwOpenFlags, // Flags the new file is opened with.
    RegMeta ** ppMeta)      // Put found RegMeta here.
{
    RegMeta * pRegMeta = 0;
    BOOL      bWillBeCopyMemory;    // Will the opened file be copied to memory?
    DWORD     dwLowFileSize;        // Low bytes of this file's size
    DWORD     dwLowFileTime;        // Low butes of this file's last write time
    HRESULT   hr;
    ULONG     ixHash = 0;
    
    IfFailGo(InitializeStatics());
    
    {
        LOCKREAD();

        hr = S_FALSE; // We haven't found a match yet.

        // Avoid confusion.
        *ppMeta = NULL;
    
        bWillBeCopyMemory = IsOfCopyMemory(dwOpenFlags);

        // The cache is locked for read, so the list will not change.
    
        // Figure out the size and timestamp of this file
        WIN32_FILE_ATTRIBUTE_DATA faData;
        if (!WszGetFileAttributesEx(szName, GetFileExInfoStandard, &faData))
            return E_FAIL;
        dwLowFileSize = faData.nFileSizeLow;
        dwLowFileTime = faData.ftLastWriteTime.dwLowDateTime;

        // Check the hash first.
        ixHash = HashFileName(szName);
        if ((pRegMeta = m_HashedModules[ixHash]) != NULL)
        {
            _ASSERTE(pRegMeta->IsReadOnly());

            // Only match if the IsOfCopyMemory() bit is the same in both.  This is because
            //  when ofCopyMemory is set, the file is not locked on disk, and may become stale
            //  in memory.
            //
            // Also, only match if the date and size are the same
            if (pRegMeta->IsCopyMemory() == bWillBeCopyMemory &&
                pRegMeta->GetLowFileTimeOfDBFile() == dwLowFileTime &&
                pRegMeta->GetLowFileSizeOfDBFile() == dwLowFileSize)
            {
                // If the name matches...
                LPCWSTR pszName = pRegMeta->GetNameOfDBFile();
    #ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM
                if (wcscmp(szName, pszName) == 0)
    #else
                if (SString::_wcsicmp(szName, pszName) == 0)
    #endif
                {
                    ULONG cRefs;
                
                    // Found it.  Add a reference, and return it.
                    *ppMeta = pRegMeta;
                    cRefs = pRegMeta->AddRef();
                
                    LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope found cached RegMeta in hash: %#8x, crefs: %d\n", pRegMeta, cRefs));
                
                    return S_OK;
                }
            }
        }

        // Not found in hash; loop through each loaded modules
        int count = s_pLoadedModules->Count();
        for (int index = 0; index < count; index++)
        {
            pRegMeta = (*s_pLoadedModules)[index];

            // If the module is read-only, and the CopyMemory bit matches, and the date
            // and size are the same....
            if (pRegMeta->IsReadOnly() && 
                pRegMeta->IsCopyMemory() == bWillBeCopyMemory &&
                pRegMeta->GetLowFileTimeOfDBFile() == dwLowFileTime &&
                pRegMeta->GetLowFileSizeOfDBFile() == dwLowFileSize)
            {
                // If the name matches...
                LPCWSTR pszName = pRegMeta->GetNameOfDBFile();
    #ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM
                if (wcscmp(szName, pszName) == 0)
    #else
                if (SString::_wcsicmp(szName, pszName) == 0)
    #endif
                {
                    ULONG cRefs;

                    // Found it.  Add a reference, and return it.
                    *ppMeta = pRegMeta;
                    cRefs = pRegMeta->AddRef();

                    // Update the hash.
                    m_HashedModules[ixHash] = pRegMeta;

                    LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope found cached RegMeta by search: %#8x, crefs: %d\n", pRegMeta, cRefs));
                
                    return S_OK;
                }
            }
        }
    }

ErrExit:
    // Didn't find it.
    LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope did not find cached RegMeta\n"));

    _ASSERTE(hr != S_OK);
    return hr;
} // LOADEDMODULES::FindCachedReadOnlyEntry
//*****************************************************************************
// GetMDInternalInterface.
// This function will check the metadata section and determine if it should
// return an interface which implements ReadOnly or ReadWrite.
//*****************************************************************************
STDAPI GetMDInternalInterface(
    LPVOID      pData, 
    ULONG       cbData, 
    DWORD       flags,                  // [IN] ofRead or ofWrite.
    REFIID      riid,                   // [in] The interface desired.
    void        **ppIUnk)               // [out] Return interface on success.
{
    HRESULT     hr = NOERROR;
    MDInternalRO *pInternalRO = NULL;
    IMDCommon    *pInternalROMDCommon = NULL;
    MDFileFormat format;

    BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW);

    if (ppIUnk == NULL)
        IfFailGo(E_INVALIDARG);

    // Determine the file format we're trying to read.
    IfFailGo( CheckFileFormat(pData, cbData, &format) );

    // Found a fully-compressed, read-only format.
    if ( format == MDFormat_ReadOnly )
    {
        pInternalRO = new (nothrow) MDInternalRO;
        IfNullGo( pInternalRO );

        IfFailGo( pInternalRO->Init(const_cast<void*>(pData), cbData) );

#ifdef FEATURE_COMINTEROP
        IfFailGo(pInternalRO->QueryInterface(IID_IMDCommon, (void**)&pInternalROMDCommon));
        IfFailGo( (flags & ofNoTransform) ? S_FALSE : CheckIfWinMDAdapterNeeded(pInternalROMDCommon));
        if (hr == S_OK)
        {
            IfFailGo(CreateWinMDInternalImportRO(pInternalROMDCommon, riid, (void**)ppIUnk));
        }
        else
#endif // FEATURE_COMINTEROP
        {
            IfFailGo(pInternalRO->QueryInterface(riid, ppIUnk));
        }

    }
    else
    {
        // Found a not-fully-compressed, ENC format.
        _ASSERTE( format == MDFormat_ReadWrite );
        IfFailGo( GetInternalWithRWFormat( pData, cbData, flags, riid, ppIUnk ) );
    }

ErrExit:

    // clean up
    if ( pInternalRO )
        pInternalRO->Release();
    if ( pInternalROMDCommon )
        pInternalROMDCommon->Release();

    END_SO_INTOLERANT_CODE;
    
    return hr;
}   // GetMDInternalInterface
Exemple #3
0
JsValueRef WScriptJsrt::LoadScript(JsValueRef callee, LPCSTR fileName, LPCSTR fileContent, LPCSTR scriptInjectType, bool isSourceModule)
{
    HRESULT hr = E_FAIL;
    JsErrorCode errorCode = JsNoError;
    LPCWSTR errorMessage = _u("Internal error.");
    JsValueRef returnValue = JS_INVALID_REFERENCE;
    JsErrorCode innerErrorCode = JsNoError;
    JsContextRef currentContext = JS_INVALID_REFERENCE;
    JsRuntimeHandle runtime = JS_INVALID_RUNTIME_HANDLE;

    char fullPathNarrow[_MAX_PATH];
    size_t len = 0;

    IfJsrtErrorSetGo(ChakraRTInterface::JsGetCurrentContext(&currentContext));
    IfJsrtErrorSetGo(ChakraRTInterface::JsGetRuntime(currentContext, &runtime));

    if (fileName)
    {
        if (_fullpath(fullPathNarrow, fileName, _MAX_PATH) == nullptr)
        {
            IfFailGo(E_FAIL);
        }
        // canonicalize that path name to lower case for the profile storage
        // REVIEW: This doesn't work for UTF8...
        len = strlen(fullPathNarrow);
        for (size_t i = 0; i < len; i++)
        {
            fullPathNarrow[i] = (char)tolower(fullPathNarrow[i]);
        }
    }
    else
    {
        // No fileName provided (WScript.LoadScript()), use dummy "script.js"
        strcpy_s(fullPathNarrow, "script.js");
    }

    if (strcmp(scriptInjectType, "self") == 0)
    {
        JsContextRef calleeContext;
        IfJsrtErrorSetGo(ChakraRTInterface::JsGetContextOfObject(callee, &calleeContext));

        IfJsrtErrorSetGo(ChakraRTInterface::JsSetCurrentContext(calleeContext));

        if (isSourceModule)
        {
            errorCode = ChakraRTInterface::JsRunModuleUtf8(fileContent, GetNextSourceContext(), fullPathNarrow, &returnValue);
        }
        else
        {
#if ENABLE_TTD
            errorCode = ChakraRTInterface::JsTTDRunScript(-1, fileContent, GetNextSourceContext(), fullPathNarrow, &returnValue);
#else
            errorCode = ChakraRTInterface::JsRunScriptUtf8(fileContent, GetNextSourceContext(), fullPathNarrow, &returnValue);
#endif
        }

        if (errorCode == JsNoError)
        {
            errorCode = ChakraRTInterface::JsGetGlobalObject(&returnValue);
        }

        IfJsrtErrorSetGo(ChakraRTInterface::JsSetCurrentContext(currentContext));
    }
    else if (strcmp(scriptInjectType, "samethread") == 0)
    {
        JsValueRef newContext = JS_INVALID_REFERENCE;

        // Create a new context and set it as the current context
        IfJsrtErrorSetGo(ChakraRTInterface::JsCreateContext(runtime, &newContext));
        IfJsrtErrorSetGo(ChakraRTInterface::JsSetCurrentContext(newContext));

        // Initialize the host objects
        Initialize();


        if (isSourceModule)
        {
            errorCode = ChakraRTInterface::JsRunModuleUtf8(fileContent, GetNextSourceContext(), fullPathNarrow, &returnValue);
        }
        else
        {
#if ENABLE_TTD
            errorCode = ChakraRTInterface::JsTTDRunScript(-1, fileContent, GetNextSourceContext(), fullPathNarrow, &returnValue);
#else
            errorCode = ChakraRTInterface::JsRunScriptUtf8(fileContent, GetNextSourceContext(), fullPathNarrow, &returnValue);
#endif
        }

        if (errorCode == JsNoError)
        {
            errorCode = ChakraRTInterface::JsGetGlobalObject(&returnValue);
        }

        // Set the context back to the old one
        ChakraRTInterface::JsSetCurrentContext(currentContext);
    }
    else
    {
        errorCode = JsErrorInvalidArgument;
        errorMessage = _u("Unsupported argument type inject type.");
    }

Error:
    JsValueRef value = returnValue;
    if (errorCode != JsNoError)
    {
        if (innerErrorCode != JsNoError)
        {
            // Failed to retrieve the inner error message, so set a custom error string
            errorMessage = ConvertErrorCodeToMessage(errorCode);
        }

        JsValueRef error = JS_INVALID_REFERENCE;
        JsValueRef messageProperty = JS_INVALID_REFERENCE;

        ERROR_MESSAGE_TO_STRING(errCode, errorMessage, messageProperty);

        if (errCode == JsNoError)
        {
            errCode = ChakraRTInterface::JsCreateError(messageProperty, &error);
            if (errCode == JsNoError)
            {
                errCode = ChakraRTInterface::JsSetException(error);
            }
        }

        ChakraRTInterface::JsDoubleToNumber(errorCode, &value);
    }

    _flushall();

    return value;
}
Exemple #4
0
HRESULT AssemblySpec::LoadAssembly(Assembly** ppAssembly,
                                   OBJECTREF* pThrowable, /*= NULL*/
                                   OBJECTREF* pExtraEvidence, /*= NULL*/
                                   BOOL fPolicyLoad) /*= FALSE*/
{
    IAssembly* pIAssembly = NULL;

    HRESULT hr;
    Assembly *pAssembly = GetAppDomain()->FindCachedAssembly(this);
    if(pAssembly) {
        if ((pExtraEvidence != NULL) && (*pExtraEvidence != NULL))
            IfFailGo(SECURITY_E_INCOMPATIBLE_EVIDENCE);

        *ppAssembly = pAssembly;
        return S_FALSE;
    }

    PEFile *pFile;
    IfFailGo(GetAppDomain()->BindAssemblySpec(this, 
                                              &pFile, 
                                              &pIAssembly, 
                                              &pAssembly, 
                                              pExtraEvidence,
                                              pThrowable));

    // Loaded by AssemblyResolve event handler
    if (hr == S_FALSE) {

        //If loaded by the AssemblyResolve event, check that
        // the public keys are the same as in the AR.
        // However, if the found assembly is a dynamically
        // created one, security has decided to allow it.
        if (m_cbPublicKeyOrToken &&
            pAssembly->m_pManifestFile) {
                
            if (!pAssembly->m_cbPublicKey)
                IfFailGo(FUSION_E_PRIVATE_ASM_DISALLOWED);

            // Ref has the full key
            if (m_dwFlags & afPublicKey) {
                if ((m_cbPublicKeyOrToken != pAssembly->m_cbPublicKey) ||
                    memcmp(m_pbPublicKeyOrToken, pAssembly->m_pbPublicKey, m_cbPublicKeyOrToken))
                    IfFailGo(FUSION_E_REF_DEF_MISMATCH);
            }
            
            // Ref has a token
            else if (pAssembly->m_cbRefedPublicKeyToken) {
                if ((m_cbPublicKeyOrToken != pAssembly->m_cbRefedPublicKeyToken) ||
                    memcmp(m_pbPublicKeyOrToken,
                           pAssembly->m_pbRefedPublicKeyToken,
                           m_cbPublicKeyOrToken))
                    IfFailGo(FUSION_E_REF_DEF_MISMATCH);
            }
            else {
                if (!StrongNameTokenFromPublicKey(pAssembly->m_pbPublicKey,
                                                  pAssembly->m_cbPublicKey,
                                                  &pAssembly->m_pbRefedPublicKeyToken,
                                                  &pAssembly->m_cbRefedPublicKeyToken))
                    IfFailGo(StrongNameErrorInfo());
                
                if ((m_cbPublicKeyOrToken != pAssembly->m_cbRefedPublicKeyToken) ||
                    memcmp(m_pbPublicKeyOrToken,
                           pAssembly->m_pbRefedPublicKeyToken,
                           m_cbPublicKeyOrToken))
                    IfFailGo(FUSION_E_REF_DEF_MISMATCH);
            }
        }
        
        *ppAssembly = pAssembly;
        return S_OK;
    }


    // Until we can create multiple Assembly objects for a single HMODULE
    // we can only store one IAssembly* per Assembly. It is very important
    // to maintain the IAssembly* for an image that is in the load-context.
    // An Assembly in the load-from-context can bind to an assembly in the
    // load-context but not visa-versa. Therefore, if we every get an IAssembly
    // from the load-from-context we must make sure that it will never be 
    // found using a load. If it did then we could end up with Assembly dependencies
    // that are wrong. For example, if I do a LoadFrom() on an assembly in the GAC
    // and it requires another Assembly that I have preloaded in the load-from-context
    // then that dependency gets burnt into the Jitted code. Later on a Load() is
    // done on the assembly in the GAC and we single instance it back to the one
    // we have gotten from the load-from-context because the HMODULES are the same.
    // Now the dependency is wrong because it would not have the preloaded assembly
    // if the order was reversed.
    
    if (pIAssembly) {
        IFusionLoadContext *pLoadContext;
        hr = pIAssembly->GetFusionLoadContext(&pLoadContext);
        _ASSERTE(SUCCEEDED(hr));
        if (SUCCEEDED(hr)) {
            if (pLoadContext->GetContextType() == LOADCTX_TYPE_LOADFROM) {

                mdAssembly mda;
                if (FAILED(pFile->GetMDImport()->GetAssemblyFromScope(&mda))) {
                    hr = COR_E_ASSEMBLYEXPECTED;
                    goto exit;
                }

                LPCUTF8 psName;
                PBYTE pbPublicKey;
                DWORD cbPublicKey;
                AssemblyMetaDataInternal context;
                DWORD dwFlags;
                pFile->GetMDImport()->GetAssemblyProps(mda,
                                                       (const void**) &pbPublicKey,
                                                       &cbPublicKey,
                                                       NULL, // hash alg
                                                       &psName,
                                                       &context,
                                                       &dwFlags);
                
                AssemblySpec spec;
                if (FAILED(hr = spec.Init(psName, 
                                          &context, 
                                          pbPublicKey,
                                          cbPublicKey, 
                                          dwFlags)))
                    goto exit;
                    
                IAssemblyName* pFoundAssemblyName;
                if (FAILED(hr = spec.CreateFusionName(&pFoundAssemblyName, FALSE)))
                    goto exit;
                
                AssemblySink* pFoundSink = GetAppDomain()->GetAssemblySink();
                if(!pFoundSink) {
                    pFoundAssemblyName->Release();
                    hr = E_OUTOFMEMORY;
                    goto exit;
                }
                    
                IAssembly *pFoundIAssembly;
                BEGIN_ENSURE_PREEMPTIVE_GC();
                hr = FusionBind::GetAssemblyFromFusion(GetAppDomain()->GetFusionContext(),
                                                       pFoundSink,
                                                       pFoundAssemblyName,
                                                       &spec.m_CodeInfo,
                                                       &pFoundIAssembly);

                if(SUCCEEDED(hr)) {
                    DWORD dwFoundSize = MAX_PATH;
                    WCHAR wszFoundPath[MAX_PATH];
                    // Get the path to the module containing the manifest
                    if (SUCCEEDED(pFoundIAssembly->GetManifestModulePath(wszFoundPath,
                                                                         &dwFoundSize))) {
                        
                        // Keep the default context's IAssembly if the paths are the same
                        if (!_wcsicmp(wszFoundPath, pFile->GetFileName())) {
                            pIAssembly->Release();
                            pIAssembly = pFoundIAssembly;

                            // Make sure the new IAssembly isn't holding its own refcount on 
                            // the file (we've just verified we're holding the same file.)
                            // Otherwise we will leak the handle when we unload the assembly,
                            // assuming fusion decides to cache this IAssembly pointer 
                            // somewhere internally.
                            PEFile::ReleaseFusionMetadataImport(pFoundIAssembly);

                        }
                        else
                            pFoundIAssembly->Release();
                    }
                }

                pFoundAssemblyName->Release();
                pFoundSink->Release();
                END_ENSURE_PREEMPTIVE_GC();
                hr = S_OK;
            }
        exit:
            pLoadContext->Release();
        }
    }


    // Create the assembly and delay loading the main module.
    Module* pModule;
    hr = GetAppDomain()->LoadAssembly(pFile, 
                                      pIAssembly, 
                                      &pModule, 
                                      &pAssembly,
                                      pExtraEvidence, 
                                      fPolicyLoad,
                                      pThrowable);

    BEGIN_ENSURE_PREEMPTIVE_GC();
    if(SUCCEEDED(hr)) {
        *ppAssembly = pAssembly;
        /*HRESULT hrLoose =*/ GetAppDomain()->AddAssemblyToCache(this, pAssembly);
    }

    if(pIAssembly)
        pIAssembly->Release();
    END_ENSURE_PREEMPTIVE_GC();

 ErrExit:
    if (FAILED(hr) && (pThrowable!=NULL)) { 
        BEGIN_ENSURE_COOPERATIVE_GC();
        if ((pThrowable != RETURN_ON_ERROR) && (*pThrowable == NULL)) {
            if (m_pAssemblyName)
                PostFileLoadException(m_pAssemblyName, FALSE,NULL, hr, pThrowable);
            else {
                MAKE_UTF8PTR_FROMWIDE(szName, m_CodeInfo.m_pszCodeBase);
                PostFileLoadException(szName, TRUE,NULL, hr, pThrowable);
            }
        }
        END_ENSURE_COOPERATIVE_GC();
    }

    return hr;
}
HRESULT Helpers::LoadBinaryFile(LPCSTR filename, LPCSTR& contents, UINT& lengthBytes, bool printFileOpenError)
{
    HRESULT hr = S_OK;
    contents = nullptr;
    lengthBytes = 0;
    size_t result;
    FILE * file;

    //
    // Open the file as a binary file to prevent CRT from handling encoding, line-break conversions,
    // etc.
    //
    if (fopen_s(&file, filename, "rb") != 0)
    {
        if (printFileOpenError)
        {
            fprintf(stderr, "Error in opening file '%s' ", filename);
#ifdef _WIN32
            DWORD lastError = GetLastError();
            char16 wszBuff[MAX_URI_LENGTH];
            wszBuff[0] = 0;
            if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                nullptr,
                lastError,
                0,
                wszBuff,
                _countof(wszBuff),
                nullptr))
            {
                fwprintf(stderr, _u(": %s"), wszBuff);
            }
#endif
            fprintf(stderr, "\n");
        }
        return E_FAIL;
    }
    // file will not be nullptr if _wfopen_s succeeds
    __analysis_assume(file != nullptr);

    //
    // Determine the file length, in bytes.
    //
    fseek(file, 0, SEEK_END);
    lengthBytes = ftell(file);
    fseek(file, 0, SEEK_SET);
    contents = (LPCSTR)HeapAlloc(GetProcessHeap(), 0, lengthBytes);
    if (nullptr == contents)
    {
        fwprintf(stderr, _u("out of memory"));
        IfFailGo(E_OUTOFMEMORY);
    }
    //
    // Read the entire content as a binary block.
    //
    result = fread((void*)contents, sizeof(char), lengthBytes, file);
    if (result != lengthBytes)
    {
        fwprintf(stderr, _u("Read error"));
        IfFailGo(E_FAIL);
    }

Error:
    fclose(file);
    if (contents && FAILED(hr))
    {
        HeapFree(GetProcessHeap(), 0, (void*)contents);
        contents = nullptr;
    }

    return hr;
}
//*****************************************************************************
//*****************************************************************************
__checkReturn 
HRESULT CLiteWeightStgdbRW::SaveToStorage(
    TiggerStorage            *pStorage,
    MetaDataReorderingOptions reorderingOptions,
    CorProfileData           *pProfileData)
{
    HRESULT  hr;                     // A result.
    LPCWSTR  szName;                 // Name of the tables stream.
    IStream *pIStreamTbl = 0;
    UINT32   cb;
    UINT32   cbSaveSize = m_cbSaveSize;
    
    // Must call GetSaveSize to cache the streams up front.
    // Don't trust cached values in the delta case... if there was a previous call to get 
    // a non-delta size, it will be incorrect.
    if ((m_cbSaveSize == 0) || IsENCDelta(m_MiniMd.m_OptionValue.m_UpdateMode))
    {
        IfFailGo(GetSaveSize(cssAccurate, &cbSaveSize));
    }
    
    // Save the header of the data file.
    IfFailGo(pStorage->WriteHeader(m_pStreamList, 0, NULL));
    
    // If this is a minimal delta, write a stream marker 
    if (IsENCDelta(m_MiniMd.m_OptionValue.m_UpdateMode))
    {
        IfFailGo(pStorage->CreateStream(MINIMAL_MD_STREAM, 
            STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 
            0, 0, &pIStreamTbl));
        pIStreamTbl->Release();
        pIStreamTbl = 0;
    }
    
    if (pProfileData != NULL)
    {
        DWORD bCompressed;
        UINT32 cbHotSize;
        // Will the stream be compressed data?
        
        // Only create this additional stream if it will be non-empty
        IfFailGo(m_MiniMd.GetSaveSize(cssAccurate, &cbHotSize, &bCompressed, reorderingOptions, pProfileData));
        
        if (cbHotSize > 0)
        {
            // Create a stream and save the hot tables.
            szName = HOT_MODEL_STREAM;
            IfFailGo(pStorage->CreateStream(szName, 
                    STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 
                    0, 0, &pIStreamTbl));
            IfFailGo(m_MiniMd.SaveTablesToStream(pIStreamTbl, reorderingOptions, pProfileData));
            pIStreamTbl->Release();
            pIStreamTbl = 0;
        }
    }
    
    if (reorderingOptions & ReArrangeStringPool)
    {
        // Save the string pool before the tables when we do not have the string pool cache
        IfFailGo(SavePool(STRING_POOL_STREAM, pStorage, MDPoolStrings));
    }
    
    // Create a stream and save the tables.
    szName = m_bSaveCompressed ? COMPRESSED_MODEL_STREAM : ENC_MODEL_STREAM;
    IfFailGo(pStorage->CreateStream(szName, 
            STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 
            0, 0, &pIStreamTbl));
    IfFailGo(m_MiniMd.SaveTablesToStream(pIStreamTbl, NoReordering, NULL));
    pIStreamTbl->Release();
    pIStreamTbl = 0;
    
    // Save the pools.
    if (!(reorderingOptions & ReArrangeStringPool))
    {
        // string pool must be saved after the tables when we have the string pool cache
        IfFailGo(SavePool(STRING_POOL_STREAM, pStorage, MDPoolStrings));
    }
    IfFailGo(SavePool(US_BLOB_POOL_STREAM, pStorage, MDPoolUSBlobs));
    IfFailGo(SavePool(GUID_POOL_STREAM, pStorage, MDPoolGuids));
    IfFailGo(SavePool(BLOB_POOL_STREAM, pStorage, MDPoolBlobs));
    
    // Write the header to disk.
    OptionValue ov;
    IfFailGo(m_MiniMd.GetOption(&ov));
    
    IfFailGo(pStorage->WriteFinished(m_pStreamList, (ULONG *)&cb, IsENCDelta(ov.m_UpdateMode)));
    
    _ASSERTE(cbSaveSize == cb);
    
    // Let the Storage release some memory.
    pStorage->ResetBackingStore();
    
    IfFailGo(m_MiniMd.SaveDone());
    
ErrExit:
    if (pIStreamTbl != NULL)
        pIStreamTbl->Release();
    delete m_pStreamList;
    m_pStreamList = 0;
    m_cbSaveSize = 0;
    return hr;
} // CLiteWeightStgdbRW::SaveToStorage
Exemple #7
0
//*******************************************************************************
// helper to add a declarative security blob to a class or method
// 
// Implements internal API code:IMetaDataEmitHelper::AddDeclarativeSecurityHelper.
//*******************************************************************************
STDMETHODIMP RegMeta::AddDeclarativeSecurityHelper(
    mdToken     tk,                     // [IN] Parent token (typedef/methoddef)
    DWORD       dwAction,               // [IN] Security action (CorDeclSecurity)
    void const  *pValue,                // [IN] Permission set blob
    DWORD       cbValue,                // [IN] Byte count of permission set blob
    mdPermission*pmdPermission)         // [OUT] Output permission token
{
    HRESULT         hr = S_OK;
    DeclSecurityRec *pDeclSec = NULL;
    RID             iDeclSec;
    short           sAction = static_cast<short>(dwAction);
    mdPermission    tkPerm;

    LOG((LOGMD, "MD RegMeta::AddDeclarativeSecurityHelper(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
        tk, dwAction, pValue, cbValue, pmdPermission));
    
    LOCKWRITE();
    IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
    
    _ASSERTE(TypeFromToken(tk) == mdtTypeDef || TypeFromToken(tk) == mdtMethodDef || TypeFromToken(tk) == mdtAssembly);

    // Check for valid Action.
    if (sAction == 0 || sAction > dclMaximumValue)
        IfFailGo(E_INVALIDARG);

    if (CheckDups(MDDupPermission))
    {
        hr = ImportHelper::FindPermission(&(m_pStgdb->m_MiniMd), tk, sAction, &tkPerm);

        if (SUCCEEDED(hr))
        {
            // Set output parameter.
            if (pmdPermission)
                *pmdPermission = tkPerm;
            if (IsENCOn())
                IfFailGo(m_pStgdb->m_MiniMd.GetDeclSecurityRecord(RidFromToken(tkPerm), &pDeclSec));
            else
            {
                hr = META_S_DUPLICATE;
                goto ErrExit;
            }
        }
        else if (hr != CLDB_E_RECORD_NOTFOUND)
            IfFailGo(hr);
    }

    // Create a new record.
    if (!pDeclSec)
    {
        IfFailGo(m_pStgdb->m_MiniMd.AddDeclSecurityRecord(&pDeclSec, &iDeclSec));
        tkPerm = TokenFromRid(iDeclSec, mdtPermission);

        // Set output parameter.
        if (pmdPermission)
            *pmdPermission = tkPerm;

        // Save parent and action information.
        IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_DeclSecurity, DeclSecurityRec::COL_Parent, pDeclSec, tk));
        pDeclSec->SetAction(sAction);

        // Turn on the internal security flag on the parent.
        if (TypeFromToken(tk) == mdtTypeDef)
            IfFailGo(_TurnInternalFlagsOn(tk, tdHasSecurity));
        else if (TypeFromToken(tk) == mdtMethodDef)
            IfFailGo(_TurnInternalFlagsOn(tk, mdHasSecurity));
        IfFailGo(UpdateENCLog(tk));
    }

    // Write the blob into the record.
    IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_DeclSecurity, DeclSecurityRec::COL_PermissionSet,
                                        pDeclSec, pValue, cbValue));

    IfFailGo(UpdateENCLog(tkPerm));

ErrExit:

    return hr;
} // RegMeta::AddDeclarativeSecurityHelper
Exemple #8
0
HRESULT RunScript(const char* fileName, LPCSTR fileContents, BYTE *bcBuffer, char *fullPath)
{
    HRESULT hr = S_OK;
    MessageQueue * messageQueue = new MessageQueue();
    WScriptJsrt::AddMessageQueue(messageQueue);

    IfJsErrorFailLog(ChakraRTInterface::JsSetPromiseContinuationCallback(PromiseContinuationCallback, (void*)messageQueue));

    if(strlen(fileName) >= 14 && strcmp(fileName + strlen(fileName) - 14, "ttdSentinal.js") == 0)
    {
#if !ENABLE_TTD
        wprintf(_u("Sential js file is only ok when in TTDebug mode!!!\n"));
        return E_FAIL;
#else
        if(!doTTDebug)
        {
            wprintf(_u("Sential js file is only ok when in TTDebug mode!!!\n"));
            return E_FAIL;
        }

        ChakraRTInterface::JsTTDStart();

        try
        {
            JsTTDMoveMode moveMode = (JsTTDMoveMode)(JsTTDMoveMode::JsTTDMoveKthEvent | ((int64) startEventCount) << 32);
            int64_t snapEventTime = -1;
            int64_t nextEventTime = -2;

            while(true)
            {
                JsErrorCode error = ChakraRTInterface::JsTTDGetSnapTimeTopLevelEventMove(chRuntime, moveMode, &nextEventTime, &snapEventTime, nullptr);

                if(error != JsNoError)
                {
                    if(error == JsErrorCategoryUsage)
                    {
                        wprintf(_u("Start time not in log range.\n"));
                    }

                    return error;
                }

                IfFailedReturn(ChakraRTInterface::JsTTDMoveToTopLevelEvent(chRuntime, moveMode, snapEventTime, nextEventTime));

                JsErrorCode res = ChakraRTInterface::JsTTDReplayExecution(&moveMode, &nextEventTime);

                //handle any uncaught exception by immediately time-traveling to the throwing line in the debugger -- in replay just report and exit
                if(res == JsErrorCategoryScript)
                {
                    wprintf(_u("An unhandled script exception occoured!!!\n"));

                    ExitProcess(0);
                }

                if(nextEventTime == -1)
                {
                    wprintf(_u("\nReached end of Execution -- Exiting.\n"));
                    break;
                }
            }
        }
        catch(...)
        {
            wprintf(_u("Terminal exception in Replay -- exiting.\n"));
            ExitProcess(0);
        }
#endif
    }
    else
    {
        Assert(fileContents != nullptr || bcBuffer != nullptr);

        JsErrorCode runScript;
        JsValueRef fname;
        IfJsErrorFailLog(ChakraRTInterface::JsCreateStringUtf8((const uint8_t*)fullPath,
            strlen(fullPath), &fname));

        if(bcBuffer != nullptr)
        {
            runScript = ChakraRTInterface::JsRunSerialized(
                bcBuffer,
                DummyJsSerializedScriptLoadUtf8Source,
                reinterpret_cast<JsSourceContext>(fileContents),
                // Use source ptr as sourceContext
                fname, nullptr /*result*/);
        }
        else
        {
            JsValueRef scriptSource;
            IfJsErrorFailLog(ChakraRTInterface::JsCreateExternalArrayBuffer((void*)fileContents,
                (unsigned int)strlen(fileContents),
                [](void *data)
                {
                    free(data);
                }, nullptr, &scriptSource));
#if ENABLE_TTD
            if(doTTRecord)
            {
                ChakraRTInterface::JsTTDStart();
            }

            runScript = ChakraRTInterface::JsRun(scriptSource,
                WScriptJsrt::GetNextSourceContext(), fname,
                JsParseScriptAttributeNone, nullptr /*result*/);
            if (runScript == JsErrorCategoryUsage)
            {
                wprintf(_u("FATAL ERROR: Core was compiled without ENABLE_TTD is defined. CH is trying to use TTD interface\n"));
                abort();
            }
#else
            runScript = ChakraRTInterface::JsRun(scriptSource,
                WScriptJsrt::GetNextSourceContext(), fname,
                JsParseScriptAttributeNone,
                nullptr /*result*/);
#endif
        }

        //Do a yield after the main script body executes
        ChakraRTInterface::JsTTDNotifyYield();

        if(runScript != JsNoError)
        {
            WScriptJsrt::PrintException(fileName, runScript);
        }
        else
        {
            // Repeatedly flush the message queue until it's empty. It is necessary to loop on this
            // because setTimeout can add scripts to execute.
            do
            {
                IfFailGo(messageQueue->ProcessAll(fileName));
            } while(!messageQueue->IsEmpty());
        }
    }

Error:
#if ENABLE_TTD
    if(doTTRecord)
    {
        ChakraRTInterface::JsTTDEmitRecording();
        ChakraRTInterface::JsTTDStop();
    }
#endif

    if (messageQueue != nullptr)
    {
        messageQueue->RemoveAll();
        // clean up possible pinned exception object on exit to avoid potential leak
        bool hasException;
        if (ChakraRTInterface::JsHasException(&hasException) == JsNoError && hasException)
        {
            JsValueRef exception = JS_INVALID_REFERENCE;
            ChakraRTInterface::JsGetAndClearException(&exception);
        }
        delete messageQueue;
    }
    return hr;
}
Exemple #9
0
HRESULT ExecuteTest(const char* fileName)
{
    HRESULT hr = S_OK;
    LPCSTR fileContents = nullptr;
    JsRuntimeHandle runtime = JS_INVALID_RUNTIME_HANDLE;
    UINT lengthBytes = 0;

    if(strlen(fileName) >= 14 && strcmp(fileName + strlen(fileName) - 14, "ttdSentinal.js") == 0)
    {
#if !ENABLE_TTD
        wprintf(_u("Sentinel js file is only ok when in TTDebug mode!!!\n"));
        return E_FAIL;
#else
        if(!doTTDebug)
        {
            wprintf(_u("Sentinel js file is only ok when in TTDebug mode!!!\n"));
            return E_FAIL;
        }

        jsrtAttributes = static_cast<JsRuntimeAttributes>(jsrtAttributes | JsRuntimeAttributeEnableExperimentalFeatures);

        IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateReplayRuntime(jsrtAttributes, ttUri, ttUriByteLength, Helpers::TTInitializeForWriteLogStreamCallback, Helpers::TTCreateStreamCallback, Helpers::TTReadBytesFromStreamCallback, Helpers::TTWriteBytesToStreamCallback, Helpers::TTFlushAndCloseStreamCallback, nullptr, &runtime));
        chRuntime = runtime;

        JsContextRef context = JS_INVALID_REFERENCE;
        IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateContext(runtime, true, &context));
        IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context));

        IfFailGo(RunScript(fileName, fileContents, nullptr, nullptr));

        unsigned int rcount = 0;
        IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(nullptr));
        ChakraRTInterface::JsRelease(context, &rcount);
        AssertMsg(rcount == 0, "Should only have had 1 ref from replay code and one ref from current context??");
#endif
    }
    else
    {
        LPCOLESTR contentsRaw = nullptr;

        char fullPath[_MAX_PATH];
        size_t len = 0;

        hr = Helpers::LoadScriptFromFile(fileName, fileContents, &lengthBytes);
        contentsRaw; lengthBytes; // Unused for now.

        IfFailGo(hr);
        if (HostConfigFlags::flags.GenerateLibraryByteCodeHeaderIsEnabled)
        {
            jsrtAttributes = (JsRuntimeAttributes)(jsrtAttributes | JsRuntimeAttributeSerializeLibraryByteCode);
        }

#if ENABLE_TTD
        if (doTTRecord)
        {
            //Ensure we run with experimental features (as that is what Node does right now).
            jsrtAttributes = static_cast<JsRuntimeAttributes>(jsrtAttributes | JsRuntimeAttributeEnableExperimentalFeatures);

            IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateRecordRuntime(jsrtAttributes, ttUri, ttUriByteLength, snapInterval, snapHistoryLength, Helpers::TTInitializeForWriteLogStreamCallback, Helpers::TTCreateStreamCallback, Helpers::TTReadBytesFromStreamCallback, Helpers::TTWriteBytesToStreamCallback, Helpers::TTFlushAndCloseStreamCallback, nullptr, &runtime));
            chRuntime = runtime;

            JsContextRef context = JS_INVALID_REFERENCE;
            IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateContext(runtime, true, &context));

#if ENABLE_TTD
            //We need this here since this context is created in record
            IfJsErrorFailLog(ChakraRTInterface::JsSetObjectBeforeCollectCallback(context, nullptr, WScriptJsrt::JsContextBeforeCollectCallback));
#endif

            IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context));
        }
        else
        {
            AssertMsg(!doTTDebug, "Should be handled in the else case above!!!");

            IfJsErrorFailLog(ChakraRTInterface::JsCreateRuntime(jsrtAttributes, nullptr, &runtime));
            chRuntime = runtime;

            if (HostConfigFlags::flags.DebugLaunch)
            {
                Debugger* debugger = Debugger::GetDebugger(runtime);
                debugger->StartDebugging(runtime);
            }

            JsContextRef context = JS_INVALID_REFERENCE;
            IfJsErrorFailLog(ChakraRTInterface::JsCreateContext(runtime, &context));

            //Don't need collect callback since this is always in replay

            IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context));
        }
#else
        IfJsErrorFailLog(ChakraRTInterface::JsCreateRuntime(jsrtAttributes, nullptr, &runtime));
        chRuntime = runtime;

        if (HostConfigFlags::flags.DebugLaunch)
        {
            Debugger* debugger = Debugger::GetDebugger(runtime);
            debugger->StartDebugging(runtime);
        }

        JsContextRef context = JS_INVALID_REFERENCE;
        IfJsErrorFailLog(ChakraRTInterface::JsCreateContext(runtime, &context));
        IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context));
#endif

#ifdef DEBUG
        ChakraRTInterface::SetCheckOpHelpersFlag(true);
#endif
#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
        ChakraRTInterface::SetOOPCFGRegistrationFlag(false);
#endif

        if (!WScriptJsrt::Initialize())
        {
            IfFailGo(E_FAIL);
        }

        if (_fullpath(fullPath, fileName, _MAX_PATH) == nullptr)
        {
            IfFailGo(E_FAIL);
        }

        // canonicalize that path name to lower case for the profile storage
        // REVIEW: Assuming no utf8 characters here
        len = strlen(fullPath);
        for (size_t i = 0; i < len; i++)
        {
            fullPath[i] = (char)tolower(fullPath[i]);
        }

        if (HostConfigFlags::flags.GenerateLibraryByteCodeHeaderIsEnabled)
        {
            if (HostConfigFlags::flags.GenerateLibraryByteCodeHeader != nullptr && *HostConfigFlags::flags.GenerateLibraryByteCodeHeader != _u('\0'))
            {
                CHAR libraryName[_MAX_PATH];
                CHAR ext[_MAX_EXT];
                _splitpath_s(fullPath, NULL, 0, NULL, 0, libraryName, _countof(libraryName), ext, _countof(ext));

                IfFailGo(CreateLibraryByteCodeHeader(fileContents, lengthBytes, HostConfigFlags::flags.GenerateLibraryByteCodeHeader, libraryName));
            }
            else
            {
                fwprintf(stderr, _u("FATAL ERROR: -GenerateLibraryByteCodeHeader must provide the file name, i.e., -GenerateLibraryByteCodeHeader:<bytecode file name>, exiting\n"));
                IfFailGo(E_FAIL);
            }
        }
        else if (HostConfigFlags::flags.SerializedIsEnabled)
        {
            CreateAndRunSerializedScript(fileName, fileContents, fullPath);
        }
        else
        {
            IfFailGo(RunScript(fileName, fileContents, nullptr, fullPath));
        }
    }
Error:
    if (Debugger::debugger != nullptr)
    {
        Debugger::debugger->CompareOrWriteBaselineFile(fileName);
        Debugger::CloseDebugger();
    }

    ChakraRTInterface::JsSetCurrentContext(nullptr);

    if (runtime != JS_INVALID_RUNTIME_HANDLE)
    {
        ChakraRTInterface::JsDisposeRuntime(runtime);
    }

    _flushall();

    return hr;
}
Exemple #10
0
void Binder::CheckMscorlib()
{
    const FieldOffsetCheck     *pOffsets = MscorlibFieldOffsets;

    while (pOffsets->fieldID != FIELD__NIL)
    {
        FieldDesc *pFD = g_Mscorlib.FetchField(pOffsets->fieldID);
        DWORD offset = pFD->GetOffset();

        if (!pFD->GetMethodTableOfEnclosingClass()->IsValueClass())
            offset += sizeof(ObjHeader);

        _ASSERTE(offset == pOffsets->expectedOffset
                 && "Managed class field offset does not match unmanaged class field offset");
        pOffsets++;
    }

    const ClassSizeCheck     *pSizes = MscorlibClassSizes;

    while (pSizes->classID != CLASS__NIL)
    {
        MethodTable *pMT = g_Mscorlib.FetchClass(pSizes->classID);
        DWORD size = pMT->GetClass()->GetNumInstanceFieldBytes();
        DWORD expected = pSizes->expectedSize - sizeof(void*);

        _ASSERTE(size == expected
                 && "Managed object size does not match unmanaged object size");
        pSizes++;
    }

    // check the consistency of BCL and VM
    // note: it is not enabled by default because of it is time consuming and 
    // changes the bootstrap sequence of the EE
    if (!g_pConfig->GetConfigDWORD(L"ConsistencyCheck", 0))
        return;

    //
    // VM referencing BCL (mscorlib.h)
    //
    for (BinderClassID cID = (BinderClassID) 1; cID <= g_Mscorlib.m_cClassRIDs; cID = (BinderClassID) (cID + 1)) {
        if (g_Mscorlib.GetClassName(cID) != NULL) // Allow for CorSigElement entries with no classes
            g_Mscorlib.FetchClass(cID);
    }

    for (BinderMethodID mID = (BinderMethodID) 1; mID <= g_Mscorlib.m_cMethodRIDs; mID = (BinderMethodID) (mID + 1))
        g_Mscorlib.FetchMethod(mID);

    for (BinderFieldID fID = (BinderFieldID) 1; fID <= g_Mscorlib.m_cFieldRIDs; fID = (BinderFieldID) (fID + 1))
        g_Mscorlib.FetchField(fID);

    //
    // BCL referencing VM (ecall.cpp)
    //
    HRESULT hr = S_OK;
    Module *pModule = g_Mscorlib.m_pModule;
    IMDInternalImport *pInternalImport = pModule->GetMDImport();

    HENUMInternal hEnum;

    // for all methods...
    IfFailGo(pInternalImport->EnumAllInit(mdtMethodDef, &hEnum));

    for (;;) {
        mdTypeDef td;
        mdTypeDef tdClass;
        DWORD dwImplFlags;

        if (!pInternalImport->EnumNext(&hEnum, &td))
            break;

        pInternalImport->GetMethodImplProps(td, NULL, &dwImplFlags);

        // ... that are internal calls ...
        if (!IsMiInternalCall(dwImplFlags))
            continue;

        IfFailGo(pInternalImport->GetParentToken(td, &tdClass));

        NameHandle className(pModule, tdClass);
        TypeHandle type;
        
        type = pModule->GetClassLoader()->LoadTypeHandle(&className, RETURN_ON_ERROR, FALSE);          
        if (type.IsNull()) {
            LPCUTF8 pszName = pInternalImport->GetNameOfMethodDef(tdClass);
            OutputDebugStringA(pszName);
            OutputDebugStringA("\n");
            _ASSERTE(false);
        }      

        MethodDesc *pMD = type.AsMethodTable()->GetClass()->FindMethod(td);;
        _ASSERTE(pMD);

        // ... check that the method is in the fcall table.
        if (GetIDForMethod(pMD) == 0xffff) {
            LPCUTF8 pszName = pInternalImport->GetNameOfMethodDef(td);
            OutputDebugStringA(pszName);
            OutputDebugStringA("\n");
            _ASSERTE(false);
        }
    }

    pInternalImport->EnumClose(&hEnum);

ErrExit:
    _ASSERTE(SUCCEEDED(hr));
}
Exemple #11
0
HRESULT Helpers::LoadScriptFromFile(LPCWSTR filename, LPCWSTR& contents, bool* isUtf8Out, LPCWSTR* contentsRawOut, UINT* lengthBytesOut, bool printFileOpenError)
{
    HRESULT hr = S_OK;
    LPCWSTR contentsRaw = nullptr;
    UINT lengthBytes = 0;
    bool isUtf8 = false;
    contents = nullptr;
    FILE * file;

    //
    // Open the file as a binary file to prevent CRT from handling encoding, line-break conversions,
    // etc.
    //
    if (_wfopen_s(&file, filename, L"rb") != 0)
    {
        if (printFileOpenError)
        {
            DWORD lastError = GetLastError();
            wchar_t wszBuff[512];
            fwprintf(stderr, L"Error in opening file '%s' ", filename);
            wszBuff[0] = 0;
            if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
                nullptr,
                lastError,
                0,
                wszBuff,
                _countof(wszBuff),
                nullptr))
            {
                fwprintf(stderr, L": %s", wszBuff);
            }
            fwprintf(stderr, L"\n");
            IfFailGo(E_FAIL);
        }
        else
        {
            return E_FAIL;
        }
    }

    //
    // Determine the file length, in bytes.
    //
    fseek(file, 0, SEEK_END);
    lengthBytes = ftell(file);
    fseek(file, 0, SEEK_SET);
    contentsRaw = (LPCWSTR)HeapAlloc(GetProcessHeap(), 0, lengthBytes + sizeof(WCHAR));
    if (nullptr == contentsRaw)
    {
        fwprintf(stderr, L"out of memory");
        IfFailGo(E_OUTOFMEMORY);
    }

    //
    // Read the entire content as a binary block.
    //
    fread((void*)contentsRaw, sizeof(char), lengthBytes, file);
    fclose(file);
    *(WCHAR*)((byte*)contentsRaw + lengthBytes) = L'\0'; // Null terminate it. Could be LPCWSTR.

    //
    // Read encoding, handling any conversion to Unicode.
    //
    // Warning: The UNICODE buffer for parsing is supposed to be provided by the host.
    // This is not a complete read of the encoding. Some encodings like UTF7, UTF1, EBCDIC, SCSU, BOCU could be
    // wrongly classified as ANSI
    //
    byte * pRawBytes = (byte*)contentsRaw;
    if ((0xEF == *pRawBytes && 0xBB == *(pRawBytes + 1) && 0xBF == *(pRawBytes + 2)))
    {
        isUtf8 = true;
    }
    else if (0xFFFE == *contentsRaw || 0x0000 == *contentsRaw && 0xFEFF == *(contentsRaw + 1))
    {
        // unicode unsupported
        fwprintf(stderr, L"unsupported file encoding");
        IfFailGo(E_UNEXPECTED);
    }
    else if (0xFEFF == *contentsRaw)
    {
        // unicode LE
        contents = contentsRaw;
    }
    else
    {
        // Assume UTF8
        isUtf8 = true;
    }


    if (isUtf8)
    {
        utf8::DecodeOptions decodeOptions = utf8::doAllowInvalidWCHARs;

        UINT cUtf16Chars = utf8::ByteIndexIntoCharacterIndex(pRawBytes, lengthBytes, decodeOptions);
        contents = (LPCWSTR)HeapAlloc(GetProcessHeap(), 0, (cUtf16Chars + 1) * sizeof(WCHAR));
        if (nullptr == contents)
        {
            fwprintf(stderr, L"out of memory");
            IfFailGo(E_OUTOFMEMORY);
        }

        utf8::DecodeIntoAndNullTerminate((wchar_t*) contents, pRawBytes, cUtf16Chars, decodeOptions);
    }

Error:
    if (SUCCEEDED(hr) && isUtf8Out)
    {
        Assert(contentsRawOut);
        Assert(lengthBytesOut);
        *isUtf8Out = isUtf8;
        *contentsRawOut = contentsRaw;
        *lengthBytesOut = lengthBytes;
    }
    else if (contentsRaw && (contentsRaw != contents)) // Otherwise contentsRaw is lost. Free it if it is different to contents.
    {
        HeapFree(GetProcessHeap(), 0, (void*)contentsRaw);
    }

    if (contents && FAILED(hr))
    {
        HeapFree(GetProcessHeap(), 0, (void*)contents);
        contents = nullptr;
    }

    return hr;
}
Exemple #12
0
HRESULT _CountBytesOfOneArg(
    PCCOR_SIGNATURE pbSig,
    ULONG       *pcbTotal)  // Initially, *pcbTotal contains the remaining size of the sig blob
{
    ULONG       cb;
    ULONG       cbTotal=0;
    ULONG       cbTotalMax;
    CorElementType ulElementType;
    ULONG       ulData;
    ULONG       ulTemp;
    int         iData;
    mdToken     tk;
    ULONG       cArg;
    ULONG       callingconv;
    ULONG       cArgsIndex;
    HRESULT     hr = NOERROR;

    if(pcbTotal==NULL) return E_FAIL;
    cbTotalMax = *pcbTotal;

    CHECK_REMAINDER;
    cbTotal = CorSigUncompressElementType(pbSig, &ulElementType);
    while (CorIsModifierElementType((CorElementType) ulElementType))
    {
        CHECK_REMAINDER;
        cbTotal += CorSigUncompressElementType(&pbSig[cbTotal], &ulElementType);
    }
    switch (ulElementType)
    {
        case ELEMENT_TYPE_SZARRAY:
        case 0x1e /* obsolete */:
            // skip over base type
            CHECK_REMAINDER;
            cb = cbTotalMax - cbTotal;
            IfFailGo( _CountBytesOfOneArg(&pbSig[cbTotal], &cb) );
            cbTotal += cb;
            break;

        case ELEMENT_TYPE_FNPTR:
            CHECK_REMAINDER;
            cbTotal += CorSigUncompressData (&pbSig[cbTotal], &callingconv);

            // remember number of bytes to represent the arg counts
            CHECK_REMAINDER;
            cbTotal += CorSigUncompressData (&pbSig[cbTotal], &cArg);

            // how many bytes to represent the return type
            CHECK_REMAINDER;
            cb = cbTotalMax - cbTotal;
            IfFailGo( _CountBytesOfOneArg( &pbSig[cbTotal], &cb) );
            cbTotal += cb;

            // loop through argument
            for (cArgsIndex = 0; cArgsIndex < cArg; cArgsIndex++)
            {
                CHECK_REMAINDER;
                cb = cbTotalMax - cbTotal;
                IfFailGo( _CountBytesOfOneArg( &pbSig[cbTotal], &cb) );
                cbTotal += cb;
            }

            break;

        case ELEMENT_TYPE_ARRAY:
            // syntax : ARRAY BaseType <rank> [i size_1... size_i] [j lowerbound_1 ... lowerbound_j]

            // skip over base type
            CHECK_REMAINDER;
            cb = cbTotalMax - cbTotal;
            IfFailGo( _CountBytesOfOneArg(&pbSig[cbTotal], &cb) );
            cbTotal += cb;

            // Parse for the rank
            CHECK_REMAINDER;
            cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulData);

            // if rank == 0, we are done
            if (ulData == 0)
                break;

            // any size of dimension specified?
            CHECK_REMAINDER;
            cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulData);
            while (ulData--)
            {
                CHECK_REMAINDER;
                cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulTemp);
            }

            // any lower bound specified?
            CHECK_REMAINDER;
            cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulData);

            while (ulData--)
            {
                CHECK_REMAINDER;
                cbTotal += CorSigUncompressSignedInt(&pbSig[cbTotal], &iData);
            }

            break;
        case ELEMENT_TYPE_VALUETYPE:
        case ELEMENT_TYPE_CLASS:
        case ELEMENT_TYPE_CMOD_REQD:
        case ELEMENT_TYPE_CMOD_OPT:
            // count the bytes for the token compression
            CHECK_REMAINDER;
            cbTotal += CorSigUncompressToken(&pbSig[cbTotal], &tk);
            if ( ulElementType == ELEMENT_TYPE_CMOD_REQD ||
                 ulElementType == ELEMENT_TYPE_CMOD_OPT)
            {
                // skip over base type
                CHECK_REMAINDER;
                cb = cbTotalMax - cbTotal;
                IfFailGo( _CountBytesOfOneArg(&pbSig[cbTotal], &cb) );
                cbTotal += cb;
            }
            break;
        default:
            break;
    }

    *pcbTotal = cbTotal;
ErrExit:
    return hr;
}
Exemple #13
0
//*****************************************************************************
// copy fixed part of VarArg signature to a buffer
//*****************************************************************************
HRESULT _GetFixedSigOfVarArg(           // S_OK or error.
    PCCOR_SIGNATURE pvSigBlob,          // [IN] point to a blob of COM+ method signature
    ULONG   cbSigBlob,                  // [IN] size of signature
    CQuickBytes *pqbSig,                // [OUT] output buffer for fixed part of VarArg Signature
    ULONG   *pcbSigBlob)                // [OUT] number of bytes written to the above output buffer
{
    HRESULT     hr = NOERROR;
    ULONG       cbCalling;
    ULONG       cbTyArgsNumber = 0;     // number of bytes to store the type arg count (generics only)
    ULONG       cbArgsNumber;           // number of bytes to store the original arg count
    ULONG       cbArgsNumberTemp;       // number of bytes to store the fixed arg count
    ULONG       cbTotal = 0;            // total of number bytes for return type + all fixed arguments
    ULONG       cbCur = 0;              // index through the pvSigBlob
    ULONG       cb;
    ULONG       cArg;
    ULONG       cTyArg;
    ULONG       callingconv;
    ULONG       cArgsIndex;
    CorElementType ulElementType;
    BYTE        *pbSig;

    _ASSERTE (pvSigBlob && pcbSigBlob);

    // remember the number of bytes to represent the calling convention
    cbCalling = CorSigUncompressData (pvSigBlob, &callingconv);
    if (cbCalling == ((ULONG)(-1)))
    {
        return E_INVALIDARG;
    }
    _ASSERTE (isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_VARARG));
    cbCur += cbCalling;

    if (callingconv & IMAGE_CEE_CS_CALLCONV_GENERIC)
    {
        cbTyArgsNumber = CorSigUncompressData(&pvSigBlob[cbCur], &cTyArg);
        if (cbTyArgsNumber == ((ULONG)(-1)))
        {
            return E_INVALIDARG;
        }
        cbCur += cbTyArgsNumber;
    }

    // remember number of bytes to represent the arg counts
    cbArgsNumber= CorSigUncompressData (&pvSigBlob[cbCur], &cArg);
    if (cbArgsNumber == ((ULONG)(-1)))
    {
        return E_INVALIDARG;
    }
    
    cbCur += cbArgsNumber;

    // how many bytes to represent the return type
    cb = cbSigBlob-cbCur;
    IfFailGo( _CountBytesOfOneArg( &pvSigBlob[cbCur], &cb) );
    cbCur += cb;
    cbTotal += cb;

    // loop through argument until we found ELEMENT_TYPE_SENTINEL or run
    // out of arguments
    for (cArgsIndex = 0; cArgsIndex < cArg; cArgsIndex++)
    {
        _ASSERTE(cbCur < cbSigBlob);

        // peak the outer most ELEMENT_TYPE_*
        CorSigUncompressElementType (&pvSigBlob[cbCur], &ulElementType);
        if (ulElementType == ELEMENT_TYPE_SENTINEL)
            break;
        cb = cbSigBlob-cbCur;
        IfFailGo( _CountBytesOfOneArg( &pvSigBlob[cbCur], &cb) );
        cbTotal += cb;
        cbCur += cb;
    }

    cbArgsNumberTemp = CorSigCompressData(cArgsIndex, &cArg);

    // now cbCalling : the number of bytes needed to store the calling convention
    // cbArgNumberTemp : number of bytes to store the fixed arg count
    // cbTotal : the number of bytes to store the ret and fixed arguments

    *pcbSigBlob = cbCalling + cbArgsNumberTemp + cbTotal;

    // resize the buffer
    IfFailGo( pqbSig->ReSizeNoThrow(*pcbSigBlob) );
    pbSig = (BYTE *)pqbSig->Ptr();

    // copy over the calling convention
    cb = CorSigCompressData(callingconv, pbSig);

    // copy over the fixed arg count
    cbArgsNumberTemp = CorSigCompressData(cArgsIndex, &pbSig[cb]);

    // copy over the fixed args + ret type
    memcpy(&pbSig[cb + cbArgsNumberTemp], &pvSigBlob[cbCalling + cbArgsNumber], cbTotal);

ErrExit:
    return hr;
}
Exemple #14
0
//*****************************************************************************
// Remove a RegMeta pointer from the loaded module list
//*****************************************************************************
// static
HRESULT 
LOADEDMODULES::ResolveTypeRefWithLoadedModules(
    mdTypeRef          tkTypeRef,       // [IN] TypeRef to be resolved.
    RegMeta *          pTypeRefRegMeta, // [IN] Scope in which the TypeRef is defined.
    IMetaModelCommon * pTypeRefScope,   // [IN] Scope in which the TypeRef is defined.
    REFIID             riid,            // [IN] iid for the return interface.
    IUnknown **        ppIScope,        // [OUT] Return interface.
    mdTypeDef *        ptd)             // [OUT] TypeDef corresponding the TypeRef.
{
    HRESULT   hr = NOERROR;
    RegMeta * pRegMeta;
    CQuickArray<mdTypeRef> cqaNesters;
    CQuickArray<LPCUTF8>   cqaNesterNamespaces;
    CQuickArray<LPCUTF8>   cqaNesterNames;
    
    IfFailGo(InitializeStatics());
    
    {
        LOCKREAD();
    
        // Get the Nesting hierarchy.
        IfFailGo(ImportHelper::GetNesterHierarchy(
            pTypeRefScope, 
            tkTypeRef, 
            cqaNesters, 
            cqaNesterNamespaces, 
            cqaNesterNames));

        int count = s_pLoadedModules->Count();
        for (int index = 0; index < count; index++)
        {
            pRegMeta = (*s_pLoadedModules)[index];
        
            {
                // Do not lock the TypeRef RegMeta (again), as it is already locked for read by the caller.
                // The code:UTSemReadWrite will block ReadLock even for thread holding already the read lock if 
                // some other thread is waiting for WriteLock on the same lock. That would cause dead-lock if we 
                // try to lock for read again here.
                CMDSemReadWrite cSemRegMeta((pRegMeta == pTypeRefRegMeta) ? NULL : pRegMeta->GetReaderWriterLock());
                IfFailGo(cSemRegMeta.LockRead());
            
                hr = ImportHelper::FindNestedTypeDef(
                    pRegMeta->GetMiniMd(), 
                    cqaNesterNamespaces, 
                    cqaNesterNames, 
                    mdTokenNil, 
                    ptd);
            }
            if (hr == CLDB_E_RECORD_NOTFOUND)
            {   // Process next MetaData module
                continue;
            }
            IfFailGo(hr);
        
            // Found a loaded module containing the TypeDef.
            IfFailGo(pRegMeta->QueryInterface(riid, (void **)ppIScope));
            break;
        }
    }
    if (FAILED(hr))
    {
        // cannot find the match!
        hr = E_FAIL;
    }
ErrExit:
    return hr;
}    // LOADEDMODULES::ResolveTypeRefWithLoadedModules
//*****************************************************************************
// Determine what the size of the saved data will be.
//*****************************************************************************
__checkReturn 
HRESULT CLiteWeightStgdbRW::GetSaveSize(// S_OK or error.
    CorSaveSize               fSave,                // Quick or accurate?
    UINT32                   *pcbSaveSize,          // Put the size here.
    MetaDataReorderingOptions reorderingOptions,
    CorProfileData           *pProfileData)        // Profile data for working set optimization
{
    HRESULT hr = S_OK;              // A result.
    UINT32  cbTotal = 0;            // The total size.
    UINT32  cbSize = 0;             // Size of a component.
    
    m_cbSaveSize = 0;
    
    // Allocate stream list if not already done.
    if (m_pStreamList == NULL)
    {
        IfNullGo(m_pStreamList = new (nothrow) STORAGESTREAMLST);
    }
    else
    {
        m_pStreamList->Clear();
    }
    
    // Make sure the user string pool is not empty. An empty user string pool causes
    // problems with edit and continue
    
    if (m_MiniMd.m_UserStringHeap.GetUnalignedSize() <= 1)
    {
        if (!IsENCDelta(m_MiniMd.m_OptionValue.m_UpdateMode) && 
            !m_MiniMd.IsMinimalDelta())
        {
            BYTE   rgData[] = {' ', 0, 0};
            UINT32 nIndex_Ignore;
            IfFailGo(m_MiniMd.PutUserString(
                MetaData::DataBlob(rgData, sizeof(rgData)), 
                &nIndex_Ignore));
        }
    }
    
    // If we're saving a delta metadata, figure out how much space it will take to
    // save the minimal metadata stream (used only to identify that we have a delta
    // metadata... nothing should be in that stream.
    if ((m_MiniMd.m_OptionValue.m_UpdateMode & MDUpdateMask) == MDUpdateDelta)
    {
        IfFailGo(AddStreamToList(0, MINIMAL_MD_STREAM));
        // Ask the storage system to add stream fixed overhead.
        IfFailGo(TiggerStorage::GetStreamSaveSize(MINIMAL_MD_STREAM, 0, &cbSize));
        cbTotal += cbSize;
    }
    
    if (reorderingOptions & ReArrangeStringPool)
    {
        if (pProfileData != NULL)
        {
            UINT32 cbHotSize = 0;          // Size of pool data.
            UINT32 cbStream;               // Size of just the stream.
            DWORD  bCompressed;            // Will the stream be compressed data?
            
            // Ask the metadata to size its hot data.
            IfFailGo(m_MiniMd.GetSaveSize(fSave, &cbHotSize, &bCompressed, reorderingOptions, pProfileData));
            cbStream = cbHotSize;
            m_bSaveCompressed = bCompressed;
            
            if (cbHotSize != 0)
            {
                // Add this item to the save list.
                IfFailGo(AddStreamToList(cbHotSize, HOT_MODEL_STREAM));
                
                // Ask the storage system to add stream fixed overhead.
                IfFailGo(TiggerStorage::GetStreamSaveSize(HOT_MODEL_STREAM, cbHotSize, &cbHotSize));
                
                // Log the size info.
                LOG((LF_METADATA, LL_INFO10, "Metadata: GetSaveSize for %ls: %d data, %d total.\n",
                    HOT_MODEL_STREAM, cbStream, cbHotSize));
                
                cbTotal += cbHotSize;
            }
        }
        
        // get string pool save size
        IfFailGo(GetPoolSaveSize(STRING_POOL_STREAM, MDPoolStrings, &cbSize));
        cbTotal += cbSize;
    }
    
    // Query the MiniMd for its size.
    IfFailGo(GetTablesSaveSize(fSave, &cbSize, reorderingOptions, pProfileData));
    cbTotal += cbSize;
    
    // Get the pools' sizes.
    if( !(reorderingOptions & ReArrangeStringPool) )
    {
        IfFailGo(GetPoolSaveSize(STRING_POOL_STREAM, MDPoolStrings, &cbSize));
        cbTotal += cbSize;
    }
    IfFailGo(GetPoolSaveSize(US_BLOB_POOL_STREAM, MDPoolUSBlobs, &cbSize));
    cbTotal += cbSize;
    IfFailGo(GetPoolSaveSize(GUID_POOL_STREAM, MDPoolGuids, &cbSize));
    cbTotal += cbSize;
    IfFailGo(GetPoolSaveSize(BLOB_POOL_STREAM, MDPoolBlobs, &cbSize));
    cbTotal += cbSize;
    
    // Finally, ask the storage system to add fixed overhead it needs for the
    // file format.  The overhead of each stream has already be calculated as
    // part of GetStreamSaveSize.  What's left is the signature and header
    // fixed size overhead.
    IfFailGo(TiggerStorage::GetStorageSaveSize((ULONG *)&cbTotal, 0, m_MiniMd.m_OptionValue.m_RuntimeVersion));
    
    // Log the size info.
    LOG((LF_METADATA, LL_INFO10, "Metadata: GetSaveSize total is %d.\n", cbTotal));
    
    // The list of streams that will be saved are now in the stream save list.
    // Next step is to walk that list and fill out the correct offsets.  This is 
    // done here so that the data can be streamed without fixing up the header.
    TiggerStorage::CalcOffsets(m_pStreamList, 0, m_MiniMd.m_OptionValue.m_RuntimeVersion);
    
    if (pcbSaveSize != NULL)
    {
        *pcbSaveSize = cbTotal;
    }
    
    // Don't cache the value for the EnC case
    if (!IsENCDelta(m_MiniMd.m_OptionValue.m_UpdateMode))
        m_cbSaveSize = cbTotal;
    
ErrExit:
    return hr;
} // CLiteWeightStgdbRW::GetSaveSize
//*****************************************************************************
// Enumerate Sym.TypeDef.
//*****************************************************************************
STDMETHODIMP RegMeta::EnumTypeDefs(
    HCORENUM    *phEnum,                // Pointer to the enumerator.
    mdTypeDef   rTypeDefs[],            // Put TypeDefs here.
    ULONG       cMax,                   // Max TypeDefs to put.
    ULONG       *pcTypeDefs)            // Put # put here.
{
    HRESULT         hr = S_OK;

    BEGIN_ENTRYPOINT_NOTHROW;

    HENUMInternal   **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
    HENUMInternal   *pEnum;

    LOG((LOGMD, "RegMeta::EnumTypeDefs(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", 
            phEnum, rTypeDefs, cMax, pcTypeDefs));
    START_MD_PERF();
    LOCKREAD();
    

    if ( *ppmdEnum == 0 )
    {
        // instantiating a new ENUM
        CMiniMdRW       *pMiniMd = &(m_pStgdb->m_MiniMd);

        if (pMiniMd->HasDelete() && 
            ((m_OptionValue.m_ImportOption & MDImportOptionAllTypeDefs) == 0))
        {
            IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtTypeDef, &pEnum) );

            // add all Types to the dynamic array if name is not _Delete
            for (ULONG index = 2; index <= pMiniMd->getCountTypeDefs(); index ++ )
            {
                TypeDefRec *pRec;
                IfFailGo(pMiniMd->GetTypeDefRecord(index, &pRec));
                LPCSTR szTypeDefName;
                IfFailGo(pMiniMd->getNameOfTypeDef(pRec, &szTypeDefName));
                if (IsDeletedName(szTypeDefName))
                {
                    continue;
                }
                IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtTypeDef) ) );
            }
        }
        else
        {
            // create the enumerator
            IfFailGo( HENUMInternal::CreateSimpleEnum(
                mdtTypeDef, 
                2, 
                pMiniMd->getCountTypeDefs() + 1, 
                &pEnum) );
        }
        
        // set the output parameter
        *ppmdEnum = pEnum;
    }
    else
    {
        pEnum = *ppmdEnum;
    }

    // we can only fill the minimun of what caller asked for or what we have left
    hr = HENUMInternal::EnumWithCount(pEnum, cMax, rTypeDefs, pcTypeDefs);

ErrExit:
    HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
    
    STOP_MD_PERF(EnumTypeDefs);

    END_ENTRYPOINT_NOTHROW;

    return hr;
} // RegMeta::EnumTypeDefs
//*****************************************************************************
// Get the save size of the metadata tables.  Also adds the tables stream to
//  the list of streams to be saved.
//*****************************************************************************
__checkReturn 
HRESULT CLiteWeightStgdbRW::GetTablesSaveSize(
    CorSaveSize               fSave,
    UINT32                   *pcbSaveSize,
    MetaDataReorderingOptions reorderingOptions,
    CorProfileData           *pProfileData)           // Add pool data to this value.
{
    UINT32  cbSize = 0;             // Size of pool data.
    UINT32  cbHotSize = 0;          // Size of pool data.
    UINT32  cbStream;               // Size of just the stream.
    DWORD   bCompressed;            // Will the stream be compressed data?
    LPCWSTR szName;                 // What will the name of the pool be?
    HRESULT hr;
    
    *pcbSaveSize = 0;

    if( !(reorderingOptions & ReArrangeStringPool) )
    {
        if (pProfileData != NULL)
        {
            // Ask the metadata to size its hot data.
            IfFailGo(m_MiniMd.GetSaveSize(fSave, &cbHotSize, &bCompressed, reorderingOptions, pProfileData));
            cbStream = cbHotSize;
            m_bSaveCompressed = bCompressed;
    
            if (cbHotSize != 0)
            {
                szName = HOT_MODEL_STREAM;
    
                // Add this item to the save list.
                IfFailGo(AddStreamToList(cbHotSize, szName));
        
                // Ask the storage system to add stream fixed overhead.
                IfFailGo(TiggerStorage::GetStreamSaveSize(szName, cbHotSize, &cbHotSize));
    
                // Log the size info.
                LOG((LF_METADATA, LL_INFO10, "Metadata: GetSaveSize for %ls: %d data, %d total.\n",
                    szName, cbStream, cbHotSize));
            }
        }
    }
    // Ask the metadata to size its data.
    IfFailGo(m_MiniMd.GetSaveSize(fSave, &cbSize, &bCompressed));
    cbStream = cbSize;
    m_bSaveCompressed = bCompressed;
    szName = m_bSaveCompressed ? COMPRESSED_MODEL_STREAM : ENC_MODEL_STREAM;

    // Add this item to the save list.
    IfFailGo(AddStreamToList(cbSize, szName));
    
    // Ask the storage system to add stream fixed overhead.
    IfFailGo(TiggerStorage::GetStreamSaveSize(szName, cbSize, &cbSize));

    // Log the size info.
    LOG((LF_METADATA, LL_INFO10, "Metadata: GetSaveSize for %ls: %d data, %d total.\n",
        szName, cbStream, cbSize));

    // Give the size of the pool to the caller's total.
    *pcbSaveSize = cbHotSize + cbSize;

ErrExit:
    return hr;
} // CLiteWeightStgdbRW::GetTablesSaveSize
//*****************************************************************************
// Enumerate Sym.InterfaceImpl where Coclass == td
//*****************************************************************************
STDMETHODIMP RegMeta::EnumInterfaceImpls(
    HCORENUM        *phEnum,            // Pointer to the enum.
    mdTypeDef       td,                 // TypeDef to scope the enumeration.
    mdInterfaceImpl rImpls[],           // Put InterfaceImpls here.
    ULONG           cMax,               // Max InterfaceImpls to put.
    ULONG           *pcImpls)           // Put # put here.
{
    HRESULT             hr = S_OK;

    BEGIN_ENTRYPOINT_NOTHROW;

    HENUMInternal       **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
    ULONG               ridStart;
    ULONG               ridEnd;
    HENUMInternal       *pEnum;
    InterfaceImplRec    *pRec;
    ULONG               index;

    LOG((LOGMD, "RegMeta::EnumInterfaceImpls(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", 
            phEnum, td, rImpls, cMax, pcImpls));
    START_MD_PERF();
    LOCKREAD();
    
    _ASSERTE(TypeFromToken(td) == mdtTypeDef);


    if ( *ppmdEnum == 0 )
    {
        // instantiating a new ENUM
        CMiniMdRW       *pMiniMd = &(m_pStgdb->m_MiniMd);
        if ( pMiniMd->IsSorted( TBL_InterfaceImpl ) )
        {
            IfFailGo(pMiniMd->getInterfaceImplsForTypeDef(RidFromToken(td), &ridEnd, &ridStart));
            IfFailGo( HENUMInternal::CreateSimpleEnum( mdtInterfaceImpl, ridStart, ridEnd, &pEnum) );
        }
        else
        {
            // table is not sorted so we have to create dynmaic array 
            // create the dynamic enumerator
            //
            ridStart = 1;
            ridEnd = pMiniMd->getCountInterfaceImpls() + 1;

            IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtInterfaceImpl, &pEnum) );
            
            for (index = ridStart; index < ridEnd; index ++ )
            {
                IfFailGo(pMiniMd->GetInterfaceImplRecord(index, &pRec));
                if ( td == pMiniMd->getClassOfInterfaceImpl(pRec) )
                {
                    IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtInterfaceImpl) ) );
                }
            }
        }

        // set the output parameter
        *ppmdEnum = pEnum;
    }
    else
    {
        pEnum = *ppmdEnum;
    }
    
    // fill the output token buffer
    hr = HENUMInternal::EnumWithCount(pEnum, cMax, rImpls, pcImpls);

ErrExit:
    HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
    
    STOP_MD_PERF(EnumInterfaceImpls);

    END_ENTRYPOINT_NOTHROW;

    return hr;
} // RegMeta::EnumInterfaceImpls
//*****************************************************************************
// Save the metadata to a file.
//*****************************************************************************
__checkReturn 
HRESULT CLiteWeightStgdbRW::Save(
    LPCWSTR szDatabase,     // Name of file to which to save.
    DWORD   dwSaveFlags)    // Flags for the save.
{
    TiggerStorage * pStorage = NULL;    // IStorage object.
    StgIO *         pStgIO = NULL;      // Backing storage.
    HRESULT         hr = S_OK;
    
    if (m_wszFileName == NULL)
    {
        if (szDatabase == NULL)
        {
            // Make sure that a NULL is not passed in the first time around.
            _ASSERTE(!"Not allowed to pass a NULL for filename on the first call to Save.");
            return E_INVALIDARG;
        }
        else
        {
            // Save the file name.
            IfFailGo(SetFileName(szDatabase));
        }
    }
    else if ((szDatabase != NULL) && (SString::_wcsicmp(szDatabase, m_wszFileName) != 0))
    {
        // Save the file name.
        IfFailGo(SetFileName(szDatabase));
    }
    
    // Sanity check the name.
    if (!IsValidFileNameLength(m_wszFileName))
    {
        IfFailGo(E_INVALIDARG);
    }
    
    m_eFileType = FILETYPE_CLB;
    
    // Allocate a new storage object.
    IfNullGo(pStgIO = new (nothrow) StgIO);
    
    // Create the output file.
    IfFailGo(pStgIO->Open(m_wszFileName, 
        DBPROP_TMODEF_DFTWRITEMASK,
        0,0,                // pbData, cbData
        0,                  // IStream*
        0));                // LPSecurityAttributes
    
    // Allocate an IStorage object to use.
    IfNullGo(pStorage = new (nothrow) TiggerStorage);
    
    // Init the storage object on the i/o system.
    OptionValue ov;
    IfFailGo(m_MiniMd.GetOption(&ov));
    IfFailGo(pStorage->Init(pStgIO, ov.m_RuntimeVersion));
    
    // Save the data.
    IfFailGo(SaveToStorage(pStorage));
    
ErrExit:
    if (pStgIO != NULL)
        pStgIO->Release();
    if (pStorage != NULL)
        delete pStorage;
    return hr;
} // CLiteWeightStgdbRW::Save
STDMETHODIMP RegMeta::EnumMethodSpecs(
        HCORENUM    *phEnum,                // [IN|OUT] Pointer to the enum.
        mdToken      tkOwner,               // [IN] MethodDef or MemberRef whose MethodSpecs are requested
        mdMethodSpec rTokens[],             // [OUT] Put MethodSpecs here.
        ULONG       cMaxTokens,             // [IN] Max tokens to put.
        ULONG       *pcTokens)              // [OUT] Put actual count here.
{
    HRESULT             hr = S_OK;

    BEGIN_ENTRYPOINT_NOTHROW;

    HENUMInternal       **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
    ULONG               ridStart;
    ULONG               ridEnd;
    HENUMInternal       *pEnum;
    MethodSpecRec       *pRec;
    ULONG               index;
    CMiniMdRW       *pMiniMd = NULL;

    LOG((LOGMD, "RegMeta::EnumMethodSpecs(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", 
            phEnum, tkOwner, rTokens, cMaxTokens, pcTokens));
    START_MD_PERF();
    LOCKREAD();

    pMiniMd = &(m_pStgdb->m_MiniMd);

    // See if this version of the metadata can do Generics
    if (!pMiniMd->SupportsGenerics())
    {
        if (pcTokens)
            *pcTokens = 0;
        hr = S_FALSE;
        goto ErrExit;
    }

    
    _ASSERTE(RidFromToken(tkOwner)==0 || TypeFromToken(tkOwner) == mdtMethodDef || TypeFromToken(tkOwner) == mdtMemberRef);


    if ( *ppmdEnum == 0 )
    {
        // instantiating a new ENUM

        if(RidFromToken(tkOwner)==0) // enumerate all MethodSpecs
        {
            ridStart = 1;
            ridEnd = pMiniMd->getCountMethodSpecs() + 1;
    
            IfFailGo( HENUMInternal::CreateSimpleEnum( mdtMethodSpec, ridStart, ridEnd, &pEnum) );
        }
        else
        {
            //@todo GENERICS: review this. Are we expecting a sorted table or not?
            if ( pMiniMd->IsSorted( TBL_MethodSpec ) )
            {
                if (TypeFromToken(tkOwner) == mdtMemberRef)
                {
                    IfFailGo(pMiniMd->getMethodSpecsForMemberRef(RidFromToken(tkOwner), &ridEnd, &ridStart));
                }
                else
                {
                    IfFailGo(pMiniMd->getMethodSpecsForMethodDef(RidFromToken(tkOwner), &ridEnd, &ridStart));
                }
    
                IfFailGo( HENUMInternal::CreateSimpleEnum(mdtMethodSpec, ridStart, ridEnd, &pEnum) );
            }
            else
            {
                // table is not sorted so we have to create dynamic array 
                // create the dynamic enumerator
                //
                ridStart = 1;
                ridEnd = pMiniMd->getCountMethodSpecs() + 1;
    
                IfFailGo( HENUMInternal::CreateDynamicArrayEnum(mdtMethodSpec, &pEnum) );
                
                for (index = ridStart; index < ridEnd; index ++ )
                {
                    IfFailGo(pMiniMd->GetMethodSpecRecord(index, &pRec));
                    if ( tkOwner == pMiniMd->getMethodOfMethodSpec(pRec) )
                    {
                        IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtMethodSpec) ) );
                    }
                }
            }
        }
        // set the output parameter
        *ppmdEnum = pEnum;
    }
    else
    {
        pEnum = *ppmdEnum;
    }
    
    // fill the output token buffer
    hr = HENUMInternal::EnumWithCount(pEnum, cMaxTokens, rTokens, pcTokens);

ErrExit:
    HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
    STOP_MD_PERF(EnumMethodSpecs);
    END_ENTRYPOINT_NOTHROW;

    return hr;
} // STDMETHODIMP RegMeta::EnumMethodSpecs()
Exemple #21
0
//*****************************************************************************
// translating signature from one scope to another scope
// 
// Implements public API code:IMetaDataEmit::TranslateSigWithScope.
// Implements internal API code:IMetaDataHelper::TranslateSigWithScope.
//*****************************************************************************
STDMETHODIMP RegMeta::TranslateSigWithScope(    // S_OK or error.
    IMetaDataAssemblyImport *pAssemImport, // [IN] importing assembly interface
    const void  *pbHashValue,           // [IN] Hash Blob for Assembly.
    ULONG       cbHashValue,            // [IN] Count of bytes.
    IMetaDataImport *pImport,           // [IN] importing interface
    PCCOR_SIGNATURE pbSigBlob,          // [IN] signature in the importing scope
    ULONG       cbSigBlob,              // [IN] count of bytes of signature
    IMetaDataAssemblyEmit   *pAssemEmit,// [IN] emit assembly interface
    IMetaDataEmit *pEmit,               // [IN] emit interface
    PCOR_SIGNATURE pvTranslatedSig,     // [OUT] buffer to hold translated signature
    ULONG       cbTranslatedSigMax,
    ULONG       *pcbTranslatedSig)      // [OUT] count of bytes in the translated signature
{
#ifdef FEATURE_METADATA_EMIT
    HRESULT     hr = S_OK;

    IMDCommon   *pAssemImportMDCommon = NULL;
    IMDCommon   *pImportMDCommon = NULL;

    BEGIN_ENTRYPOINT_NOTHROW;

    RegMeta     *pRegMetaAssemEmit = static_cast<RegMeta*>(pAssemEmit);
    RegMeta     *pRegMetaEmit = NULL;

    CQuickBytes qkSigEmit;
    ULONG       cbEmit;

    pRegMetaEmit = static_cast<RegMeta*>(pEmit);

    {
        // This function can cause new TypeRef being introduced.
        LOCKWRITE();
        
        IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
        
        _ASSERTE(pvTranslatedSig && pcbTranslatedSig);

        if (pAssemImport)
        {
            IfFailGo(pAssemImport->QueryInterface(IID_IMDCommon, (void**)&pAssemImportMDCommon));
        }
        IMetaModelCommon *pAssemImportMetaModelCommon = pAssemImportMDCommon ? pAssemImportMDCommon->GetMetaModelCommon() : 0;

        IfFailGo(pImport->QueryInterface(IID_IMDCommon, (void**)&pImportMDCommon));
        IMetaModelCommon *pImportMetaModelCommon = pImportMDCommon->GetMetaModelCommon();

        IfFailGo( ImportHelper::MergeUpdateTokenInSig(  // S_OK or error.
                pRegMetaAssemEmit ? &(pRegMetaAssemEmit->m_pStgdb->m_MiniMd) : 0, // The assembly emit scope.
                &(pRegMetaEmit->m_pStgdb->m_MiniMd),    // The emit scope.
                pAssemImportMetaModelCommon,            // Assembly where the signature is from.
                pbHashValue,                            // Hash value for the import assembly.
                cbHashValue,                            // Size in bytes.
                pImportMetaModelCommon,                 // The scope where signature is from.
                pbSigBlob,                              // signature from the imported scope
                NULL,                                   // Internal OID mapping structure.
                &qkSigEmit,                             // [OUT] translated signature
                0,                                      // start from first byte of the signature
                0,                                      // don't care how many bytes consumed
                &cbEmit));                              // [OUT] total number of bytes write to pqkSigEmit
        memcpy(pvTranslatedSig, qkSigEmit.Ptr(), cbEmit > cbTranslatedSigMax ? cbTranslatedSigMax :cbEmit );
        *pcbTranslatedSig = cbEmit;
        if (cbEmit > cbTranslatedSigMax)
            hr = CLDB_S_TRUNCATION;
    }

ErrExit:
    END_ENTRYPOINT_NOTHROW;

    if (pAssemImportMDCommon)
        pAssemImportMDCommon->Release();
    if (pImportMDCommon)
        pImportMDCommon->Release();

    return hr;
#else //!FEATURE_METADATA_EMIT
    return E_NOTIMPL;
#endif //!FEATURE_METADATA_EMIT
} // RegMeta::TranslateSigWithScope
STDMETHODIMP RegMeta::EnumGenericParamConstraints(
    HCORENUM    *phEnum,                // [IN|OUT] Pointer to the enum.
    mdGenericParam tkOwner,             // [IN] GenericParam whose constraints are requested
    mdGenericParamConstraint rTokens[],    // [OUT] Put GenericParamConstraints here.
    ULONG       cMaxTokens,                   // [IN] Max GenericParamConstraints to put.
    ULONG       *pcTokens)              // [OUT] Put # of tokens here.
{
    HRESULT             hr = S_OK;
    
    BEGIN_ENTRYPOINT_NOTHROW;

    HENUMInternal       **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum);
    ULONG               ridStart;
    ULONG               ridEnd;
    HENUMInternal       *pEnum;
    GenericParamConstraintRec     *pRec;
    ULONG               index;
    CMiniMdRW       *pMiniMd = NULL;

    LOG((LOGMD, "RegMeta::EnumGenericParamConstraints(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", 
            phEnum, tkOwner, rTokens, cMaxTokens, pcTokens));
    START_MD_PERF();
    LOCKREAD();

    pMiniMd = &(m_pStgdb->m_MiniMd);


    if(TypeFromToken(tkOwner) != mdtGenericParam)
        IfFailGo(META_E_BAD_INPUT_PARAMETER);

    // See if this version of the metadata can do Generics
    if (!pMiniMd->SupportsGenerics())
    {
        if (pcTokens)
            *pcTokens = 0;
        hr = S_FALSE;
        goto ErrExit;
    }

    if ( *ppmdEnum == 0 )
    {
        // instantiating a new ENUM

        //<TODO> GENERICS: review this. Are we expecting a sorted table or not? </TODO>
        if ( pMiniMd->IsSorted( TBL_GenericParamConstraint ) )
        {
            IfFailGo(pMiniMd->getGenericParamConstraintsForGenericParam(RidFromToken(tkOwner), &ridEnd, &ridStart));
            IfFailGo( HENUMInternal::CreateSimpleEnum(mdtGenericParamConstraint, ridStart, ridEnd, &pEnum) );
        }
        else
        {
            // table is not sorted so we have to create dynamic array 
            // create the dynamic enumerator
            //
            ridStart = 1;
            ridEnd = pMiniMd->getCountGenericParamConstraints() + 1;

            IfFailGo( HENUMInternal::CreateDynamicArrayEnum(mdtGenericParamConstraint, &pEnum));

            for (index = ridStart; index < ridEnd; index ++ )
            {
                IfFailGo(pMiniMd->GetGenericParamConstraintRecord(index, &pRec));
                if ( tkOwner == pMiniMd->getOwnerOfGenericParamConstraint(pRec))
                {
                    IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, 
                                                                       mdtGenericParamConstraint)));
                }
            }
        }

        // set the output parameter
        *ppmdEnum = pEnum;
    }
    else
    {
        pEnum = *ppmdEnum;
    }
    
    // fill the output token buffer
    hr = HENUMInternal::EnumWithCount(pEnum, cMaxTokens, rTokens, pcTokens);

ErrExit:
    HENUMInternal::DestroyEnumIfEmpty(ppmdEnum);
    STOP_MD_PERF(EnumGenericParamConstraints);
    END_ENTRYPOINT_NOTHROW;
    
    return hr;
}
HRESULT Helpers::LoadScriptFromFile(LPCSTR filenameToLoad, LPCSTR& contents, UINT* lengthBytesOut /*= nullptr*/, std::string* fullPath /*= nullptr*/, bool shouldMute /*=false */)
{
    static char sHostApplicationPathBuffer[MAX_URI_LENGTH];
    static uint sHostApplicationPathBufferLength = (uint) -1;
    char combinedPathBuffer[MAX_URI_LENGTH];

    HRESULT hr = S_OK;
    BYTE * pRawBytes = nullptr;
    BYTE * pRawBytesFromMap = nullptr;
    UINT lengthBytes = 0;
    contents = nullptr;
    FILE * file = NULL;
    size_t bufferLength = 0;

    LPCSTR filename = fullPath == nullptr ? filenameToLoad : LPCSTR(fullPath->c_str());
    if (sHostApplicationPathBufferLength == (uint)-1)
    {
        // consider incoming filename as the host app and base its' path for others
        sHostApplicationPathBufferLength = GetPathNameLocation(filename);
        if (sHostApplicationPathBufferLength == -1)
        {
            // host app has no path info. (it must be located on current folder!)
            sHostApplicationPathBufferLength = 0;
        }
        else
        {
            sHostApplicationPathBufferLength += 1;
            Assert(sHostApplicationPathBufferLength < MAX_URI_LENGTH);
            // save host app's path and fix the path separator for platform
            pathcpy(sHostApplicationPathBuffer, filename, sHostApplicationPathBufferLength);
        }
        sHostApplicationPathBuffer[sHostApplicationPathBufferLength] = char(0);
    }
    else if (filename[0] != '/' && filename[0] != '\\' && fullPath == nullptr) // make sure it's not a full path
    {
        // concat host path and filename
        uint len = ConcatPath(sHostApplicationPathBuffer, sHostApplicationPathBufferLength,
                   filename, combinedPathBuffer, MAX_URI_LENGTH);

        if (len == (uint)-1)
        {
            hr = E_FAIL;
            goto Error;
        }
        filename = combinedPathBuffer;
    }

    // check if have it registered
    AutoString *data;
    if (SourceMap::Find(filenameToLoad, strlen(filenameToLoad), &data) ||
        SourceMap::Find(filename, strlen(filename), &data))
    {
        pRawBytesFromMap = (BYTE*) data->GetString();
        lengthBytes = (UINT) data->GetLength();
    }
    else
    {
        // Open the file as a binary file to prevent CRT from handling encoding, line-break conversions,
        // etc.
        if (fopen_s(&file, filename, "rb") != 0)
        {
            if (!HostConfigFlags::flags.MuteHostErrorMsgIsEnabled && !shouldMute)
            {
#ifdef _WIN32
                DWORD lastError = GetLastError();
                char16 wszBuff[MAX_URI_LENGTH];
                fprintf(stderr, "Error in opening file '%s' ", filename);
                wszBuff[0] = 0;
                if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                    nullptr,
                    lastError,
                    0,
                    wszBuff,
                    _countof(wszBuff),
                    nullptr))
                {
                    fwprintf(stderr, _u(": %s"), wszBuff);
                }
                fwprintf(stderr, _u("\n"));
#elif defined(_POSIX_VERSION)
                fprintf(stderr, "Error in opening file: ");
                perror(filename);
#endif
            }

            IfFailGo(E_FAIL);
        }
    }

    if (file != NULL)
    {
        // Determine the file length, in bytes.
        fseek(file, 0, SEEK_END);
        lengthBytes = ftell(file);
        fseek(file, 0, SEEK_SET);
    }

    if (lengthBytes != 0)
    {
        bufferLength = lengthBytes + sizeof(BYTE);
        pRawBytes = (LPBYTE)malloc(bufferLength);
    }
    else
    {
        bufferLength = 1;
        pRawBytes = (LPBYTE)malloc(bufferLength);
    }

    if (nullptr == pRawBytes)
    {
        fwprintf(stderr, _u("out of memory"));
        IfFailGo(E_OUTOFMEMORY);
    }

    if (lengthBytes != 0)
    {
        if (file != NULL)
        {
            //
            // Read the entire content as a binary block.
            //
            size_t readBytes = fread(pRawBytes, sizeof(BYTE), lengthBytes, file);
            if (readBytes < lengthBytes * sizeof(BYTE))
            {
                IfFailGo(E_FAIL);
            }
        }
        else // from module source register
        {
            // Q: module source is on persistent memory. Why do we use the copy instead?
            // A: if we use the same memory twice, ch doesn't know that during FinalizeCallback free.
            // the copy memory will be freed by the finalizer
            Assert(pRawBytesFromMap);
            memcpy_s(pRawBytes, bufferLength, pRawBytesFromMap, lengthBytes);
        }
    }

    if (pRawBytes)
    {
        pRawBytes[lengthBytes] = 0; // Null terminate it. Could be UTF16
    }

    if (file != NULL)
    {
        //
        // Read encoding to make sure it's supported
        //
        // Warning: The UNICODE buffer for parsing is supposed to be provided by the host.
        // This is not a complete read of the encoding. Some encodings like UTF7, UTF1, EBCDIC, SCSU, BOCU could be
        // wrongly classified as ANSI
        //
#pragma warning(push)
        // suppressing prefast warning that "readable size is bufferLength
        // bytes but 2 may be read" as bufferLength is clearly > 2 in the code that follows
#pragma warning(disable:6385)
        C_ASSERT(sizeof(WCHAR) == 2);
        if (bufferLength > 2)
        {
            __analysis_assume(bufferLength > 2);
#pragma prefast(push)
#pragma prefast(disable:6385, "PREfast incorrectly reports this as an out-of-bound access.");
            if ((pRawBytes[0] == 0xFE && pRawBytes[1] == 0xFF) ||
                (pRawBytes[0] == 0xFF && pRawBytes[1] == 0xFE) ||
                (bufferLength > 4 && pRawBytes[0] == 0x00 && pRawBytes[1] == 0x00 &&
                    ((pRawBytes[2] == 0xFE && pRawBytes[3] == 0xFF) ||
                    (pRawBytes[2] == 0xFF && pRawBytes[3] == 0xFE))))

            {
                // unicode unsupported
                fwprintf(stderr, _u("unsupported file encoding. Only ANSI and UTF8 supported"));
                IfFailGo(E_UNEXPECTED);
            }
#pragma prefast(pop)
        }
#pragma warning(pop)
    }

    contents = reinterpret_cast<LPCSTR>(pRawBytes);

Error:
    if (SUCCEEDED(hr))
    {
        if (lengthBytesOut)
        {
            *lengthBytesOut = lengthBytes;
        }
    }

    if (file != NULL)
    {
        fclose(file);
    }

    if (pRawBytes && reinterpret_cast<LPCSTR>(pRawBytes) != contents)
    {
        free(pRawBytes);
    }

    return hr;
}
//*****************************************************************************
// Get info about the MD stream.
// Low level access to stream data.  Intended for metainfo, and such.
//*****************************************************************************
__checkReturn 
STDMETHODIMP 
CLiteWeightStgdbRW::GetRawStreamInfo(
    ULONG        ix,            // [IN] Stream ordinal desired.
    const char **ppchName,      // [OUT] put pointer to stream name here.
    const void **ppv,           // [OUT] put pointer to MD stream here.
    ULONG       *pcb)           // [OUT] put size of the stream here.
{
    HRESULT        hr = NOERROR;
    STORAGEHEADER  sHdr;            // Header for the storage.
    PSTORAGESTREAM pStream;         // Pointer to each stream.
    ULONG          i;               // Loop control.
    void          *pData;
    ULONG          cbData;

#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
    if (m_pStgIO == NULL)
        IfFailGo(COR_E_NOTSUPPORTED);
#endif

    pData = m_pStgIO->m_pData;
    cbData = m_pStgIO->m_cbData;
    
    // Validate the signature of the format, or it isn't ours.
    IfFailGo(MDFormat::VerifySignature((PSTORAGESIGNATURE) pData, cbData));
    
    // Get back the first stream.
    pStream = MDFormat::GetFirstStream(&sHdr, pData);
    if (pStream == NULL)
    {
        Debug_ReportError("Invalid MetaData storage signature - cannot get the first stream header.");
        IfFailGo(CLDB_E_FILE_CORRUPT);
    }
    
    // Check that the requested stream exists.
    if (ix >= sHdr.GetiStreams())
        return S_FALSE;
    
    // Skip to the desired stream.
    for (i = 0; i < ix; i++)
    {
        PSTORAGESTREAM pNext = pStream->NextStream();
        
        // Check that stream header is within the buffer.
        if (((LPBYTE)pStream >= ((LPBYTE)pData + cbData)) || 
            ((LPBYTE)pNext   >  ((LPBYTE)pData + cbData)))
        {
            Debug_ReportError("Stream header is not within MetaData block.");
            hr = CLDB_E_FILE_CORRUPT;
            goto ErrExit;
        }
        
        // Check that the stream data starts and fits within the buffer.
        //  need two checks on size because of wraparound.
        if ((pStream->GetOffset() > cbData) || 
            (pStream->GetSize() > cbData) || 
            ((pStream->GetSize() + pStream->GetOffset()) > cbData))
        {
            Debug_ReportError("Stream data are not within MetaData block.");
            hr = CLDB_E_FILE_CORRUPT;
            goto ErrExit;
        }
        
        // Pick off the next stream if there is one.
        pStream = pNext;
    }
    
    if (pStream != NULL)
    {
        *ppv = (const void *)((const BYTE *)pData + pStream->GetOffset());
        *pcb = pStream->GetSize();
        *ppchName = pStream->GetName();
    }
    else
    {
        *ppv = NULL;
        *pcb = 0;
        *ppchName = NULL;
        
        // Invalid input to the method
        hr = CLDB_E_FILE_CORRUPT;
    }
    
ErrExit:
    return hr;
} // CLiteWeightStgdbRW::GetRawStreamInfo
//*****************************************************************************
// Driver for the delta process.
//*****************************************************************************
__checkReturn
HRESULT
CMiniMdRW::ApplyDelta(
    CMiniMdRW &mdDelta) // Interface to MD with the ENC delta.
{
    HRESULT hr = S_OK;
    ULONG   iENC;       // Loop control.
    ULONG   iRid;       // RID of some record.
    ULONG   iNew;       // RID of a new record.
    int     i;          // Loop control.
    ULONG   ixTbl;      // A table.

#ifdef _DEBUG
    if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_ApplyDeltaBreak))
    {
        _ASSERTE(!"CMiniMDRW::ApplyDelta()");
    }
#endif // _DEBUG

    // Init the suppressed column table.  We know this one isn't zero...
    if (m_SuppressedDeltaColumns[TBL_TypeDef] == 0)
    {
        m_SuppressedDeltaColumns[TBL_EventMap]      = (1 << EventMapRec::COL_EventList);
        m_SuppressedDeltaColumns[TBL_PropertyMap]   = (1 << PropertyMapRec::COL_PropertyList);
        m_SuppressedDeltaColumns[TBL_EventMap]      = (1 << EventMapRec::COL_EventList);
        m_SuppressedDeltaColumns[TBL_Method]        = (1 << MethodRec::COL_ParamList);
        m_SuppressedDeltaColumns[TBL_TypeDef]       = (1 << TypeDefRec::COL_FieldList)|(1<<TypeDefRec::COL_MethodList);
    }

    // Verify the version of the MD.
    if (m_Schema.m_major != mdDelta.m_Schema.m_major ||
            m_Schema.m_minor != mdDelta.m_Schema.m_minor)
    {
        _ASSERTE(!"Version of Delta MetaData is a incompatible with current MetaData.");
        //<TODO>@FUTURE: unique error in the future since we are not shipping ENC.</TODO>
        return E_INVALIDARG;
    }

    // verify MVIDs.
    ModuleRec *pModDelta;
    ModuleRec *pModBase;
    IfFailGo(mdDelta.GetModuleRecord(1, &pModDelta));
    IfFailGo(GetModuleRecord(1, &pModBase));
    GUID GuidDelta;
    GUID GuidBase;
    IfFailGo(mdDelta.getMvidOfModule(pModDelta, &GuidDelta));
    IfFailGo(getMvidOfModule(pModBase, &GuidBase));
    if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_DeltaCheck) && (GuidDelta != GuidBase))
    {
        _ASSERTE(!"Delta MetaData has different base than current MetaData.");
        return E_INVALIDARG;
    }

#ifndef FEATURE_CORECLR
    // Verify that the delta is based on the base.
    IfFailGo(mdDelta.getEncBaseIdOfModule(pModDelta, &GuidDelta));
    IfFailGo(getEncBaseIdOfModule(pModBase,&GuidBase));
    if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_DeltaCheck) &&
            CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_UseMinimalDeltas) &&
            (GuidDelta != GuidBase))
    {
        _ASSERTE(!"The Delta MetaData is based on a different generation than the current MetaData.");
        return E_INVALIDARG;
    }
#endif //!FEATURE_CORECLR    

    // Let the other md prepare for sparse records.
    IfFailGo(mdDelta.StartENCMap());

    // Fix the heaps.
    IfFailGo(ApplyHeapDeltas(mdDelta));

    // Truncate some tables in preparation to copy in new ENCLog data.
    for (i = 0; (ixTbl = m_TruncatedEncTables[i]) != (ULONG)-1; ++i)
    {
        m_Tables[ixTbl].Delete();
        IfFailGo(m_Tables[ixTbl].InitializeEmpty_WithRecordCount(
                     m_TableDefs[ixTbl].m_cbRec,
                     mdDelta.m_Schema.m_cRecs[ixTbl]
                     COMMA_INDEBUG_MD(TRUE)));       // fIsReadWrite
        INDEBUG_MD(m_Tables[ixTbl].Debug_SetTableInfo(NULL, ixTbl));
        m_Schema.m_cRecs[ixTbl] = 0;
    }

    // For each record in the ENC log...
    for (iENC = 1; iENC <= mdDelta.m_Schema.m_cRecs[TBL_ENCLog]; ++iENC)
    {
        // Get the record, and the updated token.
        ENCLogRec *pENC;
        IfFailGo(mdDelta.GetENCLogRecord(iENC, &pENC));
        ENCLogRec *pENC2;
        IfFailGo(AddENCLogRecord(&pENC2, &iNew));
        IfNullGo(pENC2);
        ENCLogRec *pENC3;
        _ASSERTE(iNew == iENC);
        ULONG func = pENC->GetFuncCode();
        pENC2->SetFuncCode(pENC->GetFuncCode());
        pENC2->SetToken(pENC->GetToken());

        // What kind of record is this?
        if (IsRecId(pENC->GetToken()))
        {   // Non-token table
            iRid = RidFromRecId(pENC->GetToken());
            ixTbl = TblFromRecId(pENC->GetToken());
        }
        else
        {   // Token table.
            iRid = RidFromToken(pENC->GetToken());
            ixTbl = GetTableForToken(pENC->GetToken());
        }

        RID rid_Ignore;
        // Switch based on the function code.
        switch (func)
        {
        case eDeltaMethodCreate:
            // Next ENC record will define the new Method.
            MethodRec *pMethodRecord;
            IfFailGo(AddMethodRecord(&pMethodRecord, &rid_Ignore));
            IfFailGo(AddMethodToTypeDef(iRid, m_Schema.m_cRecs[TBL_Method]));
            break;

        case eDeltaParamCreate:
            // Next ENC record will define the new Param.  This record is
            //  tricky because params will be re-ordered based on their sequence,
            //  but the sequence isn't set until the NEXT record is applied.
            //  So, for ParamCreate only, apply the param record delta before
            //  adding the parent-child linkage.
            ParamRec *pParamRecord;
            IfFailGo(AddParamRecord(&pParamRecord, &rid_Ignore));

            // Should have recorded a Param delta after the Param add.
            _ASSERTE(iENC<mdDelta.m_Schema.m_cRecs[TBL_ENCLog]);
            IfFailGo(mdDelta.GetENCLogRecord(iENC+1, &pENC3));
            _ASSERTE(pENC3->GetFuncCode() == 0);
            _ASSERTE(GetTableForToken(pENC3->GetToken()) == TBL_Param);
            IfFailGo(ApplyTableDelta(mdDelta, TBL_Param, RidFromToken(pENC3->GetToken()), eDeltaFuncDefault));

            // Now that Param record is OK, set up linkage.
            IfFailGo(AddParamToMethod(iRid, m_Schema.m_cRecs[TBL_Param]));
            break;

        case eDeltaFieldCreate:
            // Next ENC record will define the new Field.
            FieldRec *pFieldRecord;
            IfFailGo(AddFieldRecord(&pFieldRecord, &rid_Ignore));
            IfFailGo(AddFieldToTypeDef(iRid, m_Schema.m_cRecs[TBL_Field]));
            break;

        case eDeltaPropertyCreate:
            // Next ENC record will define the new Property.
            PropertyRec *pPropertyRecord;
            IfFailGo(AddPropertyRecord(&pPropertyRecord, &rid_Ignore));
            IfFailGo(AddPropertyToPropertyMap(iRid, m_Schema.m_cRecs[TBL_Property]));
            break;

        case eDeltaEventCreate:
            // Next ENC record will define the new Event.
            EventRec *pEventRecord;
            IfFailGo(AddEventRecord(&pEventRecord, &rid_Ignore));
            IfFailGo(AddEventToEventMap(iRid, m_Schema.m_cRecs[TBL_Event]));
            break;

        case eDeltaFuncDefault:
            IfFailGo(ApplyTableDelta(mdDelta, ixTbl, iRid, func));
            break;

        default:
            _ASSERTE(!"Unexpected function in ApplyDelta");
            IfFailGo(E_UNEXPECTED);
            break;
        }
    }
    m_Schema.m_cRecs[TBL_ENCLog] = mdDelta.m_Schema.m_cRecs[TBL_ENCLog];

ErrExit:
    // Store the result for returning (IfFailRet will modify hr)
    HRESULT hrReturn = hr;
    IfFailRet(mdDelta.EndENCMap());

#ifndef FEATURE_CORECLR
    if (SUCCEEDED(hrReturn) &&
            CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_DeltaCheck) &&
            CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_UseMinimalDeltas))
    {
        GUID GuidNewBase;

        // We'll use the delta's 'delta guid' for our new base guid
        IfFailRet(mdDelta.getEncIdOfModule(pModDelta, &GuidNewBase));

        IfFailRet(PutGuid(TBL_Module, ModuleRec::COL_EncBaseId, pModBase, GuidNewBase));
    }
#endif //!FEATURE_CORECLR

    return hrReturn;
} // CMiniMdRW::ApplyDelta
//*****************************************************************************
// Given an StgIO, opens compressed streams and do proper initialization.
// This is a helper for other Init functions.
//*****************************************************************************
__checkReturn 
HRESULT 
CLiteWeightStgdbRW::InitFileForRead(
    StgIO * pStgIO,     // For file i/o.
    int     bReadOnly)  // If read-only open.
{
    TiggerStorage * pStorage = NULL;
    void          * pvData;
    ULONG           cbData;
    HRESULT         hr = NOERROR;
    
    // Allocate a new storage object which has IStorage on it.
    pStorage = new (nothrow) TiggerStorage();
    IfNullGo(pStorage);
    
    // Init the storage object on the backing storage.
    OptionValue ov;
    IfFailGo(m_MiniMd.GetOption(&ov));
    IfFailGo(pStorage->Init(pStgIO, ov.m_RuntimeVersion));
    
    // Save pointers to header structure for version string.
    _ASSERTE((m_pvMd == NULL) && (m_cbMd == 0));
    IfFailGo(pStorage->GetHeaderPointer(&m_pvMd, &m_cbMd));
    
    // Check to see if this is a minimal metadata
    if (SUCCEEDED(pStorage->OpenStream(MINIMAL_MD_STREAM, &cbData, &pvData)))
    {
        m_MiniMd.m_fMinimalDelta = TRUE;
    }
    
    // Load the string pool.
    if (SUCCEEDED(hr = pStorage->OpenStream(STRING_POOL_STREAM, &cbData, &pvData)))
    {
        // String pool has to end with a null-terminator, therefore we don't have to check string pool 
        // content on access.
        // Shrink size of the pool to the last null-terminator found.
        while (cbData != 0)
        {
            if (((LPBYTE)pvData)[cbData - 1] == 0)
            {   // We have found last null terminator
                break;
            }
            // Shrink size of the pool
            cbData--;
            Debug_ReportError("String heap/pool does not end with null-terminator ... shrinking the heap.");
        }
        IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolStrings, pvData, cbData, bReadOnly));
    }
    else
    {
        if (hr != STG_E_FILENOTFOUND)
        {
            IfFailGo(hr);
        }
        IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolStrings, NULL, 0, bReadOnly));
    }
    
    // Load the user string blob pool.
    if (SUCCEEDED(hr = pStorage->OpenStream(US_BLOB_POOL_STREAM, &cbData, &pvData)))
    {
        IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolUSBlobs, pvData, cbData, bReadOnly));
    }
    else
    {
        if (hr != STG_E_FILENOTFOUND)
        {
            IfFailGo(hr);
        }
        IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolUSBlobs, NULL, 0, bReadOnly));
    }
    
    // Load the guid pool.
    if (SUCCEEDED(hr = pStorage->OpenStream(GUID_POOL_STREAM, &cbData, &pvData)))
    {
        IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolGuids, pvData, cbData, bReadOnly));
    }
    else
    {
        if (hr != STG_E_FILENOTFOUND)
        {
            IfFailGo(hr);
        }
        IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolGuids, NULL, 0, bReadOnly));
    }
    
    // Load the blob pool.
    if (SUCCEEDED(hr = pStorage->OpenStream(BLOB_POOL_STREAM, &cbData, &pvData)))
    {
        IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolBlobs, pvData, cbData, bReadOnly));
    }
    else
    {
        if (hr != STG_E_FILENOTFOUND)
        {
            IfFailGo(hr);
        }
        IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolBlobs, NULL, 0, bReadOnly));
    }
    
    // Open the metadata.
    hr = pStorage->OpenStream(COMPRESSED_MODEL_STREAM, &cbData, &pvData);
    if (hr == STG_E_FILENOTFOUND)
    {
        IfFailGo(pStorage->OpenStream(ENC_MODEL_STREAM, &cbData, &pvData));
    }
    IfFailGo(m_MiniMd.InitOnMem(pvData, cbData, bReadOnly));
    IfFailGo(m_MiniMd.PostInit(0));
    
ErrExit:
    if (pStorage != NULL)
    {
        delete pStorage;
    }
    return hr;
} // CLiteWeightStgdbRW::InitFileForRead
//*****************************************************************************
// CheckFileFormat
// This function will determine if the in-memory image is a readonly, readwrite,
// or ICR format.
//*****************************************************************************
HRESULT 
CheckFileFormat(
    LPVOID        pData, 
    ULONG         cbData, 
    MDFileFormat *pFormat)  // [OUT] the file format
{
    HRESULT        hr = NOERROR;
    STORAGEHEADER  sHdr;        // Header for the storage.
    PSTORAGESTREAM pStream;     // Pointer to each stream.
    int            i;
    ULONG          cbStreamBuffer;
    
    _ASSERTE(pFormat != NULL);
    
    *pFormat = MDFormat_Invalid;
    
    // Validate the signature of the format, or it isn't ours.
    if (FAILED(hr = MDFormat::VerifySignature((PSTORAGESIGNATURE) pData, cbData)))
        goto ErrExit;
    
    // Remaining buffer size behind the stream header (pStream).
    cbStreamBuffer = cbData;
    // Get back the first stream.
    pStream = MDFormat::GetFirstStream_Verify(&sHdr, pData, &cbStreamBuffer);
    if (pStream == NULL)
    {
        Debug_ReportError("Invalid MetaData storage signature - cannot get the first stream header.");
        IfFailGo(CLDB_E_FILE_CORRUPT);
    }
    
    // Loop through each stream and pick off the ones we need.
    for (i = 0; i < sHdr.GetiStreams(); i++)
    {
        // Do we have enough buffer to read stream header?
        if (cbStreamBuffer < sizeof(*pStream))
        {
            Debug_ReportError("Stream header is not within MetaData block.");
            IfFailGo(CLDB_E_FILE_CORRUPT);
        }
        // Get next stream.
        PSTORAGESTREAM pNext = pStream->NextStream_Verify();
        
        // Check that stream header is within the buffer.
        if (((LPBYTE)pStream >= ((LPBYTE)pData + cbData)) ||
            ((LPBYTE)pNext   >  ((LPBYTE)pData + cbData)))
        {
            Debug_ReportError("Stream header is not within MetaData block.");
            hr = CLDB_E_FILE_CORRUPT;
            goto ErrExit;
        }
        
        // Check that the stream data starts and fits within the buffer.
        //  need two checks on size because of wraparound.
        if ((pStream->GetOffset() > cbData) || 
            (pStream->GetSize() > cbData) || 
            ((pStream->GetSize() + pStream->GetOffset()) < pStream->GetOffset()) || 
            ((pStream->GetSize() + pStream->GetOffset()) > cbData))
        {
            Debug_ReportError("Stream data are not within MetaData block.");
            hr = CLDB_E_FILE_CORRUPT;
            goto ErrExit;
        }
        
        // Pick off the location and size of the data.
        
        if (strcmp(pStream->GetName(), COMPRESSED_MODEL_STREAM_A) == 0)
        {
            // Validate that only one of compressed/uncompressed is present.
            if (*pFormat != MDFormat_Invalid)
            {   // Already found a good stream.
                Debug_ReportError("Compressed model stream #~ is second important stream.");
                hr = CLDB_E_FILE_CORRUPT;
                goto ErrExit;
            }
            // Found the compressed meta data stream.
            *pFormat = MDFormat_ReadOnly;
        }
        else if (strcmp(pStream->GetName(), ENC_MODEL_STREAM_A) == 0)
        {
            // Validate that only one of compressed/uncompressed is present.
            if (*pFormat != MDFormat_Invalid)
            {   // Already found a good stream.
                Debug_ReportError("ENC model stream #- is second important stream.");
                hr = CLDB_E_FILE_CORRUPT;
                goto ErrExit;
            }
            // Found the ENC meta data stream.
            *pFormat = MDFormat_ReadWrite;
        }
        else if (strcmp(pStream->GetName(), SCHEMA_STREAM_A) == 0)
        {
            // Found the uncompressed format
            *pFormat = MDFormat_ICR;
            
            // keep going. We may find the compressed format later. 
            // If so, we want to use the compressed format.
        }
        
        // Pick off the next stream if there is one.
        pStream = pNext;
        cbStreamBuffer = (ULONG)((LPBYTE)pData + cbData - (LPBYTE)pNext);
    }
    
    if (*pFormat == MDFormat_Invalid)
    {   // Didn't find a good stream.
        Debug_ReportError("Cannot find MetaData stream.");
        hr = CLDB_E_FILE_CORRUPT;
    }
    
ErrExit:
    return hr;
} // CheckFileFormat
//*****************************************************************************
// Open a metadata section for read
//*****************************************************************************
__checkReturn 
HRESULT CLiteWeightStgdbRW::OpenForRead(
    LPCWSTR     szDatabase,             // Name of database.
    void        *pbData,                // Data to open on top of, 0 default.
    ULONG       cbData,                 // How big is the data.
    DWORD       dwFlags)                // Flags for the open.
{
    LPCWSTR     pNoFile=W("");            // Constant for empty file name.
    StgIO       *pStgIO = NULL;         // For file i/o.
    HRESULT     hr;

    m_pImage = NULL;
    m_dwImageSize = 0;
    m_eFileType = FILETYPE_UNKNOWN;
    // szDatabase, and pbData are mutually exclusive.  Only one may be
    // non-NULL.  Having both NULL means empty stream creation.
    //
    _ASSERTE(!(szDatabase && (pbData)));
    _ASSERTE(!(pbData && (szDatabase)));

    // Open on memory needs there to be something to work with.
    if (pbData && cbData == 0)
        IfFailGo(CLDB_E_NO_DATA);

    // Make sure we have a path to work with.
    if (!szDatabase)
        szDatabase = pNoFile;
    
    // Sanity check the name lentgh.
    if (!IsValidFileNameLength(szDatabase))
    {
        IfFailGo(E_INVALIDARG);
    }
    
    // If we have storage to work with, init it and get type.
    if (*szDatabase || pbData)
    {
        // Allocate a storage instance to use for i/o.
        if ((pStgIO = new (nothrow) StgIO) == 0)
            IfFailGo( E_OUTOFMEMORY );

        DBPROPMODE dmOpenFlags = DBPROP_TMODEF_READ;

        // If we're taking ownership of this memory.....
        if (IsOfTakeOwnership(dwFlags))
        {
#ifdef FEATURE_METADATA_STANDALONE_WINRT_RO
            // Shared memory uses ole32.dll - we cannot depend on it in the standalone WinRT Read-Only DLL
            IfFailGo(E_INVALIDARG);
#else
            dmOpenFlags = (DBPROPMODE)(dmOpenFlags | DBPROP_TMODEF_SHAREDMEM);
#endif //!FEATURE_METADATA_STANDALONE_WINRT_RO
        }
#ifdef FEATURE_METADATA_LOAD_TRUSTED_IMAGES
        if (IsOfTrustedImage(dwFlags))
            dmOpenFlags = (DBPROPMODE)(dmOpenFlags | DBPROP_TMODEF_TRYLOADLIBRARY);
#endif

        // Open the storage so we can read the signature if there is already data.
        IfFailGo( pStgIO->Open(szDatabase, 
                               dmOpenFlags, 
                               pbData, 
                               cbData, 
                               0, // IStream*
                               NULL) );

        // Determine the type of file we are working with.
        IfFailGo( _GetFileTypeForPath(pStgIO, &m_eFileType) );
    }

    // Check for default type.
    if (m_eFileType == FILETYPE_CLB)
    {
        // If user wanted us to make a local copy of the data, do that now.
        if (IsOfCopyMemory(dwFlags))
            IfFailGo(pStgIO->LoadFileToMemory());

        // Try the native .clb file.
        IfFailGo( InitFileForRead(pStgIO, IsOfRead(dwFlags)) );
    }
    // PE/COFF executable/object format.  This requires us to find the .clb 
    // inside the binary before doing the Init.
    else if (m_eFileType == FILETYPE_NTPE || m_eFileType == FILETYPE_NTOBJ)
    {
        //<TODO>@FUTURE: Ideally the FindImageMetaData function
        //@FUTURE:  would take the pStgIO and map only the part of the file where
        //@FUTURE:  our data lives, leaving the rest alone.  This would be smaller
        //@FUTURE:  working set for us.</TODO>
        void        *ptr;
        ULONG       cbSize;

        // Map the entire binary for the FindImageMetaData function.
        IfFailGo( pStgIO->MapFileToMem(ptr, &cbSize) );

        // Find the .clb inside of the content.
        if (m_eFileType == FILETYPE_NTPE)
        {
            m_pImage = ptr;
            m_dwImageSize = cbSize;
            hr = FindImageMetaData(ptr, 
                                   cbSize, 
                                   pStgIO->GetMemoryMappedType() == MTYPE_IMAGE, 
                                   &ptr, 
                                   &cbSize);
        }
        else
        {
            _ASSERTE(pStgIO->GetMemoryMappedType() != MTYPE_IMAGE);
            hr = FindObjMetaData(ptr, cbSize, &ptr, &cbSize);
        }
        // Was the metadata found inside the PE file?
        if (FAILED(hr))
        {
            if (hr == E_OUTOFMEMORY)
                IfFailGo(E_OUTOFMEMORY);
        
            // No clb in the PE, assume it is a type library.
            m_eFileType = FILETYPE_TLB;

            // Let the caller deal with a TypeLib.
            IfFailGo(hr);
        }
        else
        {
            // Metadata was found inside the file.
            // Now reset the base of the stg object so that all memory accesses
            // are relative to the .clb content.
            //
            IfFailGo( pStgIO->SetBaseRange(ptr, cbSize) );

            // If user wanted us to make a local copy of the data, do that now.
            if (IsOfCopyMemory(dwFlags))
            {
                // Cache the PEKind, Machine.
                GetPEKind(pStgIO->GetMemoryMappedType(), NULL, NULL);
                // Copy the file into memory; releases the file.
                IfFailGo(pStgIO->LoadFileToMemory());
                // No longer have the image.
                m_pImage = NULL;
                m_dwImageSize = 0;
            }

            // Defer to the normal lookup.
            IfFailGo( InitFileForRead(pStgIO, IsOfRead(dwFlags)) );
        }
    }
    else if (m_eFileType == FILETYPE_TLB)
    {
        // Let the caller deal with a TypeLib.
        IfFailGo(CLDB_E_NO_DATA);
    }
    // This spells trouble, we need to handle all types we might find.
    else
    {
        _ASSERTE(!"Unknown file type.");
        IfFailGo( E_FAIL );
    }

    // Save off everything.
    IfFailGo(SetFileName(szDatabase));

    // If this was a file...
    if (pbData == NULL)
    {
        WIN32_FILE_ATTRIBUTE_DATA faData;
        if (!WszGetFileAttributesEx(szDatabase, GetFileExInfoStandard, &faData))
            IfFailGo(E_FAIL);
        m_dwDatabaseLFS = faData.nFileSizeLow;
        m_dwDatabaseLFT = faData.ftLastWriteTime.dwLowDateTime;
    }
    
ErrExit:
    if (SUCCEEDED(hr))
    {
        m_pStgIO = pStgIO;
    }
    else
    {
        if (pStgIO != NULL)
            pStgIO->Release();
    }
    return hr;
}
int _tmain(int argc, _TCHAR* argv[])
{
    HRESULT hr = S_OK;
    SolidEdgeFramework::ApplicationPtr pApplication = NULL;
    SolidEdgeAssembly::AssemblyDocumentPtr pAssemblyDocument = NULL;
    SolidEdgeAssembly::ConfigurationsPtr pConfigurations = NULL;
    SolidEdgeAssembly::ConfigurationPtr pConfiguration = NULL;
    CString strConfigName;

    // Initialize COM.
    ::CoInitialize(NULL);

    // Attempt to connect to a running instance of Solid Edge.
    IfFailGo(pApplication.GetActiveObject(L"SolidEdge.Application"));

    // Get a reference to the active assembly document.
    pAssemblyDocument = pApplication->ActiveDocument;

    if (pAssemblyDocument != NULL)
    {
        // Get a reference to the Configurations collection.
        pConfigurations = pAssemblyDocument->Configurations;

        LONG c = pConfigurations->Count;

        if (pConfigurations->Count > 0)
        {
            // Get a reference tot he Configurations collection.
            pConfiguration = pConfigurations->Item((LONG)1);

            // Configuration name has to be unique so for demonstration
            // purposes, use a random number.
            strConfigName.Format(L"%s %d", L"Configuration", rand());

            /* NOTE - Example is not working. Need help :-( */
            SAFEARRAY* sa;
            SAFEARRAYBOUND aDim;
            aDim.lLbound = 0;
            aDim.cElements = 1;

            sa = SafeArrayCreate(VT_BSTR, 1, &aDim);
            long index = 0;
            hr = SafeArrayPutElement(sa, &index, (void*)strConfigName.AllocSysString());

            VARIANT vConfigList;
            VariantInit(&vConfigList);
            vConfigList.vt = VT_ARRAY | VT_BSTR;
            vConfigList.parray = sa;

            pConfigurations->AddDerivedConfig(1, 0, 0, &vConfigList, NULL, NULL, strConfigName.AllocSysString());

            SafeArrayDestroy(sa);
        }
    }
    else
    {
        wprintf(L"No active document.\n");
    }

Error:
    pAssemblyDocument = NULL;
    pApplication = NULL;

    // Uninitialize COM.
    ::CoUninitialize();

    return 0;
}
Exemple #30
0
//*****************************************************************************
// Remove a RegMeta pointer from the loaded module list
//*****************************************************************************
BOOL LOADEDMODULES::RemoveModuleFromLoadedList(RegMeta * pRegMeta)
{
    BOOL  bRemoved = FALSE;     // Was this module removed from the cache?
    int   iFound = -1;          // Index at which it was found.
    ULONG cRef;                 // Ref count of the module.
    
    // Lock the cache for write, so that no other thread will find what this 
    //  thread is about to delete, and so that no other thread will delete
    //  what this thread is about to try to find.
    HRESULT hr = S_OK;
    
    IfFailGo(InitializeStatics());
    
    {
        LOCKWRITE();
    
        // Search for this module in list of loaded modules.
        int count = s_pLoadedModules->Count();
        for (int index = 0; index < count; index++)
        {
            if ((*s_pLoadedModules)[index] == pRegMeta)
            {   // found a match to remove
                iFound = index;
                break;
            }
        }
    
        // If the module is still in the cache, it hasn't been deleted yet.
        if (iFound >= 0)
        {
            // See if there are any external references left.
            cRef = pRegMeta->GetRefCount();

            // If the cRef that we got from the module is zero, it will stay that way,
            //  because no other thread can discover the module while this thread holds
            //  the lock.

            // OTOH, if the cRef is not zero, this thread can just return, because the
            //  other thread will eventually take the ref count to zero, and will then 
            //  come through here to clean up the module. And this thread must not 
            //  delete the module out from under other threads.

            // It is possible that the cRef is zero, yet another thread has a pointer that
            //  it discovered before this thread took the lock.  (And that thread has
            //  released the ref-counts.)  In such a case, this thread can still remove the 
            //  module from the cache, and tell the caller to delete it, because the
            //  other thread will wait on the lock, then discover that the module
            //  is not in the cache, and it won't try to delete the module.

            if (cRef != 0)
            {   // Some other thread snuck in and found the entry in the cache.
                return FALSE;
            }

            // No other thread owns the object.  Remove from cache, and tell caller
            //  that we're done with it.  (Caller will delete.)
            s_pLoadedModules->Delete(iFound);
            bRemoved = TRUE;

            // If the module is read-only, remove from hash.
            if (pRegMeta->IsReadOnly())
            {
                // There may have been multiple capitalizations pointing to the same entry.
                //  Find and remove all of them.
                for (ULONG ixHash = 0; ixHash < LOADEDMODULES_HASH_SIZE; ++ixHash)
                {
                    if (m_HashedModules[ixHash] == pRegMeta)
                        m_HashedModules[ixHash] = NULL;
                }
            }
        }
    }
    
ErrExit:
    return bRemoved;
}  // LOADEDMODULES::RemoveModuleFromLoadedList