PARSE.CPP
/*++ 
 
Copyright (c) 1996 Microsoft Corporation 
 
Module Name: 
 
    Parse.cpp 
 
Abstract: 
 
    DS Pathname Parser 
 
    The Pathname Parser is a key component in ADs providers. It checks for 
    syntactic validity of an ADs pathname that has been passed to this 
    provider. If the syntax is valid, then an OBJECTINFO structure is 
    constructed. This OBJECTINFO structure contains a componentized version 
    of the ADs pathname for this object. 
 
    Note all that is being done is a syntax check. Rather than special-case 
    every single new nuance to pathnames, all path checking must conform to 
    the grammar rules laid out by the parser. 
 
Author: 
 
Environment: 
 
    User mode 
 
Revision History : 
 
--*/ 
#include "adssmp.h" 
#pragma hdrstop 
 
//+--------------------------------------------------------------------------- 
//  Function:   ADsObject 
// 
//  Synopsis:   parses an ADs pathname passed to this provider. This function 
//              parses the following grammar rules 
// 
//              <ADsObject> -> <ProviderName> <SampleDSObject> 
// 
// 
//  Arguments:  [CLexer * pTokenizer] - a lexical analyzer object 
//              [POBJECTINFO pObjectInfo] - a pointer to an OBJECTINFO structure 
// 
//  Returns:    [HRESULT] 0 if successful, error HRESULT if not 
// 
//  Modifies:   pTokenizer (consumes the input buffer) 
// 
//---------------------------------------------------------------------------- 
HRESULT 
ADsObject(CLexer * pTokenizer, POBJECTINFO pObjectInfo) 
{ 
    WCHAR szToken[MAX_TOKEN_LENGTH]; 
    DWORD dwToken; 
    HRESULT hr; 
 
    hr = ProviderName(pTokenizer, pObjectInfo); 
    BAIL_IF_ERROR(hr); 
 
    hr = pTokenizer->GetNextToken(szToken, &dwToken); 
    BAIL_IF_ERROR(hr); 
 
    switch (dwToken) { 
 
    case TOKEN_END: 
        RRETURN(S_OK); 
 
    case TOKEN_COMMA: 
        hr = Type(pTokenizer, pObjectInfo); 
        BAIL_IF_ERROR(hr); 
        hr = pTokenizer->GetNextToken(szToken, &dwToken); 
        BAIL_IF_ERROR(hr); 
        if (dwToken == TOKEN_END) { 
            RRETURN(S_OK); 
        }else { 
            RRETURN(E_ADS_BAD_PATHNAME); 
        } 
 
    default: 
        hr = pTokenizer->PushBackToken(); 
 
 
        hr = SampleDSObject(pTokenizer, pObjectInfo); 
        BAIL_IF_ERROR(hr); 
 
        hr = pTokenizer->GetNextToken(szToken, &dwToken); 
        BAIL_IF_ERROR(hr); 
 
        switch (dwToken) { 
        case TOKEN_END: 
            RRETURN(S_OK); 
 
        case TOKEN_COMMA: 
            hr = Type(pTokenizer, pObjectInfo); 
            BAIL_IF_ERROR(hr); 
            hr = pTokenizer->GetNextToken(szToken, &dwToken); 
            BAIL_IF_ERROR(hr); 
            if (dwToken == TOKEN_END) { 
                RRETURN(S_OK); 
            }else { 
                RRETURN(E_ADS_BAD_PATHNAME); 
            } 
 
        default: 
            RRETURN(E_FAIL); 
 
        } 
    } 
 
cleanup: 
    RRETURN(hr); 
 
} 
 
 
//+--------------------------------------------------------------------------- 
//  Function:   SampleDSObject 
// 
//  Synopsis:   parses an ADs pathname passed to this provider. This function 
//              parses the following grammar rules 
// 
//              <SampleDSObject> -> "\\""identifier""\" <SampleDSObject> 
// 
// 
//  Arguments:  [CLexer * pTokenizer] - a lexical analyzer object 
//              [POBJECTINFO pObjectInfo] - a pointer to an OBJECTINFO structure 
// 
//  Returns:    [HRESULT] 0 if successful, error HRESULT if not 
// 
//  Modifies:   pTokenizer (consumes the input buffer) 
// 
//  History:    11-3-95   krishnag     Created. 
// 
//---------------------------------------------------------------------------- 
HRESULT 
SampleDSObject(CLexer * pTokenizer, POBJECTINFO pObjectInfo) 
{ 
    WCHAR szToken[MAX_TOKEN_LENGTH]; 
    DWORD dwToken; 
    HRESULT hr; 
 
    hr = pTokenizer->GetNextToken(szToken, &dwToken); 
    BAIL_IF_ERROR(hr); 
    if ((dwToken != TOKEN_FSLASH) &&  (dwToken != TOKEN_BSLASH)) { 
        RRETURN(E_ADS_BAD_PATHNAME); 
    } 
 
 
    hr = pTokenizer->GetNextToken(szToken, &dwToken); 
    BAIL_IF_ERROR(hr); 
    if ((dwToken != TOKEN_FSLASH) && (dwToken != TOKEN_BSLASH)) { 
        RRETURN(E_ADS_BAD_PATHNAME); 
    } 
 
 
    hr = pTokenizer->GetNextToken(szToken, &dwToken); 
    BAIL_IF_ERROR(hr); 
    if (dwToken != TOKEN_IDENTIFIER) { 
        RRETURN(E_ADS_BAD_PATHNAME); 
    } 
 
    hr = AddRootRDN(pObjectInfo, szToken); 
    BAIL_IF_ERROR(hr); 
 
    hr = pTokenizer->GetNextToken(szToken, &dwToken); 
    BAIL_IF_ERROR(hr); 
 
    // 
    // If we get an TOKEN_END, then we have a tree name only \\<tree_name> 
    // 
 
    if (dwToken == TOKEN_END || dwToken == TOKEN_COMMA) { 
        hr = pTokenizer->PushBackToken(); 
        RRETURN(S_OK); 
    } 
 
    if ((dwToken != TOKEN_BSLASH) && (dwToken != TOKEN_FSLASH)) { 
        RRETURN(E_ADS_BAD_PATHNAME); 
    } 
 
    hr = PathName(pTokenizer, pObjectInfo); 
    BAIL_IF_ERROR(hr); 
 
cleanup: 
    RRETURN(hr); 
} 
 
