Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

375 lines
12 KiB

//--------------------------------------------------------------------
// parser.cpp - sample code
// Copyright (C) Microsoft Corporation, 2001
//
// Created by: Duncan Bryce (duncanb), 9-13-2001
//
// Code to parse the samples returned from hardware providers
//
#include "pch.h"
//
// FORMAT STRING SPECIFICATION:
//
// pattern length (chars) description
// ------------------------------------------------------------
// * 1 ignored
// MJ 5 modified julian date (MJD)
// Y2 2 year without century (assumes 21st century)
// Y4 4 year with century
// M 2 month (01-12)
// D 2 day of month (01-31)
// H 2 hours (00-23)
// m 2 minutes (00-59)
// S 2 seconds (00-60) 60 indicates a leap second
// s1: 1 .1 seconds
// s2: 2 .01 seconds
// s3: 3 .001 seconds
//
// BUGBUG: research better ways for doing accuracy codes, and record clocks which support
// A: variable begin accuracy code definition: (ex: ^1A10B100C500DZ)
// In: variable I == status char, n == number of status chars
//
//--------------------------------------------------------------------------------
//
// Utility methods
//
//--------------------------------------------------------------------------------
HRESULT ParseNumber(char *pcData, DWORD dwPlaces, DWORD *pdwNumber) {
char *pcDataEnd = pcData + dwPlaces;
DWORD dwResult = 0;
HRESULT hr;
for (; pcData != pcDataEnd; pcData++) {
dwResult *= 10;
if (*pcData < '0' || '9' < *pcData) {
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "ParseNumber: non-numeric input");
}
dwResult += (DWORD)(*pcData - '0');
}
*pdwNumber = dwResult;
hr = S_OK;
error:
return hr;
}
//--------------------------------------------------------------------------------
//
// PARSER classes
//
//--------------------------------------------------------------------------------
class ParseAction {
public:
virtual HRESULT Parse(char *cData, char **cDataNew) = 0;
virtual ~ParseAction() { }
};
class ParseAccuracyCode : public ParseAction {
public:
ParseAccuracyCode() { }
HRESULT Parse(char *pcData, char **ppcDataNew) {
return HRESULT_FROM_WIN32(ERROR_CALL_NOT_IMPLEMENTED);
}
};
class ParseStatusCode : public ParseAction {
public:
ParseStatusCode() { }
HRESULT Parse(char *pcData, char **ppcDataNew) {
return HRESULT_FROM_WIN32(ERROR_CALL_NOT_IMPLEMENTED);
}
};
class IgnoreChar : public ParseAction {
public:
IgnoreChar() { }
HRESULT Parse(char *pcData, char **ppcDataNew) {
*ppcDataNew = pcData+1;
return S_OK;
}
};
class ParseModifiedJulianDate : public ParseAction {
WORD *m_pwYear;
WORD *m_pwMonth;
WORD *m_pwDay;
public:
ParseModifiedJulianDate(WORD *pwYear, WORD *pwMonth, WORD *pwDay) : m_pwYear(pwYear), m_pwMonth(pwMonth), m_pwDay(pwDay) { }
HRESULT Parse(char *pcData, char **ppcDataNew) {
DWORD dwMJD;
HRESULT hr;
long l, n, i, j, d, y, m;
hr = ParseNumber(pcData, 5/*MJD is always 5 places*/, &dwMJD);
_JumpIfError(hr, error, "ParseNumber");
// The algorithm is based on the Fliegel/van Flandern paper in COMM of the ACM 11/#10 p.657 Oct. 1968
l = dwMJD + 68569 + 2400001;
n = (( 4 * l ) - 2) / 146097;
l = l - ( 146097 * n + 3 ) / 4;
i = ( 4000 * ( l + 1 ) ) / 1461001;
l = l - ( 1461 * i ) / 4 + 31;
j = ( 80 * l ) / 2447;
d = l - ( 2447 * j ) / 80;
l = j / 11;
m = j + 2 - ( 12 * l );
y = 100 * ( n - 49 ) + i + l;
// sanity checks:
_MyAssert(1900 < y && y < (1<<16));
_MyAssert( 0 < m && m < 13);
_MyAssert( 0 < d && d < 32);
// assign result pointers:
*m_pwYear = y;
*m_pwMonth = m;
*m_pwDay = d;
// calculate the new char input pointer:
*ppcDataNew = pcData + 5 /*MJD is always 5 chars*/;
hr = S_OK;
error:
return hr;
}
};
class NumericParseAction : public ParseAction {
WORD m_wPlaces;
WORD m_wMin;
WORD m_wMax;
WORD m_wScale;
WORD m_wOffset;
WORD *m_pwValue;
public:
NumericParseAction(WORD wPlaces, WORD wMin, WORD wMax, WORD wScale, WORD wOffset, WORD *pwValue) :
m_wPlaces(wPlaces), m_wMin(wMin), m_wMax(wMax), m_wScale(wScale), m_wOffset(wOffset), m_pwValue(pwValue) { }
HRESULT Parse(char *pcData, char **ppcDataNew) {
DWORD dwValue;
HRESULT hr;
hr = ParseNumber(pcData, m_wPlaces, &dwValue);
_JumpIfError(hr, error, "ParseNumber");
// Make sure that the result can fit into a WORD:
if (dwValue >= (1<<16)) {
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "ParseSmallNumber: result too large for 4-byte word");
}
// Make sure that the value we read is within bounds:
if (m_wMin > dwValue || m_wMax < dwValue) {
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "ParseFormatString: validating numeral");
}
// multiply in our scale factor:
dwValue *= m_wScale;
// add in our offset:
dwValue += m_wOffset;
// assign the computed value:
*m_pwValue = (WORD)dwValue;
// Increment our pointer to the data stream
*ppcDataNew = pcData + m_wPlaces;
hr = S_OK;
error:
return hr;
}
};
typedef vector<ParseAction *> ParseActionVec;
typedef ParseActionVec::iterator ParseActionIter;
struct HwSampleParser {
DWORD dwSampleSize;
SYSTEMTIME stSample;
ParseActionVec vParseActions;
~HwSampleParser() {
for (ParseActionIter paIter = vParseActions.begin(); paIter != vParseActions.end(); paIter++) {
delete (*paIter);
}
vParseActions.clear();
}
};
//--------------------------------------------------------------------------------
//
// PUBLIC INTERFACE
//
//--------------------------------------------------------------------------------
void FreeParser(HANDLE hParser) {
delete (static_cast<HwSampleParser *>(hParser));
}
DWORD GetSampleSize(HANDLE hParser) {
return (static_cast<HwSampleParser *>(hParser))->dwSampleSize;
}
HRESULT MakeParser(LPWSTR pwszFormat, HANDLE *phParser) {
HRESULT hr;
HwSampleParser *pParser = NULL;
ParseAction *ppaCurrent = NULL;
pParser = new HwSampleParser;
_JumpIfOutOfMemory(hr, error, pParser);
pParser->dwSampleSize = 0;
ZeroMemory(&pParser->stSample, sizeof(pParser->stSample));
// Add a series of parse actions to take based on the supplied format string:
while (L'\0' != *pwszFormat) {
if (L'*' == *pwszFormat) {
ppaCurrent = new IgnoreChar;
_JumpIfOutOfMemory(hr, error, ppaCurrent);
pParser->dwSampleSize++;
pwszFormat++;
} else if (L'A' == *pwszFormat) {
ppaCurrent = new ParseAccuracyCode;
_JumpIfOutOfMemory(hr, error, ppaCurrent);
pwszFormat++;
} else if (L'I' == *pwszFormat) {
ppaCurrent = new ParseStatusCode;
_JumpIfOutOfMemory(hr, error, ppaCurrent);
pwszFormat++;
} else if (0 == wcsncmp(L"MJ", pwszFormat, 2)) {
ppaCurrent = new ParseModifiedJulianDate(&(pParser->stSample.wYear), &(pParser->stSample.wMonth), &(pParser->stSample.wDay));
_JumpIfOutOfMemory(hr, error, ppaCurrent);
pParser->dwSampleSize += 5;
pwszFormat += 2;
} else {
// try the numeric parse rules:
struct NumericParseRule {
WCHAR *wszPattern;
WORD wPlaces;
WORD wMin;
WORD wMax;
WORD wScale;
WORD wOffset;
WORD *pwValue;
} rgNumericParseRules[] = {
{ L"Y2", 2, 0, 99, 1, 2000, &(pParser->stSample.wYear) }, // years w/o century
{ L"Y4", 4, 0, 9999, 1, 0, &(pParser->stSample.wYear) }, // years w/ century
{ L"M", 2, 1, 12, 1, 0, &(pParser->stSample.wMonth) }, // month of year
{ L"D", 2, 1, 31, 1, 0, &(pParser->stSample.wDay) }, // day of months
{ L"H", 2, 1, 24, 1, 0, &(pParser->stSample.wHour) }, // hours
{ L"m", 2, 1, 59, 1, 0, &(pParser->stSample.wMinute) }, // minutes
{ L"S", 2, 0, 60, 1, 0, &(pParser->stSample.wSecond) }, // seconds
{ L"s1", 1, 0, 9, 100, 0, &(pParser->stSample.wMilliseconds) }, // .1 second intervals
{ L"s2", 2, 0, 99, 10, 0, &(pParser->stSample.wMilliseconds) }, // .01 second intervals
{ L"s3", 3, 0, 999, 1, 0, &(pParser->stSample.wMilliseconds) }, // .001 second intervals
};
for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(rgNumericParseRules); dwIndex++) {
NumericParseRule *npr = &rgNumericParseRules[dwIndex];
if (0 == wcsncmp(npr->wszPattern, pwszFormat, wcslen(npr->wszPattern))) {
ppaCurrent = new NumericParseAction(npr->wPlaces, npr->wMin, npr->wMax, npr->wScale, npr->wOffset, npr->pwValue);
_JumpIfOutOfMemory(hr, error, ppaCurrent);
pParser->dwSampleSize += npr->wPlaces;
pwszFormat += wcslen(npr->wszPattern);
break;
}
}
}
if (NULL == ppaCurrent) {
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "MakeParser: bad format string");
}
_SafeStlCall(pParser->vParseActions.push_back(ppaCurrent), hr, error, "pParser->vParseActions.push_back(ppaCurrent)");
ppaCurrent = NULL; // no longer responsible for freeing ppaCurrent
}
*phParser = pParser;
pParser = NULL;
hr = S_OK;
error:
if (NULL != ppaCurrent) {
delete ppaCurrent;
}
if (NULL != pParser) {
delete pParser;
}
return hr;
}
HRESULT ParseSample(HANDLE hParser, char *pcData, unsigned __int64 nSysCurrentTime, unsigned __int64 nSysPhaseOffset, unsigned __int64 nSysTickCount, TimeSample *pts) {
// DWORD dwDayOfWeek;
// DWORD dwTimeZoneBias = cdwINVALID; // offset from UTC
// DWORD dwDispersion = cdwINVALID; // possible error
// DWORD dwStatus = 0; // are we synchronized? assume success
FILETIME ftSample;
HRESULT hr;
HwSampleParser *pParser = NULL;
unsigned __int64 u64Sample;
TimeSample ts;
ZeroMemory(&ts, sizeof(ts));
pParser = static_cast<HwSampleParser *>(hParser);
// Use the parser we've built to parse the data in pcData:
for (ParseActionIter paIter = pParser->vParseActions.begin(); paIter != pParser->vParseActions.end(); paIter++) {
hr = (*paIter)->Parse(pcData, &pcData);
_JumpIfError(hr, error, "(*paIter)->Parse(pcData, &pcData)");
}
// Convert the timestamp we've parsed into a 64-bit count:
if (!SystemTimeToFileTime(&pParser->stSample, &ftSample)) {
_JumpLastError(hr, error, "SystemTimeToFileTime");
}
u64Sample = (((unsigned __int64)ftSample.dwHighDateTime) << 32) | ftSample.dwLowDateTime;
ts.dwSize = sizeof(ts);
ts.dwRefid = 0x76767676; // BUGBUG: NYI
if (u64Sample > nSysCurrentTime) {
ts.toOffset = -((signed __int64)(u64Sample - nSysCurrentTime));
} else {
ts.toOffset = nSysCurrentTime - u64Sample;
}
ts.toOffset = u64Sample - nSysCurrentTime;
ts.toDelay = 0; // no roundtrip delay
ts.tpDispersion = 0; // BUGBUG: NYI, no dispersion for now
ts.nSysTickCount = nSysTickCount;
ts.nSysPhaseOffset = nSysPhaseOffset;
ts.nLeapFlags = 0; // BUGBUG: NYI, always say no warning
ts.nStratum = 0;
ts.dwTSFlags = 0;
*pts = ts;
hr = S_OK;
error:
return hr;
}