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.

500 lines
14 KiB

  1. /******************************************************************************
  2. Source File: Code Page Knowledge Base.CPP
  3. This implements the code page knowledge base.
  4. Copyright (c) 1997 by Microsoft Corporation. All Rights Reserved.
  5. A Pretty Penny Enterprises Production.
  6. Change History:
  7. 02-22-1997 Bob_Kjelgaard@Prodigy.Net Created it
  8. ******************************************************************************/
  9. #include "StdAfx.h"
  10. //#include <AfxDllx.h>
  11. #include "Resource.H"
  12. #if defined(LONG_NAMES)
  13. #include "Code Page Knowledge Base.H"
  14. #else
  15. #include "CodePage.H"
  16. #endif
  17. #ifdef _DEBUG
  18. #define new DEBUG_NEW
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22. /*** Commented out because this code is no longer in a DLL.
  23. static AFX_EXTENSION_MODULE CodePageKnowledgeBaseDLL = { NULL, NULL };
  24. static HINSTANCE hi;
  25. extern "C" int APIENTRY
  26. DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) {
  27. if (dwReason == DLL_PROCESS_ATTACH) {
  28. hi = hInstance;
  29. TRACE0("Code Page Knowledge Base.DLL Initializing!\n");
  30. // Extension DLL one-time initialization
  31. AfxInitExtensionModule(CodePageKnowledgeBaseDLL, hInstance);
  32. // Insert this DLL into the resource chain
  33. new CDynLinkLibrary(CodePageKnowledgeBaseDLL);
  34. }
  35. else if (dwReason == DLL_PROCESS_DETACH) {
  36. TRACE0("Code Page Knowledge Base.DLL Terminating!\n");
  37. }
  38. return 1; // ok
  39. }
  40. */
  41. static CDWordArray cdaInstalled, cdaSupported, cdaMapped;
  42. static BOOL CALLBACK EnumProc(LPTSTR lpstrName) {
  43. cdaSupported.Add(atoi(lpstrName));
  44. return TRUE;
  45. }
  46. /******************************************************************************
  47. CCodePageInformation::Load
  48. This loads the selected code page into the cache, if it isn't already there.
  49. ******************************************************************************/
  50. BOOL CCodePageInformation::Load(DWORD dwidPage) {
  51. if (dwidPage == m_dwidMapped)
  52. return TRUE; // Already done!
  53. if (dwidPage > 65535) // We map words for code pages in civilized lands
  54. return FALSE;
  55. HRSRC hrsrc = FindResource(AfxGetResourceHandle(), MAKEINTRESOURCE((WORD) dwidPage),
  56. MAKEINTRESOURCE(MAPPING_TABLE));
  57. // raid 43537
  58. if (!hrsrc)
  59. return FALSE;
  60. HGLOBAL hgMap = LoadResource(AfxGetResourceHandle(), hrsrc);
  61. if (!hgMap)
  62. return FALSE; // This should never happen!
  63. LPVOID lpv = LockResource(hgMap);
  64. if (!lpv)
  65. return FALSE;
  66. try {
  67. m_cbaMap.RemoveAll();
  68. m_cbaMap.SetSize(SizeofResource(AfxGetResourceHandle(), hrsrc));
  69. memcpy(m_cbaMap.GetData(), lpv, (size_t)m_cbaMap.GetSize());
  70. }
  71. catch (CException * pce) {
  72. m_dwidMapped = 0;
  73. pce -> ReportError();
  74. pce -> Delete();
  75. return FALSE;
  76. }
  77. m_dwidMapped = dwidPage;
  78. return TRUE;
  79. }
  80. /******************************************************************************
  81. CCodePageInformation::Map
  82. This creates either the in or out of unicode translation table, as requested,
  83. using the loaded map.
  84. ******************************************************************************/
  85. BOOL CCodePageInformation::Map(BOOL bUnicode) {
  86. if (!m_dwidMapped)
  87. return FALSE;
  88. DWORD& dwid = bUnicode ? m_dwidOut : m_dwidIn;
  89. if (m_dwidMapped == dwid)
  90. return TRUE;
  91. struct MB2WCMap {
  92. WORD m_wMBCS;
  93. WORD m_wWC;
  94. } *psMap = (MB2WCMap *) m_cbaMap.GetData();
  95. if (!psMap)
  96. return 0;
  97. DWORD dwcEntries = (DWORD)m_cbaMap.GetSize() / sizeof *psMap;
  98. CWordArray& cwaMap = bUnicode ? m_cwaOut : m_cwaIn;
  99. try {
  100. cwaMap.RemoveAll();
  101. cwaMap.InsertAt(0, 0xFFFF, 65536); // This is always an invalid value
  102. while (dwcEntries--)
  103. if (bUnicode)
  104. cwaMap[psMap[dwcEntries].m_wWC] = psMap[dwcEntries].m_wMBCS;
  105. else
  106. cwaMap[psMap[dwcEntries].m_wMBCS] = psMap[dwcEntries].m_wWC;
  107. }
  108. catch (CException * pce) {
  109. dwid = 0;
  110. cwaMap.RemoveAll();
  111. pce -> ReportError();
  112. pce -> Delete();
  113. return 0;
  114. }
  115. dwid = m_dwidMapped;
  116. return TRUE;
  117. }
  118. /******************************************************************************
  119. CCodePageInformation constructor
  120. If the statistics haven't been initialized, do it now. Otherwise, this is
  121. trivial.
  122. ******************************************************************************/
  123. CCodePageInformation::CCodePageInformation() {
  124. m_dwidMapped = m_dwidIn = m_dwidOut = 0;
  125. // Initialize the statics if we need to.
  126. if (cdaInstalled.GetSize())
  127. return;
  128. EnumSystemCodePages(&EnumProc, CP_INSTALLED);
  129. cdaInstalled.Copy(cdaSupported);
  130. cdaSupported.RemoveAll();
  131. EnumSystemCodePages(&EnumProc, CP_SUPPORTED);
  132. // Build a list of mappable code pages
  133. for (DWORD dw = 400; dw < 32767; dw++)
  134. if (HaveMap(dw))
  135. cdaMapped.Add(dw);
  136. }
  137. const unsigned CCodePageInformation::SupportedCount() const {
  138. return (unsigned) cdaSupported.GetSize();
  139. }
  140. const unsigned CCodePageInformation::InstalledCount() const {
  141. return (unsigned) cdaInstalled.GetSize();
  142. }
  143. const unsigned CCodePageInformation::MappedCount() const {
  144. return (unsigned) cdaMapped.GetSize();
  145. }
  146. const DWORD CCodePageInformation::Supported(unsigned u) const {
  147. return cdaSupported[u];
  148. }
  149. const DWORD CCodePageInformation::Installed(unsigned u) const {
  150. return cdaInstalled[u];
  151. }
  152. const DWORD CCodePageInformation::Mapped(unsigned u) const {
  153. return cdaMapped[u];
  154. }
  155. /******************************************************************************
  156. CCodePageInformation::Mapped(CDWordArray& cdaReturn)
  157. Fills the given array with all of the mapped code page IDs.
  158. ******************************************************************************/
  159. void CCodePageInformation::Mapped(CDWordArray& cdaReturn) const {
  160. cdaReturn.Copy(cdaMapped);
  161. }
  162. CString CCodePageInformation::Name(DWORD dwidPage) const {
  163. CString csTemp;
  164. csTemp.LoadString(dwidPage);
  165. csTemp.TrimLeft();
  166. csTemp.TrimRight();
  167. if (csTemp.IsEmpty())
  168. csTemp.Format(_TEXT("Code Page %d"), dwidPage);
  169. return csTemp;
  170. }
  171. /******************************************************************************
  172. CCodePageInformation::IsInstalled
  173. Rturns true if the font is either installed in the OS or one of our
  174. resources.
  175. ******************************************************************************/
  176. BOOL CCodePageInformation::IsInstalled(DWORD dwidPage) const {
  177. for (unsigned u = 0; u < MappedCount(); u++)
  178. if (Mapped(u) == dwidPage)
  179. return TRUE;
  180. for (u = 0; u < InstalledCount(); u++)
  181. if (Installed(u) == dwidPage)
  182. return TRUE;
  183. return FALSE;
  184. }
  185. /******************************************************************************
  186. CCodePageInformation::GenerateMap
  187. This private member generates a map representing the available one-to-one
  188. transformations in an installed code page, and writes it to a file using
  189. the code page id to form a unique name
  190. ******************************************************************************/
  191. BOOL CCodePageInformation::GenerateMap(DWORD dwidMap) const {
  192. // If we can't get Code Page info for it, vanish
  193. CPINFO cpi;
  194. if (!GetCPInfo(dwidMap, &cpi))
  195. return FALSE;
  196. CWordArray cwaMap;
  197. for (unsigned u = 0; u < 65536; u++) {
  198. unsigned uTo = 0;
  199. BOOL bInvalid;
  200. int icTo = WideCharToMultiByte(dwidMap, 0, (PWSTR) &u, 1, (PSTR) &uTo,
  201. sizeof u, NULL, &bInvalid);
  202. if (bInvalid)
  203. continue; // Character wasn't any good...
  204. _ASSERTE((unsigned) icTo <= cpi.MaxCharSize);
  205. // OK, we mapped one- but, before we go on, make sure it also works
  206. // in the other direction, since the U2M does some jiggering
  207. unsigned u3 = 0;
  208. MultiByteToWideChar(dwidMap, 0, (PSTR) &uTo, 2, (PWSTR) &u3, 2);
  209. if (u3 != u)
  210. continue; // Not a one-for one? Not interested...
  211. cwaMap.Add((WORD)uTo);
  212. cwaMap.Add((WORD)u);
  213. }
  214. // OK, we've got the down and dirty details- now, generate the file...
  215. try {
  216. CString csName;
  217. csName.Format(_TEXT("WPS%u.CTT"), dwidMap);
  218. CFile cfOut(csName,
  219. CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive);
  220. // Write the tranlated pairs
  221. cfOut.Write(cwaMap.GetData(), (unsigned)(cwaMap.GetSize() * sizeof(WORD)));
  222. }
  223. catch(CException *pce) {
  224. pce -> ReportError();
  225. pce -> Delete();
  226. return FALSE;
  227. }
  228. return TRUE;
  229. }
  230. /******************************************************************************
  231. CCodePageInformation::GenerateAllMaps
  232. This member will generate an MBCS -> Unicode one-to-one mapping table for all
  233. installed code pages in the user's system for which we do not now have maps.
  234. ******************************************************************************/
  235. BOOL CCodePageInformation::GenerateAllMaps() const {
  236. BOOL bReturn = TRUE;
  237. for (unsigned u = InstalledCount(); u--; )
  238. if (!HaveMap(Installed(u)) && !GenerateMap(Installed(u)))
  239. bReturn = FALSE;
  240. return bReturn;
  241. }
  242. /******************************************************************************
  243. CCodePageInformation::HaveMap
  244. Reports that the map is one of our resources (or isn't, as the case may be).
  245. ******************************************************************************/
  246. BOOL CCodePageInformation::HaveMap(DWORD dwidMap) const {
  247. return (dwidMap < 65536) ? !!FindResource(AfxGetResourceHandle(),
  248. MAKEINTRESOURCE((WORD) dwidMap), MAKEINTRESOURCE(MAPPING_TABLE)) :
  249. FALSE;
  250. }
  251. /******************************************************************************
  252. CCodePageInformation::IsDBCS(DWORD dwidPage)
  253. This is actually pretty simple- if the translation table is smaller than 1024
  254. bytes (256 encodings), it isn't DBCS.
  255. ******************************************************************************/
  256. BOOL CCodePageInformation::IsDBCS(DWORD dwidPage) {
  257. if (!Load(dwidPage))
  258. return FALSE; // May be optimistic, but we'll find out...
  259. return m_cbaMap.GetSize() > 1024;
  260. }
  261. /******************************************************************************
  262. CCodePageInformation::IsDBCS(DWORD dwidPage, WORD wCodePoint)
  263. If the page isn't DBCS, we're done. Otherwise, make sure the Unicode->MBCS
  264. map is loaded, and get the answer from there.
  265. ******************************************************************************/
  266. BOOL CCodePageInformation::IsDBCS(DWORD dwidPage, WORD wCodePoint) {
  267. if (!IsDBCS(dwidPage))
  268. return FALSE;
  269. if (!Map(TRUE))
  270. return FALSE; // Just say no, because the error's already been told
  271. // 0xFFFF is invalid, hence SBCS (default always must be)
  272. _ASSERTE(m_cwaOut[wCodePoint] != 0xFFFF);
  273. return ((WORD) (1 + m_cwaOut[wCodePoint])) > 0x100;
  274. }
  275. /******************************************************************************
  276. CCodePageInformation::Convert
  277. This is one of the workhorses- it loads the given code page, and maps the
  278. given character strings one way or the other, depending upon which is empty.
  279. ******************************************************************************/
  280. unsigned CCodePageInformation::Convert(CByteArray& cbaMBCS,
  281. CWordArray& cwaWC,
  282. DWORD dwidPage){
  283. if (!cbaMBCS.GetSize() == !cwaWC.GetSize()) // Must be clear which way
  284. return 0;
  285. if (!Load(dwidPage) || !Map((int)cwaWC.GetSize()))
  286. return 0;
  287. CWordArray& cwaMap = cwaWC.GetSize() ? m_cwaOut : m_cwaIn;
  288. try {
  289. if (cbaMBCS.GetSize()) {
  290. cwaWC.RemoveAll();
  291. for (int i = 0; i < cbaMBCS.GetSize();) {
  292. WORD wcThis = cbaMBCS[i];
  293. if (cwaMap[wcThis] == 0xFFFF) { // No SBCS mapping
  294. wcThis += cbaMBCS[i + 1] << 8;
  295. if (cwaMap[wcThis] == 0xFFFF) { // No DBCS, either?
  296. _ASSERTE(FALSE);
  297. return 0; // We have failed to convert!
  298. }
  299. }
  300. cwaWC.Add(cwaMap[wcThis]);
  301. i += 1 + (wcThis > 0xFF);
  302. }
  303. }
  304. else {
  305. cbaMBCS.RemoveAll();
  306. for (int i = 0; i < cwaWC.GetSize(); i++) {
  307. if (cwaMap[cwaWC[i]] == 0xFFFF) {
  308. _ASSERTE(0);
  309. return 0;
  310. }
  311. cbaMBCS.Add((BYTE) cwaMap[cwaWC[i]]);
  312. if (0xFF < cwaMap[cwaWC[i]])
  313. cbaMBCS.Add((BYTE)(cwaMap[cwaWC[i]] >> 8));
  314. }
  315. }
  316. }
  317. catch (CException * pce) {
  318. pce -> ReportError();
  319. pce -> Delete();
  320. return 0;
  321. }
  322. return (unsigned)cwaWC.GetSize(); // Correct conversion count either way!
  323. }
  324. /******************************************************************************
  325. CCodePageInformation::Collect
  326. This member fills a passed CWordArray with either the domain or range of the
  327. mapping function. In either case, the array is in ascending order.
  328. ******************************************************************************/
  329. BOOL CCodePageInformation::Collect(DWORD dwidPage, CWordArray& cwaCollect,
  330. BOOL bUnicode) {
  331. if (!Load(dwidPage) || !Map(bUnicode))
  332. return FALSE;
  333. CWordArray& cwaMap = bUnicode ? m_cwaOut : m_cwaIn;
  334. cwaCollect.RemoveAll();
  335. // Code points < 0x20 always map, but aren't usable, so screen them out
  336. try {
  337. for (unsigned u = 0x20; u < (unsigned) cwaMap.GetSize(); u++)
  338. if (~(int)(short)cwaMap[u]) // 0xFFFF means not mapped!
  339. cwaCollect.Add((WORD)u);
  340. }
  341. catch (CException * pce) {
  342. pce -> ReportError();
  343. pce -> Delete();
  344. return FALSE;
  345. }
  346. return TRUE;
  347. }