HRESULT 
ProviderName(CLexer * pTokenizer, POBJECTINFO pObjectInfo) 
{ 
    WCHAR szToken[MAX_TOKEN_LENGTH]; 
    DWORD dwToken; 
    HRESULT hr; 
 
    hr = pTokenizer->GetNextToken(szToken, &dwToken); 
    BAIL_IF_ERROR(hr); 
 
    if (dwToken == TOKEN_ATSIGN) { 
 
        hr = pTokenizer->GetNextToken(szToken, &dwToken); 
        BAIL_IF_ERROR(hr); 
 
        if (dwToken != TOKEN_IDENTIFIER) { 
            RRETURN(E_ADS_BAD_PATHNAME); 
        } 
 
        hr = AddProviderName(pObjectInfo, szToken); 
 
        hr = pTokenizer->GetNextToken(szToken, &dwToken); 
        BAIL_IF_ERROR(hr); 
 
 
        if (dwToken != TOKEN_EXCLAMATION) { 
            RRETURN(E_ADS_BAD_PATHNAME); 
        } 
 
    }else if (dwToken == TOKEN_IDENTIFIER) { 
 
        hr = AddProviderName(pObjectInfo, szToken); 
 
        hr = pTokenizer->GetNextToken(szToken, &dwToken); 
        BAIL_IF_ERROR(hr); 
 
 
        if (dwToken != TOKEN_COLON) { 
            RRETURN(E_ADS_BAD_PATHNAME); 
        } 
 
    }else { 
        RRETURN(E_ADS_BAD_PATHNAME); 
    } 
 
    RRETURN(S_OK); 
 
cleanup: 
 
    RRETURN(hr); 
} 
 
 
// PathName -> Component \\ PathName 
// PathName -> Component 
HRESULT 
DsPathName(CLexer * pTokenizer, POBJECTINFO pObjectInfo) 
{ 
    WCHAR szToken[MAX_TOKEN_LENGTH]; 
    DWORD dwToken; 
    HRESULT hr; 
 
    hr = pTokenizer->GetNextToken(szToken, &dwToken); 
    BAIL_IF_ERROR(hr); 
    if ((dwToken != TOKEN_FSLASH) || (dwToken != TOKEN_BSLASH)) { 
        RRETURN(E_ADS_BAD_PATHNAME); 
    } 
 
 
    hr = pTokenizer->GetNextToken(szToken, &dwToken); 
    BAIL_IF_ERROR(hr); 
    if ((dwToken != TOKEN_FSLASH) || (dwToken != TOKEN_BSLASH)) { 
        RRETURN(E_ADS_BAD_PATHNAME); 
    } 
 
    hr = PathName(pTokenizer, pObjectInfo); 
    BAIL_IF_ERROR(hr); 
 
    RRETURN(S_OK); 
 
cleanup: 
 
    RRETURN(hr); 
} 
 
