990 lines
30 KiB
C++
990 lines
30 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1991 - 2000.
|
|
//
|
|
// File: LANG.CXX
|
|
//
|
|
// Contents: Language Support
|
|
//
|
|
// Classes: CLanguage
|
|
// CLangList
|
|
//
|
|
// History: 02-May-91 BartoszM Created
|
|
//
|
|
// Notes: The filtering pipeline is hidden in the Data Repository
|
|
// object which serves as a sink for the filter.
|
|
// The sink for the Data Repository is the Key Repository.
|
|
// The language dependent part of the pipeline
|
|
// is obtained from the Language List object and is called
|
|
// Key Maker. It consists of:
|
|
//
|
|
// Word Breaker
|
|
// Stemmer (optional)
|
|
// Normalizer
|
|
// Noise List
|
|
//
|
|
// Each object serves as a sink for its predecessor,
|
|
// Key Repository is the final sink.
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <pch.cxx>
|
|
#pragma hdrstop
|
|
|
|
#include <tfilt.hxx>
|
|
#include <tsource.hxx>
|
|
#include <defbreak.hxx>
|
|
#include <lang.hxx>
|
|
#include <keymak.hxx>
|
|
#include <norm.hxx>
|
|
#include <noise.hxx>
|
|
#include <ciregkey.hxx>
|
|
|
|
#define DEB_LLIST DEB_USER10
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CLangList::CLangList, public
|
|
//
|
|
// Synopsis: Create all languages.
|
|
//
|
|
// Arguments: [pICiCLangRes] -- Client-provided language creator
|
|
// [ulMaxIdle] -- Max time (in seconds) before idle language
|
|
// object is elegible for deletion.
|
|
//
|
|
// History: 02-May-91 BartoszM Created
|
|
// 14-Jul-94 SitaramR Moved constructor here from lang.hxx
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
CLangList::CLangList( ICiCLangRes * pICiCLangRes,
|
|
ULONG ulMaxIdle )
|
|
: _xICiCLangRes(pICiCLangRes),
|
|
_ulMaxIdle( ulMaxIdle * 1000 )
|
|
{
|
|
_xICiCLangRes->AddRef();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CLangList::~CLangList, public
|
|
//
|
|
// Synopsis: Delete all languages.
|
|
//
|
|
// History: 27-Apr-1994 KyleP Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
CLangList::~CLangList()
|
|
{
|
|
Shutdown();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CLangList::Shutdown, public
|
|
//
|
|
// Synopsis: Delete all languages.
|
|
//
|
|
// History: 2-July-1996 dlee Moved from the destructor
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
void CLangList::Shutdown()
|
|
{
|
|
for ( CLanguage *pLang = _langsAvailable.Pop();
|
|
0 != pLang;
|
|
pLang = _langsAvailable.Pop() )
|
|
{
|
|
delete pLang;
|
|
}
|
|
} //Shutdown
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CLangList::Supports, public
|
|
//
|
|
// Synopsis: Determines if language object is suitable for lcid/pid
|
|
//
|
|
// Arguments: [pLang] -- Language object
|
|
// [pid] -- PROPID to-be-used by [pLang]
|
|
// [lcid] -- Locale to-be-used by [pLang]
|
|
//
|
|
// Returns: TRUE is [pLang] can be used to break/stem/etc. the
|
|
// locale/property specified by [lcid]/[pid]
|
|
//
|
|
// History: 05-Jan-1998 KyleP Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL CLangList::Supports( CLanguage const * pLang, PROPID pid, LCID lcid )
|
|
{
|
|
ciDebugOut(( DEB_LLIST, "Supports, lcid %#x, pid %#x\n", lcid, pid ));
|
|
|
|
LANGID langId = LANGIDFROMLCID(lcid);
|
|
|
|
//
|
|
// Easy case: Different language.
|
|
//
|
|
|
|
if ( !pLang->IsLocale( langId ) )
|
|
{
|
|
ciDebugOut(( DEB_LLIST, " supports: lcid doesn't match\n" ));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Easy case: Everything matches.
|
|
//
|
|
|
|
if ( pLang->IsPid( pid ) )
|
|
return TRUE;
|
|
|
|
CLangPidStateInfo stateInfo;
|
|
|
|
if ( pLang->IsPid( CI_DEFAULT_PID ) )
|
|
{
|
|
//
|
|
// Hard case: Mismatch, but possible default match to previously
|
|
// seen pid.
|
|
//
|
|
|
|
if ( _pidHash.LokLookupOrAddLang( langId, stateInfo ) &&
|
|
_pidHash.LokIsUseDefaultPid( pid, stateInfo.GetLangIndex() ) )
|
|
{
|
|
ciDebugOut(( DEB_LLIST, "CLangList::Supports -- Pid 0x%x can use current [default] language object\n", pid ));
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Hardest case: Mismatch, but possible default match to brand
|
|
// new pid.
|
|
//
|
|
|
|
CLanguage * pNewLang = FindLangAndActivate( langId, pid );
|
|
|
|
if ( 0 != pNewLang )
|
|
{
|
|
//
|
|
// Obviously not a default match if there is already a specific
|
|
// language created. Note that extra work searching the list
|
|
// in FindLangAndActivate is not wasted, as the ReturnLang below
|
|
// will place the activated language on the top of the list for
|
|
// easy access when the call is soon made to fetch the new
|
|
// language object supporting this pid/locale.
|
|
//
|
|
|
|
ReturnLang( pNewLang );
|
|
ciDebugOut(( DEB_LLIST, " supports found it, but returning FALSE\n" ));
|
|
return FALSE;
|
|
}
|
|
|
|
pNewLang = CreateLang( langId, pid, stateInfo, pLang );
|
|
|
|
if ( 0 == pNewLang )
|
|
{
|
|
ciDebugOut(( DEB_LLIST, "CLangList::Supports -- New pid 0x%x can use current [default] language object\n", pid ));
|
|
Win4Assert( pLang->IsPid( CI_DEFAULT_PID ) ); // May be a bogus assert...
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
ciDebugOut(( DEB_LLIST, "CLangList::Supports -- New pid 0x%x cannot use current language object\n", pid ));
|
|
ReturnLang( pNewLang ); // This one should get used in just a few calls...
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
} //Supports
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLangList::BorrowLang
|
|
//
|
|
// Synopsis: Borrows a language object
|
|
//
|
|
// Arguments: [locale] -- Locale
|
|
// [pid] -- property id
|
|
// [resources] -- Which resources to load.
|
|
//
|
|
// History: 19-Sep-91 BartoszM Created original GetLang.
|
|
// 15-Aug-94 SitaramR Renamed GetLang to BorrowLang and
|
|
// added code to look up registry.
|
|
// 2-14-97 mohamedn use ICiCLangRes, use lang specific
|
|
// default pid cache.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
CLanguage* CLangList::BorrowLang( LCID locale, PROPID pid, ULONG resources )
|
|
{
|
|
LANGID langId = LANGIDFROMLCID(locale);
|
|
|
|
ciDebugOut(( DEB_LLIST, "BorrowLang lang %#x, pid %#x, resources %#x\n",
|
|
locale, pid, resources ));
|
|
|
|
CLanguage * pLang = FindLangAndActivate( langId, pid );
|
|
if ( 0 != pLang )
|
|
return pLang;
|
|
|
|
//==========================================================
|
|
{
|
|
//
|
|
// We have to create a new language object. Serialize so that
|
|
// multiple threads are not creating simultaneously.
|
|
//
|
|
CLock lockCreat( _mtxCreate );
|
|
|
|
//
|
|
// lookup the given pid if a default pid hash table exist
|
|
// for the given LangID.
|
|
// If pid found in default pid cache, use CI_DEFAULT_PID
|
|
//
|
|
|
|
CLangPidStateInfo stateInfo;
|
|
|
|
if ( _pidHash.LokLookupOrAddLang( langId, stateInfo ) )
|
|
{
|
|
if ( _pidHash.LokIsUseDefaultPid( pid, stateInfo.GetLangIndex() ) )
|
|
pid = CI_DEFAULT_PID;
|
|
}
|
|
|
|
// Check to see if one became available while we were waiting.
|
|
|
|
pLang = FindLangAndActivate( langId, pid );
|
|
|
|
if ( 0 != pLang )
|
|
return pLang;
|
|
|
|
// Create a new CLanguage object
|
|
|
|
pLang = CreateLang( langId, pid, stateInfo, 0, resources );
|
|
}
|
|
//==========================================================
|
|
|
|
Win4Assert( pLang );
|
|
|
|
return pLang;
|
|
} //BorrowLang
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLangList::CreateLang
|
|
//
|
|
// Synopsis: Creates & Returns a language object
|
|
//
|
|
// Arguments: [langId] -- Locale
|
|
// [pid] -- property id
|
|
// [stateInfo] -- stateInfo to set internal state info.
|
|
// [pDup] -- Don't create a language just like this.
|
|
// Instead, return this one.
|
|
// [resources] -- Which to load.
|
|
//
|
|
// Returns: [pLang] -- a valid pointer to CLanguage object.
|
|
//
|
|
// History: 19-Sep-91 BartoszM Created original GetLang.
|
|
// 15-Aug-94 SitaramR Renamed GetLang to BorrowLang and
|
|
// added code to look up registry.
|
|
// 2-27-97 mohamedn use ICiCLangRes,
|
|
// use lang specific default pid cache.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CLanguage * CLangList::CreateLang( LANGID langId,
|
|
PROPID pid,
|
|
CLangPidStateInfo & stateInfo,
|
|
CLanguage const * pDup,
|
|
ULONG resources )
|
|
{
|
|
ciDebugOut(( DEB_LLIST, "CreateLang lang %#x, pid %#x, resources %#x\n",
|
|
langId, pid, resources ));
|
|
|
|
ULONG pidFlags = 0;
|
|
|
|
if ( LoadWB( resources ) )
|
|
pidFlags |= USE_WB_DEFAULT_PID;
|
|
if ( LoadST( resources ) )
|
|
pidFlags |= USE_STEMMER_DEFAULT_PID;
|
|
if ( LoadNO( resources ) )
|
|
pidFlags |= USE_NWL_DEFAULT_PID;
|
|
|
|
//
|
|
// Get interfaces to the wordbreaker, stemmer and noise word list
|
|
// via ICiCLangRes
|
|
//
|
|
|
|
XInterface<IWordBreaker> xIWBreak;
|
|
XInterface<IStemmer> xIStemmer;
|
|
XInterface<IStream> xIStrmNoiseFile;
|
|
|
|
if ( pid == CI_DEFAULT_PID )
|
|
{
|
|
// create default word breaker, stemmer & nwl
|
|
|
|
if ( LoadWB( resources ) )
|
|
xIWBreak.Set( GetWordBreaker ( langId, pid, stateInfo, TRUE ) );
|
|
|
|
if ( LoadST( resources ) )
|
|
xIStemmer.Set( GetStemmer ( langId, pid, stateInfo ) );
|
|
|
|
if ( LoadNO( resources ) )
|
|
xIStrmNoiseFile.Set( GetNoiseWordList ( langId, pid, stateInfo ) );
|
|
}
|
|
else
|
|
{
|
|
// try to create wb, stemmer, and nwl using this pid (non-default)
|
|
if ( LoadWB( resources ) )
|
|
xIWBreak.Set( GetWordBreaker( langId, pid, stateInfo, FALSE ) );
|
|
|
|
if ( LoadST( resources ) )
|
|
xIStemmer.Set( GetStemmer( langId, pid, stateInfo ) );
|
|
|
|
if ( LoadNO( resources ) )
|
|
xIStrmNoiseFile.Set( GetNoiseWordList( langId, pid, stateInfo ) );
|
|
|
|
ciDebugOut(( DEB_LLIST, " GetPidFlags: %#x\n", stateInfo.GetPidFlags() ));
|
|
|
|
if ( stateInfo.GetPidFlags() == pidFlags )
|
|
{
|
|
// Client requested to use DEFAULT_PID:
|
|
// add pid to the default pid cache for this langid,
|
|
// scan availble lang objects for a match, and return it if
|
|
// found else create default wb, stemmer, and nwl.
|
|
|
|
Win4Assert ( xIWBreak.IsNull() );
|
|
Win4Assert ( xIStemmer.IsNull() );
|
|
Win4Assert ( xIStrmNoiseFile.IsNull() );
|
|
|
|
_pidHash.LokAddDefaultPid( pid, stateInfo.GetLangIndex() );
|
|
|
|
pid = CI_DEFAULT_PID;
|
|
|
|
if ( 0 != pDup && pDup->IsLocale( langId ) && pDup->IsPid( pid ) )
|
|
return 0;
|
|
|
|
CLanguage * pLang = FindLangAndActivate( langId, pid );
|
|
|
|
if ( 0 != pLang )
|
|
return pLang;
|
|
|
|
if ( LoadWB( resources ) )
|
|
xIWBreak.Set( GetWordBreaker( langId, pid, stateInfo, TRUE ) );
|
|
|
|
if ( LoadST( resources ) )
|
|
xIStemmer.Set( GetStemmer( langId, pid, stateInfo ) );
|
|
|
|
if ( LoadNO( resources ) )
|
|
xIStrmNoiseFile.Set( GetNoiseWordList( langId, pid, stateInfo ) );
|
|
}
|
|
else
|
|
{
|
|
// Client didn't request default pid for all, create default wb, stemmer or nwl
|
|
// only if client requested using default pid for it.
|
|
|
|
if ( stateInfo.IsPidFlagSet( USE_WB_DEFAULT_PID ) )
|
|
{
|
|
if ( LoadWB( resources ) )
|
|
xIWBreak.Set( GetWordBreaker( langId, CI_DEFAULT_PID, stateInfo, TRUE ) );
|
|
}
|
|
else
|
|
Win4Assert ( !xIWBreak.IsNull() );
|
|
|
|
if ( stateInfo.IsPidFlagSet( USE_STEMMER_DEFAULT_PID ) )
|
|
{
|
|
if ( LoadST( resources ) )
|
|
xIStemmer.Set( GetStemmer( langId, CI_DEFAULT_PID, stateInfo ) );
|
|
}
|
|
|
|
if ( stateInfo.IsPidFlagSet( USE_NWL_DEFAULT_PID ) )
|
|
{
|
|
if ( LoadNO( resources ) )
|
|
xIStrmNoiseFile.Set( GetNoiseWordList ( langId, CI_DEFAULT_PID, stateInfo ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
// create a language object given the wb, stemmer & nwl.
|
|
|
|
CLanguage * pLang = new CLanguage( langId,
|
|
pid,
|
|
xIWBreak,
|
|
xIStemmer,
|
|
xIStrmNoiseFile );
|
|
|
|
// Queue can't fail, so no smart pointer for pLang is needed
|
|
|
|
//------------------------------------------------------
|
|
{
|
|
CLock lock( _mtxList );
|
|
|
|
_langsInUse.Queue( pLang );
|
|
}
|
|
//------------------------------------------------------
|
|
|
|
return pLang;
|
|
} //CreateLang
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLangList::GetWordBreaker, private
|
|
//
|
|
// Synopsis: gets a word breaker interface given a langid and a pid
|
|
//
|
|
// Arguments: [langid] -- langid
|
|
// [pid] -- property id
|
|
// [stateInfo] -- stateInfo to set internal state info.
|
|
// [fCreateDefault]-- flag to create default word breaker if TRUE
|
|
//
|
|
// Returns: IWordBreaker interface upon success, throws upon failure.
|
|
//
|
|
// History: 2-27-97 MohamedN Created (from borrowlang)
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
IWordBreaker * CLangList::GetWordBreaker( LANGID langid,
|
|
PROPID pid,
|
|
CLangPidStateInfo & stateInfo,
|
|
BOOL fCreateDefault )
|
|
{
|
|
IWordBreaker * pIWordBreaker = 0;
|
|
|
|
ciDebugOut(( DEB_LLIST, "!!! Actually creating a wordbreaker\n" ));
|
|
|
|
SCODE sc = _xICiCLangRes->GetWordBreaker( langid, pid, &pIWordBreaker );
|
|
if ( SUCCEEDED(sc) )
|
|
{
|
|
Win4Assert( 0 != pIWordBreaker );
|
|
}
|
|
else
|
|
{
|
|
switch (sc)
|
|
{
|
|
case CI_E_NOT_FOUND:
|
|
if ( fCreateDefault )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,"Using default word breaker for locale 0x%x\n",
|
|
langid ));
|
|
|
|
pIWordBreaker = new CDefWordBreaker();
|
|
}
|
|
|
|
// force fall thru
|
|
|
|
case CI_E_USE_DEFAULT_PID:
|
|
stateInfo.SetPidFlags( USE_WB_DEFAULT_PID );
|
|
break;
|
|
|
|
default:
|
|
ciDebugOut(( DEB_ERROR, "GetWordBreaker Failed(locale: %x,pid: %x): sc: %x\n",
|
|
langid, pid, sc ));
|
|
|
|
THROW( CException( sc ) );
|
|
} // switch
|
|
|
|
} // else
|
|
|
|
return pIWordBreaker;
|
|
} //GetWordBreaker
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLangList::GetStemmer, private
|
|
//
|
|
// Synopsis: gets a stemmer interface given a langid and a pid
|
|
//
|
|
// Arguments: [langid] -- langid
|
|
// [pid] -- property id
|
|
// [stateInfo] -- stateInfo to set internal state info.
|
|
//
|
|
// Returns: IStemmer interface upon success, null or throws upon failure.
|
|
//
|
|
// History: 2-27-97 MohamedN Created (from borrowlang)
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
IStemmer * CLangList::GetStemmer( LANGID langid,
|
|
PROPID pid,
|
|
CLangPidStateInfo & stateInfo )
|
|
{
|
|
SCODE sc = S_OK;
|
|
IStemmer * pIStemmer = 0;
|
|
|
|
|
|
sc = _xICiCLangRes->GetStemmer( langid, pid, &pIStemmer );
|
|
if ( FAILED(sc) )
|
|
{
|
|
switch (sc)
|
|
{
|
|
|
|
case CI_E_NOT_FOUND:
|
|
|
|
ciDebugOut(( DEB_ITRACE,"no stemmer found for locale 0x%x\n",
|
|
langid ));
|
|
|
|
break;
|
|
|
|
case CI_E_USE_DEFAULT_PID:
|
|
|
|
stateInfo.SetPidFlags( USE_STEMMER_DEFAULT_PID );
|
|
|
|
break;
|
|
|
|
default:
|
|
ciDebugOut(( DEB_ERROR, "GetStemmer Failed(locale: %x,pid: %x): sc: %x\n",
|
|
langid,pid, sc ));
|
|
|
|
THROW( CException(sc) );
|
|
} // switch
|
|
|
|
} // else
|
|
|
|
|
|
return pIStemmer;
|
|
} // GetStemmer
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLangList::GetNoiseWordList, private
|
|
//
|
|
// Synopsis: gets an IStream pointer to the noise word list, given a langid & locale.
|
|
//
|
|
// Arguments: [langid] -- langid
|
|
// [pid] -- property id
|
|
// [stateInfo] -- stateInfo to set internal state info.
|
|
//
|
|
// Returns: IStream interface upon success, null or throws upon failure.
|
|
//
|
|
// History: 2-27-97 MohamedN Created (from borrowlang)
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
IStream * CLangList::GetNoiseWordList( LANGID langid,
|
|
PROPID pid,
|
|
CLangPidStateInfo & stateInfo )
|
|
{
|
|
SCODE sc = S_OK;
|
|
IStream * pIStream = 0;
|
|
|
|
sc = _xICiCLangRes->GetNoiseWordList( langid, pid, &pIStream );
|
|
if ( FAILED(sc) )
|
|
{
|
|
switch (sc)
|
|
{
|
|
|
|
case CI_E_NOT_FOUND:
|
|
|
|
ciDebugOut(( DEB_ITRACE,"no NoiseWordList found for locale 0x%x\n",
|
|
langid ));
|
|
|
|
break;
|
|
|
|
case CI_E_USE_DEFAULT_PID:
|
|
|
|
stateInfo.SetPidFlags( USE_NWL_DEFAULT_PID );
|
|
|
|
break;
|
|
|
|
default:
|
|
ciDebugOut(( DEB_ERROR, "GetNoiseWordList Failed(locale: %x,pid: %x): sc: %x\n",
|
|
langid, pid, sc ));
|
|
|
|
THROW( CException(sc) );
|
|
} // switch
|
|
|
|
} // else
|
|
|
|
return pIStream;
|
|
} //GetNoiseWordList
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLangList::FindLangAndActivate, private
|
|
//
|
|
// Synopsis: If a language with the given locale exits, then return the
|
|
// language after making it active
|
|
//
|
|
// Arguments: [locale] -- Locale
|
|
// [pid] -- property id
|
|
//
|
|
// Notes:
|
|
//
|
|
// History: 14-Sep-94 SitaramR Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CLanguage *CLangList::FindLangAndActivate( LCID locale, PROPID pid )
|
|
{
|
|
ciDebugOut(( DEB_LLIST, "FindLangAndActivate lcid %#x, pid %#x\n",
|
|
locale, pid ));
|
|
|
|
ULONG dwTick = GetTickCount();
|
|
|
|
CLock lock( _mtxList );
|
|
|
|
CLanguage *pLang = 0;
|
|
|
|
CLangIter iter( _langsAvailable );
|
|
|
|
while ( !_langsAvailable.AtEnd(iter) )
|
|
{
|
|
ciDebugOut(( DEB_LLIST, " looking for match, lcid %#x, iter->IsPid %d\n",
|
|
iter->Locale(), iter->IsPid(pid) ));
|
|
|
|
if ( iter->IsLocale(locale) && iter->IsPid(pid) )
|
|
{
|
|
pLang = iter.GetLang();
|
|
|
|
_langsAvailable.Advance(iter);
|
|
|
|
// move from Available list to InUse list
|
|
pLang->Unlink();
|
|
_langsInUse.Queue( pLang );
|
|
|
|
//
|
|
// Check one beyond, just to make some progress removing extra copies.
|
|
//
|
|
|
|
if ( !_langsAvailable.AtEnd(iter) &&
|
|
(dwTick - iter->LastUsed()) > _ulMaxIdle )
|
|
{
|
|
CLanguage *pLangTemp = iter.GetLang();
|
|
_langsAvailable.Advance(iter);
|
|
pLangTemp->Unlink();
|
|
delete pLangTemp;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Is it idle? Ignore overflow. It just means we delete too early
|
|
// once every few days.
|
|
//
|
|
|
|
if ( (dwTick - iter->LastUsed()) > _ulMaxIdle )
|
|
{
|
|
ciDebugOut(( DEB_LLIST, "deleting idle language object\n" ));
|
|
|
|
pLang = iter.GetLang();
|
|
_langsAvailable.Advance(iter);
|
|
pLang->Unlink();
|
|
delete pLang;
|
|
pLang = 0;
|
|
}
|
|
else
|
|
_langsAvailable.Advance(iter);
|
|
}
|
|
|
|
ciDebugOut(( DEB_LLIST, " FindLangAndActivate returning %p\n", pLang ));
|
|
|
|
return pLang;
|
|
} //FindLangAndActivate
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLangList::ReturnLang, public
|
|
//
|
|
// Synopsis: Returns a Language
|
|
//
|
|
// Arguments: [pLang] -- language to be returned
|
|
//
|
|
// History: 15-Aug-94 SitaramR Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CLangList::ReturnLang( CLanguage *pLang )
|
|
{
|
|
ULONG dwTick = GetTickCount();
|
|
|
|
CLock lock( _mtxList );
|
|
|
|
Win4Assert( pLang != 0 );
|
|
|
|
if ( pLang->IsZombie() )
|
|
delete pLang;
|
|
else
|
|
{
|
|
// Move from InUse list to Available list. Put it at the front of
|
|
// the list so we don't cycle through the cached languages.
|
|
|
|
pLang->Unlink();
|
|
pLang->SetLastUsed( dwTick );
|
|
_langsAvailable.Push( pLang );
|
|
}
|
|
} //ReturnLang
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLangList::InvalidateLangResources, public
|
|
//
|
|
// Synopsis: Delete all language objects so that new language objects
|
|
// can be demand loaded from registry.
|
|
//
|
|
// History: 15-Aug-94 SitaramR Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CLangList::InvalidateLangResources()
|
|
{
|
|
CLock lock( _mtxList );
|
|
|
|
ciDebugOut(( DEB_LLIST, "InvalidateLangResources\n" ));
|
|
|
|
for ( CLanguage *pLang = _langsAvailable.Pop();
|
|
0 != pLang;
|
|
pLang = _langsAvailable.Pop() )
|
|
{
|
|
delete pLang;
|
|
}
|
|
|
|
for ( pLang = _langsInUse.Pop();
|
|
pLang;
|
|
pLang = _langsInUse.Pop() )
|
|
{
|
|
pLang->Zombify(); // because language is still in use
|
|
}
|
|
} //InvalidateLangResources
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CDefaultPidHash::LokLookupOrAddLang
|
|
//
|
|
// Synopsis: Sets internal index to the position of langId
|
|
// if langId is found, else creates a langId and
|
|
// a corresponding default pid hash table.
|
|
//
|
|
// Arguments: [langid] -- langid
|
|
// [stateInfo] -- to set internal langId specific index value.
|
|
//
|
|
// Returns: TRUE if lang is found
|
|
// FALSE if lang is not found
|
|
//
|
|
// History: 2-27-97 MohamedN Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CDefaultPidHash::LokLookupOrAddLang( LANGID langId, CLangPidStateInfo & stateInfo )
|
|
{
|
|
|
|
BOOL fLangIdFound = FALSE;
|
|
unsigned i;
|
|
|
|
//
|
|
// find whether langId is in _aLangId Table
|
|
//
|
|
|
|
for ( i = 0; i < _langIdCount ; i++ )
|
|
{
|
|
if ( _aLangId[i] == langId )
|
|
{
|
|
fLangIdFound = TRUE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// if _aLangId is not found in _aLangID table,
|
|
// add it, and create a corresponding hash table for it.
|
|
//
|
|
|
|
if ( !fLangIdFound )
|
|
{
|
|
BOOL fAddedLangId = FALSE;
|
|
|
|
TRY
|
|
{
|
|
_aLangId.Add( langId, i );
|
|
|
|
fAddedLangId = TRUE;
|
|
|
|
XPtr<CPidHash> xPidHash( new CPidHash( INIT_PID_HASH_TABLE_SIZE ) );
|
|
|
|
_aHashPidTables.Add( xPidHash.GetPointer(), i );
|
|
|
|
xPidHash.Acquire();
|
|
|
|
_langIdCount++;
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
if ( fAddedLangId )
|
|
_aLangId.Remove( i );
|
|
|
|
RETHROW();
|
|
}
|
|
END_CATCH
|
|
}
|
|
|
|
//
|
|
// store position of langId in our state object (found or created).
|
|
//
|
|
|
|
stateInfo.SetLangIndex(i);
|
|
|
|
return fLangIdFound;
|
|
} //LokLookupOrAddLang
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CDefaultPidHash::LokIsUseDefaultPid
|
|
//
|
|
// Synopsis: Determines if the passed-in pid belongs to the
|
|
// default pid group.
|
|
//
|
|
// Arguments: [pid] -- property id
|
|
// [index] -- position of langid cache table
|
|
//
|
|
// Returns: TRUE if pid is a member of the default pid group
|
|
// FALSE if pid is not a member of the default pid group
|
|
//
|
|
// History: 2-27-97 MohamedN Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CDefaultPidHash::LokIsUseDefaultPid( PROPID pid, unsigned index )
|
|
{
|
|
CWidHashEntry entry(pid);
|
|
|
|
if ( _aHashPidTables[index] )
|
|
return _aHashPidTables[index]->LookUpWorkId( entry );
|
|
|
|
Win4Assert( !"invalid _aHashPidTables[index]" );
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CDefaultPidHash::LokAddDefaultPid
|
|
//
|
|
// Synopsis: Inserts pid into the default pid hash table for a given langId
|
|
//
|
|
// Arguments: [pid] -- property id
|
|
// [index] -- position of langid cache table
|
|
//
|
|
// Returns: none
|
|
//
|
|
// History: 2-27-97 MohamedN Created
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CDefaultPidHash::LokAddDefaultPid( PROPID pid, unsigned index )
|
|
{
|
|
CWidHashEntry entry(pid);
|
|
|
|
Win4Assert( _aHashPidTables[index] );
|
|
|
|
_aHashPidTables[index]->AddEntry(entry);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLanguage::CLanguage
|
|
//
|
|
// Synopsis: Finds language information
|
|
//
|
|
// History: 16-Jul-91 BartoszM Created.
|
|
// 15-Aug-94 SitaramR Changed constructor to take
|
|
// wordbreaker and noisefile.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#define NOISE_SIZE 257
|
|
|
|
CLanguage::CLanguage( LCID locale,
|
|
PROPID pid,
|
|
XInterface<IWordBreaker> & xWBreak,
|
|
XInterface<IStemmer> & xStemmer,
|
|
XInterface<IStream> & xIStrmNoiseFile )
|
|
: _locale( locale ),
|
|
_pid( pid ),
|
|
_xWBreak( xWBreak.Acquire() ),
|
|
_xStemmer( xStemmer.Acquire() ),
|
|
_xIStrmNoiseFile( xIStrmNoiseFile.Acquire() ),
|
|
_zombie( FALSE )
|
|
{
|
|
ciDebugOut(( DEB_LLIST, "CLanguage, locale %#x, pid %#x\n", locale, pid ));
|
|
|
|
//
|
|
// Set up for filtering noise word list. This will always use the
|
|
// default filter. We don't go through CFilterDriver, because that
|
|
// performs too much extra work: Ole binding, property filtering, etc.
|
|
//
|
|
|
|
if ( !_xIStrmNoiseFile.IsNull() )
|
|
{
|
|
XInterface<CTextIFilter> xTextIFilter( new CTextIFilter );
|
|
SCODE sc = xTextIFilter->Load( _xIStrmNoiseFile.GetPointer() );
|
|
if ( FAILED(sc) )
|
|
{
|
|
ciDebugOut(( DEB_ERROR, "Filter of pIStrmNoiseFile(%x) returned 0x%x\n",
|
|
_xIStrmNoiseFile.GetPointer(), sc ));
|
|
}
|
|
else
|
|
{
|
|
ULONG fBulkyObject;
|
|
sc = xTextIFilter->Init( IFILTER_INIT_CANON_PARAGRAPHS |
|
|
IFILTER_INIT_CANON_HYPHENS |
|
|
IFILTER_INIT_CANON_SPACES |
|
|
IFILTER_INIT_APPLY_INDEX_ATTRIBUTES |
|
|
IFILTER_INIT_INDEXING_ONLY,
|
|
0,
|
|
0,
|
|
&fBulkyObject );
|
|
|
|
if ( FAILED(sc) )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,
|
|
"IFilter->Init() of pIStrmNoiseFile(%x) returned 0x%x.\n",
|
|
_xIStrmNoiseFile.GetPointer(), sc ));
|
|
}
|
|
else
|
|
{
|
|
STAT_CHUNK statChunk;
|
|
|
|
for ( sc = xTextIFilter->GetChunk( &statChunk );
|
|
SUCCEEDED(sc) && (statChunk.flags & CHUNK_TEXT) == 0;
|
|
sc = xTextIFilter->GetChunk( &statChunk ) );
|
|
|
|
if ( FAILED(sc) )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,
|
|
"IFilter->GetChunk() of pIStrmNoiseFile(%x) returned 0x%x.\n",
|
|
_xIStrmNoiseFile.GetPointer(), sc ));
|
|
}
|
|
else
|
|
{
|
|
CNoiseListInit noiseInit( NOISE_SIZE );
|
|
|
|
//
|
|
// If we got this far, try creating the key maker.
|
|
//
|
|
|
|
CKeyMaker keymak( _xWBreak.GetPointer(), noiseInit );
|
|
|
|
OCCURRENCE occ = 0;
|
|
CTextSource tsource( xTextIFilter.GetPointer(), statChunk );
|
|
keymak.PutStream( occ, &tsource );
|
|
|
|
_xNoiseTable.Set( noiseInit.AcqStringTable() );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// _xIStrmNoiseFile is null, don't use a noise file in filtering
|
|
//
|
|
ciDebugOut(( DEB_ITRACE,
|
|
"Creating language object 0x%x, noise file = EMPTY\n",
|
|
locale ));
|
|
}
|
|
} //CLanguage
|
|
|
|
CLanguage::~CLanguage()
|
|
{
|
|
}
|
|
|