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.

203 lines
6.7 KiB

  1. #include "pch.hxx"
  2. #include <stdio.h>
  3. #include <windows.h>
  4. #include "iso8601.h"
  5. // This code implements a parser & generater for the ISO 8601 date format.
  6. // This table defines different "types" of characters for use as the columns
  7. // of the state table
  8. unsigned char iso8601chartable[256] = {
  9. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  10. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  11. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0x82, 0,
  12. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 0, 0, 0, 0, 0,
  13. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  14. 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0,
  15. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  16. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  17. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  18. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  19. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  20. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  21. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  22. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  23. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  24. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  25. };
  26. // State table
  27. // 0x80 bit = Error
  28. // 0x20 = Add character & advance to next field
  29. // 0x40 = Add character & advance to next field + skip one (for day of week)
  30. // 0x1f = Mask to determine next state #
  31. // Columns = input character type: unknown, number, "-", "T", ":", "Z"
  32. unsigned char iso8601StateTable[][6] =
  33. {
  34. 0x80, 0x01, 0x25, 0x80, 0x80, 0x80, // year
  35. 0x80, 0x02, 0x80, 0x80, 0x80, 0x80,
  36. 0x80, 0x03, 0x80, 0x80, 0x80, 0x80,
  37. 0x80, 0x24, 0x80, 0x80, 0x80, 0x80,
  38. 0x80, 0x06, 0x05, 0x85, 0x85, 0x05, //0x04 month
  39. 0x80, 0x06, 0x48, 0x80, 0x80, 0x80,
  40. 0x80, 0x47, 0x80, 0x80, 0x80, 0x80,
  41. 0x80, 0x09, 0x08, 0x88, 0x88, 0x08, //0x07 day
  42. 0x80, 0x09, 0x8b, 0x2b, 0x8b, 0x80,
  43. 0x80, 0x2a, 0x80, 0x80, 0x80, 0x80,
  44. 0x80, 0x0c, 0x8b, 0x0b, 0x8b, 0x08, //0x0a hour
  45. 0x80, 0x0c, 0x80, 0x80, 0x80, 0x80,
  46. 0x80, 0x2d, 0x80, 0x80, 0x80, 0x80,
  47. 0x80, 0x0f, 0x8e, 0x8e, 0x0e, 0x08, //0x0d min
  48. 0x80, 0x0f, 0x80, 0x80, 0x80, 0x80,
  49. 0x80, 0x30, 0x80, 0x80, 0x80, 0x80,
  50. 0x80, 0x12, 0x91, 0x91, 0x11, 0x08, //0x10 sec
  51. 0x80, 0x12, 0x80, 0x80, 0x80, 0x80,
  52. 0x80, 0x30, 0x80, 0x80, 0x80, 0x80,
  53. };
  54. // Convert a character string formatted as iso8601 into a SYSTEMTIME structure
  55. // Supports both basic & extended forms of iso8601.
  56. // isoDate: Input string. It can be null or space terminated.
  57. // pSysTime: Output SYSTEMTIME structure
  58. // lenient: true for normal operation. "false" if you want to detect incorrectly
  59. // formatted iso8601. Will still return the "best guess" value.
  60. // partial: Set to true if you will accept partial results. Note that this just fills
  61. // in zeros where data is missing, which strictly speaking can't be distinguished
  62. // from real zeros in this implementation. An improvement would have a second
  63. // structure to fill in with validity bits.
  64. HRESULT iso8601::toSystemTime(char *pszISODate, SYSTEMTIME *pst, DWORD *pdwFlags, BOOL fLenient, BOOL fPartial)
  65. {
  66. HRESULT hr = S_OK;
  67. WORD *dateWords = (WORD *)pst;
  68. WORD *endWord = dateWords + 7; // To detect the end of the date
  69. DWORD dwFlags = NOFLAGS;
  70. int state = 0;
  71. DWORD pos = 0;
  72. *dateWords = 0;
  73. if (NULL == pszISODate || NULL == pst)
  74. return E_INVALIDARG;
  75. // Main state machine loop. Loop until a space or null.
  76. while(*pszISODate && *pszISODate != ' ')
  77. {
  78. char code = iso8601chartable[*pszISODate];
  79. if(code & 0x80)
  80. {
  81. if(!fLenient)
  82. hr = E_FAIL; // Illegal character only when lenient
  83. code = code & 0x7f;
  84. }
  85. unsigned char action = iso8601StateTable[state][code];
  86. state = action&0x1f; // Calculate the next state
  87. if(code == 1) // The character code 1 is always a number which gets accumulated
  88. {
  89. dwFlags |= (1 << pos);
  90. *dateWords = *dateWords * 10 + *pszISODate - '0';
  91. }
  92. switch(action >> 5)
  93. {
  94. case 0x1:
  95. if(!fPartial && !*dateWords)
  96. hr = E_FAIL; // Only partial, error
  97. if(dateWords == endWord) // Prevent an overflow
  98. {
  99. if (pdwFlags)
  100. *pdwFlags = dwFlags;
  101. return S_OK;
  102. }
  103. pos++;
  104. dateWords++;
  105. *dateWords = 0;
  106. break;
  107. case 0x2: // Finish piece & advance twice (past day of week)
  108. if(!fPartial && !*dateWords)
  109. hr = E_FAIL; // Only partial, error
  110. // We don't need to check for an overflow here since the state machine
  111. // only calls this to skip "dayofweek" in the SYSTEMTIME structure.
  112. // We could do dateWords+=2 instead of the following if leaving random
  113. // values in dayofweek is acceptable.
  114. dateWords++;
  115. *dateWords = 0;
  116. dateWords++;
  117. *dateWords = 0;
  118. pos += 2;
  119. break;
  120. }
  121. if((action & 0x80) && !fLenient)
  122. hr = E_FAIL;
  123. pszISODate++;
  124. }
  125. // Zero out the rest of the SYSTEMTIME structure
  126. while(dateWords < endWord)
  127. *(++dateWords) = 0;
  128. if (pdwFlags)
  129. *pdwFlags = dwFlags;
  130. return hr;
  131. }
  132. // The function toExtended accepts a SYSTEMTIME and converts it into the ISO8601 extended
  133. // form, placeing it in the character buffer 'buf'. The buffer 'buf' must have room for
  134. // a minimum of 40 characters to support the longest forms of 8601 (currently only 21 are used).
  135. HRESULT iso8601::fromSystemTime(SYSTEMTIME *pst, char *pszISODate)
  136. {
  137. if (NULL == pst || NULL == pszISODate)
  138. return E_INVALIDARG;
  139. pszISODate[0] = pst->wYear / 1000 + '0';
  140. pszISODate[1] = ((pst->wYear / 100) % 10) + '0';
  141. pszISODate[2] = ((pst->wYear / 10) % 10) + '0';
  142. pszISODate[3] = ((pst->wYear) % 10) + '0';
  143. pszISODate[4] = '.';
  144. pszISODate[5] = pst->wMonth / 10 + '0';
  145. pszISODate[6] = (pst->wMonth % 10) + '0';
  146. pszISODate[7] = '.';
  147. pszISODate[8] = pst->wDay / 10 + '0';
  148. pszISODate[9] = (pst->wDay % 10) + '0';
  149. pszISODate[10] = 'T';
  150. pszISODate[11] = pst->wHour / 10 + '0';
  151. pszISODate[12] = (pst->wHour % 10) + '0';
  152. pszISODate[13] = ':';
  153. pszISODate[14] = pst->wMinute / 10 + '0';
  154. pszISODate[15] = (pst->wMinute % 10) + '0';
  155. pszISODate[16] = ':';
  156. pszISODate[17] = pst->wSecond / 10 + '0';
  157. pszISODate[18] = (pst->wSecond % 10) + '0';
  158. pszISODate[19] = 'Z';
  159. pszISODate[20] = 0;
  160. return S_OK;
  161. }
  162. HRESULT iso8601::toFileTime(char *pszISODate, FILETIME *pft, DWORD *pdwFlags, BOOL fLenient, BOOL fPartial)
  163. {
  164. SYSTEMTIME st;
  165. HRESULT hr;
  166. hr = toSystemTime(pszISODate, &st, pdwFlags, fLenient, fPartial);
  167. if (SUCCEEDED(hr))
  168. hr = (SystemTimeToFileTime(&st, pft)?S_OK:E_FAIL);
  169. return hr;
  170. }
  171. HRESULT iso8601::fromFileTime(FILETIME *pft, char *pszISODate)
  172. {
  173. SYSTEMTIME stTime;
  174. HRESULT hr = E_FAIL;
  175. if (FileTimeToSystemTime(pft, &stTime))
  176. hr = fromSystemTime(&stTime, pszISODate);
  177. return hr;
  178. }