/**@@@+++@@@@******************************************************************
**
** Microsoft Windows Media
** Copyright (C) Microsoft Corporation. All rights reserved.
**
***@@@---@@@@******************************************************************
*/

#include <drmcommon.h>
#include <drmutilities.h>
#include <drmcrt.h>
#include <drmcontextsizes.h>
#include <drmexpreval.h>
#include <drmliceval.h>
#include <drmlicenseparser.h>
#include <drmheaderparser.h>
#include <oemimpl.h>
#include <drmlicreason.h>

#if DRM_SUPPORT_ANTIROLLBACK_CLOCK
    #define C_SECONDS_IN_ROLLBACK_GRACE_PERIOD 30
#endif
#define C_TICS_PER_SECOND 10000000

DRM_RESULT DRM_API VariableDRMGetorSet       (const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet);
DRM_RESULT DRM_API VariableDRMKGetorSet      (const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet);
DRM_RESULT DRM_API VariableMachineGetorSet   (const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet);
DRM_RESULT DRM_API VariableAPPGetorSet       (const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet);
DRM_RESULT DRM_API VariableSecStateGetorSet  (const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet);
DRM_RESULT DRM_API VariableLicenseGetorSet   (const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet);
DRM_RESULT DRM_API VariableContentGetorSet   (const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet);
DRM_RESULT DRM_API VariableDeviceGetorSet    (const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet);
DRM_RESULT DRM_API VariablePMLicenseGetorSet (const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet);

#if DRM_SUPPORT_SECURE_CLOCK
DRM_RESULT DRM_API VariableSecureTimeGetorSet(const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet);
#endif

#if DRM_SUPPORT_PLAYLIST_BURN
DRM_RESULT DRM_API VariablePlaylistBurnGetorSet  (const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet);
#endif

#if DRM_SUPPORT_SST_REDUNANCY
DRM_RESULT DRM_API VariableSSTRedundancyGetorSet (const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet);
#endif

typedef DRM_RESULT  ( DRM_API *pfnGetorSetVariable)(const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet);

typedef struct tagDRM_VARIABLE_NAMESPACES
{
    const DRM_CONST_STRING *pdstrNamespace;
    pfnGetorSetVariable GetorSetVariable;    
} DRM_VARIABLE_NAMESPACES;

DRM_VARIABLE_NAMESPACES g_VariableNamespaces[] = 
{
    { &g_dstrDRM_PREFIX,          VariableDRMGetorSet       },
    { &g_dstrDRMK_PREFIX,         VariableDRMKGetorSet      },
    { &g_dstrMACHINE_PREFIX,      VariableMachineGetorSet   },
    { &g_dstrAPP_PREFIX,          VariableAPPGetorSet       },
    { &g_dstrSECSTATE_PREFIX,     VariableSecStateGetorSet  },
    { &g_dstrLICENSE_PREFIX,      VariableLicenseGetorSet   },
    { &g_dstrCONTENT_PREFIX,      VariableContentGetorSet   },
    { &g_dstrDEVICE_PREFIX,       VariableDeviceGetorSet    },
    { &g_dstrPMLICENSE_PREFIX,    VariablePMLicenseGetorSet },

#if DRM_SUPPORT_SECURE_CLOCK
    { &g_dstrSECURETIME_PREFIX,   VariableSecureTimeGetorSet },
#endif

#if DRM_SUPPORT_PLAYLIST_BURN
    { &g_dstrPLAYLISTBURN_PREFIX, VariablePlaylistBurnGetorSet },
#endif

#if DRM_SUPPORT_SST_REDUNANCY
    { &g_dstrSSTREDUNDANCY_PREFIX, VariableSSTRedundancyGetorSet },
#endif

};

