Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svgio/source/svguno/xsvgparser.cxx
Line
Count
Source
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 <sal/config.h>
21
22
#include <com/sun/star/graphic/XSvgParser.hpp>
23
#include <com/sun/star/lang/XServiceInfo.hpp>
24
#include <com/sun/star/lang/XInitialization.hpp>
25
#include <comphelper/processfactory.hxx>
26
#include <cppuhelper/implbase.hxx>
27
#include <cppuhelper/supportsservice.hxx>
28
#include <com/sun/star/xml/sax/XParser.hpp>
29
#include <com/sun/star/xml/sax/Parser.hpp>
30
#include <com/sun/star/xml/sax/InputSource.hpp>
31
#include <svgdocumenthandler.hxx>
32
#include <svgfeimagenode.hxx>
33
#include <svgimagenode.hxx>
34
#include <comphelper/sequence.hxx>
35
#include <comphelper/diagnose_ex.hxx>
36
#include <rtl/ref.hxx>
37
#include <tools/stream.hxx>
38
#include <unotools/streamwrap.hxx>
39
40
#include <svgvisitor.hxx>
41
#include <algorithm>
42
#include <utility>
43
44
using namespace ::com::sun::star;
45
46
namespace svgio::svgreader
47
{
48
        namespace {
49
50
        class XSvgParser : public ::cppu::WeakImplHelper< graphic::XSvgParser, lang::XServiceInfo >
51
        {
52
        private:
53
            std::shared_ptr<SvgDrawVisitor> mpVisitor;
54
55
            uno::Reference< uno::XComponentContext > context_;
56
            bool parseSvgXML(uno::Reference<io::XInputStream> const & xSVGStream,
57
                             uno::Reference<xml::sax::XDocumentHandler> const & xSvgDocHdl);
58
        public:
59
            explicit XSvgParser(
60
                uno::Reference< uno::XComponentContext > context);
61
            XSvgParser(const XSvgParser&) = delete;
62
            XSvgParser& operator=(const XSvgParser&) = delete;
63
64
            // XSvgParser
65
            virtual uno::Sequence< uno::Reference< ::graphic::XPrimitive2D > > SAL_CALL getDecomposition(
66
                const uno::Reference< ::io::XInputStream >& xSVGStream,
67
                const OUString& aAbsolutePath) override;
68
69
            virtual uno::Any SAL_CALL getDrawCommands(
70
                uno::Reference<io::XInputStream> const & xSvgStream,
71
                const OUString& aAbsolutePath) override;
72
73
            virtual uno::Sequence<OUString> SAL_CALL getExternalImageUrls(
74
                uno::Reference<io::XInputStream> const & xSvgStream,
75
                const OUString& aAbsolutePath) override;
76
77
            // XServiceInfo
78
            virtual OUString SAL_CALL getImplementationName() override;
79
            virtual sal_Bool SAL_CALL supportsService(const OUString&) override;
80
            virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
81
        };
82
83
        }
84
85
        XSvgParser::XSvgParser(
86
            uno::Reference< uno::XComponentContext > context):
87
11.7k
            context_(std::move(context))
88
11.7k
        {
89
11.7k
        }
90
91
        bool XSvgParser::parseSvgXML(uno::Reference<io::XInputStream> const & xSVGStream, uno::Reference<xml::sax::XDocumentHandler> const & xSvgDocHdl)
92
11.7k
        {
93
11.7k
            try
94
11.7k
            {
95
                // prepare ParserInputSource
96
11.7k
                xml::sax::InputSource myInputSource;
97
11.7k
                myInputSource.aInputStream = xSVGStream;
98
99
                // get parser
100
11.7k
                uno::Reference< xml::sax::XParser > xParser(
101
11.7k
                    xml::sax::Parser::create(context_));
102
                // fdo#60471 need to enable internal entities because
103
                // certain ... popular proprietary products write SVG files
104
                // that use entities to define XML namespaces.
105
11.7k
                uno::Reference<lang::XInitialization> const xInit(xParser,
106
11.7k
                        uno::UNO_QUERY_THROW);
107
11.7k
                uno::Sequence<uno::Any> args{ uno::Any(u"DoSmeplease"_ustr) };
108
11.7k
                xInit->initialize(args);
109
110
                // connect parser and filter
111
11.7k
                xParser->setDocumentHandler(xSvgDocHdl);
112
113
                // finally, parse the stream to a hierarchy of
114
                // SVGGraphicPrimitive2D which will be embedded to the
115
                // primitive sequence. Their decompositions will in the
116
                // end create local low-level primitives, thus SVG will
117
                // be processable from all our processors
118
11.7k
                xParser->parseStream(myInputSource);
119
11.7k
            }
120
11.7k
            catch(const uno::Exception&)
121
11.7k
            {
122
11.7k
                TOOLS_INFO_EXCEPTION( "svg", "Parse error");
123
11.7k
                return false;
124
11.7k
            }
125
126
1
            return true;
127
11.7k
        }
128
129
        uno::Sequence< uno::Reference< ::graphic::XPrimitive2D > > XSvgParser::getDecomposition(
130
            const uno::Reference< ::io::XInputStream >& xSVGStream,
131
            const OUString& aAbsolutePath )
132
11.7k
        {
133
11.7k
            drawinglayer::primitive2d::Primitive2DContainer aRetval;
134
135
11.7k
            if(xSVGStream.is())
136
11.7k
            {
137
                // local document handler
138
11.7k
                rtl::Reference<SvgDocHdl> pSvgDocHdl = new SvgDocHdl(aAbsolutePath);
139
11.7k
                parseSvgXML(xSVGStream, pSvgDocHdl);
140
141
                // decompose to primitives
142
11.7k
                for(std::unique_ptr<SvgNode> const & pCandidate : pSvgDocHdl->getSvgDocument().getSvgNodeVector())
143
157
                {
144
157
                    if (Display::None != pCandidate->getDisplay())
145
116
                    {
146
116
                        pCandidate->decomposeSvgNode(aRetval, false);
147
116
                    }
148
157
                }
149
11.7k
            }
150
0
            else
151
0
            {
152
0
                OSL_ENSURE(false, "Invalid stream (!)");
153
0
            }
154
155
11.7k
            return aRetval.toSequence();
156
11.7k
        }
157
158
        uno::Any SAL_CALL XSvgParser::getDrawCommands(
159
                uno::Reference<io::XInputStream> const & xSvgStream,
160
                const OUString& aAbsolutePath)
161
0
        {
162
0
            uno::Any aAnyResult;
163
164
0
            if (!xSvgStream.is())
165
0
                return aAnyResult;
166
167
0
            rtl::Reference<SvgDocHdl> pSvgDocHdl = new SvgDocHdl(aAbsolutePath);
168
0
            parseSvgXML(xSvgStream, pSvgDocHdl);
169
170
            // decompose to primitives
171
0
            for (std::unique_ptr<SvgNode> const & pCandidate : pSvgDocHdl->getSvgDocument().getSvgNodeVector())
172
0
            {
173
0
                if (Display::None != pCandidate->getDisplay())
174
0
                {
175
0
                    mpVisitor = std::make_shared<SvgDrawVisitor>();
176
0
                    pCandidate->accept(*mpVisitor);
177
0
                    std::shared_ptr<gfx::DrawRoot> pDrawRoot(mpVisitor->getDrawRoot());
178
0
                    sal_uInt64 nPointer = reinterpret_cast<sal_uInt64>(pDrawRoot.get());
179
0
                    aAnyResult <<= sal_uInt64(nPointer);
180
0
                }
181
0
            }
182
183
0
            return aAnyResult;
184
0
        }
185
186
        static void collectExternalImageUrls(const SvgNode& rNode, std::vector<OUString>& rUrls)
187
0
        {
188
0
            OUString aUrl;
189
0
            if (auto pImage = dynamic_cast<const SvgImageNode*>(&rNode))
190
0
                aUrl = pImage->getExternalImageUrl();
191
0
            else if (auto pFeImage = dynamic_cast<const SvgFeImageNode*>(&rNode))
192
0
                aUrl = pFeImage->getExternalImageUrl();
193
194
0
            if (!aUrl.isEmpty() && std::find(rUrls.begin(), rUrls.end(), aUrl) == rUrls.end())
195
0
                rUrls.push_back(aUrl);
196
197
0
            for (std::unique_ptr<SvgNode> const & pChild : rNode.getChildren())
198
0
                collectExternalImageUrls(*pChild, rUrls);
199
0
        }
200
201
        uno::Sequence<OUString> XSvgParser::getExternalImageUrls(
202
                uno::Reference<io::XInputStream> const & xSvgStream,
203
                const OUString& aAbsolutePath)
204
0
        {
205
0
            std::vector<OUString> aUrls;
206
207
0
            if (!xSvgStream.is())
208
0
                return {};
209
210
0
            rtl::Reference<SvgDocHdl> pSvgDocHdl = new SvgDocHdl(aAbsolutePath);
211
0
            parseSvgXML(xSvgStream, pSvgDocHdl);
212
213
0
            const SvgDocument& rDocument = pSvgDocHdl->getSvgDocument();
214
0
            for (std::unique_ptr<SvgNode> const & pCandidate : rDocument.getSvgNodeVector())
215
0
                collectExternalImageUrls(*pCandidate, aUrls);
216
217
0
            return comphelper::containerToSequence(aUrls);
218
0
        }
219
220
        OUString SAL_CALL XSvgParser::getImplementationName()
221
0
        {
222
0
            return u"svgio::svgreader::XSvgParser"_ustr;
223
0
        }
224
225
        sal_Bool SAL_CALL XSvgParser::supportsService(const OUString& rServiceName)
226
0
        {
227
0
            return cppu::supportsService(this, rServiceName);
228
0
        }
229
230
        uno::Sequence< OUString > SAL_CALL XSvgParser::getSupportedServiceNames()
231
0
        {
232
0
            return { u"com.sun.star.graphic.SvgTools"_ustr };
233
0
        }
234
235
} // end of namespace svgio::svgreader
236
237
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
238
svgio_XSvgParser_get_implementation(
239
    css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
240
11.7k
{
241
11.7k
    return cppu::acquire(new svgio::svgreader::XSvgParser(context));
242
11.7k
}
243
244
extern "C" bool TestImportSVG(SvStream& rStream)
245
2
{
246
2
    css::uno::Reference<css::io::XInputStream> xStream(new utl::OInputStreamWrapper(rStream));
247
2
    rtl::Reference<svgio::svgreader::XSvgParser> xSvgParser(new svgio::svgreader::XSvgParser(comphelper::getProcessComponentContext()));
248
2
    return xSvgParser->getDecomposition(xStream, OUString()).getLength() != 0;
249
2
}
250
251
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */