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