2025-04-27 07:49:33 -04:00

344 lines
7.1 KiB
C++

/*
- WMCOMM.CPP
-
* Purpose:
* WebClient Common IIS/Store Utility Functions
*
* Copyright (C) 1997-1999 Microsoft Corporation
*
* References:
*
*
* [Date] [email] [Comment]
* 11/22/99 wardb Creation.
*
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "wmcomm.h"
/*
- CAcceptHeaderIterator::ScInit
-
* Purpose:
* Initializes the object with the Accept-language header.
* The header should conform to the specifications in HTTP 1.1 RFC.
*
*/
HRESULT
CAcceptHeaderIterator::ScInit(LPCSTR pszAcceptHeader)
{
HRESULT sc = S_OK;
LPSTR pszAcceptToken = NULL;
LPSTR pszT = NULL;
DWORD cbLen = 0;
if (!pszAcceptHeader || !*pszAcceptHeader)
{
// if there is no accept header, treat the header
// as a wildcard. (HTTP 1.1 RFC)
//
m_fWildCardPresent = TRUE;
goto Exit;
}
// Make a local copy of the header
//
cbLen = strlen(pszAcceptHeader) + 1;
m_pszAcceptHeader = new CHAR[cbLen];
if (m_pszAcceptHeader == NULL)
{
sc = E_OUTOFMEMORY;
goto Exit;
}
strcpy(m_pszAcceptHeader, pszAcceptHeader);
// Findout number of accept tokens we have. "," is the delimiter.
// Comma is the separator (not terminator) according to the RFC, so start
// counting from 1.
//
m_ctiMax = 1;
for (pszT = m_pszAcceptHeader; *pszT; pszT++)
{
if (*pszT == ',') m_ctiMax++;
}
// Allocate the memory for lang info
//
m_pti = new TOKENINFO[m_ctiMax];
if (!m_pti)
{
sc = E_OUTOFMEMORY;
goto Exit;
}
memset(m_pti, 0, sizeof(TOKENINFO) * m_ctiMax);
// Parse and sort the tokens correctly.
//
m_ctiUsed = 0;
pszAcceptToken = strtok(m_pszAcceptHeader, ",");
while (pszAcceptToken)
{
TOKENINFO ti = {0};
BOOL fWildCard = FALSE;
// if we fail to get token and Q factor, ignore the token
//
if (SUCCEEDED(ScGetTokenQFactor( pszAcceptToken,
&fWildCard,
&ti)))
{
if (!fWildCard)
{
// Not a wild card. Insert it in our array
//
sc = ScInsert(&ti);
if (FAILED(sc))
goto Exit;
}
else
{
// If it is a wild card, set a flag
//
m_fWildCardPresent = TRUE;
}
}
// Get the next token from the header
//
pszAcceptToken = strtok(NULL, ",");
}
Exit:
return(sc);
}
/*
- CAcceptHeaderIterator::ScGetTokenQFactor
-
* Purpose:
* Parses the accept token string with the quality factor and
* returns the values in TOKENINFO structure. If the quality
* factor is not present, then the q factor is assumed as 1.0
* if the quality factor is either <= 0.0 or greater than 1.0
* an error value is returned.
*
*/
HRESULT
CAcceptHeaderIterator::ScGetTokenQFactor( LPSTR pszAcceptToken,
BOOL * pfWildCard,
TOKENINFO * pti)
{
HRESULT sc = S_OK;
LPSTR pszAcceptTokenEnd = NULL;
LPSTR pszAcceptTokenStart = NULL;
LPSTR pszQuality = NULL;
double dbQuality = 0;
// Findout the accept token end;
//
pszAcceptTokenStart = pszAcceptToken;
pszAcceptTokenEnd = strchr(pszAcceptTokenStart, ';');
if (pszAcceptTokenEnd)
{
// We have quality factor -- Terminate the token string where
// the quality string starts.
//
*pszAcceptTokenEnd = '\0';
pszQuality = pszAcceptTokenEnd + 1;
}
else
{
// No Quality factor -- Set the accept token end to point to the end of
// the string.
pszQuality = NULL;
pszAcceptTokenEnd = pszAcceptTokenStart + strlen(pszAcceptTokenStart);
}
// Find out the quality param
//
dbQuality = 1.0;
if (pszQuality && *pszQuality)
{
// The syntax for quality parameter is: "q=0.5"
//
while (*pszQuality && isspace(*pszQuality)) pszQuality++;
if (*pszQuality != 'q')
goto ErrorInvalidArg;
pszQuality++; // go past the 'q'
while (*pszQuality && isspace(*pszQuality)) pszQuality++;
if (*pszQuality != '=')
goto ErrorInvalidArg;
pszQuality++; // move past the '=' sign.
dbQuality = atof(pszQuality);
if (dbQuality > 1.0 || dbQuality <= 0.0)
{
// If the Q value is not one of the legal values, just ignore.
// Ignore the token if the Q value is 0.0 (as per the RFC)
//
goto ErrorInvalidArg;
}
}
// Normalize accept tokens -- remove leading and trailing white spaces
//
while (*pszAcceptTokenStart && isspace(*pszAcceptTokenStart))
{
pszAcceptTokenStart++;
}
if (!*pszAcceptTokenStart)
{
// Accept token is empty
//
goto ErrorInvalidArg;
}
while (pszAcceptTokenEnd > pszAcceptTokenStart &&
isspace(*(pszAcceptTokenEnd - 1)))
{
pszAcceptTokenEnd--;
}
*pszAcceptTokenEnd = '\0';
// Check if it is a wild card string
//
*pfWildCard = (strcmp(pszAcceptTokenStart,"*") == 0);
// Initialize the token info structure
//
pti->dbQuality = dbQuality;
pti->pszToken = pszAcceptTokenStart;
Exit:
return sc;
ErrorInvalidArg:
sc = E_INVALIDARG;
goto Exit;
}
/*
- CAcceptHeaderIterator::ScInsert
-
* Purpose:
* Insert the tokeninfo in correct order (based on the
* quality factor). If two tokens have same quality factors, then their
* order in which they were added will be preserved.
*
*/
HRESULT
CAcceptHeaderIterator::ScInsert(TOKENINFO * ptiCurrent)
{
// Insert the accept token in correct order of qvalue (quality)
//
HRESULT sc = S_OK;
DWORD iCurLang = m_ctiUsed;
while ( iCurLang > 0 &&
ptiCurrent->dbQuality > m_pti[iCurLang - 1].dbQuality)
{
iCurLang--;
}
if (iCurLang != m_ctiUsed)
{
memmove( &m_pti[iCurLang+1],
&m_pti[iCurLang],
(m_ctiUsed - iCurLang) * sizeof(TOKENINFO));
}
m_pti[iCurLang] = *ptiCurrent;
m_ctiUsed++;
return sc;
}
/*
- CAcceptHeaderIterator::ScGetNextAcceptToken
-
* Purpose:
* Returns the next non-null accept-token from the list. If the
* string is a wild card, then the wildcard flag will be set to true and
* the accept token is set to NULL.
*
*/
HRESULT
CAcceptHeaderIterator::ScGetNextAcceptToken( LPCSTR * ppszAcceptToken,
double * pdbQuality)
{
HRESULT sc = S_OK;
*ppszAcceptToken = NULL;
*pdbQuality = 0;
// If we dont have any more tokens or wild cards to return
// return an error back.
//
if (m_fIterationCompleted)
{
sc = HRESULT_FROM_WIN32(ERROR_NO_DATA);
}
else
{
// Advance our accept token pointer
//
sc = ScAdvance();
if (SUCCEEDED(sc))
{
*ppszAcceptToken = m_pti[m_itiCurrent].pszToken;
*pdbQuality = m_pti[m_itiCurrent].dbQuality;
}
else
{
// ScAdvance failed -- No more accept tokens
// If the header has a wild-card char send it.
//
m_fIterationCompleted = TRUE;
}
}
return sc;
}
/*
- CAcceptHeaderIterator::ScAdvance
-
* Purpose:
* Advance the iterator to the next token. Override this function
* if we want to advance the iterator differently.
*
*/
HRESULT
CAcceptHeaderIterator::ScAdvance()
{
HRESULT sc = S_OK;
// Assert(m_ctiUsed <= m_ctiMax);
if (!m_ctiUsed || m_itiCurrent>=m_ctiUsed)
{
// List is empty or the current pointer is at the end.
//
sc = HRESULT_FROM_WIN32(ERROR_NO_DATA);
goto Exit;
}
m_itiCurrent++;
Exit:
return sc;
}