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