1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "precompiled_configmgr.hxx"
25 #include "sal/config.h"
26
27 #include <algorithm>
28
29 #include "com/sun/star/uno/Reference.hxx"
30 #include "com/sun/star/uno/RuntimeException.hpp"
31 #include "com/sun/star/uno/XInterface.hpp"
32 #include "osl/diagnose.h"
33 #include "rtl/ref.hxx"
34 #include "rtl/string.h"
35 #include "rtl/textenc.h"
36 #include "rtl/ustrbuf.hxx"
37 #include "rtl/ustring.h"
38 #include "rtl/ustring.hxx"
39 #include "sal/types.h"
40
41 #include "additions.hxx"
42 #include "data.hxx"
43 #include "groupnode.hxx"
44 #include "node.hxx"
45 #include "nodemap.hxx"
46 #include "setnode.hxx"
47
48 namespace configmgr {
49
50 namespace {
51
52 namespace css = com::sun::star;
53
decode(rtl::OUString const & encoded,sal_Int32 begin,sal_Int32 end,rtl::OUString * decoded)54 bool decode(
55 rtl::OUString const & encoded, sal_Int32 begin, sal_Int32 end,
56 rtl::OUString * decoded)
57 {
58 OSL_ASSERT(
59 begin >= 0 && begin <= end && end <= encoded.getLength() &&
60 decoded != 0);
61 rtl::OUStringBuffer buf;
62 while (begin != end) {
63 sal_Unicode c = encoded[begin++];
64 if (c == '&') {
65 if (encoded.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("amp;"), begin))
66 {
67 buf.append(sal_Unicode('&'));
68 begin += RTL_CONSTASCII_LENGTH("amp;");
69 } else if (encoded.matchAsciiL(
70 RTL_CONSTASCII_STRINGPARAM("quot;"), begin))
71 {
72 buf.append(sal_Unicode('"'));
73 begin += RTL_CONSTASCII_LENGTH("quot;");
74 } else if (encoded.matchAsciiL(
75 RTL_CONSTASCII_STRINGPARAM("apos;"), begin))
76 {
77 buf.append(sal_Unicode('\''));
78 begin += RTL_CONSTASCII_LENGTH("apos;");
79 } else {
80 return false;
81 }
82 OSL_ASSERT(begin <= end);
83 } else {
84 buf.append(c);
85 }
86 }
87 *decoded = buf.makeStringAndClear();
88 return true;
89 }
90
91 }
92
createSegment(rtl::OUString const & templateName,rtl::OUString const & name)93 rtl::OUString Data::createSegment(
94 rtl::OUString const & templateName, rtl::OUString const & name)
95 {
96 if (templateName.getLength() == 0) {
97 return name;
98 }
99 rtl::OUStringBuffer buf(templateName);
100 //TODO: verify template name contains no bad chars?
101 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("['"));
102 for (sal_Int32 i = 0; i < name.getLength(); ++i) {
103 sal_Unicode c = name[i];
104 switch (c) {
105 case '&':
106 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("&"));
107 break;
108 case '"':
109 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("""));
110 break;
111 case '\'':
112 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("'"));
113 break;
114 default:
115 buf.append(c);
116 break;
117 }
118 }
119 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("']"));
120 return buf.makeStringAndClear();
121 }
122
parseSegment(rtl::OUString const & path,sal_Int32 index,rtl::OUString * name,bool * setElement,rtl::OUString * templateName)123 sal_Int32 Data::parseSegment(
124 rtl::OUString const & path, sal_Int32 index, rtl::OUString * name,
125 bool * setElement, rtl::OUString * templateName)
126 {
127 OSL_ASSERT(
128 index >= 0 && index <= path.getLength() && name != 0 &&
129 setElement != 0);
130 sal_Int32 i = index;
131 while (i < path.getLength() && path[i] != '/' && path[i] != '[') {
132 ++i;
133 }
134 if (i == path.getLength() || path[i] == '/') {
135 *name = path.copy(index, i - index);
136 *setElement = false;
137 return i;
138 }
139 if (templateName != 0) {
140 if (i - index == 1 && path[index] == '*') {
141 *templateName = rtl::OUString();
142 } else {
143 *templateName = path.copy(index, i - index);
144 }
145 }
146 if (++i == path.getLength()) {
147 return -1;
148 }
149 sal_Unicode del = path[i++];
150 if (del != '\'' && del != '"') {
151 return -1;
152 }
153 sal_Int32 j = path.indexOf(del, i);
154 if (j == -1 || j + 1 == path.getLength() || path[j + 1] != ']' ||
155 !decode(path, i, j, name))
156 {
157 return -1;
158 }
159 *setElement = true;
160 return j + 2;
161 }
162
fullTemplateName(rtl::OUString const & component,rtl::OUString const & name)163 rtl::OUString Data::fullTemplateName(
164 rtl::OUString const & component, rtl::OUString const & name)
165 {
166 if (component.indexOf(':') != -1 || name.indexOf(':') != -1) {
167 throw css::uno::RuntimeException(
168 (rtl::OUString(
169 RTL_CONSTASCII_USTRINGPARAM(
170 "bad component/name pair containing colon ")) +
171 component + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")) +
172 name),
173 css::uno::Reference< css::uno::XInterface >());
174 }
175 rtl::OUStringBuffer buf(component);
176 buf.append(sal_Unicode(':'));
177 buf.append(name);
178 return buf.makeStringAndClear();
179 }
180
equalTemplateNames(rtl::OUString const & shortName,rtl::OUString const & longName)181 bool Data::equalTemplateNames(
182 rtl::OUString const & shortName, rtl::OUString const & longName)
183 {
184 if (shortName.indexOf(':') == -1) {
185 sal_Int32 i = longName.indexOf(':') + 1;
186 OSL_ASSERT(i > 0);
187 return
188 rtl_ustr_compare_WithLength(
189 shortName.getStr(), shortName.getLength(),
190 longName.getStr() + i, longName.getLength() - i) ==
191 0;
192 } else {
193 return shortName == longName;
194 }
195 }
196
findNode(int layer,NodeMap const & map,rtl::OUString const & name)197 rtl::Reference< Node > Data::findNode(
198 int layer, NodeMap const & map, rtl::OUString const & name)
199 {
200 NodeMap::const_iterator i(map.find(name));
201 return i == map.end() || i->second->getLayer() > layer
202 ? rtl::Reference< Node >() : i->second;
203 }
204
resolvePathRepresentation(rtl::OUString const & pathRepresentation,rtl::OUString * canonicRepresentation,Path * path,int * finalizedLayer) const205 rtl::Reference< Node > Data::resolvePathRepresentation(
206 rtl::OUString const & pathRepresentation,
207 rtl::OUString * canonicRepresentation, Path * path, int * finalizedLayer)
208 const
209 {
210 if (pathRepresentation.getLength() == 0 || pathRepresentation[0] != '/') {
211 throw css::uno::RuntimeException(
212 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad path ")) +
213 pathRepresentation),
214 css::uno::Reference< css::uno::XInterface >());
215 }
216 rtl::OUString seg;
217 bool setElement;
218 rtl::OUString templateName;
219 sal_Int32 n = parseSegment(pathRepresentation, 1, &seg, &setElement, 0);
220 if (n == -1 || setElement)
221 {
222 throw css::uno::RuntimeException(
223 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad path ")) +
224 pathRepresentation),
225 css::uno::Reference< css::uno::XInterface >());
226 }
227 NodeMap::const_iterator i(components.find(seg));
228 rtl::OUStringBuffer canonic;
229 if (path != 0) {
230 path->clear();
231 }
232 rtl::Reference< Node > parent;
233 int finalized = NO_LAYER;
234 for (rtl::Reference< Node > p(i == components.end() ? 0 : i->second);;) {
235 if (!p.is()) {
236 return p;
237 }
238 if (canonicRepresentation != 0) {
239 canonic.append(sal_Unicode('/'));
240 canonic.append(createSegment(templateName, seg));
241 }
242 if (path != 0) {
243 path->push_back(seg);
244 }
245 finalized = std::min(finalized, p->getFinalized());
246 if (n != pathRepresentation.getLength() &&
247 pathRepresentation[n++] != '/')
248 {
249 throw css::uno::RuntimeException(
250 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad path ")) +
251 pathRepresentation),
252 css::uno::Reference< css::uno::XInterface >());
253 }
254 // for backwards compatibility, ignore a final slash
255 if (n == pathRepresentation.getLength()) {
256 if (canonicRepresentation != 0) {
257 *canonicRepresentation = canonic.makeStringAndClear();
258 }
259 if (finalizedLayer != 0) {
260 *finalizedLayer = finalized;
261 }
262 return p;
263 }
264 parent = p;
265 templateName = rtl::OUString();
266 n = parseSegment(
267 pathRepresentation, n, &seg, &setElement, &templateName);
268 if (n == -1) {
269 throw css::uno::RuntimeException(
270 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad path ")) +
271 pathRepresentation),
272 css::uno::Reference< css::uno::XInterface >());
273 }
274 // For backwards compatibility, allow set members to be accessed with
275 // simple path segments, like group members:
276 p = p->getMember(seg);
277 if (setElement) {
278 switch (parent->kind()) {
279 case Node::KIND_LOCALIZED_PROPERTY:
280 if (templateName.getLength() != 0) {
281 throw css::uno::RuntimeException(
282 (rtl::OUString(
283 RTL_CONSTASCII_USTRINGPARAM("bad path ")) +
284 pathRepresentation),
285 css::uno::Reference< css::uno::XInterface >());
286 }
287 break;
288 case Node::KIND_SET:
289 if (templateName.getLength() != 0 &&
290 !dynamic_cast< SetNode * >(parent.get())->isValidTemplate(
291 templateName))
292 {
293 throw css::uno::RuntimeException(
294 (rtl::OUString(
295 RTL_CONSTASCII_USTRINGPARAM("bad path ")) +
296 pathRepresentation),
297 css::uno::Reference< css::uno::XInterface >());
298 }
299 break;
300 default:
301 throw css::uno::RuntimeException(
302 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad path ")) +
303 pathRepresentation),
304 css::uno::Reference< css::uno::XInterface >());
305 }
306 if (templateName.getLength() != 0 && p != 0) {
307 OSL_ASSERT(p->getTemplateName().getLength() != 0);
308 if (!equalTemplateNames(templateName, p->getTemplateName())) {
309 throw css::uno::RuntimeException(
310 (rtl::OUString(
311 RTL_CONSTASCII_USTRINGPARAM("bad path ")) +
312 pathRepresentation),
313 css::uno::Reference< css::uno::XInterface >());
314 }
315 }
316 }
317 }
318 }
319
getTemplate(int layer,rtl::OUString const & fullName) const320 rtl::Reference< Node > Data::getTemplate(
321 int layer, rtl::OUString const & fullName) const
322 {
323 return findNode(layer, templates, fullName);
324 }
325
addExtensionXcuAdditions(rtl::OUString const & url,int layer)326 Additions * Data::addExtensionXcuAdditions(
327 rtl::OUString const & url, int layer)
328 {
329 rtl::Reference< ExtensionXcu > item(new ExtensionXcu);
330 ExtensionXcuAdditions::iterator i(
331 extensionXcuAdditions_.insert(
332 ExtensionXcuAdditions::value_type(
333 url, rtl::Reference< ExtensionXcu >())).first);
334 if (i->second.is()) {
335 throw css::uno::RuntimeException(
336 (rtl::OUString(
337 RTL_CONSTASCII_USTRINGPARAM(
338 "already added extension xcu ")) +
339 url),
340 css::uno::Reference< css::uno::XInterface >());
341 }
342 i->second = item;
343 item->layer = layer;
344 return &item->additions;
345 }
346
removeExtensionXcuAdditions(rtl::OUString const & url)347 rtl::Reference< Data::ExtensionXcu > Data::removeExtensionXcuAdditions(
348 rtl::OUString const & url)
349 {
350 ExtensionXcuAdditions::iterator i(extensionXcuAdditions_.find(url));
351 if (i == extensionXcuAdditions_.end()) {
352 // This can happen, as migration of pre OOo 3.3 UserInstallation
353 // extensions in dp_registry::backend::configuration::BackendImpl::
354 // PackageImpl::processPackage_ can cause just-in-time creation of
355 // extension xcu files that are never added via addExtensionXcuAdditions
356 // (also, there might be url spelling differences between calls to
357 // addExtensionXcuAdditions and removeExtensionXcuAdditions?):
358 OSL_TRACE(
359 "unknown configmgr::Data::removeExtensionXcuAdditions(%s)",
360 rtl::OUStringToOString(url, RTL_TEXTENCODING_UTF8).getStr());
361 return rtl::Reference< ExtensionXcu >();
362 }
363 rtl::Reference< ExtensionXcu > item(i->second);
364 extensionXcuAdditions_.erase(i);
365 return item;
366 }
367
368 }
369