571 lines
18 KiB
C++
571 lines
18 KiB
C++
|
// a class to maintain the PICS data. It reads and write it to the metabase and
|
||
|
// reads the file and all that. It also serves as a wrapper for the PICS parsing
|
||
|
// objects that have already been written elsewhere
|
||
|
// Created 4/18/97 by BoydM
|
||
|
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include <iadmw.h>
|
||
|
#include "cnfgprts.h"
|
||
|
#include "parserat.h"
|
||
|
#include "RatData.h"
|
||
|
|
||
|
#include <iiscnfg.h>
|
||
|
#include <wrapmb.h>
|
||
|
#include "metatool.h"
|
||
|
|
||
|
#include <isvctrl.h>
|
||
|
|
||
|
#include "mdobjs.h"
|
||
|
#include <winsock2.h>
|
||
|
|
||
|
// Here is the plan. First, we scan the local directory - looking for all
|
||
|
// the .rat files, load them and parse them
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
CRatingsData::CRatingsData(IMSAdminBase* pMB):
|
||
|
iRat(0),
|
||
|
m_fEnabled( FALSE ),
|
||
|
m_start_minute(0),
|
||
|
m_start_hour(0),
|
||
|
m_start_day(0),
|
||
|
m_start_month(0),
|
||
|
m_start_year(0),
|
||
|
m_expire_minute(0),
|
||
|
m_expire_hour(0),
|
||
|
m_expire_day(0),
|
||
|
m_expire_month(0),
|
||
|
m_expire_year(0),
|
||
|
m_pMB( pMB )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
CRatingsData::~CRatingsData()
|
||
|
{
|
||
|
// delete the rating systems
|
||
|
DWORD nRats = (DWORD)rgbRats.GetSize();
|
||
|
for ( DWORD iRat = 0; iRat < nRats; iRat++ )
|
||
|
delete rgbRats[iRat];
|
||
|
}
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
BOOL CRatingsData::FCreateURL( CString &sz )
|
||
|
{
|
||
|
CHAR nameBuf[MAX_PATH+1];
|
||
|
|
||
|
// start it off with the mandatory http header
|
||
|
sz.LoadString( IDS_HTTP_HEADER );
|
||
|
// get the host name of the machine
|
||
|
if ( gethostname( nameBuf, sizeof(nameBuf)) )
|
||
|
return FALSE;
|
||
|
sz += nameBuf;
|
||
|
|
||
|
// next, we need to add on the virtual path supplied by the metabase location
|
||
|
// but that means starting by finding the root portion of the string
|
||
|
CString szVir = m_szMeta;
|
||
|
CString szRoot = _T("/Root");
|
||
|
szVir = szVir.Right( szVir.GetLength() - szVir.Find(szRoot) );
|
||
|
szVir = szVir.Right( szVir.GetLength() - szRoot.GetLength() );
|
||
|
|
||
|
// concatenate and done
|
||
|
sz += szVir;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
// generate the label and save it into the metabase
|
||
|
void CRatingsData::SaveTheLable()
|
||
|
{
|
||
|
BOOL fBuiltLabel = FALSE;
|
||
|
BOOL f;
|
||
|
|
||
|
// prepare the metabase wrapper
|
||
|
CWrapMetaBase mbWrap;
|
||
|
f = mbWrap.FInit(m_pMB);
|
||
|
if ( !f ) return;
|
||
|
|
||
|
// if the rating is NOT enabled, delete any existing label and return
|
||
|
if ( !m_fEnabled )
|
||
|
{
|
||
|
// attempt to open the object we want to store into
|
||
|
if ( mbWrap.Open( m_szMeta, METADATA_PERMISSION_WRITE ) )
|
||
|
{
|
||
|
// delete any existing PICS metaobject
|
||
|
// f = mbWrap.DeleteData( _T(""), MD_HTTP_PICS, IIS_MD_UT_FILE, MULTISZ_METADATA );
|
||
|
f = mbWrap.DeleteData( _T(""), MD_HTTP_PICS, MULTISZ_METADATA );
|
||
|
// close the metabase
|
||
|
mbWrap.Close();
|
||
|
}
|
||
|
//leave
|
||
|
return;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CString szLabel;
|
||
|
|
||
|
// first, we add the actual HTTP header to the header
|
||
|
// szLabel = _T("Protocol: {PICS-1.0 {headers PICS-Label}}\nPICS-Label: ");
|
||
|
szLabel = _T("PICS-Label: ");
|
||
|
|
||
|
// create the URL string for this label
|
||
|
CString szURL;
|
||
|
FCreateURL( szURL );
|
||
|
|
||
|
// create the modified string for this label
|
||
|
CString szMod;
|
||
|
CreateDateSz( szMod, m_start_day, m_start_month, m_start_year, m_start_hour, m_start_minute );
|
||
|
|
||
|
// create the exipres string for this label
|
||
|
CString szExpire;
|
||
|
CreateDateSz( szExpire, m_expire_day, m_expire_month, m_expire_year, m_expire_hour, m_expire_minute );
|
||
|
|
||
|
// tell each ratings system object to add its label to the string
|
||
|
DWORD nRatingSystems = (DWORD)rgbRats.GetSize();
|
||
|
for ( DWORD iRat = 0; iRat < nRatingSystems; iRat++ )
|
||
|
{
|
||
|
// build the label string
|
||
|
rgbRats[iRat]->OutputLabels( szLabel, szURL, m_szEmail, szMod, szExpire );
|
||
|
}
|
||
|
|
||
|
|
||
|
// the data gets saved as a multisz, so prep it up
|
||
|
PTCHAR psz = szLabel.GetBuffer( szLabel.GetLength()+4 );
|
||
|
|
||
|
DWORD dw = szLabel.GetLength();
|
||
|
|
||
|
// add the second null
|
||
|
psz[dw + 1] = 0;
|
||
|
psz[dw + 2] = 0;
|
||
|
|
||
|
// save the data
|
||
|
// save the PICS header string
|
||
|
// f = SetMetaData(&mbWrap, szPartial, MD_HTTP_PICS, IIS_MD_UT_FILE,
|
||
|
// psz, szLabel.GetLength()+2 );
|
||
|
// f = SetMetaMultiSz( &mbWrap, m_szMeta, MD_HTTP_PICS, IIS_MD_UT_FILE,
|
||
|
// psz, dw+2 );
|
||
|
|
||
|
f = SetMetaMultiSz(m_pMB, m_szServer, m_szMeta, _T(""), MD_HTTP_PICS,
|
||
|
IIS_MD_UT_FILE, psz, dw+2, TRUE );
|
||
|
|
||
|
|
||
|
// release the buffer
|
||
|
szLabel.ReleaseBuffer();
|
||
|
|
||
|
// these changes are permanent - so write them out
|
||
|
if ( f )
|
||
|
mbWrap.Save();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
BOOL CRatingsData::FInit( CString szServer, CString szMeta )
|
||
|
{
|
||
|
CWinApp* pApp = AfxGetApp();
|
||
|
CString sz;
|
||
|
BOOL fGotSomething = FALSE;
|
||
|
BOOL fFoundAFile = FALSE;
|
||
|
|
||
|
// store the target metabase location
|
||
|
m_szServer = szServer;
|
||
|
m_szMeta = szMeta;
|
||
|
|
||
|
// build the search string
|
||
|
CString szSearch;
|
||
|
|
||
|
// the ratings files are in the system32 directory. First, get that
|
||
|
// directory from the system. The first call is to get the size of the buffer.
|
||
|
// add one for the terminating NULL
|
||
|
DWORD cchSysDir = GetSystemDirectory( NULL, 0 ) + 1;
|
||
|
// if we didn't get one - fail
|
||
|
if ( cchSysDir == 1 ) return FALSE;
|
||
|
|
||
|
// Now get it for real
|
||
|
cchSysDir = GetSystemDirectory( szSearch.GetBuffer(cchSysDir), cchSysDir );
|
||
|
szSearch.ReleaseBuffer();
|
||
|
// if we didn't get one - fail
|
||
|
if ( !cchSysDir ) return FALSE;
|
||
|
|
||
|
// finish making it a proper search string
|
||
|
|
||
|
//
|
||
|
// RONALDM -- add .rat to only find rat files.
|
||
|
//
|
||
|
szSearch += _T("\\*.rat");
|
||
|
|
||
|
// scan the local files looking for rat files. For each we find, load
|
||
|
// them into the list of rat files
|
||
|
BOOL fKeepGoing = TRUE;
|
||
|
CFileFind finder;
|
||
|
fFoundAFile = finder.FindFile( szSearch );
|
||
|
while ( fFoundAFile )
|
||
|
{
|
||
|
// get rid of the directories right away
|
||
|
if ( finder.MatchesMask( FILE_ATTRIBUTE_DIRECTORY ) )
|
||
|
{
|
||
|
// get the next file
|
||
|
fFoundAFile = finder.FindNextFile();
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// get and normalize the path
|
||
|
sz = finder.GetFilePath();
|
||
|
sz.MakeLower();
|
||
|
|
||
|
// if it is a rat file, go for it
|
||
|
|
||
|
//
|
||
|
// RONALDM -- changed the mask so that this is all that's necc.
|
||
|
//
|
||
|
//if ( sz.Find(_T(".rat")) > 0 )
|
||
|
{
|
||
|
// set the found flag based on if we can load it
|
||
|
fGotSomething |= FLoadRatingsFile( sz );
|
||
|
}
|
||
|
|
||
|
// get the next file
|
||
|
if ( !fKeepGoing )
|
||
|
{
|
||
|
fFoundAFile = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fKeepGoing = finder.FindNextFile();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if we loaded a file, check what is in the metabase and load the values
|
||
|
if ( fGotSomething )
|
||
|
{
|
||
|
LoadMetabaseValues();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// if we didn't find any rat files, tell the user and return
|
||
|
AfxMessageBox( IDS_RAT_FINDFILE_ERROR );
|
||
|
}
|
||
|
|
||
|
// return the answer
|
||
|
return fGotSomething;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
// load a ratings file
|
||
|
BOOL CRatingsData::FLoadRatingsFile( CString szFilePath )
|
||
|
{
|
||
|
HANDLE hFile;
|
||
|
HANDLE hFileMapping;
|
||
|
VOID * pMem;
|
||
|
BOOL fParsed = FALSE;
|
||
|
|
||
|
hFile = CreateFile( szFilePath,
|
||
|
GENERIC_READ,
|
||
|
0,
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL,
|
||
|
NULL );
|
||
|
|
||
|
if ( hFile == INVALID_HANDLE_VALUE )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
hFileMapping = CreateFileMapping( hFile,
|
||
|
NULL,
|
||
|
PAGE_READONLY,
|
||
|
0,
|
||
|
0,
|
||
|
NULL );
|
||
|
|
||
|
if ( hFileMapping == NULL )
|
||
|
{
|
||
|
CloseHandle( hFile );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
pMem = MapViewOfFile( hFileMapping,
|
||
|
FILE_MAP_READ,
|
||
|
0,
|
||
|
0,
|
||
|
0 );
|
||
|
|
||
|
if ( pMem == NULL )
|
||
|
{
|
||
|
CloseHandle( hFileMapping );
|
||
|
CloseHandle( hFile );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// parse this and load it in and all that stuff
|
||
|
fParsed = FParseRatingsFile( (LPSTR) pMem, szFilePath );
|
||
|
|
||
|
UnmapViewOfFile( pMem );
|
||
|
CloseHandle( hFileMapping );
|
||
|
CloseHandle( hFile );
|
||
|
|
||
|
// return the answer
|
||
|
return fParsed;
|
||
|
}
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
BOOL CRatingsData::FParseRatingsFile( LPSTR pData, CString szPath )
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
BOOL fSuccess = FALSE;
|
||
|
|
||
|
// first, try and parse the data
|
||
|
PicsRatingSystem* pRating = new PicsRatingSystem();
|
||
|
|
||
|
// parse the data
|
||
|
hres = pRating->Parse( pData );
|
||
|
fSuccess = (hres == 0);
|
||
|
|
||
|
// if it didn't parse, leave now
|
||
|
if ( !fSuccess )
|
||
|
{
|
||
|
delete pRating;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// add the rat to the list of parsed rats
|
||
|
rgbRats.Add( pRating );
|
||
|
|
||
|
return fSuccess;
|
||
|
}
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
// create a date string
|
||
|
void CRatingsData::CreateDateSz( CString &sz, WORD day, WORD month, WORD year, WORD hour, WORD minute )
|
||
|
{
|
||
|
// get the local time zone
|
||
|
TIME_ZONE_INFORMATION tZone;
|
||
|
INT hrZone, mnZone;
|
||
|
DWORD dwDaylight = GetTimeZoneInformation( &tZone );
|
||
|
// Fix for 339525: Boyd, this could be negative and must be signed type!
|
||
|
LONG tBias;
|
||
|
|
||
|
// First, calculate the correct bias - depending whether or not
|
||
|
// we are in daylight savings time.
|
||
|
if ( dwDaylight == TIME_ZONE_ID_DAYLIGHT )
|
||
|
{
|
||
|
tBias = tZone.Bias + tZone.DaylightBias;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
tBias = tZone.Bias + tZone.StandardBias;
|
||
|
}
|
||
|
|
||
|
// calculate the hours and minutes offset for the time-zone
|
||
|
hrZone = tBias / 60;
|
||
|
mnZone = tBias % 60;
|
||
|
|
||
|
// need to handle time zones east of GMT
|
||
|
if ( hrZone < 0 )
|
||
|
{
|
||
|
hrZone *= (-1);
|
||
|
mnZone *= (-1);
|
||
|
// make the string
|
||
|
sz.Format( _T("%04d.%02d.%02dT%02d:%02d+%02d%02d"), year, month, day, hour, minute, hrZone, mnZone );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// make the string
|
||
|
sz.Format( _T("%04d.%02d.%02dT%02d:%02d-%02d%02d"), year, month, day, hour, minute, hrZone, mnZone );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
// read a date string
|
||
|
void CRatingsData::ReadDateSz( CString sz, WORD* pDay, WORD* pMonth, WORD* pYear, WORD* pHour, WORD* pMinute )
|
||
|
{
|
||
|
CString szNum;
|
||
|
WORD i;
|
||
|
DWORD dw;
|
||
|
|
||
|
// year
|
||
|
szNum = sz.Left( sz.Find(_T('.')) );
|
||
|
i = (WORD)swscanf( szNum, _T("%d"), &dw );
|
||
|
*pYear = (WORD)dw;
|
||
|
sz = sz.Right( sz.GetLength() - szNum.GetLength() - 1 );
|
||
|
|
||
|
// month
|
||
|
szNum = sz.Left( sz.Find(_T('.')) );
|
||
|
i = (WORD)swscanf( szNum, _T("%d"), &dw );
|
||
|
*pMonth = (WORD)dw;
|
||
|
sz = sz.Right( sz.GetLength() - szNum.GetLength() - 1 );
|
||
|
|
||
|
// day
|
||
|
szNum = sz.Left( sz.Find(_T('T')) );
|
||
|
i = (WORD)swscanf( szNum, _T("%d"), &dw );
|
||
|
*pDay = (WORD)dw;
|
||
|
sz = sz.Right( sz.GetLength() - szNum.GetLength() - 1 );
|
||
|
|
||
|
// hour
|
||
|
szNum = sz.Left( sz.Find(_T(':')) );
|
||
|
i = (WORD)swscanf( szNum, _T("%d"), &dw );
|
||
|
*pHour = (WORD)dw;
|
||
|
sz = sz.Right( sz.GetLength() - szNum.GetLength() - 1 );
|
||
|
|
||
|
// minute
|
||
|
szNum = sz.Left( 2 );
|
||
|
i = (WORD)swscanf( szNum, _T("%d"), &dw );
|
||
|
*pMinute = (WORD)dw;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
// for simplicity's sake (and for the sake of gettings done) only check the
|
||
|
// metabase values against the first loaded ratings system. Everything I've
|
||
|
// been hearing is that there will be only one.
|
||
|
void CRatingsData::LoadMetabaseValues()
|
||
|
{
|
||
|
CString szRating;
|
||
|
BOOL f;
|
||
|
|
||
|
// prepare the metabase wrapper
|
||
|
CWrapMetaBase mbWrap;
|
||
|
f = mbWrap.FInit(m_pMB);
|
||
|
if ( !f ) return;
|
||
|
|
||
|
// if we succeded in building the lables, save it in the metabase
|
||
|
// attempt to open the object we want to store into
|
||
|
CString szMeta;
|
||
|
|
||
|
// arg arg arg. For things like directories, the metapath may not exist
|
||
|
// seperate the partial path from the base - the root is always SZ_ROOT
|
||
|
szMeta = SZ_W3_ROOT;
|
||
|
m_szMetaPartial = m_szMeta.Right(m_szMeta.GetLength() - szMeta.GetLength() );
|
||
|
|
||
|
// save the data
|
||
|
if ( mbWrap.Open( szMeta, METADATA_PERMISSION_READ ) )
|
||
|
{
|
||
|
DWORD cbData;
|
||
|
// attempt to read the data from the metabase
|
||
|
WCHAR* pData= (WCHAR*)mbWrap.GetData( m_szMetaPartial, MD_HTTP_PICS, IIS_MD_UT_FILE, MULTISZ_METADATA,
|
||
|
&cbData, METADATA_INHERIT | METADATA_PARTIAL_PATH );
|
||
|
|
||
|
// copy the string into place
|
||
|
if ( pData )
|
||
|
szRating = pData;
|
||
|
// free the buffer
|
||
|
mbWrap.FreeWrapData( pData );
|
||
|
// close the metabase
|
||
|
mbWrap.Close();
|
||
|
|
||
|
// if we got the string, parse it and all that jazz
|
||
|
if ( !szRating.IsEmpty() )
|
||
|
ParseMetaRating( szRating );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
// NOTE: this is a pretty fragile reading of the PICS file. If things are
|
||
|
// not in the order that this file would write them back out in, it will fail.
|
||
|
// however, This will work on PICS ratings that this module has written out,
|
||
|
// which should pretty much be all of them
|
||
|
// it also assumes that one-letter abbreviations are used just about everywhere
|
||
|
#define RAT_PERSON_DETECTOR _T("by \"")
|
||
|
#define RAT_LABEL_DETECTOR _T("l ")
|
||
|
#define RAT_ON_DETECTOR _T("on \"")
|
||
|
#define RAT_EXPIRE_DETECTOR _T("exp \"")
|
||
|
#define RAT_RAT_DETECTOR _T("r (")
|
||
|
void CRatingsData::ParseMetaRating( CString szRating )
|
||
|
{
|
||
|
CString szScratch;
|
||
|
|
||
|
// if we got here, then we know that the rating system is enabled
|
||
|
m_fEnabled = TRUE;
|
||
|
|
||
|
// operate on a copy of the data
|
||
|
CString szRat;
|
||
|
|
||
|
// skip past the http headerpart
|
||
|
szRat = szRating.Right( szRating.GetLength() - szRating.Find(_T("\"http://")) - 1 );
|
||
|
szRat = szRat.Right( szRat.GetLength() - szRat.Find(_T('\"')) - 1 );
|
||
|
szRat.TrimLeft();
|
||
|
|
||
|
// the next bit should be the label indicator. Skip over it
|
||
|
if ( szRat.Left(wcslen(RAT_LABEL_DETECTOR)) == RAT_LABEL_DETECTOR )
|
||
|
szRat = szRat.Right( szRat.GetLength() - wcslen(RAT_LABEL_DETECTOR) );
|
||
|
|
||
|
// we should now be at the author part. If it is there, load it in
|
||
|
if ( szRat.Left(wcslen(RAT_PERSON_DETECTOR)) == RAT_PERSON_DETECTOR )
|
||
|
{
|
||
|
szRat = szRat.Right( szRat.GetLength() - wcslen(RAT_PERSON_DETECTOR) );
|
||
|
m_szEmail = szRat.Left( szRat.Find(_T('\"')) );
|
||
|
szRat = szRat.Right( szRat.GetLength() - m_szEmail.GetLength() - 1 );
|
||
|
szRat.TrimLeft();
|
||
|
}
|
||
|
|
||
|
// next should be the modification date
|
||
|
// we should now be at the author part. If we are, load it in
|
||
|
if ( szRat.Left(wcslen(RAT_ON_DETECTOR)) == RAT_ON_DETECTOR )
|
||
|
{
|
||
|
szRat = szRat.Right( szRat.GetLength() - wcslen(RAT_ON_DETECTOR) );
|
||
|
szScratch = szRat.Left( szRat.Find(_T('\"')) );
|
||
|
szRat = szRat.Right( szRat.GetLength() - szScratch.GetLength() - 1 );
|
||
|
szRat.TrimLeft();
|
||
|
ReadDateSz( szScratch, &m_start_day, &m_start_month, &m_start_year,
|
||
|
&m_start_hour, &m_start_minute );
|
||
|
}
|
||
|
|
||
|
// next should be the expiration date
|
||
|
// we should now be at the author part. If we are, load it in
|
||
|
if ( szRat.Left(wcslen(RAT_EXPIRE_DETECTOR)) == RAT_EXPIRE_DETECTOR )
|
||
|
{
|
||
|
szRat = szRat.Right( szRat.GetLength() - wcslen(RAT_EXPIRE_DETECTOR) );
|
||
|
szScratch = szRat.Left( szRat.Find(_T('\"')) );
|
||
|
szRat = szRat.Right( szRat.GetLength() - szScratch.GetLength() - 1 );
|
||
|
szRat.TrimLeft();
|
||
|
ReadDateSz( szScratch, &m_expire_day, &m_expire_month, &m_expire_year,
|
||
|
&m_expire_hour, &m_expire_minute );
|
||
|
}
|
||
|
|
||
|
// we should now be at the actual ratings part. If we are, load it in as one string first
|
||
|
if ( szRat.Left(wcslen(RAT_RAT_DETECTOR)) == RAT_RAT_DETECTOR )
|
||
|
{
|
||
|
szRat = szRat.Right( szRat.GetLength() - wcslen(RAT_RAT_DETECTOR) );
|
||
|
szScratch = szRat.Left( szRat.Find(_T(')')) );
|
||
|
szRat = szRat.Right( szRat.GetLength() - szScratch.GetLength() - 1 );
|
||
|
szRat.TrimLeft();
|
||
|
|
||
|
// loop through all the value pairs in the ratings string
|
||
|
while ( szScratch.GetLength() )
|
||
|
{
|
||
|
// this part goes <ch> sp <ch> so that we know we can use chars 0 and 2
|
||
|
ParseMetaPair( szScratch[0], szScratch[2] );
|
||
|
|
||
|
// cut down the string
|
||
|
szScratch = szScratch.Right( szScratch.GetLength() - 3 );
|
||
|
szScratch.TrimLeft();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
void CRatingsData::ParseMetaPair( TCHAR chCat, TCHAR chVal )
|
||
|
{
|
||
|
// check validity of the value character
|
||
|
if ( (chVal < _T('0')) || (chVal > _T('9')) )
|
||
|
return;
|
||
|
|
||
|
// convert the value into a number - the quick way
|
||
|
WORD value = chVal - _T('0');
|
||
|
|
||
|
// try all the categories
|
||
|
DWORD nCat = rgbRats[0]->arrpPC.Length();
|
||
|
for ( DWORD iCat = 0; iCat < nCat; iCat++ )
|
||
|
{
|
||
|
// stop at the first successful setting
|
||
|
if ( rgbRats[0]->arrpPC[iCat]->FSetValuePair((CHAR)chCat, (CHAR)value) )
|
||
|
break;
|
||
|
}
|
||
|
}
|