Coverage Report

Created: 2025-07-07 10:01

/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: */