DRM_RESULT DRM_API GlobalSetVariable(
    const DRM_CONST_STRING *pdstrToken, 
    TOKEN            *pNewValue, 
    TOKEN            *pResult, 
    DRM_VOID         *pvOpaqueData)
{
    DRM_UINT i,j;    

    /* Find the period first and use that to  */
    for( j=0; j<pdstrToken->cchString; j++ )
    {
        if( pdstrToken->pwszString[j] == g_wchPeriod )
        {
            j++;
            break;
        }
    }
    if( j < pdstrToken->cchString )
    {
        DRM_CONST_STRING dstrToken;
        
        dstrToken.pwszString = pdstrToken->pwszString + j;
        dstrToken.cchString  = pdstrToken->cchString  - j;
        for( i = 0; i < NO_OF( g_VariableNamespaces ); i++ )
        {
            if( j == g_VariableNamespaces[i].pdstrNamespace->cchString &&
                0 == DRM_wcsncmp(pdstrToken->pwszString, g_VariableNamespaces[i].pdstrNamespace->pwszString, j) )
            {                
                return g_VariableNamespaces[i].GetorSetVariable(&dstrToken, pNewValue, pResult, pvOpaqueData, TRUE ) ;
            }
        }
    }
    return CPRMEXP_INVALID_VARIABLE;
}

DRM_RESULT DRM_API GlobalGetVariable(const DRM_CONST_STRING* pdstrToken, TOKEN* pResult, DRM_VOID* pvOpaqueData)
{
    DRM_UINT i,j;    

    /* Find the g_wchPeriod first and use that to  */
    for( j=0; j<pdstrToken->cchString; j++ )
    {
        if( pdstrToken->pwszString[j] == g_wchPeriod )
        {
            j++;
            break;
        }
    }
    if( j < pdstrToken->cchString )
    {
        DRM_CONST_STRING dstrToken;
        dstrToken.pwszString = pdstrToken->pwszString + j;
        dstrToken.cchString = pdstrToken->cchString - j;
        for( i = 0; i < NO_OF( g_VariableNamespaces ); i++ )
        {
            if( j == g_VariableNamespaces[i].pdstrNamespace->cchString &&
                0 == DRM_wcsncmp(pdstrToken->pwszString, g_VariableNamespaces[i].pdstrNamespace->pwszString, j) )
            {                
                return g_VariableNamespaces[i].GetorSetVariable(&dstrToken, NULL, pResult, pvOpaqueData, FALSE ) ;
            }
        }
    }
    return CPRMEXP_INVALID_VARIABLE;
}


DRM_RESULT DRM_API VariableDRMKGetorSet(const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet)
{
    DRM_LICEVAL_CONTEXT* pLicEval = (DRM_LICEVAL_CONTEXT*) pvOpaqueData;

    if ( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarVersion, pdstrToken ) )
    {
        if( fSet )
        {
            return CPRMEXP_UPDATE_UNSUPPORTED;
        }
        if( pLicEval->dstrDRMKVer.pwszString && pLicEval->dstrDRMKVer.cchString )
        {
            pResult->TokenType = TOKEN_STRING;
            pResult->val.stringValue.pwszString = pLicEval->dstrDRMKVer.pwszString;
            pResult->val.stringValue.cchString = pLicEval->dstrDRMKVer.cchString;
        }
        else
        {
            return CPRMEXP_RETRIEVAL_FAILURE;
        }
    }
    else if ( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarParameter, pdstrToken ) )
    {
        if( fSet )
        {
            if( pNewValue->TokenType != TOKEN_STRING )
            {
                return CPRMEXP_WRONG_TYPE_OPERAND;
            }
            pLicEval->wszDRMKParam.pwszString = pNewValue->val.stringValue.pwszString;
            pLicEval->wszDRMKParam.cchString  = pNewValue->val.stringValue.cchString;
        }
        else if( NULL == pLicEval->wszDRMKParam.pwszString || 0 == pLicEval->wszDRMKParam.cchString )
        {
            return CPRMEXP_RETRIEVAL_FAILURE;
        }

        pResult->TokenType = TOKEN_STRING;
        pResult->val.stringValue.pwszString = pLicEval->wszDRMKParam.pwszString;
        pResult->val.stringValue.cchString = pLicEval->wszDRMKParam.cchString;
    }
    else
    {        
        return CPRMEXP_INVALID_VARIABLE;
    }

    return DRM_SUCCESS;
}


DRM_RESULT DRM_API VariableDRMGetorSet(const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet)
{
    DRM_LICEVAL_CONTEXT* pLicEval = (DRM_LICEVAL_CONTEXT*) pvOpaqueData;

    if( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarReason, pdstrToken ) )
    {
        if( !fSet )
        {
            return CPRMEXP_RETRIEVAL_FAILURE;
        }
        if( pNewValue->TokenType != TOKEN_LONG )
        {
            return CPRMEXP_WRONG_TYPE_OPERAND;
        }

        pResult->TokenType = TOKEN_LONG;
        pLicEval->lReasonForFail = pResult->val.lValue = pNewValue->val.lValue;
    }
    else if ( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarVersion, pdstrToken ) )
    {
        if( fSet )
        {
            return CPRMEXP_UPDATE_UNSUPPORTED;
        }
        if( pLicEval->dstrDRMVer.pwszString && pLicEval->dstrDRMVer.cchString )
        {
            pResult->TokenType = TOKEN_STRING;
            pResult->val.stringValue.pwszString = pLicEval->dstrDRMVer.pwszString;
            pResult->val.stringValue.cchString = pLicEval->dstrDRMVer.cchString;
        }
        else
        {
            return CPRMEXP_RETRIEVAL_FAILURE;
        }

    }
    else if ( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarBBMSDRMVersion, pdstrToken ) )
    {
        if( fSet )
        {
            return CPRMEXP_UPDATE_UNSUPPORTED;
        }
        if( pLicEval->dstrBBVer.pwszString && pLicEval->dstrBBVer.cchString )
        {
            pResult->TokenType = TOKEN_STRING;
            pResult->val.stringValue.pwszString = pLicEval->dstrBBVer.pwszString;
            pResult->val.stringValue.cchString = pLicEval->dstrBBVer.cchString;
        }
        else
        {
            return CPRMEXP_RETRIEVAL_FAILURE;
        }
    }
    else
    {
        return CPRMEXP_INVALID_VARIABLE;
    }

    return DRM_SUCCESS;
}

DRM_RESULT DRM_API VariableMachineGetorSet(const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet)
{
    DRM_RESULT dr = DRM_SUCCESS;
    DRM_LICEVAL_CONTEXT* pLicEval = (DRM_LICEVAL_CONTEXT*) pvOpaqueData;

    if( fSet )
    {
        return CPRMEXP_UPDATE_UNSUPPORTED;
    }

    if ( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarDateTime, pdstrToken ) )
    {
        TOKEN token;
        DRMFILETIME filetime = {0};

        if ( pLicEval->fIgnoreTimeBoundLicense )
        {
            pLicEval->lReasonForFail = LR_LICENSE_CLOCK_NOT_SET;
            return CPRMEXP_CLOCK_REQUIRED;
        }

        if (pLicEval->eTimeBasedState != LICEVAL_GRACEPERIODREFERENCED )
        {
            pLicEval->eTimeBasedState = LICEVAL_MACHINEDATETIMEREFERENCED;
        }
        
#if DRM_SUPPORT_ANTIROLLBACK_CLOCK
        dr = VariableSecStateGetorSet( &g_dstrSavedDateTime, NULL, &token, pvOpaqueData, FALSE );
#endif
        pResult->TokenType = TOKEN_DATETIME;
        OEM_GetDeviceTime(&filetime);
        FILETIME_TO_UI64( filetime, pResult->val.u64DateTime );
#if DRM_SUPPORT_ANTIROLLBACK_CLOCK
        if( dr == DRM_SUCCESS )
        {
            /* Compare for the grace period */
            if( DRM_UI64Les( pResult->val.u64DateTime, token.val.u64DateTime ) )
            {
                pResult->val.u64DateTime = DRM_UI64Sub( token.val.u64DateTime, pResult->val.u64DateTime );

                if( DRM_UI64Les( pResult->val.u64DateTime, DRM_UI64(C_SECONDS_IN_ROLLBACK_GRACE_PERIOD * C_TICS_PER_SECOND) ) )
                {
                    pResult->TokenType       = TOKEN_DATETIME;
                    pResult->val.u64DateTime = token.val.u64DateTime;
                }
            }
        }
#endif
    }
    else
    {
        return CPRMEXP_INVALID_VARIABLE;
    }
    return DRM_SUCCESS;
}

