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.

629 lines
18 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1998.
  5. //
  6. // File: langres.cxx
  7. //
  8. // Contents: Interacts with the registry to obtain locale specific info.
  9. //
  10. // Classes: CLangRes class
  11. //
  12. // History: 2-14-97 mohamedn created
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.cxx>
  16. #pragma hdrstop
  17. #include <defbreak.hxx>
  18. #include <lang.hxx>
  19. #include <ciole.hxx>
  20. #include <ciregkey.hxx>
  21. #include <langres.hxx>
  22. #include "isreg.hxx"
  23. //+---------------------------------------------------------------------------
  24. //
  25. // Class: CLangReg
  26. //
  27. // Purpose: maintains lang. specific info for the passed in locale id.
  28. //
  29. // History: 29-Aug-94 SitaramR Created.
  30. // 17 Apr 98 mohamedn Switched from callback and doesn't
  31. // depend on InstalledLangs key.
  32. //
  33. //----------------------------------------------------------------------------
  34. class CLangReg
  35. {
  36. public:
  37. CLangReg( LCID locale );
  38. //
  39. // For matching locale or language
  40. //
  41. BOOL LocaleFound() const { return _fLocaleFound; }
  42. BOOL LangFound() const { return _fLangFound; }
  43. WCHAR *GetWBreakerClass() { return _wszWBreakerClass; }
  44. WCHAR *GetStemmerClass() { return _wszStemmerClass; }
  45. WCHAR *GetNoiseFile() { return _wszNoiseFile; }
  46. private:
  47. void EnumLangEntries(void);
  48. void GetLangInfo(DWORD dwLocale, CWin32RegAccess & langKey);
  49. BOOL FillLangInfo( CWin32RegAccess & regLang );
  50. BOOL PrimaryLangsMatch( LCID lcid1, LCID lcid2 )
  51. {
  52. //
  53. // Do the primary languages of the two lcids match ?
  54. //
  55. return( PRIMARYLANGID( LANGIDFROMLCID( lcid1 ) )
  56. == PRIMARYLANGID( LANGIDFROMLCID( lcid2 ) ) );
  57. }
  58. LCID _locale;
  59. BOOL _fLocaleFound; // exact match with locale found
  60. BOOL _fLangFound; // primary language match
  61. WCHAR _wszWBreakerClass[MAX_REG_STR_LEN];
  62. WCHAR _wszStemmerClass[MAX_REG_STR_LEN];
  63. WCHAR _wszNoiseFile[MAX_PATH];
  64. };
  65. //+-------------------------------------------------------------------------
  66. //
  67. // Method: CLangReg::CLangReg
  68. //
  69. // Arguments: [locale] -- current locale
  70. //
  71. // History: 29-Aug-94 SitaramR Created.
  72. //
  73. //--------------------------------------------------------------------------
  74. CLangReg::CLangReg( LCID locale )
  75. : _locale(locale),
  76. _fLocaleFound( FALSE ),
  77. _fLangFound( FALSE )
  78. {
  79. EnumLangEntries();
  80. }
  81. //+-------------------------------------------------------------------------
  82. //
  83. // Method: EnumLangEntries, private
  84. //
  85. // Synopsis: enumerates CI lang subkeys.
  86. //
  87. // Arguments: none.
  88. //
  89. // Returns: none. sets internal values.
  90. //
  91. // History: 4/17/98 mohamedn created
  92. //
  93. //--------------------------------------------------------------------------
  94. void CLangReg::EnumLangEntries(void)
  95. {
  96. CWin32RegAccess langKey ( HKEY_LOCAL_MACHINE, wcsRegAdminLanguage );
  97. WCHAR wcsSubKeyName[MAX_PATH+1];
  98. DWORD cwcName = sizeof wcsSubKeyName / sizeof WCHAR;
  99. while ( !_fLocaleFound && langKey.Enum( wcsSubKeyName, cwcName ) )
  100. {
  101. CWin32RegAccess langSubKey( langKey.GetHKey() , wcsSubKeyName );
  102. DWORD dwLocaleId = 0;
  103. if ( langSubKey.Get( L"Locale", dwLocaleId ) )
  104. {
  105. GetLangInfo( dwLocaleId, langSubKey );
  106. }
  107. }
  108. }
  109. //+-------------------------------------------------------------------------
  110. //
  111. // Method: GetLangInfo, private
  112. //
  113. // Synopsis: Gets language values from registry lang key.
  114. //
  115. // Arguments: [pwszLangKey] -- language key to retrieve values from.
  116. //
  117. // Returns: none. sets internal flags.
  118. //
  119. // History: 4/17/98 mohamedn created
  120. //
  121. //--------------------------------------------------------------------------
  122. void CLangReg::GetLangInfo(DWORD dwLocale, CWin32RegAccess & regLang)
  123. {
  124. if ( dwLocale == _locale )
  125. {
  126. _fLocaleFound = FillLangInfo( regLang );
  127. }
  128. else if ( !_fLangFound && PrimaryLangsMatch( dwLocale, _locale ) )
  129. {
  130. //
  131. // Approximate match with same primary language
  132. //
  133. _fLangFound = FillLangInfo( regLang );
  134. }
  135. }
  136. //+-------------------------------------------------------------------------
  137. //
  138. // Method: FillLangInfo, private
  139. //
  140. // Synopsis: fills internal members with lang values from lang. subkey
  141. //
  142. // Arguments: [regLang] -- reference to open lang key
  143. //
  144. // Returns: TRUE if succeeded, FALSE otherwise.
  145. //
  146. // History: 4/17/98 mohamedn created
  147. //
  148. //--------------------------------------------------------------------------
  149. BOOL CLangReg::FillLangInfo( CWin32RegAccess & regLang )
  150. {
  151. BOOL fRetVal1 = FALSE;
  152. BOOL fRetVal2 = FALSE;
  153. BOOL fRetVal3 = FALSE;
  154. fRetVal1 = regLang.Get( L"WBreakerClass", _wszWBreakerClass,
  155. sizeof (_wszWBreakerClass)/sizeof (_wszWBreakerClass[0]) );
  156. fRetVal2 = regLang.Get( L"StemmerClass", _wszStemmerClass,
  157. sizeof (_wszStemmerClass)/sizeof (_wszStemmerClass[0]) );
  158. fRetVal3 = regLang.Get( L"NoiseFile", _wszNoiseFile,
  159. sizeof (_wszNoiseFile)/sizeof (_wszNoiseFile[0]) );
  160. BOOL fRetVal = ( fRetVal1 || fRetVal2 || fRetVal3 );
  161. if ( ! fRetVal )
  162. {
  163. ciDebugOut(( DEB_ERROR, "CLangRes::FillLangInfo() Failed\n" ));
  164. }
  165. return fRetVal;
  166. }
  167. //+---------------------------------------------------------------------------
  168. //
  169. // Member: CLangRes::GetNoiseWordList
  170. //
  171. // Synopsis: provides an IStream interface to the noise word list given
  172. // a locale and pid
  173. //
  174. // arguments: [locale] [in] locale
  175. // [pid] [in] property id
  176. // [ppIStrmNoiseFile] [out]IStream interface to the noise word list.
  177. //
  178. // returns: S_OK noise file found
  179. // CI_E_NOT_FOUND no noise file found
  180. // CI_E_USE_DEFAULT_PID only default pid is supported
  181. //
  182. // History: 15-Aug-94 SitaramR Renamed GetLang to BorrowLang and
  183. // added code to look up registry.
  184. // 2-14-97 mohamedn used to be in CLangList::BorrorwLang
  185. //
  186. //----------------------------------------------------------------------------
  187. SCODE CLangRes::GetNoiseWordList( LCID locale,
  188. PROPID pid,
  189. IStream **ppIStrmNoiseFile)
  190. {
  191. //
  192. // we only support default pid, except for Filename
  193. //
  194. if ( pid != CI_DEFAULT_PID )
  195. {
  196. if ( pidName == pid || pidRevName == pid )
  197. {
  198. *ppIStrmNoiseFile = 0;
  199. return S_OK;
  200. }
  201. else
  202. return CI_E_USE_DEFAULT_PID;
  203. }
  204. //
  205. // default to no noise file found
  206. //
  207. LANGID langid = LANGIDFROMLCID(locale);
  208. SCODE sc = CI_E_NOT_FOUND;
  209. *ppIStrmNoiseFile = 0;
  210. //
  211. // Try to bind to language object by looking up registry
  212. //
  213. CLangReg langReg( langid );
  214. TRY
  215. {
  216. if ( langReg.LocaleFound() || langReg.LangFound() )
  217. {
  218. const WCHAR * pwszNoiseFile = langReg.GetNoiseFile();
  219. *ppIStrmNoiseFile = _GetIStrmNoiseFile( pwszNoiseFile );
  220. sc = S_OK;
  221. }
  222. }
  223. CATCH ( CException, e )
  224. {
  225. ciDebugOut (( DEB_ERROR,
  226. "Exception 0x%x caught: Failed to get IStrmNoiseFile for langId(0x%x)\n",
  227. e.GetErrorCode(), langid ));
  228. sc = e.GetErrorCode();
  229. }
  230. END_CATCH;
  231. return sc;
  232. }
  233. //+---------------------------------------------------------------------------
  234. //
  235. // Member: CLangRes::_GetIStrmNoiseFile, private static
  236. //
  237. // Synopsis: provides an IStream interface given noise file name
  238. //
  239. // Arguments: [pwszNoiseFile] -- [in] noise file name
  240. //
  241. // Returns: IStream* -- IStream interface to the noise file.
  242. // Throws value of GetLastError() upon failure.
  243. //
  244. // History: 2-14-97 mohamedn created
  245. //
  246. // Notes:
  247. //----------------------------------------------------------------------------
  248. IStream *CLangRes::_GetIStrmNoiseFile(const WCHAR *pwszNoiseFile )
  249. {
  250. SCODE sc = S_OK;
  251. IStream *pIStrmNoiseFile = 0;
  252. Win4Assert( pwszNoiseFile );
  253. WCHAR wszNoisePath[MAX_PATH];
  254. if ( (pwszNoiseFile[0] != L'\\' || pwszNoiseFile[1] != L'\\') &&
  255. (! *pwszNoiseFile || pwszNoiseFile[1] != L':' || pwszNoiseFile[2] != L'\\') )
  256. {
  257. //
  258. // Form full path of noise file
  259. //
  260. const ULONG cchBufSize = sizeof wszNoisePath/sizeof wszNoisePath[0];
  261. ULONG len = GetSystemDirectory( wszNoisePath, cchBufSize );
  262. if (len == 0 || len >= (cchBufSize-1))
  263. {
  264. sc = GetLastError();
  265. ciDebugOut (( DEB_ERROR,
  266. "CLangRes: GetSystemDirectory(%ws) failed: %x\n",
  267. wszNoisePath, sc ));
  268. THROW ( CException(sc) );
  269. }
  270. if ( wszNoisePath[len-1] != L'\\' )
  271. {
  272. wszNoisePath[len] = L'\\';
  273. len++;
  274. wszNoisePath[len] = L'\0';
  275. }
  276. if ( (len + wcslen( pwszNoiseFile ) + 1) >= cchBufSize )
  277. {
  278. ciDebugOut (( DEB_ERROR,
  279. "CLangRes: Noise word file path too long: %ws\n",
  280. pwszNoiseFile ));
  281. THROW ( CException( CI_E_BUFFERTOOSMALL ) );
  282. }
  283. }
  284. else
  285. {
  286. wszNoisePath[0] = L'\0';
  287. }
  288. wcscat( wszNoisePath, pwszNoiseFile );
  289. ciDebugOut(( DEB_ITRACE,
  290. "Obtaining IStrmNoiseFile to file = %ws\n", wszNoisePath ));
  291. //
  292. // open noise file, and obtain its IStream
  293. //
  294. HANDLE hFile = CreateFile( wszNoisePath,
  295. GENERIC_READ,
  296. FILE_SHARE_READ,
  297. 0,
  298. OPEN_EXISTING,
  299. 0,
  300. 0 );
  301. if ( INVALID_HANDLE_VALUE == hFile )
  302. {
  303. ciDebugOut (( DEB_ERROR, "CreateFile(%ws) failed: %x\n",
  304. wszNoisePath, sc = GetLastError() ));
  305. THROW ( CException(sc) );
  306. }
  307. SWin32Handle xhFile(hFile);
  308. ULONG cb = GetFileSize( hFile, NULL );
  309. if ( cb == 0xffffffff )
  310. {
  311. THROW( CException( sc = GetLastError() ) );
  312. }
  313. HGLOBAL hg = GlobalAlloc( GMEM_MOVEABLE | GMEM_NODISCARD, cb );
  314. if ( NULL == hg )
  315. {
  316. THROW( CException( sc = GetLastError() ) );
  317. }
  318. // store it in smart pointer to enable freeing in case of a THROW.
  319. // Upon success, it will be freed when pIStrmNoiseFile is freed.
  320. XGlobalAllocMem xGlobalMem(hg);
  321. void * pb = GlobalLock( hg );
  322. if ( NULL == pb )
  323. {
  324. THROW( CException( sc = GetLastError() ));
  325. }
  326. ULONG cbRead;
  327. BOOL fErr = ReadFile( hFile, pb, cb, &cbRead, 0 );
  328. if ( 0 == fErr )
  329. {
  330. THROW( CException( sc = GetLastError() ));
  331. }
  332. fErr = GlobalUnlock( hg );
  333. if ( 0 == fErr && GetLastError() != NO_ERROR )
  334. {
  335. THROW( CException( sc = GetLastError() ));
  336. }
  337. sc = CreateStreamOnHGlobal( hg, //Memory handle for the stream object
  338. TRUE, //Whether to free memory when the object is released
  339. &pIStrmNoiseFile ); //Indirect pointer to the new stream object
  340. if ( FAILED(sc) )
  341. {
  342. THROW( CException(sc) );
  343. }
  344. //
  345. // will be freed when pIStrmNoiseFile is released.
  346. //
  347. xGlobalMem.Acquire();
  348. return pIStrmNoiseFile;
  349. }
  350. //+---------------------------------------------------------------------------
  351. //
  352. // Member: CLangRes::GetWordBreaker
  353. //
  354. // Synopsis: provides an IWordBreaker interface after scanning the registry.
  355. //
  356. // arguments: [locale] [in] locale
  357. // [pid] [in] property id
  358. // [ppwbBreaker] [out]IWordBreaker interface
  359. //
  360. // returns: S_OK valid IWordBreaker is returned
  361. // CI_E_NOT_FOUND no IWordBreaker found - use default
  362. // CI_E_USE_DEFAULT_PID only default pid is supported
  363. //
  364. // History: 15-Aug-94 SitaramR Renamed GetLang to BorrowLang and
  365. // added code to look up registry.
  366. // 2-14-97 mohamedn Used to be in CLangList::BorrorwLang
  367. //
  368. //----------------------------------------------------------------------------
  369. SCODE CLangRes::GetWordBreaker( LCID locale,
  370. PROPID pid,
  371. IWordBreaker ** ppwbBreaker )
  372. {
  373. //
  374. // we only support default pid, except for Filename
  375. //
  376. if ( pid != CI_DEFAULT_PID )
  377. {
  378. if ( pidName == pid || pidRevName == pid )
  379. locale = LOCALE_NEUTRAL;
  380. else
  381. return CI_E_USE_DEFAULT_PID;
  382. }
  383. LANGID langid = LANGIDFROMLCID(locale);
  384. //
  385. // default to no word breaker found
  386. //
  387. XInterface<IWordBreaker> xWBreak;
  388. SCODE sc = CI_E_NOT_FOUND;
  389. //
  390. // Try to bind to language object by looking up registry
  391. //
  392. CLangReg langReg( langid );
  393. TRY
  394. {
  395. GUID guidClass;
  396. if ( ( langReg.LocaleFound() || langReg.LangFound() ) &&
  397. wcscmp( langReg.GetWBreakerClass(), L"" ) != 0 )
  398. {
  399. StringToCLSID( langReg.GetWBreakerClass(), guidClass );
  400. xWBreak.Set( CCiOle::NewWordBreaker( guidClass ) );
  401. if ( !xWBreak.IsNull() )
  402. sc = S_OK;
  403. }
  404. }
  405. CATCH ( CException, e )
  406. {
  407. ciDebugOut (( DEB_ERROR,
  408. "Exception 0x%x caught: no such language (0x%x) found in registry\n",
  409. e.GetErrorCode(), langid ));
  410. sc = e.GetErrorCode();
  411. }
  412. END_CATCH;
  413. //
  414. // set ppwbBreaker to what we found, or null if nothing is found
  415. //
  416. *ppwbBreaker = xWBreak.Acquire();
  417. return sc;
  418. }
  419. //+---------------------------------------------------------------------------
  420. //
  421. // Member: CLangRes::GetStemmer
  422. //
  423. // Synopsis: provides an IStemmer interface after scanning the registry.
  424. //
  425. // arguments: [locale] [in] locale
  426. // [pid] [in] property id
  427. // [ppStemmer] [out]IStemmer interface
  428. //
  429. // returns: S_OK valid IStemmer is returned
  430. // CI_E_NOT_FOUND no IStemmer found
  431. // CI_E_USE_DEFAULT_PID only default pid is supported
  432. //
  433. // History: 15-Aug-94 SitaramR Renamed GetLang to BorrowLang and
  434. // added code to look up registry.
  435. // 2-14-97 mohamedn Used to be in CLangList::BorrorwLang
  436. //
  437. //----------------------------------------------------------------------------
  438. SCODE CLangRes::GetStemmer( LCID locale,
  439. PROPID pid,
  440. IStemmer ** ppStemmer )
  441. {
  442. GUID guidClass;
  443. LANGID langid = LANGIDFROMLCID(locale);
  444. //
  445. // we only support default pid, except for Filename
  446. //
  447. if ( pid != CI_DEFAULT_PID )
  448. {
  449. if ( pidName == pid || pidRevName == pid )
  450. {
  451. *ppStemmer = 0;
  452. return S_OK;
  453. }
  454. else
  455. return CI_E_USE_DEFAULT_PID;
  456. }
  457. //
  458. // default to no stemmer
  459. //
  460. XInterface<IStemmer> _xStemmer;
  461. SCODE sc = CI_E_NOT_FOUND;
  462. //
  463. // Try to bind to language object by looking up registry
  464. //
  465. CLangReg langReg( langid );
  466. TRY
  467. {
  468. if ( langReg.LocaleFound() || langReg.LangFound() )
  469. {
  470. // Is a stemmer available for given langid ?
  471. if ( wcscmp( langReg.GetStemmerClass(), L"" ) != 0 )
  472. {
  473. StringToCLSID( langReg.GetStemmerClass(), guidClass );
  474. _xStemmer.Set( CCiOle::NewStemmer( guidClass ) );
  475. sc = S_OK;
  476. }
  477. }
  478. }
  479. CATCH ( CException, e )
  480. {
  481. ciDebugOut (( DEB_ERROR,
  482. "Exception 0x%x caught: no such language (0x%x) found in registry\n",
  483. e.GetErrorCode(), langid ));
  484. sc = e.GetErrorCode();
  485. }
  486. END_CATCH;
  487. //
  488. // set ppStemmer to what we found, or null if nothing is found
  489. //
  490. *ppStemmer = _xStemmer.Acquire();
  491. return sc;
  492. }
  493. //+-------------------------------------------------------------------------
  494. //
  495. // Method: CLangList::StringToCLSID
  496. //
  497. // Synopsis: Convert string containing CLSID to CLSID
  498. //
  499. // Arguments: [wszClass] -- string containg CLSID
  500. // [guidClass] -- output guid
  501. //
  502. // History: 15-Aug-94 SitaramR Created.
  503. // Algorithm copied from shtole.cxx
  504. //
  505. //--------------------------------------------------------------------------
  506. void CLangRes::StringToCLSID( WCHAR *wszClass, GUID& guidClass )
  507. {
  508. wszClass[9] = 0;
  509. guidClass.Data1 = wcstoul( &wszClass[1], 0, 16 );
  510. wszClass[14] = 0;
  511. guidClass.Data2 = (USHORT)wcstoul( &wszClass[10], 0, 16 );
  512. wszClass[19] = 0;
  513. guidClass.Data3 = (USHORT)wcstoul( &wszClass[15], 0, 16 );
  514. WCHAR wc = wszClass[22];
  515. wszClass[22] = 0;
  516. guidClass.Data4[0] = (unsigned char)wcstoul( &wszClass[20], 0, 16 );
  517. wszClass[22] = wc;
  518. wszClass[24] = 0;
  519. guidClass.Data4[1] = (unsigned char)wcstoul( &wszClass[22], 0, 16 );
  520. for ( int i = 0; i < 6; i++ )
  521. {
  522. wc = wszClass[27+i*2];
  523. wszClass[27+i*2] = 0;
  524. guidClass.Data4[2+i] = (unsigned char)wcstoul( &wszClass[25+i*2], 0, 16 );
  525. wszClass[27+i*2] = wc;
  526. }
  527. }