//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1998. // // File: langres.cxx // // Contents: Interacts with the registry to obtain locale specific info. // // Classes: CLangRes class // // History: 2-14-97 mohamedn created // //---------------------------------------------------------------------------- #include #pragma hdrstop #include #include #include #include #include #include "isreg.hxx" //+--------------------------------------------------------------------------- // // Class: CLangReg // // Purpose: maintains lang. specific info for the passed in locale id. // // History: 29-Aug-94 SitaramR Created. // 17 Apr 98 mohamedn Switched from callback and doesn't // depend on InstalledLangs key. // //---------------------------------------------------------------------------- class CLangReg { public: CLangReg( LCID locale ); // // For matching locale or language // BOOL LocaleFound() const { return _fLocaleFound; } BOOL LangFound() const { return _fLangFound; } WCHAR *GetWBreakerClass() { return _wszWBreakerClass; } WCHAR *GetStemmerClass() { return _wszStemmerClass; } WCHAR *GetNoiseFile() { return _wszNoiseFile; } private: void EnumLangEntries(void); void GetLangInfo(DWORD dwLocale, CWin32RegAccess & langKey); BOOL FillLangInfo( CWin32RegAccess & regLang ); BOOL PrimaryLangsMatch( LCID lcid1, LCID lcid2 ) { // // Do the primary languages of the two lcids match ? // return( PRIMARYLANGID( LANGIDFROMLCID( lcid1 ) ) == PRIMARYLANGID( LANGIDFROMLCID( lcid2 ) ) ); } LCID _locale; BOOL _fLocaleFound; // exact match with locale found BOOL _fLangFound; // primary language match WCHAR _wszWBreakerClass[MAX_REG_STR_LEN]; WCHAR _wszStemmerClass[MAX_REG_STR_LEN]; WCHAR _wszNoiseFile[MAX_PATH]; }; //+------------------------------------------------------------------------- // // Method: CLangReg::CLangReg // // Arguments: [locale] -- current locale // // History: 29-Aug-94 SitaramR Created. // //-------------------------------------------------------------------------- CLangReg::CLangReg( LCID locale ) : _locale(locale), _fLocaleFound( FALSE ), _fLangFound( FALSE ) { EnumLangEntries(); } //+------------------------------------------------------------------------- // // Method: EnumLangEntries, private // // Synopsis: enumerates CI lang subkeys. // // Arguments: none. // // Returns: none. sets internal values. // // History: 4/17/98 mohamedn created // //-------------------------------------------------------------------------- void CLangReg::EnumLangEntries(void) { CWin32RegAccess langKey ( HKEY_LOCAL_MACHINE, wcsRegAdminLanguage ); WCHAR wcsSubKeyName[MAX_PATH+1]; DWORD cwcName = sizeof wcsSubKeyName / sizeof WCHAR; while ( !_fLocaleFound && langKey.Enum( wcsSubKeyName, cwcName ) ) { CWin32RegAccess langSubKey( langKey.GetHKey() , wcsSubKeyName ); DWORD dwLocaleId = 0; if ( langSubKey.Get( L"Locale", dwLocaleId ) ) { GetLangInfo( dwLocaleId, langSubKey ); } } } //+------------------------------------------------------------------------- // // Method: GetLangInfo, private // // Synopsis: Gets language values from registry lang key. // // Arguments: [pwszLangKey] -- language key to retrieve values from. // // Returns: none. sets internal flags. // // History: 4/17/98 mohamedn created // //-------------------------------------------------------------------------- void CLangReg::GetLangInfo(DWORD dwLocale, CWin32RegAccess & regLang) { if ( dwLocale == _locale ) { _fLocaleFound = FillLangInfo( regLang ); } else if ( !_fLangFound && PrimaryLangsMatch( dwLocale, _locale ) ) { // // Approximate match with same primary language // _fLangFound = FillLangInfo( regLang ); } } //+------------------------------------------------------------------------- // // Method: FillLangInfo, private // // Synopsis: fills internal members with lang values from lang. subkey // // Arguments: [regLang] -- reference to open lang key // // Returns: TRUE if succeeded, FALSE otherwise. // // History: 4/17/98 mohamedn created // //-------------------------------------------------------------------------- BOOL CLangReg::FillLangInfo( CWin32RegAccess & regLang ) { BOOL fRetVal1 = FALSE; BOOL fRetVal2 = FALSE; BOOL fRetVal3 = FALSE; fRetVal1 = regLang.Get( L"WBreakerClass", _wszWBreakerClass, sizeof (_wszWBreakerClass)/sizeof (_wszWBreakerClass[0]) ); fRetVal2 = regLang.Get( L"StemmerClass", _wszStemmerClass, sizeof (_wszStemmerClass)/sizeof (_wszStemmerClass[0]) ); fRetVal3 = regLang.Get( L"NoiseFile", _wszNoiseFile, sizeof (_wszNoiseFile)/sizeof (_wszNoiseFile[0]) ); BOOL fRetVal = ( fRetVal1 || fRetVal2 || fRetVal3 ); if ( ! fRetVal ) { ciDebugOut(( DEB_ERROR, "CLangRes::FillLangInfo() Failed\n" )); } return fRetVal; } //+--------------------------------------------------------------------------- // // Member: CLangRes::GetNoiseWordList // // Synopsis: provides an IStream interface to the noise word list given // a locale and pid // // arguments: [locale] [in] locale // [pid] [in] property id // [ppIStrmNoiseFile] [out]IStream interface to the noise word list. // // returns: S_OK noise file found // CI_E_NOT_FOUND no noise file found // CI_E_USE_DEFAULT_PID only default pid is supported // // History: 15-Aug-94 SitaramR Renamed GetLang to BorrowLang and // added code to look up registry. // 2-14-97 mohamedn used to be in CLangList::BorrorwLang // //---------------------------------------------------------------------------- SCODE CLangRes::GetNoiseWordList( LCID locale, PROPID pid, IStream **ppIStrmNoiseFile) { // // we only support default pid, except for Filename // if ( pid != CI_DEFAULT_PID ) { if ( pidName == pid || pidRevName == pid ) { *ppIStrmNoiseFile = 0; return S_OK; } else return CI_E_USE_DEFAULT_PID; } // // default to no noise file found // LANGID langid = LANGIDFROMLCID(locale); SCODE sc = CI_E_NOT_FOUND; *ppIStrmNoiseFile = 0; // // Try to bind to language object by looking up registry // CLangReg langReg( langid ); TRY { if ( langReg.LocaleFound() || langReg.LangFound() ) { const WCHAR * pwszNoiseFile = langReg.GetNoiseFile(); *ppIStrmNoiseFile = _GetIStrmNoiseFile( pwszNoiseFile ); sc = S_OK; } } CATCH ( CException, e ) { ciDebugOut (( DEB_ERROR, "Exception 0x%x caught: Failed to get IStrmNoiseFile for langId(0x%x)\n", e.GetErrorCode(), langid )); sc = e.GetErrorCode(); } END_CATCH; return sc; } //+--------------------------------------------------------------------------- // // Member: CLangRes::_GetIStrmNoiseFile, private static // // Synopsis: provides an IStream interface given noise file name // // Arguments: [pwszNoiseFile] -- [in] noise file name // // Returns: IStream* -- IStream interface to the noise file. // Throws value of GetLastError() upon failure. // // History: 2-14-97 mohamedn created // // Notes: //---------------------------------------------------------------------------- IStream *CLangRes::_GetIStrmNoiseFile(const WCHAR *pwszNoiseFile ) { SCODE sc = S_OK; IStream *pIStrmNoiseFile = 0; Win4Assert( pwszNoiseFile ); WCHAR wszNoisePath[MAX_PATH]; if ( (pwszNoiseFile[0] != L'\\' || pwszNoiseFile[1] != L'\\') && (! *pwszNoiseFile || pwszNoiseFile[1] != L':' || pwszNoiseFile[2] != L'\\') ) { // // Form full path of noise file // const ULONG cchBufSize = sizeof wszNoisePath/sizeof wszNoisePath[0]; ULONG len = GetSystemDirectory( wszNoisePath, cchBufSize ); if (len == 0 || len >= (cchBufSize-1)) { sc = GetLastError(); ciDebugOut (( DEB_ERROR, "CLangRes: GetSystemDirectory(%ws) failed: %x\n", wszNoisePath, sc )); THROW ( CException(sc) ); } if ( wszNoisePath[len-1] != L'\\' ) { wszNoisePath[len] = L'\\'; len++; wszNoisePath[len] = L'\0'; } if ( (len + wcslen( pwszNoiseFile ) + 1) >= cchBufSize ) { ciDebugOut (( DEB_ERROR, "CLangRes: Noise word file path too long: %ws\n", pwszNoiseFile )); THROW ( CException( CI_E_BUFFERTOOSMALL ) ); } } else { wszNoisePath[0] = L'\0'; } wcscat( wszNoisePath, pwszNoiseFile ); ciDebugOut(( DEB_ITRACE, "Obtaining IStrmNoiseFile to file = %ws\n", wszNoisePath )); // // open noise file, and obtain its IStream // HANDLE hFile = CreateFile( wszNoisePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0 ); if ( INVALID_HANDLE_VALUE == hFile ) { ciDebugOut (( DEB_ERROR, "CreateFile(%ws) failed: %x\n", wszNoisePath, sc = GetLastError() )); THROW ( CException(sc) ); } SWin32Handle xhFile(hFile); ULONG cb = GetFileSize( hFile, NULL ); if ( cb == 0xffffffff ) { THROW( CException( sc = GetLastError() ) ); } HGLOBAL hg = GlobalAlloc( GMEM_MOVEABLE | GMEM_NODISCARD, cb ); if ( NULL == hg ) { THROW( CException( sc = GetLastError() ) ); } // store it in smart pointer to enable freeing in case of a THROW. // Upon success, it will be freed when pIStrmNoiseFile is freed. XGlobalAllocMem xGlobalMem(hg); void * pb = GlobalLock( hg ); if ( NULL == pb ) { THROW( CException( sc = GetLastError() )); } ULONG cbRead; BOOL fErr = ReadFile( hFile, pb, cb, &cbRead, 0 ); if ( 0 == fErr ) { THROW( CException( sc = GetLastError() )); } fErr = GlobalUnlock( hg ); if ( 0 == fErr && GetLastError() != NO_ERROR ) { THROW( CException( sc = GetLastError() )); } sc = CreateStreamOnHGlobal( hg, //Memory handle for the stream object TRUE, //Whether to free memory when the object is released &pIStrmNoiseFile ); //Indirect pointer to the new stream object if ( FAILED(sc) ) { THROW( CException(sc) ); } // // will be freed when pIStrmNoiseFile is released. // xGlobalMem.Acquire(); return pIStrmNoiseFile; } //+--------------------------------------------------------------------------- // // Member: CLangRes::GetWordBreaker // // Synopsis: provides an IWordBreaker interface after scanning the registry. // // arguments: [locale] [in] locale // [pid] [in] property id // [ppwbBreaker] [out]IWordBreaker interface // // returns: S_OK valid IWordBreaker is returned // CI_E_NOT_FOUND no IWordBreaker found - use default // CI_E_USE_DEFAULT_PID only default pid is supported // // History: 15-Aug-94 SitaramR Renamed GetLang to BorrowLang and // added code to look up registry. // 2-14-97 mohamedn Used to be in CLangList::BorrorwLang // //---------------------------------------------------------------------------- SCODE CLangRes::GetWordBreaker( LCID locale, PROPID pid, IWordBreaker ** ppwbBreaker ) { // // we only support default pid, except for Filename // if ( pid != CI_DEFAULT_PID ) { if ( pidName == pid || pidRevName == pid ) locale = LOCALE_NEUTRAL; else return CI_E_USE_DEFAULT_PID; } LANGID langid = LANGIDFROMLCID(locale); // // default to no word breaker found // XInterface xWBreak; SCODE sc = CI_E_NOT_FOUND; // // Try to bind to language object by looking up registry // CLangReg langReg( langid ); TRY { GUID guidClass; if ( ( langReg.LocaleFound() || langReg.LangFound() ) && wcscmp( langReg.GetWBreakerClass(), L"" ) != 0 ) { StringToCLSID( langReg.GetWBreakerClass(), guidClass ); xWBreak.Set( CCiOle::NewWordBreaker( guidClass ) ); if ( !xWBreak.IsNull() ) sc = S_OK; } } CATCH ( CException, e ) { ciDebugOut (( DEB_ERROR, "Exception 0x%x caught: no such language (0x%x) found in registry\n", e.GetErrorCode(), langid )); sc = e.GetErrorCode(); } END_CATCH; // // set ppwbBreaker to what we found, or null if nothing is found // *ppwbBreaker = xWBreak.Acquire(); return sc; } //+--------------------------------------------------------------------------- // // Member: CLangRes::GetStemmer // // Synopsis: provides an IStemmer interface after scanning the registry. // // arguments: [locale] [in] locale // [pid] [in] property id // [ppStemmer] [out]IStemmer interface // // returns: S_OK valid IStemmer is returned // CI_E_NOT_FOUND no IStemmer found // CI_E_USE_DEFAULT_PID only default pid is supported // // History: 15-Aug-94 SitaramR Renamed GetLang to BorrowLang and // added code to look up registry. // 2-14-97 mohamedn Used to be in CLangList::BorrorwLang // //---------------------------------------------------------------------------- SCODE CLangRes::GetStemmer( LCID locale, PROPID pid, IStemmer ** ppStemmer ) { GUID guidClass; LANGID langid = LANGIDFROMLCID(locale); // // we only support default pid, except for Filename // if ( pid != CI_DEFAULT_PID ) { if ( pidName == pid || pidRevName == pid ) { *ppStemmer = 0; return S_OK; } else return CI_E_USE_DEFAULT_PID; } // // default to no stemmer // XInterface _xStemmer; SCODE sc = CI_E_NOT_FOUND; // // Try to bind to language object by looking up registry // CLangReg langReg( langid ); TRY { if ( langReg.LocaleFound() || langReg.LangFound() ) { // Is a stemmer available for given langid ? if ( wcscmp( langReg.GetStemmerClass(), L"" ) != 0 ) { StringToCLSID( langReg.GetStemmerClass(), guidClass ); _xStemmer.Set( CCiOle::NewStemmer( guidClass ) ); sc = S_OK; } } } CATCH ( CException, e ) { ciDebugOut (( DEB_ERROR, "Exception 0x%x caught: no such language (0x%x) found in registry\n", e.GetErrorCode(), langid )); sc = e.GetErrorCode(); } END_CATCH; // // set ppStemmer to what we found, or null if nothing is found // *ppStemmer = _xStemmer.Acquire(); return sc; } //+------------------------------------------------------------------------- // // Method: CLangList::StringToCLSID // // Synopsis: Convert string containing CLSID to CLSID // // Arguments: [wszClass] -- string containg CLSID // [guidClass] -- output guid // // History: 15-Aug-94 SitaramR Created. // Algorithm copied from shtole.cxx // //-------------------------------------------------------------------------- void CLangRes::StringToCLSID( WCHAR *wszClass, GUID& guidClass ) { wszClass[9] = 0; guidClass.Data1 = wcstoul( &wszClass[1], 0, 16 ); wszClass[14] = 0; guidClass.Data2 = (USHORT)wcstoul( &wszClass[10], 0, 16 ); wszClass[19] = 0; guidClass.Data3 = (USHORT)wcstoul( &wszClass[15], 0, 16 ); WCHAR wc = wszClass[22]; wszClass[22] = 0; guidClass.Data4[0] = (unsigned char)wcstoul( &wszClass[20], 0, 16 ); wszClass[22] = wc; wszClass[24] = 0; guidClass.Data4[1] = (unsigned char)wcstoul( &wszClass[22], 0, 16 ); for ( int i = 0; i < 6; i++ ) { wc = wszClass[27+i*2]; wszClass[27+i*2] = 0; guidClass.Data4[2+i] = (unsigned char)wcstoul( &wszClass[25+i*2], 0, 16 ); wszClass[27+i*2] = wc; } }