DRM_RESULT DRM_API VariableAPPGetorSet(const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet)
{
    DRM_RESULT dr                 = DRM_SUCCESS;
    DRM_LICEVAL_CONTEXT* pLicEval = (DRM_LICEVAL_CONTEXT*) pvOpaqueData;

    pResult->TokenType = TOKEN_LONG;

    if( fSet )
    {
        /* Set not allowed */
        dr = CPRMEXP_UPDATE_UNSUPPORTED;
    }
    else if( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarCount, pdstrToken ) )
    {
        if( pLicEval->fAppInfoValid )
        {
            pResult->val.lValue = 2;
        }
        else
        {
            pResult->val.lValue = 1;
        }            
    }
    else if( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarMinSecLevel, pdstrToken ) )
    {
        pResult->val.lValue = pLicEval->certinfoSDK.appSec;
        if( pLicEval->fAppInfoValid )
        {
            if( pLicEval->certinfoApp.appSec < pLicEval->certinfoSDK.appSec )
            {
                pResult->val.lValue = pLicEval->certinfoApp.appSec;
            }
        }
    }
    else if( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarSecLevel, pdstrToken ) )
    {
        pResult->val.lValue = pLicEval->certinfoSDK.appSec;
    }
    else if( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarAppSecLevel, pdstrToken ) )
    {
        if( pLicEval->fAppInfoValid )
        {
            pResult->val.lValue = pLicEval->certinfoApp.appSec;
        }
        else
        {
            pResult->val.lValue = pLicEval->certinfoSDK.appSec;
        }
    }
    else if( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarSubjID, pdstrToken ) )
    {
        pResult->val.lValue = pLicEval->certinfoSDK.appcd_subject;
    }
    else if( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarAppSubjID, pdstrToken ) )
    {
        if( pLicEval->fAppInfoValid )
        {
            pResult->val.lValue = pLicEval->certinfoApp.appcd_subject;
        }
        else
        {
            pResult->val.lValue = pLicEval->certinfoSDK.appcd_subject;
        }        
    }
    else
    {
        dr  = CPRMEXP_RETRIEVAL_FAILURE;
    }

    return dr;
}

DRM_RESULT DRM_API VariableSecStateGetorSet(const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet)
{
    DRM_RESULT dr = DRM_SUCCESS;
    DRM_LICEVAL_CONTEXT  *pLicEval  = (DRM_LICEVAL_CONTEXT*) pvOpaqueData;
    DRM_SECSTORE_CONTEXT *pbContext = NULL;
    DRM_CONST_STRING      dstrToken = EMPTY_DRM_STRING;

    dstrToken.pwszString = pdstrToken->pwszString;
    dstrToken.cchString  = pdstrToken->cchString;

    if( g_dstrExprVarGlobal.cchString < dstrToken.cchString &&
        DRM_wcsncmp( g_dstrExprVarGlobal.pwszString, dstrToken.pwszString, g_dstrExprVarGlobal.cchString ) == 0 )
    {
        /* Move the pointer past the globalstate string */
        dstrToken.pwszString += g_dstrExprVarGlobal.cchString;
        dstrToken.cchString  -= g_dstrExprVarGlobal.cchString;
        
        
        /* Look for both savedatetime and saveddatetime due to a bug in older WMRM versions */
        if( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarSaveDateTime, &dstrToken ) )
        {
            dstrToken.pwszString = g_dstrExprVarSavedDateTime.pwszString;
            dstrToken.cchString = g_dstrExprVarSavedDateTime.cchString;
        }

        /* It is a global state variable.  If this is a set call we have to check to see if set is available right now */
        if( fSet )
        {
            if( !pLicEval->fGlobalSecStoreWritable )
            {
                dr = CPRMEXP_UPDATE_FAILURE;
                goto ErrorExit;
            }
            else if( ( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarSavedDateTime, &dstrToken ) )&&
                    pNewValue->TokenType != TOKEN_DATETIME )
            {
                /* saveddatetime MUST be a DATE token */
                dr = CPRMEXP_WRONG_TYPE_OPERAND;
                goto ErrorExit;
            }
        }
        pbContext = pLicEval->pcontextSSTGlobal;
    }
