1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_linguistic.hxx"
26 #include <tools/urlobj.hxx>
27 #include <tools/debug.hxx>
28 #include <tools/fsys.hxx>
29 #include <tools/string.hxx>
30 #include <i18npool/mslangid.hxx>
31 #include <tools/stream.hxx>
32 #include <osl/mutex.hxx>
33 #include <unotools/processfactory.hxx>
34 #include <ucbhelper/content.hxx>
35 
36 #include <cppuhelper/factory.hxx>   // helper for factories
37 #include <com/sun/star/linguistic2/XConversionDictionary.hpp>
38 #include <com/sun/star/linguistic2/ConversionDictionaryType.hpp>
39 #include <com/sun/star/linguistic2/ConversionPropertyType.hpp>
40 #include <com/sun/star/util/XFlushable.hpp>
41 #include <com/sun/star/lang/Locale.hpp>
42 #include <com/sun/star/lang/EventObject.hpp>
43 #ifndef _COM_SUN_STAR_UNO_REFERENCE_HPP_
44 #include <com/sun/star/uno/Reference.h>
45 #endif
46 #include <com/sun/star/registry/XRegistryKey.hpp>
47 #include <com/sun/star/util/XFlushListener.hpp>
48 #include <com/sun/star/io/XActiveDataSource.hpp>
49 #include <com/sun/star/document/XFilter.hpp>
50 #include <com/sun/star/beans/PropertyValue.hpp>
51 #include <xmloff/nmspmap.hxx>
52 #include <xmloff/xmlnmspe.hxx>
53 #include <unotools/streamwrap.hxx>
54 
55 #include "convdic.hxx"
56 #include "convdicxml.hxx"
57 #include "linguistic/misc.hxx"
58 #include "defs.hxx"
59 
60 using namespace std;
61 using namespace utl;
62 using namespace osl;
63 using namespace rtl;
64 using namespace com::sun::star;
65 using namespace com::sun::star::lang;
66 using namespace com::sun::star::uno;
67 using namespace com::sun::star::linguistic2;
68 using namespace linguistic;
69 
70 #define XML_NAMESPACE_TCD_STRING        "http://openoffice.org/2003/text-conversion-dictionary"
71 #define CONV_TYPE_HANGUL_HANJA          "Hangul / Hanja"
72 #define CONV_TYPE_SCHINESE_TCHINESE     "Chinese simplified / Chinese traditional"
73 
74 ///////////////////////////////////////////////////////////////////////////
75 
ConversionTypeToText(sal_Int16 nConversionType)76 static const OUString ConversionTypeToText( sal_Int16 nConversionType )
77 {
78     OUString aRes;
79     if (nConversionType == ConversionDictionaryType::HANGUL_HANJA)
80         aRes = A2OU( CONV_TYPE_HANGUL_HANJA );
81     else if (nConversionType == ConversionDictionaryType::SCHINESE_TCHINESE)
82         aRes = A2OU( CONV_TYPE_SCHINESE_TCHINESE );
83     return aRes;
84 }
85 
GetConversionTypeFromText(const String & rText)86 static sal_Int16 GetConversionTypeFromText( const String &rText )
87 {
88     sal_Int16 nRes = -1;
89     if (rText.EqualsAscii( CONV_TYPE_HANGUL_HANJA ))
90         nRes = ConversionDictionaryType::HANGUL_HANJA;
91     else if (rText.EqualsAscii( CONV_TYPE_SCHINESE_TCHINESE ))
92         nRes = ConversionDictionaryType::SCHINESE_TCHINESE;
93     return nRes;
94 }
95 
96 ///////////////////////////////////////////////////////////////////////////
97 
98 class ConvDicXMLImportContext :
99 	public SvXMLImportContext
100 {
101 public:
ConvDicXMLImportContext(ConvDicXMLImport & rImport,sal_uInt16 nPrfx,const OUString & rLName)102     ConvDicXMLImportContext(
103 			ConvDicXMLImport &rImport,
104 			sal_uInt16 nPrfx, const OUString& rLName ) :
105         SvXMLImportContext( rImport, nPrfx, rLName )
106     {
107     }
108 
GetConvDicImport() const109     const ConvDicXMLImport & GetConvDicImport() const
110     {
111         return (const ConvDicXMLImport &) GetImport();
112     }
113 
GetConvDicImport()114     ConvDicXMLImport & GetConvDicImport()
115     {
116         return (ConvDicXMLImport &) GetImport();
117     }
118 
119     // SvXMLImportContext
120     virtual void Characters( const OUString &rChars );
121     virtual SvXMLImportContext * CreateChildContext( sal_uInt16 nPrefix, const OUString& rLocalName, const uno::Reference< xml::sax::XAttributeList > &rxAttrList);
122 };
123 
124 
125 class ConvDicXMLDictionaryContext_Impl :
126 	public ConvDicXMLImportContext
127 {
128     sal_Int16		nLanguage;
129     sal_Int16   nConversionType;
130 
131 public:
ConvDicXMLDictionaryContext_Impl(ConvDicXMLImport & rImport,sal_uInt16 nPrefix,const OUString & rLName)132     ConvDicXMLDictionaryContext_Impl( ConvDicXMLImport &rImport,
133 			sal_uInt16 nPrefix, const OUString& rLName) :
134         ConvDicXMLImportContext( rImport, nPrefix, rLName )
135     {
136         nLanguage = LANGUAGE_NONE;
137         nConversionType = -1;
138     }
139 
140     // SvXMLImportContext
141     virtual void StartElement( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList );
142     virtual SvXMLImportContext * CreateChildContext( sal_uInt16 nPrefix, const OUString& rLocalName, const uno::Reference< xml::sax::XAttributeList > &rxAttrList );
143 
GetLanguage() const144     sal_Int16		GetLanguage() const			{ return nLanguage; }
GetConversionType() const145 	sal_Int16   GetConversionType() const	{ return nConversionType; }
146 };
147 
148 
149 class ConvDicXMLEntryTextContext_Impl :
150 	public ConvDicXMLImportContext
151 {
152     OUString    aLeftText;
153     sal_Int16   nPropertyType;  // used for Chinese simplified/traditional conversion
154 	ConvDicXMLDictionaryContext_Impl	&rDicContext;
155 
156 public:
ConvDicXMLEntryTextContext_Impl(ConvDicXMLImport & rImport,sal_uInt16 nPrefix,const OUString & rLName,ConvDicXMLDictionaryContext_Impl & rParentContext)157     ConvDicXMLEntryTextContext_Impl(
158 			ConvDicXMLImport &rImport,
159 			sal_uInt16 nPrefix, const OUString& rLName,
160 			ConvDicXMLDictionaryContext_Impl &rParentContext ) :
161         ConvDicXMLImportContext( rImport, nPrefix, rLName ),
162         nPropertyType( ConversionPropertyType::NOT_DEFINED ),
163         rDicContext( rParentContext )
164     {
165     }
166 
167     // SvXMLImportContext
168     virtual void StartElement( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList );
169     virtual SvXMLImportContext * CreateChildContext( sal_uInt16 nPrefix, const OUString& rLocalName, const uno::Reference< xml::sax::XAttributeList > &rxAttrList );
170 
GetLeftText() const171 	const OUString &	GetLeftText() const	{ return aLeftText; }
GetPropertyType() const172     sal_Int16           GetPropertyType() const { return nPropertyType; }
SetPropertyType(sal_Int16 nVal)173     void                SetPropertyType( sal_Int16 nVal )   { nPropertyType = nVal; }
174 };
175 
176 
177 class ConvDicXMLRightTextContext_Impl :
178 	public ConvDicXMLImportContext
179 {
180     OUString aRightText;
181 	ConvDicXMLEntryTextContext_Impl &rEntryContext;
182 
183 public:
ConvDicXMLRightTextContext_Impl(ConvDicXMLImport & rImport,sal_uInt16 nPrefix,const OUString & rLName,ConvDicXMLEntryTextContext_Impl & rParentContext)184     ConvDicXMLRightTextContext_Impl(
185 			ConvDicXMLImport &rImport,
186 			sal_uInt16 nPrefix, const OUString& rLName,
187 			ConvDicXMLEntryTextContext_Impl &rParentContext ) :
188         ConvDicXMLImportContext( rImport, nPrefix, rLName ),
189 		rEntryContext( rParentContext )
190     {
191     }
192 
193     // SvXMLImportContext
194     virtual void EndElement();
195     virtual SvXMLImportContext * CreateChildContext( sal_uInt16 nPrefix, const OUString& rLocalName, const uno::Reference< xml::sax::XAttributeList > &rxAttrList );
196     virtual void Characters( const OUString &rChars );
197 
GetRightText() const198 	const OUString &	GetRightText() const	{ return aRightText; }
GetLeftText() const199 	const OUString &	GetLeftText() const		{ return rEntryContext.GetLeftText(); }
GetDic()200 	ConvDic *			GetDic()				{ return GetConvDicImport().GetDic(); }
201 };
202 
203 ///////////////////////////////////////////////////////////////////////////
204 
Characters(const OUString &)205 void ConvDicXMLImportContext::Characters(const OUString & /*rChars*/)
206 {
207     /*
208     Whitespace occurring within the content of token elements is "trimmed"
209     from the ends (i.e. all whitespace at the beginning and end of the
210     content is removed), and "collapsed" internally (i.e. each sequence of
211     1 or more whitespace characters is replaced with one blank character).
212     */
213     //collapsing not done yet!
214 
215     // warning-free code: since the result is not used there is no need for trimming...
216     //const OUString &rChars2 = rChars.trim();
217 }
218 
CreateChildContext(sal_uInt16 nPrefix,const OUString & rLocalName,const uno::Reference<xml::sax::XAttributeList> &)219 SvXMLImportContext * ConvDicXMLImportContext::CreateChildContext(
220         sal_uInt16 nPrefix, const OUString& rLocalName,
221         const uno::Reference< xml::sax::XAttributeList > & /*rxAttrList*/ )
222 {
223     SvXMLImportContext *pContext = 0;
224     if (nPrefix == XML_NAMESPACE_TCD && rLocalName.equalsAscii( "text-conversion-dictionary" ))
225         pContext = new ConvDicXMLDictionaryContext_Impl( GetConvDicImport(), nPrefix, rLocalName );
226 	else
227         pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
228     return pContext;
229 }
230 
231 ////////////////////////////////////////
232 
StartElement(const uno::Reference<xml::sax::XAttributeList> & rxAttrList)233 void ConvDicXMLDictionaryContext_Impl::StartElement(
234     const uno::Reference< xml::sax::XAttributeList > &rxAttrList )
235 {
236     sal_Int16 nAttrCount = rxAttrList.is() ? rxAttrList->getLength() : 0;
237     for (sal_Int16 i = 0;  i < nAttrCount;  ++i)
238     {
239         OUString aAttrName = rxAttrList->getNameByIndex(i);
240         OUString aLocalName;
241         sal_uInt16 nPrefix = GetImport().GetNamespaceMap().
242                                     GetKeyByAttrName( aAttrName, &aLocalName );
243         OUString aValue = rxAttrList->getValueByIndex(i);
244 
245         if (nPrefix == XML_NAMESPACE_TCD && aLocalName.equalsAscii( "lang" ))
246 			nLanguage = MsLangId::convertIsoStringToLanguage( aValue );
247         else if (nPrefix == XML_NAMESPACE_TCD && aLocalName.equalsAscii( "conversion-type" ))
248 			nConversionType = GetConversionTypeFromText( aValue );
249     }
250     GetConvDicImport().SetLanguage( nLanguage );
251 	GetConvDicImport().SetConversionType( nConversionType );
252 
253 	//!! hack to stop the parser from reading the rest of the file  !!
254 	//!! when only the header (language, conversion type) is needed !!
255 //   if (GetConvDicImport().GetDic() == 0)
256 //        throw uno::RuntimeException();
257 }
258 
CreateChildContext(sal_uInt16 nPrefix,const OUString & rLocalName,const uno::Reference<xml::sax::XAttributeList> &)259 SvXMLImportContext * ConvDicXMLDictionaryContext_Impl::CreateChildContext(
260         sal_uInt16 nPrefix, const OUString& rLocalName,
261         const uno::Reference< xml::sax::XAttributeList > & /*rxAttrList*/ )
262 {
263 	SvXMLImportContext *pContext = 0;
264 	if (nPrefix == XML_NAMESPACE_TCD  &&  rLocalName.equalsAscii( "entry" ))
265 		pContext = new ConvDicXMLEntryTextContext_Impl( GetConvDicImport(), nPrefix, rLocalName, *this );
266 	else
267 		pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
268     return pContext;
269 }
270 
271 ////////////////////////////////////////
272 
CreateChildContext(sal_uInt16 nPrefix,const OUString & rLocalName,const uno::Reference<xml::sax::XAttributeList> &)273 SvXMLImportContext * ConvDicXMLEntryTextContext_Impl::CreateChildContext(
274         sal_uInt16 nPrefix, const OUString& rLocalName,
275         const uno::Reference< xml::sax::XAttributeList > & /*rxAttrList*/ )
276 {
277 	SvXMLImportContext *pContext = 0;
278 	if (nPrefix == XML_NAMESPACE_TCD  &&  rLocalName.equalsAscii( "right-text" ))
279 		pContext = new ConvDicXMLRightTextContext_Impl( GetConvDicImport(), nPrefix, rLocalName, *this );
280 	else
281 		pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
282     return pContext;
283 }
284 
StartElement(const uno::Reference<xml::sax::XAttributeList> & rxAttrList)285 void ConvDicXMLEntryTextContext_Impl::StartElement(
286 		const uno::Reference< xml::sax::XAttributeList >& rxAttrList )
287 {
288     sal_Int16 nAttrCount = rxAttrList.is() ? rxAttrList->getLength() : 0;
289     for (sal_Int16 i = 0;  i < nAttrCount;  ++i)
290     {
291         OUString aAttrName = rxAttrList->getNameByIndex(i);
292         OUString aLocalName;
293         sal_uInt16 nPrefix = GetImport().GetNamespaceMap().
294                                     GetKeyByAttrName( aAttrName, &aLocalName );
295         OUString aValue = rxAttrList->getValueByIndex(i);
296 
297         if (nPrefix == XML_NAMESPACE_TCD && aLocalName.equalsAscii( "left-text" ))
298 			aLeftText = aValue;
299         if (nPrefix == XML_NAMESPACE_TCD && aLocalName.equalsAscii( "property-type" ))
300             nPropertyType = (sal_Int16) aValue.toInt32();
301     }
302 }
303 
304 ////////////////////////////////////////
305 
CreateChildContext(sal_uInt16 nPrefix,const OUString & rLocalName,const uno::Reference<xml::sax::XAttributeList> &)306 SvXMLImportContext * ConvDicXMLRightTextContext_Impl::CreateChildContext(
307         sal_uInt16 nPrefix, const OUString& rLocalName,
308         const uno::Reference< xml::sax::XAttributeList > & /*rxAttrList*/ )
309 {
310     // leaf: return default (empty) context
311     SvXMLImportContext *pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
312     return pContext;
313 }
314 
Characters(const OUString & rChars)315 void ConvDicXMLRightTextContext_Impl::Characters( const OUString &rChars )
316 {
317     aRightText += rChars;
318 }
319 
EndElement()320 void ConvDicXMLRightTextContext_Impl::EndElement()
321 {
322 	ConvDic *pDic = GetDic();
323 	if (pDic)
324 		pDic->AddEntry( GetLeftText(), GetRightText() );
325 }
326 
327 
328 ///////////////////////////////////////////////////////////////////////////
329 
Export()330 sal_Bool ConvDicXMLExport::Export()
331 {
332     sal_Bool bRet = sal_False;
333 
334     uno::Reference< document::XExporter > xExporter( this );
335     uno::Reference< document::XFilter > xFilter( xExporter, UNO_QUERY );
336     uno::Sequence< beans::PropertyValue > aProps(0);
337     xFilter->filter( aProps );      // calls exportDoc implicitly
338 
339     return bRet = bSuccess;
340 }
341 
342 
exportDoc(enum::xmloff::token::XMLTokenEnum)343 sal_uInt32 ConvDicXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum /*eClass*/ )
344 {
345     _GetNamespaceMap().Add( A2OU( "tcd" ),
346             A2OU( XML_NAMESPACE_TCD_STRING ), XML_NAMESPACE_TCD );
347 
348     GetDocHandler()->startDocument();
349 
350     // Add xmlns line and some other arguments
351     AddAttribute( _GetNamespaceMap().GetAttrNameByKey( XML_NAMESPACE_TCD ),
352                   _GetNamespaceMap().GetNameByKey( XML_NAMESPACE_TCD ) );
353     AddAttributeASCII( XML_NAMESPACE_TCD, "package", "org.openoffice.Office" );
354 
355     OUString aIsoLang( MsLangId::convertLanguageToIsoString( rDic.nLanguage ) );
356     AddAttribute( XML_NAMESPACE_TCD, "lang", aIsoLang );
357     OUString aConvType( ConversionTypeToText( rDic.nConversionType ) );
358     AddAttribute( XML_NAMESPACE_TCD, "conversion-type", aConvType );
359 
360     //!! block necessary in order to have SvXMLElementExport d-tor called
361     //!! before the call to endDocument
362     {
363         SvXMLElementExport aRoot( *this, XML_NAMESPACE_TCD, "text-conversion-dictionary", sal_True, sal_True );
364         _ExportContent();
365     }
366 
367     GetDocHandler()->endDocument();
368 
369     bSuccess = sal_True;
370     return 0;
371 }
372 
373 
_ExportContent()374 void ConvDicXMLExport::_ExportContent()
375 {
376     // aquire sorted list of all keys
377     ConvMapKeySet   aKeySet;
378     ConvMap::iterator aIt;
379     for (aIt = rDic.aFromLeft.begin();  aIt != rDic.aFromLeft.end();  ++aIt)
380         aKeySet.insert( (*aIt).first );
381 
382     ConvMapKeySet::iterator aKeyIt;
383     for (aKeyIt = aKeySet.begin();  aKeyIt != aKeySet.end();  ++aKeyIt)
384     {
385         OUString aLeftText( *aKeyIt );
386         AddAttribute( XML_NAMESPACE_TCD, "left-text", aLeftText );
387         if (rDic.pConvPropType.get())   // property-type list available?
388         {
389             sal_Int16 nPropertyType = -1;
390             PropTypeMap::iterator aIt2 = rDic.pConvPropType->find( aLeftText );
391             if (aIt2 != rDic.pConvPropType->end())
392                 nPropertyType = (*aIt2).second;
393             DBG_ASSERT( nPropertyType, "property-type not found" );
394             if (nPropertyType == -1)
395                 nPropertyType = ConversionPropertyType::NOT_DEFINED;
396             AddAttribute( XML_NAMESPACE_TCD, "property-type", OUString::valueOf( (sal_Int32) nPropertyType ) );
397         }
398         SvXMLElementExport aEntryMain( *this, XML_NAMESPACE_TCD,
399                 "entry" , sal_True, sal_True );
400 
401         pair< ConvMap::iterator, ConvMap::iterator > aRange =
402                 rDic.aFromLeft.equal_range( *aKeyIt );
403         for (aIt = aRange.first;  aIt != aRange.second;  ++aIt)
404         {
405             DBG_ASSERT( *aKeyIt == (*aIt).first, "key <-> entry mismatch" );
406             OUString aRightText( (*aIt).second );
407             SvXMLElementExport aEntryRightText( *this, XML_NAMESPACE_TCD,
408                     "right-text" , sal_True, sal_False );
409             Characters( aRightText );
410         }
411     }
412 }
413 
getImplementationName()414 ::rtl::OUString SAL_CALL ConvDicXMLExport::getImplementationName()
415     throw( uno::RuntimeException )
416 {
417     return A2OU( "com.sun.star.lingu2.ConvDicXMLExport" );
418 }
419 
420 ///////////////////////////////////////////////////////////////////////////
421 
startDocument(void)422 void SAL_CALL ConvDicXMLImport::startDocument(void)
423     throw( xml::sax::SAXException, uno::RuntimeException )
424 {
425     // register namespace at first possible opportunity
426     GetNamespaceMap().Add( A2OU( "tcd" ),
427             A2OU( XML_NAMESPACE_TCD_STRING ), XML_NAMESPACE_TCD );
428     SvXMLImport::startDocument();
429 }
430 
endDocument(void)431 void SAL_CALL ConvDicXMLImport::endDocument(void)
432     throw( xml::sax::SAXException, uno::RuntimeException )
433 {
434     SvXMLImport::endDocument();
435 }
436 
CreateContext(sal_uInt16 nPrefix,const rtl::OUString & rLocalName,const uno::Reference<xml::sax::XAttributeList> &)437 SvXMLImportContext * ConvDicXMLImport::CreateContext(
438         sal_uInt16 nPrefix,
439         const rtl::OUString &rLocalName,
440         const uno::Reference < xml::sax::XAttributeList > & /*rxAttrList*/ )
441 {
442 	SvXMLImportContext *pContext = 0;
443     if (nPrefix == XML_NAMESPACE_TCD && rLocalName.equalsAscii( "text-conversion-dictionary" ))
444 		pContext = new ConvDicXMLDictionaryContext_Impl( *this, nPrefix, rLocalName );
445 	else
446 		pContext = new SvXMLImportContext( *this, nPrefix, rLocalName );
447 	return pContext;
448 }
449 
450 
getImplementationName()451 OUString SAL_CALL ConvDicXMLImport::getImplementationName()
452     throw( uno::RuntimeException )
453 {
454     return A2OU( "com.sun.star.lingu2.ConvDicXMLImport" );
455 }
456 
457 ///////////////////////////////////////////////////////////////////////////
458 
459