diff options
Diffstat (limited to 'linguistic/source/convdic.cxx')
-rw-r--r-- | linguistic/source/convdic.cxx | 744 |
1 files changed, 744 insertions, 0 deletions
diff --git a/linguistic/source/convdic.cxx b/linguistic/source/convdic.cxx new file mode 100644 index 000000000000..0b7245eb3019 --- /dev/null +++ b/linguistic/source/convdic.cxx @@ -0,0 +1,744 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_linguistic.hxx" + +#include <cppuhelper/factory.hxx> +#include <i18npool/lang.h> +#include <osl/mutex.hxx> +#include <tools/debug.hxx> +#include <tools/fsys.hxx> +#include <tools/stream.hxx> +#include <tools/stream.hxx> +#include <tools/string.hxx> +#include <tools/urlobj.hxx> +#include <ucbhelper/content.hxx> +#include <unotools/processfactory.hxx> +#include <unotools/streamwrap.hxx> +#include <unotools/ucbstreamhelper.hxx> + +#include <com/sun/star/linguistic2/XConversionDictionary.hpp> +#include <com/sun/star/linguistic2/ConversionDictionaryType.hpp> +#include <com/sun/star/linguistic2/XConversionPropertyType.hpp> +#include <com/sun/star/linguistic2/ConversionPropertyType.hpp> +#include <com/sun/star/util/XFlushable.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/lang/EventObject.hpp> +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/registry/XRegistryKey.hpp> +#include <com/sun/star/util/XFlushListener.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#include <com/sun/star/document/XFilter.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/xml/sax/InputSource.hpp> +#include <com/sun/star/xml/sax/XParser.hpp> + + +#include "convdic.hxx" +#include "convdicxml.hxx" +#include "misc.hxx" +#include "defs.hxx" + +using namespace std; +using namespace utl; +using namespace osl; +using namespace rtl; +using namespace com::sun::star; +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace com::sun::star::linguistic2; +using namespace linguistic; + +#define SN_CONV_DICTIONARY "com.sun.star.linguistic2.ConversionDictionary" +#define SN_HCD_CONV_DICTIONARY "com.sun.star.linguistic2.HangulHanjaConversionDictionary" + + +/////////////////////////////////////////////////////////////////////////// +void ReadThroughDic( const String &rMainURL, ConvDicXMLImport &rImport ) +{ + if (rMainURL.Len() == 0) + return; + DBG_ASSERT(!INetURLObject( rMainURL ).HasError(), "invalid URL"); + + uno::Reference< lang::XMultiServiceFactory > xServiceFactory( utl::getProcessServiceFactory() ); + + // get xInputStream stream + uno::Reference< io::XInputStream > xIn; + try + { + uno::Reference< ucb::XSimpleFileAccess > xAccess( xServiceFactory->createInstance( + A2OU( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY_THROW ); + xIn = xAccess->openFileRead( rMainURL ); + } + catch (uno::Exception & e) + { + DBG_ASSERT( 0, "failed to get input stream" ); + (void) e; + } + if (!xIn.is()) + return; + + SvStreamPtr pStream = SvStreamPtr( utl::UcbStreamHelper::CreateStream( xIn ) ); + + ULONG nError = sal::static_int_cast< ULONG >(-1); + + // prepare ParserInputSource + xml::sax::InputSource aParserInput; + aParserInput.aInputStream = xIn; + + // get parser + uno::Reference< xml::sax::XParser > xParser; + try + { + xParser = uno::Reference< xml::sax::XParser >( xServiceFactory->createInstance( + A2OU( "com.sun.star.xml.sax.Parser" ) ), UNO_QUERY ); + } + catch (uno::Exception &) + { + } + DBG_ASSERT( xParser.is(), "Can't create parser" ); + if (!xParser.is()) + return; + + // get filter + //ConvDicXMLImport *pImport = new ConvDicXMLImport( this, rMainURL ); + //!! keep a reference until everything is done to + //!! ensure the proper lifetime of the object + uno::Reference < xml::sax::XDocumentHandler > xFilter( + (xml::sax::XExtendedDocumentHandler *) &rImport, UNO_QUERY ); + + // connect parser and filter + xParser->setDocumentHandler( xFilter ); + + // finally, parser the stream + try + { + xParser->parseStream( aParserInput ); // implicitly calls ConvDicXMLImport::CreateContext + if (rImport.GetSuccess()) + nError = 0; + } + catch( xml::sax::SAXParseException& ) + { +// if( bEncrypted ) +// nError = ERRCODE_SFX_WRONGPASSWORD; + } + catch( xml::sax::SAXException& ) + { +// if( bEncrypted ) +// nError = ERRCODE_SFX_WRONGPASSWORD; + } + catch( io::IOException& ) + { + } +} + +BOOL IsConvDic( const String &rFileURL, INT16 &nLang, sal_Int16 &nConvType ) +{ + BOOL bRes = FALSE; + + if (rFileURL.Len() == 0) + return bRes; + + // check if file extension matches CONV_DIC_EXT + String aExt; + xub_StrLen nPos = rFileURL.SearchBackward( '.' ); + if (STRING_NOTFOUND != nPos) + aExt = rFileURL.Copy( nPos + 1 ); + aExt.ToLowerAscii(); + if (!aExt.EqualsAscii( CONV_DIC_EXT )) + return bRes; + + // first argument being 0 should stop the file from being parsed + // up to the end (reading all entries) when the required + // data (language, conversion type) is found. + ConvDicXMLImport *pImport = new ConvDicXMLImport( 0, rFileURL ); + + //!! keep a first reference to ensure the lifetime of the object !! + uno::Reference< XInterface > xRef( (document::XFilter *) pImport, UNO_QUERY ); + + ReadThroughDic( rFileURL, *pImport ); // will implicitly add the entries + bRes = pImport->GetLanguage() != LANGUAGE_NONE && + pImport->GetConversionType() != -1; + DBG_ASSERT( bRes, "conversion dictionary corrupted?" ); + + if (bRes) + { + nLang = pImport->GetLanguage(); + nConvType = pImport->GetConversionType(); + } + + return bRes; +} + + +/////////////////////////////////////////////////////////////////////////// + +ConvDic::ConvDic( + const String &rName, + INT16 nLang, + sal_Int16 nConvType, + BOOL bBiDirectional, + const String &rMainURL) : + aFlushListeners( GetLinguMutex() ) +{ + aName = rName; + nLanguage = nLang; + nConversionType = nConvType; + aMainURL = rMainURL; + + if (bBiDirectional) + pFromRight = std::auto_ptr< ConvMap >( new ConvMap ); + if (nLang == LANGUAGE_CHINESE_SIMPLIFIED || nLang == LANGUAGE_CHINESE_TRADITIONAL) + pConvPropType = std::auto_ptr< PropTypeMap >( new PropTypeMap ); + + nMaxLeftCharCount = nMaxRightCharCount = 0; + bMaxCharCountIsValid = TRUE; + + bNeedEntries = TRUE; + bIsModified = bIsActive = FALSE; + bIsReadonly = FALSE; + + if( rMainURL.Len() > 0 ) + { + BOOL bExists = FALSE; + bIsReadonly = IsReadOnly( rMainURL, &bExists ); + + if( !bExists ) // new empty dictionary + { + bNeedEntries = FALSE; + //! create physical representation of an **empty** dictionary + //! that could be found by the dictionary-list implementation + // (Note: empty dictionaries are not just empty files!) + Save(); + bIsReadonly = IsReadOnly( rMainURL ); // will be FALSE if Save was succesfull + } + } + else + { + bNeedEntries = FALSE; + } +} + + +ConvDic::~ConvDic() +{ +} + + +void ConvDic::Load() +{ + DBG_ASSERT( !bIsModified, "dictionary is modified. Really do 'Load'?" ); + + //!! prevent function from being called recursively via HasEntry, AddEntry + bNeedEntries = FALSE; + ConvDicXMLImport *pImport = new ConvDicXMLImport( this, aMainURL ); + //!! keep a first reference to ensure the lifetime of the object !! + uno::Reference< XInterface > xRef( (document::XFilter *) pImport, UNO_QUERY ); + ReadThroughDic( aMainURL, *pImport ); // will implicitly add the entries + bIsModified = FALSE; +} + + +void ConvDic::Save() +{ + DBG_ASSERT( !bNeedEntries, "saving while entries missing" ); + if (aMainURL.Len() == 0 || bNeedEntries) + return; + DBG_ASSERT(!INetURLObject( aMainURL ).HasError(), "invalid URL"); + + uno::Reference< lang::XMultiServiceFactory > xServiceFactory( utl::getProcessServiceFactory() ); + + // get XOutputStream stream + uno::Reference< io::XStream > xStream; + try + { + uno::Reference< ucb::XSimpleFileAccess > xAccess( xServiceFactory->createInstance( + A2OU( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY_THROW ); + xStream = xAccess->openFileReadWrite( aMainURL ); + } + catch (uno::Exception & e) + { + DBG_ASSERT( 0, "failed to get input stream" ); + (void) e; + } + if (!xStream.is()) + return; + + SvStreamPtr pStream = SvStreamPtr( utl::UcbStreamHelper::CreateStream( xStream ) ); + + // get XML writer + uno::Reference< io::XActiveDataSource > xSaxWriter; + if (xServiceFactory.is()) + { + try + { + xSaxWriter = uno::Reference< io::XActiveDataSource >( + xServiceFactory->createInstance( + OUString::createFromAscii( "com.sun.star.xml.sax.Writer" ) ), UNO_QUERY ); + } + catch (uno::Exception &) + { + } + } + DBG_ASSERT( xSaxWriter.is(), "can't instantiate XML writer" ); + + if (xSaxWriter.is() && xStream.is()) + { + // connect XML writer to output stream + xSaxWriter->setOutputStream( xStream->getOutputStream() ); + + // prepare arguments (prepend doc handler to given arguments) + uno::Reference< xml::sax::XDocumentHandler > xDocHandler( xSaxWriter, UNO_QUERY ); + ConvDicXMLExport *pExport = new ConvDicXMLExport( *this, aMainURL, xDocHandler ); + //!! keep a first(!) reference until everything is done to + //!! ensure the proper lifetime of the object + uno::Reference< document::XFilter > aRef( (document::XFilter *) pExport ); + sal_Bool bRet = pExport->Export(); // write entries to file + DBG_ASSERT( !pStream->GetError(), "I/O error while writing to stream" ); + if (bRet) + bIsModified = FALSE; + } + DBG_ASSERT( !bIsModified, "dictionary still modified after save. Save failed?" ); +} + + +ConvMap::iterator ConvDic::GetEntry( ConvMap &rMap, const rtl::OUString &rFirstText, const rtl::OUString &rSecondText ) +{ + pair< ConvMap::iterator, ConvMap::iterator > aRange = + rMap.equal_range( rFirstText ); + ConvMap::iterator aPos = rMap.end(); + for (ConvMap::iterator aIt = aRange.first; + aIt != aRange.second && aPos == rMap.end(); + ++aIt) + { + if ((*aIt).second == rSecondText) + aPos = aIt; + } + return aPos; +} + + +BOOL ConvDic::HasEntry( const OUString &rLeftText, const OUString &rRightText ) +{ + if (bNeedEntries) + Load(); + ConvMap::iterator aIt = GetEntry( aFromLeft, rLeftText, rRightText ); + return aIt != aFromLeft.end(); +} + + +void ConvDic::AddEntry( const OUString &rLeftText, const OUString &rRightText ) +{ + if (bNeedEntries) + Load(); + + DBG_ASSERT(!HasEntry( rLeftText, rRightText), "entry already exists" ); + aFromLeft .insert( ConvMap::value_type( rLeftText, rRightText ) ); + if (pFromRight.get()) + pFromRight->insert( ConvMap::value_type( rRightText, rLeftText ) ); + + if (bMaxCharCountIsValid) + { + if (rLeftText.getLength() > nMaxLeftCharCount) + nMaxLeftCharCount = (sal_Int16) rLeftText.getLength(); + if (pFromRight.get() && rRightText.getLength() > nMaxRightCharCount) + nMaxRightCharCount = (sal_Int16) rRightText.getLength(); + } + + bIsModified = TRUE; +} + + +void ConvDic::RemoveEntry( const OUString &rLeftText, const OUString &rRightText ) +{ + if (bNeedEntries) + Load(); + + ConvMap::iterator aLeftIt = GetEntry( aFromLeft, rLeftText, rRightText ); + DBG_ASSERT( aLeftIt != aFromLeft.end(), "left map entry missing" ); + aFromLeft .erase( aLeftIt ); + + if (pFromRight.get()) + { + ConvMap::iterator aRightIt = GetEntry( *pFromRight, rRightText, rLeftText ); + DBG_ASSERT( aRightIt != pFromRight->end(), "right map entry missing" ); + pFromRight->erase( aRightIt ); + } + + bIsModified = TRUE; + bMaxCharCountIsValid = FALSE; +} + + +OUString SAL_CALL ConvDic::getName( ) + throw (RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + return aName; +} + + +Locale SAL_CALL ConvDic::getLocale( ) + throw (RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + return CreateLocale( nLanguage ); +} + + +sal_Int16 SAL_CALL ConvDic::getConversionType( ) + throw (RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + return nConversionType; +} + + +void SAL_CALL ConvDic::setActive( sal_Bool bActivate ) + throw (RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + bIsActive = bActivate; +} + + +sal_Bool SAL_CALL ConvDic::isActive( ) + throw (RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + return bIsActive; +} + + +void SAL_CALL ConvDic::clear( ) + throw (RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + aFromLeft .clear(); + if (pFromRight.get()) + pFromRight->clear(); + bNeedEntries = FALSE; + bIsModified = TRUE; + nMaxLeftCharCount = 0; + nMaxRightCharCount = 0; + bMaxCharCountIsValid = TRUE; +} + + +uno::Sequence< OUString > SAL_CALL ConvDic::getConversions( + const OUString& aText, + sal_Int32 nStartPos, + sal_Int32 nLength, + ConversionDirection eDirection, + sal_Int32 /*nTextConversionOptions*/ ) + throw (IllegalArgumentException, RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + if (!pFromRight.get() && eDirection == ConversionDirection_FROM_RIGHT) + return uno::Sequence< OUString >(); + + if (bNeedEntries) + Load(); + + OUString aLookUpText( aText.copy(nStartPos, nLength) ); + ConvMap &rConvMap = eDirection == ConversionDirection_FROM_LEFT ? + aFromLeft : *pFromRight; + pair< ConvMap::iterator, ConvMap::iterator > aRange = + rConvMap.equal_range( aLookUpText ); + + INT32 nCount = 0; + ConvMap::iterator aIt; + for (aIt = aRange.first; aIt != aRange.second; ++aIt) + ++nCount; + + uno::Sequence< OUString > aRes( nCount ); + OUString *pRes = aRes.getArray(); + INT32 i = 0; + for (aIt = aRange.first; aIt != aRange.second; ++aIt) + pRes[i++] = (*aIt).second; + + return aRes; +} + + +static BOOL lcl_SeqHasEntry( + const OUString *pSeqStart, // first element to check + INT32 nToCheck, // number of elements to check + const OUString &rText) +{ + BOOL bRes = FALSE; + if (pSeqStart && nToCheck > 0) + { + const OUString *pDone = pSeqStart + nToCheck; // one behind last to check + while (!bRes && pSeqStart != pDone) + { + if (*pSeqStart++ == rText) + bRes = TRUE; + } + } + return bRes; +} + +uno::Sequence< OUString > SAL_CALL ConvDic::getConversionEntries( + ConversionDirection eDirection ) + throw (RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + if (!pFromRight.get() && eDirection == ConversionDirection_FROM_RIGHT) + return uno::Sequence< OUString >(); + + if (bNeedEntries) + Load(); + + ConvMap &rConvMap = eDirection == ConversionDirection_FROM_LEFT ? + aFromLeft : *pFromRight; + uno::Sequence< OUString > aRes( rConvMap.size() ); + OUString *pRes = aRes.getArray(); + ConvMap::iterator aIt = rConvMap.begin(); + INT32 nIdx = 0; + while (aIt != rConvMap.end()) + { + OUString aCurEntry( (*aIt).first ); + // skip duplicate entries ( duplicate = duplicate entries + // respective to the evaluated side (FROM_LEFT or FROM_RIGHT). + // Thus if FROM_LEFT is evaluated for pairs (A,B) and (A,C) + // only one entry for A will be returned in the result) + if (nIdx == 0 || !lcl_SeqHasEntry( pRes, nIdx, aCurEntry )) + pRes[ nIdx++ ] = aCurEntry; + ++aIt; + } + aRes.realloc( nIdx ); + + return aRes; +} + + +void SAL_CALL ConvDic::addEntry( + const OUString& aLeftText, + const OUString& aRightText ) + throw (IllegalArgumentException, container::ElementExistException, RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + if (bNeedEntries) + Load(); + if (HasEntry( aLeftText, aRightText )) + throw container::ElementExistException(); + AddEntry( aLeftText, aRightText ); +} + + +void SAL_CALL ConvDic::removeEntry( + const OUString& aLeftText, + const OUString& aRightText ) + throw (container::NoSuchElementException, RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + if (bNeedEntries) + Load(); + if (!HasEntry( aLeftText, aRightText )) + throw container::NoSuchElementException(); + RemoveEntry( aLeftText, aRightText ); +} + + +sal_Int16 SAL_CALL ConvDic::getMaxCharCount( ConversionDirection eDirection ) + throw (RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + if (!pFromRight.get() && eDirection == ConversionDirection_FROM_RIGHT) + { + DBG_ASSERT( nMaxRightCharCount == 0, "max right char count should be 0" ); + return 0; + } + + if (bNeedEntries) + Load(); + + if (!bMaxCharCountIsValid) + { + nMaxLeftCharCount = 0; + ConvMap::iterator aIt = aFromLeft.begin(); + while (aIt != aFromLeft.end()) + { + sal_Int16 nTmp = (sal_Int16) (*aIt).first.getLength(); + if (nTmp > nMaxLeftCharCount) + nMaxLeftCharCount = nTmp; + ++aIt; + } + + nMaxRightCharCount = 0; + if (pFromRight.get()) + { + aIt = pFromRight->begin(); + while (aIt != pFromRight->end()) + { + sal_Int16 nTmp = (sal_Int16) (*aIt).first.getLength(); + if (nTmp > nMaxRightCharCount) + nMaxRightCharCount = nTmp; + ++aIt; + } + } + + bMaxCharCountIsValid = TRUE; + } + sal_Int16 nRes = eDirection == ConversionDirection_FROM_LEFT ? + nMaxLeftCharCount : nMaxRightCharCount; + DBG_ASSERT( nRes >= 0, "invalid MaxCharCount" ); + return nRes; +} + + +void SAL_CALL ConvDic::setPropertyType( + const OUString& rLeftText, + const OUString& rRightText, + sal_Int16 nPropertyType ) + throw (container::NoSuchElementException, IllegalArgumentException, RuntimeException) +{ + sal_Bool bHasElement = HasEntry( rLeftText, rRightText); + if (!bHasElement) + throw container::NoSuchElementException(); + + // currently we assume that entries with the same left text have the + // same PropertyType even if the right text is different... + if (pConvPropType.get()) + pConvPropType->insert( PropTypeMap::value_type( rLeftText, nPropertyType ) ); + bIsModified = sal_True; +} + + +sal_Int16 SAL_CALL ConvDic::getPropertyType( + const OUString& rLeftText, + const OUString& rRightText ) + throw (container::NoSuchElementException, RuntimeException) +{ + sal_Bool bHasElement = HasEntry( rLeftText, rRightText); + if (!bHasElement) + throw container::NoSuchElementException(); + + sal_Int16 nRes = ConversionPropertyType::NOT_DEFINED; + if (pConvPropType.get()) + { + // still assuming that entries with same left text have same PropertyType + // even if they have different right text... + PropTypeMap::iterator aIt = pConvPropType->find( rLeftText ); + if (aIt != pConvPropType->end()) + nRes = (*aIt).second; + } + return nRes; +} + + +void SAL_CALL ConvDic::flush( ) + throw (RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + if (!bIsModified) + return; + + Save(); + + // notify listeners + EventObject aEvtObj; + aEvtObj.Source = uno::Reference< XFlushable >( this ); + cppu::OInterfaceIteratorHelper aIt( aFlushListeners ); + while (aIt.hasMoreElements()) + { + uno::Reference< util::XFlushListener > xRef( aIt.next(), UNO_QUERY ); + if (xRef.is()) + xRef->flushed( aEvtObj ); + } +} + + +void SAL_CALL ConvDic::addFlushListener( + const uno::Reference< util::XFlushListener >& rxListener ) + throw (RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + if (rxListener.is()) + aFlushListeners.addInterface( rxListener ); +} + + +void SAL_CALL ConvDic::removeFlushListener( + const uno::Reference< util::XFlushListener >& rxListener ) + throw (RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + if (rxListener.is()) + aFlushListeners.removeInterface( rxListener ); +} + + +OUString SAL_CALL ConvDic::getImplementationName( ) + throw (RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + return getImplementationName_Static(); +} + + +sal_Bool SAL_CALL ConvDic::supportsService( const OUString& rServiceName ) + throw (RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + sal_Bool bRes = sal_False; + if (rServiceName.equalsAscii( SN_CONV_DICTIONARY )) + bRes = sal_True; + return bRes; +} + + +uno::Sequence< OUString > SAL_CALL ConvDic::getSupportedServiceNames( ) + throw (RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + return getSupportedServiceNames_Static(); +} + + +uno::Sequence< OUString > ConvDic::getSupportedServiceNames_Static() + throw() +{ + uno::Sequence< OUString > aSNS( 1 ); + aSNS.getArray()[0] = A2OU( SN_CONV_DICTIONARY ); + return aSNS; +} + +/////////////////////////////////////////////////////////////////////////// + + |