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 1569 : 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 1569 : OUStringBuffer buf;
56 36708 : while (begin != end) {
57 33570 : sal_Unicode c = encoded[begin++];
58 33570 : if (c == '&') {
59 0 : if (encoded.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("amp;"), begin))
60 : {
61 0 : buf.append(sal_Unicode('&'));
62 0 : begin += RTL_CONSTASCII_LENGTH("amp;");
63 0 : } else if (encoded.matchAsciiL(
64 0 : RTL_CONSTASCII_STRINGPARAM("quot;"), begin))
65 : {
66 0 : buf.append(sal_Unicode('"'));
67 0 : begin += RTL_CONSTASCII_LENGTH("quot;");
68 0 : } else if (encoded.matchAsciiL(
69 0 : RTL_CONSTASCII_STRINGPARAM("apos;"), begin))
70 : {
71 0 : buf.append(sal_Unicode('\''));
72 0 : begin += RTL_CONSTASCII_LENGTH("apos;");
73 : } else {
74 0 : return false;
75 : }
76 : assert(begin <= end);
77 : } else {
78 33570 : buf.append(c);
79 : }
80 : }
81 1569 : *decoded = buf.makeStringAndClear();
82 1569 : return true;
83 : }
84 :
85 : }
86 :
87 14174 : OUString Data::createSegment(
88 : OUString const & templateName, OUString const & name)
89 : {
90 14174 : if (templateName.isEmpty()) {
91 14111 : return name;
92 : }
93 63 : OUStringBuffer buf(templateName);
94 : //TODO: verify template name contains no bad chars?
95 63 : buf.appendAscii("['");
96 1953 : for (sal_Int32 i = 0; i < name.getLength(); ++i) {
97 1890 : sal_Unicode c = name[i];
98 1890 : switch (c) {
99 : case '&':
100 0 : buf.appendAscii("&");
101 0 : break;
102 : case '"':
103 0 : buf.appendAscii(""");
104 0 : break;
105 : case '\'':
106 0 : buf.appendAscii("'");
107 0 : break;
108 : default:
109 1890 : buf.append(c);
110 1890 : break;
111 : }
112 : }
113 63 : buf.appendAscii("']");
114 63 : return buf.makeStringAndClear();
115 : }
116 :
117 91431 : sal_Int32 Data::parseSegment(
118 : OUString const & path, sal_Int32 index, OUString * name,
119 : bool * setElement, OUString * templateName)
120 : {
121 : assert(
122 : index >= 0 && index <= path.getLength() && name != 0 &&
123 : setElement != 0);
124 91431 : sal_Int32 i = index;
125 1385724 : while (i < path.getLength() && path[i] != '/' && path[i] != '[') {
126 1202862 : ++i;
127 : }
128 91431 : if (i == path.getLength() || path[i] == '/') {
129 89862 : *name = path.copy(index, i - index);
130 89862 : *setElement = false;
131 89862 : return i;
132 : }
133 1569 : if (templateName != 0) {
134 1569 : if (i - index == 1 && path[index] == '*') {
135 1505 : *templateName = OUString();
136 : } else {
137 64 : *templateName = path.copy(index, i - index);
138 : }
139 : }
140 1569 : if (++i == path.getLength()) {
141 0 : return -1;
142 : }
143 1569 : sal_Unicode del = path[i++];
144 1569 : if (del != '\'' && del != '"') {
145 0 : return -1;
146 : }
147 1569 : sal_Int32 j = path.indexOf(del, i);
148 3138 : if (j == -1 || j + 1 == path.getLength() || path[j + 1] != ']' ||
149 1569 : !decode(path, i, j, name))
150 : {
151 0 : return -1;
152 : }
153 1569 : *setElement = true;
154 1569 : return j + 2;
155 : }
156 :
157 15232 : OUString Data::fullTemplateName(
158 : OUString const & component, OUString const & name)
159 : {
160 15232 : if (component.indexOf(':') != -1 || name.indexOf(':') != -1) {
161 : throw css::uno::RuntimeException(
162 : (OUString("bad component/name pair containing colon ") +
163 0 : component + OUString("/") +
164 0 : name),
165 0 : css::uno::Reference< css::uno::XInterface >());
166 : }
167 15232 : OUStringBuffer buf(component);
168 15232 : buf.append(sal_Unicode(':'));
169 15232 : buf.append(name);
170 15232 : return buf.makeStringAndClear();
171 : }
172 :
173 243185 : bool Data::equalTemplateNames(
174 : OUString const & shortName, OUString const & longName)
175 : {
176 243185 : if (shortName.indexOf(':') == -1) {
177 0 : sal_Int32 i = longName.indexOf(':') + 1;
178 : assert(i > 0);
179 : return
180 : rtl_ustr_compare_WithLength(
181 : shortName.getStr(), shortName.getLength(),
182 0 : longName.getStr() + i, longName.getLength() - i) ==
183 0 : 0;
184 : } else {
185 243185 : return shortName == longName;
186 : }
187 : }
188 :
189 267479 : rtl::Reference< Node > Data::findNode(
190 : int layer, NodeMap const & map, OUString const & name)
191 : {
192 267479 : NodeMap::const_iterator i(map.find(name));
193 1069916 : return i == map.end() || i->second->getLayer() > layer
194 1337395 : ? rtl::Reference< Node >() : i->second;
195 : }
196 :
197 32 : Data::Data(): root_(new RootNode) {}
198 :
199 9922 : rtl::Reference< Node > Data::resolvePathRepresentation(
200 : OUString const & pathRepresentation,
201 : OUString * canonicRepresentation, Path * path, int * finalizedLayer)
202 : const
203 : {
204 9922 : if (pathRepresentation.isEmpty() || pathRepresentation[0] != '/') {
205 : throw css::uno::RuntimeException(
206 : (OUString("bad path ") +
207 0 : pathRepresentation),
208 0 : css::uno::Reference< css::uno::XInterface >());
209 : }
210 9922 : if (path != 0) {
211 8711 : path->clear();
212 : }
213 9922 : if ( pathRepresentation == "/" ) {
214 419 : if (canonicRepresentation != 0) {
215 419 : *canonicRepresentation = pathRepresentation;
216 : }
217 419 : if (finalizedLayer != 0) {
218 419 : *finalizedLayer = NO_LAYER;
219 : }
220 419 : return root_;
221 : }
222 9503 : OUString seg;
223 : bool setElement;
224 9503 : OUString templateName;
225 9503 : sal_Int32 n = parseSegment(pathRepresentation, 1, &seg, &setElement, 0);
226 9503 : if (n == -1 || setElement)
227 : {
228 : throw css::uno::RuntimeException(
229 : (OUString("bad path ") +
230 0 : pathRepresentation),
231 0 : css::uno::Reference< css::uno::XInterface >());
232 : }
233 9503 : NodeMap const & components = getComponents();
234 9503 : NodeMap::const_iterator i(components.find(seg));
235 9503 : OUStringBuffer canonic;
236 9503 : rtl::Reference< Node > parent;
237 9503 : int finalized = NO_LAYER;
238 15417 : for (rtl::Reference< Node > p(i == components.end() ? 0 : i->second);;) {
239 15417 : if (!p.is()) {
240 0 : return p;
241 : }
242 15417 : if (canonicRepresentation != 0) {
243 13958 : canonic.append(sal_Unicode('/'));
244 13958 : canonic.append(createSegment(templateName, seg));
245 : }
246 15417 : if (path != 0) {
247 13958 : path->push_back(seg);
248 : }
249 15417 : finalized = std::min(finalized, p->getFinalized());
250 22022 : if (n != pathRepresentation.getLength() &&
251 6605 : pathRepresentation[n++] != '/')
252 : {
253 : throw css::uno::RuntimeException(
254 : (OUString("bad path ") +
255 0 : pathRepresentation),
256 0 : css::uno::Reference< css::uno::XInterface >());
257 : }
258 : // for backwards compatibility, ignore a final slash
259 15417 : if (n == pathRepresentation.getLength()) {
260 9503 : if (canonicRepresentation != 0) {
261 8292 : *canonicRepresentation = canonic.makeStringAndClear();
262 : }
263 9503 : if (finalizedLayer != 0) {
264 9503 : *finalizedLayer = finalized;
265 : }
266 9503 : return p;
267 : }
268 5914 : parent = p;
269 5914 : templateName = OUString();
270 : n = parseSegment(
271 5914 : pathRepresentation, n, &seg, &setElement, &templateName);
272 5914 : if (n == -1) {
273 : throw css::uno::RuntimeException(
274 : (OUString("bad path ") +
275 0 : pathRepresentation),
276 0 : css::uno::Reference< css::uno::XInterface >());
277 : }
278 : // For backwards compatibility, allow set members to be accessed with
279 : // simple path segments, like group members:
280 5914 : p = p->getMember(seg);
281 5914 : if (setElement) {
282 128 : switch (parent->kind()) {
283 : case Node::KIND_LOCALIZED_PROPERTY:
284 0 : if (!templateName.isEmpty()) {
285 : throw css::uno::RuntimeException(
286 : (OUString("bad path ") +
287 0 : pathRepresentation),
288 0 : css::uno::Reference< css::uno::XInterface >());
289 : }
290 0 : break;
291 : case Node::KIND_SET:
292 128 : if (!templateName.isEmpty() &&
293 0 : !dynamic_cast< SetNode * >(parent.get())->isValidTemplate(
294 0 : templateName))
295 : {
296 : throw css::uno::RuntimeException(
297 : (OUString("bad path ") +
298 0 : pathRepresentation),
299 0 : css::uno::Reference< css::uno::XInterface >());
300 : }
301 128 : break;
302 : default:
303 : throw css::uno::RuntimeException(
304 : (OUString("bad path ") +
305 0 : pathRepresentation),
306 0 : css::uno::Reference< css::uno::XInterface >());
307 : }
308 128 : if (!templateName.isEmpty() && p != 0) {
309 : assert(!p->getTemplateName().isEmpty());
310 0 : if (!equalTemplateNames(templateName, p->getTemplateName())) {
311 : throw css::uno::RuntimeException(
312 : (OUString("bad path ") +
313 0 : pathRepresentation),
314 0 : css::uno::Reference< css::uno::XInterface >());
315 : }
316 : }
317 : }
318 9503 : }
319 : }
320 :
321 244593 : rtl::Reference< Node > Data::getTemplate(
322 : int layer, OUString const & fullName) const
323 : {
324 244593 : return findNode(layer, templates, fullName);
325 : }
326 :
327 16905 : NodeMap & Data::getComponents() const {
328 16905 : return root_->getMembers();
329 : }
330 :
331 0 : Additions * Data::addExtensionXcuAdditions(
332 : OUString const & url, int layer)
333 : {
334 0 : rtl::Reference< ExtensionXcu > item(new ExtensionXcu);
335 : ExtensionXcuAdditions::iterator i(
336 : extensionXcuAdditions_.insert(
337 : ExtensionXcuAdditions::value_type(
338 0 : url, rtl::Reference< ExtensionXcu >())).first);
339 0 : if (i->second.is()) {
340 : throw css::uno::RuntimeException(
341 : (OUString("already added extension xcu ") +
342 0 : url),
343 0 : css::uno::Reference< css::uno::XInterface >());
344 : }
345 0 : i->second = item;
346 0 : item->layer = layer;
347 0 : return &item->additions;
348 : }
349 :
350 0 : rtl::Reference< Data::ExtensionXcu > Data::removeExtensionXcuAdditions(
351 : OUString const & url)
352 : {
353 0 : ExtensionXcuAdditions::iterator i(extensionXcuAdditions_.find(url));
354 0 : 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?):
361 : SAL_INFO(
362 : "configmgr",
363 : "unknown Data::removeExtensionXcuAdditions(" << url << ")");
364 0 : return rtl::Reference< ExtensionXcu >();
365 : }
366 0 : rtl::Reference< ExtensionXcu > item(i->second);
367 0 : extensionXcuAdditions_.erase(i);
368 0 : return item;
369 : }
370 :
371 : }
372 :
373 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|