#if DRM_SUPPORT_SECURE_CLOCK
    else if( g_dstrSECURETIME_PREFIX.cchString < dstrToken.cchString 
          && DRM_wcsncmp( g_dstrSECURETIME_PREFIX.pwszString, dstrToken.pwszString, g_dstrSECURETIME_PREFIX.cchString ) == 0 )

    {
        /* Move the pointer past the securetime string */
        dstrToken.pwszString += g_dstrSECURETIME_PREFIX.cchString;
        dstrToken.cchString  -= g_dstrSECURETIME_PREFIX.cchString;
        dr = VariableSecureTimeGetorSet( &dstrToken, pNewValue, pResult, pvOpaqueData, fSet);
        goto ErrorExit;
    }
#endif
    else
    {
        pbContext = pLicEval->pcontextSSTLicense;
    }

    if( NULL == pbContext )
    {
        dr = CPRMEXP_RETRIEVAL_FAILURE;
    }
    else if( fSet )
    {
        TOKEN tempToken;

        if( pNewValue->TokenType == TOKEN_STRING )
        {
            /* String types can not be assigned to secure store variables */
            dr = CPRMEXP_WRONG_TYPE_OPERAND;
            goto ErrorExit;
        }
        MEMCPY( &tempToken, pNewValue, SIZEOF( TOKEN ) );

        if( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarDRMReason, &dstrToken ) )
        {
            pLicEval->lReasonForFail = pNewValue->val.lValue;
        }
        else
        {
            dr = DRM_SST_SetTokenValue( pbContext, &dstrToken, &tempToken);
            if( DRM_FAILED( dr ) )
            {
                dr = CPRMEXP_UPDATE_FAILURE;
                goto ErrorExit;
            }
        }
        if( pResult )
        {
            MEMCPY( pResult, pNewValue, SIZEOF( TOKEN ) );
        }
    }
    else
    {
        dr = DRM_SST_GetTokenValue( pbContext, &dstrToken, pResult);
        if( DRM_FAILED(dr) || dr == DRM_S_FALSE )
        {
            dr = CPRMEXP_RETRIEVAL_FAILURE;
            goto ErrorExit;
        }
    }
    
ErrorExit:
    return dr;
}

DRM_RESULT DRM_API VariableLicenseGetorSet(const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet)
{
    DRM_RESULT dr = DRM_SUCCESS;
    DRM_LICEVAL_CONTEXT* pLicEval = (DRM_LICEVAL_CONTEXT*) pvOpaqueData;

    if( fSet )
    {
        /* Set not allowed */
        return CPRMEXP_UPDATE_UNSUPPORTED;
    }
    pResult->TokenType = TOKEN_STRING;
    if( NULL == pLicEval->dstrContentLicense.pwszString ||
        0 == pLicEval->dstrContentLicense.cchString ||
        DRM_FAILED( DRM_LIC_GetAttribute( &(pLicEval->dstrContentLicense), pdstrToken, DRM_LICENSE_ATTRIB_OTHER, NULL, &(pResult->val.stringValue), g_wchPeriod ) )
        )
    {
        dr = CPRMEXP_RETRIEVAL_FAILURE;
    }
    
    return dr;
}

