1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
26 #include <com/sun/star/uno/RuntimeException.hpp>
27 #include <rtl/ref.hxx>
28 #include <rtl/string.h>
29 #include <rtl/ustrbuf.hxx>
30 #include <rtl/ustring.h>
31 #include <rtl/ustring.hxx>
32 #include <sal/log.hxx>
33 #include <sal/types.h>
34 #include <o3tl/string_view.hxx>
36 #include "additions.hxx"
39 #include "nodemap.hxx"
40 #include "rootnode.hxx"
41 #include "setnode.hxx"
48 std::u16string_view encoded
, std::size_t begin
, std::size_t end
,
52 begin
<= end
&& end
<= encoded
.size() &&
54 OUStringBuffer
buf(end
- begin
);
55 while (begin
!= end
) {
56 sal_Unicode c
= encoded
[begin
++];
58 if (o3tl::starts_with(encoded
.substr(begin
), u
"amp;")) {
60 begin
+= RTL_CONSTASCII_LENGTH("amp;");
61 } else if (o3tl::starts_with(encoded
.substr(begin
), u
"quot;")) {
63 begin
+= RTL_CONSTASCII_LENGTH("quot;");
64 } else if (o3tl::starts_with(encoded
.substr(begin
), u
"apos;")) {
66 begin
+= RTL_CONSTASCII_LENGTH("apos;");
75 *decoded
= buf
.makeStringAndClear();
81 OUString
Data::createSegment(
82 std::u16string_view templateName
, OUString
const & name
)
84 if (templateName
.empty()) {
87 OUStringBuffer
buf(128);
88 //TODO: verify template name contains no bad chars?
89 buf
.append(OUString::Concat(templateName
) + "['");
90 for (sal_Int32 i
= 0; i
< name
.getLength(); ++i
) {
91 sal_Unicode c
= name
[i
];
100 buf
.append("'");
108 return buf
.makeStringAndClear();
111 sal_Int32
Data::parseSegment(
112 OUString
const & path
, sal_Int32 index
, OUString
* name
,
113 bool * setElement
, OUString
* templateName
)
116 index
>= 0 && index
<= path
.getLength() && name
!= nullptr &&
117 setElement
!= nullptr);
119 while (i
< path
.getLength() && path
[i
] != '/' && path
[i
] != '[') {
122 if (i
== path
.getLength() || path
[i
] == '/') {
123 *name
= path
.copy(index
, i
- index
);
127 if (i
- index
== 1 && path
[index
] == '*') {
129 if (templateName
!= nullptr) {
130 templateName
->clear();
133 *setElement
= i
!= index
;
134 if (templateName
!= nullptr) {
135 *templateName
= path
.copy(index
, i
- index
);
138 if (++i
== path
.getLength()) {
141 sal_Unicode del
= path
[i
++];
142 if (del
!= '\'' && del
!= '"') {
145 sal_Int32 j
= path
.indexOf(del
, i
);
146 if (j
== -1 || j
+ 1 == path
.getLength() || path
[j
+ 1] != ']' ||
147 !decode(path
, i
, j
, name
))
154 OUString
Data::fullTemplateName(
155 std::u16string_view component
, std::u16string_view name
)
157 if (component
.find(':') != std::u16string_view::npos
|| name
.find(':') != std::u16string_view::npos
) {
158 throw css::uno::RuntimeException(
159 OUString::Concat("bad component/name pair containing colon ") + component
+ "/" +
162 return OUString::Concat(component
) + ":" + name
;
165 bool Data::equalTemplateNames(
166 OUString
const & shortName
, OUString
const & longName
)
168 if (shortName
.indexOf(':') == -1) {
169 sal_Int32 i
= longName
.indexOf(':') + 1;
172 rtl_ustr_compare_WithLength(
173 shortName
.getStr(), shortName
.getLength(),
174 longName
.getStr() + i
, longName
.getLength() - i
) ==
177 return shortName
== longName
;
181 Data::Data(): root_(new RootNode
) {}
183 rtl::Reference
< Node
> Data::resolvePathRepresentation(
184 OUString
const & pathRepresentation
,
185 OUString
* canonicRepresentation
, std::vector
<OUString
> * path
, int * finalizedLayer
)
188 if (pathRepresentation
.isEmpty() || pathRepresentation
[0] != '/') {
189 throw css::uno::RuntimeException(
190 "bad path " + pathRepresentation
);
192 if (path
!= nullptr) {
195 if (pathRepresentation
== "/") {
196 if (canonicRepresentation
!= nullptr) {
197 *canonicRepresentation
= pathRepresentation
;
199 if (finalizedLayer
!= nullptr) {
200 *finalizedLayer
= NO_LAYER
;
206 OUString templateName
;
207 sal_Int32 n
= parseSegment(pathRepresentation
, 1, &seg
, &setElement
, nullptr);
208 if (n
== -1 || setElement
)
210 throw css::uno::RuntimeException(
211 "bad path " + pathRepresentation
);
213 NodeMap
const & components
= getComponents();
214 NodeMap::const_iterator
i(components
.find(seg
));
215 OUStringBuffer
canonic(128);
216 rtl::Reference
< Node
> parent
;
217 int finalized
= NO_LAYER
;
218 for (rtl::Reference
< Node
> p(i
== components
.end() ? nullptr : i
->second
);;) {
222 if (canonicRepresentation
!= nullptr) {
223 canonic
.append("/" + createSegment(templateName
, seg
));
225 if (path
!= nullptr) {
226 path
->push_back(seg
);
228 finalized
= std::min(finalized
, p
->getFinalized());
229 if (n
!= pathRepresentation
.getLength() &&
230 pathRepresentation
[n
++] != '/')
232 throw css::uno::RuntimeException(
233 "bad path " + pathRepresentation
);
235 // for backwards compatibility, ignore a final slash
236 if (n
== pathRepresentation
.getLength()) {
237 if (canonicRepresentation
!= nullptr) {
238 *canonicRepresentation
= canonic
.makeStringAndClear();
240 if (finalizedLayer
!= nullptr) {
241 *finalizedLayer
= finalized
;
246 templateName
.clear();
248 pathRepresentation
, n
, &seg
, &setElement
, &templateName
);
250 throw css::uno::RuntimeException(
251 "bad path " + pathRepresentation
);
253 // For backwards compatibility, allow set members to be accessed with
254 // simple path segments, like group members:
255 p
= p
->getMember(seg
);
257 switch (parent
->kind()) {
258 case Node::KIND_LOCALIZED_PROPERTY
:
259 if (!templateName
.isEmpty()) {
260 throw css::uno::RuntimeException(
261 "bad path " + pathRepresentation
);
265 if (!templateName
.isEmpty() &&
266 !static_cast< SetNode
* >(parent
.get())->isValidTemplate(
269 throw css::uno::RuntimeException(
270 "bad path " + pathRepresentation
);
274 throw css::uno::RuntimeException(
275 "bad path " + pathRepresentation
);
277 if (!templateName
.isEmpty() && p
!= nullptr) {
278 assert(!p
->getTemplateName().isEmpty());
279 if (!equalTemplateNames(templateName
, p
->getTemplateName())) {
280 throw css::uno::RuntimeException(
281 "bad path " + pathRepresentation
);
288 rtl::Reference
< Node
> Data::getTemplate(
289 int layer
, OUString
const & fullName
) const
291 return templates
.findNode(layer
, fullName
);
294 NodeMap
& Data::getComponents() const {
295 return root_
->getMembers();
298 Additions
* Data::addExtensionXcuAdditions(
299 OUString
const & url
, int layer
)
301 rtl::Reference
item(new ExtensionXcu
);
302 ExtensionXcuAdditions::iterator
i(
303 extensionXcuAdditions_
.emplace(
304 url
, rtl::Reference
< ExtensionXcu
>()).first
);
305 if (i
->second
.is()) {
306 throw css::uno::RuntimeException(
307 "already added extension xcu " + url
);
311 return &item
->additions
;
314 rtl::Reference
< Data::ExtensionXcu
> Data::removeExtensionXcuAdditions(
315 OUString
const & url
)
317 ExtensionXcuAdditions::iterator
i(extensionXcuAdditions_
.find(url
));
318 if (i
== extensionXcuAdditions_
.end()) {
319 // This can happen, as migration of pre OOo 3.3 UserInstallation
320 // extensions in dp_registry::backend::configuration::BackendImpl::
321 // PackageImpl::processPackage_ can cause just-in-time creation of
322 // extension xcu files that are never added via addExtensionXcuAdditions
323 // (also, there might be url spelling differences between calls to
324 // addExtensionXcuAdditions and removeExtensionXcuAdditions?):
327 "unknown Data::removeExtensionXcuAdditions(" << url
<< ")");
328 return rtl::Reference
< ExtensionXcu
>();
330 rtl::Reference
< ExtensionXcu
> item(i
->second
);
331 extensionXcuAdditions_
.erase(i
);
337 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */