/*++ // Copyright (c) 1998-2001 Microsoft Corporation, All Rights Reserved Module Name: ActualParse.CPP Abstract: Implements the object path parser engine History: a-davj 11-feb-00 Created. --*/ #include "precomp.h" #include #include "opathlex2.h" #include "PathParse.h" #include "ActualParse.h" #include "commain.h" //#include "resource.h" #include "wbemcli.h" #include #include "helpers.h" //*************************************************************************** // // CActualPathParser // //*************************************************************************** LPWSTR CActualPathParser::GetRelativePath(LPWSTR wszFullPath) { // We need the last colon, if any LPWSTR wszTemp = wcschr(wszFullPath, L':'); while (wszTemp != NULL) { LPWSTR wszSave = wszTemp; wszTemp++; wszTemp = wcschr(wszTemp, L':'); if (!wszTemp) { wszTemp = wszSave; break; } } if (wszTemp) return wszTemp + 1; else return NULL; } void CActualPathParser::Zero() { m_nCurrentToken = 0; m_pLexer = 0; m_pInitialIdent = 0; m_pOutput = 0; m_pTmpKeyRef = 0; } CActualPathParser::CActualPathParser(DWORD eFlags) : m_eFlags(eFlags) { Zero(); } void CActualPathParser::Empty() { delete m_pLexer; delete m_pInitialIdent; delete m_pTmpKeyRef; // m_pOutput is intentionally left alone, // since all code paths delete this already on error, or // else the user acquired the pointer. } CActualPathParser::~CActualPathParser() { Empty(); } int CActualPathParser::Parse( LPCWSTR pRawPath, CDefPathParser & Output ) { DWORD dwTest = m_eFlags & ~WBEMPATH_TREAT_SINGLE_IDENT_AS_NS; if(dwTest != WBEMPATH_CREATE_ACCEPT_RELATIVE && dwTest != WBEMPATH_CREATE_ACCEPT_ABSOLUTE && dwTest != WBEMPATH_CREATE_ACCEPT_ALL) return CActualPathParser::InvalidParameter; if (pRawPath == 0 || wcslen(pRawPath) == 0) return CActualPathParser::InvalidParameter; // Check for leading / trailing ws. // ================================ if (iswspace(pRawPath[wcslen(pRawPath)-1]) || iswspace(pRawPath[0])) return InvalidParameter; // These are required for multiple calls to Parse(). // ================================================== Empty(); Zero(); m_pOutput = &Output; // Parse the server name (if there is one) manually // ================================================ if ( (pRawPath[0] == '\\' && pRawPath[1] == '\\') || (pRawPath[0] == '/' && pRawPath[1] == '/')) { const WCHAR* pwcStart = pRawPath + 2; // Find the next backslash --- it's the end of the server name // Since the next slash can be either, search for both and take // the first one. If the first character is a '[', then then // end is indicated by a ']' // ============================================================ WCHAR* pwcEnd = NULL; if(*pwcStart == L'[') { // look for the ']' WCHAR * pCloseBrace = wcschr(pwcStart, L']'); if(pCloseBrace == NULL) return SyntaxError; pwcEnd = pCloseBrace+1; } else { WCHAR* pwcNextBack = wcschr(pwcStart, L'\\'); WCHAR* pwcNextForward = wcschr(pwcStart, L'/'); pwcEnd = pwcNextBack; if(pwcEnd == NULL) pwcEnd = pwcNextForward; else if(pwcNextForward && (pwcNextForward < pwcNextBack)) pwcEnd = pwcNextForward; } if (pwcEnd == NULL) { // If we have already exhausted the object path string, // a lone server name was all there was. // ==================================================== if ((m_eFlags & WBEMPATH_CREATE_ACCEPT_ALL) == 0) { return SyntaxError; } else // A lone server name is legal. { m_pOutput->SetServer(pwcStart); return NoError; } } if(pwcEnd == pwcStart) { // No name at all. // =============== return SyntaxError; } WCHAR * wTemp = new WCHAR[pwcEnd-pwcStart+1]; if(wTemp == NULL) return NoMemory; wcsncpy(wTemp, pwcStart, pwcEnd-pwcStart); wTemp[pwcEnd-pwcStart] = 0; m_pOutput->SetServer(wTemp, false, true); pRawPath = pwcEnd; } // Point the lexer at the source. // ============================== CTextLexSource src((LPWSTR)pRawPath); { AutoClear ac(this); m_pLexer = new CGenLexer(OPath_LexTable2, &src); if(m_pLexer == NULL) return NoMemory; Output.m_pGenLex = m_pLexer; // TEST CODE // Go. // === int nRes = begin_parse(); if (nRes) { return nRes; } if (m_nCurrentToken != OPATH_TOK_EOF) { return SyntaxError; } if (m_pOutput->GetNumComponents() > 0 && !m_pOutput->HasServer()) { if ( ! ( m_eFlags & WBEMPATH_CREATE_ACCEPT_RELATIVE ) && ! ( m_eFlags & WBEMPATH_CREATE_ACCEPT_ALL ) ) { return SyntaxError; } else { // Local namespace --- set server to "." // ===================================== m_pOutput->SetServer(L".", true, false); } } } Output.SortKeys(); // Add in key refs. // ================ return NoError; } BOOL CActualPathParser::NextToken() { m_nCurrentToken = m_pLexer->NextToken(); if (m_nCurrentToken == OPATH_TOK_ERROR) return FALSE; return TRUE; } // // ::= BACKSLASH ; // ::= IDENT ; // ::= COLON ; // int CActualPathParser::begin_parse() { if (!NextToken()) return SyntaxError; if (m_nCurrentToken == OPATH_TOK_BACKSLASH) { if (!NextToken()) return SyntaxError; return ns_or_server(); } else if (m_nCurrentToken == OPATH_TOK_IDENT) { m_pInitialIdent = Macro_CloneLPWSTR(m_pLexer->GetTokenText()); if(m_pInitialIdent == NULL) return NoMemory; if (!NextToken()) return SyntaxError; // Copy the token and put it in a temporary holding place // until we figure out whether it is a namespace or a class name. // ============================================================== return ns_or_class(); } else if (m_nCurrentToken == OPATH_TOK_COLON) { // A colon may indicate a namespace now... if (!NextToken()) return SyntaxError; return ns_or_class(); } // If here, we had a bad starter token. // ==================================== return SyntaxError; } // // ::= IDENT ; // int CActualPathParser::ns_or_server() { if (m_nCurrentToken == OPATH_TOK_BACKSLASH) { // Actually, server names have been take care of, so this is a failure // =================================================================== return SyntaxError; } else if (m_nCurrentToken == OPATH_TOK_IDENT) { return ns_list(); } else if (m_nCurrentToken == OPATH_TOK_EOF) return NoError; return SyntaxError; } // ::= COLON ; // ::= BACKSLASH ; // ::= ; // ::= ; int CActualPathParser::ns_or_class() { if (m_nCurrentToken == OPATH_TOK_COLON) { ident_becomes_ns(); if (!NextToken()) return SyntaxError; int nRes = objref(); if (nRes) return nRes; if ((m_nCurrentToken != OPATH_TOK_EOF)) return optional_scope_class_list(); return NoError; } else if (m_nCurrentToken == OPATH_TOK_BACKSLASH) { ident_becomes_ns(); if (!NextToken()) return SyntaxError; return ns_list(); } else if ((m_nCurrentToken == OPATH_TOK_EOF) && (m_eFlags & WBEMPATH_TREAT_SINGLE_IDENT_AS_NS)) { return ident_becomes_ns(); } // Else // ==== ident_becomes_class(); if(objref_rest()) return SyntaxError; else return optional_scope_class_list(); } // ::= COLON // ::= <> int CActualPathParser::optional_scope_class_list() { if (m_nCurrentToken == OPATH_TOK_EOF) return NoError; else if (m_nCurrentToken == OPATH_TOK_COLON) { if (!NextToken()) return SyntaxError; if (objref() == NoError) return optional_scope_class_list(); return SyntaxError; } return NoError; } // // ::= IDENT ; // IDENT is classname // int CActualPathParser::objref() { if (m_nCurrentToken != OPATH_TOK_IDENT) return SyntaxError; m_pOutput->AddClass(m_pLexer->GetTokenText()); if (!NextToken()) return SyntaxError; return objref_rest(); } // // ::= IDENT ; // int CActualPathParser::ns_list() { if (m_nCurrentToken == OPATH_TOK_IDENT) { m_pOutput->AddNamespace(m_pLexer->GetTokenText()); if (!NextToken()) return SyntaxError; return ns_list_rest(); } return SyntaxError; } // // ::= <>; // becomes a namespace // int CActualPathParser::ident_becomes_ns() { m_pOutput->AddNamespace(m_pInitialIdent); delete m_pInitialIdent; m_pInitialIdent = 0; return NoError; } // // ::= <>; // becomes the class // int CActualPathParser::ident_becomes_class() { m_pOutput->AddClass(m_pInitialIdent); delete m_pInitialIdent; m_pInitialIdent = 0; return NoError; } // // ::= EQUALS ; // ::= EQUALS @; // ::= DOT ; // ::= <>; // int CActualPathParser::objref_rest() { if (m_nCurrentToken == OPATH_TOK_EQ) { if (!NextToken()) return SyntaxError; // Take care of the singleton case. This is a path of the form // MyClass=@ and represents a singleton instance of a class with no // keys. if(m_nCurrentToken == OPATH_TOK_SINGLETON_SYM) { NextToken(); m_pOutput->SetSingletonObj(); return NoError; } m_pTmpKeyRef = new CKeyRef; if(m_pTmpKeyRef == NULL) return NoMemory; int nRes = key_const(); if (nRes) { delete m_pTmpKeyRef; m_pTmpKeyRef = 0; return nRes; } m_pOutput->AddKeyRef(m_pTmpKeyRef); m_pTmpKeyRef = 0; } else if (m_nCurrentToken == OPATH_TOK_DOT) { if (!NextToken()) return SyntaxError; return keyref_list(); } return NoError; } // // ::= BACKSLASH ; // ::= COLON ; // ::= <>; int CActualPathParser::ns_list_rest() { if (m_nCurrentToken == OPATH_TOK_BACKSLASH) { if (!NextToken()) return SyntaxError; return ns_list(); } else if (m_nCurrentToken == OPATH_TOK_COLON) { if (!NextToken()) return SyntaxError; if (objref() == NoError) return optional_scope_class_list(); return SyntaxError; } return NoError; } // // ::= STRING_CONST; // ::= INTEGRAL_CONST; // ::= REAL_CONST; // ::= IDENT; // Where IDENT is "OBJECT" for singleton classes // int CActualPathParser::key_const() { // If here, we have a key constant. // We may or may not have the property name // associated with it. // ======================================== if (m_nCurrentToken == OPATH_TOK_QSTRING) { int iNumByte = 2*(wcslen(m_pLexer->GetTokenText()) +1); m_pTmpKeyRef->SetData(CIM_STRING, iNumByte, m_pLexer->GetTokenText()); } else if (m_nCurrentToken == OPATH_TOK_REFERENCE) { int iNumByte = 2*(wcslen(m_pLexer->GetTokenText()) +1); m_pTmpKeyRef->SetData(CIM_REFERENCE, iNumByte, m_pLexer->GetTokenText()); } else if (m_nCurrentToken == OPATH_TOK_INT) { if(*(m_pLexer->GetTokenText()) == L'-') { __int64 llVal = _wtoi64(m_pLexer->GetTokenText()); if(llVal > 2147483647 || llVal < -(__int64)2147483648) m_pTmpKeyRef->SetData(CIM_SINT64, 8, &llVal); else m_pTmpKeyRef->SetData(CIM_SINT32, 4, &llVal); } else { unsigned __int64 ullVal; if(0 == swscanf(m_pLexer->GetTokenText(), L"%I64u", &ullVal)) return SyntaxError; if(ullVal < 2147483648) m_pTmpKeyRef->SetData(CIM_SINT32, 4, &ullVal); else if(ullVal > 0xffffffff) m_pTmpKeyRef->SetData(CIM_UINT64, 8, &ullVal); else m_pTmpKeyRef->SetData(CIM_UINT32, 4, &ullVal); } } else if (m_nCurrentToken == OPATH_TOK_HEXINT) { unsigned __int64 ullVal; if(0 ==swscanf(m_pLexer->GetTokenText(),L"%I64x", &ullVal)) return SyntaxError; m_pTmpKeyRef->SetData(CIM_UINT64, 8, &ullVal); } else if (m_nCurrentToken == OPATH_TOK_IDENT) { if (_wcsicmp(m_pLexer->GetTokenText(), L"TRUE") == 0) { long lVal = 1; m_pTmpKeyRef->SetData(CIM_BOOLEAN, 4, &lVal); } else if (_wcsicmp(m_pLexer->GetTokenText(), L"FALSE") == 0) { long lVal = 0; m_pTmpKeyRef->SetData(CIM_BOOLEAN, 4, &lVal); } else return SyntaxError; } else return SyntaxError; if (!NextToken()) return SyntaxError; return NoError; } // // ::= ; // int CActualPathParser::keyref_list() { int nRes = keyref(); if (nRes) return nRes; return keyref_term(); } // // ::= EQUALS ; // int CActualPathParser::keyref() { m_pTmpKeyRef = new CKeyRef; if(m_pTmpKeyRef == NULL) return NoMemory; int nRes = propname(); if (nRes) { delete m_pTmpKeyRef; m_pTmpKeyRef = 0; return nRes; } if (m_nCurrentToken != OPATH_TOK_EQ) { delete m_pTmpKeyRef; m_pTmpKeyRef = 0; return SyntaxError; } if (!NextToken()) { delete m_pTmpKeyRef; m_pTmpKeyRef = 0; return SyntaxError; } nRes = key_const(); if (nRes) { delete m_pTmpKeyRef; m_pTmpKeyRef = 0; return nRes; } m_pOutput->AddKeyRef(m_pTmpKeyRef); m_pTmpKeyRef = 0; return NoError; } // // ::= COMMA ; // Used for compound keys // ::= <>; // int CActualPathParser::keyref_term() { if (m_nCurrentToken == OPATH_TOK_COMMA) { if (!NextToken()) return SyntaxError; return keyref_list(); } return NoError; } // // ::= IDENT; // int CActualPathParser::propname() { if (m_nCurrentToken != OPATH_TOK_IDENT) return SyntaxError; m_pTmpKeyRef->m_pName = Macro_CloneLPWSTR(m_pLexer->GetTokenText()); if (!m_pTmpKeyRef->m_pName) return NoMemory; if (!NextToken()) { delete m_pTmpKeyRef; m_pTmpKeyRef = 0; return SyntaxError; } return NoError; }