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 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 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("&")); 107 break; 108 case '"': 109 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(""")); 110 break; 111 case '\'': 112 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("'")); 113 break; 114 default: 115 buf.append(c); 116 break; 117 } 118 } 119 buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("']")); 120 return buf.makeStringAndClear(); 121 } 122 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 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 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 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 205 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 320 rtl::Reference< Node > Data::getTemplate( 321 int layer, rtl::OUString const & fullName) const 322 { 323 return findNode(layer, templates, fullName); 324 } 325 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 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