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/Reference.hxx>
26 #include <com/sun/star/uno/RuntimeException.hpp>
27 #include <com/sun/star/uno/XInterface.hpp>
28 #include <rtl/ref.hxx>
29 #include <rtl/string.h>
30 #include <rtl/ustrbuf.hxx>
31 #include <rtl/ustring.h>
32 #include <rtl/ustring.hxx>
33 #include <sal/log.hxx>
34 #include <sal/types.h>
36 #include "additions.hxx"
38 #include "groupnode.hxx"
40 #include "nodemap.hxx"
41 #include "rootnode.hxx"
42 #include "setnode.hxx"
49 OUString
const & encoded
, sal_Int32 begin
, sal_Int32 end
,
53 begin
>= 0 && begin
<= end
&& end
<= encoded
.getLength() &&
56 while (begin
!= end
) {
57 sal_Unicode c
= encoded
[begin
++];
59 if (encoded
.match("amp;", begin
)) {
61 begin
+= RTL_CONSTASCII_LENGTH("amp;");
62 } else if (encoded
.match("quot;", begin
)) {
64 begin
+= RTL_CONSTASCII_LENGTH("quot;");
65 } else if (encoded
.match("apos;", begin
)) {
67 begin
+= RTL_CONSTASCII_LENGTH("apos;");
76 *decoded
= buf
.makeStringAndClear();
82 OUString
Data::createSegment(
83 OUString
const & templateName
, OUString
const & name
)
85 if (templateName
.isEmpty()) {
88 OUStringBuffer
buf(templateName
);
89 //TODO: verify template name contains no bad chars?
90 buf
.appendAscii("['");
91 for (sal_Int32 i
= 0; i
< name
.getLength(); ++i
) {
92 sal_Unicode c
= name
[i
];
95 buf
.appendAscii("&");
98 buf
.appendAscii(""");
101 buf
.appendAscii("'");
108 buf
.appendAscii("']");
109 return buf
.makeStringAndClear();
112 sal_Int32
Data::parseSegment(
113 OUString
const & path
, sal_Int32 index
, OUString
* name
,
114 bool * setElement
, OUString
* templateName
)
117 index
>= 0 && index
<= path
.getLength() && name
!= 0 &&
120 while (i
< path
.getLength() && path
[i
] != '/' && path
[i
] != '[') {
123 if (i
== path
.getLength() || path
[i
] == '/') {
124 *name
= path
.copy(index
, i
- index
);
128 if (templateName
!= 0) {
129 if (i
- index
== 1 && path
[index
] == '*') {
130 templateName
->clear();
132 *templateName
= path
.copy(index
, i
- index
);
135 if (++i
== path
.getLength()) {
138 sal_Unicode del
= path
[i
++];
139 if (del
!= '\'' && del
!= '"') {
142 sal_Int32 j
= path
.indexOf(del
, i
);
143 if (j
== -1 || j
+ 1 == path
.getLength() || path
[j
+ 1] != ']' ||
144 !decode(path
, i
, j
, name
))
152 OUString
Data::fullTemplateName(
153 OUString
const & component
, OUString
const & name
)
155 if (component
.indexOf(':') != -1 || name
.indexOf(':') != -1) {
156 throw css::uno::RuntimeException(
157 "bad component/name pair containing colon " + component
+ "/" +
160 OUStringBuffer
buf(component
);
163 return buf
.makeStringAndClear();
166 bool Data::equalTemplateNames(
167 OUString
const & shortName
, OUString
const & longName
)
169 if (shortName
.indexOf(':') == -1) {
170 sal_Int32 i
= longName
.indexOf(':') + 1;
173 rtl_ustr_compare_WithLength(
174 shortName
.getStr(), shortName
.getLength(),
175 longName
.getStr() + i
, longName
.getLength() - i
) ==
178 return shortName
== longName
;
182 Data::Data(): root_(new RootNode
) {}
184 rtl::Reference
< Node
> Data::resolvePathRepresentation(
185 OUString
const & pathRepresentation
,
186 OUString
* canonicRepresentation
, Path
* path
, int * finalizedLayer
)
189 if (pathRepresentation
.isEmpty() || pathRepresentation
[0] != '/') {
190 throw css::uno::RuntimeException(
191 "bad path " + pathRepresentation
);
196 if (pathRepresentation
== "/") {
197 if (canonicRepresentation
!= 0) {
198 *canonicRepresentation
= pathRepresentation
;
200 if (finalizedLayer
!= 0) {
201 *finalizedLayer
= NO_LAYER
;
207 OUString templateName
;
208 sal_Int32 n
= parseSegment(pathRepresentation
, 1, &seg
, &setElement
, 0);
209 if (n
== -1 || setElement
)
211 throw css::uno::RuntimeException(
212 "bad path " + pathRepresentation
);
214 NodeMap
const & components
= getComponents();
215 NodeMap::const_iterator
i(components
.find(seg
));
216 OUStringBuffer canonic
;
217 rtl::Reference
< Node
> parent
;
218 int finalized
= NO_LAYER
;
219 for (rtl::Reference
< Node
> p(i
== components
.end() ? 0 : i
->second
);;) {
223 if (canonicRepresentation
!= 0) {
225 canonic
.append(createSegment(templateName
, seg
));
228 path
->push_back(seg
);
230 finalized
= std::min(finalized
, p
->getFinalized());
231 if (n
!= pathRepresentation
.getLength() &&
232 pathRepresentation
[n
++] != '/')
234 throw css::uno::RuntimeException(
235 "bad path " + pathRepresentation
);
237 // for backwards compatibility, ignore a final slash
238 if (n
== pathRepresentation
.getLength()) {
239 if (canonicRepresentation
!= 0) {
240 *canonicRepresentation
= canonic
.makeStringAndClear();
242 if (finalizedLayer
!= 0) {
243 *finalizedLayer
= finalized
;
248 templateName
.clear();
250 pathRepresentation
, n
, &seg
, &setElement
, &templateName
);
252 throw css::uno::RuntimeException(
253 "bad path " + pathRepresentation
);
255 // For backwards compatibility, allow set members to be accessed with
256 // simple path segments, like group members:
257 p
= p
->getMember(seg
);
259 switch (parent
->kind()) {
260 case Node::KIND_LOCALIZED_PROPERTY
:
261 if (!templateName
.isEmpty()) {
262 throw css::uno::RuntimeException(
263 "bad path " + pathRepresentation
);
267 if (!templateName
.isEmpty() &&
268 !static_cast< SetNode
* >(parent
.get())->isValidTemplate(
271 throw css::uno::RuntimeException(
272 "bad path " + pathRepresentation
);
276 throw css::uno::RuntimeException(
277 "bad path " + pathRepresentation
);
279 if (!templateName
.isEmpty() && p
!= 0) {
280 assert(!p
->getTemplateName().isEmpty());
281 if (!equalTemplateNames(templateName
, p
->getTemplateName())) {
282 throw css::uno::RuntimeException(
283 "bad path " + pathRepresentation
);
290 rtl::Reference
< Node
> Data::getTemplate(
291 int layer
, OUString
const & fullName
) const
293 return templates
.findNode(layer
, fullName
);
296 NodeMap
& Data::getComponents() const {
297 return root_
->getMembers();
300 Additions
* Data::addExtensionXcuAdditions(
301 OUString
const & url
, int layer
)
303 rtl::Reference
< ExtensionXcu
> item(new ExtensionXcu
);
304 ExtensionXcuAdditions::iterator
i(
305 extensionXcuAdditions_
.insert(
306 ExtensionXcuAdditions::value_type(
307 url
, rtl::Reference
< ExtensionXcu
>())).first
);
308 if (i
->second
.is()) {
309 throw css::uno::RuntimeException(
310 "already added extension xcu " + url
);
314 return &item
->additions
;
317 rtl::Reference
< Data::ExtensionXcu
> Data::removeExtensionXcuAdditions(
318 OUString
const & url
)
320 ExtensionXcuAdditions::iterator
i(extensionXcuAdditions_
.find(url
));
321 if (i
== extensionXcuAdditions_
.end()) {
322 // This can happen, as migration of pre OOo 3.3 UserInstallation
323 // extensions in dp_registry::backend::configuration::BackendImpl::
324 // PackageImpl::processPackage_ can cause just-in-time creation of
325 // extension xcu files that are never added via addExtensionXcuAdditions
326 // (also, there might be url spelling differences between calls to
327 // addExtensionXcuAdditions and removeExtensionXcuAdditions?):
330 "unknown Data::removeExtensionXcuAdditions(" << url
<< ")");
331 return rtl::Reference
< ExtensionXcu
>();
333 rtl::Reference
< ExtensionXcu
> item(i
->second
);
334 extensionXcuAdditions_
.erase(i
);
340 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */