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.

242 lines
6.5 KiB

  1. // ========================================================================
  2. //
  3. // LANGID.CPP
  4. //
  5. // DAV language id cache
  6. // Maps between MIME language identifiers and Win32 LCIDs.
  7. //
  8. // Copyright 1997-1998 Microsoft Corporation, All Rights Reserved
  9. //
  10. // ========================================================================
  11. // Disable unnecessary (i.e. harmless) warnings
  12. //
  13. #pragma warning(disable:4127) // conditional expression is constant
  14. #pragma warning(disable:4710) // (inline) function not expanded
  15. // Standard C/C++ headers
  16. //
  17. #include <malloc.h> // For _alloca declaration ONLY!
  18. // Windows headers
  19. //
  20. #include <windows.h>
  21. // CAL headers
  22. //
  23. #include <caldbg.h>
  24. #include <calrc.h>
  25. #include <crc.h>
  26. #include <ex\autoptr.h>
  27. #include <ex\buffer.h>
  28. #include <langid.h>
  29. static LONG
  30. LHexFromSz (LPCSTR psz)
  31. {
  32. LONG lVal = 0;
  33. Assert (psz);
  34. Assert (*psz);
  35. do
  36. {
  37. lVal = lVal << 4;
  38. if (('0' <= *psz) && ('9' >= *psz))
  39. lVal += *psz - '0';
  40. else if (('A' <= *psz) && ('F' >= *psz))
  41. lVal += *psz - L'A' + 10;
  42. else if (('a' <= *psz) && ('f' >= *psz))
  43. lVal += *psz - 'a' + 10;
  44. else
  45. return 0;
  46. } while (*++psz);
  47. return lVal;
  48. }
  49. // LcidFind() - lookup language ID from the locale.
  50. //
  51. LONG
  52. CLangIDCache::LcidFind (LPCSTR pszLangID)
  53. {
  54. LONG * plid;
  55. plid = Instance().m_cache.Lookup (CRCSzi(pszLangID));
  56. return plid ? *plid : 0;
  57. }
  58. BOOL FNullTerminated (LPCSTR psz, DWORD cch)
  59. {
  60. for (DWORD ich = 0; ich < cch; ich++)
  61. if (0 == psz[ich])
  62. break;
  63. return (ich < cch);
  64. }
  65. // FFillCacheData() for filling the cache with data
  66. //
  67. BOOL
  68. CLangIDCache::FFillCacheData()
  69. {
  70. BOOL fSuccess = FALSE;
  71. HKEY hkey = 0;
  72. CStackBuffer<CHAR,256> rgchKey;
  73. CStackBuffer<CHAR,256> rgchValue;
  74. LONG lRet;
  75. DWORD dwIndex = 0;
  76. // Querying registry for buffer sizes
  77. //
  78. DWORD cchMaxKeyLen; // longest value name length (in characters without zero termination)
  79. DWORD cbMaxKeyLen; // longest value name length (in bytes, including zero termination)
  80. DWORD cbMaxValueLen; // longest value data length (in bytes, including zero termination)
  81. // Load all thet lang ID's that come from the registry
  82. //
  83. lRet = RegOpenKeyExA (HKEY_CLASSES_ROOT,
  84. "MIME\\DATABASE\\RFC1766",
  85. 0,
  86. KEY_READ,
  87. &hkey);
  88. if (ERROR_SUCCESS != lRet)
  89. {
  90. DebugTrace("LANGID: Failed to get MIME\\DATABASE\\RFC1766 registry key handle, error code 0x%08X.\n", lRet);
  91. goto ret;
  92. }
  93. // Query for the length of the longest value name and for the length of the longest data piece under the key we have got.
  94. // That will give us enough information about what size buffers we need for querying.
  95. //
  96. lRet = RegQueryInfoKeyA(hkey,
  97. NULL,
  98. NULL,
  99. NULL,
  100. NULL,
  101. NULL,
  102. NULL,
  103. NULL,
  104. &cchMaxKeyLen, // Value names come back in number of characters
  105. &cbMaxValueLen, // Data length comes back in number of bytes
  106. NULL,
  107. NULL);
  108. if (ERROR_SUCCESS != lRet)
  109. {
  110. DebugTrace("LANGID: Failed to get registry key MIME\\DATABASE\\RFC1766 max data length buffer sizes, error code 0x%08X.\n", lRet);
  111. goto ret;
  112. }
  113. // Calculate maximum number of bytes needed for the value name
  114. //
  115. cbMaxKeyLen = (cchMaxKeyLen + 1) * sizeof(CHAR);
  116. // Allocate the query buffers on the stack
  117. //
  118. if ((NULL == rgchKey.resize(cbMaxKeyLen)) ||
  119. (NULL == rgchValue.resize(cbMaxValueLen)))
  120. goto ret;
  121. do
  122. {
  123. DWORD cbKey = cbMaxKeyLen;
  124. DWORD cbValue = cbMaxValueLen;
  125. DWORD dwType;
  126. LPSTR pch;
  127. LONG lLangId;
  128. lRet = RegEnumValueA(hkey,
  129. dwIndex++,
  130. rgchKey.get(),
  131. &cbKey,
  132. NULL,
  133. &dwType,
  134. reinterpret_cast<LPBYTE>(rgchValue.get()),
  135. &cbValue);
  136. if (ERROR_NO_MORE_ITEMS == lRet)
  137. break;
  138. // Encountering unknown error code is a failure
  139. //
  140. if (ERROR_SUCCESS != lRet)
  141. {
  142. DebugTrace("LANGID: Failed to query registry key MIME\\DATABASE\\RFC1766 data with error code 0x%08X.\n", lRet);
  143. goto ret;
  144. }
  145. // Skip unacceptable types.
  146. //
  147. if (REG_SZ != dwType)
  148. continue;
  149. // Skip non-NULL terminated strings
  150. if (!FNullTerminated (rgchValue.get(), cbValue))
  151. continue;
  152. // Find the semi-colon that separates the ID from the name
  153. // and terminate the ID.
  154. //
  155. pch = strchr (rgchValue.get(), ';');
  156. if (pch != NULL)
  157. *pch++ = '\0';
  158. // Persist the name and add the key to the cache
  159. //
  160. #ifdef DBG
  161. if (NULL != Instance().m_cache.Lookup (CRCSzi(rgchValue.get())))
  162. DebugTrace ("Dav: language identifier repeated (%hs)\n", rgchValue.get());
  163. #endif // DBG
  164. // If making the copy of the string failed... Well we can live with it.
  165. //
  166. pch = Instance().m_sb.Append (
  167. static_cast<UINT>((strlen (rgchValue.get()) + 1) * sizeof(CHAR)),
  168. rgchValue.get());
  169. if (!pch)
  170. continue; // Skip addition to the cache if allocation failed so we do not crash in CRCSzi(pch).
  171. // If we did not succeeded adding to the cache... Well we can live with it too.
  172. //
  173. lLangId = LHexFromSz(rgchKey.get());
  174. if (0 != lLangId)
  175. {
  176. (void)Instance().m_cache.FSet (CRCSzi(pch), lLangId);
  177. }
  178. } while (TRUE);
  179. // Set in one ISO language code which W2K forgot in RTM bits (2195)
  180. //
  181. (void)Instance().m_cache.FSet ("fr-mc", MAKELANGID (LANG_FRENCH,SUBLANG_FRENCH_MONACO));
  182. // Set in some additional ISO language codes supported by Navigator,
  183. // but not present in the Windows registry.
  184. //
  185. (void)Instance().m_cache.FSet ("fr-fr", MAKELANGID (LANG_FRENCH,SUBLANG_FRENCH));
  186. (void)Instance().m_cache.FSet ("de-de", MAKELANGID (LANG_GERMAN,SUBLANG_GERMAN));
  187. (void)Instance().m_cache.FSet ("es-es", MAKELANGID (LANG_SPANISH,SUBLANG_SPANISH));
  188. // Set in some of the known three-char language identifiers.
  189. // We can live without them if addition to the cache failed.
  190. //
  191. (void)Instance().m_cache.FSet ("eng", MAKELANGID (LANG_ENGLISH,SUBLANG_ENGLISH_US));
  192. (void)Instance().m_cache.FSet ("fra", MAKELANGID (LANG_FRENCH,SUBLANG_FRENCH));
  193. (void)Instance().m_cache.FSet ("fre", MAKELANGID (LANG_FRENCH,SUBLANG_FRENCH));
  194. (void)Instance().m_cache.FSet ("deu", MAKELANGID (LANG_GERMAN,SUBLANG_GERMAN));
  195. (void)Instance().m_cache.FSet ("ger", MAKELANGID (LANG_GERMAN,SUBLANG_GERMAN));
  196. (void)Instance().m_cache.FSet ("esl", MAKELANGID (LANG_SPANISH,SUBLANG_SPANISH_MODERN));
  197. (void)Instance().m_cache.FSet ("spa", MAKELANGID (LANG_SPANISH,SUBLANG_SPANISH_MODERN));
  198. fSuccess = TRUE;
  199. ret:
  200. if (hkey)
  201. {
  202. RegCloseKey (hkey);
  203. }
  204. return fSuccess;
  205. }