DRM_RESULT DRM_API VariableContentGetorSet(const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet)
{
    DRM_RESULT dr = DRM_SUCCESS;
    DRM_LICEVAL_CONTEXT* pLicEval = (DRM_LICEVAL_CONTEXT*) pvOpaqueData;

    /* Use content header parsing to extract a property */
    if( fSet )
    {        
        return CPRMEXP_UPDATE_UNSUPPORTED;
    }
    pResult->TokenType = TOKEN_STRING;
    if( NULL == pLicEval->dstrContentHeader.pwszString ||
        0 == pLicEval->dstrContentHeader.cchString ||
        DRM_FAILED( DRM_HDR_GetAttribute( &(pLicEval->dstrContentHeader), pdstrToken, DRM_HEADER_ATTRIB_OTHER, &(pResult->val.stringValue), g_wchPeriod ) )
        )    
    {
        dr = CPRMEXP_RETRIEVAL_FAILURE;
    }
    
    return dr;
}

DRM_RESULT DRM_API VariableDeviceGetorSet(const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet)
{
    /* We are depricating the device namespace */
#if !DRM_SUPPORT_DEVICE_NAMESPACE
    return DRM_E_NOTIMPL;
#else

    DRM_LICEVAL_CONTEXT* pContext = (DRM_LICEVAL_CONTEXT*) pvOpaqueData;

    DRMASSERT( pContext != NULL );

    /* device-registered flag */
    if( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarDevReg, pdstrToken ) )
    {
        if( fSet )
        {
            if( pNewValue->TokenType != TOKEN_LONG )
            {
                return CPRMEXP_WRONG_TYPE_OPERAND;                
            }
            pContext->fDeviceRegistered = pNewValue->val.lValue;
        }
        pResult->TokenType  = TOKEN_LONG;
        pResult->val.lValue = pContext->fDeviceRegistered;
    }
    else
    {
        return CPRMEXP_RETRIEVAL_FAILURE;
    }

    return DRM_SUCCESS;

#endif

}

DRM_RESULT DRM_API VariablePMLicenseGetorSet(const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet)
{
#if !DRM_SUPPORT_PMLICENSE
    return DRM_E_NOTIMPL;
#else
    DRM_LICEVAL_CONTEXT* pContext = (DRM_LICEVAL_CONTEXT*) pvOpaqueData;

    DRMASSERT( pContext != NULL );

    if( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarRights, pdstrToken ) )
    {
        if( fSet )
        {
            if( pNewValue->TokenType != TOKEN_LONG )
            {
                return CPRMEXP_WRONG_TYPE_OPERAND;                
            }
            pContext->lPMRights = pNewValue->val.lValue;
        }
        pResult->TokenType = TOKEN_LONG;
        pResult->val.lValue    = pContext->lPMRights;
    }
    else if( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarExpiryDate, pdstrToken ) )
    {
        DRMFILETIME filetime;
        if( fSet )
        {            
            if( pNewValue->TokenType != TOKEN_DATETIME )
            {
                return CPRMEXP_WRONG_TYPE_OPERAND;                
            }
            UI64_TO_FILETIME( pNewValue->val.u64DateTime, filetime );
            if (!OEM_FileTimeToSystemTime(&filetime, &pContext->PMExpiryDate))
            {
                return CPRMEXP_UPDATE_FAILURE;
            }            
        }
        pResult->TokenType = TOKEN_DATETIME;
        if (!OEM_SystemTimeToFileTime(&pContext->PMExpiryDate, &filetime))
        {
            return CPRMEXP_RETRIEVAL_FAILURE; /* Should not happen. */            
        }
        FILETIME_TO_UI64(filetime, pResult->val.u64DateTime)
    }
    else if( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarAppSecLevel, pdstrToken ) )
    {
        if( fSet )
        {
            if( pNewValue->TokenType != TOKEN_LONG )
            {
                return CPRMEXP_WRONG_TYPE_OPERAND;                
            }
            pContext->lPMAppSec = pNewValue->val.lValue;
        }
        pResult->TokenType = TOKEN_LONG;
        pResult->val.lValue    = pContext->lPMAppSec;
    }
    else if( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarVersion, pdstrToken ) )
    {
        if( fSet )
        {
            return CPRMEXP_UPDATE_UNSUPPORTED;
        }

        if (pContext->pwszPMLicVersion && pContext->pwszPMLicVersion->cchString > 0)
        {
            pResult->TokenType = TOKEN_STRING;
            pResult->val.stringValue.cchString = pContext->pwszPMLicVersion->cchString;
            pResult->val.stringValue.pwszString = pContext->pwszPMLicVersion->pwszString;
        }
        else
        {
            return CPRMEXP_RETRIEVAL_FAILURE;             
        }
    }

    else
    {
        return CPRMEXP_RETRIEVAL_FAILURE;
    }

    return DRM_SUCCESS;