HRESULT 
PathName(CLexer * pTokenizer, POBJECTINFO pObjectInfo) 
{ 
    HRESULT hr; 
    WCHAR szToken[MAX_TOKEN_LENGTH]; 
    DWORD dwToken; 
 
    hr = Component(pTokenizer, pObjectInfo); 
    BAIL_IF_ERROR(hr); 
 
    hr = pTokenizer->GetNextToken(szToken, &dwToken); 
 
    if ((dwToken == TOKEN_BSLASH) || (dwToken == TOKEN_FSLASH)) { 
        RRETURN (PathName(pTokenizer, pObjectInfo)); 
    }else { 
        hr = pTokenizer->PushBackToken(); 
        RRETURN (S_OK); 
    } 
cleanup: 
    RRETURN(hr); 
} 
 
HRESULT 
Component(CLexer * pTokenizer, POBJECTINFO pObjectInfo) 
{ 
    WCHAR szValue[MAX_TOKEN_LENGTH]; 
    WCHAR szEqual[MAX_TOKEN_LENGTH]; 
    WCHAR szComponent[MAX_TOKEN_LENGTH]; 
    DWORD dwToken; 
    HRESULT hr; 
 
    hr = pTokenizer->GetNextToken(szComponent, &dwToken); 
    BAIL_IF_ERROR(hr); 
 
    if (dwToken != TOKEN_IDENTIFIER) { 
        RRETURN(E_ADS_BAD_PATHNAME); 
    } 
 
    hr = pTokenizer->GetNextToken(szEqual, &dwToken); 
    BAIL_IF_ERROR(hr); 
 
    if (dwToken == TOKEN_EQUAL) { 
 
        hr = pTokenizer->GetNextToken(szValue, &dwToken); 
        BAIL_IF_ERROR(hr); 
 
        if (dwToken != TOKEN_IDENTIFIER) { 
            RRETURN(E_ADS_BAD_PATHNAME); 
        } 
 
        hr = AddComponent(pObjectInfo, szComponent, szValue); 
        BAIL_IF_ERROR(hr); 
 
    }else { 
 
        hr = AddComponent(pObjectInfo, szComponent, NULL); 
        BAIL_IF_ERROR(hr); 
 
        hr = pTokenizer->PushBackToken(); 
        BAIL_IF_ERROR(hr); 
    } 
 
    RRETURN(S_OK); 
 
cleanup: 
    RRETURN(hr); 
} 
 
CLexer::CLexer(LPWSTR szBuffer): 
                _ptr(NULL), 
                _Buffer(NULL), 
                _dwLastTokenLength(0), 
                _dwLastToken(0), 
                _dwEndofString(0) 
{ 
    if (!szBuffer || !*szBuffer) { 
        return; 
    } 
    _Buffer = AllocProvStr(szBuffer); 
    _ptr = _Buffer; 
} 
 
CLexer::~CLexer() 
{ 
    FreeProvStr(_Buffer); 
} 
 
HRESULT 
CLexer::GetNextToken(LPWSTR szToken, LPDWORD pdwToken) 
{ 
    WCHAR c; 
    DWORD state = 0; 
    LPWSTR pch = szToken; 
 
    memset(szToken, 0, sizeof(WCHAR) * MAX_TOKEN_LENGTH); 
    _dwLastTokenLength = 0; 
    while (1) { 
        c = NextChar(); 
        switch (state) { 
        case  0: 
            *pch++ = c; 
            _dwLastTokenLength++; 
 
            if (c == L'\\') { 
                *pdwToken = TOKEN_BSLASH; 
                _dwLastToken = *pdwToken; 
                RRETURN(S_OK); 
            }else if (c == L'/') { 
                *pdwToken = TOKEN_FSLASH; 
                _dwLastToken = *pdwToken; 
                RRETURN(S_OK); 
            }else if (c == L',') { 
                *pdwToken = TOKEN_COMMA; 
                _dwLastToken = *pdwToken; 
                RRETURN(S_OK); 
            }else if (c == L'@'){ 
                *pdwToken = TOKEN_ATSIGN; 
                _dwLastToken = *pdwToken; 
                RRETURN(S_OK); 
            }else if (c == L'='){ 
                *pdwToken = TOKEN_EQUAL; 
                _dwLastToken = *pdwToken; 
                RRETURN(S_OK); 
            }else if (c == L'.'){ 
                *pdwToken = TOKEN_PERIOD; 
                _dwLastToken = *pdwToken; 
                RRETURN(S_OK); 
            }else if (c == L'!'){ 
                *pdwToken = TOKEN_EXCLAMATION; 
                _dwLastToken = *pdwToken; 
                RRETURN(S_OK); 
            }else if (c == L':'){ 
                *pdwToken = TOKEN_COLON; 
                _dwLastToken = *pdwToken; 
                RRETURN(S_OK); 
            }else if (c == L'\0'){ 
                *pdwToken = TOKEN_END; 
                _dwLastToken = *pdwToken; 
                RRETURN(S_OK); 
            }else { 
                state = 1; 
            } 
            break; 
 
        case 1: 
            if (c == L'\\' || c == L'\0' || c == L',' || 
                    c == L'@' || c == L'!'|| c == L'=' || c == L'.' || 
                    c == L':' || c == L'/') { 
                PushbackChar(); 
 
                *pdwToken = TOKEN_IDENTIFIER; 
                _dwLastToken = *pdwToken; 
                RRETURN (S_OK); 
            }else { 
                *pch++ = c; 
                _dwLastTokenLength++; 
                state = 1; 
                break; 
            } 
        default: 
            RRETURN(E_FAIL); 
        } 
    } 
} 
 
