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