#endif
}

#if DRM_SUPPORT_SECURE_CLOCK
DRM_RESULT DRM_API VariableSecureTimeGetorSet(const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet)
{
    DRM_RESULT dr = DRM_SUCCESS;
    DRM_LICEVAL_CONTEXT* pLicEval = (DRM_LICEVAL_CONTEXT*) pvOpaqueData;


    if( fSet )
    {        
        return CPRMEXP_UPDATE_UNSUPPORTED;
    }
    if( NULL == pLicEval )
    {
        dr = CPRMEXP_RETRIEVAL_FAILURE;
    }

    if( !pLicEval->fSecureTimeDataValid )
    {        
        return CPRMEXP_RETRIEVAL_FAILURE;
    }

    /* fInGracePeriod variable*/
    /*Set the flag in lic Eval context if this function was ever called, to know that if Grace period expression exists in license.
     * It is called before validation of variables, but it is fine since the function will error out if variables doesn’t match.
    */
    pLicEval->eTimeBasedState = LICEVAL_GRACEPERIODREFERENCED;

    if( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarInGracePeriod, pdstrToken ) )
    {
        pResult->TokenType  = TOKEN_LONG;
        pResult->val.lValue = (DRM_LONG)pLicEval->fInGracePeriod;
    }
    else if( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarGpStartTime, pdstrToken ) )
    {
        pResult->TokenType  = TOKEN_DATETIME;
        MEMCPY(&pResult->val.u64DateTime, &pLicEval->u64GPStartTime, SIZEOF( pResult->val.u64DateTime ) ) ;
    }
    else
    {
        return CPRMEXP_RETRIEVAL_FAILURE;
    }

    return DRM_SUCCESS;
  
}
#endif


#if DRM_SUPPORT_PLAYLIST_BURN
DRM_RESULT DRM_API VariablePlaylistBurnGetorSet(const DRM_CONST_STRING* pdstrToken, TOKEN* pNewValue, TOKEN* pResult, DRM_VOID* pvOpaqueData, DRM_BOOL fSet)
{
    DRM_LICEVAL_CONTEXT* pContext = (DRM_LICEVAL_CONTEXT*) pvOpaqueData;

    DRMASSERT( pContext != NULL );

    if( DRM_UTL_DSTRStringsEqual( &g_dstrExprVarIncrementCount, pdstrToken ) )
    {
        if( fSet )
        {
            if( pNewValue->TokenType != TOKEN_LONG )
            {
                return CPRMEXP_WRONG_TYPE_OPERAND;                
            }
            pContext->cPlaylistBurnIncrement = pNewValue->val.lValue;
        }
        pResult->TokenType  = TOKEN_LONG;
        pResult->val.lValue = pContext->cPlaylistBurnIncrement;
    }
    else
    {
        return CPRMEXP_RETRIEVAL_FAILURE;
    }

    return DRM_SUCCESS;
}
#endif