WCHAR 
CLexer::NextChar() 
{ 
    if (_ptr == NULL || *_ptr == L'\0') { 
        _dwEndofString = TRUE; 
        return(L'\0'); 
    } 
    return(*_ptr++); 
} 
 
HRESULT 
CLexer::PushBackToken() 
{ 
    if (_dwLastToken == TOKEN_END) { 
        RRETURN(S_OK); 
    } 
    _ptr -= _dwLastTokenLength; 
 
    RRETURN(S_OK); 
} 
 
 
void 
CLexer::PushbackChar() 
{ 
    if (_dwEndofString) { 
        return; 
    } 
    _ptr--; 
 
} 
 
BOOL 
CLexer::IsKeyword(LPWSTR szToken, LPDWORD pdwToken) 
{ 
    DWORD i = 0; 
 
    for (i = 0; i < MAX_KEYWORDS; i++) { 
        if (!_wcsicmp(szToken, KeywordList[i].Keyword)) { 
            *pdwToken = KeywordList[i].dwTokenId; 
            return(TRUE); 
        } 
    } 
    *pdwToken = 0; 
    return(FALSE); 
} 
 
HRESULT 
AddComponent(POBJECTINFO pObjectInfo, LPWSTR szComponent, LPWSTR szValue) 
{ 
    if (!szComponent || !*szComponent) { 
        RRETURN(E_FAIL); 
    } 
 
 
    if (pObjectInfo->NumComponents < MAXCOMPONENTS) { 
 
        pObjectInfo->ComponentArray[pObjectInfo->NumComponents].szComponent = 
                        AllocProvStr(szComponent); 
 
        pObjectInfo->ComponentArray[pObjectInfo->NumComponents].szValue = 
                        AllocProvStr(szValue); 
 
        pObjectInfo->NumComponents++; 
 
        RRETURN(S_OK); 
 
    }else { 
        RRETURN(E_FAIL); 
    } 
} 
 
HRESULT 
AddProviderName(POBJECTINFO pObjectInfo, LPWSTR szToken) 
{ 
    if (!szToken || !*szToken) { 
        RRETURN(E_FAIL); 
    } 
 
    pObjectInfo->ProviderName = AllocProvStr(szToken); 
 
    RRETURN(S_OK); 
} 
 
 
HRESULT 
AddRootRDN(POBJECTINFO pObjectInfo, LPWSTR szToken) 
{ 
    if (!szToken || !*szToken) { 
        RRETURN(E_FAIL); 
    } 
 
    pObjectInfo->RootRDN = AllocProvStr(szToken); 
 
    RRETURN(S_OK); 
} 
 
 
HRESULT 
SetType(POBJECTINFO pObjectInfo, DWORD dwToken) 
{ 
    pObjectInfo->ObjectType = dwToken; 
    RRETURN(S_OK); 
} 
 
 
// Type -> "user", "group","printer","service", "fileservice" 
 
//+--------------------------------------------------------------------------- 
// Function:    Type 
// 
// Synopsis:    Parses Type-> "user" | "group" etc 
// 
// Arguments:   [CLexer * pTokenizer] 
//              [POBJECTINFo pObjectInfo] 
// 
// Returns:     HRESULT 
// 
// Modifies:     
// 
// History:     
// 
//---------------------------------------------------------------------------- 
HRESULT 
Type(CLexer * pTokenizer, POBJECTINFO pObjectInfo) 
{ 
    WCHAR szToken[MAX_PATH]; 
    DWORD dwToken; 
    HRESULT hr; 
 
    hr = pTokenizer->GetNextToken(szToken, &dwToken); 
    BAIL_IF_ERROR(hr); 
 
    if (dwToken == TOKEN_IDENTIFIER ) { 
        RRETURN(hr); 
    } 
 
    RRETURN(E_FAIL); 
 
cleanup: 
    RRETURN(hr); 
}