/src/libreoffice/linguistic/source/convdicxml.cxx
Line | Count | Source (jump to first uncovered line) |
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/namespacemap.hxx> |
30 | | #include <xmloff/xmlnamespace.hxx> |
31 | | #include <unotools/streamwrap.hxx> |
32 | | |
33 | | #include "convdic.hxx" |
34 | | #include "convdicxml.hxx" |
35 | | #include <linguistic/misc.hxx> |
36 | | |
37 | | using namespace com::sun::star; |
38 | | using namespace com::sun::star::uno; |
39 | | using namespace com::sun::star::linguistic2; |
40 | | |
41 | | |
42 | | constexpr OUStringLiteral XML_NAMESPACE_TCD_STRING = u"http://openoffice.org/2003/text-conversion-dictionary"; |
43 | | constexpr OUString CONV_TYPE_HANGUL_HANJA = u"Hangul / Hanja"_ustr; |
44 | | constexpr OUString CONV_TYPE_SCHINESE_TCHINESE = u"Chinese simplified / Chinese traditional"_ustr; |
45 | | |
46 | | |
47 | | static OUString ConversionTypeToText( sal_Int16 nConversionType ) |
48 | 0 | { |
49 | 0 | OUString aRes; |
50 | 0 | if (nConversionType == ConversionDictionaryType::HANGUL_HANJA) |
51 | 0 | aRes = CONV_TYPE_HANGUL_HANJA; |
52 | 0 | else if (nConversionType == ConversionDictionaryType::SCHINESE_TCHINESE) |
53 | 0 | aRes = CONV_TYPE_SCHINESE_TCHINESE; |
54 | 0 | return aRes; |
55 | 0 | } |
56 | | |
57 | | static sal_Int16 GetConversionTypeFromText( std::u16string_view rText ) |
58 | 0 | { |
59 | 0 | sal_Int16 nRes = -1; |
60 | 0 | if (rText == CONV_TYPE_HANGUL_HANJA) |
61 | 0 | nRes = ConversionDictionaryType::HANGUL_HANJA; |
62 | 0 | else if (rText == CONV_TYPE_SCHINESE_TCHINESE) |
63 | 0 | nRes = ConversionDictionaryType::SCHINESE_TCHINESE; |
64 | 0 | return nRes; |
65 | 0 | } |
66 | | |
67 | | namespace { |
68 | | |
69 | | class ConvDicXMLImportContext : |
70 | | public SvXMLImportContext |
71 | | { |
72 | | public: |
73 | | ConvDicXMLImportContext( ConvDicXMLImport &rImport ) : |
74 | 0 | SvXMLImportContext( rImport ) |
75 | 0 | { |
76 | 0 | } |
77 | | |
78 | | ConvDicXMLImport & GetConvDicImport() |
79 | 0 | { |
80 | 0 | return static_cast<ConvDicXMLImport &>(GetImport()); |
81 | 0 | } |
82 | | |
83 | | // SvXMLImportContext |
84 | | virtual css::uno::Reference<XFastContextHandler> SAL_CALL createFastChildContext( |
85 | | sal_Int32 Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override; |
86 | | }; |
87 | | |
88 | | |
89 | | class ConvDicXMLDictionaryContext_Impl : |
90 | | public ConvDicXMLImportContext |
91 | | { |
92 | | LanguageType nLanguage; |
93 | | sal_Int16 nConversionType; |
94 | | |
95 | | public: |
96 | | ConvDicXMLDictionaryContext_Impl( ConvDicXMLImport &rImport ) : |
97 | 0 | ConvDicXMLImportContext( rImport ), |
98 | 0 | nLanguage(LANGUAGE_NONE), nConversionType(-1) |
99 | 0 | { |
100 | 0 | } |
101 | | |
102 | | // SvXMLImportContext |
103 | | virtual void SAL_CALL startFastElement( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override; |
104 | | virtual css::uno::Reference<XFastContextHandler> SAL_CALL createFastChildContext( |
105 | | sal_Int32 Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override; |
106 | | }; |
107 | | |
108 | | |
109 | | class ConvDicXMLEntryTextContext_Impl : |
110 | | public ConvDicXMLImportContext |
111 | | { |
112 | | OUString aLeftText; |
113 | | |
114 | | public: |
115 | | ConvDicXMLEntryTextContext_Impl( ConvDicXMLImport &rImport ) : |
116 | 0 | ConvDicXMLImportContext( rImport ) |
117 | 0 | { |
118 | 0 | } |
119 | | |
120 | | // SvXMLImportContext |
121 | | virtual void SAL_CALL startFastElement( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override; |
122 | | virtual css::uno::Reference<XFastContextHandler> SAL_CALL createFastChildContext( |
123 | | sal_Int32 Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override; |
124 | | |
125 | 0 | const OUString & GetLeftText() const { return aLeftText; } |
126 | | }; |
127 | | |
128 | | |
129 | | class ConvDicXMLRightTextContext_Impl : |
130 | | public ConvDicXMLImportContext |
131 | | { |
132 | | OUString aRightText; |
133 | | ConvDicXMLEntryTextContext_Impl &rEntryContext; |
134 | | |
135 | | public: |
136 | | ConvDicXMLRightTextContext_Impl( |
137 | | ConvDicXMLImport &rImport, |
138 | | ConvDicXMLEntryTextContext_Impl &rParentContext ) : |
139 | 0 | ConvDicXMLImportContext( rImport ), |
140 | 0 | rEntryContext( rParentContext ) |
141 | 0 | { |
142 | 0 | } |
143 | | |
144 | | // SvXMLImportContext |
145 | | virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override; |
146 | | virtual void SAL_CALL characters( const OUString &rChars ) override; |
147 | | }; |
148 | | |
149 | | } |
150 | | |
151 | | //void ConvDicXMLImportContext::characters(const OUString & /*rChars*/) |
152 | | //{ |
153 | | /* |
154 | | Whitespace occurring within the content of token elements is "trimmed" |
155 | | from the ends (i.e. all whitespace at the beginning and end of the |
156 | | content is removed), and "collapsed" internally (i.e. each sequence of |
157 | | 1 or more whitespace characters is replaced with one blank character). |
158 | | */ |
159 | | //collapsing not done yet! |
160 | | |
161 | | //} |
162 | | |
163 | | css::uno::Reference<XFastContextHandler> ConvDicXMLImportContext::createFastChildContext( |
164 | | sal_Int32 Element, |
165 | | const css::uno::Reference< css::xml::sax::XFastAttributeList > & /*xAttrList*/ ) |
166 | 0 | { |
167 | 0 | if ( Element == ConvDicXMLToken::TEXT_CONVERSION_DICTIONARY ) |
168 | 0 | return new ConvDicXMLDictionaryContext_Impl( GetConvDicImport() ); |
169 | 0 | return nullptr; |
170 | 0 | } |
171 | | |
172 | | |
173 | | void ConvDicXMLDictionaryContext_Impl::startFastElement( sal_Int32 /*nElement*/, |
174 | | const css::uno::Reference< css::xml::sax::XFastAttributeList >& rxAttrList ) |
175 | 0 | { |
176 | 0 | for (auto &aIter : sax_fastparser::castToFastAttributeList( rxAttrList )) |
177 | 0 | { |
178 | 0 | switch (aIter.getToken()) |
179 | 0 | { |
180 | 0 | case XML_NAMESPACE_TCD | XML_LANG: |
181 | 0 | nLanguage = LanguageTag::convertToLanguageType( aIter.toString() ); |
182 | 0 | break; |
183 | 0 | case XML_NAMESPACE_TCD | XML_CONVERSION_TYPE: |
184 | 0 | nConversionType = GetConversionTypeFromText( aIter.toString() ); |
185 | 0 | break; |
186 | 0 | default: |
187 | 0 | ; |
188 | 0 | } |
189 | 0 | } |
190 | 0 | GetConvDicImport().SetLanguage( nLanguage ); |
191 | 0 | GetConvDicImport().SetConversionType( nConversionType ); |
192 | |
|
193 | 0 | } |
194 | | |
195 | | css::uno::Reference<XFastContextHandler> ConvDicXMLDictionaryContext_Impl::createFastChildContext( |
196 | | sal_Int32 Element, |
197 | | const css::uno::Reference< css::xml::sax::XFastAttributeList > & /*xAttrList*/ ) |
198 | 0 | { |
199 | 0 | if ( Element == ConvDicXMLToken::ENTRY ) |
200 | 0 | return new ConvDicXMLEntryTextContext_Impl( GetConvDicImport() ); |
201 | 0 | return nullptr; |
202 | 0 | } |
203 | | |
204 | | css::uno::Reference<XFastContextHandler> ConvDicXMLEntryTextContext_Impl::createFastChildContext( |
205 | | sal_Int32 Element, |
206 | | const css::uno::Reference< css::xml::sax::XFastAttributeList > & /*xAttrList*/ ) |
207 | 0 | { |
208 | 0 | if ( Element == ConvDicXMLToken::RIGHT_TEXT ) |
209 | 0 | return new ConvDicXMLRightTextContext_Impl( GetConvDicImport(), *this ); |
210 | 0 | return nullptr; |
211 | 0 | } |
212 | | |
213 | | void ConvDicXMLEntryTextContext_Impl::startFastElement( |
214 | | sal_Int32 /*Element*/, |
215 | | const css::uno::Reference< css::xml::sax::XFastAttributeList >& rxAttrList ) |
216 | 0 | { |
217 | 0 | for (auto &aIter : sax_fastparser::castToFastAttributeList( rxAttrList )) |
218 | 0 | { |
219 | 0 | switch (aIter.getToken()) |
220 | 0 | { |
221 | 0 | case XML_NAMESPACE_TCD | XML_LEFT_TEXT: |
222 | 0 | aLeftText = aIter.toString(); |
223 | 0 | break; |
224 | 0 | default: |
225 | 0 | ; |
226 | 0 | } |
227 | 0 | } |
228 | 0 | } |
229 | | |
230 | | |
231 | | void ConvDicXMLRightTextContext_Impl::characters( const OUString &rChars ) |
232 | 0 | { |
233 | 0 | aRightText += rChars; |
234 | 0 | } |
235 | | |
236 | | void ConvDicXMLRightTextContext_Impl::endFastElement( sal_Int32 /*nElement*/ ) |
237 | 0 | { |
238 | 0 | ConvDic *pDic = GetConvDicImport().GetDic(); |
239 | 0 | if (pDic) |
240 | 0 | pDic->AddEntry( rEntryContext.GetLeftText(), aRightText ); |
241 | 0 | } |
242 | | |
243 | | |
244 | | bool ConvDicXMLExport::Export() |
245 | 0 | { |
246 | 0 | uno::Reference< document::XExporter > xExporter( this ); |
247 | 0 | uno::Reference< document::XFilter > xFilter( xExporter, UNO_QUERY ); |
248 | 0 | xFilter->filter( {} ); // calls exportDoc implicitly |
249 | |
|
250 | 0 | return bSuccess; |
251 | 0 | } |
252 | | |
253 | | |
254 | | ErrCode ConvDicXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum /*eClass*/ ) |
255 | 0 | { |
256 | 0 | GetNamespaceMap_().Add( u"tcd"_ustr, |
257 | 0 | XML_NAMESPACE_TCD_STRING, XML_NAMESPACE_TCD ); |
258 | |
|
259 | 0 | GetDocHandler()->startDocument(); |
260 | | |
261 | | // Add xmlns line and some other arguments |
262 | 0 | AddAttribute( GetNamespaceMap_().GetAttrNameByKey( XML_NAMESPACE_TCD ), |
263 | 0 | GetNamespaceMap_().GetNameByKey( XML_NAMESPACE_TCD ) ); |
264 | 0 | AddAttribute( XML_NAMESPACE_TCD, u"package"_ustr, u"org.openoffice.Office"_ustr ); |
265 | |
|
266 | 0 | OUString aIsoLang( LanguageTag::convertToBcp47( rDic.nLanguage ) ); |
267 | 0 | AddAttribute( XML_NAMESPACE_TCD, u"lang"_ustr, aIsoLang ); |
268 | 0 | OUString aConvType( ConversionTypeToText( rDic.nConversionType ) ); |
269 | 0 | AddAttribute( XML_NAMESPACE_TCD, u"conversion-type"_ustr, aConvType ); |
270 | | |
271 | | //!! block necessary in order to have SvXMLElementExport d-tor called |
272 | | //!! before the call to endDocument |
273 | 0 | { |
274 | 0 | SvXMLElementExport aRoot( *this, XML_NAMESPACE_TCD, u"text-conversion-dictionary"_ustr, true, true ); |
275 | 0 | ExportContent_(); |
276 | 0 | } |
277 | |
|
278 | 0 | GetDocHandler()->endDocument(); |
279 | |
|
280 | 0 | bSuccess = true; |
281 | 0 | return ERRCODE_NONE; |
282 | 0 | } |
283 | | |
284 | | |
285 | | void ConvDicXMLExport::ExportContent_() |
286 | 0 | { |
287 | | // acquire sorted list of all keys |
288 | 0 | std::set<OUString> aKeySet; |
289 | 0 | for (auto const& elem : rDic.aFromLeft) |
290 | 0 | aKeySet.insert( elem.first ); |
291 | |
|
292 | 0 | for (const OUString& aLeftText : aKeySet) |
293 | 0 | { |
294 | 0 | AddAttribute( XML_NAMESPACE_TCD, u"left-text"_ustr, aLeftText ); |
295 | 0 | if (rDic.pConvPropType) // property-type list available? |
296 | 0 | { |
297 | 0 | sal_Int16 nPropertyType = -1; |
298 | 0 | PropTypeMap::iterator aIt2 = rDic.pConvPropType->find( aLeftText ); |
299 | 0 | if (aIt2 != rDic.pConvPropType->end()) |
300 | 0 | nPropertyType = (*aIt2).second; |
301 | 0 | DBG_ASSERT( nPropertyType, "property-type not found" ); |
302 | 0 | if (nPropertyType == -1) |
303 | 0 | nPropertyType = ConversionPropertyType::NOT_DEFINED; |
304 | 0 | AddAttribute( XML_NAMESPACE_TCD, u"property-type"_ustr, OUString::number( nPropertyType ) ); |
305 | 0 | } |
306 | 0 | SvXMLElementExport aEntryMain( *this, XML_NAMESPACE_TCD, |
307 | 0 | u"entry"_ustr , true, true ); |
308 | |
|
309 | 0 | std::pair< ConvMap::iterator, ConvMap::iterator > aRange = |
310 | 0 | rDic.aFromLeft.equal_range(aLeftText); |
311 | 0 | for (auto aIt = aRange.first; aIt != aRange.second; ++aIt) |
312 | 0 | { |
313 | 0 | DBG_ASSERT( aLeftText == (*aIt).first, "key <-> entry mismatch" ); |
314 | 0 | OUString aRightText( (*aIt).second ); |
315 | 0 | SvXMLElementExport aEntryRightText( *this, XML_NAMESPACE_TCD, |
316 | 0 | u"right-text"_ustr , true, false ); |
317 | 0 | Characters( aRightText ); |
318 | 0 | } |
319 | 0 | } |
320 | 0 | } |
321 | | |
322 | | //!! see comment for pDic member |
323 | | ConvDicXMLImport::ConvDicXMLImport( ConvDic *pConvDic ) : |
324 | 0 | SvXMLImport ( comphelper::getProcessComponentContext(), u"com.sun.star.lingu2.ConvDicXMLImport"_ustr, SvXMLImportFlags::ALL ), |
325 | 0 | pDic ( pConvDic ), nLanguage(LANGUAGE_NONE), nConversionType(-1) |
326 | 0 | { |
327 | 0 | GetNamespaceMap().Add( GetXMLToken(XML_NP_TCD), GetXMLToken(XML_N_TCD), XML_NAMESPACE_TCD); |
328 | 0 | } |
329 | | |
330 | | SvXMLImportContext * ConvDicXMLImport::CreateFastContext( |
331 | | sal_Int32 Element, |
332 | | const css::uno::Reference< css::xml::sax::XFastAttributeList > & /*xAttrList*/ ) |
333 | 0 | { |
334 | 0 | if( Element == ConvDicXMLToken::TEXT_CONVERSION_DICTIONARY ) |
335 | 0 | return new ConvDicXMLDictionaryContext_Impl( *this ); |
336 | 0 | return nullptr; |
337 | 0 | } |
338 | | |
339 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |