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("&")); 111 break; 112 case '"': 113 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(""")); 114 break; 115 case '\'': 116 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("'")); 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