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 42946 : 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 42946 : OUStringBuffer buf;
56 972485 : while (begin != end) {
57 886593 : sal_Unicode c = encoded[begin++];
58 886593 : 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 886593 : buf.append(c);
74 : }
75 : }
76 42946 : *decoded = buf.makeStringAndClear();
77 42946 : return true;
78 : }
79 :
80 : }
81 :
82 372196 : OUString Data::createSegment(
83 : OUString const & templateName, OUString const & name)
84 : {
85 372196 : if (templateName.isEmpty()) {
86 358544 : return name;
87 : }
88 13652 : OUStringBuffer buf(templateName);
89 : //TODO: verify template name contains no bad chars?
90 13652 : buf.appendAscii("['");
91 398328 : for (sal_Int32 i = 0; i < name.getLength(); ++i) {
92 384676 : sal_Unicode c = name[i];
93 384676 : 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 384676 : buf.append(c);
105 384676 : break;
106 : }
107 : }
108 13652 : buf.appendAscii("']");
109 13652 : return buf.makeStringAndClear();
110 : }
111 :
112 6020324 : 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 6020324 : sal_Int32 i = index;
120 83157451 : while (i < path.getLength() && path[i] != '/' && path[i] != '[') {
121 71116803 : ++i;
122 : }
123 6020324 : if (i == path.getLength() || path[i] == '/') {
124 5977378 : *name = path.copy(index, i - index);
125 5977378 : *setElement = false;
126 5977378 : return i;
127 : }
128 42946 : if (templateName != 0) {
129 42946 : if (i - index == 1 && path[index] == '*') {
130 31428 : *templateName = "";
131 : } else {
132 11518 : *templateName = path.copy(index, i - index);
133 : }
134 : }
135 42946 : if (++i == path.getLength()) {
136 0 : return -1;
137 : }
138 42946 : sal_Unicode del = path[i++];
139 42946 : if (del != '\'' && del != '"') {
140 0 : return -1;
141 : }
142 42946 : sal_Int32 j = path.indexOf(del, i);
143 85892 : if (j == -1 || j + 1 == path.getLength() || path[j + 1] != ']' ||
144 42946 : !decode(path, i, j, name))
145 : {
146 0 : return -1;
147 : }
148 42946 : *setElement = true;
149 42946 : return j + 2;
150 : }
151 :
152 181737 : OUString Data::fullTemplateName(
153 : OUString const & component, OUString const & name)
154 : {
155 181737 : if (component.indexOf(':') != -1 || name.indexOf(':') != -1) {
156 : throw css::uno::RuntimeException(
157 0 : "bad component/name pair containing colon " + component + "/" +
158 0 : name);
159 : }
160 181737 : OUStringBuffer buf(component);
161 181737 : buf.append(':');
162 181737 : buf.append(name);
163 181737 : return buf.makeStringAndClear();
164 : }
165 :
166 2558693 : bool Data::equalTemplateNames(
167 : OUString const & shortName, OUString const & longName)
168 : {
169 2558693 : if (shortName.indexOf(':') == -1) {
170 50 : sal_Int32 i = longName.indexOf(':') + 1;
171 : assert(i > 0);
172 : return
173 : rtl_ustr_compare_WithLength(
174 : shortName.getStr(), shortName.getLength(),
175 50 : longName.getStr() + i, longName.getLength() - i) ==
176 50 : 0;
177 : } else {
178 2558643 : return shortName == longName;
179 : }
180 : }
181 :
182 381 : Data::Data(): root_(new RootNode) {}
183 :
184 242165 : rtl::Reference< Node > Data::resolvePathRepresentation(
185 : OUString const & pathRepresentation,
186 : OUString * canonicRepresentation, Path * path, int * finalizedLayer)
187 : const
188 : {
189 242165 : if (pathRepresentation.isEmpty() || pathRepresentation[0] != '/') {
190 : throw css::uno::RuntimeException(
191 0 : "bad path " + pathRepresentation);
192 : }
193 242165 : if (path != 0) {
194 176444 : path->clear();
195 : }
196 242165 : if (pathRepresentation == "/") {
197 8658 : if (canonicRepresentation != 0) {
198 8214 : *canonicRepresentation = pathRepresentation;
199 : }
200 8658 : if (finalizedLayer != 0) {
201 8658 : *finalizedLayer = NO_LAYER;
202 : }
203 8658 : return root_;
204 : }
205 233507 : OUString seg;
206 : bool setElement;
207 467014 : OUString templateName;
208 233507 : sal_Int32 n = parseSegment(pathRepresentation, 1, &seg, &setElement, 0);
209 233507 : if (n == -1 || setElement)
210 : {
211 : throw css::uno::RuntimeException(
212 0 : "bad path " + pathRepresentation);
213 : }
214 233507 : NodeMap const & components = getComponents();
215 233507 : NodeMap::const_iterator i(components.find(seg));
216 467014 : OUStringBuffer canonic;
217 467014 : rtl::Reference< Node > parent;
218 233507 : int finalized = NO_LAYER;
219 233507 : for (rtl::Reference< Node > p(i == components.end() ? 0 : i->second);;) {
220 353437 : if (!p.is()) {
221 0 : return p;
222 : }
223 353437 : if (canonicRepresentation != 0) {
224 250554 : canonic.append('/');
225 250554 : canonic.append(createSegment(templateName, seg));
226 : }
227 353437 : if (path != 0) {
228 264406 : path->push_back(seg);
229 : }
230 353437 : finalized = std::min(finalized, p->getFinalized());
231 490897 : if (n != pathRepresentation.getLength() &&
232 137460 : pathRepresentation[n++] != '/')
233 : {
234 : throw css::uno::RuntimeException(
235 0 : "bad path " + pathRepresentation);
236 : }
237 : // for backwards compatibility, ignore a final slash
238 353437 : if (n == pathRepresentation.getLength()) {
239 233507 : if (canonicRepresentation != 0) {
240 163338 : *canonicRepresentation = canonic.makeStringAndClear();
241 : }
242 233507 : if (finalizedLayer != 0) {
243 233507 : *finalizedLayer = finalized;
244 : }
245 233507 : return p;
246 : }
247 119930 : parent = p;
248 119930 : templateName = "";
249 : n = parseSegment(
250 119930 : pathRepresentation, n, &seg, &setElement, &templateName);
251 119930 : if (n == -1) {
252 : throw css::uno::RuntimeException(
253 0 : "bad path " + pathRepresentation);
254 : }
255 : // For backwards compatibility, allow set members to be accessed with
256 : // simple path segments, like group members:
257 119930 : p = p->getMember(seg);
258 119930 : if (setElement) {
259 2546 : switch (parent->kind()) {
260 : case Node::KIND_LOCALIZED_PROPERTY:
261 0 : if (!templateName.isEmpty()) {
262 : throw css::uno::RuntimeException(
263 0 : "bad path " + pathRepresentation);
264 : }
265 0 : break;
266 : case Node::KIND_SET:
267 3366 : if (!templateName.isEmpty() &&
268 820 : !static_cast< SetNode * >(parent.get())->isValidTemplate(
269 820 : templateName))
270 : {
271 : throw css::uno::RuntimeException(
272 0 : "bad path " + pathRepresentation);
273 : }
274 2546 : break;
275 : default:
276 : throw css::uno::RuntimeException(
277 0 : "bad path " + pathRepresentation);
278 : }
279 2546 : if (!templateName.isEmpty() && p != 0) {
280 : assert(!p->getTemplateName().isEmpty());
281 820 : if (!equalTemplateNames(templateName, p->getTemplateName())) {
282 : throw css::uno::RuntimeException(
283 0 : "bad path " + pathRepresentation);
284 : }
285 : }
286 : }
287 467014 : }
288 : }
289 :
290 2572243 : rtl::Reference< Node > Data::getTemplate(
291 : int layer, OUString const & fullName) const
292 : {
293 2572243 : return templates.findNode(layer, fullName);
294 : }
295 :
296 357914 : NodeMap & Data::getComponents() const {
297 357914 : return root_->getMembers();
298 : }
299 :
300 0 : Additions * Data::addExtensionXcuAdditions(
301 : OUString const & url, int layer)
302 : {
303 0 : rtl::Reference< ExtensionXcu > item(new ExtensionXcu);
304 : ExtensionXcuAdditions::iterator i(
305 : extensionXcuAdditions_.insert(
306 : ExtensionXcuAdditions::value_type(
307 0 : url, rtl::Reference< ExtensionXcu >())).first);
308 0 : if (i->second.is()) {
309 : throw css::uno::RuntimeException(
310 0 : "already added extension xcu " + url);
311 : }
312 0 : i->second = item;
313 0 : item->layer = layer;
314 0 : return &item->additions;
315 : }
316 :
317 0 : rtl::Reference< Data::ExtensionXcu > Data::removeExtensionXcuAdditions(
318 : OUString const & url)
319 : {
320 0 : ExtensionXcuAdditions::iterator i(extensionXcuAdditions_.find(url));
321 0 : 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?):
328 : SAL_INFO(
329 : "configmgr",
330 : "unknown Data::removeExtensionXcuAdditions(" << url << ")");
331 0 : return rtl::Reference< ExtensionXcu >();
332 : }
333 0 : rtl::Reference< ExtensionXcu > item(i->second);
334 0 : extensionXcuAdditions_.erase(i);
335 0 : return item;
336 : }
337 :
338 : }
339 :
340 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|