1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <tools/debug.hxx>
21 #include <i18nlangtag/languagetag.hxx>
22 
23 #include <com/sun/star/linguistic2/ConversionDictionaryType.hpp>
24 #include <com/sun/star/linguistic2/ConversionPropertyType.hpp>
25 #include <com/sun/star/lang/Locale.hpp>
26 #include <com/sun/star/uno/Reference.h>
27 #include <com/sun/star/document/XFilter.hpp>
28 #include <com/sun/star/beans/PropertyValue.hpp>
29 #include <xmloff/nmspmap.hxx>
30 #include <xmloff/xmlnmspe.hxx>
31 #include <unotools/streamwrap.hxx>
32 
33 #include "convdic.hxx"
34 #include "convdicxml.hxx"
35 #include <linguistic/misc.hxx>
36 
37 using namespace std;
38 using namespace utl;
39 using namespace com::sun::star;
40 using namespace com::sun::star::lang;
41 using namespace com::sun::star::uno;
42 using namespace com::sun::star::linguistic2;
43 using namespace linguistic;
44 
45 
46 #define XML_NAMESPACE_TCD_STRING        "http://openoffice.org/2003/text-conversion-dictionary"
47 #define CONV_TYPE_HANGUL_HANJA          "Hangul / Hanja"
48 #define CONV_TYPE_SCHINESE_TCHINESE     "Chinese simplified / Chinese traditional"
49 
50 
ConversionTypeToText(sal_Int16 nConversionType)51 static OUString ConversionTypeToText( sal_Int16 nConversionType )
52 {
53     OUString aRes;
54     if (nConversionType == ConversionDictionaryType::HANGUL_HANJA)
55         aRes = CONV_TYPE_HANGUL_HANJA;
56     else if (nConversionType == ConversionDictionaryType::SCHINESE_TCHINESE)
57         aRes = CONV_TYPE_SCHINESE_TCHINESE;
58     return aRes;
59 }
60 
GetConversionTypeFromText(const OUString & rText)61 static sal_Int16 GetConversionTypeFromText( const OUString &rText )
62 {
63     sal_Int16 nRes = -1;
64     if (rText == CONV_TYPE_HANGUL_HANJA)
65         nRes = ConversionDictionaryType::HANGUL_HANJA;
66     else if (rText == CONV_TYPE_SCHINESE_TCHINESE)
67         nRes = ConversionDictionaryType::SCHINESE_TCHINESE;
68     return nRes;
69 }
70 
71 
72 class ConvDicXMLImportContext :
73     public SvXMLImportContext
74 {
75 public:
ConvDicXMLImportContext(ConvDicXMLImport & rImport)76     ConvDicXMLImportContext( ConvDicXMLImport &rImport ) :
77         SvXMLImportContext( rImport )
78     {
79     }
80 
GetConvDicImport()81     ConvDicXMLImport & GetConvDicImport()
82     {
83         return static_cast<ConvDicXMLImport &>(GetImport());
84     }
85 
86     // SvXMLImportContext
87     virtual void Characters( const OUString &rChars ) override;
88     virtual css::uno::Reference<XFastContextHandler> SAL_CALL createFastChildContext(
89         sal_Int32 Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override;
90 };
91 
92 
93 class ConvDicXMLDictionaryContext_Impl :
94     public ConvDicXMLImportContext
95 {
96     LanguageType nLanguage;
97     sal_Int16    nConversionType;
98 
99 public:
ConvDicXMLDictionaryContext_Impl(ConvDicXMLImport & rImport)100     ConvDicXMLDictionaryContext_Impl( ConvDicXMLImport &rImport ) :
101         ConvDicXMLImportContext( rImport )
102     {
103         nLanguage = LANGUAGE_NONE;
104         nConversionType = -1;
105     }
106 
107     // SvXMLImportContext
108     virtual void SAL_CALL startFastElement( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override;
109     virtual css::uno::Reference<XFastContextHandler> SAL_CALL createFastChildContext(
110         sal_Int32 Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override;
111 };
112 
113 
114 class ConvDicXMLEntryTextContext_Impl :
115     public ConvDicXMLImportContext
116 {
117     OUString    aLeftText;
118 
119 public:
ConvDicXMLEntryTextContext_Impl(ConvDicXMLImport & rImport)120     ConvDicXMLEntryTextContext_Impl( ConvDicXMLImport &rImport ) :
121         ConvDicXMLImportContext( rImport )
122     {
123     }
124 
125     // SvXMLImportContext
126     virtual void SAL_CALL startFastElement( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override;
127     virtual css::uno::Reference<XFastContextHandler> SAL_CALL createFastChildContext(
128         sal_Int32 Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override;
129 
GetLeftText() const130     const OUString &    GetLeftText() const { return aLeftText; }
131 };
132 
133 
134 class ConvDicXMLRightTextContext_Impl :
135     public ConvDicXMLImportContext
136 {
137     OUString aRightText;
138     ConvDicXMLEntryTextContext_Impl &rEntryContext;
139 
140 public:
ConvDicXMLRightTextContext_Impl(ConvDicXMLImport & rImport,ConvDicXMLEntryTextContext_Impl & rParentContext)141     ConvDicXMLRightTextContext_Impl(
142             ConvDicXMLImport &rImport,
143             ConvDicXMLEntryTextContext_Impl &rParentContext ) :
144         ConvDicXMLImportContext( rImport ),
145         rEntryContext( rParentContext )
146     {
147     }
148 
149     // SvXMLImportContext
150     virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override;
151     virtual void Characters( const OUString &rChars ) override;
152 
GetRightText() const153     const OUString &    GetRightText() const    { return aRightText; }
GetLeftText() const154     const OUString &    GetLeftText() const     { return rEntryContext.GetLeftText(); }
155 };
156 
157 
Characters(const OUString &)158 void ConvDicXMLImportContext::Characters(const OUString & /*rChars*/)
159 {
160     /*
161     Whitespace occurring within the content of token elements is "trimmed"
162     from the ends (i.e. all whitespace at the beginning and end of the
163     content is removed), and "collapsed" internally (i.e. each sequence of
164     1 or more whitespace characters is replaced with one blank character).
165     */
166     //collapsing not done yet!
167 
168 }
169 
createFastChildContext(sal_Int32 Element,const css::uno::Reference<css::xml::sax::XFastAttributeList> &)170 css::uno::Reference<XFastContextHandler> ConvDicXMLImportContext::createFastChildContext(
171         sal_Int32 Element,
172         const css::uno::Reference< css::xml::sax::XFastAttributeList > & /*xAttrList*/ )
173 {
174     if ( Element == ConvDicXMLToken::TEXT_CONVERSION_DICTIONARY )
175         return new ConvDicXMLDictionaryContext_Impl( GetConvDicImport() );
176     else
177         return new SvXMLImportContext( GetImport() );
178 }
179 
180 
startFastElement(sal_Int32,const css::uno::Reference<css::xml::sax::XFastAttributeList> & rxAttrList)181 void ConvDicXMLDictionaryContext_Impl::startFastElement( sal_Int32 /*nElement*/,
182     const css::uno::Reference< css::xml::sax::XFastAttributeList >& rxAttrList )
183 {
184     if ( rxAttrList.is() )
185     {
186         sax_fastparser::FastAttributeList *pAttribList =
187             sax_fastparser::FastAttributeList::castToFastAttributeList( rxAttrList );
188 
189         for (auto &aIter : *pAttribList)
190         {
191             switch (aIter.getToken())
192             {
193                 case XML_NAMESPACE_TCD | XML_LANG:
194                     nLanguage = LanguageTag::convertToLanguageType( aIter.toString() );
195                 break;
196                 case XML_NAMESPACE_TCD | XML_CONVERSION_TYPE:
197                     nConversionType = GetConversionTypeFromText( aIter.toString() );
198                 break;
199                 default:
200                     ;
201             }
202         }
203     }
204     GetConvDicImport().SetLanguage( nLanguage );
205     GetConvDicImport().SetConversionType( nConversionType );
206 
207 }
208 
createFastChildContext(sal_Int32 Element,const css::uno::Reference<css::xml::sax::XFastAttributeList> &)209 css::uno::Reference<XFastContextHandler> ConvDicXMLDictionaryContext_Impl::createFastChildContext(
210         sal_Int32 Element,
211         const css::uno::Reference< css::xml::sax::XFastAttributeList > & /*xAttrList*/ )
212 {
213     if ( Element == ConvDicXMLToken::ENTRY )
214         return new ConvDicXMLEntryTextContext_Impl( GetConvDicImport() );
215     else
216         return new SvXMLImportContext(GetImport());
217 }
218 
createFastChildContext(sal_Int32 Element,const css::uno::Reference<css::xml::sax::XFastAttributeList> &)219 css::uno::Reference<XFastContextHandler> ConvDicXMLEntryTextContext_Impl::createFastChildContext(
220         sal_Int32 Element,
221         const css::uno::Reference< css::xml::sax::XFastAttributeList > & /*xAttrList*/ )
222 {
223     if ( Element == ConvDicXMLToken::RIGHT_TEXT )
224         return new ConvDicXMLRightTextContext_Impl( GetConvDicImport(), *this );
225     else
226         return new SvXMLImportContext(GetImport());
227 }
228 
startFastElement(sal_Int32,const css::uno::Reference<css::xml::sax::XFastAttributeList> & rxAttrList)229 void ConvDicXMLEntryTextContext_Impl::startFastElement(
230     sal_Int32 /*Element*/,
231     const css::uno::Reference< css::xml::sax::XFastAttributeList >& rxAttrList )
232 {
233     if ( rxAttrList.is() )
234     {
235         sax_fastparser::FastAttributeList *pAttribList =
236             sax_fastparser::FastAttributeList::castToFastAttributeList( rxAttrList );
237 
238         for (auto &aIter : *pAttribList)
239         {
240             switch (aIter.getToken())
241             {
242                 case XML_NAMESPACE_TCD | XML_LEFT_TEXT:
243                     aLeftText = aIter.toString();
244                     break;
245                 default:
246                     ;
247             }
248         }
249     }
250 }
251 
252 
Characters(const OUString & rChars)253 void ConvDicXMLRightTextContext_Impl::Characters( const OUString &rChars )
254 {
255     aRightText += rChars;
256 }
257 
endFastElement(sal_Int32)258 void ConvDicXMLRightTextContext_Impl::endFastElement( sal_Int32 /*nElement*/ )
259 {
260     ConvDic *pDic = GetConvDicImport().GetDic();
261     if (pDic)
262         pDic->AddEntry( GetLeftText(), GetRightText() );
263 }
264 
265 
Export()266 bool ConvDicXMLExport::Export()
267 {
268     uno::Reference< document::XExporter > xExporter( this );
269     uno::Reference< document::XFilter > xFilter( xExporter, UNO_QUERY );
270     uno::Sequence< beans::PropertyValue > aProps(0);
271     xFilter->filter( aProps );      // calls exportDoc implicitly
272 
273     return bSuccess;
274 }
275 
276 
exportDoc(enum::xmloff::token::XMLTokenEnum)277 ErrCode ConvDicXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum /*eClass*/ )
278 {
279     GetNamespaceMap_().Add( "tcd",
280             XML_NAMESPACE_TCD_STRING, XML_NAMESPACE_TCD );
281 
282     GetDocHandler()->startDocument();
283 
284     // Add xmlns line and some other arguments
285     AddAttribute( GetNamespaceMap_().GetAttrNameByKey( XML_NAMESPACE_TCD ),
286                   GetNamespaceMap_().GetNameByKey( XML_NAMESPACE_TCD ) );
287     AddAttributeASCII( XML_NAMESPACE_TCD, "package", "org.openoffice.Office" );
288 
289     OUString aIsoLang( LanguageTag::convertToBcp47( rDic.nLanguage ) );
290     AddAttribute( XML_NAMESPACE_TCD, "lang", aIsoLang );
291     OUString aConvType( ConversionTypeToText( rDic.nConversionType ) );
292     AddAttribute( XML_NAMESPACE_TCD, "conversion-type", aConvType );
293 
294     //!! block necessary in order to have SvXMLElementExport d-tor called
295     //!! before the call to endDocument
296     {
297         SvXMLElementExport aRoot( *this, XML_NAMESPACE_TCD, "text-conversion-dictionary", true, true );
298         ExportContent_();
299     }
300 
301     GetDocHandler()->endDocument();
302 
303     bSuccess = true;
304     return ERRCODE_NONE;
305 }
306 
307 
ExportContent_()308 void ConvDicXMLExport::ExportContent_()
309 {
310     // acquire sorted list of all keys
311     ConvMapKeySet   aKeySet;
312     for (auto const& elem : rDic.aFromLeft)
313         aKeySet.insert( elem.first );
314 
315     for (const OUString& aLeftText : aKeySet)
316     {
317         AddAttribute( XML_NAMESPACE_TCD, "left-text", aLeftText );
318         if (rDic.pConvPropType) // property-type list available?
319         {
320             sal_Int16 nPropertyType = -1;
321             PropTypeMap::iterator aIt2 = rDic.pConvPropType->find( aLeftText );
322             if (aIt2 != rDic.pConvPropType->end())
323                 nPropertyType = (*aIt2).second;
324             DBG_ASSERT( nPropertyType, "property-type not found" );
325             if (nPropertyType == -1)
326                 nPropertyType = ConversionPropertyType::NOT_DEFINED;
327             AddAttribute( XML_NAMESPACE_TCD, "property-type", OUString::number(  nPropertyType ) );
328         }
329         SvXMLElementExport aEntryMain( *this, XML_NAMESPACE_TCD,
330                 "entry" , true, true );
331 
332         pair< ConvMap::iterator, ConvMap::iterator > aRange =
333                 rDic.aFromLeft.equal_range(aLeftText);
334         for (auto aIt = aRange.first;  aIt != aRange.second;  ++aIt)
335         {
336             DBG_ASSERT( aLeftText == (*aIt).first, "key <-> entry mismatch" );
337             OUString aRightText( (*aIt).second );
338             SvXMLElementExport aEntryRightText( *this, XML_NAMESPACE_TCD,
339                     "right-text" , true, false );
340             Characters( aRightText );
341         }
342     }
343 }
344 
345     //!!  see comment for pDic member
ConvDicXMLImport(ConvDic * pConvDic)346 ConvDicXMLImport::ConvDicXMLImport( ConvDic *pConvDic ) :
347     SvXMLImport ( comphelper::getProcessComponentContext(), "com.sun.star.lingu2.ConvDicXMLImport", SvXMLImportFlags::ALL ),
348     pDic        ( pConvDic )
349 {
350     nLanguage       = LANGUAGE_NONE;
351     nConversionType = -1;
352     GetNamespaceMap().Add( GetXMLToken(XML_NP_TCD), GetXMLToken(XML_N_TCD), XML_NAMESPACE_TCD);
353 }
354 
CreateFastContext(sal_Int32 Element,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)355 SvXMLImportContext * ConvDicXMLImport::CreateFastContext(
356         sal_Int32 Element,
357         const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList )
358 {
359     if( Element == ConvDicXMLToken::TEXT_CONVERSION_DICTIONARY )
360         return new ConvDicXMLDictionaryContext_Impl( *this );
361     else
362         return SvXMLImport::CreateFastContext( Element, xAttrList );
363 }
364 
365 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
366