diff options
Diffstat (limited to 'src/vm/mda.cpp')
-rw-r--r-- | src/vm/mda.cpp | 4017 |
1 files changed, 4017 insertions, 0 deletions
diff --git a/src/vm/mda.cpp b/src/vm/mda.cpp new file mode 100644 index 0000000000..77c26a993e --- /dev/null +++ b/src/vm/mda.cpp @@ -0,0 +1,4017 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + + +#include "common.h" +#include "eeconfig.h" +#include "eeconfigfactory.h" +#include "corhlpr.h" +#include <xmlparser.h> +#include <mscorcfg.h> +#include <holder.h> +#include <dbginterface.h> +#include "wrappers.h" +#include "mda.h" +#include "mdaassistants.h" +#include "sstring.h" +#include "util.hpp" +#include "debugdebugger.h" + +#ifdef MDA_SUPPORTED + +// +// MdaHashtable +// + +BOOL MdaLockOwner(LPVOID) { LIMITED_METHOD_CONTRACT; return TRUE; } + +BOOL IsJustMyCode(MethodDesc* pMethodDesc) +{ + CONTRACT(BOOL) + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACT_END; + + if (!ManagedDebuggingAssistants::IsManagedDebuggerAttached()) + return TRUE; + + BOOL bIsJMC = FALSE; + + EX_TRY + { + if (g_pDebugInterface && g_pDebugInterface->IsJMCMethod(pMethodDesc->GetModule(), pMethodDesc->GetMemberDef())) + bIsJMC = TRUE; + } + EX_CATCH + { + } + EX_END_CATCH(SwallowAllExceptions); + + RETURN bIsJMC; +} + + +// +// ManagedDebuggingAssistants +// + +const bool g_mdaAssistantIsSwitch[] = +{ +#define MDA_ASSISTANT_IS_SWITCH +#include "mdaschema.inl" +#undef MDA_ASSISTANT_IS_SWITCH + false +}; + +void ManagedDebuggingAssistants::Initialize() +{ + CONTRACT_VOID + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACT_END; + + EX_TRY + { + // + // Initialize + // + m_pSwitchActivationXml = NULL; + m_pMdaXmlIndustry = new MdaXmlIndustry(); + + MdaSchema::Initialize(); + + // + // Create AssistantSchema + // + m_pAssistantSchema = new MdaAssistantSchema(); + + // + // Create AssistantMsgSchema + // + m_pAssistantMsgSchema = new MdaAssistantMsgSchema(); + + // + // Create SchemaSchema + // + m_pSchemaSchema = new MdaSchemaSchema(); + + // + // InvalidConfigFile + // + g_mdaStaticHeap.m_mdaInvalidConfigFile.Enable(); + +#ifdef _DEBUG + StackSString sszValidateFramework(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MDAValidateFramework)); + if (!sszValidateFramework.IsEmpty() && sszValidateFramework.Equals(W("1"))) + DebugInitialize(); +#endif + } + EX_CATCH + { + // MDA State corrupted, unable to initialize, runtime still OK + } + EX_END_CATCH(SwallowAllExceptions); + + RETURN; +} + +MdaEnvironment::~MdaEnvironment() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (m_pStringFactory) + delete m_pStringFactory; + + if (m_pGroups) + delete m_pGroups; + + if (m_szMda) + delete m_szMda; +} + +MdaEnvironment::MdaEnvironment() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + m_bDisable = TRUE; + m_szMda = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_MDA); + m_pStringFactory = NULL; + m_pGroups = NULL; + + if (ManagedDebuggingAssistants::IsManagedDebuggerAttached()) + { + if (m_pStringFactory == NULL) + m_pStringFactory = new MdaFactory<StackSString>(); + + if (m_pGroups == NULL) + m_pGroups = new SArray<SString*>(); + + SString* pStr = m_pStringFactory->Create(); + pStr->Set(W("managedDebugger")); + m_pGroups->Append(pStr); + m_bDisable = FALSE; + } + + if (ManagedDebuggingAssistants::IsUnmanagedDebuggerAttached()) + { + if (m_pStringFactory == NULL) + m_pStringFactory = new MdaFactory<StackSString>(); + + if (m_pGroups == NULL) + m_pGroups = new SArray<SString*>(); + + SString* pStr = m_pStringFactory->Create(); + pStr->Set(W("unmanagedDebugger")); + m_pGroups->Append(pStr); + m_bDisable = FALSE; + } + + if (m_szMda) + { + if (m_pStringFactory == NULL) + m_pStringFactory = new MdaFactory<StackSString>(); + + if (m_pGroups == NULL) + m_pGroups = new SArray<SString*>(); + + StackSString sszMda(m_szMda); + SString::Iterator s = sszMda.Begin(); + SString::Iterator e = s; + + while (true) + { + if (!sszMda.Find(e, W(';'))) + e = sszMda.End(); + SString* psszGroup = m_pStringFactory->Create(); + psszGroup->Set(sszMda, s, e); + + if (psszGroup->Equals(W("0"))) + { + m_pGroups->Clear(); + m_bDisable = TRUE; + } + else + { + m_pGroups->Append(psszGroup); + + m_bDisable = FALSE; + } + + if (e == sszMda.End()) + break; + s = ++e; + } + } + + if (m_bDisable == FALSE) + { + // If we get here, m_pStringFactory should already have been created. + _ASSERTE(m_pStringFactory != NULL); + + WCHAR szExe[_MAX_PATH]; + if (!WszGetModuleFileName(NULL, szExe, _MAX_PATH)) + return; + + // Construct file name of the config file + m_psszConfigFile = m_pStringFactory->Create(); + m_psszConfigFile->Set(szExe); + m_psszConfigFile->Append(W(".config")); + + // Construct file name of mda config file + m_psszMdaConfigFile = m_pStringFactory->Create(); + m_psszMdaConfigFile->Set(szExe); + m_psszMdaConfigFile->Append(W(".mda.config")); + } +} + +void ManagedDebuggingAssistants::EEStartupActivation() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + // + // Read environment variable, then registry settings + // + MdaEnvironment env; + + if (env.IsDisabled()) + return; + + AllocateManagedDebuggingAssistants(); + + // + // ConfigFile Activation + // + g_mdaStaticHeap.m_pMda->EnvironmentActivation(&env); +} + +#ifdef _DEBUG +void ManagedDebuggingAssistants::DebugInitialize() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + SO_INTOLERANT; + MODE_ANY; + } + CONTRACTL_END; + + // + // Validate MDA output on Debug builds + // + m_bValidateOutput = TRUE; + + // + // XmlValidationError + // + g_mdaStaticHeap.m_mdaXmlValidationError.Enable(); + + MdaSchema::ValidationResult validationResult; + + // + // Validate SchemaScheam + // + MdaXmlElement* pXmlSchemaSchema = m_pSchemaSchema->ToXml(m_pMdaXmlIndustry); + if (m_pSchemaSchema->Validate(pXmlSchemaSchema, &validationResult)->ValidationFailed()) + { + MDA_TRIGGER_ASSISTANT(XmlValidationError, ReportError(&validationResult)); + UNREACHABLE(); + } + + // + // Validate AssistantSchema + // + MdaXmlElement* pXmlAssistantSchema = m_pAssistantSchema->ToXml(m_pMdaXmlIndustry); + if (m_pSchemaSchema->Validate(pXmlAssistantSchema, &validationResult)->ValidationFailed()) + { + MDA_TRIGGER_ASSISTANT(XmlValidationError, ReportError(&validationResult)); + ASSERT(!W("You're modifications to MdaAssistantSchema for assistant input don't conform to XSD")); + } + + // + // Validate AssistantMsgSchema + // + MdaXmlElement* pXmlAssistantMsgSchema = m_pAssistantMsgSchema->ToXml(m_pMdaXmlIndustry); + if (m_pSchemaSchema->Validate(pXmlAssistantMsgSchema, &validationResult)->ValidationFailed()) + { + MDA_TRIGGER_ASSISTANT(XmlValidationError, ReportError(&validationResult)); + ASSERT(!W("You're modifications to MdaAssistantSchema for assistant output don't conform to XSD")); + } +} +#endif + +void ManagedDebuggingAssistants::ConfigFileActivation(LPCWSTR szConfigFile, MdaXmlIndustry* pXmlIndustry, MdaHashtable<MdaXmlElement*>* pMdaXmlPairs) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + // Parse + MdaSchema::ValidationResult validationResult; + MdaXmlElement* pMdaConfig = MdaConfigFactory::ParseXmlStream(pXmlIndustry, szConfigFile); + if (!pMdaConfig) + return; + + // Validate + if (m_pAssistantSchema->Validate(pMdaConfig, &validationResult)->ValidationFailed()) + { + MDA_TRIGGER_ASSISTANT(InvalidConfigFile, ReportError(MdaElemDef(MdaConfig))); + g_mdaStaticHeap.DisableAll(); + return; + } + + // Activate + InlineSArray<MdaXmlElement*, MdaElemDef(Max)> xmlMdaConfigs; + MdaXPath::FindElements(pMdaConfig, W("/mdaConfig/assistants/*"), &xmlMdaConfigs); + for(COUNT_T i = 0; i < xmlMdaConfigs.GetCount(); i ++) + { + MdaXmlElement* pXmlMdaConfig = xmlMdaConfigs[i]; + if (pXmlMdaConfig->GetAttribute(MdaAttrDecl(Enable))->GetValueAsBool()) + { + pMdaXmlPairs->Set(pXmlMdaConfig->GetName(), xmlMdaConfigs[i]); + } + else + { + if (pMdaXmlPairs->HasKey(pXmlMdaConfig->GetName())) + pMdaXmlPairs->DeleteValue(pXmlMdaConfig->GetName()); + } + } +} + +MdaXmlElement* ManagedDebuggingAssistants::GetSwitchActivationXml(MdaElemDeclDef mda) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (g_mdaAssistantIsSwitch[mda]) + { + MdaXmlElement* pXml = m_pMdaXmlIndustry->CreateElement()->SetDeclDef(mda); + pXml->AddAttributeBool(MdaAttrDecl(Enable), TRUE); + return pXml; + } + else + { + if (!m_pSwitchActivationXml) + { + MdaXmlElement* pXmlMdaConfig = m_pMdaXmlIndustry->CreateElement()->SetDeclDef(MdaElemDef(MdaConfig)); + m_pSwitchActivationXml = pXmlMdaConfig->AddChild(MdaElemDecl(Assistants)); + + for (COUNT_T i = 0; i < MdaElemDef(AssistantMax); i ++) + m_pSwitchActivationXml->AddChild((MdaElemDeclDef)i); + + MdaSchema::ValidationResult validationResult; + + // Validating the schema has the side-effect of initializing the default XML attributes + if (m_pAssistantSchema->Validate(pXmlMdaConfig, &validationResult)->ValidationFailed()) + ASSERT(!W("MDA Assistant must allow <Assistant /> form.")); + } + + return m_pSwitchActivationXml->GetChild(mda); + } +} + +void ManagedDebuggingAssistants::ActivateGroup(LPCWSTR groupName, SArray<MdaElemDeclDef>* pGroupMdaXmlParis, MdaHashtable<MdaXmlElement*>* pActivationMdaXmlPairs) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + StackSString sszGroupName(groupName); + BOOL bIsManagedDebuggerSet = sszGroupName.EqualsCaseInsensitive(W("managedDebugger")); + + SArray<MdaElemDeclDef>& groupMdaXmlParis = *pGroupMdaXmlParis; + + for (COUNT_T i = 0; i < groupMdaXmlParis.GetCount(); i++) + { + MdaElemDeclDef mda = groupMdaXmlParis[i]; + MdaXmlElement* pSwitchActivationXml = GetSwitchActivationXml(mda); + + PREFIX_ASSUME(pSwitchActivationXml != NULL); + + pSwitchActivationXml->AddAttributeBool(MdaAttrDecl(SuppressDialog), bIsManagedDebuggerSet); + + pActivationMdaXmlPairs->Set(MdaSchema::g_arElementNames[mda], pSwitchActivationXml); + } +} + +LPCWSTR ToLowerFirstChar(LPCWSTR name, MdaFactory<SString>* pSstringFactory) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + ASSERT(*name >= 'A' && *name <= 'Z'); + + SString* pOutput = pSstringFactory->Create(); + pOutput->Clear(); + pOutput->Append(*name - W('A') + W('a')); + pOutput->Append(&name[1]); + return pOutput->GetUnicode(); +} + +void ManagedDebuggingAssistants::EnvironmentActivation(MdaEnvironment* pEnvironment) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + if (pEnvironment->GetActivationMechanisms().GetCount() == 0) + return; + + MdaFactory<StackSArray<MdaElemDeclDef> > arrayFactory; + MdaFactory<SString> sstringFactory; + MdaHashtable<MdaXmlElement*> mdaXmlPairs; + + // Activate + SArray<SString*>& aActivationMechanisms = pEnvironment->GetActivationMechanisms(); + SArray<MdaElemDeclDef>* pGroup = NULL; + StackSArray<SArray<MdaElemDeclDef>* > aGroups; + +#define MDA_DEFINE_GROUPS +#include "mdaschema.inl" +#undef MDA_DEFINE_GROUPS + + // Match COMPlus_MDA env var to group + for (COUNT_T i = 0; i < aActivationMechanisms.GetCount(); i++) + { + SString& sszActivationMechanism = *aActivationMechanisms[i]; + + if (sszActivationMechanism.EqualsCaseInsensitive(W("ConfigFile")) || sszActivationMechanism.EqualsCaseInsensitive(W("1"))) + { + ConfigFileActivation(pEnvironment->GetMdaConfigFile(), m_pMdaXmlIndustry, &mdaXmlPairs); + } + else + { + COUNT_T cGroup = 0; + +#define MDA_ACTIVATE_GROUPS +#include "mdaschema.inl" +#undef MDA_ACTIVATE_GROUPS + +#define MDA_ACTIVATE_SINGLTON_GROUPS +#include "mdaschema.inl" +#undef MDA_ACTIVATE_SINGLTON_GROUPS + + } + } + + if (mdaXmlPairs.GetCount() == 0) + return; + + // Create + MdaXmlElement* pXmlAssistant = NULL; + +#define MDA_ASSISTANT_CREATION +#include "mdaschema.inl" +#undef MDA_ASSISTANT_CREATION +} + +typedef enum +{ + MDA_MSGBOX_NONE = 0, + MDA_MSGBOX_RETRY = 4, + MDA_MSGBOX_CANCLE = 2, +} MsgBoxResult; + +BOOL ManagedDebuggingAssistants::IsUnmanagedDebuggerAttached() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (IsDebuggerPresent()) + return TRUE; + + return FALSE; +} + +BOOL ManagedDebuggingAssistants::IsManagedDebuggerAttached() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + +#if DEBUGGING_SUPPORTED + if (CORDebuggerAttached()) + return TRUE; +#endif + + return FALSE; +} + +BOOL ManagedDebuggingAssistants::IsDebuggerAttached() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + return IsUnmanagedDebuggerAttached() || IsManagedDebuggerAttached(); +} + +MdaXmlElement* ManagedDebuggingAssistants::GetRootElement(MdaXmlElement* pMdaXmlRoot) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + pMdaXmlRoot->SetDeclDef(MdaElemDef(Msg)); + pMdaXmlRoot->AddAttributeSz(MdaAttrDecl(Xmlns), MDA_TARGET_NAMESPACE)->SetNs(W("mda")); + return pMdaXmlRoot; +} + + + +// +// MdaXmlMessage +// +BOOL IsFormatChar(WCHAR c) { LIMITED_METHOD_CONTRACT; return (c == W('\\') || c == W('!') || c == W('+') || c == W('.') || c == W(':') || c == W('-')); } + +// Logic copied from /fx/src/Xml/System/Xml/Core/XmlRawTextWriterGenerator.cxx::WriteAttributeTextBlock +SString& MdaXmlEscape(SString& sszBuffer, const SString& sszXml, BOOL bEscapeComment = FALSE) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + sszBuffer.Clear(); + + SString::CIterator itr = sszXml.Begin(); + SString::CIterator end = sszXml.End(); + + while (itr != end) + { + WCHAR c = *itr; + + switch(c) + { + case W('-'): + if (*(itr+1) == W('-') && bEscapeComment) + sszBuffer.Append(W("- ")); + else + sszBuffer.Append(W("-")); + break; + case W('&'): + sszBuffer.Append(W("&")); + break; + case W('<'): + sszBuffer.Append(W("<")); + break; + case W('>'): + sszBuffer.Append(W(">")); + break; + case W('"'): + sszBuffer.Append(W(""e;")); + break; + default: + sszBuffer.Append(c); + } + + itr++; + } + + return sszBuffer; +} + +SString* WrapString(SString& buffer, SString& sszString, SCOUNT_T cWidth, SCOUNT_T cIndent = 0, SCOUNT_T cPostIndent = 0) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + StackSString sszEscapedString; + MdaXmlEscape(sszEscapedString, sszString, TRUE); + + StackSString sszIndent; + for (SCOUNT_T i = 0; i < cIndent; i ++) + sszIndent.Append(W(" ")); + + StackSString sszPostIndent; + for (SCOUNT_T i = 0; i < cPostIndent; i ++) + sszPostIndent.Append(W(" ")); + + buffer.Append(sszIndent); + + SString::CIterator itr = sszEscapedString.Begin(); + SString::CIterator lineStart = sszEscapedString.Begin(); + SString::CIterator lineEnd = sszEscapedString.Begin(); + SString::CIterator lastFormatChar = sszEscapedString.Begin(); + SString::CIterator end = sszEscapedString.End(); + + while (itr != end) + { + if (*itr == W(' ')) + lineEnd = itr; + + // Keep track of reasonable breaks in member and file names... + if (IsFormatChar(*itr) && itr - lineStart < cWidth) + lastFormatChar = itr; + + if (itr - lineStart >= cWidth || *itr == W('\n')) + { + if (*itr == W('\n')) + lineEnd = itr; + + // If we didn't find a space or wrapping at found space wraps less than 3/5 of the line... + else if (lineEnd == end || itr - lineEnd > cWidth * 3 / 5) + { + // ...then if we found a format char, start the wrap there... + if (lastFormatChar != end) + lineEnd = lastFormatChar + 1; + // ...else just do a simple wrap... + else + lineEnd = itr; + } + + SString sszLine(sszEscapedString, lineStart, lineEnd); + buffer.Append(sszLine); + buffer.Append(sszPostIndent); + buffer.Append(W("\n")); + buffer.Append(sszIndent); + + lineStart = lineEnd; + + // If we wrapped on a space or a return than skip over that character as we already replaced it with a \n. + if (*lineEnd == W(' ') || *lineEnd == W('\n')) + lineStart++; + + lineEnd = end; + lastFormatChar = end; + } + + itr++; + } + + SString sszLine(sszEscapedString, lineStart, itr); + buffer.Append(sszLine); + + return &buffer; +} + +LPCWSTR ToUpperFirstChar(SString& buffer, LPCWSTR name) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + ASSERT(*name >= 'a' && *name <= 'z'); + + buffer.Clear(); + buffer.Append(*name - W('a') + W('A')); + buffer.Append(&name[1]); + return buffer.GetUnicode(); +} + +MdaXmlMessage::MdaXmlMessage(MdaAssistant* pAssistant, BOOL bBreak, MdaXmlElement** ppMdaXmlRoot) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + PRECONDITION(CheckPointer(g_mdaStaticHeap.m_pMda)); + } + CONTRACTL_END; + + m_pMdaAssistant = pAssistant; + m_bBreak = (pAssistant->GetSuppressDialog()) ? FALSE : bBreak; + m_pMdaXmlRoot = g_mdaStaticHeap.m_pMda->GetRootElement(m_mdaXmlIndustry.CreateElement()); + *ppMdaXmlRoot = m_pAssistantXmlRoot = pAssistant->GetRootElement(m_mdaXmlIndustry.CreateElement(), bBreak); +} + +MdaXmlMessage::MdaXmlMessage(MdaXmlElement** ppMdaXmlRoot) : m_bBreak(FALSE) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + PRECONDITION(CheckPointer(g_mdaStaticHeap.m_pMda)); + } + CONTRACTL_END; + + *ppMdaXmlRoot = m_pMdaXmlRoot = g_mdaStaticHeap.m_pMda->GetRootElement(m_mdaXmlIndustry.CreateElement()); +} + +BOOL MdaXmlMessage::ShouldLogToManagedDebugger() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + BOOL bUnmanagedDebuggerAttached = FALSE; + BOOL bManagedDebuggerAttached = FALSE; + BOOL bManagedDebugLoggingEnabled = FALSE; + + bUnmanagedDebuggerAttached = IsUnmanagedDebuggerAttached(); + +#if DEBUGGING_SUPPORTED + bManagedDebuggerAttached = IsManagedDebuggerAttached(); + bManagedDebugLoggingEnabled = (g_pDebugInterface && g_pDebugInterface->IsLoggingEnabled()); +#endif + + return (!bUnmanagedDebuggerAttached && bManagedDebuggerAttached && bManagedDebugLoggingEnabled); +} + +// Send an event for this MDA. +void MdaXmlMessage::SendEvent() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + if (IsHostRegisteredForEvent(Event_MDAFired)) + { + // A host is registered for the MDA fired event so let's start by notifying the + // debugger is on is attached. + if (IsManagedDebuggerAttached() || IsUnmanagedDebuggerAttached()) + { + SendDebugEvent(); + } + + // Now that the debugger has been notified and continued, let's notify the host + // so it can take any action it deems neccessary based on the MDA that fired. + SendHostEvent(); + } + else + { + // We aren't hosted or no host registered for the MDA fired event so let's simply + // send the MDA to the debubber. Note that as opposed to the hosted case, we + // will force a JIT attach if no debugger is present. + SendDebugEvent(); + } +} + +// Send an event for this MDA. +void MdaXmlMessage::SendHostEvent() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + MDAInfo info; + SString strStackTrace; + + EX_TRY + { + // Retrieve the textual representation of the managed stack trace and add it to + // the MDA information we give the host. + GetManagedStackTraceString(TRUE, strStackTrace); + } + EX_CATCH + { + // We failed to get the stack trace string. This isn't fatal, we will simply not be + // able to provide this information as part of the notification. + } + EX_END_CATCH(SwallowAllExceptions); + + // Set up the information and invoke the host to process the MDA fired event. + info.lpMDACaption = m_pMdaAssistant->GetName(); + info.lpStackTrace = strStackTrace; + info.lpMDAMessage = m_localizedMessage; + ProcessEventForHost(Event_MDAFired, &info); + + // If the host initiated a thread abort, we want to raise it immediatly to + // prevent any further code inside the VM from running and potentially + // crashing the process. + Thread *pThread = GetThread(); + TESTHOOKCALL(AppDomainCanBeUnloaded(pThread->GetDomain()->GetId().m_dwId,FALSE)); + + if (pThread && pThread->IsAbortInitiated()) + pThread->HandleThreadAbort(TRUE); +} + +// Send a managed debug event for this MDA. +// This will block until the debugger continues us. This means the debugger could to things like run callstacks +// and change debuggee state. +void MdaXmlMessage::SendDebugEvent() +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + PRECONDITION(CheckPointer(g_mdaStaticHeap.m_pMda)); + } + CONTRACTL_END; + + // Simple check to avoid getting XML string if we're not going to actually use it. + if (!IsManagedDebuggerAttached() && !IsUnmanagedDebuggerAttached() && !m_bBreak) + { + return; + } + + EX_TRY + { + StackSString sszXml; + LPCWSTR ns = NULL; + + MdaSchema * pSchema = g_mdaStaticHeap.m_pMda->m_pAssistantSchema; + ns = pSchema->SetRootAttributes(m_pMdaXmlRoot); + m_pMdaXmlRoot->ToXml(&sszXml, ns); + + // For managed + interop cases, send a managed debug event. + // If m_bBreak is true and no unmanaged debugger is attached trigger a jit-attach. + if (IsManagedDebuggerAttached() || (m_bBreak && !IsUnmanagedDebuggerAttached())) + { + // Get MDA name (this is the type) + StackSString sszMdaName; + ToUpperFirstChar(sszMdaName, m_pMdaAssistant->GetName()); + // SendMDANotification needs to be called in preemptive GC mode. + GCX_PREEMP(); + + // This will do two things: + // 1. If a managed debugger is attached, it will send the managed debug event for the MDA. + // 2. If it's a m_bBreak, we'll try to do a managed jit-attach. + // This blocks until continued. Since we're not slipping, we don't need the MDA_FLAG_SLIP flag. + g_pDebugInterface->SendMDANotification( + GetThread(), + &sszMdaName, + &m_localizedMessage, + &sszXml, + ((CorDebugMDAFlags) 0 ), + RunningInteractive() ? m_bBreak : FALSE); + } + + if (IsUnmanagedDebuggerAttached() && !IsManagedDebuggerAttached()) + { + // For native case, sent native debug event for logging. + WszOutputDebugString(sszXml.GetUnicode()); + + if (m_bBreak) + RetailBreak(); + } + } + EX_CATCH + { + // No global MDA state modified in TRY + } + EX_END_CATCH(SwallowAllExceptions); +} + +void MdaXmlMessage::SendMessagef(int resourceID, ...) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + StackSString sszResourcef; + sszResourcef.LoadResource(CCompRC::DesktopCLR, resourceID ); + ASSERT(!sszResourcef.IsEmpty()); + + va_list argItr; + va_start(argItr, resourceID); + m_localizedMessage.PVPrintf(sszResourcef, argItr); + va_end(argItr); + + SendMessage(); +} + + +void MdaXmlMessage::SendMessage(int resourceID) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + SendMessagef(resourceID); +} + +void MdaXmlMessage::SendMessage(LPCWSTR szMessage) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + m_localizedMessage.Set(szMessage); + + SendMessage(); +} + +void MdaXmlMessage::SendMessage() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + PRECONDITION(CheckPointer(g_mdaStaticHeap.m_pMda)); + } + CONTRACTL_END; + +#if _DEBUG + if (g_mdaStaticHeap.m_pMda->m_bValidateOutput) + { + MdaSchema::ValidationResult validationResult; + if (g_mdaStaticHeap.m_pMda->m_pAssistantMsgSchema->Validate(m_pAssistantXmlRoot, &validationResult)->ValidationFailed()) + { + MDA_TRIGGER_ASSISTANT(XmlValidationError, ReportError(&validationResult)); + ASSERT(W("Your MDA assistant's output did not match its output schema.")); + } + } +#endif + + if (!m_localizedMessage.IsEmpty()) + { + StackSString sszComment(m_localizedMessage); + StackSString sszWrappedComment(W("\n")); + WrapString(sszWrappedComment, sszComment, 80, 7); + sszWrappedComment.Append(W("\n ")); + m_pMdaXmlRoot->AddChildComment(sszWrappedComment.GetUnicode()); + } + + m_pMdaXmlRoot->AddChild(m_pAssistantXmlRoot); + + // Send applicable debug event (managed, native, interop) for this MDA. + // If this is a severe probe, it may trigger a jit-attach + SendEvent(); +} + + +// +// MdaXPath::FindXXX +// + +void MdaXPath::Find(SArray<MdaXPathVariable>& args, SString* pWildCard, va_list argItr) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + for (COUNT_T i = 0; i < GetArgCount(); i ++) + { + XPathVarType varType = m_argTypes[i]; + + if (varType == XPathVarElemDeclDef) + args[i].m_u.m_elemDeclDef = va_arg(argItr, MdaElemDeclDef); + + else if (varType == XPathVarAttrDeclDef) + args[i].m_u.m_attrDeclDef = va_arg(argItr, MdaAttrDeclDef); + + else if (varType == XPathVarAttrBool) + args[i].m_u.m_bool = va_arg(argItr, BOOL); + + else if (varType == XPathVarAttrINT32) + args[i].m_u.m_int32 = va_arg(argItr, INT32); + + else if (varType == XPathVarAttrSString) + { + SString* pSString = va_arg(argItr, SString*); + ASSERT(CheckPointer(pSString, NULL_OK)); + if (!pSString) + pSString = pWildCard; + args[i].m_u.m_pSstr = pSString; + } + + else { UNREACHABLE(); } + } +} + +MdaXmlElement* MdaXPath::FindElement(MdaXmlElement* pRoot, ...) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (!pRoot) + return NULL; + + va_list argItr; + va_start(argItr, pRoot); + + SString wildCard; + InlineSArray<MdaXPathVariable, 20> args; + Find(args, &wildCard, argItr); + + MdaXPathResult result(&args); + m_pCompiledQuery->Run(pRoot, &result); + + va_end(argItr); + return result.GetXmlElement(); +} + +MdaXmlAttribute* MdaXPath::FindAttribute(MdaXmlElement* pRoot, ...) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (!pRoot) + return NULL; + + va_list argItr; + va_start(argItr, pRoot); + + SString wildCard; + InlineSArray<MdaXPathVariable, 20> args; + Find(args, &wildCard, argItr); + + MdaXPathResult result(&args); + m_pCompiledQuery->Run(pRoot, &result); + + va_end(argItr); + return result.GetXmlAttribute(); +} + +SArray<MdaXmlElement*>* MdaXPath::FindElements(MdaXmlElement* pRoot, SArray<MdaXmlElement*>* pResult, ...) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (!pRoot) + return NULL; + + va_list argItr; + va_start(argItr, pResult); + + SString wildCard; + InlineSArray<MdaXPathVariable, 20> args; + Find(args, &wildCard, argItr); + + MdaXPathResult result(pResult, &args); + m_pCompiledQuery->Run(pRoot, &result); + + va_end(argItr); + return pResult; +} + +SArray<MdaXmlAttribute*>* MdaXPath::FindAttributes(MdaXmlElement* pRoot, SArray<MdaXmlAttribute*>* pResult, ...) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (!pRoot) + return NULL; + + va_list argItr; + va_start(argItr, pResult); + + SString wildCard; + InlineSArray<MdaXPathVariable, 20> args; + Find(args, &wildCard, argItr); + + MdaXPathResult result(pResult, &args); + m_pCompiledQuery->Run(pRoot, &result); + + va_end(argItr); + return pResult; +} + + +// +// MdaXPath::MdaXPathCompiler -- Lexifier +// + +#define ISWHITE(ch) (ch == W(' ') || ch == W('\t') || ch == W('\n')) +#define ISRESERVED(ch) (wcschr(W("./()[]&|=@*?':"), ch) != NULL) +#define ISMDAID(ch) (!ISWHITE(ch) && !ISRESERVED(ch)) + +MdaXPath::MdaXPathCompiler::MdaXPathTokens MdaXPath::MdaXPathCompiler::LexAToken() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (*m_itr == W('\0')) + return MdaXPathEnd; + + if (ISWHITE(*m_itr)) + { + m_itr++; + return LexAToken(); + } + + if (ISMDAID(*m_itr)) + { + m_identifier.Clear(); + + do + { + m_identifier.Append(*m_itr); + m_itr++; + } + while(ISMDAID(*m_itr)); + + m_identifier.Append(W("\0")); + return MdaXPathIdentifier; + } + + if (*m_itr == W('\'')) + { + m_identifier.Clear(); + + m_itr++; + + while(*m_itr != W('\'')) + { + m_identifier.Append(*m_itr); + m_itr++; + } + + m_identifier.Append(W("\0")); + + m_itr++; + return MdaXPathQuotedString; + } + + WCHAR c = *m_itr; + m_itr++; + switch(c) + { + case W('.'): return MdaXPathDot; + case W('/'): return MdaXPathSlash; + case W('('): return MdaXPathOpenParen; + case W(')'): return MdaXPathCloseParen; + case W('['): return MdaXPathOpenSqBracket; + case W(']'): return MdaXPathCloseSqBracket; + case W('&'): return MdaXPathLogicalAnd; + case W('|'): return MdaXPathLogicalOr; + case W('='): return MdaXPathEquals; + case W('@'): return MdaXPathAtSign; + case W('*'): return MdaXPathAstrix; + case W('?'): return MdaXPathQMark; + } + + UNREACHABLE(); +} + + +// +// MdaXPath::MdaXPathCompiler -- Parser +// + +// XPATH +// '/' ELEMENT_EXPR end +// '/' ELEMENT_EXPR XPATH +// '/' ATTRIBUTE end +MdaXPath::MdaXPathBase* MdaXPath::MdaXPathCompiler::XPATH() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + PRECONDITION(TokenIs(MdaXPathXPATH)); + + MdaXPathElement* pElementExpr = NULL; + + NextToken(); + if (TokenIs(MdaXPathELEMENT_EXPR)) + pElementExpr = ELEMENT_EXPR(); + + else if (TokenIs(MdaXPathATTRIBUTE)) + { + MdaXPathAttribute* pAttr = ATTRIBUTE(); + pAttr->MarkAsTarget(); + NextToken(); + ASSERT(TokenIs(MdaXPathEnd)); + return pAttr; + } + + else { UNREACHABLE(); } + + + if (TokenIs(MdaXPathEnd)) + return pElementExpr->MarkAsTarget(); + + else if (TokenIs(MdaXPathXPATH)) + return pElementExpr->SetChild(XPATH()); + + else { UNREACHABLE(); } +} + +// ATTRIBUTE +// '@' id +// '@' '?' +MdaXPath::MdaXPathAttribute* MdaXPath::MdaXPathCompiler::ATTRIBUTE() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + PRECONDITION(TokenIs(MdaXPathATTRIBUTE)); + + MdaXPathAttribute* pAttr = NULL; + + NextToken(); + if (TokenIs(MdaXPathQMark)) + { + pAttr = m_pXPath->m_attrFactory.Create()->SetName(++m_pXPath->m_cArgs); + *m_pXPath->m_argTypes.Append() = XPathVarAttrDeclDef; + } + + else if (TokenIs(MdaXPathIdentifier)) + { + pAttr = m_pXPath->m_attrFactory.Create()->SetName(MdaSchema::GetAttributeType(GetIdentifier())); + } + + else { UNREACHABLE(); } + + NextToken(); + return pAttr; +} + +// ELEMENT_EXPR +// ELEMENT '[' FILTER_EXPR ']' +// ELEMENT +MdaXPath::MdaXPathElement* MdaXPath::MdaXPathCompiler::ELEMENT_EXPR() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + PRECONDITION(TokenIs(MdaXPathELEMENT_EXPR)); + + MdaXPathElement* pElement = ELEMENT(); + + if (TokenIs(MdaXPathOpenSqBracket)) + { + NextToken(); + pElement->SetQualifier(FILTER_EXPR()); + ASSERT(TokenIs(MdaXPathCloseSqBracket)); + + NextToken(); + } + + return pElement; +} + +// FILTER_EXPR +// FILTER +// '(' FILTER ')' +// FILTER '&' FILTER +// FILTER '|' FILTER +MdaXPath::MdaXPathBase* MdaXPath::MdaXPathCompiler::FILTER_EXPR() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + PRECONDITION(TokenIs(MdaXPathFILTER_EXPR)); + + // '(' FILTER ')' + if (TokenIs(MdaXPathOpenParen)) + { + MdaXPath::MdaXPathBase* pFilter = FILTER(); + ASSERT(TokenIs(MdaXPathCloseParen)); + + NextToken(); + return pFilter; + } + + if (TokenIs(MdaXPathFILTER)) + { + MdaXPath::MdaXPathBase* pFilter = FILTER(); + + // FILTER '&' FILTER + if (TokenIs(MdaXPathLogicalAnd)) + { + NextToken(); + return m_pXPath->m_logicalOpFactory.Create()->Initialize(TRUE, pFilter, FILTER()); + } + + // FILTER '|' FILTER + if (TokenIs(MdaXPathLogicalOr)) + { + NextToken(); + return m_pXPath->m_logicalOpFactory.Create()->Initialize(FALSE, pFilter, FILTER()); + } + + // FILTER + return pFilter; + } + + UNREACHABLE(); +} + +// FILTER +// ELEMENT_EXPR +// ATTRIBUTE_FILTER +// ELEMENT_EXPR ATTRIBUTE_FILTER +MdaXPath::MdaXPathBase* MdaXPath::MdaXPathCompiler::FILTER() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + PRECONDITION(TokenIs(MdaXPathFILTER)); + + if (TokenIs(MdaXPathELEMENT_EXPR)) + { + MdaXPathElement* pElementExpr = ELEMENT_EXPR(); + + if (TokenIs(MdaXPathATTRIBUTE_FILTER)) + pElementExpr->SetQualifier(ATTRIBUTE_FILTER()); + + return pElementExpr; + } + + if (TokenIs(MdaXPathATTRIBUTE_FILTER)) + return ATTRIBUTE_FILTER(); + + UNREACHABLE(); +} + +// ELEMENT +// id +// '*' +// '?' +MdaXPath::MdaXPathElement* MdaXPath::MdaXPathCompiler::ELEMENT() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + PRECONDITION(TokenIs(MdaXPathELEMENT)); + + MdaXPathElement* pElement = m_pXPath->m_elementFactory.Create(); + + if (TokenIs(MdaXPathAstrix)) + pElement->Initialize(); + + else if (TokenIs(MdaXPathIdentifier)) + pElement->Initialize(MdaSchema::GetElementType(GetIdentifier())); + + else if (TokenIs(MdaXPathQMark)) + { + pElement->Initialize(++m_pXPath->m_cArgs); + *m_pXPath->m_argTypes.Append() = XPathVarElemDeclDef; + } + + else { UNREACHABLE(); } + + NextToken(); + return pElement; +} + +// ATTRIBUTE_FILTER(); +// ATTRIBUTE +// ATTRIBUTE '=' ''' id ''' +// ATTRIBUTE '=' '?' +MdaXPath::MdaXPathAttribute* MdaXPath::MdaXPathCompiler::ATTRIBUTE_FILTER() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + PRECONDITION(TokenIs(MdaXPathATTRIBUTE_FILTER)); + + MdaXPathAttribute* pAttr = ATTRIBUTE(); + + if (TokenIs(MdaXPathEquals)) + { + NextToken(); + + if (TokenIs(MdaXPathQuotedString)) + { + NextToken(); + pAttr->SetValue(GetIdentifier()); + + NextToken(); + ASSERT(TokenIs(MdaXPathQuotedString)); + } + else if (TokenIs(MdaXPathQMark)) + { + pAttr->SetValue(++m_pXPath->m_cArgs); + *m_pXPath->m_argTypes.Append() = XPathVarAttrSString; + } + else { UNREACHABLE(); } + } + + NextToken(); + return pAttr; +} + + +// +// MdaXPath::Elements::Run() -- The search engine +// + +BOOL MdaXPath::MdaXPathElement::Run(MdaXmlElement* pElement, MdaXPathResult* pResult) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + BOOL bAnyPass = FALSE; + if (pResult->IsRoot()) + { + bAnyPass |= RunOnChild(pElement, pResult); + } + else + { + SArray<MdaXmlElement*>& children = pElement->GetChildren(); + + for (UINT32 i = 0; i < children.GetCount(); i ++) + { + bAnyPass |= RunOnChild(children[i], pResult); + } + } + + return bAnyPass; +} + +BOOL MdaXPath::MdaXPathElement::RunOnChild(MdaXmlElement* pElement, MdaXPathResult* pResult) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + MdaElemDeclDef name = m_nameArg == NOT_VARIABLE ? m_name : pResult->GetArgs()[m_nameArg].m_u.m_elemDeclDef; + + if (name != MdaElemUndefined && name != pElement->GetDeclDef()) + return FALSE; + + if (m_pQualifier && !m_pQualifier->Run(pElement, pResult)) + return FALSE; + + if (m_pChild && !m_pChild->Run(pElement, pResult)) + return FALSE; + + if (m_bIsTarget) + { + ASSERT(!m_pChild); + pResult->AddMatch(pElement); + } + + return TRUE; +} + +BOOL MdaXPath::MdaXPathAttribute::Run(MdaXmlElement* pElement, MdaXPathResult* pResult) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + MdaAttrDeclDef name = m_nameArg == NOT_VARIABLE ? m_name : pResult->GetArgs()[m_nameArg].m_u.m_attrDeclDef; + SString& value = m_valueArg == NOT_VARIABLE ? m_value : *pResult->GetArgs()[m_valueArg].m_u.m_pSstr; + + MdaXmlAttribute* pAttr = pElement->GetAttribute(name); + if (!pAttr) + return FALSE; + + LPCWSTR szAttrValue = pAttr->GetValue(); + if (!value.IsEmpty() && *szAttrValue != W('*') && !value.Equals(szAttrValue)) + return FALSE; + + if (m_bIsTarget) + pResult->AddMatch(pElement); + + return TRUE; +} + +BOOL MdaXPath::MdaXPathLogicalOp::Run(MdaXmlElement* pParent, MdaXPathResult* pResult) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (m_andOp) + return m_pLhs->Run(pParent, pResult) && m_pRhs->Run(pParent, pResult); + + return m_pLhs->Run(pParent, pResult) || m_pRhs->Run(pParent, pResult); +} + + +// +// MdaSchema +// + +MdaHashtable<MdaElemDeclDef>* MdaSchema::g_pHtElementType; +MdaHashtable<MdaAttrDeclDef>* MdaSchema::g_pHtAttributeType; +LPCWSTR MdaSchema::g_arElementNames[MdaElemEnd]; +LPCWSTR MdaSchema::g_arAttributeNames[MdaAttrEnd]; +MdaFactory<SString>* MdaSchema::g_pSstringFactory; +MdaElemDeclDef MdaSchema::MdaSchemaTypeToElemDef[MdaSchema::MdaSchemaTypeEnd]; +MdaSchema::MdaSchemaMetaType MdaSchema::MdaSchemaTypeToMetaType[MdaSchema::MdaSchemaTypeEnd]; + +LPCWSTR MdaSchema::ToLowerFirstChar(LPCWSTR name) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + return ::ToLowerFirstChar(name, g_pSstringFactory); +} + +void MdaSchema::Initialize() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + g_pHtElementType = new MdaHashtable<MdaElemDeclDef>(); + g_pHtAttributeType = new MdaHashtable<MdaAttrDeclDef>(); + g_pSstringFactory = new MdaFactory<SString>(); + + COUNT_T i = 0; + MdaSchemaTypeToElemDef[i++] = MdaElemDef(Sequence); // MdaSchemaSequenceType + MdaSchemaTypeToElemDef[i++] = MdaElemDef(Choice); // MdaSchemaChoiceType + MdaSchemaTypeToElemDef[i++] = MdaElemDef(Group); // MdaSchemaGroupType + MdaSchemaTypeToElemDef[i++] = MdaElemDef(Group); // MdaSchemaGroupRefType + MdaSchemaTypeToElemDef[i++] = MdaElemDef(Schema); // MdaSchemaRootType + MdaSchemaTypeToElemDef[i++] = MdaElemDef(Attribute); // MdaSchemaAttributeType + MdaSchemaTypeToElemDef[i++] = MdaElemDef(Element); // MdaSchemaElementType + MdaSchemaTypeToElemDef[i++] = MdaElemDef(ComplexType); // MdaSchemaComplexTypeType + MdaSchemaTypeToElemDef[i++] = MdaElemDef(ComplexType); // MdaSchemaComplexTypeDefType + MdaSchemaTypeToElemDef[i++] = MdaElemDef(Element); // MdaSchemaElementRefTyp + MdaSchemaTypeToElemDef[i++] = MdaElemDef(Extension); // MdaSchemaExtensionType + MdaSchemaTypeToElemDef[i++] = MdaElemDef(Element); // MdaSchemaElementRefTypeType + MdaSchemaTypeToElemDef[i++] = MdaElemDef(ComplexContent); // MdaSchemaComplexContentType + MdaSchemaTypeToElemDef[i++] = MdaElemDef(Element); // MdaSchemaElementAnyType + + i = 0; + MdaSchemaTypeToMetaType[i++] = MdaSchemaMataTypePattern; // MdaSchemaSequenceType + MdaSchemaTypeToMetaType[i++] = MdaSchemaMataTypePattern; // MdaSchemaChoiceType + MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataTypePattern | MdaSchemaMataTypeDeclDef); // MdaSchemaGroupType + MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataTypePattern | MdaSchemaMataTypeRef); // MdaSchemaGroupRefType + MdaSchemaTypeToMetaType[i++] = MdaSchemaMataNone; // MdaSchemaRootType + MdaSchemaTypeToMetaType[i++] = MdaSchemaMataNone; // MdaSchemaAttributeType + MdaSchemaTypeToMetaType[i++] = MdaSchemaMataTypeDeclDef; // MdaSchemaElementType + MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataNone | MdaSchemaMataMayHaveAttributes); // MdaSchemaComplexTypeType + MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataTypeDeclDef | MdaSchemaMataMayHaveAttributes); // MdaSchemaComplexTypeDefType + MdaSchemaTypeToMetaType[i++] = MdaSchemaMataTypeRef; // MdaSchemaElementRefTyp + MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataTypeRef | MdaSchemaMataMayHaveAttributes); // MdaSchemaExtensionType + MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataTypeDeclDef | MdaSchemaMataTypeRef); // MdaSchemaElementRefTypeType + MdaSchemaTypeToMetaType[i++] = MdaSchemaMataNone; // MdaSchemaComplexContentType + MdaSchemaTypeToMetaType[i++] = MdaSchemaMataTypeDeclDef; // MdaSchemaElementAnyType + + i = 0; +#define MDA_MAP_ASSISTANT_DEFINITION_TO_NAME +#include "mdaschema.inl" +#undef MDA_MAP_ASSISTANT_DEFINITION_TO_NAME + g_arElementNames[i++] = NULL; +#define MDA_MAP_ELEMENT_DEFINITION_TO_NAME +#include "mdaschema.inl" +#undef MDA_MAP_ELEMENT_DEFINITION_TO_NAME + g_arElementNames[i++] = NULL; +#define MDA_MAP_ELEMENT_DECLARATION_TO_NAME +#include "mdaschema.inl" +#undef MDA_MAP_ELEMENT_DECLARATION_TO_NAME + g_arElementNames[i++] = NULL; // Max + g_arElementNames[i++] = W("!--"); // Comment + g_arElementNames[i++] = NULL; // Undefined + + i = 0; +#define MDA_MAP_ATTRIBUTE_DECLARATION_TO_NAME +#include "mdaschema.inl" +#undef MDA_MAP_ATTRIBUTE_DECLARATION_TO_NAME + +#define MDA_MAP_ASSISTANT_NAME_TO_DEFINITION +#include "mdaschema.inl" +#undef MDA_MAP_ASSISTANT_NAME_TO_DEFINITION + +#define MDA_MAP_ELEMENT_NAME_TO_DEFINITION +#include "mdaschema.inl" +#undef MDA_MAP_ELEMENT_NAME_TO_DEFINITION + +#define MDA_MAP_ELEMENT_NAME_TO_DECLARATION +#include "mdaschema.inl" +#undef MDA_MAP_ELEMENT_NAME_TO_DECLARATION + +#define MDA_MAP_ATTRIBUTE_NAME_TO_DECLARATION +#include "mdaschema.inl" +#undef MDA_MAP_ATTRIBUTE_NAME_TO_DECLARATION +} + +MdaElemDeclDef MdaSchema::GetElementType(LPCWSTR name, BOOL bAssertDefined) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + MdaElemDeclDef type; + + if (!g_pHtElementType->Get(name, &type)) + { + ASSERT(!bAssertDefined); + return MdaElemUndefined; + } + + return type; +} + +LPCWSTR MdaSchema::GetElementName(MdaElemDeclDef type) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + PRECONDITION(type >= 0 && type < MdaElemUndefined); + return g_arElementNames[type]; +} + +MdaAttrDeclDef MdaSchema::GetAttributeType(LPCWSTR name, BOOL bAssertDefined) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + MdaAttrDeclDef type; + + if (!g_pHtAttributeType->Get(name, &type)) + { + ASSERT(!bAssertDefined); + return MdaAttrUndefined; + } + + return type; +} + +LPCWSTR MdaSchema::GetAttributeName(MdaAttrDeclDef type) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + return g_arAttributeNames[type]; +} + +// TODO: Validation error reporting needs work +MdaSchema::ValidationResult* MdaSchema::Validate(MdaXmlElement* pRoot, ValidationResult* pResult) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + pResult->Initialize(this, pRoot); + + MdaSchemaBase* pXsd = *GetDef(pRoot->GetDeclDef()); + ASSERT((CheckPointer(pXsd) || (pRoot->GetDeclDef() > MdaElemDecl(Max))) && W("You likley did not include a MDA_DEFINE_OUTPUT section in your schema!")); + + BOOL bValidationSucceeded = pXsd ? pXsd->Validate(pRoot, pResult) : FALSE; + + if (bValidationSucceeded) + pResult->ResetResult(); + else + pResult->SetError(); + + ASSERT(pResult->ValidationFailed() == !bValidationSucceeded); + return pResult; +} + +MdaSchema::MdaSchema() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + for(COUNT_T i = 0; i < MdaElemEnd; i ++) + m_definitions[i] = NULL; +} + + +// +// MdaAssistantSchema +// + +MdaAssistantSchema::MdaAssistantSchema() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + +#define MDA_DEFINE_ASSISTANT_SCHEMA +#include "mdaschema.inl" +#undef MDA_DEFINE_ASSISTANT_SCHEMA + +#define MDA_DEFINE_MDA_ASSISTANT_CONFIG_GROUP +#include "mdaschema.inl" +#undef MDA_DEFINE_MDA_ASSISTANT_CONFIG_GROUP +} + +LPCWSTR MdaAssistantSchema::SetRootAttributes(MdaXmlElement* pXml) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + //pXml->AddAttribute(W("xmlns:") MDA_SCHEMA_PREFIX, MDA_TARGET_NAMESPACE); + //pXml->AddAttribute(W("xmlns:xsi"), W("http://www.w3.org/2001/XMLSchema-instance")); + return MDA_SCHEMA_PREFIX; +} + + +// +// MdaAssistantMsgSchema +// + +MdaAssistantMsgSchema::MdaAssistantMsgSchema() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + +#define MDA_DEFINE_ASSISTANT_MSG_SCHEMA +#include "mdaschema.inl" +#undef MDA_DEFINE_ASSISTANT_MSG_SCHEMA + +#define MDA_DEFINE_MDA_ASSISTANT_MSG_GROUP +#include "mdaschema.inl" +#undef MDA_DEFINE_MDA_ASSISTANT_MSG_GROUP +} + +LPCWSTR MdaAssistantMsgSchema::SetRootAttributes(MdaXmlElement* pXml) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + //pXml->AddAttribute(W("xmlns:") MDA_SCHEMA_PREFIX, MDA_TARGET_NAMESPACE); + //pXml->AddAttribute(W("xmlns:xsi"), W("http://www.w3.org/2001/XMLSchema-instance")); + return MDA_SCHEMA_PREFIX; +} + + +// +// MdaSchemaSchema +// + +MdaSchemaSchema::MdaSchemaSchema() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + +#define MDA_DEFINE_SCHEMA_SCHEMA +#include "mdaschema.inl" +#undef MDA_DEFINE_SCHEMA_SCHEMA +} + +LPCWSTR MdaSchemaSchema::SetRootAttributes(MdaXmlElement* pXml) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + pXml->AddAttributeSz(MdaAttrDecl(TargetNamespace), MDA_TARGET_NAMESPACE); + pXml->AddAttributeSz(MdaAttrDecl(Xmlns), W("http://www.w3.org/2001/XMLSchema"))->SetNs(W("xs")); + pXml->AddAttributeSz(MdaAttrDecl(Xmlns), MDA_TARGET_NAMESPACE); + return W("xs"); +} + + +// +// MdaSchema::MdaSchemaXXX +// +MdaXmlElement* MdaSchema::MdaSchemaBase::ToXml(MdaXmlIndustry* pMdaXmlIndustry, MdaSchemaBase* pViolation) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + return ToXml(pMdaXmlIndustry->CreateElement(), pViolation); +} + +MdaXmlElement* MdaSchema::MdaSchemaBase::ToXml(MdaXmlElement* pXmlRoot, MdaSchemaBase* pViolation) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + LPCWSTR debugName = GetName(); + + MdaXmlElement* pXml = pXmlRoot->AddChild(GetSchemaDeclDef()); + SetAttributes(pXml); + +// if (this == pViolation) +// pXml->AddAttributeSz(MdaAttrDecl(Violated), W("---- THIS XSD ELEMENT VIOLATED -----")); + + if (m_children.GetCount() == 1 && + m_children[0]->GetSchemaDeclDef() == MdaElemDef(ComplexType) && + m_children[0]->m_children.GetCount() == 0 && + (!MayHaveAttr(m_children[0]) || + m_children[0]->GetAttributes().GetCount() == 0)) + { + // Convert <Element><ComplexType/><Element> to <Element/> + return pXml; + } + + for(COUNT_T i = 0; i < m_children.GetCount(); i ++) + { + debugName = m_children[i]->GetName(); + m_children[i]->ToXml(pXml, pViolation); + } + + if (MayHaveAttr(this)) + { + SArray<MdaSchemaAttribute*>& attributes = GetAttributes(); + for(COUNT_T j = 0; j < attributes.GetCount(); j ++) + { + debugName = attributes[j]->GetName(); + attributes[j]->ToXml(pXml, pViolation); + } + } + + return pXml; +} + + +void MdaSchema::MdaSchemaBase::AddChild(MdaSchemaBase* pElement) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (pElement->GetSchemaDeclDef() == MdaElemDef(Attribute)) + *GetAttributes().Append() = (MdaSchemaAttribute*)pElement; + else + *m_children.Append() = pElement; +} + +// +// Validation +// + +#define CpdXsdIfFailGo(EXPR) do { if (!(EXPR)) { goto Fail; } } while (0) +#define CpdXsdTest(EXPR) do { if (!(EXPR)) { pResult->SetError(this, pElement); goto Fail; } } while (0) +#define MDA_XSD_VERIFY_OK return TRUE; +#define MDA_XSD_VERIFY_FAIL Fail: return FALSE; + +BOOL MdaSchema::MdaSchemaElement::Validate(MdaXmlElement* pElement, ValidationResult* pResult) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + StackSString buffer; + LPCWSTR debug = pElement->DebugToString(&buffer); + + CpdXsdTest(pElement->GetDeclDef() == GetDeclDef()); + + for(COUNT_T i = 0; i < m_children.GetCount(); i++) + CpdXsdIfFailGo(m_children[i]->Validate(pElement, pResult)); + + MDA_XSD_VERIFY_OK; + MDA_XSD_VERIFY_FAIL; +} + +BOOL MdaSchema::MdaSchemaSequence::ValidatePattern(MdaXmlElement* pElement, ValidationResult* pResult, COUNT_T* pCount) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + StackSString buffer; + LPCWSTR debug = pElement->DebugToString(&buffer); + + COUNT_T cPeriod = m_children.GetCount(); + COUNT_T cChildren = pElement->GetChildren().GetCount(); + COUNT_T cCurrent = *pCount; + COUNT_T cCount = cCurrent; + COUNT_T cMatches = 0; + + if (cPeriod == 0) + return TRUE; + + while(cCurrent <= cChildren) + { + MdaSchemaBase* pXsd = m_children[cMatches % cPeriod]; + if (pXsd->GetSchemaDeclDef() == MdaElemDef(Element)) + { + if (cCurrent == cChildren) + break; + + if (!pXsd->Validate(pElement->GetChildren()[cCurrent], pResult)) + break; + + cCurrent++; + } + else + { + ASSERT(IsPattern(pXsd)); + if (!pXsd->ValidatePattern(pElement, pResult, &cCurrent)) + break; + } + + cMatches++; + + // One period matched + if (cMatches % cPeriod == 0) + cCount = cCurrent; + + // Maximum periods matcheds + if (cMatches / cPeriod == m_max) + break; + } + + // Test if the minumum number periods have been matched + if (cMatches / cPeriod < m_min) + return FALSE; + + // Update the position past the matched elements + *pCount = cCount; + + return TRUE; +} + +BOOL MdaSchema::MdaSchemaChoice::ValidatePattern(MdaXmlElement* pElement, ValidationResult* pResult, COUNT_T* pCount) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + StackSString buffer; + LPCWSTR debug = pElement->DebugToString(&buffer); + + BOOL bFound = FALSE; + COUNT_T cCurrent = *pCount; + COUNT_T cChildren = pElement->GetChildren().GetCount(); + + for(COUNT_T cXsd = 0; cXsd < m_children.GetCount(); cXsd++) + { + MdaSchemaBase* pXsd = m_children[cXsd]; + + if (IsPattern(pXsd)) + { + COUNT_T cOldCurrent = cCurrent; + if (pXsd->ValidatePattern(pElement, pResult, &cCurrent)) + { + // "Empty matches" only allowed in choice pattern if there are no children to match + if (cOldCurrent != cCurrent || cChildren == 0) + { + bFound = TRUE; + break; + } + } + } + else + { + if (cCurrent == cChildren) + break; + + if (pXsd->Validate(pElement->GetChildren()[cCurrent], pResult)) + { + cCurrent++; + bFound = TRUE; + break; + } + } + } + + CpdXsdIfFailGo(bFound); + + *pCount = cCurrent; + + MDA_XSD_VERIFY_OK; + MDA_XSD_VERIFY_FAIL; +} + +#define this pThis +BOOL MdaSchema::Validate(MdaSchemaAttribute* pThis, MdaXmlElement* pElement, ValidationResult* pResult) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + StackSString sszValue; + MdaXmlAttribute* pAttr = (MdaXmlAttribute*)pElement->GetAttribute(pThis->m_declDef); + + if (!pAttr && !pThis->m_szDefault.IsEmpty()) + { + pAttr = pElement->AddDefaultAttribute(pThis->m_declDef, pThis->m_szDefault.GetUnicode()); + } + + if (!pAttr) + { + CpdXsdTest(!pThis->m_bRequired); + return TRUE; + } + +#ifdef _DEBUG + // Only necessary for validation of assistant output + if (pAttr->m_type != MdaSchemaPrimitiveUnknown) + { + CpdXsdTest(pAttr->m_type == pThis->m_type); + return TRUE; + } +#endif + + LPCWSTR szValue = pAttr->GetValue(); + sszValue.Set(szValue); + + if (pThis->m_type == MdaSchemaPrimitiveSString) + { + /* accept all strings? */ + } + else if (pThis->m_type == MdaSchemaPrimitiveINT32) + { + CpdXsdTest(!sszValue.IsEmpty() && sszValue.GetCount() != 0); + + for (COUNT_T i = 0; i < sszValue.GetCount(); i ++) + { + if (i == 0 && *szValue == W('-') && sszValue.GetCount() > 1) + continue; + + CpdXsdTest(IS_DIGIT(szValue[i])); + } + + pAttr->SetINT32(_wtoi(szValue)); + } + else if (pThis->m_type == MdaSchemaPrimitiveBOOL) + { + CpdXsdTest(!sszValue.IsEmpty() && sszValue.GetCount() != 0); + + if (sszValue.Equals(W("true"))) + pAttr->SetBOOL(true); + else if (sszValue.Equals(W("false"))) + pAttr->SetBOOL(false); + else + CpdXsdTest(FALSE); + } + + MDA_XSD_VERIFY_OK; + MDA_XSD_VERIFY_FAIL; +} +#undef this + +BOOL MdaSchema::MdaSchemaBase::Validate(MdaXmlElement* pElement, ValidationResult* pResult) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + COUNT_T count = 0; + + CpdXsdTest(ValidatePattern(pElement, pResult, &count)); + + CpdXsdTest(count == pElement->GetChildren().GetCount()); + + MDA_XSD_VERIFY_OK; + MDA_XSD_VERIFY_FAIL; +} + +BOOL MdaSchema::MdaSchemaRoot::Validate(MdaXmlElement* pElement, ValidationResult* pResult) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + for(COUNT_T i = 0; i < m_children.GetCount(); i++) + CpdXsdIfFailGo(m_children[i]->Validate(pElement, pResult)); + + MDA_XSD_VERIFY_OK; + MDA_XSD_VERIFY_FAIL; +} + +BOOL MdaSchema::MdaSchemaComplexType::Validate(MdaXmlElement* pElement, ValidationResult* pResult) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + for(COUNT_T i = 0; i < m_children.GetCount(); i++) + CpdXsdIfFailGo(m_children[i]->Validate(pElement, pResult)); + + for(COUNT_T i = 0; i < m_attributes.GetCount(); i++) + CpdXsdIfFailGo(m_attributes[i]->Validate(pElement, pResult)); + + MDA_XSD_VERIFY_OK; + MDA_XSD_VERIFY_FAIL; +} + +BOOL MdaSchema::MdaSchemaComplexTypeDef::Validate(MdaXmlElement* pElement, ValidationResult* pResult) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + for(COUNT_T i = 0; i < m_children.GetCount(); i++) + CpdXsdIfFailGo(m_children[i]->Validate(pElement, pResult)); + + for(COUNT_T i = 0; i < m_attributes.GetCount(); i++) + CpdXsdIfFailGo(m_attributes[i]->Validate(pElement, pResult)); + + MDA_XSD_VERIFY_OK; + MDA_XSD_VERIFY_FAIL; +} + +BOOL MdaSchema::MdaSchemaComplexContent::Validate(MdaXmlElement* pElement, ValidationResult* pResult) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + for(COUNT_T i = 0; i < m_children.GetCount(); i++) + CpdXsdIfFailGo(m_children[i]->Validate(pElement, pResult)); + + MDA_XSD_VERIFY_OK; + MDA_XSD_VERIFY_FAIL; +} + +BOOL MdaSchema::MdaSchemaGroup::ValidatePattern(MdaXmlElement* pElement, ValidationResult* pResult, COUNT_T* pCount) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + for(COUNT_T i = 0; i < m_children.GetCount(); i++) + { + ASSERT(IsPattern(m_children[i])); + CpdXsdIfFailGo(m_children[i]->ValidatePattern(pElement, pResult, pCount)); + } + + MDA_XSD_VERIFY_OK; + MDA_XSD_VERIFY_FAIL; +} + +BOOL MdaSchema::MdaSchemaGroupRef::ValidatePattern(MdaXmlElement* pElement, ValidationResult* pResult, COUNT_T* pCount) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + MdaSchemaBase* pReference = GetRef(); + LPCWSTR debug = GetRefName(); + ASSERT(IsPattern(this)); + return pReference->ValidatePattern(pElement, pResult, pCount); +} + +BOOL MdaSchema::MdaSchemaExtension::Validate(MdaXmlElement* pElement, ValidationResult* pResult) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + ASSERT(GetRef()->GetSchemaType() == MdaSchemaComplexTypeDefType); + MdaSchemaComplexTypeDef* pReference = (MdaSchemaComplexTypeDef*)GetRef(); + + MdaSchemaSequence sequence; + sequence.Initialize(1, 1); + + MdaSchemaBase* pXsd = pReference; + while(true) + { + if (MayHaveAttr(pXsd)) + { + for(COUNT_T i = 0; i < pXsd->GetAttributes().GetCount(); i++) + CpdXsdIfFailGo(pXsd->GetAttributes()[i]->Validate(pElement, pResult)); + } + + if (pXsd->GetSchemaType() == MdaSchemaExtensionType) + { + pXsd = ((MdaSchemaComplexTypeDef*)pXsd)->GetRef(); + continue; + } + + if (pXsd->m_children.GetCount() == 0) + break; + + pXsd = pXsd->m_children[0]; + + if (IsPattern(pXsd)) + { + sequence.AddChild(pXsd); + break; + } + } + + if (m_children.GetCount() == 1) + { + ASSERT(IsPattern(m_children[0])); + sequence.AddChild(m_children[0]); + } + + CpdXsdIfFailGo(sequence.Validate(pElement, pResult)); + + for(COUNT_T i = 0; i < m_attributes.GetCount(); i++) + CpdXsdIfFailGo(m_attributes[i]->Validate(pElement, pResult)); + + MDA_XSD_VERIFY_OK; + MDA_XSD_VERIFY_FAIL; +} + +BOOL MdaSchema::MdaSchemaElementRefType::Validate(MdaXmlElement* pElement, ValidationResult* pResult) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + CpdXsdIfFailGo(GetRef()->Validate(pElement, pResult)); + + MDA_XSD_VERIFY_OK; + MDA_XSD_VERIFY_FAIL; +} + +BOOL MdaSchema::MdaSchemaElementAny::Validate(MdaXmlElement* pElement, ValidationResult* pResult) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + StackSString buffer; + LPCWSTR debug = pElement->DebugToString(&buffer); + + CpdXsdTest(pElement->GetDeclDef() == GetDeclDef()); + + MDA_XSD_VERIFY_OK; + MDA_XSD_VERIFY_FAIL; +} + +BOOL MdaSchema::MdaSchemaElementRef::Validate(MdaXmlElement* pElement, ValidationResult* pResult) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + LPCWSTR debug = GetRefName(); + CpdXsdIfFailGo(GetRef()->Validate(pElement, pResult)); + + MDA_XSD_VERIFY_OK; + MDA_XSD_VERIFY_FAIL; +} + + +// +// MdaSchema::XXX::SetAttributes() +// + +void MdaSchema::MdaSchemaSequence::SetAttributes(MdaXmlElement* pXml) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + SmallStackSString ssBound; + + ssBound.Printf(W("%d"), m_min); + pXml->AddAttributeSz(MdaAttrDecl(MinOccurs), ssBound.GetUnicode()); + + if (m_max == -1) + { + pXml->AddAttributeSz(MdaAttrDecl(MaxOccurs), W("unbounded")); + } + else + { + ssBound.Printf(W("%d"), m_max); + pXml->AddAttributeSz(MdaAttrDecl(MaxOccurs), ssBound.GetUnicode()); + } +} + +void MdaSchema::MdaSchemaAttribute::SetAttributes(MdaXmlElement* pXml) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + pXml->AddAttributeSz(MdaAttrDecl(Name), GetAttributeName(m_declDef)); + + LPCWSTR szType = NULL; + if (m_type == MdaSchemaPrimitiveBOOL) + szType = W("xs:boolean"); + else if (m_type == MdaSchemaPrimitiveINT32) + szType = W("xs:int"); + else if (m_type == MdaSchemaPrimitiveSString) + szType = W("xs:string"); + else { UNREACHABLE(); } + + pXml->AddAttributeSz(MdaAttrDecl(Type), szType); + pXml->AddAttributeSz(MdaAttrDecl(Use), m_bRequired ? W("required") : W("optional")); + + if (!m_szDefault.IsEmpty()) + pXml->AddAttributeSz(MdaAttrDecl(Default), m_szDefault); +} + +void MdaSchema::MdaSchemaDeclDefRef::SetAttributes(MdaXmlElement* pXml) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + LPCWSTR szDeclDef = NULL; + LPCWSTR szRef = NULL; + + if (IsDeclDef(this)) + szDeclDef = GetDeclDefName(); + + if (IsRef(this)) + szRef = GetRefName(); + + switch (GetSchemaType()) + { + case MdaSchemaGroupRefType: + case MdaSchemaElementRefTyp: + pXml->AddAttributeSz(MdaAttrDecl(Ref), szRef); + break; + + case MdaSchemaExtensionType: + pXml->AddAttributeSz(MdaAttrDecl(Base), szRef); + break; + + case MdaSchemaElementRefTypeType: + pXml->AddAttributeSz(MdaAttrDecl(Name), szDeclDef); + pXml->AddAttributeSz(MdaAttrDecl(Type), szRef); + break; + + case MdaSchemaElementAnyType: + pXml->AddAttributeSz(MdaAttrDecl(Name), szDeclDef); + pXml->AddAttributeSz(MdaAttrDecl(Type), W("xs:anyType")); + break; + + case MdaSchemaGroupType: + case MdaSchemaElementType: + case MdaSchemaComplexTypeDefType: + pXml->AddAttributeSz(MdaAttrDecl(Name), szDeclDef); + break; + + default: + UNREACHABLE(); + } +} + +// +// MdaAssistant +// +void MdaAssistant::Initialize(MdaXmlElement* pXmlInput) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (pXmlInput->GetAttribute(MdaAttrDecl(SuppressDialog))) + m_bSuppressDialog = !!pXmlInput->GetAttributeValueAsBool(MdaAttrDecl(SuppressDialog)); +} + +LPCWSTR MdaAssistant::GetName() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + return MdaSchema::GetElementName(m_assistantDeclDef); +} + +MdaXmlElement* MdaAssistant::GetRootElement(MdaXmlElement* pRoot, BOOL bBreak) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + MdaXmlElement* pXmlAssistant = pRoot->AddChild(GetAssistantMsgDeclDef()); + + if (bBreak) + pXmlAssistant->AddAttributeSz(MdaAttrDecl(Break), W("true")); + + return pXmlAssistant; +} + +BOOL MdaAssistant::IsAssistantActive(MdaXmlElement* pXml) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + return TRUE; +} + +MdaXmlElement* MdaAssistant::OutputThread(Thread* pThread, MdaXmlElement* pXml) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + _ASSERTE(pThread); + pXml->AddAttributeInt(MdaAttrDecl(OsId), pThread->GetOSThreadId()); + pXml->AddAttributeInt(MdaAttrDecl(ManagedId), pThread->GetThreadId()); + + return pXml; +} + +MdaXmlElement* MdaAssistant::OutputMethodTable(MethodTable* pMT, MdaXmlElement* pXml) +{ + CONTRACT (MdaXmlElement*) + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + PRECONDITION(CheckPointer(pMT)); + PRECONDITION(CheckPointer(pXml)); + POSTCONDITION(CheckPointer(RETVAL)); + } + CONTRACT_END; + + static WCHAR szTemplateMsg[] = {W("Failed to QI for interface %s because it does not have a COM proxy stub registered.")}; + + DefineFullyQualifiedNameForClassWOnStack(); + pXml->AddAttributeSz(MdaAttrDecl(Name), GetFullyQualifiedNameForClassW(pMT)); + + RETURN pXml; +} + +void MdaAssistant::ToString(TypeHandle typeHandle, SString* psszFullname, SString* psszNamespace) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + StackSString ssz;; + + psszFullname->Clear(); + + LPCSTR szDeclTypeName, szNamespace; + InlineSArray<mdTypeDef, 32> nesting; + + mdTypeDef tkTypeDef = typeHandle.GetCl(); + Module* pModule = typeHandle.GetModule(); + IMDInternalImport* pImport = pModule->GetMDImport(); + + // Get tkTypeDef tokens for declaring type and its nested classes + nesting.Append(tkTypeDef); + while (S_OK == pImport->GetNestedClassProps(tkTypeDef, &tkTypeDef)) + nesting.Append(tkTypeDef); + + // Append the namespace + COUNT_T i = nesting.GetCount() - 1; + if (FAILED(pImport->GetNameOfTypeDef(nesting[i], &szDeclTypeName, &szNamespace))) + { + szNamespace = NULL; + szDeclTypeName = NULL; + } + if (szNamespace && *szNamespace != W('\0')) + { + if (psszNamespace) + psszNamespace->SetUTF8(szNamespace); + + psszFullname->SetUTF8(szNamespace); + psszFullname->Append(W(".")); + } + + // Append the nested classes + for(; i > 0; i --) + { + IfFailThrow(pImport->GetNameOfTypeDef(nesting[i], &szDeclTypeName, &szNamespace)); + ssz.SetUTF8(szDeclTypeName); + psszFullname->Append(ssz); + psszFullname->Append(W("+")); + } + + // Append the declaring type name + IfFailThrow(pImport->GetNameOfTypeDef(nesting[i], &szDeclTypeName, &szNamespace)); + ssz.SetUTF8(szDeclTypeName); + psszFullname->Append(ssz); +} + +SString& MdaAssistant::ToString(SString& sszBuffer, Module* pModule) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + sszBuffer.AppendUTF8(pModule->GetSimpleName()); + return sszBuffer; +} + +SString& MdaAssistant::ToString(SString& sszBuffer, TypeHandle typeHandle) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + StackSString sszScratch; + ToString(sszBuffer, typeHandle.GetModule()).GetUnicode(); + sszBuffer.Append(W("!")); + ToString(typeHandle, &sszScratch, NULL); + sszBuffer.Append(sszScratch); + return sszBuffer; +} + +SString& MdaAssistant::ToString(SString& sszBuffer, MethodDesc* pMethodDesc) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + ToString(sszBuffer, pMethodDesc->GetMethodTable()).GetUnicode(); + sszBuffer.Append(W("::")); + StackSString ssz; + ssz.SetUTF8(pMethodDesc->GetName()); + sszBuffer.Append(ssz); + return sszBuffer; +} + +SString& MdaAssistant::ToString(SString& sszBuffer, FieldDesc* pFieldDesc) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + ToString(sszBuffer, pFieldDesc->GetEnclosingMethodTable()).GetUnicode(); + sszBuffer.Append(W("::")); + StackSString ssz; + ssz.SetUTF8(pFieldDesc->GetName()); + sszBuffer.Append(ssz); + return sszBuffer; +} + +MdaXmlElement* MdaAssistant::OutputParameter(SString parameterName, USHORT sequence, MethodDesc* pMethodDesc, MdaXmlElement* pXml) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + TypeHandle declType(pMethodDesc->GetMethodTable()); + Module* pDeclModule = declType.GetModule(); + + pXml->AddAttributeSz(MdaAttrDecl(Name), parameterName); + pXml->AddAttributeInt(MdaAttrDecl(Index), sequence); + + OutputMethodDesc(pMethodDesc, pXml->AddChild(MdaElemDecl(DeclaringMethod))); + + return pXml; +} + +MdaXmlElement* MdaAssistant::OutputMethodDesc(MethodDesc* pMethodDesc, MdaXmlElement* pXml) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + TypeHandle declType(pMethodDesc->GetMethodTable()); + Module* pDeclModule = declType.GetModule(); + + StackSString sszMethod; + + pXml->AddAttributeSz(MdaAttrDecl(Name), ToString(sszMethod, pMethodDesc).GetUnicode()); + + return pXml; +} + +MdaXmlElement* MdaAssistant::OutputFieldDesc(FieldDesc* pFieldDesc, MdaXmlElement* pXml) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + StackSString sszField; + + pXml->AddAttributeSz(MdaAttrDecl(Name), ToString(sszField, pFieldDesc).GetUnicode()); + + return pXml; +} + +MdaXmlElement* MdaAssistant::OutputTypeHandle(TypeHandle typeHandle, MdaXmlElement* pXml) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + StackSString sszTypeName; + + // Set Attribute + pXml->AddAttributeSz(MdaAttrDecl(Name), ToString(sszTypeName, typeHandle.GetMethodTable()).GetUnicode()); + + return pXml; +} + +MdaXmlElement* MdaAssistant::OutputModule(Module* pModule, MdaXmlElement* pXml) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + pXml->AddAttributeSz(MdaAttrDecl(Name), pModule->GetSimpleName()); + + return pXml; +} + +MdaXmlElement* MdaAssistant::OutputCallsite(MethodDesc *pMethodDesc, DWORD dwOffset, MdaXmlElement* pXml) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + StackSString sszMethod; + pXml->AddAttributeSz(MdaAttrDecl(Name), ToString(sszMethod, pMethodDesc).GetUnicode()); + + StackSString sszOffset; + sszOffset.Printf(W("0x%04X"), dwOffset); + pXml->AddAttributeSz(MdaAttrDecl(Offset), sszOffset.GetUnicode()); + + return pXml; +} + +MdaXmlElement* MdaAssistant::OutputException(OBJECTREF *pExceptionObj, MdaXmlElement* pXml) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + OutputTypeHandle((*pExceptionObj)->GetTypeHandle(), pXml->AddChild(MdaElemDecl(Type))); + + StackSString message; + GetExceptionMessage(*pExceptionObj, message); + + pXml->AddAttributeSz(MdaAttrDecl(Message), message); + + return pXml; +} + +// +// MdaQuery::CompiledQueries +// +BOOL MdaQuery::CompiledQueries::Test(MethodDesc* pMethodDesc) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + for (COUNT_T i = 0; i < m_queries.GetCount(); i ++) + { + if (m_queries[i]->Test(pMethodDesc)) + return TRUE; + } + + return FALSE; +} + +BOOL MdaQuery::CompiledQueries::Test(FieldDesc* pFieldDesc) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + for (COUNT_T i = 0; i < m_queries.GetCount(); i ++) + { + if (m_queries[i]->Test(pFieldDesc)) + return TRUE; + } + + return FALSE; +} + +BOOL MdaQuery::CompiledQueries::Test(MethodTable* pMethodTable) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + for (COUNT_T i = 0; i < m_queries.GetCount(); i ++) + { + if (m_queries[i]->Test(pMethodTable)) + return TRUE; + } + + return FALSE; +} + +MdaQuery::CompiledQuery* MdaQuery::CompiledQueries::AddQuery() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + CompiledQuery* pQuery = m_factory.Create(); + m_queries.Append(pQuery); + return pQuery; +} + + +// +// MdaQuery::CompiledQuery +// +void MdaQuery::Compile(MdaXmlElement* pXmlFilters, CompiledQueries* pCompiledQueries) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + SArray<MdaXmlElement*>& children = pXmlFilters->GetChildren(); + BOOL bJmc = pXmlFilters->GetAttribute(MdaAttrDecl(JustMyCode))->GetValueAsBool(); + + for (COUNT_T i = 0; i < children.GetCount(); i ++) + { + MdaXmlElement* pXmlFilter = children[i]; + SString* psszName = pXmlFilter->GetAttribute(MdaAttrDecl(Name))->GetValueAsCSString(); + MdaXmlAttribute* pJmcOptAttr = pXmlFilter->GetAttribute(MdaAttrDecl(JustMyCode)); + if (pJmcOptAttr) + bJmc = pJmcOptAttr->GetValueAsBool(); + Compiler compiler; + CompiledQuery* pQuery = pCompiledQueries->AddQuery(); + compiler.Compile(psszName, pQuery); + if (bJmc) + pQuery->SetJustMyCode(); + } +} + +MdaQuery::CompiledQuery::CompiledQuery() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + m_bJustMyCode = FALSE; + m_bAnyMember = FALSE; + m_bAnyType = FALSE; + m_sszFullname.Clear(); + m_sszMember.Clear(); +} + +BOOL StartsWith(SString* psszString, SString* psszSubstring) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + StackSString sszString(*psszString); + if (psszString->GetCount() < psszSubstring->GetCount()) + return FALSE; + sszString.Truncate(sszString.Begin() + psszSubstring->GetCount()); + return sszString.Equals(*psszSubstring); +} + +BOOL MdaQuery::CompiledQuery::Test(MethodDesc* pMethodDesc) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + StackSString sszName(SString::Utf8, pMethodDesc->GetName()); + + if (pMethodDesc->IsLCGMethod() || pMethodDesc->IsILStub()) + return FALSE; + + if (!Test(&sszName, pMethodDesc->GetMethodTable())) + return FALSE; + + if (!m_bJustMyCode) + return TRUE; + + if (IsJustMyCode(pMethodDesc)) + return TRUE; + + return FALSE; +} + +BOOL MdaQuery::CompiledQuery::Test(FieldDesc* pFieldDesc) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + StackSString sszName(SString::Utf8, pFieldDesc->GetName()); + if (!Test(&sszName, pFieldDesc->GetApproxEnclosingMethodTable())) + return FALSE; + + if (!m_bJustMyCode) + return TRUE; + + return TRUE; +} + +BOOL MdaQuery::CompiledQuery::Test(SString* psszName, MethodTable* pMethodTable) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (!m_sszMember.IsEmpty()) + { + if (!m_sszMember.Equals(*psszName)) + return FALSE; + + if (m_sszMember.GetCount() == m_sszFullname.GetCount()) + return TRUE; + } + else if (!m_bAnyMember) + return FALSE; + + return Test(pMethodTable); +} + +BOOL MdaQuery::CompiledQuery::Test(MethodTable* pMethodTable) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (!pMethodTable) + return FALSE; + + if (m_sszFullname.IsEmpty()) + return TRUE; + + StackSString sszNamespace, sszFullName; + MdaAssistant::ToString(pMethodTable, &sszFullName, &sszNamespace); + + if (m_bAnyType && StartsWith(&m_sszFullname, &sszNamespace)) + return TRUE; + + if (m_bAnyMember && StartsWith(&m_sszFullname, &sszFullName)) + return TRUE; + + return m_sszFullname.Equals(sszFullName); +} + +void MdaQuery::CompiledQuery::SetName(LPCWSTR name) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (!m_sszFullname.IsEmpty()) + { + m_sszFullname.Append(W(".")); + m_sszMember.Clear(); + } + else + { + m_sszMember.Set(name); + } + + m_sszFullname.Append(name); + +} + +void MdaQuery::CompiledQuery::SetNestedTypeName(LPCWSTR name) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + m_sszMember.Clear(); + + if (!m_sszFullname.IsEmpty()) + m_sszFullname.Append(W("+")); + + m_sszFullname.Append(name); +} + +void MdaQuery::CompiledQuery::SetAnyMember() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + m_bAnyMember = TRUE; + m_sszMember.Clear(); +} + +void MdaQuery::CompiledQuery::SetAnyType() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + m_bAnyType = TRUE; + m_sszMember.Clear(); + + if (m_sszFullname.IsEmpty()) + m_bAnyMember = TRUE; +} + + +// +// MdaQuery::CompiledQuery +// + +MdaQuery::Compiler::Token MdaQuery::Compiler::LexAToken() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (*m_itr == W('\0')) + return MdaFilterEnd; + + if (ISWHITE(*m_itr)) + { + m_itr++; + return LexAToken(); + } + + if (ISMDAID(*m_itr)) + { + m_identifier.Clear(); + + do + { + m_identifier.Append(*m_itr); + m_itr++; + } + while(ISMDAID(*m_itr)); + + m_identifier.Append(W("\0")); + return MdaFilterIdentifier; + } + + WCHAR c = *m_itr; + m_itr++; + switch(c) + { + case W('.'): return MdaFilterDot; + case W(':'): return MdaFilterColon; + case W('*'): return MdaFilterAstrix; + case W('+'): return MdaFilterPlus; + } + + return MdaFilterEnd; +} + +// +// MdaXPath::MdaXPathCompiler -- Parser +// +BOOL MdaQuery::Compiler::Compile(SString* sszQuery, CompiledQuery* pAst) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + m_itr = sszQuery->Begin(); + + NextToken(); + BOOL bResult = NAME(pAst); + + return bResult; +} + +// NAME +// '*' +// id +// id '.' NAME +// id '+' NESTNAME +// id ':' ':' NESTNAME +BOOL MdaQuery::Compiler::NAME(CompiledQuery* pAst) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (TokenIs(MdaFilterIdentifier)) + { + pAst->SetName(GetIdentifier()); + + NextToken(); + if (TokenIs(MdaFilterDot)) + { + NextToken(); + return NAME(pAst); + } + else if (TokenIs(MdaFilterPlus)) + { + NextToken(); + return NESTNAME(pAst); + } + else if (TokenIs(MdaFilterColon)) + { + NextToken(); + if (!TokenIs(MdaFilterColon)) + return FALSE; + + NextToken(); + return MEMBERNAME(pAst); + } + } + else if (TokenIs(MdaFilterAstrix)) + { + pAst->SetAnyType(); + NextToken(); + } + else return FALSE; + + return TRUE; +} + +// NESTNAME +// id '+' NESTNAME +// id ':' ':' NESTNAME +BOOL MdaQuery::Compiler::NESTNAME(CompiledQuery* pAst) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (!TokenIs(MdaFilterIdentifier)) + return FALSE; + + pAst->SetNestedTypeName(GetIdentifier()); + + NextToken(); + + if (TokenIs(MdaFilterPlus)) + { + NextToken(); + return NESTNAME(pAst); + } + else if (TokenIs(MdaFilterColon)) + { + NextToken(); + if (!TokenIs(MdaFilterColon)) + return FALSE; + + NextToken(); + return MEMBERNAME(pAst); + } + else return FALSE; +} + +// MEMBERNAME +// '*' +// id +BOOL MdaQuery::Compiler::MEMBERNAME(CompiledQuery* pAst) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (TokenIs(MdaFilterIdentifier)) + pAst->SetMemberName(GetIdentifier()); + + else if (TokenIs(MdaFilterAstrix)) + pAst->SetAnyMember(); + + else return FALSE; + + NextToken(); + return TRUE; +} + + +// +// MdaXmlElement +// +MdaXmlElement* MdaXmlElement::GetChild(MdaElemDeclDef declDef) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + for(COUNT_T i = 0; i < m_children.GetCount(); i ++) + { + if (m_children[i]->GetDeclDef() == declDef) + return m_children[i]; + } + + return NULL; +} + +SString* MdaXmlElement::ToXml(SString* pXml, LPCWSTR ns, INT32 depth) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + PRECONDITION(depth < 60); // Trap for recursion + } + CONTRACTL_END; + + // Indent + for (INT32 i = 0; i < depth; i ++) + pXml->Append(W(" ")); + + pXml->Append(W("<")); + if (ns && IsDefinition()) { pXml->Append(ns); pXml->Append(W(":")); } + pXml->Append(GetName()); + + if (m_attributes.GetCount() != 0) + { + for (COUNT_T i = 0; i < m_defaultAttrIndex && i < m_attributes.GetCount(); i ++) + { + pXml->Append(W(" ")); + m_attributes[i]->ToXml(pXml); + } + } + + if (m_children.GetCount() == 0) + { + if (GetDeclDef() == MdaElemComment) + { + pXml->Append(W(" ")); + pXml->Append(m_szName.GetUnicode()); + pXml->Append(W(" -->\n")); + } + else + pXml->Append(W("/>\n")); + } + else + { + pXml->Append(W(">")); + + SArray<MdaXmlElement*>::Iterator itr = m_children.Begin(); + SArray<MdaXmlElement*>::Iterator end = m_children.End(); + + pXml->Append(W("\n")); + while (itr != end) + { + (*itr)->ToXml(pXml, ns, depth + 1); + itr++; + } + + // Indent + for (INT32 i = 0; i < depth; i ++) + pXml->Append(W(" ")); + + pXml->Append(W("</")); + if (ns && IsDefinition()) { pXml->Append(ns); pXml->Append(W(":")); } + pXml->Append(GetName()); + pXml->Append(W(">\n")); + } + + + return pXml; +} + +LPCWSTR MdaXmlElement::DebugToString(SString* pBuffer) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + pBuffer->Append(W("<")); + pBuffer->Append(GetName()); + + for(COUNT_T i = 0; i < GetAttributes().GetCount(); i++) + { + pBuffer->Append(W(" ")); + GetAttributes()[i]->ToXml(pBuffer); + } + + pBuffer->Append(W("/>")); + return pBuffer->GetUnicode(); +} + +MdaXmlElement* MdaXmlElement::SetName(LPCWSTR name, BOOL bAssertDefined) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + SetDeclDef(MdaSchema::GetElementType(name, bAssertDefined)); + + if (GetDeclDef() == MdaElemUndefined) + m_szName.Set(name); + + return this; +} + +MdaXmlAttribute* MdaXmlElement::AddAttribute(MdaAttrDeclDef declDef) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + return AddAttribute(m_pXmlIndustry->CreateAttribute()->SetDeclDef(declDef)); +} + +MdaXmlAttribute* MdaXmlElement::AddAttribute(LPCWSTR szName, LPCWSTR szValue) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + return AddAttribute(m_pXmlIndustry->CreateAttribute()->Initialize(szName, szValue)); +} + +MdaXmlAttribute* MdaXmlElement::AddDefaultAttribute(MdaAttrDeclDef attrDeclDef, LPCWSTR szValue) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (m_defaultAttrIndex == -1) + m_defaultAttrIndex = m_attributes.GetCount(); + MdaXmlAttribute* pAttr = AddAttribute(attrDeclDef)->SetSString(szValue); + pAttr->m_type = MdaSchemaPrimitiveUnknown; + return pAttr; +} + +MdaXmlElement* MdaXmlElement::AddChild(MdaXmlElement* pChild) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + //PRECONDITION(m_elemDeclDef != MdaElemUndefined); + PRECONDITION(CheckPointer(pChild)); + PRECONDITION(CheckPointer(pChild->m_pXmlIndustry)); + + *m_children.Append() = pChild; + return pChild; +} + +MdaXmlElement* MdaXmlElement::AddChild(LPCWSTR name, BOOL bAssertDefined) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + return AddChild(m_pXmlIndustry->CreateElement())->SetName(name, bAssertDefined); +} + +MdaXmlElement* MdaXmlElement::AddChild(MdaElemDeclDef type) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + return AddChild(m_pXmlIndustry->CreateElement()->SetDeclDef(type)); +} + +LPCWSTR MdaXmlElement::GetName() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (GetDeclDef() == MdaElemUndefined) + return m_szName.GetUnicode(); + + return MdaSchema::GetElementName(m_elemDeclDef); +} + +MdaXmlAttribute* MdaXmlElement::GetAttribute(MdaAttrDeclDef attrDeclDef) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + + for(UINT32 i = 0; i < m_attributes.GetCount(); i++) + { + if (attrDeclDef == m_attributes[i]->GetDeclDef()) + return m_attributes[i]; + } + + return NULL; +} + +BOOL MdaXmlElement::GetAttributeValueAsBool(MdaAttrDeclDef attrDeclDef, BOOL bDefault) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + MdaXmlAttribute* pAttr = GetAttribute(attrDeclDef); + + if (!pAttr) + return bDefault; + + return pAttr->GetValueAsBool(); +} + +BOOL MdaXmlElement::GetAttributeValueAsBool(MdaAttrDeclDef attrDeclDef) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + MdaXmlAttribute* pAttr = GetAttribute(attrDeclDef); + PREFIX_ASSUME(pAttr != NULL); + ASSERT(pAttr); + return pAttr->GetValueAsBool(); +} + +// +// MdaXmlAttribute +// + +SString* MdaXmlAttribute::ToXml(SString* xml) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + SString sszBuffer; + + xml->Append(GetName()); + if (!m_szNs.IsEmpty()) + { + xml->Append(W(":")); + xml->Append(m_szNs.GetUnicode()); + } + + xml->Append(W("=\"")); + if (m_type == MdaSchemaPrimitiveSString) + xml->Append(MdaXmlEscape(sszBuffer, m_value)); + else if (m_type == MdaSchemaPrimitiveBOOL) + xml->Append(m_bool ? W("true") : W("false")); + else if (m_type == MdaSchemaPrimitiveINT32) + { + StackSString sszOutput; + sszOutput.Printf(W("%d"), m_int); + xml->Append(sszOutput); + } + xml->Append(W("\"")); + return xml; +} + +LPCWSTR MdaXmlAttribute::GetName() +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + if (m_declDef != MdaAttrUndefined) + return MdaSchema::GetAttributeName(m_declDef); + + return m_szName.GetUnicode(); +} + +MdaXmlAttribute* MdaXmlAttribute::Initialize(LPCWSTR szName, LPCWSTR szValue) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + m_type = MdaSchemaPrimitiveUnknown; + m_value.Set(szValue); + + SetDeclDef(MdaSchema::GetAttributeType(szName, FALSE)); + if (m_declDef == MdaAttrUndefined) + m_szName.Set(szName); + + return this; +} + + +// +// MdaConfigFactory +// +STDAPI GetXMLObjectEx(IXMLParser **ppv); + +MdaXmlElement* MdaConfigFactory::ParseXmlStream(MdaXmlIndustry* pXmlIndustry, LPCWSTR pszFileName) +{ + CONTRACT(MdaXmlElement*) + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACT_END; + + HRESULT hr = S_OK; + MdaXmlElement* pRoot = NULL; + + EX_TRY + { + { + if (!pszFileName) + goto Exit; + + NonVMComHolder<IXMLParser> pIXMLParser(NULL); + NonVMComHolder<IStream> pFile(NULL); + + hr = CreateConfigStream(pszFileName, &pFile); + if(FAILED(hr)) goto Exit; + + hr = GetXMLObjectEx(&pIXMLParser); + if(FAILED(hr)) goto Exit; + + hr = pIXMLParser->SetInput(pFile); // filestream's RefCount=2 + if ( ! SUCCEEDED(hr)) + goto Exit; + + pRoot = pXmlIndustry->CreateElement()->SetDeclDef(MdaElemDef(Dummy)); + MdaConfigFactory mdaConfigFactory(pRoot); + + hr = pIXMLParser->SetFactory(&mdaConfigFactory); // factory's RefCount=2 + if (!SUCCEEDED(hr)) + goto Exit; + + hr = pIXMLParser->Run(-1); + + if (pRoot->GetChildren().GetCount() == 1) + pRoot = pRoot->GetChildren()[0]; + else + pRoot = NULL; + } + Exit: ; + } + EX_CATCH + { + } + EX_END_CATCH(SwallowAllExceptions); + + if (hr == (HRESULT)XML_E_MISSINGROOT) + hr = S_OK; + else if (Assembly::FileNotFound(hr)) + hr = S_FALSE; + + RETURN pRoot; +} + +HRESULT STDMETHODCALLTYPE MdaConfigFactory::CreateNode( + IXMLNodeSource* pSource, + PVOID pNodeParent, + USHORT cNumRecs, + XML_NODE_INFO** apNodeInfo) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + m_pMdaXmlElement = NULL; + + for(INT32 i = 0; i < cNumRecs; i++) + { + DWORD dwType = apNodeInfo[i]->dwType; + + if(dwType == XML_ELEMENT || dwType == XML_ATTRIBUTE) + { + StackSString sszName((WCHAR*)apNodeInfo[i]->pwcText, apNodeInfo[i]->ulLen); + + if (dwType == XML_ELEMENT) + { + m_pMdaXmlElement = m_stack.Tos()->AddChild(sszName, FALSE); + } + else if (dwType == XML_ATTRIBUTE) + { + i++; + InlineSString<MDA_BUFFER_SIZE> szValue((WCHAR*)apNodeInfo[i]->pwcText, apNodeInfo[i]->ulLen); + + if (m_pMdaXmlElement) + m_pMdaXmlElement->AddAttribute(sszName.GetUnicode(), szValue); + } + } + } + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE MdaConfigFactory::BeginChildren( + IXMLNodeSource* pSource, + XML_NODE_INFO* pNodeInfo) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + m_stack.Push(m_pMdaXmlElement); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE MdaConfigFactory::EndChildren( + IXMLNodeSource* pSource, + BOOL fEmptyNode, + XML_NODE_INFO* pNodeInfo) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + + if (fEmptyNode) + return S_OK; + + m_stack.Pop(); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE MdaConfigFactory::NotifyEvent( + IXMLNodeSource* pSource, + XML_NODEFACTORY_EVENT iEvt) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE MdaConfigFactory::Error( + IXMLNodeSource* pSource, + HRESULT hrErrorCode, + USHORT cNumRecs, + XML_NODE_INFO** apNodeInfo) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + return E_FAIL; +} + +#endif |