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>
25 #include <com/sun/star/uno/RuntimeException.hpp>
26 #include <rtl/ref.hxx>
27 #include <rtl/string.h>
28 #include <rtl/ustrbuf.hxx>
29 #include <rtl/ustring.h>
30 #include <rtl/ustring.hxx>
31 #include <sal/log.hxx>
32 #include <sal/types.h>
34 #include "additions.hxx"
37 #include "nodemap.hxx"
38 #include "rootnode.hxx"
39 #include "setnode.hxx"
46 OUString
const & encoded
, sal_Int32 begin
, sal_Int32 end
,
50 begin
>= 0 && begin
<= end
&& end
<= encoded
.getLength() &&
52 OUStringBuffer
buf(end
- begin
);
53 while (begin
!= end
) {
54 sal_Unicode c
= encoded
[begin
++];
56 if (encoded
.match("amp;", begin
)) {
58 begin
+= RTL_CONSTASCII_LENGTH("amp;");
59 } else if (encoded
.match("quot;", begin
)) {
61 begin
+= RTL_CONSTASCII_LENGTH("quot;");
62 } else if (encoded
.match("apos;", begin
)) {
64 begin
+= RTL_CONSTASCII_LENGTH("apos;");
73 *decoded
= buf
.makeStringAndClear();
79 OUString
Data::createSegment(
80 std::u16string_view templateName
, OUString
const & name
)
82 if (templateName
.empty()) {
85 OUStringBuffer
buf(128);
86 buf
.append(templateName
);
87 //TODO: verify template name contains no bad chars?
89 for (sal_Int32 i
= 0; i
< name
.getLength(); ++i
) {
90 sal_Unicode c
= name
[i
];
107 return buf
.makeStringAndClear();
110 sal_Int32
Data::parseSegment(
111 OUString
const & path
, sal_Int32 index
, OUString
* name
,
112 bool * setElement
, OUString
* templateName
)
115 index
>= 0 && index
<= path
.getLength() && name
!= nullptr &&
116 setElement
!= nullptr);
118 while (i
< path
.getLength() && path
[i
] != '/' && path
[i
] != '[') {
121 if (i
== path
.getLength() || path
[i
] == '/') {
122 *name
= path
.copy(index
, i
- index
);
126 if (templateName
!= nullptr) {
127 if (i
- index
== 1 && path
[index
] == '*') {
128 templateName
->clear();
130 *templateName
= path
.copy(index
, i
- index
);
133 if (++i
== path
.getLength()) {
136 sal_Unicode del
= path
[i
++];
137 if (del
!= '\'' && del
!= '"') {
140 sal_Int32 j
= path
.indexOf(del
, i
);
141 if (j
== -1 || j
+ 1 == path
.getLength() || path
[j
+ 1] != ']' ||
142 !decode(path
, i
, j
, name
))
150 OUString
Data::fullTemplateName(
151 OUString
const & component
, OUString
const & name
)
153 if (component
.indexOf(':') != -1 || name
.indexOf(':') != -1) {
154 throw css::uno::RuntimeException(
155 "bad component/name pair containing colon " + component
+ "/" +
158 return component
+ ":" + name
;
161 bool Data::equalTemplateNames(
162 OUString
const & shortName
, OUString
const & longName
)
164 if (shortName
.indexOf(':') == -1) {
165 sal_Int32 i
= longName
.indexOf(':') + 1;
168 rtl_ustr_compare_WithLength(
169 shortName
.getStr(), shortName
.getLength(),
170 longName
.getStr() + i
, longName
.getLength() - i
) ==
173 return shortName
== longName
;
177 Data::Data(): root_(new RootNode
) {}
179 rtl::Reference
< Node
> Data::resolvePathRepresentation(
180 OUString
const & pathRepresentation
,
181 OUString
* canonicRepresentation
, std::vector
<OUString
> * path
, int * finalizedLayer
)
184 if (pathRepresentation
.isEmpty() || pathRepresentation
[0] != '/') {
185 throw css::uno::RuntimeException(
186 "bad path " + pathRepresentation
);
188 if (path
!= nullptr) {
191 if (pathRepresentation
== "/") {
192 if (canonicRepresentation
!= nullptr) {
193 *canonicRepresentation
= pathRepresentation
;
195 if (finalizedLayer
!= nullptr) {
196 *finalizedLayer
= NO_LAYER
;
202 OUString templateName
;
203 sal_Int32 n
= parseSegment(pathRepresentation
, 1, &seg
, &setElement
, nullptr);
204 if (n
== -1 || setElement
)
206 throw css::uno::RuntimeException(
207 "bad path " + pathRepresentation
);
209 NodeMap
const & components
= getComponents();
210 NodeMap::const_iterator
i(components
.find(seg
));
211 OUStringBuffer
canonic(128);
212 rtl::Reference
< Node
> parent
;
213 int finalized
= NO_LAYER
;
214 for (rtl::Reference
< Node
> p(i
== components
.end() ? nullptr : i
->second
);;) {
218 if (canonicRepresentation
!= nullptr) {
220 canonic
.append(createSegment(templateName
, seg
));
222 if (path
!= nullptr) {
223 path
->push_back(seg
);
225 finalized
= std::min(finalized
, p
->getFinalized());
226 if (n
!= pathRepresentation
.getLength() &&
227 pathRepresentation
[n
++] != '/')
229 throw css::uno::RuntimeException(
230 "bad path " + pathRepresentation
);
232 // for backwards compatibility, ignore a final slash
233 if (n
== pathRepresentation
.getLength()) {
234 if (canonicRepresentation
!= nullptr) {
235 *canonicRepresentation
= canonic
.makeStringAndClear();
237 if (finalizedLayer
!= nullptr) {
238 *finalizedLayer
= finalized
;
243 templateName
.clear();
245 pathRepresentation
, n
, &seg
, &setElement
, &templateName
);
247 throw css::uno::RuntimeException(
248 "bad path " + pathRepresentation
);
250 // For backwards compatibility, allow set members to be accessed with
251 // simple path segments, like group members:
252 p
= p
->getMember(seg
);
254 switch (parent
->kind()) {
255 case Node::KIND_LOCALIZED_PROPERTY
:
256 if (!templateName
.isEmpty()) {
257 throw css::uno::RuntimeException(
258 "bad path " + pathRepresentation
);
262 if (!templateName
.isEmpty() &&
263 !static_cast< SetNode
* >(parent
.get())->isValidTemplate(
266 throw css::uno::RuntimeException(
267 "bad path " + pathRepresentation
);
271 throw css::uno::RuntimeException(
272 "bad path " + pathRepresentation
);
274 if (!templateName
.isEmpty() && p
!= nullptr) {
275 assert(!p
->getTemplateName().isEmpty());
276 if (!equalTemplateNames(templateName
, p
->getTemplateName())) {
277 throw css::uno::RuntimeException(
278 "bad path " + pathRepresentation
);
285 rtl::Reference
< Node
> Data::getTemplate(
286 int layer
, OUString
const & fullName
) const
288 return templates
.findNode(layer
, fullName
);
291 NodeMap
& Data::getComponents() const {
292 return root_
->getMembers();
295 Additions
* Data::addExtensionXcuAdditions(
296 OUString
const & url
, int layer
)
298 rtl::Reference
item(new ExtensionXcu
);
299 ExtensionXcuAdditions::iterator
i(
300 extensionXcuAdditions_
.emplace(
301 url
, rtl::Reference
< ExtensionXcu
>()).first
);
302 if (i
->second
.is()) {
303 throw css::uno::RuntimeException(
304 "already added extension xcu " + url
);
308 return &item
->additions
;
311 rtl::Reference
< Data::ExtensionXcu
> Data::removeExtensionXcuAdditions(
312 OUString
const & url
)
314 ExtensionXcuAdditions::iterator
i(extensionXcuAdditions_
.find(url
));
315 if (i
== extensionXcuAdditions_
.end()) {
316 // This can happen, as migration of pre OOo 3.3 UserInstallation
317 // extensions in dp_registry::backend::configuration::BackendImpl::
318 // PackageImpl::processPackage_ can cause just-in-time creation of
319 // extension xcu files that are never added via addExtensionXcuAdditions
320 // (also, there might be url spelling differences between calls to
321 // addExtensionXcuAdditions and removeExtensionXcuAdditions?):
324 "unknown Data::removeExtensionXcuAdditions(" << url
<< ")");
325 return rtl::Reference
< ExtensionXcu
>();
327 rtl::Reference
< ExtensionXcu
> item(i
->second
);
328 extensionXcuAdditions_
.erase(i
);
334 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */