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.

2265 lines
59 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1996
  6. //
  7. // File: ntcalls.cxx
  8. //
  9. // Contents: Code for rtl support on Win95
  10. //
  11. //
  12. // History: 01-April-1997 Created ChandanS
  13. //
  14. //------------------------------------------------------------------------
  15. #include <kerb.hxx>
  16. #include <kerbp.h>
  17. /*++
  18. Copyright (c) 1989 Microsoft Corporation
  19. Module Name:
  20. Time.c
  21. Abstract:
  22. This module implements the absolute time conversion routines for NT.
  23. Absolute LARGE_INTEGER in NT is represented by a 64-bit large integer accurate
  24. to 100ns resolution. The smallest time resolution used by this package
  25. is One millisecond. The basis for NT time is the start of 1601 which
  26. was chosen because it is the start of a new quadricentury. Some facts
  27. to note are:
  28. o At 100ns resolution 32 bits is good for about 429 seconds (or 7 minutes)
  29. o At 100ns resolution a large integer (i.e., 63 bits) is good for
  30. about 29,247 years, or around 10,682,247 days.
  31. o At 1 second resolution 31 bits is good for about 68 years
  32. o At 1 second resolution 32 bits is good for about 136 years
  33. o 100ns Time (ignoring time less than a millisecond) can be expressed
  34. as two values, Days and Milliseconds. Where Days is the number of
  35. whole days and Milliseconds is the number of milliseconds for the
  36. partial day. Both of these values are ULONG.
  37. Given these facts most of the conversions are done by first splitting
  38. LARGE_INTEGER into Days and Milliseconds.
  39. Author:
  40. Gary Kimura [GaryKi] 26-Aug-1989
  41. Environment:
  42. Pure utility routine
  43. Revision History:
  44. --*/
  45. //
  46. // The following two tables map a day offset within a year to the month
  47. // containing the day. Both tables are zero based. For example, day
  48. // offset of 0 to 30 map to 0 (which is Jan).
  49. //
  50. UCHAR LeapYearDayToMonth[366] = {
  51. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // January
  52. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // February
  53. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // March
  54. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // April
  55. 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // May
  56. 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // June
  57. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // July
  58. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // August
  59. 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // September
  60. 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // October
  61. 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // November
  62. 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11}; // December
  63. UCHAR NormalYearDayToMonth[365] = {
  64. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // January
  65. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // February
  66. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // March
  67. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // April
  68. 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // May
  69. 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // June
  70. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // July
  71. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // August
  72. 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // September
  73. 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // October
  74. 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // November
  75. 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11}; // December
  76. //
  77. // The following two tables map a month index to the number of days preceding
  78. // the month in the year. Both tables are zero based. For example, 1 (Feb)
  79. // has 31 days preceding it. To help calculate the maximum number of days
  80. // in a month each table has 13 entries, so the number of days in a month
  81. // of index i is the table entry of i+1 minus the table entry of i.
  82. //
  83. CSHORT LeapYearDaysPrecedingMonth[13] = {
  84. 0, // January
  85. 31, // February
  86. 31+29, // March
  87. 31+29+31, // April
  88. 31+29+31+30, // May
  89. 31+29+31+30+31, // June
  90. 31+29+31+30+31+30, // July
  91. 31+29+31+30+31+30+31, // August
  92. 31+29+31+30+31+30+31+31, // September
  93. 31+29+31+30+31+30+31+31+30, // October
  94. 31+29+31+30+31+30+31+31+30+31, // November
  95. 31+29+31+30+31+30+31+31+30+31+30, // December
  96. 31+29+31+30+31+30+31+31+30+31+30+31};
  97. CSHORT NormalYearDaysPrecedingMonth[13] = {
  98. 0, // January
  99. 31, // February
  100. 31+28, // March
  101. 31+28+31, // April
  102. 31+28+31+30, // May
  103. 31+28+31+30+31, // June
  104. 31+28+31+30+31+30, // July
  105. 31+28+31+30+31+30+31, // August
  106. 31+28+31+30+31+30+31+31, // September
  107. 31+28+31+30+31+30+31+31+30, // October
  108. 31+28+31+30+31+30+31+31+30+31, // November
  109. 31+28+31+30+31+30+31+31+30+31+30, // December
  110. 31+28+31+30+31+30+31+31+30+31+30+31};
  111. //
  112. // The following definitions and declarations are some important constants
  113. // used in the time conversion routines
  114. //
  115. //
  116. // This is the week day that January 1st, 1601 fell on (a Monday)
  117. //
  118. #define WEEKDAY_OF_1601 1
  119. //
  120. // These are known constants used to convert 1970 and 1980 times to 1601
  121. // times. They are the number of seconds from the 1601 base to the start
  122. // of 1970 and the start of 1980. The number of seconds from 1601 to
  123. // 1970 is 369 years worth, or (369 * 365) + 89 leap days = 134774 days, or
  124. // 134774 * 864000 seconds, which is equal to the large integer defined
  125. // below. The number of seconds from 1601 to 1980 is 379 years worth, or etc.
  126. //
  127. LARGE_INTEGER SecondsToStartOf1970 = {0xb6109100, 0x00000002};
  128. LARGE_INTEGER SecondsToStartOf1980 = {0xc8df3700, 0x00000002};
  129. //
  130. // These are the magic numbers needed to do our extended division. The
  131. // only numbers we ever need to divide by are
  132. //
  133. // 10,000 = convert 100ns tics to millisecond tics
  134. //
  135. // 10,000,000 = convert 100ns tics to one second tics
  136. //
  137. // 86,400,000 = convert Millisecond tics to one day tics
  138. //
  139. LARGE_INTEGER Magic10000 = {0xe219652c, 0xd1b71758};
  140. #define SHIFT10000 13
  141. LARGE_INTEGER Magic10000000 = {0xe57a42bd, 0xd6bf94d5};
  142. #define SHIFT10000000 23
  143. LARGE_INTEGER Magic86400000 = {0xfa67b90e, 0xc6d750eb};
  144. #define SHIFT86400000 26
  145. //
  146. // To make the code more readable we'll also define some macros to
  147. // do the actual division for use
  148. //
  149. #define Convert100nsToMilliseconds(LARGE_INTEGER) ( \
  150. RtlExtendedMagicDivide( (LARGE_INTEGER), Magic10000, SHIFT10000 ) \
  151. )
  152. #define ConvertMillisecondsTo100ns(MILLISECONDS) ( \
  153. RtlExtendedIntegerMultiply( (MILLISECONDS), 10000 ) \
  154. )
  155. #define Convert100nsToSeconds(LARGE_INTEGER) ( \
  156. RtlExtendedMagicDivide( (LARGE_INTEGER), Magic10000000, SHIFT10000000 ) \
  157. )
  158. #define ConvertSecondsTo100ns(SECONDS) ( \
  159. RtlExtendedIntegerMultiply( (SECONDS), 10000000 ) \
  160. )
  161. #define ConvertMillisecondsToDays(LARGE_INTEGER) ( \
  162. RtlExtendedMagicDivide( (LARGE_INTEGER), Magic86400000, SHIFT86400000 ) \
  163. )
  164. #define ConvertDaysToMilliseconds(DAYS) ( \
  165. Int32x32To64( (DAYS), 86400000 ) \
  166. )
  167. //
  168. // Local support routine
  169. //
  170. ULONG
  171. ElapsedDaysToYears (
  172. IN ULONG ElapsedDays
  173. )
  174. /*++
  175. Routine Description:
  176. This routine computes the number of total years contained in the indicated
  177. number of elapsed days. The computation is to first compute the number of
  178. 400 years and subtract that it, then do the 100 years and subtract that out,
  179. then do the number of 4 years and subtract that out. Then what we have left
  180. is the number of days with in a normalized 4 year block. Normalized being that
  181. the first three years are not leap years.
  182. Arguments:
  183. ElapsedDays - Supplies the number of days to use
  184. Return Value:
  185. ULONG - Returns the number of whole years contained within the input number
  186. of days.
  187. --*/
  188. {
  189. ULONG NumberOf400s;
  190. ULONG NumberOf100s;
  191. ULONG NumberOf4s;
  192. ULONG Years;
  193. //
  194. // A 400 year time block is 365*400 + 400/4 - 400/100 + 400/400 = 146097 days
  195. // long. So we simply compute the number of whole 400 year block and the
  196. // the number days contained in those whole blocks, and subtract if from the
  197. // elapsed day total
  198. //
  199. NumberOf400s = ElapsedDays / 146097;
  200. ElapsedDays -= NumberOf400s * 146097;
  201. //
  202. // A 100 year time block is 365*100 + 100/4 - 100/100 = 36524 days long.
  203. // The computation for the number of 100 year blocks is biased by 3/4 days per
  204. // 100 years to account for the extra leap day thrown in on the last year
  205. // of each 400 year block.
  206. //
  207. NumberOf100s = (ElapsedDays * 100 + 75) / 3652425;
  208. ElapsedDays -= NumberOf100s * 36524;
  209. //
  210. // A 4 year time block is 365*4 + 4/4 = 1461 days long.
  211. //
  212. NumberOf4s = ElapsedDays / 1461;
  213. ElapsedDays -= NumberOf4s * 1461;
  214. //
  215. // Now the number of whole years is the number of 400 year blocks times 400,
  216. // 100 year blocks time 100, 4 year blocks times 4, and the number of elapsed
  217. // whole years, taking into account the 3/4 day per year needed to handle the
  218. // leap year.
  219. //
  220. Years = (NumberOf400s * 400) +
  221. (NumberOf100s * 100) +
  222. (NumberOf4s * 4) +
  223. (ElapsedDays * 100 + 75) / 36525;
  224. return Years;
  225. }
  226. //
  227. // ULONG
  228. // NumberOfLeapYears (
  229. // IN ULONG ElapsedYears
  230. // );
  231. //
  232. // The number of leap years is simply the number of years divided by 4
  233. // minus years divided by 100 plus years divided by 400. This says
  234. // that every four years is a leap year except centuries, and the
  235. // exception to the exception is the quadricenturies
  236. //
  237. #define NumberOfLeapYears(YEARS) ( \
  238. ((YEARS) / 4) - ((YEARS) / 100) + ((YEARS) / 400) \
  239. )
  240. //
  241. // ULONG
  242. // ElapsedYearsToDays (
  243. // IN ULONG ElapsedYears
  244. // );
  245. //
  246. // The number of days contained in elapsed years is simply the number
  247. // of years times 365 (because every year has at least 365 days) plus
  248. // the number of leap years there are (i.e., the number of 366 days years)
  249. //
  250. #define ElapsedYearsToDays(YEARS) ( \
  251. ((YEARS) * 365) + NumberOfLeapYears(YEARS) \
  252. )
  253. //
  254. // BOOLEAN
  255. // IsLeapYear (
  256. // IN ULONG ElapsedYears
  257. // );
  258. //
  259. // If it is an even 400 or a non century leapyear then the
  260. // answer is true otherwise it's false
  261. //
  262. #define IsLeapYear(YEARS) ( \
  263. (((YEARS) % 400 == 0) || \
  264. ((YEARS) % 100 != 0) && ((YEARS) % 4 == 0)) ? \
  265. TRUE \
  266. : \
  267. FALSE \
  268. )
  269. //
  270. // ULONG
  271. // MaxDaysInMonth (
  272. // IN ULONG Year,
  273. // IN ULONG Month
  274. // );
  275. //
  276. // The maximum number of days in a month depend on the year and month.
  277. // It is the difference between the days to the month and the days
  278. // to the following month
  279. //
  280. #define MaxDaysInMonth(YEAR,MONTH) ( \
  281. IsLeapYear(YEAR) ? \
  282. LeapYearDaysPrecedingMonth[(MONTH) + 1] - \
  283. LeapYearDaysPrecedingMonth[(MONTH)] \
  284. : \
  285. NormalYearDaysPrecedingMonth[(MONTH) + 1] - \
  286. NormalYearDaysPrecedingMonth[(MONTH)] \
  287. )
  288. //
  289. // Internal Support routine
  290. //
  291. static
  292. VOID
  293. TimeToDaysAndFraction (
  294. IN PLARGE_INTEGER Time,
  295. OUT PULONG ElapsedDays,
  296. OUT PULONG Milliseconds
  297. )
  298. /*++
  299. Routine Description:
  300. This routine converts an input 64-bit time value to the number
  301. of total elapsed days and the number of milliseconds in the
  302. partial day.
  303. Arguments:
  304. Time - Supplies the input time to convert from
  305. ElapsedDays - Receives the number of elapsed days
  306. Milliseconds - Receives the number of milliseconds in the partial day
  307. Return Value:
  308. None
  309. --*/
  310. {
  311. LARGE_INTEGER TotalMilliseconds;
  312. LARGE_INTEGER Temp;
  313. //
  314. // Convert the input time to total milliseconds
  315. //
  316. TotalMilliseconds = Convert100nsToMilliseconds( *(PLARGE_INTEGER)Time );
  317. //
  318. // Convert milliseconds to total days
  319. //
  320. Temp = ConvertMillisecondsToDays( TotalMilliseconds );
  321. //
  322. // Set the elapsed days from temp, we've divided it enough so that
  323. // the high part must be zero.
  324. //
  325. *ElapsedDays = Temp.LowPart;
  326. //
  327. // Calculate the exact number of milliseconds in the elapsed days
  328. // and subtract that from the total milliseconds to figure out
  329. // the number of milliseconds left in the partial day
  330. //
  331. Temp.QuadPart = ConvertDaysToMilliseconds( *ElapsedDays );
  332. Temp.QuadPart = TotalMilliseconds.QuadPart - Temp.QuadPart;
  333. //
  334. // Set the fraction part from temp, the total number of milliseconds in
  335. // a day guarantees that the high part must be zero.
  336. //
  337. *Milliseconds = Temp.LowPart;
  338. //
  339. // And return to our caller
  340. //
  341. return;
  342. }
  343. //
  344. // Internal Support routine
  345. //
  346. //static
  347. VOID
  348. DaysAndFractionToTime (
  349. IN ULONG ElapsedDays,
  350. IN ULONG Milliseconds,
  351. OUT PLARGE_INTEGER Time
  352. )
  353. /*++
  354. Routine Description:
  355. This routine converts an input elapsed day count and partial time
  356. in milliseconds to a 64-bit time value.
  357. Arguments:
  358. ElapsedDays - Supplies the number of elapsed days
  359. Milliseconds - Supplies the number of milliseconds in the partial day
  360. Time - Receives the output time to value
  361. Return Value:
  362. None
  363. --*/
  364. {
  365. LARGE_INTEGER Temp;
  366. LARGE_INTEGER Temp2;
  367. //
  368. // Calculate the exact number of milliseconds in the elapsed days.
  369. //
  370. Temp.QuadPart = ConvertDaysToMilliseconds( ElapsedDays );
  371. //
  372. // Convert milliseconds to a large integer
  373. //
  374. Temp2.LowPart = Milliseconds;
  375. Temp2.HighPart = 0;
  376. //
  377. // add milliseconds to the whole day milliseconds
  378. //
  379. Temp.QuadPart = Temp.QuadPart + Temp2.QuadPart;
  380. //
  381. // Finally convert the milliseconds to 100ns resolution
  382. //
  383. *(PLARGE_INTEGER)Time = ConvertMillisecondsTo100ns( Temp );
  384. //
  385. // and return to our caller
  386. //
  387. return;
  388. }
  389. WCHAR
  390. MyUpcaseChar (WCHAR wc)
  391. //
  392. // WARNING -- not DBCS safe
  393. //
  394. {
  395. CHAR sz[2];
  396. sz[0]= (CHAR) wc;
  397. sz[1]=0;
  398. AnsiUpper(sz);
  399. return (WCHAR) (sz[0]);
  400. }
  401. WCHAR
  402. MyLowercaseChar (WCHAR wc)
  403. //
  404. // WARNING -- not DBCS safe
  405. //
  406. {
  407. CHAR sz[2];
  408. sz[0]= (CHAR) wc;
  409. sz[1]=0;
  410. AnsiLower(sz);
  411. return (WCHAR) (sz[0]);
  412. }
  413. VOID
  414. MyRtlTimeToTimeFields (
  415. IN PLARGE_INTEGER Time,
  416. OUT PTIME_FIELDS TimeFields
  417. )
  418. /*++
  419. Routine Description:
  420. This routine converts an input 64-bit LARGE_INTEGER variable to its corresponding
  421. time field record. It will tell the caller the year, month, day, hour,
  422. minute, second, millisecond, and weekday corresponding to the input time
  423. variable.
  424. Arguments:
  425. Time - Supplies the time value to interpret
  426. TimeFields - Receives a value corresponding to Time
  427. Return Value:
  428. None
  429. --*/
  430. {
  431. ULONG Years;
  432. ULONG Month;
  433. ULONG Days;
  434. ULONG Hours;
  435. ULONG Minutes;
  436. ULONG Seconds;
  437. ULONG Milliseconds;
  438. //
  439. // First divide the input time 64 bit time variable into
  440. // the number of whole days and part days (in milliseconds)
  441. //
  442. TimeToDaysAndFraction( Time, &Days, &Milliseconds );
  443. //
  444. // Compute which weekday it is and save it away now in the output
  445. // variable. We add the weekday of the base day to bias our computation
  446. // which means that if one day has elapsed then we the weekday we want
  447. // is the Jan 2nd, 1601.
  448. //
  449. TimeFields->Weekday = (CSHORT)((Days + WEEKDAY_OF_1601) % 7);
  450. //
  451. // Calculate the number of whole years contained in the elapsed days
  452. // For example if Days = 500 then Years = 1
  453. //
  454. Years = ElapsedDaysToYears( Days );
  455. //
  456. // And subtract the number of whole years from our elapsed days
  457. // For example if Days = 500, Years = 1, and the new days is equal
  458. // to 500 - 365 (normal year).
  459. //
  460. Days = Days - ElapsedYearsToDays( Years );
  461. //
  462. // Now test whether the year we are working on (i.e., The year
  463. // after the total number of elapsed years) is a leap year
  464. // or not.
  465. //
  466. if (IsLeapYear( Years + 1 )) {
  467. //
  468. // The current year is a leap year, so figure out what month
  469. // it is, and then subtract the number of days preceding the
  470. // month from the days to figure out what day of the month it is
  471. //
  472. Month = LeapYearDayToMonth[Days];
  473. Days = Days - LeapYearDaysPrecedingMonth[Month];
  474. } else {
  475. //
  476. // The current year is a normal year, so figure out the month
  477. // and days as described above for the leap year case
  478. //
  479. Month = NormalYearDayToMonth[Days];
  480. Days = Days - NormalYearDaysPrecedingMonth[Month];
  481. }
  482. //
  483. // Now we need to compute the elapsed hour, minute, second, milliseconds
  484. // from the millisecond variable. This variable currently contains
  485. // the number of milliseconds in our input time variable that did not
  486. // fit into a whole day. To compute the hour, minute, second part
  487. // we will actually do the arithmetic backwards computing milliseconds
  488. // seconds, minutes, and then hours. We start by computing the
  489. // number of whole seconds left in the day, and then computing
  490. // the millisecond remainder.
  491. //
  492. Seconds = Milliseconds / 1000;
  493. Milliseconds = Milliseconds % 1000;
  494. //
  495. // Now we compute the number of whole minutes left in the day
  496. // and the number of remainder seconds
  497. //
  498. Minutes = Seconds / 60;
  499. Seconds = Seconds % 60;
  500. //
  501. // Now compute the number of whole hours left in the day
  502. // and the number of remainder minutes
  503. //
  504. Hours = Minutes / 60;
  505. Minutes = Minutes % 60;
  506. //
  507. // As our final step we put everything into the time fields
  508. // output variable
  509. //
  510. TimeFields->Year = (CSHORT)(Years + 1601);
  511. TimeFields->Month = (CSHORT)(Month + 1);
  512. TimeFields->Day = (CSHORT)(Days + 1);
  513. TimeFields->Hour = (CSHORT)Hours;
  514. TimeFields->Minute = (CSHORT)Minutes;
  515. TimeFields->Second = (CSHORT)Seconds;
  516. TimeFields->Milliseconds = (CSHORT)Milliseconds;
  517. //
  518. // and return to our caller
  519. //
  520. return;
  521. }
  522. BOOLEAN
  523. MyRtlTimeFieldsToTime (
  524. IN PTIME_FIELDS TimeFields,
  525. OUT PLARGE_INTEGER Time
  526. )
  527. /*++
  528. Routine Description:
  529. This routine converts an input Time Field variable to a 64-bit NT time
  530. value. It ignores the WeekDay of the time field.
  531. Arguments:
  532. TimeFields - Supplies the time field record to use
  533. Time - Receives the NT Time corresponding to TimeFields
  534. Return Value:
  535. BOOLEAN - TRUE if the Time Fields is well formed and within the
  536. range of time expressible by LARGE_INTEGER and FALSE otherwise.
  537. --*/
  538. {
  539. ULONG Year;
  540. ULONG Month;
  541. ULONG Day;
  542. ULONG Hour;
  543. ULONG Minute;
  544. ULONG Second;
  545. ULONG Milliseconds;
  546. ULONG ElapsedDays;
  547. ULONG ElapsedMilliseconds;
  548. //
  549. // Load the time field elements into local variables. This should
  550. // ensure that the compiler will only load the input elements
  551. // once, even if there are alias problems. It will also make
  552. // everything (except the year) zero based. We cannot zero base the
  553. // year because then we can't recognize cases where we're given a year
  554. // before 1601.
  555. //
  556. Year = TimeFields->Year;
  557. Month = TimeFields->Month - 1;
  558. Day = TimeFields->Day - 1;
  559. Hour = TimeFields->Hour;
  560. Minute = TimeFields->Minute;
  561. Second = TimeFields->Second;
  562. Milliseconds = TimeFields->Milliseconds;
  563. //
  564. // Check that the time field input variable contains
  565. // proper values.
  566. //
  567. if ((TimeFields->Month < 1) ||
  568. (TimeFields->Day < 1) ||
  569. (Year < 1601) ||
  570. (Month > 11) ||
  571. ((CSHORT)Day >= MaxDaysInMonth(Year, Month)) ||
  572. (Hour > 23) ||
  573. (Minute > 59) ||
  574. (Second > 59) ||
  575. (Milliseconds > 999)) {
  576. return FALSE;
  577. }
  578. //
  579. // Compute the total number of elapsed days represented by the
  580. // input time field variable
  581. //
  582. ElapsedDays = ElapsedYearsToDays( Year - 1601 );
  583. if (IsLeapYear( Year - 1600 )) {
  584. ElapsedDays += LeapYearDaysPrecedingMonth[ Month ];
  585. } else {
  586. ElapsedDays += NormalYearDaysPrecedingMonth[ Month ];
  587. }
  588. ElapsedDays += Day;
  589. //
  590. // Now compute the total number of milliseconds in the fractional
  591. // part of the day
  592. //
  593. ElapsedMilliseconds = (((Hour*60) + Minute)*60 + Second)*1000 + Milliseconds;
  594. //
  595. // Given the elapsed days and milliseconds we can now build
  596. // the output time variable
  597. //
  598. DaysAndFractionToTime( ElapsedDays, ElapsedMilliseconds, Time );
  599. //
  600. // And return to our caller
  601. //
  602. return TRUE;
  603. }
  604. VOID
  605. MyRtlInitUnicodeString(
  606. OUT PUNICODE_STRING DestinationString,
  607. IN PCWSTR SourceString OPTIONAL
  608. )
  609. /*++
  610. Routine Description:
  611. The RtlInitUnicodeString function initializes an NT counted
  612. unicode string. The DestinationString is initialized to point to
  613. the SourceString and the Length and MaximumLength fields of
  614. DestinationString are initialized to the length of the SourceString,
  615. which is zero if SourceString is not specified.
  616. Arguments:
  617. DestinationString - Pointer to the counted string to initialize
  618. SourceString - Optional pointer to a null terminated unicode string that
  619. the counted string is to point to.
  620. Return Value:
  621. None.
  622. --*/
  623. {
  624. ULONG Length;
  625. DestinationString->Buffer = (PWSTR)SourceString;
  626. if (ARGUMENT_PRESENT( SourceString )) {
  627. Length = wcslen( SourceString ) * sizeof( WCHAR );
  628. DestinationString->Length = (USHORT)Length;
  629. DestinationString->MaximumLength = (USHORT)(Length + sizeof(UNICODE_NULL));
  630. }
  631. else {
  632. DestinationString->MaximumLength = 0;
  633. DestinationString->Length = 0;
  634. }
  635. }
  636. VOID
  637. MyRtlInitAnsiString(
  638. OUT PANSI_STRING DestinationString,
  639. IN PCSTR SourceString OPTIONAL
  640. )
  641. /*++
  642. Routine Description:
  643. The RtlInitAnsiString function initializes an NT counted string.
  644. The DestinationString is initialized to point to the SourceString
  645. and the Length and MaximumLength fields of DestinationString are
  646. initialized to the length of the SourceString, which is zero if
  647. SourceString is not specified.
  648. Arguments:
  649. DestinationString - Pointer to the counted string to initialize
  650. SourceString - Optional pointer to a null terminated string that
  651. the counted string is to point to.
  652. Return Value:
  653. None.
  654. --*/
  655. {
  656. ULONG Length;
  657. DestinationString->Buffer = (PCHAR)SourceString;
  658. if (ARGUMENT_PRESENT( SourceString )) {
  659. Length = strlen(SourceString);
  660. DestinationString->Length = (USHORT)Length;
  661. DestinationString->MaximumLength = (USHORT)(Length+1);
  662. }
  663. else {
  664. DestinationString->Length = 0;
  665. DestinationString->MaximumLength = 0;
  666. }
  667. }
  668. NTSTATUS
  669. MyRtlAnsiStringToUnicodeString(
  670. OUT PUNICODE_STRING DestinationString,
  671. IN PANSI_STRING SourceString,
  672. IN BOOLEAN AllocateDestinationString
  673. )
  674. /*++
  675. Routine Description:
  676. This functions converts the specified ansi source string into a
  677. Unicode string. The translation is done with respect to the
  678. current system locale information.
  679. Arguments:
  680. DestinationString - Returns a unicode string that is equivalent to
  681. the ansi source string. The maximum length field is only
  682. set if AllocateDestinationString is TRUE.
  683. SourceString - Supplies the ansi source string that is to be
  684. converted to unicode.
  685. AllocateDestinationString - Supplies a flag that controls whether or
  686. not this API allocates the buffer space for the destination
  687. string. If it does, then the buffer must be deallocated using
  688. RtlFreeUnicodeString (note that only storage for
  689. DestinationString->Buffer is allocated by this API).
  690. Return Value:
  691. SUCCESS - The conversion was successful
  692. !SUCCESS - The operation failed. No storage was allocated and no
  693. conversion was done. None.
  694. --*/
  695. {
  696. ULONG UnicodeLength;
  697. ULONG Index = 0;
  698. NTSTATUS st = STATUS_SUCCESS;
  699. UnicodeLength = (SourceString->Length + 1) * sizeof(WCHAR);
  700. if ( UnicodeLength > MAXUSHORT ) {
  701. return STATUS_INVALID_PARAMETER_2;
  702. }
  703. DestinationString->Length = (USHORT)(UnicodeLength - sizeof(UNICODE_NULL));
  704. if ( AllocateDestinationString ) {
  705. DestinationString->MaximumLength = (USHORT)UnicodeLength;
  706. DestinationString->Buffer = (PWSTR) LocalAlloc(0, UnicodeLength);
  707. if ( !DestinationString->Buffer ) {
  708. return STATUS_NO_MEMORY;
  709. }
  710. }
  711. else {
  712. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  713. return STATUS_BUFFER_OVERFLOW;
  714. }
  715. }
  716. if (SourceString->Length != 0)
  717. {
  718. Index = MultiByteToWideChar(
  719. CP_ACP,
  720. MB_PRECOMPOSED,
  721. SourceString->Buffer,
  722. SourceString->Length,
  723. DestinationString->Buffer,
  724. DestinationString->MaximumLength
  725. );
  726. if (Index == 0) {
  727. if ( AllocateDestinationString ) {
  728. LocalFree(DestinationString->Buffer);
  729. }
  730. return STATUS_NO_MEMORY;
  731. }
  732. }
  733. DestinationString->Buffer[Index] = UNICODE_NULL;
  734. return st;
  735. }
  736. BOOLEAN
  737. MyRtlCreateUnicodeStringFromAsciiz(
  738. OUT PUNICODE_STRING DestinationString,
  739. IN PCSTR SourceString
  740. )
  741. {
  742. ANSI_STRING AnsiString;
  743. NTSTATUS Status;
  744. if (!ARGUMENT_PRESENT(SourceString))
  745. {
  746. DestinationString->Buffer = NULL;
  747. DestinationString->Length = 0;
  748. DestinationString->MaximumLength = 0;
  749. return (TRUE);
  750. }
  751. MyRtlInitAnsiString( &AnsiString, SourceString );
  752. Status = MyRtlAnsiStringToUnicodeString( DestinationString, &AnsiString, TRUE );
  753. if (NT_SUCCESS( Status )) {
  754. return( TRUE );
  755. }
  756. else {
  757. return( FALSE );
  758. }
  759. }
  760. NTSTATUS
  761. MyRtlUpcaseUnicodeString(
  762. OUT PUNICODE_STRING DestinationString,
  763. IN PUNICODE_STRING SourceString,
  764. IN BOOLEAN AllocateDestinationString
  765. )
  766. /*++
  767. Routine Description:
  768. This functions converts the specified unicode source string into an
  769. upcased unicode string. The translation is done with respect to the
  770. current system locale information.
  771. Arguments:
  772. DestinationString - Returns a unicode string that is the upcased equivalent
  773. to the unicode source string. The maximum length field is only set if
  774. AllocateDestinationString is TRUE.
  775. SourceString - Supplies the unicode source string that is to being
  776. upcased.
  777. AllocateDestinationString - Supplies a flag that controls whether or
  778. not this API allocates the buffer space for the destination
  779. string. If it does, then the buffer must be deallocated using
  780. RtlFreeUnicodeString (note that only storage for
  781. DestinationString->Buffer is allocated by this API).
  782. Return Value:
  783. SUCCESS - The conversion was successful
  784. !SUCCESS - The operation failed. No storage was allocated and no
  785. conversion was done. None.
  786. --*/
  787. {
  788. ULONG Index;
  789. ULONG StopIndex;
  790. if ( AllocateDestinationString ) {
  791. DestinationString->MaximumLength = SourceString->Length;
  792. DestinationString->Buffer = (LPWSTR)LocalAlloc(0, (ULONG)DestinationString->MaximumLength);
  793. if ( !DestinationString->Buffer ) {
  794. return STATUS_NO_MEMORY;
  795. }
  796. }
  797. else {
  798. if ( SourceString->Length > DestinationString->MaximumLength ) {
  799. return STATUS_BUFFER_OVERFLOW;
  800. }
  801. }
  802. StopIndex = ((ULONG)SourceString->Length) / sizeof( WCHAR );
  803. for (Index = 0; Index < StopIndex; Index++) {
  804. // WIN32_CHICAGO Use some other Upcase mechanism
  805. // DestinationString->Buffer[Index] = (WCHAR)NLS_UPCASE(SourceString->Buffer[Index]);
  806. WCHAR uc;
  807. uc = MyUpcaseChar(SourceString->Buffer[Index]);
  808. DestinationString->Buffer[Index] = uc;
  809. }
  810. DestinationString->Length = SourceString->Length;
  811. return STATUS_SUCCESS;
  812. }
  813. NTSTATUS
  814. RtlDowncaseUnicodeString(
  815. OUT PUNICODE_STRING DestinationString,
  816. IN PUNICODE_STRING SourceString,
  817. IN BOOLEAN AllocateDestinationString
  818. )
  819. /*++
  820. Routine Description:
  821. This functions converts the specified unicode source string into a
  822. downcased unicode string. The translation is done with respect to the
  823. current system locale information.
  824. Arguments:
  825. DestinationString - Returns a unicode string that is the downcased
  826. equivalent to the unicode source string. The maximum length field
  827. is only set if AllocateDestinationString is TRUE.
  828. SourceString - Supplies the unicode source string that is to being
  829. downcased.
  830. AllocateDestinationString - Supplies a flag that controls whether or
  831. not this API allocates the buffer space for the destination
  832. string. If it does, then the buffer must be deallocated using
  833. RtlFreeUnicodeString (note that only storage for
  834. DestinationString->Buffer is allocated by this API).
  835. Return Value:
  836. SUCCESS - The conversion was successful
  837. !SUCCESS - The operation failed. No storage was allocated and no
  838. conversion was done. None.
  839. --*/
  840. {
  841. ULONG Index;
  842. ULONG StopIndex;
  843. if ( AllocateDestinationString ) {
  844. DestinationString->MaximumLength = SourceString->Length;
  845. DestinationString->Buffer = (LPWSTR)LocalAlloc(0, (ULONG)DestinationString->MaximumLength);
  846. if ( !DestinationString->Buffer ) {
  847. return STATUS_NO_MEMORY;
  848. }
  849. }
  850. else {
  851. if ( SourceString->Length > DestinationString->MaximumLength ) {
  852. return STATUS_BUFFER_OVERFLOW;
  853. }
  854. }
  855. StopIndex = ((ULONG)SourceString->Length) / sizeof( WCHAR );
  856. for (Index = 0; Index < StopIndex; Index++) {
  857. // WIN32_CHICAGO Use some other Downcase mechanism
  858. // DestinationString->Buffer[Index] = (WCHAR)NLS_DOWNCASE(SourceString->Buffer[Index]);
  859. WCHAR lc;
  860. WCHAR TempChar = SourceString->Buffer[Index];
  861. lc = MyLowercaseChar(TempChar);
  862. DestinationString->Buffer[Index] = lc;
  863. }
  864. DestinationString->Length = SourceString->Length;
  865. return STATUS_SUCCESS;
  866. }
  867. VOID
  868. MyRtlFreeAnsiString(
  869. IN OUT PANSI_STRING AnsiString
  870. )
  871. /*++
  872. Routine Description:
  873. This API is used to free storage allocated by
  874. RtlUnicodeStringToAnsiString. Note that only AnsiString->Buffer
  875. is free'd by this routine.
  876. Arguments:
  877. AnsiString - Supplies the address of the ansi string whose buffer
  878. was previously allocated by RtlUnicodeStringToAnsiString.
  879. Return Value:
  880. None.
  881. --*/
  882. {
  883. if (AnsiString->Buffer) {
  884. LocalFree(AnsiString->Buffer);
  885. #if 0
  886. memset( AnsiString, 0, sizeof( *AnsiString ) );
  887. #endif
  888. ZeroMemory( AnsiString, sizeof( *AnsiString ) );
  889. }
  890. }
  891. BOOLEAN
  892. MyRtlEqualUnicodeString(
  893. IN PUNICODE_STRING String1,
  894. IN PUNICODE_STRING String2,
  895. IN BOOLEAN CaseInSensitive
  896. )
  897. /*++
  898. Routine Description:
  899. The RtlEqualUnicodeString function compares two counted unicode strings for
  900. equality.
  901. The CaseInSensitive parameter specifies if case is to be ignored when
  902. doing the comparison.
  903. Arguments:
  904. String1 - Pointer to the first string.
  905. String2 - Pointer to the second string.
  906. CaseInsensitive - TRUE if case should be ignored when doing the
  907. comparison.
  908. Return Value:
  909. Boolean value that is TRUE if String1 equals String2 and FALSE otherwise.
  910. --*/
  911. {
  912. PWCHAR s1, s2;
  913. ULONG n1, n2, Count;
  914. CHAR c1, c2;
  915. n1 = String1->Length;
  916. n2 = String2->Length;
  917. DsysAssert((n1 & 1) == 0);
  918. DsysAssert((n2 & 1) == 0);
  919. if (n1 == n2) {
  920. s1 = String1->Buffer;
  921. s2 = String2->Buffer;
  922. #if 0
  923. DsysAssert(!(((((ULONG)s1 & 1) != 0) || (((ULONG)s2 & 1) != 0)) && (n1 != 0) && (n2 != 0)));
  924. Limit = (PWCHAR)((PCHAR)s1 + n1);
  925. if (CaseInSensitive) {
  926. while (s1 < Limit) {
  927. c1 = (CHAR) (*s1)++;
  928. c2 = (CHAR) (*s2)++;
  929. // WIN32_CHICAGO Do something better than AnsiUpper
  930. uc1= AnsiUpper (&c1);
  931. uc2 = AnsiUpper (&c2);
  932. if ((c1 != c2) && ((*uc1) != *(uc2))) {
  933. return FALSE;
  934. }
  935. }
  936. return TRUE;
  937. } else {
  938. while (s1 < Limit) {
  939. c1 = (CHAR) (*s1)++;
  940. c2 = (CHAR) (*s2)++;
  941. if (c1 != c2) {
  942. return FALSE;
  943. }
  944. }
  945. return TRUE;
  946. }
  947. #else // 0
  948. if (CaseInSensitive)
  949. {
  950. Count = 0;
  951. // Can't use wcsnicmp
  952. while (Count < (n1/sizeof(WCHAR)))
  953. {
  954. WCHAR uc1, uc2;
  955. uc1= MyUpcaseChar (*(s1 + Count));
  956. uc2 = MyUpcaseChar (*(s2 + Count));
  957. if (uc1 != uc2) {
  958. return FALSE;
  959. }
  960. Count++;
  961. }
  962. return TRUE;
  963. }
  964. else
  965. {
  966. if (wcsncmp (s1, s2, (n1/sizeof(WCHAR))) == 0)
  967. {
  968. return TRUE;
  969. }
  970. else
  971. {
  972. return FALSE;
  973. }
  974. }
  975. #endif // 0
  976. } else {
  977. return FALSE;
  978. }
  979. }
  980. NTSTATUS
  981. MyRtlUnicodeStringToAnsiString(
  982. OUT PANSI_STRING DestinationString,
  983. IN PUNICODE_STRING SourceString,
  984. IN BOOLEAN AllocateDestinationString
  985. )
  986. /*++
  987. Routine Description:
  988. This functions converts the specified unicode source string into an
  989. ansi string. The translation is done with respect to the
  990. current system locale information.
  991. Arguments:
  992. DestinationString - Returns an ansi string that is equivalent to the
  993. unicode source string. If the translation can not be done,
  994. an error is returned. The maximum length field is only set if
  995. AllocateDestinationString is TRUE.
  996. SourceString - Supplies the unicode source string that is to be
  997. converted to ansi.
  998. AllocateDestinationString - Supplies a flag that controls whether or
  999. not this API allocates the buffer space for the destination
  1000. string. If it does, then the buffer must be deallocated using
  1001. RtlFreeAnsiString (note that only storage for
  1002. DestinationString->Buffer is allocated by this API).
  1003. Return Value:
  1004. SUCCESS - The conversion was successful
  1005. !SUCCESS - The operation failed. No storage was allocated and no
  1006. conversion was done. None.
  1007. --*/
  1008. {
  1009. ULONG AnsiLength;
  1010. ULONG Index = 0;
  1011. NTSTATUS ReturnStatus = STATUS_SUCCESS;
  1012. BOOL fUsed;
  1013. AnsiLength = (SourceString->Length / sizeof(WCHAR)) + 1;
  1014. if ( AnsiLength > MAXUSHORT ) {
  1015. return STATUS_INVALID_PARAMETER_2;
  1016. }
  1017. DestinationString->Length = (USHORT)(AnsiLength - 1);
  1018. if ( AllocateDestinationString ) {
  1019. DestinationString->MaximumLength = (USHORT)AnsiLength;
  1020. DestinationString->Buffer = (LPSTR)LocalAlloc(0, AnsiLength);
  1021. if ( !DestinationString->Buffer ) {
  1022. return STATUS_NO_MEMORY;
  1023. }
  1024. }
  1025. else {
  1026. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  1027. /*
  1028. * Return STATUS_BUFFER_OVERFLOW, but translate as much as
  1029. * will fit into the buffer first. This is the expected
  1030. * behavior for routines such as GetProfileStringA.
  1031. * Set the length of the buffer to one less than the maximum
  1032. * (so that the trail byte of a double byte char is not
  1033. * overwritten by doing DestinationString->Buffer[Index] = '\0').
  1034. * RtlUnicodeToMultiByteN is careful not to truncate a
  1035. * multibyte character.
  1036. */
  1037. if (!DestinationString->MaximumLength) {
  1038. return STATUS_BUFFER_OVERFLOW;
  1039. }
  1040. ReturnStatus = STATUS_BUFFER_OVERFLOW;
  1041. DestinationString->Length = DestinationString->MaximumLength - 1;
  1042. }
  1043. }
  1044. if (SourceString->Length != 0)
  1045. {
  1046. Index = WideCharToMultiByte(
  1047. CP_ACP,
  1048. 0, // WIN32_CHICAGO this is something else
  1049. SourceString->Buffer,
  1050. SourceString->Length / sizeof (WCHAR),
  1051. DestinationString->Buffer,
  1052. DestinationString->MaximumLength,
  1053. NULL,
  1054. &fUsed
  1055. );
  1056. if (Index == 0)
  1057. { // WIN32_CHICAGO do something useful here
  1058. if ( AllocateDestinationString ) {
  1059. LocalFree(DestinationString->Buffer);
  1060. }
  1061. return STATUS_NO_MEMORY;
  1062. }
  1063. }
  1064. DestinationString->Buffer[Index] = '\0';
  1065. return ReturnStatus;
  1066. }
  1067. NTSTATUS
  1068. MyRtlUpcaseUnicodeStringToOemString(
  1069. OUT POEM_STRING DestinationString,
  1070. IN PUNICODE_STRING SourceString,
  1071. IN BOOLEAN AllocateDestinationString
  1072. )
  1073. /*++
  1074. Routine Description:
  1075. This function upper cases the specified unicode source string and then
  1076. converts it into an oem string. The translation is done with respect
  1077. to the OEM code page (OCP).
  1078. Arguments:
  1079. DestinationString - Returns an oem string that is equivalent to the
  1080. unicode source string. The maximum length field is only set if
  1081. AllocateDestinationString is TRUE.
  1082. SourceString - Supplies the unicode source string that is to be
  1083. converted to oem.
  1084. AllocateDestinationString - Supplies a flag that controls whether or
  1085. not this API allocates the buffer space for the destination
  1086. string. If it does, then the buffer must be deallocated using
  1087. RtlFreeAnsiString (note that only storage for
  1088. DestinationString->Buffer is allocated by this API).
  1089. Return Value:
  1090. SUCCESS - The conversion was successful
  1091. !SUCCESS - The operation failed. No storage was allocated and no
  1092. conversion was done. None.
  1093. --*/
  1094. {
  1095. // NOTE: This routine is not DBCS safe yet!
  1096. ULONG OemLength;
  1097. ULONG Index;
  1098. BOOL fUsed;
  1099. NTSTATUS st = STATUS_SUCCESS;
  1100. // Do not rely on callers to set MaximumLength as Length + 2
  1101. OemLength = (SourceString->Length / sizeof(WCHAR)) + 1;
  1102. if ( OemLength > MAXUSHORT ) {
  1103. return STATUS_INVALID_PARAMETER_2;
  1104. }
  1105. DestinationString->Length = (USHORT)(OemLength - 1);
  1106. if ( AllocateDestinationString ) {
  1107. DestinationString->MaximumLength = (USHORT)OemLength;
  1108. DestinationString->Buffer = (LPSTR)LocalAlloc(0, OemLength);
  1109. if ( !DestinationString->Buffer ) {
  1110. return STATUS_NO_MEMORY;
  1111. }
  1112. }
  1113. else {
  1114. if ( DestinationString->Length >= DestinationString->MaximumLength ) {
  1115. return STATUS_BUFFER_OVERFLOW;
  1116. }
  1117. }
  1118. Index = WideCharToMultiByte(
  1119. CP_OEMCP,
  1120. 0, // WIN32_CHICAGO this is something else
  1121. SourceString->Buffer,
  1122. SourceString->Length / sizeof (WCHAR),
  1123. DestinationString->Buffer,
  1124. DestinationString->MaximumLength,
  1125. NULL,
  1126. &fUsed
  1127. );
  1128. if (Index == 0)
  1129. { // WIN32_CHICAGO do something useful here
  1130. if ( AllocateDestinationString ) {
  1131. LocalFree(DestinationString->Buffer);
  1132. }
  1133. return STATUS_NO_MEMORY;
  1134. }
  1135. /*
  1136. st = RtlUnicodeToMultiByteN(
  1137. DestinationString->Buffer,
  1138. DestinationString->Length,
  1139. &Index,
  1140. SourceString->Buffer,
  1141. SourceString->Length
  1142. );
  1143. if (!NT_SUCCESS(st))
  1144. {
  1145. if ( AllocateDestinationString ) {
  1146. LocalFree(DestinationString->Buffer);
  1147. }
  1148. }
  1149. */
  1150. DestinationString->Buffer[Index] = '\0';
  1151. return st;
  1152. }
  1153. BOOLEAN
  1154. MyRtlEqualString(
  1155. IN POEM_STRING String1,
  1156. IN POEM_STRING String2,
  1157. IN BOOLEAN CaseInSensitive
  1158. )
  1159. /*++
  1160. Routine Description:
  1161. The RtlEqualString function compares two counted strings for equality.
  1162. The CaseInSensitive parameter specifies if case is to be ignored when
  1163. doing the comparison.
  1164. Arguments:
  1165. String1 - Pointer to the first string.
  1166. String2 - Pointer to the second string.
  1167. CaseInsensitive - TRUE if case should be ignored when doing the
  1168. comparison.
  1169. Return Value:
  1170. Boolean value that is TRUE if String1 equals String2 and FALSE otherwise.
  1171. --*/
  1172. {
  1173. PUCHAR s1, s2, Limit;
  1174. LONG n1, n2;
  1175. UCHAR c1, c2;
  1176. n1 = String1->Length;
  1177. n2 = String2->Length;
  1178. if (n1 == n2) {
  1179. s1 = (PUCHAR)String1->Buffer;
  1180. s2 = (PUCHAR)String2->Buffer;
  1181. Limit = s1 + n1;
  1182. if (CaseInSensitive) {
  1183. while (s1 < Limit) {
  1184. c1 = *s1++;
  1185. c2 = *s2++;
  1186. if (c1 != c2) {
  1187. WCHAR uc1, uc2;
  1188. // WIN32_CHICAGO Use something better to upcase here
  1189. uc1 = MyUpcaseChar((WCHAR)c1);
  1190. uc2 = MyUpcaseChar((WCHAR)c2);
  1191. if (uc1 != uc2) {
  1192. return FALSE;
  1193. }
  1194. }
  1195. }
  1196. return TRUE;
  1197. } else {
  1198. while (s1 < Limit) {
  1199. c1 = *s1++;
  1200. c2 = *s2++;
  1201. if (c1 != c2) {
  1202. return FALSE;
  1203. }
  1204. }
  1205. return TRUE;
  1206. }
  1207. } else {
  1208. return FALSE;
  1209. }
  1210. }
  1211. VOID
  1212. MyRtlFreeOemString(
  1213. IN OUT POEM_STRING OemString
  1214. )
  1215. /*++
  1216. Routine Description:
  1217. This API is used to free storage allocated by
  1218. RtlUnicodeStringToOemString. Note that only OemString->Buffer
  1219. is free'd by this routine.
  1220. Arguments:
  1221. OemString - Supplies the address of the oem string whose buffer
  1222. was previously allocated by RtlUnicodeStringToOemString.
  1223. Return Value:
  1224. None.
  1225. --*/
  1226. {
  1227. if (OemString->Buffer) {
  1228. LocalFree(OemString->Buffer);
  1229. memset( OemString, 0, sizeof( *OemString ) );
  1230. }
  1231. }
  1232. BOOLEAN
  1233. MyRtlEqualDomainName(
  1234. IN PUNICODE_STRING String1,
  1235. IN PUNICODE_STRING String2
  1236. )
  1237. /*++
  1238. Routine Description:
  1239. The RtlEqualDomainName function compares two domain names for equality.
  1240. The comparison is a case insensitive comparison of the OEM equivalent
  1241. strings.
  1242. The domain name is not validated for length nor invalid characters.
  1243. Arguments:
  1244. String1 - Pointer to the first string.
  1245. String2 - Pointer to the second string.
  1246. Return Value:
  1247. Boolean value that is TRUE if String1 equals String2 and FALSE otherwise.
  1248. --*/
  1249. {
  1250. NTSTATUS Status;
  1251. BOOLEAN ReturnValue = FALSE;
  1252. OEM_STRING OemString1;
  1253. OEM_STRING OemString2;
  1254. //
  1255. // Upper case and convert the first string to OEM
  1256. //
  1257. Status = MyRtlUpcaseUnicodeStringToOemString( &OemString1,
  1258. String1,
  1259. TRUE ); // Allocate Dest
  1260. if ( NT_SUCCESS( Status ) ) {
  1261. //
  1262. // Upper case and convert the second string to OEM
  1263. //
  1264. Status = MyRtlUpcaseUnicodeStringToOemString( &OemString2,
  1265. String2,
  1266. TRUE ); // Allocate Dest
  1267. if ( NT_SUCCESS( Status ) ) {
  1268. //
  1269. // Do a case insensitive comparison.
  1270. //
  1271. ReturnValue = MyRtlEqualString( &OemString1,
  1272. &OemString2,
  1273. FALSE );
  1274. MyRtlFreeOemString( &OemString2 );
  1275. }
  1276. MyRtlFreeOemString( &OemString1 );
  1277. }
  1278. return ReturnValue;
  1279. }
  1280. VOID
  1281. MyRtlInitString(
  1282. OUT PSTRING DestinationString,
  1283. IN PCSTR SourceString OPTIONAL
  1284. )
  1285. /*++
  1286. Routine Description:
  1287. The RtlInitString function initializes an NT counted string.
  1288. The DestinationString is initialized to point to the SourceString
  1289. and the Length and MaximumLength fields of DestinationString are
  1290. initialized to the length of the SourceString, which is zero if
  1291. SourceString is not specified.
  1292. Arguments:
  1293. DestinationString - Pointer to the counted string to initialize
  1294. SourceString - Optional pointer to a null terminated string that
  1295. the counted string is to point to.
  1296. Return Value:
  1297. None.
  1298. --*/
  1299. {
  1300. ULONG Length;
  1301. DestinationString->Buffer = (PCHAR)SourceString;
  1302. if (ARGUMENT_PRESENT( SourceString )) {
  1303. Length = strlen(SourceString);
  1304. DestinationString->Length = (USHORT)Length;
  1305. DestinationString->MaximumLength = (USHORT)(Length+1);
  1306. }
  1307. }
  1308. LONG
  1309. MyRtlCompareUnicodeString(
  1310. IN PUNICODE_STRING String1,
  1311. IN PUNICODE_STRING String2,
  1312. IN BOOLEAN CaseInSensitive
  1313. )
  1314. /*++
  1315. Routine Description:
  1316. The RtlCompareUnicodeString function compares two counted strings. The
  1317. return value indicates if the strings are equal or String1 is less than
  1318. String2 or String1 is greater than String2.
  1319. The CaseInSensitive parameter specifies if case is to be ignored when
  1320. doing the comparison.
  1321. Arguments:
  1322. String1 - Pointer to the first string.
  1323. String2 - Pointer to the second string.
  1324. CaseInsensitive - TRUE if case should be ignored when doing the
  1325. comparison.
  1326. Return Value:
  1327. Signed value that gives the results of the comparison:
  1328. Zero - String1 equals String2
  1329. < Zero - String1 less than String2
  1330. > Zero - String1 greater than String2
  1331. --*/
  1332. {
  1333. PWCHAR s1, s2, Limit;
  1334. LONG n1, n2;
  1335. WCHAR c1, c2;
  1336. s1 = String1->Buffer;
  1337. s2 = String2->Buffer;
  1338. n1 = String1->Length;
  1339. n2 = String2->Length;
  1340. DsysAssert((n1 & 1) == 0);
  1341. DsysAssert((n2 & 1) == 0);
  1342. DsysAssert(!(((((ULONG)s1 & 1) != 0) || (((ULONG)s2 & 1) != 0)) && (n1 != 0) && (n2 != 0)));
  1343. Limit = (PWCHAR)((PCHAR)s1 + (n1 <= n2 ? n1 : n2));
  1344. if (CaseInSensitive) {
  1345. while (s1 < Limit) {
  1346. c1 = *s1++;
  1347. c2 = *s2++;
  1348. if (c1 != c2) {
  1349. WCHAR uc1, uc2;
  1350. //
  1351. // Note that this needs to reference the translation table!
  1352. //
  1353. // WIN32_CHICAGO Need to do something better here
  1354. uc1 = MyUpcaseChar(c1);
  1355. uc2 = MyUpcaseChar(c2);
  1356. if (uc1 != uc2) {
  1357. return (LONG)(c1) - (LONG)(c2);
  1358. }
  1359. }
  1360. }
  1361. } else {
  1362. while (s1 < Limit) {
  1363. c1 = *s1++;
  1364. c2 = *s2++;
  1365. if (c1 != c2) {
  1366. return (LONG)(c1) - (LONG)(c2);
  1367. }
  1368. }
  1369. }
  1370. return n1 - n2;
  1371. }
  1372. VOID
  1373. MyRtlFreeUnicodeString(
  1374. IN OUT PUNICODE_STRING UnicodeString
  1375. )
  1376. /*++
  1377. Routine Description:
  1378. This API is used to free storage allocated by
  1379. RtlAnsiStringToUnicodeString. Note that only UnicodeString->Buffer
  1380. is free'd by this routine.
  1381. Arguments:
  1382. UnicodeString - Supplies the address of the unicode string whose
  1383. buffer was previously allocated by RtlAnsiStringToUnicodeString.
  1384. Return Value:
  1385. None.
  1386. --*/
  1387. {
  1388. if (UnicodeString->Buffer) {
  1389. LocalFree(UnicodeString->Buffer);
  1390. memset( UnicodeString, 0, sizeof( *UnicodeString ) );
  1391. }
  1392. }
  1393. NTSTATUS
  1394. MyRtlConvertSidToUnicodeString(
  1395. PUNICODE_STRING UnicodeString,
  1396. PSID Sid,
  1397. BOOLEAN AllocateDestinationString
  1398. )
  1399. /*++
  1400. Routine Description:
  1401. This function generates a printable unicode string representation
  1402. of a SID.
  1403. The resulting string will take one of two forms. If the
  1404. IdentifierAuthority value is not greater than 2^32, then
  1405. the SID will be in the form:
  1406. S-1-281736-12-72-9-110
  1407. ^ ^^ ^^ ^ ^^^
  1408. | | | | |
  1409. +-----+--+-+--+---- Decimal
  1410. Otherwise it will take the form:
  1411. S-1-0x173495281736-12-72-9-110
  1412. ^^^^^^^^^^^^^^ ^^ ^^ ^ ^^^
  1413. Hexidecimal | | | |
  1414. +--+-+--+---- Decimal
  1415. Arguments:
  1416. UnicodeString - Returns a unicode string that is equivalent to
  1417. the SID. The maximum length field is only set if
  1418. AllocateDestinationString is TRUE.
  1419. Sid - Supplies the SID that is to be converted to unicode.
  1420. AllocateDestinationString - Supplies a flag that controls whether or
  1421. not this API allocates the buffer space for the destination
  1422. string. If it does, then the buffer must be deallocated using
  1423. RtlFreeUnicodeString (note that only storage for
  1424. DestinationString->Buffer is allocated by this API).
  1425. Return Value:
  1426. SUCCESS - The conversion was successful
  1427. STATUS_INVALID_SID - The sid provided does not have a valid structure,
  1428. or has too many sub-authorities (more than SID_MAX_SUB_AUTHORITIES).
  1429. STATUS_NO_MEMORY - There was not sufficient memory to allocate the
  1430. target string. This is returned only if AllocateDestinationString
  1431. is specified as TRUE.
  1432. STATUS_BUFFER_OVERFLOW - This is returned only if
  1433. AllocateDestinationString is specified as FALSE.
  1434. --*/
  1435. {
  1436. NTSTATUS Status;
  1437. UCHAR Buffer[256];
  1438. UCHAR String[256];
  1439. UCHAR i;
  1440. ULONG Tmp;
  1441. PISID iSid = (PISID)Sid; // pointer to opaque structure
  1442. ANSI_STRING AnsiString;
  1443. #ifndef WIN32_CHICAGO // Painful to do this
  1444. if (RtlValidSid( Sid ) != TRUE) {
  1445. return(STATUS_INVALID_SID);
  1446. }
  1447. #endif // WIN32_CHICAGO
  1448. _snprintf((CHAR *)Buffer, sizeof(Buffer), "S-%u-", (USHORT)iSid->Revision );
  1449. strcpy((char *)String, (const char *)Buffer);
  1450. if ( (iSid->IdentifierAuthority.Value[0] != 0) ||
  1451. (iSid->IdentifierAuthority.Value[1] != 0) ){
  1452. _snprintf((CHAR *) Buffer, sizeof(Buffer), "0x%02hx%02hx%02hx%02hx%02hx%02hx",
  1453. (USHORT)iSid->IdentifierAuthority.Value[0],
  1454. (USHORT)iSid->IdentifierAuthority.Value[1],
  1455. (USHORT)iSid->IdentifierAuthority.Value[2],
  1456. (USHORT)iSid->IdentifierAuthority.Value[3],
  1457. (USHORT)iSid->IdentifierAuthority.Value[4],
  1458. (USHORT)iSid->IdentifierAuthority.Value[5] );
  1459. strcat((char *) String, (const char *)Buffer);
  1460. } else {
  1461. Tmp = (ULONG)iSid->IdentifierAuthority.Value[5] +
  1462. (ULONG)(iSid->IdentifierAuthority.Value[4] << 8) +
  1463. (ULONG)(iSid->IdentifierAuthority.Value[3] << 16) +
  1464. (ULONG)(iSid->IdentifierAuthority.Value[2] << 24);
  1465. _snprintf((char *)Buffer, sizeof(Buffer), "%lu", Tmp);
  1466. strcat((char *)String, (const char *)Buffer);
  1467. }
  1468. for (i=0;i<iSid->SubAuthorityCount ;i++ ) {
  1469. _snprintf((char *) Buffer, sizeof(Buffer), "-%lu", iSid->SubAuthority[i]);
  1470. strcat((char *)String, (const char *)Buffer);
  1471. }
  1472. //
  1473. // Convert the string to a Unicode String
  1474. //
  1475. RtlInitString(&AnsiString, (PSZ) String);
  1476. Status = RtlAnsiStringToUnicodeString( UnicodeString,
  1477. &AnsiString,
  1478. AllocateDestinationString
  1479. );
  1480. return(Status);
  1481. }
  1482. //
  1483. // Inline functions to convert between FILETIME and TimeStamp
  1484. //
  1485. #pragma warning( disable : 4035) // Don't complain about no return
  1486. TimeStamp __inline
  1487. FileTimeToTimeStamp(
  1488. const FILETIME *pft)
  1489. {
  1490. _asm {
  1491. mov edx, pft
  1492. mov eax, [edx].dwLowDateTime
  1493. mov edx, [edx].dwHighDateTime
  1494. }
  1495. }
  1496. #pragma warning( default : 4035) // Reenable warning
  1497. NTSTATUS
  1498. MyNtQuerySystemTime (
  1499. OUT PTimeStamp SystemTimeStamp
  1500. )
  1501. /*++
  1502. Routine Description:
  1503. This routine returns the current system time (UTC), as a timestamp
  1504. (a 64-bit unsigned integer, in 100-nanosecond increments).
  1505. Arguments:
  1506. None.
  1507. Return Value:
  1508. The current system time.
  1509. --*/
  1510. {
  1511. SYSTEMTIME SystemTime;
  1512. FILETIME FileTime;
  1513. GetSystemTime(&SystemTime);
  1514. SystemTimeToFileTime(&SystemTime, &FileTime);
  1515. *SystemTimeStamp = FileTimeToTimeStamp(&FileTime);
  1516. return STATUS_SUCCESS; // WIN32_CHICAGO do something useful here
  1517. }
  1518. NTSTATUS
  1519. MyNtAllocateLocallyUniqueId(
  1520. OUT PLUID Luid
  1521. )
  1522. {
  1523. // WIN32_CHICAGO do something useful here
  1524. Luid->HighPart = 1;
  1525. Luid->LowPart = 1;
  1526. return STATUS_SUCCESS;
  1527. }
  1528. NTSTATUS
  1529. GetClientInfo(
  1530. OUT PSECPKG_CLIENT_INFO ClientInfo
  1531. )
  1532. {
  1533. // We don't care about these. Just fake it so that the common code does
  1534. // look too unreadable.
  1535. MyNtAllocateLocallyUniqueId (&ClientInfo->LogonId);
  1536. ClientInfo->HasTcbPrivilege = TRUE;
  1537. ClientInfo->ProcessID = 0;
  1538. return STATUS_SUCCESS;
  1539. }
  1540. BOOLEAN
  1541. GetCallInfo(
  1542. OUT PSECPKG_CALL_INFO CallInfo
  1543. )
  1544. {
  1545. ZeroMemory( CallInfo, sizeof( SECPKG_CALL_INFO ) );
  1546. return(TRUE);
  1547. }
  1548. NTSTATUS
  1549. CopyFromClientBuffer(
  1550. IN PLSA_CLIENT_REQUEST ClientRequest,
  1551. IN ULONG Length,
  1552. IN PVOID BufferToCopy,
  1553. IN PVOID ClientBaseAddress
  1554. )
  1555. {
  1556. RtlCopyMemory(
  1557. BufferToCopy,
  1558. ClientBaseAddress,
  1559. Length
  1560. );
  1561. return STATUS_SUCCESS;
  1562. }
  1563. NTSTATUS
  1564. AllocateClientBuffer(
  1565. IN PLSA_CLIENT_REQUEST ClientRequest,
  1566. IN ULONG LengthRequired,
  1567. OUT PVOID *ClientBaseAddress
  1568. )
  1569. {
  1570. *ClientBaseAddress = (PVOID)KerbAllocate(LengthRequired);
  1571. if (ClientBaseAddress == NULL)
  1572. {
  1573. return STATUS_NO_MEMORY;
  1574. }
  1575. return STATUS_SUCCESS;
  1576. }
  1577. NTSTATUS
  1578. CopyToClientBuffer(
  1579. IN PLSA_CLIENT_REQUEST ClientRequest,
  1580. IN ULONG Length,
  1581. IN PVOID ClientBaseAddress,
  1582. IN PVOID BufferToCopy
  1583. )
  1584. {
  1585. RtlCopyMemory(
  1586. ClientBaseAddress,
  1587. BufferToCopy,
  1588. Length
  1589. );
  1590. return STATUS_SUCCESS;
  1591. }
  1592. NTSTATUS
  1593. FreeClientBuffer (
  1594. IN PLSA_CLIENT_REQUEST ClientRequest,
  1595. IN PVOID ClientBaseAddress
  1596. )
  1597. {
  1598. KerbFree(ClientBaseAddress);
  1599. return STATUS_SUCCESS;
  1600. }
  1601. VOID
  1602. AuditLogon(
  1603. IN NTSTATUS Status,
  1604. IN NTSTATUS SubStatus,
  1605. IN PUNICODE_STRING AccountName,
  1606. IN PUNICODE_STRING AuthenticatingAuthority,
  1607. IN PUNICODE_STRING WorkstationName,
  1608. IN OPTIONAL PSID UserSid,
  1609. IN SECURITY_LOGON_TYPE LogonType,
  1610. IN PTOKEN_SOURCE TokenSource,
  1611. IN PLUID LogonId
  1612. )
  1613. {
  1614. // WIN32_CHICAGO do something useful here
  1615. }
  1616. ULONG
  1617. MyRtlLengthSid (
  1618. PSID Sid
  1619. )
  1620. {
  1621. return 0;
  1622. }
  1623. BOOLEAN
  1624. MyRtlValidSid (
  1625. PSID Sid
  1626. )
  1627. {
  1628. return TRUE;
  1629. }
  1630. NTSTATUS
  1631. MapBuffer(
  1632. IN PSecBuffer InputBuffer,
  1633. OUT PSecBuffer OutputBuffer
  1634. )
  1635. {
  1636. // WIN32_CHICAGO do something useful here
  1637. return STATUS_SUCCESS;
  1638. }
  1639. NTSTATUS
  1640. MyNtClose(
  1641. IN HANDLE Handle
  1642. )
  1643. {
  1644. return STATUS_SUCCESS;
  1645. }
  1646. NTSTATUS
  1647. KerbDuplicateHandle(
  1648. IN HANDLE SourceHandle,
  1649. OUT PHANDLE DestionationHandle
  1650. )
  1651. {
  1652. // WIN32_CHICAGO do something useful here
  1653. return STATUS_SUCCESS;
  1654. }
  1655. PVOID
  1656. AllocateLsaHeap(
  1657. IN ULONG Length
  1658. )
  1659. {
  1660. return LocalAlloc(0, Length);
  1661. }
  1662. VOID
  1663. FreeLsaHeap(
  1664. IN PVOID Base
  1665. )
  1666. {
  1667. LocalFree(Base);
  1668. }
  1669. VOID
  1670. FreeReturnBuffer(
  1671. IN PVOID Base
  1672. )
  1673. {
  1674. LocalFree(Base);
  1675. }
  1676. //+-------------------------------------------------------------------------
  1677. //
  1678. // Function: FreeContextBuffer
  1679. //
  1680. // Synopsis:
  1681. //
  1682. // Effects:
  1683. //
  1684. // Arguments:
  1685. //
  1686. // Requires:
  1687. //
  1688. // Returns:
  1689. //
  1690. // Notes:
  1691. //
  1692. //
  1693. //--------------------------------------------------------------------------
  1694. SECURITY_STATUS SEC_ENTRY
  1695. FreeContextBuffer(
  1696. void SEC_FAR * pvContextBuffer
  1697. )
  1698. {
  1699. LocalFree(pvContextBuffer);
  1700. return(SEC_E_OK);
  1701. }