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.

787 lines
19 KiB

  1. #include <setupp.h>
  2. DEFINE_GUID(
  3. SAC_CHANNEL_GUI_MODE_DEBUG_GUID,
  4. 0x5ed3bac7, 0xa2f9, 0x4e45, 0x98, 0x75, 0xb2, 0x59, 0xea, 0x3f, 0x29, 0x1f
  5. );
  6. DEFINE_GUID(
  7. SAC_CHANNEL_GUI_MODE_ERROR_LOG_GUID,
  8. 0x773d2759, 0x19b8, 0x4d6e, 0x80, 0x45, 0x26, 0xbf, 0x38, 0x40, 0x22, 0x52
  9. );
  10. DEFINE_GUID(
  11. SAC_CHANNEL_GUI_MODE_ACTION_LOG_GUID,
  12. 0xd37c67ba, 0x89e7, 0x44ba, 0xae, 0x5a, 0x11, 0x2c, 0x68, 0x06, 0xb0, 0xdd
  13. );
  14. //
  15. // The GUI-mode channels
  16. //
  17. SAC_CHANNEL_HANDLE SacChannelGuiModeDebugHandle;
  18. BOOL SacChannelGuiModeDebugEnabled = FALSE;
  19. SAC_CHANNEL_HANDLE SacChannelActionLogHandle;
  20. BOOL SacChannelActionLogEnabled = FALSE;
  21. SAC_CHANNEL_HANDLE SacChannelErrorLogHandle;
  22. BOOL SacChannelErrorLogEnabled = FALSE;
  23. PUCHAR Utf8ConversionBuffer = NULL;
  24. ULONG Utf8ConversionBufferSize = 0;
  25. //
  26. // Define the max # of Unicode chars that can be translated with the
  27. // given size of the utf8 translation buffer
  28. //
  29. #define MAX_UTF8_ENCODE_BLOCK_LENGTH ((Utf8ConversionBufferSize / 3) - 1)
  30. VOID
  31. SacChannelInitialize(
  32. VOID
  33. )
  34. /*++
  35. Routine Description:
  36. This routine creates and initializes all the GUI-mode channels
  37. Arguments:
  38. None
  39. Return Value:
  40. None
  41. --*/
  42. {
  43. BOOL bSuccess;
  44. SAC_CHANNEL_OPEN_ATTRIBUTES Attributes;
  45. //
  46. //
  47. //
  48. Utf8ConversionBufferSize = 512*3+3;
  49. Utf8ConversionBuffer = malloc(Utf8ConversionBufferSize);
  50. if (Utf8ConversionBuffer == NULL) {
  51. return;
  52. }
  53. //
  54. // Configure the new channel
  55. //
  56. RtlZeroMemory(&Attributes, sizeof(SAC_CHANNEL_OPEN_ATTRIBUTES));
  57. Attributes.Type = ChannelTypeRaw;
  58. if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_DEBUG_NAME, Attributes.Name, ARRAYSIZE(Attributes.Name)) ) {
  59. Attributes.Name[0] = L'\0';
  60. }
  61. if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_DEBUG_DESCRIPTION, Attributes.Description, ARRAYSIZE(Attributes.Description)) ) {
  62. Attributes.Description[0] = L'\0';
  63. }
  64. Attributes.ApplicationType = SAC_CHANNEL_GUI_MODE_DEBUG_GUID;
  65. //
  66. // Create a channel for the GUI Mode Debug spew
  67. //
  68. bSuccess = SacChannelOpen(
  69. &SacChannelGuiModeDebugHandle,
  70. &Attributes
  71. );
  72. if (bSuccess) {
  73. //
  74. // We can now use this channel
  75. //
  76. SacChannelGuiModeDebugEnabled = TRUE;
  77. SetupDebugPrint(L"Successfully opened GuiModeDebug channel\n");
  78. } else {
  79. SetupDebugPrint(L"Failed to open GuiModeDebug channel\n");
  80. }
  81. //
  82. // Configure the new channel
  83. //
  84. RtlZeroMemory(&Attributes, sizeof(SAC_CHANNEL_OPEN_ATTRIBUTES));
  85. Attributes.Type = ChannelTypeRaw;
  86. if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_ACTION_LOG_NAME, Attributes.Name, ARRAYSIZE(Attributes.Name)) ) {
  87. Attributes.Name[0] = L'\0';
  88. }
  89. if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_ACTION_LOG_DESCRIPTION, Attributes.Description, ARRAYSIZE(Attributes.Description)) ) {
  90. Attributes.Description[0] = L'\0';
  91. }
  92. Attributes.ApplicationType = SAC_CHANNEL_GUI_MODE_ACTION_LOG_GUID;
  93. //
  94. // Create a channel for the Action Log spew
  95. //
  96. bSuccess = SacChannelOpen(
  97. &SacChannelActionLogHandle,
  98. &Attributes
  99. );
  100. if (bSuccess) {
  101. //
  102. // We can now use this channel
  103. //
  104. SacChannelActionLogEnabled = TRUE;
  105. SetupDebugPrint(L"Successfully opened ActionLog channel\n");
  106. } else {
  107. SetupDebugPrint(L"Failed to open ActionLog channel\n");
  108. }
  109. //
  110. // Configure the new channel
  111. //
  112. RtlZeroMemory(&Attributes, sizeof(SAC_CHANNEL_OPEN_ATTRIBUTES));
  113. Attributes.Type = ChannelTypeRaw;
  114. if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_ERROR_LOG_NAME, Attributes.Name, ARRAYSIZE(Attributes.Name)) ) {
  115. Attributes.Name[0] = L'\0';
  116. }
  117. if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_ERROR_LOG_DESCRIPTION, Attributes.Description, ARRAYSIZE(Attributes.Description)) ) {
  118. Attributes.Description[0] = L'\0';
  119. }
  120. Attributes.ApplicationType = SAC_CHANNEL_GUI_MODE_ERROR_LOG_GUID;
  121. //
  122. // Create a channel for the Error Log spew
  123. //
  124. bSuccess = SacChannelOpen(
  125. &SacChannelErrorLogHandle,
  126. &Attributes
  127. );
  128. if (bSuccess) {
  129. //
  130. // We can now use this channel
  131. //
  132. SacChannelErrorLogEnabled = TRUE;
  133. SetupDebugPrint(L"Successfully opened ErrorLog channel\n");
  134. } else {
  135. SetupDebugPrint(L"Failed to open ErrorLog channel\n");
  136. }
  137. }
  138. VOID
  139. SacChannelTerminate(
  140. VOID
  141. )
  142. /*++
  143. Routine Description:
  144. This routine closes all the GUI-mode setup channels
  145. Arguments:
  146. None
  147. Return Value:
  148. None
  149. --*/
  150. {
  151. //
  152. // If the channel is enabled,
  153. // then attempt to close it
  154. //
  155. if (SacChannelActionLogEnabled) {
  156. //
  157. // This channel is no longer available
  158. //
  159. SacChannelActionLogEnabled = FALSE;
  160. //
  161. // Attempt to close the channel
  162. //
  163. if (SacChannelClose(&SacChannelActionLogHandle)) {
  164. SetupDebugPrint(L"Successfully closed ActionLog channel\n");
  165. } else {
  166. SetupDebugPrint(L"Failed to close ActionLog channel\n");
  167. }
  168. }
  169. //
  170. // If the channel is enabled,
  171. // then attempt to close it
  172. //
  173. if (SacChannelErrorLogEnabled) {
  174. //
  175. // This channel is no longer available
  176. //
  177. SacChannelErrorLogEnabled = FALSE;
  178. //
  179. // Attempt to close the channel
  180. //
  181. if (SacChannelClose(&SacChannelErrorLogHandle)) {
  182. SetupDebugPrint(L"Successfully closed ErrorLog channel\n");
  183. } else {
  184. SetupDebugPrint(L"Failed to close ErrorLog channel\n");
  185. }
  186. }
  187. //
  188. // If the channel is enabled,
  189. // then attempt to close it
  190. //
  191. if (SacChannelGuiModeDebugEnabled) {
  192. //
  193. // This channel is no longer available
  194. //
  195. SacChannelGuiModeDebugEnabled = FALSE;
  196. //
  197. // Attempt to close the channel
  198. //
  199. if (SacChannelClose(&SacChannelGuiModeDebugHandle)) {
  200. SetupDebugPrint(L"Successfully closed GuiModeDebug channel\n");
  201. } else {
  202. SetupDebugPrint(L"Failed to close GuiModeDebug channel\n");
  203. }
  204. }
  205. //
  206. // free the conversion buffer if necessary
  207. //
  208. if (Utf8ConversionBuffer != NULL) {
  209. free(Utf8ConversionBuffer);
  210. Utf8ConversionBuffer = NULL;
  211. Utf8ConversionBufferSize = 0;
  212. }
  213. }
  214. #if 0
  215. BOOL
  216. CopyAndInsertStringAtInterval(
  217. IN PSTR SourceStr,
  218. IN ULONG Interval,
  219. IN PSTR InsertStr,
  220. OUT PSTR *pDestStr
  221. )
  222. /*++
  223. Routine Description:
  224. This routine takes a source string and inserts an
  225. "interval string" at interval characters in the new
  226. destination string.
  227. Note: caller is responsible for releasing DestStr if successful
  228. ex:
  229. src "aaabbbccc"
  230. interval string = "XYZ"
  231. interval = 3
  232. ==> dest string == "aaaXYZbbbXYZccc"
  233. Arguments:
  234. SourceStr - the source string
  235. Interval - spanning interval
  236. InsertStr - the insert string
  237. DestStr - the destination string
  238. Return Value:
  239. Status
  240. --*/
  241. {
  242. ULONG SrcLength;
  243. ULONG DestLength;
  244. ULONG DestSize;
  245. ULONG InsertLength;
  246. ULONG k;
  247. ULONG l;
  248. ULONG i;
  249. PSTR DestStr;
  250. ULONG IntervalCnt;
  251. ASSERT(SourceStr);
  252. ASSERT(Interval > 0);
  253. ASSERT(InsertStr);
  254. ASSERT(pDestStr > 0);
  255. //
  256. // the length of the insert string
  257. //
  258. InsertLength = strlen(InsertStr);
  259. //
  260. // Compute how large the destination string needs to be,
  261. // including the source string and the interval strings.
  262. //
  263. // Note: if the srclength is an integer multiple of Interval
  264. // then we need to subtract 1 from the # of partitions
  265. //
  266. SrcLength = strlen(SourceStr);
  267. IntervalCnt = SrcLength / Interval;
  268. if (SrcLength % Interval == 0) {
  269. IntervalCnt = IntervalCnt > 0 ? IntervalCnt - 1 : IntervalCnt;
  270. }
  271. DestLength = SrcLength + (IntervalCnt * strlen(InsertStr));
  272. DestSize = (DestLength + 1) * sizeof(UCHAR);
  273. //
  274. // Allocate the new destination string
  275. //
  276. DestStr = LocalAlloc(LPTR, DestSize);
  277. if (!DestStr) {
  278. return FALSE;
  279. }
  280. RtlZeroMemory(DestStr, DestSize);
  281. //
  282. // Initialize the pointers into the source and destination strings
  283. //
  284. l = 0;
  285. i = 0;
  286. do {
  287. //
  288. // k = # of characters to copy
  289. //
  290. // if Interval > # of characters left to copy,
  291. // then k = # of characters left to copy
  292. // else k = interval
  293. //
  294. k = Interval > (SrcLength - i) ? (SrcLength - i) : Interval;
  295. //
  296. // Copy k charactars to the destination buffer
  297. //
  298. strncpy(
  299. &DestStr[l],
  300. &SourceStr[i],
  301. k
  302. );
  303. //
  304. // Account for how many characters we just copied
  305. //
  306. l += k;
  307. i += k;
  308. //
  309. // If there are any characters left to copy,
  310. // then we need to insert the InsertString
  311. // That is, we are at an interval.
  312. //
  313. if (i < SrcLength) {
  314. //
  315. // Insert the specified string at the interval
  316. //
  317. strcpy(
  318. &DestStr[l],
  319. InsertStr
  320. );
  321. //
  322. // Account for how many characters we just copied
  323. //
  324. l += InsertLength;
  325. }
  326. } while ( i < SrcLength);
  327. //
  328. //
  329. //
  330. ASSERT(i == SrcLength);
  331. ASSERT(l == DestLength);
  332. ASSERT((l + 1) * sizeof(UCHAR) == DestSize);
  333. //
  334. // Send back the destination string
  335. //
  336. *pDestStr = DestStr;
  337. return TRUE;
  338. }
  339. BOOL
  340. SacChannelWrappedWrite(
  341. IN SAC_CHANNEL_HANDLE SacChannelHandle,
  342. IN PCBYTE Buffer,
  343. IN ULONG BufferSize
  344. )
  345. /*++
  346. Routine Description:
  347. This routine takes a string and makes it wrap at 80 cols
  348. and then sends the new string to the specified channel.
  349. Arguments:
  350. SacChannelHandle - the channel reference to received the data
  351. Buffer - the string
  352. BufferSize - the string size
  353. Return Value:
  354. --*/
  355. {
  356. BOOL bSuccess;
  357. PSTR OutStr;
  358. UNREFERENCED_PARAMETER(BufferSize);
  359. bSuccess = CopyAndInsertStringAtInterval(
  360. Buffer,
  361. 80,
  362. "\r\n",
  363. &OutStr
  364. );
  365. if (bSuccess) {
  366. bSuccess = SacChannelRawWrite(
  367. SacChannelHandle,
  368. OutStr,
  369. strlen(OutStr)*sizeof(UCHAR)
  370. );
  371. LocalFree(OutStr);
  372. }
  373. return bSuccess;
  374. }
  375. #endif
  376. BOOLEAN
  377. SacTranslateUnicodeToUtf8(
  378. IN PCWSTR SourceBuffer,
  379. IN ULONG SourceBufferLength,
  380. IN PUCHAR DestinationBuffer,
  381. IN ULONG DestinationBufferSize,
  382. OUT PULONG UTF8Count,
  383. OUT PULONG ProcessedCount
  384. )
  385. /*++
  386. Routine Description:
  387. This routine translates a Unicode string into a UFT8
  388. encoded string.
  389. Note: if the destination buffer is not large enough to hold
  390. the entire encoded UFT8 string, then it will contain
  391. as much as can fit.
  392. TODO: this routine should return some notification if
  393. the entire Unicode string was not encoded.
  394. Arguments:
  395. SourceBuffer - the source Unicode string
  396. SourceBufferLength - the # of characters the caller wants to translate
  397. note: a NULL termination overrides this
  398. DestinationBuffer - the destination for the UTF8 string
  399. DestinationBufferSize - the size of the destination buffer
  400. UTF8Count - on exit, contains the # of resulting UTF8 characters
  401. ProcessedCount - on exit, contains the # of processed Unicode characters
  402. Return Value:
  403. Status
  404. --*/
  405. {
  406. //
  407. // Init
  408. //
  409. *UTF8Count = 0;
  410. *ProcessedCount = 0;
  411. //
  412. // convert into UTF8 for actual transmission
  413. //
  414. // UTF-8 encodes 2-byte Unicode characters as follows:
  415. // If the first nine bits are zero (00000000 0xxxxxxx), encode it as one byte 0xxxxxxx
  416. // If the first five bits are zero (00000yyy yyxxxxxx), encode it as two bytes 110yyyyy 10xxxxxx
  417. // Otherwise (zzzzyyyy yyxxxxxx), encode it as three bytes 1110zzzz 10yyyyyy 10xxxxxx
  418. //
  419. //
  420. // Process until one of the specified conditions is met
  421. //
  422. while (*SourceBuffer &&
  423. (*UTF8Count < DestinationBufferSize) &&
  424. (*ProcessedCount < SourceBufferLength)
  425. ) {
  426. if( (*SourceBuffer & 0xFF80) == 0 ) {
  427. //
  428. // if the top 9 bits are zero, then just
  429. // encode as 1 byte. (ASCII passes through unchanged).
  430. //
  431. DestinationBuffer[(*UTF8Count)++] = (UCHAR)(*SourceBuffer & 0x7F);
  432. } else if( (*SourceBuffer & 0xF800) == 0 ) {
  433. //
  434. // see if we pass the end of the buffer
  435. //
  436. if ((*UTF8Count + 2) >= DestinationBufferSize) {
  437. break;
  438. }
  439. //
  440. // if the top 5 bits are zero, then encode as 2 bytes
  441. //
  442. DestinationBuffer[(*UTF8Count)++] = (UCHAR)((*SourceBuffer >> 6) & 0x1F) | 0xC0;
  443. DestinationBuffer[(*UTF8Count)++] = (UCHAR)(*SourceBuffer & 0xBF) | 0x80;
  444. } else {
  445. //
  446. // see if we pass the end of the buffer
  447. //
  448. if ((*UTF8Count + 3) >= DestinationBufferSize) {
  449. break;
  450. }
  451. //
  452. // encode as 3 bytes
  453. //
  454. DestinationBuffer[(*UTF8Count)++] = (UCHAR)((*SourceBuffer >> 12) & 0xF) | 0xE0;
  455. DestinationBuffer[(*UTF8Count)++] = (UCHAR)((*SourceBuffer >> 6) & 0x3F) | 0x80;
  456. DestinationBuffer[(*UTF8Count)++] = (UCHAR)(*SourceBuffer & 0xBF) | 0x80;
  457. }
  458. //
  459. // Advance the # of characters processed
  460. //
  461. (*ProcessedCount)++;
  462. //
  463. // Advanced to the next character to process
  464. //
  465. SourceBuffer += 1;
  466. }
  467. //
  468. // Sanity checks
  469. //
  470. ASSERT(*ProcessedCount <= SourceBufferLength);
  471. ASSERT(*UTF8Count <= DestinationBufferSize);
  472. return(TRUE);
  473. }
  474. BOOL
  475. SacChannelUnicodeWrite(
  476. IN SAC_CHANNEL_HANDLE SacChannelHandle,
  477. IN PCWSTR String
  478. )
  479. /*++
  480. Routine Description:
  481. This is a wrapper routine for sending data to a channel. That is,
  482. we can use this routine to modify the string before we send it off
  483. without having to modify the callers.
  484. This is a convenience routine to simplify
  485. UFT8 encoding and sending a Unicode string.
  486. Arguments:
  487. Channel - Previously created channel.
  488. String - Output string.
  489. Return Value:
  490. STATUS_SUCCESS if successful, otherwise status
  491. --*/
  492. {
  493. BOOL bStatus;
  494. ULONG Length;
  495. ULONG i;
  496. ULONG k;
  497. ULONG j;
  498. ULONG TranslatedCount;
  499. ULONG UTF8TranslationSize;
  500. PCWSTR pwch;
  501. ASSERT(String);
  502. //
  503. // Determine the total # of WCHARs to process
  504. //
  505. Length = wcslen(String);
  506. //
  507. // Do nothing if there is nothing to do
  508. //
  509. if (Length == 0) {
  510. return TRUE;
  511. }
  512. //
  513. // Point to the beginning of the string
  514. //
  515. pwch = (PCWSTR)String;
  516. //
  517. // default:
  518. //
  519. bStatus = TRUE;
  520. //
  521. // Divide the incoming buffer into blocks of length
  522. // MAX_UTF8_ENCODE_BLOCK_LENGTH.
  523. //
  524. do {
  525. //
  526. // Determine the remainder
  527. //
  528. k = Length % MAX_UTF8_ENCODE_BLOCK_LENGTH;
  529. if (k > 0) {
  530. //
  531. // Translate the first k characters
  532. //
  533. bStatus = SacTranslateUnicodeToUtf8(
  534. pwch,
  535. k,
  536. Utf8ConversionBuffer,
  537. Utf8ConversionBufferSize,
  538. &UTF8TranslationSize,
  539. &TranslatedCount
  540. );
  541. //
  542. // If this assert hits, it is probably caused by
  543. // a premature NULL termination in the incoming string
  544. //
  545. ASSERT(k == TranslatedCount);
  546. if (!bStatus) {
  547. break;
  548. }
  549. //
  550. // Send the UTF8 encoded characters
  551. //
  552. bStatus = SacChannelRawWrite(
  553. SacChannelHandle,
  554. Utf8ConversionBuffer,
  555. UTF8TranslationSize
  556. );
  557. if (! bStatus) {
  558. break;
  559. }
  560. //
  561. // Adjust the pwch to account for the sent length
  562. //
  563. pwch += k;
  564. }
  565. //
  566. // Determine the # of blocks we can process
  567. //
  568. j = Length / MAX_UTF8_ENCODE_BLOCK_LENGTH;
  569. //
  570. // Translate each WCHAR to UTF8 individually. This way,
  571. // no matter how big the String is, we don't run into
  572. // buffer size problems (it just might take a while).
  573. //
  574. for (i = 0; i < j; i++) {
  575. //
  576. // Encode the next block
  577. //
  578. bStatus = SacTranslateUnicodeToUtf8(
  579. pwch,
  580. MAX_UTF8_ENCODE_BLOCK_LENGTH,
  581. Utf8ConversionBuffer,
  582. Utf8ConversionBufferSize,
  583. &UTF8TranslationSize,
  584. &TranslatedCount
  585. );
  586. //
  587. // If this assert hits, it is probably caused by
  588. // a premature NULL termination in the incoming string
  589. //
  590. ASSERT(MAX_UTF8_ENCODE_BLOCK_LENGTH == TranslatedCount);
  591. if (! bStatus) {
  592. break;
  593. }
  594. //
  595. // Adjust the pwch to account for the sent length
  596. //
  597. pwch += MAX_UTF8_ENCODE_BLOCK_LENGTH;
  598. //
  599. // Send the UTF8 encoded characters
  600. //
  601. bStatus = SacChannelRawWrite(
  602. SacChannelHandle,
  603. Utf8ConversionBuffer,
  604. UTF8TranslationSize
  605. );
  606. if (! bStatus) {
  607. break;
  608. }
  609. }
  610. } while ( FALSE );
  611. //
  612. // Validate that the pwch pointer stopped at the end of the buffer
  613. //
  614. ASSERT(pwch == (String + Length));
  615. return bStatus;
  616. }