Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "sal/config.h"
21 :
22 : #include <algorithm>
23 : #include <cassert>
24 :
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"
35 :
36 : #include "additions.hxx"
37 : #include "data.hxx"
38 : #include "groupnode.hxx"
39 : #include "node.hxx"
40 : #include "nodemap.hxx"
41 : #include "rootnode.hxx"
42 : #include "setnode.hxx"
43 :
44 : namespace configmgr {
45 :
46 : namespace {
47 :
48 0 : bool decode(
49 : OUString const & encoded, sal_Int32 begin, sal_Int32 end,
50 : OUString * decoded)
51 : {
52 : assert(
53 : begin >= 0 && begin <= end && end <= encoded.getLength() &&
54 : decoded != 0);
55 0 : OUStringBuffer buf;
56 0 : while (begin != end) {
57 0 : sal_Unicode c = encoded[begin++];
58 0 : if (c == '&') {
59 0 : if (encoded.match("amp;", begin)) {
60 0 : buf.append('&');
61 0 : begin += RTL_CONSTASCII_LENGTH("amp;");
62 0 : } else if (encoded.match("quot;", begin)) {
63 0 : buf.append('"');
64 0 : begin += RTL_CONSTASCII_LENGTH("quot;");
65 0 : } else if (encoded.match("apos;", begin)) {
66 0 : buf.append('\'');
67 0 : begin += RTL_CONSTASCII_LENGTH("apos;");
68 : } else {
69 0 : return false;
70 : }
71 : assert(begin <= end);
72 : } else {
73 0 : buf.append(c);
74 : }
75 : }
76 0 : *decoded = buf.makeStringAndClear();
77 0 : return true;
78 : }
79 :
80 : }
81 :
82 0 : OUString Data::createSegment(
83 : OUString const & templateName, OUString const & name)
84 : {
85 0 : if (templateName.isEmpty()) {
86 0 : return name;
87 : }
88 0 : OUStringBuffer buf(templateName);
89 : //TODO: verify template name contains no bad chars?
90 0 : buf.appendAscii("['");
91 0 : for (sal_Int32 i = 0; i < name.getLength(); ++i) {
92 0 : sal_Unicode c = name[i];
93 0 : switch (c) {
94 : case '&':
95 0 : buf.appendAscii("&");
96 0 : break;
97 : case '"':
98 0 : buf.appendAscii(""");
99 0 : break;
100 : case '\'':
101 0 : buf.appendAscii("'");
102 0 : break;
103 : default:
104 0 : buf.append(c);
105 0 : break;
106 : }
107 : }
108 0 : buf.appendAscii("']");
109 0 : return buf.makeStringAndClear();
110 : }
111 :
112 0 : sal_Int32 Data::parseSegment(
113 : OUString const & path, sal_Int32 index, OUString * name,
114 : bool * setElement, OUString * templateName)
115 : {
116 : assert(
117 : index >= 0 && index <= path.getLength() && name != 0 &&
118 : setElement != 0);
119 0 : sal_Int32 i = index;
120 0 : while (i < path.getLength() && path[i] != '/' && path[i] != '[') {
121 0 : ++i;
122 : }
123 0 : if (i == path.getLength() || path[i] == '/') {
124 0 : *name = path.copy(index, i - index);
125 0 : *setElement = false;
126 0 : return i;
127 : }
128 0 : if (templateName != 0) {
129 0 : if (i - index == 1 && path[index] == '*') {
130 0 : *templateName = "";
131 : } else {
132 0 : *templateName = path.copy(index, i - index);
133 : }
134 : }
135 0 : if (++i == path.getLength()) {
136 0 : return -1;
137 : }
138 0 : sal_Unicode del = path[i++];
139 0 : if (del != '\'' && del != '"') {
140 0 : return -1;
141 : }
142 0 : sal_Int32 j = path.indexOf(del, i);
143 0 : if (j == -1 || j + 1 == path.getLength() || path[j + 1] != ']' ||
144 0 : !decode(path, i, j, name))
145 : {
146 0 : return -1;
147 : }
148 0 : *setElement = true;
149 0 : return j + 2;
150 : }
151 :
152 0 : OUString Data::fullTemplateName(
153 : OUString const & component, OUString const & name)
154 : {
155 0 : if (component.indexOf(':') != -1 || name.indexOf(':') != -1) {
156 : throw css::uno::RuntimeException(
157 0 : ("bad component/name pair containing colon " + component + "/" +
158 : name),
159 0 : css::uno::Reference< css::uno::XInterface >());
160 : }
161 0 : OUStringBuffer buf(component);
162 0 : buf.append(':');
163 0 : buf.append(name);
164 0 : return buf.makeStringAndClear();
165 : }
166 :
167 0 : bool Data::equalTemplateNames(
168 : OUString const & shortName, OUString const & longName)
169 : {
170 0 : if (shortName.indexOf(':') == -1) {
171 0 : sal_Int32 i = longName.indexOf(':') + 1;
172 : assert(i > 0);
173 : return
174 : rtl_ustr_compare_WithLength(
175 : shortName.getStr(), shortName.getLength(),
176 0 : longName.getStr() + i, longName.getLength() - i) ==
177 0 : 0;
178 : } else {
179 0 : return shortName == longName;
180 : }
181 : }
182 :
183 0 : rtl::Reference< Node > Data::findNode(
184 : int layer, NodeMap const & map, OUString const & name)
185 : {
186 0 : NodeMap::const_iterator i(map.find(name));
187 0 : return i == map.end() || i->second->getLayer() > layer
188 0 : ? rtl::Reference< Node >() : i->second;
189 : }
190 :
191 0 : Data::Data(): root_(new RootNode) {}
192 :
193 0 : rtl::Reference< Node > Data::resolvePathRepresentation(
194 : OUString const & pathRepresentation,
195 : OUString * canonicRepresentation, Path * path, int * finalizedLayer)
196 : const
197 : {
198 0 : if (pathRepresentation.isEmpty() || pathRepresentation[0] != '/') {
199 : throw css::uno::RuntimeException(
200 0 : "bad path " + pathRepresentation,
201 0 : css::uno::Reference< css::uno::XInterface >());
202 : }
203 0 : if (path != 0) {
204 0 : path->clear();
205 : }
206 0 : if (pathRepresentation == "/") {
207 0 : if (canonicRepresentation != 0) {
208 0 : *canonicRepresentation = pathRepresentation;
209 : }
210 0 : if (finalizedLayer != 0) {
211 0 : *finalizedLayer = NO_LAYER;
212 : }
213 0 : return root_;
214 : }
215 0 : OUString seg;
216 : bool setElement;
217 0 : OUString templateName;
218 0 : sal_Int32 n = parseSegment(pathRepresentation, 1, &seg, &setElement, 0);
219 0 : if (n == -1 || setElement)
220 : {
221 : throw css::uno::RuntimeException(
222 0 : "bad path " + pathRepresentation,
223 0 : css::uno::Reference< css::uno::XInterface >());
224 : }
225 0 : NodeMap const & components = getComponents();
226 0 : NodeMap::const_iterator i(components.find(seg));
227 0 : OUStringBuffer canonic;
228 0 : rtl::Reference< Node > parent;
229 0 : int finalized = NO_LAYER;
230 0 : for (rtl::Reference< Node > p(i == components.end() ? 0 : i->second);;) {
231 0 : if (!p.is()) {
232 0 : return p;
233 : }
234 0 : if (canonicRepresentation != 0) {
235 0 : canonic.append('/');
236 0 : canonic.append(createSegment(templateName, seg));
237 : }
238 0 : if (path != 0) {
239 0 : path->push_back(seg);
240 : }
241 0 : finalized = std::min(finalized, p->getFinalized());
242 0 : if (n != pathRepresentation.getLength() &&
243 0 : pathRepresentation[n++] != '/')
244 : {
245 : throw css::uno::RuntimeException(
246 0 : "bad path " + pathRepresentation,
247 0 : css::uno::Reference< css::uno::XInterface >());
248 : }
249 : // for backwards compatibility, ignore a final slash
250 0 : if (n == pathRepresentation.getLength()) {
251 0 : if (canonicRepresentation != 0) {
252 0 : *canonicRepresentation = canonic.makeStringAndClear();
253 : }
254 0 : if (finalizedLayer != 0) {
255 0 : *finalizedLayer = finalized;
256 : }
257 0 : return p;
258 : }
259 0 : parent = p;
260 0 : templateName = "";
261 : n = parseSegment(
262 0 : pathRepresentation, n, &seg, &setElement, &templateName);
263 0 : if (n == -1) {
264 : throw css::uno::RuntimeException(
265 0 : "bad path " + pathRepresentation,
266 0 : css::uno::Reference< css::uno::XInterface >());
267 : }
268 : // For backwards compatibility, allow set members to be accessed with
269 : // simple path segments, like group members:
270 0 : p = p->getMember(seg);
271 0 : if (setElement) {
272 0 : switch (parent->kind()) {
273 : case Node::KIND_LOCALIZED_PROPERTY:
274 0 : if (!templateName.isEmpty()) {
275 : throw css::uno::RuntimeException(
276 0 : "bad path " + pathRepresentation,
277 0 : css::uno::Reference< css::uno::XInterface >());
278 : }
279 0 : break;
280 : case Node::KIND_SET:
281 0 : if (!templateName.isEmpty() &&
282 0 : !static_cast< SetNode * >(parent.get())->isValidTemplate(
283 0 : templateName))
284 : {
285 : throw css::uno::RuntimeException(
286 0 : "bad path " + pathRepresentation,
287 0 : css::uno::Reference< css::uno::XInterface >());
288 : }
289 0 : break;
290 : default:
291 : throw css::uno::RuntimeException(
292 0 : "bad path " + pathRepresentation,
293 0 : css::uno::Reference< css::uno::XInterface >());
294 : }
295 0 : if (!templateName.isEmpty() && p != 0) {
296 : assert(!p->getTemplateName().isEmpty());
297 0 : if (!equalTemplateNames(templateName, p->getTemplateName())) {
298 : throw css::uno::RuntimeException(
299 0 : "bad path " + pathRepresentation,
300 0 : css::uno::Reference< css::uno::XInterface >());
301 : }
302 : }
303 : }
304 0 : }
305 : }
306 :
307 0 : rtl::Reference< Node > Data::getTemplate(
308 : int layer, OUString const & fullName) const
309 : {
310 0 : return findNode(layer, templates, fullName);
311 : }
312 :
313 0 : NodeMap & Data::getComponents() const {
314 0 : return root_->getMembers();
315 : }
316 :
317 0 : Additions * Data::addExtensionXcuAdditions(
318 : OUString const & url, int layer)
319 : {
320 0 : rtl::Reference< ExtensionXcu > item(new ExtensionXcu);
321 : ExtensionXcuAdditions::iterator i(
322 : extensionXcuAdditions_.insert(
323 : ExtensionXcuAdditions::value_type(
324 0 : url, rtl::Reference< ExtensionXcu >())).first);
325 0 : if (i->second.is()) {
326 : throw css::uno::RuntimeException(
327 0 : "already added extension xcu " + url,
328 0 : css::uno::Reference< css::uno::XInterface >());
329 : }
330 0 : i->second = item;
331 0 : item->layer = layer;
332 0 : return &item->additions;
333 : }
334 :
335 0 : rtl::Reference< Data::ExtensionXcu > Data::removeExtensionXcuAdditions(
336 : OUString const & url)
337 : {
338 0 : ExtensionXcuAdditions::iterator i(extensionXcuAdditions_.find(url));
339 0 : if (i == extensionXcuAdditions_.end()) {
340 : // This can happen, as migration of pre OOo 3.3 UserInstallation
341 : // extensions in dp_registry::backend::configuration::BackendImpl::
342 : // PackageImpl::processPackage_ can cause just-in-time creation of
343 : // extension xcu files that are never added via addExtensionXcuAdditions
344 : // (also, there might be url spelling differences between calls to
345 : // addExtensionXcuAdditions and removeExtensionXcuAdditions?):
346 : SAL_INFO(
347 : "configmgr",
348 : "unknown Data::removeExtensionXcuAdditions(" << url << ")");
349 0 : return rtl::Reference< ExtensionXcu >();
350 : }
351 0 : rtl::Reference< ExtensionXcu > item(i->second);
352 0 : extensionXcuAdditions_.erase(i);
353 0 : return item;
354 : }
355 :
356 : }
357 :
358 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|