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

  1. //--------------------------------------------------------------------
  2. // parser.cpp - sample code
  3. // Copyright (C) Microsoft Corporation, 2001
  4. //
  5. // Created by: Duncan Bryce (duncanb), 9-13-2001
  6. //
  7. // Code to parse the samples returned from hardware providers
  8. //
  9. #include "pch.h"
  10. //
  11. // FORMAT STRING SPECIFICATION:
  12. //
  13. // pattern length (chars) description
  14. // ------------------------------------------------------------
  15. // * 1 ignored
  16. // MJ 5 modified julian date (MJD)
  17. // Y2 2 year without century (assumes 21st century)
  18. // Y4 4 year with century
  19. // M 2 month (01-12)
  20. // D 2 day of month (01-31)
  21. // H 2 hours (00-23)
  22. // m 2 minutes (00-59)
  23. // S 2 seconds (00-60) 60 indicates a leap second
  24. // s1: 1 .1 seconds
  25. // s2: 2 .01 seconds
  26. // s3: 3 .001 seconds
  27. //
  28. // BUGBUG: research better ways for doing accuracy codes, and record clocks which support
  29. // A: variable begin accuracy code definition: (ex: ^1A10B100C500DZ)
  30. // In: variable I == status char, n == number of status chars
  31. //
  32. //--------------------------------------------------------------------------------
  33. //
  34. // Utility methods
  35. //
  36. //--------------------------------------------------------------------------------
  37. HRESULT ParseNumber(char *pcData, DWORD dwPlaces, DWORD *pdwNumber) {
  38. char *pcDataEnd = pcData + dwPlaces;
  39. DWORD dwResult = 0;
  40. HRESULT hr;
  41. for (; pcData != pcDataEnd; pcData++) {
  42. dwResult *= 10;
  43. if (*pcData < '0' || '9' < *pcData) {
  44. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  45. _JumpError(hr, error, "ParseNumber: non-numeric input");
  46. }
  47. dwResult += (DWORD)(*pcData - '0');
  48. }
  49. *pdwNumber = dwResult;
  50. hr = S_OK;
  51. error:
  52. return hr;
  53. }
  54. //--------------------------------------------------------------------------------
  55. //
  56. // PARSER classes
  57. //
  58. //--------------------------------------------------------------------------------
  59. class ParseAction {
  60. public:
  61. virtual HRESULT Parse(char *cData, char **cDataNew) = 0;
  62. virtual ~ParseAction() { }
  63. };
  64. class ParseAccuracyCode : public ParseAction {
  65. public:
  66. ParseAccuracyCode() { }
  67. HRESULT Parse(char *pcData, char **ppcDataNew) {
  68. return HRESULT_FROM_WIN32(ERROR_CALL_NOT_IMPLEMENTED);
  69. }
  70. };
  71. class ParseStatusCode : public ParseAction {
  72. public:
  73. ParseStatusCode() { }
  74. HRESULT Parse(char *pcData, char **ppcDataNew) {
  75. return HRESULT_FROM_WIN32(ERROR_CALL_NOT_IMPLEMENTED);
  76. }
  77. };
  78. class IgnoreChar : public ParseAction {
  79. public:
  80. IgnoreChar() { }
  81. HRESULT Parse(char *pcData, char **ppcDataNew) {
  82. *ppcDataNew = pcData+1;
  83. return S_OK;
  84. }
  85. };
  86. class ParseModifiedJulianDate : public ParseAction {
  87. WORD *m_pwYear;
  88. WORD *m_pwMonth;
  89. WORD *m_pwDay;
  90. public:
  91. ParseModifiedJulianDate(WORD *pwYear, WORD *pwMonth, WORD *pwDay) : m_pwYear(pwYear), m_pwMonth(pwMonth), m_pwDay(pwDay) { }
  92. HRESULT Parse(char *pcData, char **ppcDataNew) {
  93. DWORD dwMJD;
  94. HRESULT hr;
  95. long l, n, i, j, d, y, m;
  96. hr = ParseNumber(pcData, 5/*MJD is always 5 places*/, &dwMJD);
  97. _JumpIfError(hr, error, "ParseNumber");
  98. // The algorithm is based on the Fliegel/van Flandern paper in COMM of the ACM 11/#10 p.657 Oct. 1968
  99. l = dwMJD + 68569 + 2400001;
  100. n = (( 4 * l ) - 2) / 146097;
  101. l = l - ( 146097 * n + 3 ) / 4;
  102. i = ( 4000 * ( l + 1 ) ) / 1461001;
  103. l = l - ( 1461 * i ) / 4 + 31;
  104. j = ( 80 * l ) / 2447;
  105. d = l - ( 2447 * j ) / 80;
  106. l = j / 11;
  107. m = j + 2 - ( 12 * l );
  108. y = 100 * ( n - 49 ) + i + l;
  109. // sanity checks:
  110. _MyAssert(1900 < y && y < (1<<16));
  111. _MyAssert( 0 < m && m < 13);
  112. _MyAssert( 0 < d && d < 32);
  113. // assign result pointers:
  114. *m_pwYear = y;
  115. *m_pwMonth = m;
  116. *m_pwDay = d;
  117. // calculate the new char input pointer:
  118. *ppcDataNew = pcData + 5 /*MJD is always 5 chars*/;
  119. hr = S_OK;
  120. error:
  121. return hr;
  122. }
  123. };
  124. class NumericParseAction : public ParseAction {
  125. WORD m_wPlaces;
  126. WORD m_wMin;
  127. WORD m_wMax;
  128. WORD m_wScale;
  129. WORD m_wOffset;
  130. WORD *m_pwValue;
  131. public:
  132. NumericParseAction(WORD wPlaces, WORD wMin, WORD wMax, WORD wScale, WORD wOffset, WORD *pwValue) :
  133. m_wPlaces(wPlaces), m_wMin(wMin), m_wMax(wMax), m_wScale(wScale), m_wOffset(wOffset), m_pwValue(pwValue) { }
  134. HRESULT Parse(char *pcData, char **ppcDataNew) {
  135. DWORD dwValue;
  136. HRESULT hr;
  137. hr = ParseNumber(pcData, m_wPlaces, &dwValue);
  138. _JumpIfError(hr, error, "ParseNumber");
  139. // Make sure that the result can fit into a WORD:
  140. if (dwValue >= (1<<16)) {
  141. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  142. _JumpError(hr, error, "ParseSmallNumber: result too large for 4-byte word");
  143. }
  144. // Make sure that the value we read is within bounds:
  145. if (m_wMin > dwValue || m_wMax < dwValue) {
  146. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  147. _JumpError(hr, error, "ParseFormatString: validating numeral");
  148. }
  149. // multiply in our scale factor:
  150. dwValue *= m_wScale;
  151. // add in our offset:
  152. dwValue += m_wOffset;
  153. // assign the computed value:
  154. *m_pwValue = (WORD)dwValue;
  155. // Increment our pointer to the data stream
  156. *ppcDataNew = pcData + m_wPlaces;
  157. hr = S_OK;
  158. error:
  159. return hr;
  160. }
  161. };
  162. typedef vector<ParseAction *> ParseActionVec;
  163. typedef ParseActionVec::iterator ParseActionIter;
  164. struct HwSampleParser {
  165. DWORD dwSampleSize;
  166. SYSTEMTIME stSample;
  167. ParseActionVec vParseActions;
  168. ~HwSampleParser() {
  169. for (ParseActionIter paIter = vParseActions.begin(); paIter != vParseActions.end(); paIter++) {
  170. delete (*paIter);
  171. }
  172. vParseActions.clear();
  173. }
  174. };
  175. //--------------------------------------------------------------------------------
  176. //
  177. // PUBLIC INTERFACE
  178. //
  179. //--------------------------------------------------------------------------------
  180. void FreeParser(HANDLE hParser) {
  181. delete (static_cast<HwSampleParser *>(hParser));
  182. }
  183. DWORD GetSampleSize(HANDLE hParser) {
  184. return (static_cast<HwSampleParser *>(hParser))->dwSampleSize;
  185. }
  186. HRESULT MakeParser(LPWSTR pwszFormat, HANDLE *phParser) {
  187. HRESULT hr;
  188. HwSampleParser *pParser = NULL;
  189. ParseAction *ppaCurrent = NULL;
  190. pParser = new HwSampleParser;
  191. _JumpIfOutOfMemory(hr, error, pParser);
  192. pParser->dwSampleSize = 0;
  193. ZeroMemory(&pParser->stSample, sizeof(pParser->stSample));
  194. // Add a series of parse actions to take based on the supplied format string:
  195. while (L'\0' != *pwszFormat) {
  196. if (L'*' == *pwszFormat) {
  197. ppaCurrent = new IgnoreChar;
  198. _JumpIfOutOfMemory(hr, error, ppaCurrent);
  199. pParser->dwSampleSize++;
  200. pwszFormat++;
  201. } else if (L'A' == *pwszFormat) {
  202. ppaCurrent = new ParseAccuracyCode;
  203. _JumpIfOutOfMemory(hr, error, ppaCurrent);
  204. pwszFormat++;
  205. } else if (L'I' == *pwszFormat) {
  206. ppaCurrent = new ParseStatusCode;
  207. _JumpIfOutOfMemory(hr, error, ppaCurrent);
  208. pwszFormat++;
  209. } else if (0 == wcsncmp(L"MJ", pwszFormat, 2)) {
  210. ppaCurrent = new ParseModifiedJulianDate(&(pParser->stSample.wYear), &(pParser->stSample.wMonth), &(pParser->stSample.wDay));
  211. _JumpIfOutOfMemory(hr, error, ppaCurrent);
  212. pParser->dwSampleSize += 5;
  213. pwszFormat += 2;
  214. } else {
  215. // try the numeric parse rules:
  216. struct NumericParseRule {
  217. WCHAR *wszPattern;
  218. WORD wPlaces;
  219. WORD wMin;
  220. WORD wMax;
  221. WORD wScale;
  222. WORD wOffset;
  223. WORD *pwValue;
  224. } rgNumericParseRules[] = {
  225. { L"Y2", 2, 0, 99, 1, 2000, &(pParser->stSample.wYear) }, // years w/o century
  226. { L"Y4", 4, 0, 9999, 1, 0, &(pParser->stSample.wYear) }, // years w/ century
  227. { L"M", 2, 1, 12, 1, 0, &(pParser->stSample.wMonth) }, // month of year
  228. { L"D", 2, 1, 31, 1, 0, &(pParser->stSample.wDay) }, // day of months
  229. { L"H", 2, 1, 24, 1, 0, &(pParser->stSample.wHour) }, // hours
  230. { L"m", 2, 1, 59, 1, 0, &(pParser->stSample.wMinute) }, // minutes
  231. { L"S", 2, 0, 60, 1, 0, &(pParser->stSample.wSecond) }, // seconds
  232. { L"s1", 1, 0, 9, 100, 0, &(pParser->stSample.wMilliseconds) }, // .1 second intervals
  233. { L"s2", 2, 0, 99, 10, 0, &(pParser->stSample.wMilliseconds) }, // .01 second intervals
  234. { L"s3", 3, 0, 999, 1, 0, &(pParser->stSample.wMilliseconds) }, // .001 second intervals
  235. };
  236. for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(rgNumericParseRules); dwIndex++) {
  237. NumericParseRule *npr = &rgNumericParseRules[dwIndex];
  238. if (0 == wcsncmp(npr->wszPattern, pwszFormat, wcslen(npr->wszPattern))) {
  239. ppaCurrent = new NumericParseAction(npr->wPlaces, npr->wMin, npr->wMax, npr->wScale, npr->wOffset, npr->pwValue);
  240. _JumpIfOutOfMemory(hr, error, ppaCurrent);
  241. pParser->dwSampleSize += npr->wPlaces;
  242. pwszFormat += wcslen(npr->wszPattern);
  243. break;
  244. }
  245. }
  246. }
  247. if (NULL == ppaCurrent) {
  248. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  249. _JumpError(hr, error, "MakeParser: bad format string");
  250. }
  251. _SafeStlCall(pParser->vParseActions.push_back(ppaCurrent), hr, error, "pParser->vParseActions.push_back(ppaCurrent)");
  252. ppaCurrent = NULL; // no longer responsible for freeing ppaCurrent
  253. }
  254. *phParser = pParser;
  255. pParser = NULL;
  256. hr = S_OK;
  257. error:
  258. if (NULL != ppaCurrent) {
  259. delete ppaCurrent;
  260. }
  261. if (NULL != pParser) {
  262. delete pParser;
  263. }
  264. return hr;
  265. }
  266. HRESULT ParseSample(HANDLE hParser, char *pcData, unsigned __int64 nSysCurrentTime, unsigned __int64 nSysPhaseOffset, unsigned __int64 nSysTickCount, TimeSample *pts) {
  267. // DWORD dwDayOfWeek;
  268. // DWORD dwTimeZoneBias = cdwINVALID; // offset from UTC
  269. // DWORD dwDispersion = cdwINVALID; // possible error
  270. // DWORD dwStatus = 0; // are we synchronized? assume success
  271. FILETIME ftSample;
  272. HRESULT hr;
  273. HwSampleParser *pParser = NULL;
  274. unsigned __int64 u64Sample;
  275. TimeSample ts;
  276. ZeroMemory(&ts, sizeof(ts));
  277. pParser = static_cast<HwSampleParser *>(hParser);
  278. // Use the parser we've built to parse the data in pcData:
  279. for (ParseActionIter paIter = pParser->vParseActions.begin(); paIter != pParser->vParseActions.end(); paIter++) {
  280. hr = (*paIter)->Parse(pcData, &pcData);
  281. _JumpIfError(hr, error, "(*paIter)->Parse(pcData, &pcData)");
  282. }
  283. // Convert the timestamp we've parsed into a 64-bit count:
  284. if (!SystemTimeToFileTime(&pParser->stSample, &ftSample)) {
  285. _JumpLastError(hr, error, "SystemTimeToFileTime");
  286. }
  287. u64Sample = (((unsigned __int64)ftSample.dwHighDateTime) << 32) | ftSample.dwLowDateTime;
  288. ts.dwSize = sizeof(ts);
  289. ts.dwRefid = 0x76767676; // BUGBUG: NYI
  290. if (u64Sample > nSysCurrentTime) {
  291. ts.toOffset = -((signed __int64)(u64Sample - nSysCurrentTime));
  292. } else {
  293. ts.toOffset = nSysCurrentTime - u64Sample;
  294. }
  295. ts.toOffset = u64Sample - nSysCurrentTime;
  296. ts.toDelay = 0; // no roundtrip delay
  297. ts.tpDispersion = 0; // BUGBUG: NYI, no dispersion for now
  298. ts.nSysTickCount = nSysTickCount;
  299. ts.nSysPhaseOffset = nSysPhaseOffset;
  300. ts.nLeapFlags = 0; // BUGBUG: NYI, always say no warning
  301. ts.nStratum = 0;
  302. ts.dwTSFlags = 0;
  303. *pts = ts;
  304. hr = S_OK;
  305. error:
  306. return hr;
  307. }