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 25847 : 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 25847 : OUStringBuffer buf;
56 579027 : while (begin != end) {
57 527333 : sal_Unicode c = encoded[begin++];
58 527333 : 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 527333 : buf.append(c);
74 : }
75 : }
76 25847 : *decoded = buf.makeStringAndClear();
77 25847 : return true;
78 : }
79 :
80 : }
81 :
82 26922963 : OUString Data::createSegment(
83 : OUString const & templateName, OUString const & name)
84 : {
85 26922963 : if (templateName.isEmpty()) {
86 26913585 : return name;
87 : }
88 9378 : OUStringBuffer buf(templateName);
89 : //TODO: verify template name contains no bad chars?
90 9378 : buf.appendAscii("['");
91 271813 : for (sal_Int32 i = 0; i < name.getLength(); ++i) {
92 262435 : sal_Unicode c = name[i];
93 262435 : 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 262435 : buf.append(c);
105 262435 : break;
106 : }
107 : }
108 9378 : buf.appendAscii("']");
109 9378 : return buf.makeStringAndClear();
110 : }
111 :
112 30542965 : 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 30542965 : sal_Int32 i = index;
120 962160833 : while (i < path.getLength() && path[i] != '/' && path[i] != '[') {
121 901074903 : ++i;
122 : }
123 30542965 : if (i == path.getLength() || path[i] == '/') {
124 30517118 : *name = path.copy(index, i - index);
125 30517118 : *setElement = false;
126 30517118 : return i;
127 : }
128 25847 : if (templateName != 0) {
129 25847 : if (i - index == 1 && path[index] == '*') {
130 18961 : templateName->clear();
131 : } else {
132 6886 : *templateName = path.copy(index, i - index);
133 : }
134 : }
135 25847 : if (++i == path.getLength()) {
136 0 : return -1;
137 : }
138 25847 : sal_Unicode del = path[i++];
139 25847 : if (del != '\'' && del != '"') {
140 0 : return -1;
141 : }
142 25847 : sal_Int32 j = path.indexOf(del, i);
143 51694 : if (j == -1 || j + 1 == path.getLength() || path[j + 1] != ']' ||
144 25847 : !decode(path, i, j, name))
145 : {
146 0 : return -1;
147 : }
148 25847 : *setElement = true;
149 25847 : return j + 2;
150 : }
151 :
152 118500 : OUString Data::fullTemplateName(
153 : OUString const & component, OUString const & name)
154 : {
155 118500 : 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 118500 : OUStringBuffer buf(component);
161 118500 : buf.append(':');
162 118500 : buf.append(name);
163 118500 : return buf.makeStringAndClear();
164 : }
165 :
166 1684706 : bool Data::equalTemplateNames(
167 : OUString const & shortName, OUString const & longName)
168 : {
169 1684706 : if (shortName.indexOf(':') == -1) {
170 25 : sal_Int32 i = longName.indexOf(':') + 1;
171 : assert(i > 0);
172 : return
173 : rtl_ustr_compare_WithLength(
174 : shortName.getStr(), shortName.getLength(),
175 25 : longName.getStr() + i, longName.getLength() - i) ==
176 25 : 0;
177 : } else {
178 1684681 : return shortName == longName;
179 : }
180 : }
181 :
182 250 : Data::Data(): root_(new RootNode) {}
183 :
184 26862224 : rtl::Reference< Node > Data::resolvePathRepresentation(
185 : OUString const & pathRepresentation,
186 : OUString * canonicRepresentation, Path * path, int * finalizedLayer)
187 : const
188 : {
189 26862224 : if (pathRepresentation.isEmpty() || pathRepresentation[0] != '/') {
190 : throw css::uno::RuntimeException(
191 0 : "bad path " + pathRepresentation);
192 : }
193 26862224 : if (path != 0) {
194 26824748 : path->clear();
195 : }
196 26862224 : if (pathRepresentation == "/") {
197 5696 : if (canonicRepresentation != 0) {
198 5185 : *canonicRepresentation = pathRepresentation;
199 : }
200 5696 : if (finalizedLayer != 0) {
201 5696 : *finalizedLayer = NO_LAYER;
202 : }
203 5696 : return root_;
204 : }
205 26856528 : OUString seg;
206 : bool setElement;
207 53713056 : OUString templateName;
208 26856528 : sal_Int32 n = parseSegment(pathRepresentation, 1, &seg, &setElement, 0);
209 26856528 : if (n == -1 || setElement)
210 : {
211 : throw css::uno::RuntimeException(
212 0 : "bad path " + pathRepresentation);
213 : }
214 26856528 : NodeMap const & components = getComponents();
215 26856528 : NodeMap::const_iterator i(components.find(seg));
216 53713056 : OUStringBuffer canonic;
217 53713056 : rtl::Reference< Node > parent;
218 26856528 : int finalized = NO_LAYER;
219 26856528 : for (rtl::Reference< Node > p(i == components.end() ? 0 : i->second);;) {
220 26921396 : if (!p.is()) {
221 0 : return p;
222 : }
223 26921396 : if (canonicRepresentation != 0) {
224 26871615 : canonic.append('/');
225 26871615 : canonic.append(createSegment(templateName, seg));
226 : }
227 26921396 : if (path != 0) {
228 26876727 : path->push_back(seg);
229 : }
230 26921396 : finalized = std::min(finalized, p->getFinalized());
231 26996592 : if (n != pathRepresentation.getLength() &&
232 75196 : pathRepresentation[n++] != '/')
233 : {
234 : throw css::uno::RuntimeException(
235 0 : "bad path " + pathRepresentation);
236 : }
237 : // for backwards compatibility, ignore a final slash
238 26921396 : if (n == pathRepresentation.getLength()) {
239 26856528 : if (canonicRepresentation != 0) {
240 26817660 : *canonicRepresentation = canonic.makeStringAndClear();
241 : }
242 26856528 : if (finalizedLayer != 0) {
243 26856528 : *finalizedLayer = finalized;
244 : }
245 26856528 : return p;
246 : }
247 64868 : parent = p;
248 64868 : templateName.clear();
249 : n = parseSegment(
250 64868 : pathRepresentation, n, &seg, &setElement, &templateName);
251 64868 : 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 64868 : p = p->getMember(seg);
258 64868 : if (setElement) {
259 1335 : 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 1782 : if (!templateName.isEmpty() &&
268 447 : !static_cast< SetNode * >(parent.get())->isValidTemplate(
269 447 : templateName))
270 : {
271 : throw css::uno::RuntimeException(
272 0 : "bad path " + pathRepresentation);
273 : }
274 1335 : break;
275 : default:
276 : throw css::uno::RuntimeException(
277 0 : "bad path " + pathRepresentation);
278 : }
279 1335 : if (!templateName.isEmpty() && p != 0) {
280 : assert(!p->getTemplateName().isEmpty());
281 447 : if (!equalTemplateNames(templateName, p->getTemplateName())) {
282 : throw css::uno::RuntimeException(
283 0 : "bad path " + pathRepresentation);
284 : }
285 : }
286 : }
287 53713056 : }
288 : }
289 :
290 1693787 : rtl::Reference< Node > Data::getTemplate(
291 : int layer, OUString const & fullName) const
292 : {
293 1693787 : return templates.findNode(layer, fullName);
294 : }
295 :
296 26936191 : NodeMap & Data::getComponents() const {
297 26936191 : 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: */
|