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.

1202 lines
31 KiB

  1. //--------------------------------------------------------------------------
  2. // WrapWide.cpp
  3. //--------------------------------------------------------------------------
  4. #include "pch.hxx"
  5. #include "dllmain.h"
  6. // --------------------------------------------------------------------------
  7. // AllocateStringA
  8. // --------------------------------------------------------------------------
  9. LPSTR AllocateStringA(DWORD cch)
  10. {
  11. // Allocate It
  12. return((LPSTR)g_pMalloc->Alloc((cch + 1) * sizeof(CHAR)));
  13. }
  14. // --------------------------------------------------------------------------
  15. // AllocateStringW
  16. // --------------------------------------------------------------------------
  17. LPWSTR AllocateStringW(DWORD cch)
  18. {
  19. // Allocate It
  20. return((LPWSTR)g_pMalloc->Alloc((cch + 1) * sizeof(WCHAR)));
  21. }
  22. // --------------------------------------------------------------------------
  23. // DuplicateStringA
  24. // --------------------------------------------------------------------------
  25. LPSTR DuplicateStringA(LPCSTR psz)
  26. {
  27. // Locals
  28. HRESULT hr=S_OK;
  29. DWORD cch;
  30. LPSTR pszT;
  31. // Trace
  32. TraceCall("DuplicateStringA");
  33. // Invalid Arg
  34. if (NULL == psz)
  35. return(NULL);
  36. // Length
  37. cch = lstrlenA(psz);
  38. // Allocate
  39. IF_NULLEXIT(pszT = AllocateStringA(cch));
  40. // Copy (including NULL)
  41. CopyMemory(pszT, psz, (cch + 1) * sizeof(CHAR));
  42. exit:
  43. // Done
  44. return(pszT);
  45. }
  46. // --------------------------------------------------------------------------
  47. // DuplicateStringW
  48. // --------------------------------------------------------------------------
  49. LPWSTR DuplicateStringW(LPCWSTR psz)
  50. {
  51. // Locals
  52. HRESULT hr=S_OK;
  53. DWORD cch;
  54. LPWSTR pszT;
  55. // Trace
  56. TraceCall("DuplicateStringW");
  57. // Invalid Arg
  58. if (NULL == psz)
  59. return(NULL);
  60. // Length
  61. cch = lstrlenW(psz);
  62. // Allocate
  63. IF_NULLEXIT(pszT = AllocateStringW(cch));
  64. // Copy (including NULL)
  65. CopyMemory(pszT, psz, (cch + 1) * sizeof(WCHAR));
  66. exit:
  67. // Done
  68. return(pszT);
  69. }
  70. // --------------------------------------------------------------------------
  71. // ConvertToUnicode
  72. // --------------------------------------------------------------------------
  73. LPWSTR ConvertToUnicode(UINT cp, LPCSTR pcszSource)
  74. {
  75. // Locals
  76. HRESULT hr=S_OK;
  77. INT cchNarrow;
  78. INT cchWide;
  79. LPWSTR pwszDup=NULL;
  80. // No Source
  81. if (pcszSource == NULL)
  82. goto exit;
  83. // Length
  84. cchNarrow = lstrlenA(pcszSource) + 1;
  85. // Determine how much space is needed for translated widechar
  86. cchWide = MultiByteToWideChar(cp, MB_PRECOMPOSED, pcszSource, cchNarrow, NULL, 0);
  87. // Error
  88. if (cchWide == 0)
  89. goto exit;
  90. // Alloc temp buffer
  91. IF_NULLEXIT(pwszDup = AllocateStringW(cchWide));
  92. // Do the actual translation
  93. cchWide = MultiByteToWideChar(cp, MB_PRECOMPOSED, pcszSource, cchNarrow, pwszDup, cchWide+1);
  94. // Error
  95. if (cchWide == 0)
  96. {
  97. SafeMemFree(pwszDup);
  98. goto exit;
  99. }
  100. exit:
  101. // Done
  102. return(pwszDup);
  103. }
  104. // --------------------------------------------------------------------------
  105. // ConvertToANSI
  106. // --------------------------------------------------------------------------
  107. LPSTR ConvertToANSI(UINT cp, LPCWSTR pcwszSource)
  108. {
  109. // Locals
  110. HRESULT hr=S_OK;
  111. INT cchNarrow;
  112. INT cchWide;
  113. LPSTR pszDup=NULL;
  114. // No Source
  115. if (pcwszSource == NULL)
  116. goto exit;
  117. // Length
  118. cchWide = lstrlenW(pcwszSource) + 1;
  119. // Determine how much space is needed for translated widechar
  120. cchNarrow = WideCharToMultiByte(cp, 0, pcwszSource, cchWide, NULL, 0, NULL, NULL);
  121. // Error
  122. if (cchNarrow == 0)
  123. goto exit;
  124. // Alloc temp buffer
  125. IF_NULLEXIT(pszDup = AllocateStringA(cchNarrow + 1));
  126. // Do the actual translation
  127. cchNarrow = WideCharToMultiByte(cp, 0, pcwszSource, cchWide, pszDup, cchNarrow + 1, NULL, NULL);
  128. // Error
  129. if (cchNarrow == 0)
  130. {
  131. SafeMemFree(pszDup);
  132. goto exit;
  133. }
  134. exit:
  135. // Done
  136. return(pszDup);
  137. }
  138. //--------------------------------------------------------------------------
  139. // GetFullPathNameWrapW
  140. //--------------------------------------------------------------------------
  141. DWORD GetFullPathNameWrapW(LPCWSTR pwszFileName, DWORD nBufferLength,
  142. LPWSTR pwszBuffer, LPWSTR *ppwszFilePart)
  143. {
  144. // Locals
  145. HRESULT hr=S_OK;
  146. DWORD dwReturn;
  147. LPSTR pszFileName=NULL;
  148. LPSTR pszFilePart=NULL;
  149. LPSTR pszBuffer=NULL;
  150. DWORD dwError=0;
  151. // Trace
  152. TraceCall("GetFullPathNameWrapW");
  153. // If WinNT, call Unicode Version
  154. if (g_fIsWinNT)
  155. return(GetFullPathNameW(pwszFileName, nBufferLength, pwszBuffer, ppwszFilePart));
  156. // Convert
  157. if (pwszFileName)
  158. {
  159. // To ANSI
  160. IF_NULLEXIT(pszFileName = ConvertToANSI(CP_ACP, pwszFileName));
  161. }
  162. // Allocate
  163. if (pwszBuffer && nBufferLength)
  164. {
  165. // Allocate a Buffer
  166. IF_NULLEXIT(pszBuffer = AllocateStringA(nBufferLength));
  167. }
  168. // Call
  169. dwReturn = GetFullPathNameA(pszFileName, nBufferLength, pszBuffer, &pszFilePart);
  170. // Save Last Error
  171. dwError = GetLastError();
  172. // If we have a buffer
  173. if (pwszBuffer && nBufferLength)
  174. {
  175. // Convert to Unicode
  176. if (0 == (dwReturn = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszBuffer, -1, pwszBuffer, nBufferLength)))
  177. {
  178. TraceResult(E_FAIL);
  179. goto exit;
  180. }
  181. if(dwReturn < nBufferLength)
  182. pwszBuffer[dwReturn] = L'\0';
  183. else
  184. Assert(FALSE);
  185. }
  186. // Set ppwszFilePath
  187. if (ppwszFilePart)
  188. {
  189. // Do we have a file part
  190. if (pszFilePart && pszBuffer && pwszBuffer && nBufferLength)
  191. {
  192. // Set Length
  193. DWORD cch = (DWORD)(pszFilePart - pszBuffer);
  194. // Set
  195. *ppwszFilePart = (LPWSTR)((LPBYTE)pwszBuffer + (cch * sizeof(WCHAR)));
  196. }
  197. // Otherwise
  198. else
  199. *ppwszFilePart = NULL;
  200. }
  201. exit:
  202. // Cleanup
  203. g_pMalloc->Free(pszFileName);
  204. g_pMalloc->Free(pszBuffer);
  205. // Save Last Error
  206. SetLastError(dwError);
  207. // Done
  208. return(SUCCEEDED(hr) ? dwReturn : 0);
  209. }
  210. //--------------------------------------------------------------------------
  211. // CreateMutexWrapW
  212. //--------------------------------------------------------------------------
  213. HANDLE CreateMutexWrapW(LPSECURITY_ATTRIBUTES pMutexAttributes,
  214. BOOL bInitialOwner, LPCWSTR pwszName)
  215. {
  216. // Locals
  217. HRESULT hr=S_OK;
  218. HANDLE hMutex=NULL;
  219. LPSTR pszName=NULL;
  220. DWORD dwError=0;
  221. // Trace
  222. TraceCall("CreateMutexWrapW");
  223. // If WinNT, call Unicode Version
  224. if (g_fIsWinNT)
  225. return(CreateMutexW(pMutexAttributes, bInitialOwner, pwszName));
  226. // Convert to Ansi
  227. if (pwszName)
  228. {
  229. // To ANSI
  230. IF_NULLEXIT(pszName = ConvertToANSI(CP_ACP, pwszName));
  231. }
  232. // Call ANSI
  233. hMutex = CreateMutexA(pMutexAttributes, bInitialOwner, pszName);
  234. // Save Last Error
  235. dwError = GetLastError();
  236. exit:
  237. // Cleanup
  238. g_pMalloc->Free(pszName);
  239. // Save Last Error
  240. SetLastError(dwError);
  241. // Done
  242. return(hMutex);
  243. }
  244. //--------------------------------------------------------------------------
  245. // CharLowerBuffWrapW
  246. //--------------------------------------------------------------------------
  247. DWORD CharLowerBuffWrapW(LPWSTR pwsz, DWORD cch)
  248. {
  249. // Locals
  250. HRESULT hr=S_OK;
  251. LPSTR psz=NULL;
  252. DWORD dwReturn=0;
  253. DWORD dwError=0;
  254. DWORD cchMax;
  255. // Trace
  256. TraceCall("CharLowerBuffWrapW");
  257. // If WinNT, call Unicode Version
  258. if (g_fIsWinNT)
  259. return(CharLowerBuffW(pwsz, cch));
  260. // Convert
  261. if (pwsz)
  262. {
  263. // Convert to ANSI
  264. IF_NULLEXIT(psz = ConvertToANSI(CP_ACP, pwsz));
  265. }
  266. // Call ANSI
  267. dwReturn = CharLowerBuffA(psz, cch);
  268. // Get the last error
  269. dwError = GetLastError();
  270. // If psz
  271. if (psz)
  272. {
  273. // Convert back to unicode
  274. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, psz, -1, pwsz, cch);
  275. }
  276. exit:
  277. // Cleanup
  278. g_pMalloc->Free(psz);
  279. // Save the last error
  280. SetLastError(dwError);
  281. // Done
  282. return(dwReturn);
  283. }
  284. //--------------------------------------------------------------------------
  285. // CreateFileWrapW
  286. //--------------------------------------------------------------------------
  287. HANDLE CreateFileWrapW(LPCWSTR pwszFileName, DWORD dwDesiredAccess,
  288. DWORD dwShareMode, LPSECURITY_ATTRIBUTES pSecurityAttributes,
  289. DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
  290. HANDLE hTemplateFile)
  291. {
  292. // Locals
  293. HRESULT hr=S_OK;
  294. HANDLE hFile=INVALID_HANDLE_VALUE;
  295. LPSTR pszFileName=NULL;
  296. DWORD dwError=0;
  297. // Trace
  298. TraceCall("CreateFileWrapW");
  299. // If WinNT, call Unicode Version
  300. if (g_fIsWinNT)
  301. return(CreateFileW(pwszFileName, dwDesiredAccess, dwShareMode, pSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile));
  302. // To ANSI
  303. if (pwszFileName)
  304. {
  305. // Convert to ANSI
  306. IF_NULLEXIT(pszFileName = ConvertToANSI(CP_ACP, pwszFileName));
  307. }
  308. // Call ANSI
  309. hFile = CreateFileA(pszFileName, dwDesiredAccess, dwShareMode, pSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
  310. // Save the last Error
  311. dwError = GetLastError();
  312. exit:
  313. // Cleanup
  314. g_pMalloc->Free(pszFileName);
  315. // Set Last Error
  316. SetLastError(dwError);
  317. // Done
  318. return(hFile);
  319. }
  320. //--------------------------------------------------------------------------
  321. // GetDiskFreeSpaceWrapW
  322. //--------------------------------------------------------------------------
  323. BOOL GetDiskFreeSpaceWrapW(LPCWSTR pwszRootPathName, LPDWORD pdwSectorsPerCluster,
  324. LPDWORD pdwBytesPerSector, LPDWORD pdwNumberOfFreeClusters,
  325. LPDWORD pdwTotalNumberOfClusters)
  326. {
  327. // Locals
  328. HRESULT hr=S_OK;
  329. BOOL fReturn=FALSE;
  330. LPSTR pszRootPathName=NULL;
  331. DWORD dwError=0;
  332. // Trace
  333. TraceCall("GetClassInfoWrapW");
  334. // If WinNT, call Unicode Version
  335. if (g_fIsWinNT)
  336. return(GetDiskFreeSpaceW(pwszRootPathName, pdwSectorsPerCluster, pdwBytesPerSector, pdwNumberOfFreeClusters, pdwTotalNumberOfClusters));
  337. // To ANSI
  338. if (pwszRootPathName)
  339. {
  340. // to ANSI
  341. IF_NULLEXIT(pszRootPathName = ConvertToANSI(CP_ACP, pwszRootPathName));
  342. }
  343. // Call ANSI
  344. fReturn = GetDiskFreeSpaceA(pszRootPathName, pdwSectorsPerCluster, pdwBytesPerSector, pdwNumberOfFreeClusters, pdwTotalNumberOfClusters);
  345. // Save Last Error
  346. dwError = GetLastError();
  347. exit:
  348. // Cleanup
  349. g_pMalloc->Free(pszRootPathName);
  350. // Save Last Error
  351. SetLastError(dwError);
  352. // Done
  353. return(fReturn);
  354. }
  355. //--------------------------------------------------------------------------
  356. // OpenFileMappingWrapW
  357. //--------------------------------------------------------------------------
  358. HANDLE OpenFileMappingWrapW(DWORD dwDesiredAccess, BOOL bInheritHandle,
  359. LPCWSTR pwszName)
  360. {
  361. // Locals
  362. HRESULT hr=S_OK;
  363. HANDLE hMapping=NULL;
  364. LPSTR pszName=NULL;
  365. DWORD dwError=0;
  366. // Trace
  367. TraceCall("OpenFileMappingWrapW");
  368. // If WinNT, call Unicode Version
  369. if (g_fIsWinNT)
  370. return(OpenFileMappingW(dwDesiredAccess, bInheritHandle, pwszName));
  371. // To ANSI
  372. if (pwszName)
  373. {
  374. // to ANSI
  375. IF_NULLEXIT(pszName = ConvertToANSI(CP_ACP, pwszName));
  376. }
  377. // Call ANSI
  378. hMapping = OpenFileMappingA(dwDesiredAccess, bInheritHandle, pszName);
  379. // Save the last error
  380. dwError = GetLastError();
  381. exit:
  382. // Cleanup
  383. g_pMalloc->Free(pszName);
  384. // Set the last error
  385. SetLastError(dwError);
  386. // Done
  387. return(hMapping);
  388. }
  389. //--------------------------------------------------------------------------
  390. // CreateFileMappingWrapW
  391. //--------------------------------------------------------------------------
  392. HANDLE CreateFileMappingWrapW(HANDLE hFile, LPSECURITY_ATTRIBUTES pFileMappingAttributes,
  393. DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow,
  394. LPCWSTR pwszName)
  395. {
  396. // Locals
  397. HRESULT hr=S_OK;
  398. HANDLE hMapping=NULL;
  399. LPSTR pszName=NULL;
  400. DWORD dwError=0;
  401. // Trace
  402. TraceCall("OpenFileMappingWrapW");
  403. // If WinNT, call Unicode Version
  404. if (g_fIsWinNT)
  405. return(CreateFileMappingW(hFile, pFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName));
  406. // To ANSI
  407. if (pwszName)
  408. {
  409. // to ANSI
  410. IF_NULLEXIT(pszName = ConvertToANSI(CP_ACP, pwszName));
  411. }
  412. // Call ANSI
  413. hMapping = CreateFileMappingA(hFile, pFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pszName);
  414. // Save last error
  415. dwError = GetLastError();
  416. exit:
  417. // Cleanup
  418. g_pMalloc->Free(pszName);
  419. // Save last error
  420. SetLastError(dwError);
  421. // Done
  422. return(hMapping);
  423. }
  424. //--------------------------------------------------------------------------
  425. // MoveFileWrapW
  426. //--------------------------------------------------------------------------
  427. BOOL MoveFileWrapW(LPCWSTR pwszExistingFileName, LPCWSTR pwszNewFileName)
  428. {
  429. // Locals
  430. HRESULT hr=S_OK;
  431. BOOL fReturn=FALSE;
  432. LPSTR pszExistingFileName=NULL;
  433. LPSTR pszNewFileName=NULL;
  434. DWORD dwError=0;
  435. // Trace
  436. TraceCall("MoveFileWrapW");
  437. // If WinNT, call Unicode Version
  438. if (g_fIsWinNT)
  439. return(MoveFileW(pwszExistingFileName, pwszNewFileName));
  440. // To ANSI
  441. if (pwszExistingFileName)
  442. {
  443. // to ANSI
  444. IF_NULLEXIT(pszExistingFileName = ConvertToANSI(CP_ACP, pwszExistingFileName));
  445. }
  446. // To ANSI
  447. if (pwszNewFileName)
  448. {
  449. // to ANSI
  450. IF_NULLEXIT(pszNewFileName = ConvertToANSI(CP_ACP, pwszNewFileName));
  451. }
  452. // Call ANSI
  453. fReturn = MoveFileA(pszExistingFileName, pszNewFileName);
  454. // Save the last Error
  455. dwError = GetLastError();
  456. exit:
  457. // Cleanup
  458. g_pMalloc->Free(pszExistingFileName);
  459. g_pMalloc->Free(pszNewFileName);
  460. // Save the last Error
  461. SetLastError(dwError);
  462. // Done
  463. return(fReturn);
  464. }
  465. //--------------------------------------------------------------------------
  466. // DeleteFileWrapW
  467. //--------------------------------------------------------------------------
  468. BOOL DeleteFileWrapW(LPCWSTR pwszFileName)
  469. {
  470. // Locals
  471. HRESULT hr=S_OK;
  472. BOOL fReturn=FALSE;
  473. LPSTR pszFileName=NULL;
  474. DWORD dwError=0;
  475. // Trace
  476. TraceCall("DeleteFileWrapW");
  477. // If WinNT, call Unicode Version
  478. if (g_fIsWinNT)
  479. return(DeleteFileW(pwszFileName));
  480. // To ANSI
  481. if (pwszFileName)
  482. {
  483. // to ANSI
  484. IF_NULLEXIT(pszFileName = ConvertToANSI(CP_ACP, pwszFileName));
  485. }
  486. // Call ANSI
  487. fReturn = DeleteFileA(pszFileName);
  488. // Save the last Error
  489. dwError = GetLastError();
  490. exit:
  491. // Cleanup
  492. g_pMalloc->Free(pszFileName);
  493. // Save the last Error
  494. SetLastError(dwError);
  495. // Done
  496. return(fReturn);
  497. }
  498. /**********************************************************************************\
  499. * from msoert ported by YSt 6/25/99
  500. *
  501. * bobn 6/23/99
  502. *
  503. * The following code was ported from ShlWapi. There were problems with
  504. * our implementation on Win95 and it seemed prudent to have a solution
  505. * without a bunch of special cases.
  506. *
  507. *
  508. \**********************************************************************************/
  509. #define DBCS_CHARSIZE (2)
  510. int DDB_MBToWCS(LPSTR pszIn, int cchIn, LPWSTR *ppwszOut)
  511. {
  512. int cch = 0;
  513. int cbAlloc;
  514. if ((0 != cchIn) && (NULL != ppwszOut))
  515. {
  516. cchIn++;
  517. cbAlloc = cchIn * sizeof(WCHAR);
  518. *ppwszOut = (LPWSTR)LocalAlloc(LMEM_FIXED, cbAlloc);
  519. if (NULL != *ppwszOut)
  520. {
  521. cch = MultiByteToWideChar(CP_ACP, 0, pszIn, cchIn, *ppwszOut, cchIn);
  522. if (!cch)
  523. {
  524. LocalFree(*ppwszOut);
  525. *ppwszOut = NULL;
  526. }
  527. else
  528. {
  529. cch--; // Just return the number of characters
  530. }
  531. }
  532. }
  533. return cch;
  534. }
  535. int DDB_WCSToMB(LPCWSTR pwszIn, int cchIn, LPSTR *ppszOut)
  536. {
  537. int cch = 0;
  538. int cbAlloc;
  539. if ((0 != cchIn) && (NULL != ppszOut))
  540. {
  541. cchIn++;
  542. cbAlloc = cchIn * DBCS_CHARSIZE;
  543. *ppszOut = (LPSTR)LocalAlloc(LMEM_FIXED, cbAlloc);
  544. if (NULL != *ppszOut)
  545. {
  546. cch = WideCharToMultiByte(CP_ACP, 0, pwszIn, cchIn,
  547. *ppszOut, cbAlloc, NULL, NULL);
  548. if (!cch)
  549. {
  550. LocalFree(*ppszOut);
  551. *ppszOut = NULL;
  552. }
  553. else
  554. {
  555. cch--; // Just return the number of characters
  556. }
  557. }
  558. }
  559. return cch;
  560. }
  561. /****************************** Module Header ******************************\
  562. * Module Name: wsprintf.c
  563. *
  564. * Copyright (c) 1985-91, Microsoft Corporation
  565. * sprintf.c
  566. *
  567. * Implements Windows friendly versions of sprintf and vsprintf
  568. *
  569. * History:
  570. * 2-15-89 craigc Initial
  571. * 11-12-90 MikeHar Ported from windows 3
  572. \***************************************************************************/
  573. /* Max number of characters. Doesn't include termination character */
  574. #define out(c) if (cchLimit) {*lpOut++=(c); cchLimit--;} else goto errorout
  575. /***************************************************************************\
  576. * DDB_SP_GetFmtValueW
  577. *
  578. * reads a width or precision value from the format string
  579. *
  580. * History:
  581. * 11-12-90 MikeHar Ported from windows 3
  582. * 07-27-92 GregoryW Created Unicode version (copied from DDB_SP_GetFmtValue)
  583. \***************************************************************************/
  584. LPCWSTR DDB_SP_GetFmtValueW(
  585. LPCWSTR lpch,
  586. int *lpw)
  587. {
  588. int ii = 0;
  589. /* It might not work for some locales or digit sets */
  590. while (*lpch >= L'0' && *lpch <= L'9') {
  591. ii *= 10;
  592. ii += (int)(*lpch - L'0');
  593. lpch++;
  594. }
  595. *lpw = ii;
  596. /*
  597. * return the address of the first non-digit character
  598. */
  599. return lpch;
  600. }
  601. /***************************************************************************\
  602. * DDB_SP_PutNumberW
  603. *
  604. * Takes an unsigned long integer and places it into a buffer, respecting
  605. * a buffer limit, a radix, and a case select (upper or lower, for hex).
  606. *
  607. *
  608. * History:
  609. * 11-12-90 MikeHar Ported from windows 3 asm --> C
  610. * 12-11-90 GregoryW need to increment lpstr after assignment of mod
  611. * 02-11-92 GregoryW temporary version until we have C runtime support
  612. \***************************************************************************/
  613. int DDB_SP_PutNumberW(
  614. LPWSTR lpstr,
  615. DWORD n,
  616. int limit,
  617. DWORD radix,
  618. int uppercase,
  619. int *pcch)
  620. {
  621. DWORD mod;
  622. *pcch = 0;
  623. /* It might not work for some locales or digit sets */
  624. if(uppercase)
  625. uppercase = 'A'-'0'-10;
  626. else
  627. uppercase = 'a'-'0'-10;
  628. if (limit) {
  629. do {
  630. mod = n % radix;
  631. n /= radix;
  632. mod += '0';
  633. if (mod > '9')
  634. mod += uppercase;
  635. *lpstr++ = (WCHAR)mod;
  636. (*pcch)++;
  637. } while((*pcch < limit) && n);
  638. }
  639. return (n == 0) && (*pcch > 0);
  640. }
  641. /***************************************************************************\
  642. * DDB_SP_ReverseW
  643. *
  644. * reverses a string in place
  645. *
  646. * History:
  647. * 11-12-90 MikeHar Ported from windows 3 asm --> C
  648. * 12-11-90 GregoryW fixed boundary conditions; removed count
  649. * 02-11-92 GregoryW temporary version until we have C runtime support
  650. \***************************************************************************/
  651. void DDB_SP_ReverseW(
  652. LPWSTR lpFirst,
  653. LPWSTR lpLast)
  654. {
  655. WCHAR ch;
  656. while(lpLast > lpFirst){
  657. ch = *lpFirst;
  658. *lpFirst++ = *lpLast;
  659. *lpLast-- = ch;
  660. }
  661. }
  662. /***************************************************************************\
  663. * wvsprintfW (API)
  664. *
  665. * wsprintfW() calls this function.
  666. *
  667. * History:
  668. * 11-Feb-1992 GregoryW copied xwvsprintf
  669. * Temporary hack until we have C runtime support
  670. * 1-22-97 tnoonan Converted to wvnsprintfW
  671. \***************************************************************************/
  672. int DDB_wvnsprintfW(
  673. LPWSTR lpOut,
  674. int cchLimitIn,
  675. LPCWSTR lpFmt,
  676. va_list arglist)
  677. {
  678. BOOL fAllocateMem = FALSE;
  679. WCHAR prefix, fillch;
  680. int left, width, prec, size, sign, radix, upper, hprefix;
  681. int cchLimit = --cchLimitIn, cch, cchAvailable;
  682. LPWSTR lpT, lpTWC;
  683. LPSTR psz;
  684. va_list varglist = arglist;
  685. union {
  686. long l;
  687. unsigned long ul;
  688. CHAR sz[2];
  689. WCHAR wsz[2];
  690. } val;
  691. if (cchLimit < 0)
  692. return 0;
  693. while (*lpFmt != 0) {
  694. if (*lpFmt == L'%') {
  695. /*
  696. * read the flags. These can be in any order
  697. */
  698. left = 0;
  699. prefix = 0;
  700. while (*++lpFmt) {
  701. if (*lpFmt == L'-')
  702. left++;
  703. else if (*lpFmt == L'#')
  704. prefix++;
  705. else
  706. break;
  707. }
  708. /*
  709. * find fill character
  710. */
  711. if (*lpFmt == L'0') {
  712. fillch = L'0';
  713. lpFmt++;
  714. } else
  715. fillch = L' ';
  716. /*
  717. * read the width specification
  718. */
  719. lpFmt = DDB_SP_GetFmtValueW(lpFmt, &cch);
  720. width = cch;
  721. /*
  722. * read the precision
  723. */
  724. if (*lpFmt == L'.') {
  725. lpFmt = DDB_SP_GetFmtValueW(++lpFmt, &cch);
  726. prec = cch;
  727. } else
  728. prec = -1;
  729. /*
  730. * get the operand size
  731. * default size: size == 0
  732. * long number: size == 1
  733. * wide chars: size == 2
  734. * It may be a good idea to check the value of size when it
  735. * is tested for non-zero below (IanJa)
  736. */
  737. hprefix = 0;
  738. if ((*lpFmt == L'w') || (*lpFmt == L't')) {
  739. size = 2;
  740. lpFmt++;
  741. } else if (*lpFmt == L'l') {
  742. size = 1;
  743. lpFmt++;
  744. } else {
  745. size = 0;
  746. if (*lpFmt == L'h') {
  747. lpFmt++;
  748. hprefix = 1;
  749. }
  750. }
  751. upper = 0;
  752. sign = 0;
  753. radix = 10;
  754. switch (*lpFmt) {
  755. case 0:
  756. goto errorout;
  757. case L'i':
  758. case L'd':
  759. size=1;
  760. sign++;
  761. /*** FALL THROUGH to case 'u' ***/
  762. case L'u':
  763. /* turn off prefix if decimal */
  764. prefix = 0;
  765. donumeric:
  766. /* special cases to act like MSC v5.10 */
  767. if (left || prec >= 0)
  768. fillch = L' ';
  769. /*
  770. * if size == 1, "%lu" was specified (good);
  771. * if size == 2, "%wu" was specified (bad)
  772. */
  773. if (size) {
  774. val.l = va_arg(varglist, LONG);
  775. } else if (sign) {
  776. val.l = va_arg(varglist, SHORT);
  777. } else {
  778. val.ul = va_arg(varglist, unsigned);
  779. }
  780. if (sign && val.l < 0L)
  781. val.l = -val.l;
  782. else
  783. sign = 0;
  784. lpT = lpOut;
  785. /*
  786. * blast the number backwards into the user buffer
  787. * DDB_SP_PutNumberW returns FALSE if it runs out of space
  788. */
  789. if (!DDB_SP_PutNumberW(lpOut, val.l, cchLimit, radix, upper, &cch))
  790. {
  791. break;
  792. }
  793. // Now we have the number backwards, calculate how much
  794. // more buffer space we'll need for this number to
  795. // format correctly.
  796. cchAvailable = cchLimit - cch;
  797. width -= cch;
  798. prec -= cch;
  799. if (prec > 0)
  800. {
  801. width -= prec;
  802. cchAvailable -= prec;
  803. }
  804. if (width > 0)
  805. {
  806. cchAvailable -= width - (sign ? 1 : 0);
  807. }
  808. if (sign)
  809. {
  810. cchAvailable--;
  811. }
  812. if (cchAvailable < 0)
  813. {
  814. break;
  815. }
  816. // We have enough space to format the buffer as requested
  817. // without overflowing.
  818. lpOut += cch;
  819. cchLimit -= cch;
  820. /*
  821. * fill to the field precision
  822. */
  823. while (prec-- > 0)
  824. out(L'0');
  825. if (width > 0 && !left) {
  826. /*
  827. * if we're filling with spaces, put sign first
  828. */
  829. if (fillch != L'0') {
  830. if (sign) {
  831. sign = 0;
  832. out(L'-');
  833. width--;
  834. }
  835. if (prefix) {
  836. out(prefix);
  837. out(L'0');
  838. prefix = 0;
  839. }
  840. }
  841. if (sign)
  842. width--;
  843. /*
  844. * fill to the field width
  845. */
  846. while (width-- > 0)
  847. out(fillch);
  848. /*
  849. * still have a sign?
  850. */
  851. if (sign)
  852. out(L'-');
  853. if (prefix) {
  854. out(prefix);
  855. out(L'0');
  856. }
  857. /*
  858. * now reverse the string in place
  859. */
  860. DDB_SP_ReverseW(lpT, lpOut - 1);
  861. } else {
  862. /*
  863. * add the sign character
  864. */
  865. if (sign) {
  866. out(L'-');
  867. width--;
  868. }
  869. if (prefix) {
  870. out(prefix);
  871. out(L'0');
  872. }
  873. /*
  874. * reverse the string in place
  875. */
  876. DDB_SP_ReverseW(lpT, lpOut - 1);
  877. /*
  878. * pad to the right of the string in case left aligned
  879. */
  880. while (width-- > 0)
  881. out(fillch);
  882. }
  883. break;
  884. case L'X':
  885. upper++;
  886. /*** FALL THROUGH to case 'x' ***/
  887. case L'x':
  888. radix = 16;
  889. if (prefix)
  890. if (upper)
  891. prefix = L'X';
  892. else
  893. prefix = L'x';
  894. goto donumeric;
  895. case L'c':
  896. if (!size && !hprefix) {
  897. size = 1; // force WCHAR
  898. }
  899. /*** FALL THROUGH to case 'C' ***/
  900. case L'C':
  901. /*
  902. * if size == 0, "%C" or "%hc" was specified (CHAR);
  903. * if size == 1, "%c" or "%lc" was specified (WCHAR);
  904. * if size == 2, "%wc" or "%tc" was specified (WCHAR)
  905. */
  906. cch = 1; /* One character must be copied to the output buffer */
  907. if (size) {
  908. val.wsz[0] = va_arg(varglist, WCHAR);
  909. val.wsz[1] = 0;
  910. lpT = val.wsz;
  911. goto putwstring;
  912. } else {
  913. val.sz[0] = va_arg(varglist, CHAR);
  914. val.sz[1] = 0;
  915. psz = (LPSTR)(val.sz);
  916. goto putstring;
  917. }
  918. case L's':
  919. if (!size && !hprefix) {
  920. size = 1; // force LPWSTR
  921. }
  922. /*** FALL THROUGH to case 'S' ***/
  923. case L'S':
  924. /*
  925. * if size == 0, "%S" or "%hs" was specified (LPSTR)
  926. * if size == 1, "%s" or "%ls" was specified (LPWSTR);
  927. * if size == 2, "%ws" or "%ts" was specified (LPWSTR)
  928. */
  929. if (size) {
  930. lpT = va_arg(varglist, LPWSTR);
  931. cch = lstrlenW(lpT);
  932. } else {
  933. psz = va_arg(varglist, LPSTR);
  934. cch = lstrlen((LPCSTR)psz);
  935. putstring:
  936. cch = DDB_MBToWCS(psz, cch, &lpTWC);
  937. fAllocateMem = (BOOL) cch;
  938. lpT = lpTWC;
  939. }
  940. putwstring:
  941. if (prec >= 0 && cch > prec)
  942. cch = prec;
  943. width -= cch;
  944. if (left) {
  945. while (cch--)
  946. out(*lpT++);
  947. while (width-- > 0)
  948. out(fillch);
  949. } else {
  950. while (width-- > 0)
  951. out(fillch);
  952. while (cch--)
  953. out(*lpT++);
  954. }
  955. if (fAllocateMem) {
  956. LocalFree(lpTWC);
  957. fAllocateMem = FALSE;
  958. }
  959. break;
  960. default:
  961. normalch:
  962. out((WCHAR)*lpFmt);
  963. break;
  964. } /* END OF SWITCH(*lpFmt) */
  965. } /* END OF IF(%) */ else
  966. goto normalch; /* character not a '%', just do it */
  967. /*
  968. * advance to next format string character
  969. */
  970. lpFmt++;
  971. } /* END OF OUTER WHILE LOOP */
  972. errorout:
  973. *lpOut = 0;
  974. if (fAllocateMem)
  975. {
  976. LocalFree(lpTWC);
  977. }
  978. return cchLimitIn - cchLimit;
  979. }
  980. int wsprintfWrapW( LPWSTR lpOut, int cchLimitIn, LPCWSTR lpFmt, ... )
  981. {
  982. va_list arglist;
  983. int ret;
  984. Assert(lpOut);
  985. Assert(lpFmt);
  986. lpOut[0] = 0;
  987. va_start(arglist, lpFmt);
  988. ret = DDB_wvnsprintfW(lpOut, cchLimitIn, lpFmt, arglist);
  989. va_end(arglist);
  990. return ret;
  991. }