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
.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("amp;"), begin
))
61 buf
.append(sal_Unicode('&'));
62 begin
+= RTL_CONSTASCII_LENGTH("amp;");
63 } else if (encoded
.matchAsciiL(
64 RTL_CONSTASCII_STRINGPARAM("quot;"), begin
))
66 buf
.append(sal_Unicode('"'));
67 begin
+= RTL_CONSTASCII_LENGTH("quot;");
68 } else if (encoded
.matchAsciiL(
69 RTL_CONSTASCII_STRINGPARAM("apos;"), begin
))
71 buf
.append(sal_Unicode('\''));
72 begin
+= RTL_CONSTASCII_LENGTH("apos;");
81 *decoded
= buf
.makeStringAndClear();
87 OUString
Data::createSegment(
88 OUString
const & templateName
, OUString
const & name
)
90 if (templateName
.isEmpty()) {
93 OUStringBuffer
buf(templateName
);
94 //TODO: verify template name contains no bad chars?
95 buf
.appendAscii("['");
96 for (sal_Int32 i
= 0; i
< name
.getLength(); ++i
) {
97 sal_Unicode c
= name
[i
];
100 buf
.appendAscii("&");
103 buf
.appendAscii(""");
106 buf
.appendAscii("'");
113 buf
.appendAscii("']");
114 return buf
.makeStringAndClear();
117 sal_Int32
Data::parseSegment(
118 OUString
const & path
, sal_Int32 index
, OUString
* name
,
119 bool * setElement
, OUString
* templateName
)
122 index
>= 0 && index
<= path
.getLength() && name
!= 0 &&
125 while (i
< path
.getLength() && path
[i
] != '/' && path
[i
] != '[') {
128 if (i
== path
.getLength() || path
[i
] == '/') {
129 *name
= path
.copy(index
, i
- index
);
133 if (templateName
!= 0) {
134 if (i
- index
== 1 && path
[index
] == '*') {
135 *templateName
= OUString();
137 *templateName
= path
.copy(index
, i
- index
);
140 if (++i
== path
.getLength()) {
143 sal_Unicode del
= path
[i
++];
144 if (del
!= '\'' && del
!= '"') {
147 sal_Int32 j
= path
.indexOf(del
, i
);
148 if (j
== -1 || j
+ 1 == path
.getLength() || path
[j
+ 1] != ']' ||
149 !decode(path
, i
, j
, name
))
157 OUString
Data::fullTemplateName(
158 OUString
const & component
, OUString
const & name
)
160 if (component
.indexOf(':') != -1 || name
.indexOf(':') != -1) {
161 throw css::uno::RuntimeException(
162 (OUString("bad component/name pair containing colon ") +
163 component
+ OUString("/") +
165 css::uno::Reference
< css::uno::XInterface
>());
167 OUStringBuffer
buf(component
);
168 buf
.append(sal_Unicode(':'));
170 return buf
.makeStringAndClear();
173 bool Data::equalTemplateNames(
174 OUString
const & shortName
, OUString
const & longName
)
176 if (shortName
.indexOf(':') == -1) {
177 sal_Int32 i
= longName
.indexOf(':') + 1;
180 rtl_ustr_compare_WithLength(
181 shortName
.getStr(), shortName
.getLength(),
182 longName
.getStr() + i
, longName
.getLength() - i
) ==
185 return shortName
== longName
;
189 rtl::Reference
< Node
> Data::findNode(
190 int layer
, NodeMap
const & map
, OUString
const & name
)
192 NodeMap::const_iterator
i(map
.find(name
));
193 return i
== map
.end() || i
->second
->getLayer() > layer
194 ? rtl::Reference
< Node
>() : i
->second
;
197 Data::Data(): root_(new RootNode
) {}
199 rtl::Reference
< Node
> Data::resolvePathRepresentation(
200 OUString
const & pathRepresentation
,
201 OUString
* canonicRepresentation
, Path
* path
, int * finalizedLayer
)
204 if (pathRepresentation
.isEmpty() || pathRepresentation
[0] != '/') {
205 throw css::uno::RuntimeException(
206 (OUString("bad path ") +
208 css::uno::Reference
< css::uno::XInterface
>());
213 if ( pathRepresentation
== "/" ) {
214 if (canonicRepresentation
!= 0) {
215 *canonicRepresentation
= pathRepresentation
;
217 if (finalizedLayer
!= 0) {
218 *finalizedLayer
= NO_LAYER
;
224 OUString templateName
;
225 sal_Int32 n
= parseSegment(pathRepresentation
, 1, &seg
, &setElement
, 0);
226 if (n
== -1 || setElement
)
228 throw css::uno::RuntimeException(
229 (OUString("bad path ") +
231 css::uno::Reference
< css::uno::XInterface
>());
233 NodeMap
const & components
= getComponents();
234 NodeMap::const_iterator
i(components
.find(seg
));
235 OUStringBuffer canonic
;
236 rtl::Reference
< Node
> parent
;
237 int finalized
= NO_LAYER
;
238 for (rtl::Reference
< Node
> p(i
== components
.end() ? 0 : i
->second
);;) {
242 if (canonicRepresentation
!= 0) {
243 canonic
.append(sal_Unicode('/'));
244 canonic
.append(createSegment(templateName
, seg
));
247 path
->push_back(seg
);
249 finalized
= std::min(finalized
, p
->getFinalized());
250 if (n
!= pathRepresentation
.getLength() &&
251 pathRepresentation
[n
++] != '/')
253 throw css::uno::RuntimeException(
254 (OUString("bad path ") +
256 css::uno::Reference
< css::uno::XInterface
>());
258 // for backwards compatibility, ignore a final slash
259 if (n
== pathRepresentation
.getLength()) {
260 if (canonicRepresentation
!= 0) {
261 *canonicRepresentation
= canonic
.makeStringAndClear();
263 if (finalizedLayer
!= 0) {
264 *finalizedLayer
= finalized
;
269 templateName
= OUString();
271 pathRepresentation
, n
, &seg
, &setElement
, &templateName
);
273 throw css::uno::RuntimeException(
274 (OUString("bad path ") +
276 css::uno::Reference
< css::uno::XInterface
>());
278 // For backwards compatibility, allow set members to be accessed with
279 // simple path segments, like group members:
280 p
= p
->getMember(seg
);
282 switch (parent
->kind()) {
283 case Node::KIND_LOCALIZED_PROPERTY
:
284 if (!templateName
.isEmpty()) {
285 throw css::uno::RuntimeException(
286 (OUString("bad path ") +
288 css::uno::Reference
< css::uno::XInterface
>());
292 if (!templateName
.isEmpty() &&
293 !dynamic_cast< SetNode
* >(parent
.get())->isValidTemplate(
296 throw css::uno::RuntimeException(
297 (OUString("bad path ") +
299 css::uno::Reference
< css::uno::XInterface
>());
303 throw css::uno::RuntimeException(
304 (OUString("bad path ") +
306 css::uno::Reference
< css::uno::XInterface
>());
308 if (!templateName
.isEmpty() && p
!= 0) {
309 assert(!p
->getTemplateName().isEmpty());
310 if (!equalTemplateNames(templateName
, p
->getTemplateName())) {
311 throw css::uno::RuntimeException(
312 (OUString("bad path ") +
314 css::uno::Reference
< css::uno::XInterface
>());
321 rtl::Reference
< Node
> Data::getTemplate(
322 int layer
, OUString
const & fullName
) const
324 return findNode(layer
, templates
, fullName
);
327 NodeMap
& Data::getComponents() const {
328 return root_
->getMembers();
331 Additions
* Data::addExtensionXcuAdditions(
332 OUString
const & url
, int layer
)
334 rtl::Reference
< ExtensionXcu
> item(new ExtensionXcu
);
335 ExtensionXcuAdditions::iterator
i(
336 extensionXcuAdditions_
.insert(
337 ExtensionXcuAdditions::value_type(
338 url
, rtl::Reference
< ExtensionXcu
>())).first
);
339 if (i
->second
.is()) {
340 throw css::uno::RuntimeException(
341 (OUString("already added extension xcu ") +
343 css::uno::Reference
< css::uno::XInterface
>());
347 return &item
->additions
;
350 rtl::Reference
< Data::ExtensionXcu
> Data::removeExtensionXcuAdditions(
351 OUString
const & url
)
353 ExtensionXcuAdditions::iterator
i(extensionXcuAdditions_
.find(url
));
354 if (i
== extensionXcuAdditions_
.end()) {
355 // This can happen, as migration of pre OOo 3.3 UserInstallation
356 // extensions in dp_registry::backend::configuration::BackendImpl::
357 // PackageImpl::processPackage_ can cause just-in-time creation of
358 // extension xcu files that are never added via addExtensionXcuAdditions
359 // (also, there might be url spelling differences between calls to
360 // addExtensionXcuAdditions and removeExtensionXcuAdditions?):
363 "unknown Data::removeExtensionXcuAdditions(" << url
<< ")");
364 return rtl::Reference
< ExtensionXcu
>();
366 rtl::Reference
< ExtensionXcu
> item(i
->second
);
367 extensionXcuAdditions_
.erase(i
);
373 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */