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