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 rtl::OUString
const & encoded
, sal_Int32 begin
, sal_Int32 end
,
50 rtl::OUString
* decoded
)
53 begin
>= 0 && begin
<= end
&& end
<= encoded
.getLength() &&
55 rtl::OUStringBuffer buf
;
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 rtl::OUString
Data::createSegment(
88 rtl::OUString
const & templateName
, rtl::OUString
const & name
)
90 if (templateName
.isEmpty()) {
93 rtl::OUStringBuffer
buf(templateName
);
94 //TODO: verify template name contains no bad chars?
95 buf
.appendAscii(RTL_CONSTASCII_STRINGPARAM("['"));
96 for (sal_Int32 i
= 0; i
< name
.getLength(); ++i
) {
97 sal_Unicode c
= name
[i
];
100 buf
.appendAscii(RTL_CONSTASCII_STRINGPARAM("&"));
103 buf
.appendAscii(RTL_CONSTASCII_STRINGPARAM("""));
106 buf
.appendAscii(RTL_CONSTASCII_STRINGPARAM("'"));
113 buf
.appendAscii(RTL_CONSTASCII_STRINGPARAM("']"));
114 return buf
.makeStringAndClear();
117 sal_Int32
Data::parseSegment(
118 rtl::OUString
const & path
, sal_Int32 index
, rtl::OUString
* name
,
119 bool * setElement
, rtl::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
= rtl::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 rtl::OUString
Data::fullTemplateName(
158 rtl::OUString
const & component
, rtl::OUString
const & name
)
160 if (component
.indexOf(':') != -1 || name
.indexOf(':') != -1) {
161 throw css::uno::RuntimeException(
163 RTL_CONSTASCII_USTRINGPARAM(
164 "bad component/name pair containing colon ")) +
165 component
+ rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")) +
167 css::uno::Reference
< css::uno::XInterface
>());
169 rtl::OUStringBuffer
buf(component
);
170 buf
.append(sal_Unicode(':'));
172 return buf
.makeStringAndClear();
175 bool Data::equalTemplateNames(
176 rtl::OUString
const & shortName
, rtl::OUString
const & longName
)
178 if (shortName
.indexOf(':') == -1) {
179 sal_Int32 i
= longName
.indexOf(':') + 1;
182 rtl_ustr_compare_WithLength(
183 shortName
.getStr(), shortName
.getLength(),
184 longName
.getStr() + i
, longName
.getLength() - i
) ==
187 return shortName
== longName
;
191 rtl::Reference
< Node
> Data::findNode(
192 int layer
, NodeMap
const & map
, rtl::OUString
const & name
)
194 NodeMap::const_iterator
i(map
.find(name
));
195 return i
== map
.end() || i
->second
->getLayer() > layer
196 ? rtl::Reference
< Node
>() : i
->second
;
199 Data::Data(): root_(new RootNode
) {}
201 rtl::Reference
< Node
> Data::resolvePathRepresentation(
202 rtl::OUString
const & pathRepresentation
,
203 rtl::OUString
* canonicRepresentation
, Path
* path
, int * finalizedLayer
)
206 if (pathRepresentation
.isEmpty() || pathRepresentation
[0] != '/') {
207 throw css::uno::RuntimeException(
208 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad path ")) +
210 css::uno::Reference
< css::uno::XInterface
>());
215 if ( pathRepresentation
== "/" ) {
216 if (canonicRepresentation
!= 0) {
217 *canonicRepresentation
= pathRepresentation
;
219 if (finalizedLayer
!= 0) {
220 *finalizedLayer
= NO_LAYER
;
226 rtl::OUString templateName
;
227 sal_Int32 n
= parseSegment(pathRepresentation
, 1, &seg
, &setElement
, 0);
228 if (n
== -1 || setElement
)
230 throw css::uno::RuntimeException(
231 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad path ")) +
233 css::uno::Reference
< css::uno::XInterface
>());
235 NodeMap
const & components
= getComponents();
236 NodeMap::const_iterator
i(components
.find(seg
));
237 rtl::OUStringBuffer canonic
;
238 rtl::Reference
< Node
> parent
;
239 int finalized
= NO_LAYER
;
240 for (rtl::Reference
< Node
> p(i
== components
.end() ? 0 : i
->second
);;) {
244 if (canonicRepresentation
!= 0) {
245 canonic
.append(sal_Unicode('/'));
246 canonic
.append(createSegment(templateName
, seg
));
249 path
->push_back(seg
);
251 finalized
= std::min(finalized
, p
->getFinalized());
252 if (n
!= pathRepresentation
.getLength() &&
253 pathRepresentation
[n
++] != '/')
255 throw css::uno::RuntimeException(
256 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad path ")) +
258 css::uno::Reference
< css::uno::XInterface
>());
260 // for backwards compatibility, ignore a final slash
261 if (n
== pathRepresentation
.getLength()) {
262 if (canonicRepresentation
!= 0) {
263 *canonicRepresentation
= canonic
.makeStringAndClear();
265 if (finalizedLayer
!= 0) {
266 *finalizedLayer
= finalized
;
271 templateName
= rtl::OUString();
273 pathRepresentation
, n
, &seg
, &setElement
, &templateName
);
275 throw css::uno::RuntimeException(
276 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad path ")) +
278 css::uno::Reference
< css::uno::XInterface
>());
280 // For backwards compatibility, allow set members to be accessed with
281 // simple path segments, like group members:
282 p
= p
->getMember(seg
);
284 switch (parent
->kind()) {
285 case Node::KIND_LOCALIZED_PROPERTY
:
286 if (!templateName
.isEmpty()) {
287 throw css::uno::RuntimeException(
289 RTL_CONSTASCII_USTRINGPARAM("bad path ")) +
291 css::uno::Reference
< css::uno::XInterface
>());
295 if (!templateName
.isEmpty() &&
296 !dynamic_cast< SetNode
* >(parent
.get())->isValidTemplate(
299 throw css::uno::RuntimeException(
301 RTL_CONSTASCII_USTRINGPARAM("bad path ")) +
303 css::uno::Reference
< css::uno::XInterface
>());
307 throw css::uno::RuntimeException(
308 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad path ")) +
310 css::uno::Reference
< css::uno::XInterface
>());
312 if (!templateName
.isEmpty() && p
!= 0) {
313 assert(!p
->getTemplateName().isEmpty());
314 if (!equalTemplateNames(templateName
, p
->getTemplateName())) {
315 throw css::uno::RuntimeException(
317 RTL_CONSTASCII_USTRINGPARAM("bad path ")) +
319 css::uno::Reference
< css::uno::XInterface
>());
326 rtl::Reference
< Node
> Data::getTemplate(
327 int layer
, rtl::OUString
const & fullName
) const
329 return findNode(layer
, templates
, fullName
);
332 NodeMap
& Data::getComponents() const {
333 return root_
->getMembers();
336 Additions
* Data::addExtensionXcuAdditions(
337 rtl::OUString
const & url
, int layer
)
339 rtl::Reference
< ExtensionXcu
> item(new ExtensionXcu
);
340 ExtensionXcuAdditions::iterator
i(
341 extensionXcuAdditions_
.insert(
342 ExtensionXcuAdditions::value_type(
343 url
, rtl::Reference
< ExtensionXcu
>())).first
);
344 if (i
->second
.is()) {
345 throw css::uno::RuntimeException(
347 RTL_CONSTASCII_USTRINGPARAM(
348 "already added extension xcu ")) +
350 css::uno::Reference
< css::uno::XInterface
>());
354 return &item
->additions
;
357 rtl::Reference
< Data::ExtensionXcu
> Data::removeExtensionXcuAdditions(
358 rtl::OUString
const & url
)
360 ExtensionXcuAdditions::iterator
i(extensionXcuAdditions_
.find(url
));
361 if (i
== extensionXcuAdditions_
.end()) {
362 // This can happen, as migration of pre OOo 3.3 UserInstallation
363 // extensions in dp_registry::backend::configuration::BackendImpl::
364 // PackageImpl::processPackage_ can cause just-in-time creation of
365 // extension xcu files that are never added via addExtensionXcuAdditions
366 // (also, there might be url spelling differences between calls to
367 // addExtensionXcuAdditions and removeExtensionXcuAdditions?):
370 "unknown Data::removeExtensionXcuAdditions(" << url
<< ")");
371 return rtl::Reference
< ExtensionXcu
>();
373 rtl::Reference
< ExtensionXcu
> item(i
->second
);
374 extensionXcuAdditions_
.erase(i
);
380 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */