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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_desktop.hxx"
26
27 //TODO: Large parts of this file were copied from dp_component.cxx; those parts
28 // should be consolidated.
29
30 #include "dp_configuration.hrc"
31 #include "dp_backend.h"
32 #include "dp_persmap.h"
33 #include "dp_ucb.h"
34 #include "rtl/string.hxx"
35 #include "rtl/ustrbuf.hxx"
36 #include "rtl/uri.hxx"
37 #include "rtl/memory.h"
38 #include "osl/file.hxx"
39 #include "cppuhelper/exc_hlp.hxx"
40 #include "ucbhelper/content.hxx"
41 #include "comphelper/anytostring.hxx"
42 #include "comphelper/servicedecl.hxx"
43 #include "xmlscript/xml_helper.hxx"
44 #include "svl/inettype.hxx"
45 #include "com/sun/star/configuration/Update.hpp"
46 #include "com/sun/star/ucb/NameClash.hpp"
47 #include "com/sun/star/io/XActiveDataSink.hpp"
48 #include "com/sun/star/lang/WrappedTargetRuntimeException.hpp"
49 #include "com/sun/star/util/XRefreshable.hpp"
50 #include <list>
51 #include <memory>
52
53 #include "dp_configurationbackenddb.hxx"
54
55 using namespace ::dp_misc;
56 using namespace ::com::sun::star;
57 using namespace ::com::sun::star::uno;
58 using namespace ::com::sun::star::ucb;
59 using ::rtl::OUString;
60
61 namespace dp_registry {
62 namespace backend {
63 namespace configuration {
64 namespace {
65
66 typedef ::std::list<OUString> t_stringlist;
67
68 //==============================================================================
69 class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend
70 {
71 class PackageImpl : public ::dp_registry::backend::Package
72 {
73 BackendImpl * getMyBackend() const ;
74
75 const bool m_isSchema;
76
77 // Package
78 virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_(
79 ::osl::ResettableMutexGuard & guard,
80 ::rtl::Reference<AbortChannel> const & abortChannel,
81 Reference<XCommandEnvironment> const & xCmdEnv );
82 virtual void processPackage_(
83 ::osl::ResettableMutexGuard & guard,
84 bool registerPackage,
85 bool startup,
86 ::rtl::Reference<AbortChannel> const & abortChannel,
87 Reference<XCommandEnvironment> const & xCmdEnv );
88
89 public:
PackageImpl(::rtl::Reference<PackageRegistryBackend> const & myBackend,OUString const & url,OUString const & name,Reference<deployment::XPackageTypeInfo> const & xPackageType,bool isSchema,bool bRemoved,OUString const & identifier)90 inline PackageImpl(
91 ::rtl::Reference<PackageRegistryBackend> const & myBackend,
92 OUString const & url, OUString const & name,
93 Reference<deployment::XPackageTypeInfo> const & xPackageType,
94 bool isSchema, bool bRemoved, OUString const & identifier)
95 : Package( myBackend, url, name, name /* display-name */,
96 xPackageType, bRemoved, identifier),
97 m_isSchema( isSchema )
98 {}
99 };
100 friend class PackageImpl;
101
102 t_stringlist m_xcs_files;
103 t_stringlist m_xcu_files;
getFiles(bool xcs)104 t_stringlist & getFiles( bool xcs ) {
105 return xcs ? m_xcs_files : m_xcu_files;
106 }
107
108 bool m_configmgrini_inited;
109 bool m_configmgrini_modified;
110 std::auto_ptr<ConfigurationBackendDb> m_backendDb;
111
112 // PackageRegistryBackend
113 virtual Reference<deployment::XPackage> bindPackage_(
114 OUString const & url, OUString const & mediaType, sal_Bool bRemoved,
115 OUString const & identifier,
116 Reference<XCommandEnvironment> const & xCmdEnv );
117
118 ::std::auto_ptr<PersistentMap> m_registeredPackages;
119 // for backwards compatibility
120
121 virtual void SAL_CALL disposing();
122
123 const Reference<deployment::XPackageTypeInfo> m_xConfDataTypeInfo;
124 const Reference<deployment::XPackageTypeInfo> m_xConfSchemaTypeInfo;
125 Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos;
126
127 void configmgrini_verify_init(
128 Reference<XCommandEnvironment> const & xCmdEnv );
129 void configmgrini_flush( Reference<XCommandEnvironment> const & xCmdEnv );
130
131 /* The parameter isURL is false in the case of adding the conf:ini-entry
132 value from the backend db. This entry already contains the path as it
133 is used in the configmgr.ini.
134 */
135 bool addToConfigmgrIni( bool isSchema, bool isURL, OUString const & url,
136 Reference<XCommandEnvironment> const & xCmdEnv );
137 bool removeFromConfigmgrIni( bool isSchema, OUString const & url,
138 Reference<XCommandEnvironment> const & xCmdEnv );
139
140 void addDataToDb(OUString const & url, ConfigurationBackendDb::Data const & data);
141 ::boost::optional<ConfigurationBackendDb::Data> readDataFromDb(OUString const & url);
142 void revokeEntryFromDb(OUString const & url);
143 ::std::list<OUString> getAllIniEntries();
144 bool hasActiveEntry(OUString const & url);
145 bool activateEntry(OUString const & url);
146
147 public:
148 BackendImpl( Sequence<Any> const & args,
149 Reference<XComponentContext> const & xComponentContext );
150
151 // XPackageRegistry
152 virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL
153 getSupportedPackageTypes() throw (RuntimeException);
154 virtual void SAL_CALL packageRemoved(OUString const & url, OUString const & mediaType)
155 throw (deployment::DeploymentException,
156 uno::RuntimeException);
157
158 using PackageRegistryBackend::disposing;
159 };
160
161 //______________________________________________________________________________
disposing()162 void BackendImpl::disposing()
163 {
164 try {
165 configmgrini_flush( Reference<XCommandEnvironment>() );
166
167 PackageRegistryBackend::disposing();
168 }
169 catch (RuntimeException &) {
170 throw;
171 }
172 catch (Exception &) {
173 Any exc( ::cppu::getCaughtException() );
174 throw lang::WrappedTargetRuntimeException(
175 OUSTR("caught unexpected exception while disposing..."),
176 static_cast<OWeakObject *>(this), exc );
177 }
178 }
179
180 //______________________________________________________________________________
BackendImpl(Sequence<Any> const & args,Reference<XComponentContext> const & xComponentContext)181 BackendImpl::BackendImpl(
182 Sequence<Any> const & args,
183 Reference<XComponentContext> const & xComponentContext )
184 : PackageRegistryBackend( args, xComponentContext ),
185 m_configmgrini_inited( false ),
186 m_configmgrini_modified( false ),
187 m_xConfDataTypeInfo( new Package::TypeInfo(
188 OUSTR("application/"
189 "vnd.sun.star.configuration-data"),
190 OUSTR("*.xcu"),
191 getResourceString(RID_STR_CONF_DATA),
192 RID_IMG_CONF_XML, RID_IMG_CONF_XML_HC ) ),
193 m_xConfSchemaTypeInfo( new Package::TypeInfo(
194 OUSTR("application/"
195 "vnd.sun.star.configuration-schema"),
196 OUSTR("*.xcs"),
197 getResourceString(RID_STR_CONF_SCHEMA),
198 RID_IMG_CONF_XML, RID_IMG_CONF_XML_HC ) ),
199 m_typeInfos( 2 )
200 {
201 m_typeInfos[ 0 ] = m_xConfDataTypeInfo;
202 m_typeInfos[ 1 ] = m_xConfSchemaTypeInfo;
203
204 const Reference<XCommandEnvironment> xCmdEnv;
205
206 if (transientMode())
207 {
208 //TODO
209 }
210 else
211 {
212 OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml"));
213 m_backendDb.reset(
214 new ConfigurationBackendDb(getComponentContext(), dbFile));
215 //clean up data folders which are no longer used.
216 //This must not be done in the same process where the help files
217 //are still registers. Only after revoking and restarting OOo the folders
218 //can be removed. This works now, because the extension manager is a singleton
219 //and the backends are only create once per process.
220 ::std::list<OUString> folders = m_backendDb->getAllDataUrls();
221 deleteUnusedFolders(OUString(), folders);
222
223
224 configmgrini_verify_init( xCmdEnv );
225 m_registeredPackages.reset(
226 new PersistentMap(
227 makeURL( getCachePath(), OUSTR("registered_packages.pmap") ),
228 false ) );
229 }
230 }
231
addDataToDb(OUString const & url,ConfigurationBackendDb::Data const & data)232 void BackendImpl::addDataToDb(
233 OUString const & url, ConfigurationBackendDb::Data const & data)
234 {
235 if (m_backendDb.get())
236 m_backendDb->addEntry(url, data);
237 }
238
readDataFromDb(OUString const & url)239 ::boost::optional<ConfigurationBackendDb::Data> BackendImpl::readDataFromDb(
240 OUString const & url)
241 {
242 ::boost::optional<ConfigurationBackendDb::Data> data;
243 if (m_backendDb.get())
244 data = m_backendDb->getEntry(url);
245 return data;
246 }
247
revokeEntryFromDb(OUString const & url)248 void BackendImpl::revokeEntryFromDb(OUString const & url)
249 {
250 if (m_backendDb.get())
251 m_backendDb->revokeEntry(url);
252 }
253
getAllIniEntries()254 ::std::list<OUString> BackendImpl::getAllIniEntries()
255 {
256 if (m_backendDb.get())
257 return m_backendDb->getAllIniEntries();
258 else
259 return ::std::list<OUString>();
260 }
261
hasActiveEntry(OUString const & url)262 bool BackendImpl::hasActiveEntry(OUString const & url)
263 {
264 if (m_backendDb.get())
265 return m_backendDb->hasActiveEntry(url);
266 return false;
267 }
268
activateEntry(OUString const & url)269 bool BackendImpl::activateEntry(OUString const & url)
270 {
271 if (m_backendDb.get())
272 return m_backendDb->activateEntry(url);
273 return false;
274 }
275
276
277
278 // XPackageRegistry
279 //______________________________________________________________________________
280 Sequence< Reference<deployment::XPackageTypeInfo> >
getSupportedPackageTypes()281 BackendImpl::getSupportedPackageTypes() throw (RuntimeException)
282 {
283 return m_typeInfos;
284 }
packageRemoved(OUString const & url,OUString const &)285 void BackendImpl::packageRemoved(OUString const & url, OUString const & /*mediaType*/)
286 throw (deployment::DeploymentException,
287 uno::RuntimeException)
288 {
289 if (m_backendDb.get())
290 m_backendDb->removeEntry(url);
291 }
292
293 // PackageRegistryBackend
294 //______________________________________________________________________________
bindPackage_(OUString const & url,OUString const & mediaType_,sal_Bool bRemoved,OUString const & identifier,Reference<XCommandEnvironment> const & xCmdEnv)295 Reference<deployment::XPackage> BackendImpl::bindPackage_(
296 OUString const & url, OUString const & mediaType_,
297 sal_Bool bRemoved, OUString const & identifier,
298 Reference<XCommandEnvironment> const & xCmdEnv )
299 {
300 OUString mediaType( mediaType_ );
301 if (mediaType.getLength() == 0)
302 {
303 // detect media-type:
304 ::ucbhelper::Content ucbContent;
305 if (create_ucb_content( &ucbContent, url, xCmdEnv ))
306 {
307 const OUString title( ucbContent.getPropertyValue(
308 StrTitle::get() ).get<OUString>() );
309 if (title.endsWithIgnoreAsciiCaseAsciiL(
310 RTL_CONSTASCII_STRINGPARAM(".xcu") )) {
311 mediaType = OUSTR("application/"
312 "vnd.sun.star.configuration-data");
313 }
314 if (title.endsWithIgnoreAsciiCaseAsciiL(
315 RTL_CONSTASCII_STRINGPARAM(".xcs") )) {
316 mediaType = OUSTR("application/"
317 "vnd.sun.star.configuration-schema");
318 }
319 }
320 if (mediaType.getLength() == 0)
321 throw lang::IllegalArgumentException(
322 StrCannotDetectMediaType::get() + url,
323 static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
324 }
325
326 String type, subType;
327 INetContentTypeParameterList params;
328 if (INetContentTypes::parse( mediaType, type, subType, ¶ms ))
329 {
330 if (type.EqualsIgnoreCaseAscii("application"))
331 {
332 OUString name;
333 if (!bRemoved)
334 {
335 ::ucbhelper::Content ucbContent( url, xCmdEnv );
336 name = ucbContent.getPropertyValue(
337 StrTitle::get() ).get<OUString>();
338 }
339
340 ::ucbhelper::Content ucbContent( url, xCmdEnv );
341 if (subType.EqualsIgnoreCaseAscii(
342 "vnd.sun.star.configuration-data"))
343 {
344 return new PackageImpl(
345 this, url, name, m_xConfDataTypeInfo, false /* data file */,
346 bRemoved, identifier);
347 }
348 else if (subType.EqualsIgnoreCaseAscii(
349 "vnd.sun.star.configuration-schema")) {
350 return new PackageImpl(
351 this, url, name, m_xConfSchemaTypeInfo, true /* schema file */,
352 bRemoved, identifier);
353 }
354 }
355 }
356 throw lang::IllegalArgumentException(
357 StrUnsupportedMediaType::get() + mediaType,
358 static_cast<OWeakObject *>(this),
359 static_cast<sal_Int16>(-1) );
360 }
361
362 //##############################################################################
363
364 //______________________________________________________________________________
configmgrini_verify_init(Reference<XCommandEnvironment> const & xCmdEnv)365 void BackendImpl::configmgrini_verify_init(
366 Reference<XCommandEnvironment> const & xCmdEnv )
367 {
368 if (transientMode())
369 return;
370 const ::osl::MutexGuard guard( getMutex() );
371 if (! m_configmgrini_inited)
372 {
373 // common rc:
374 ::ucbhelper::Content ucb_content;
375 if (create_ucb_content(
376 &ucb_content,
377 makeURL( getCachePath(), OUSTR("configmgr.ini") ),
378 xCmdEnv, false /* no throw */ ))
379 {
380 OUString line;
381 if (readLine( &line, OUSTR("SCHEMA="), ucb_content,
382 RTL_TEXTENCODING_UTF8 ))
383 {
384 sal_Int32 index = sizeof ("SCHEMA=") - 1;
385 do {
386 OUString token( line.getToken( 0, ' ', index ).trim() );
387 if (token.getLength() > 0) {
388 //The file may not exist anymore if a shared or bundled
389 //extension was removed, but it can still be in the configmgrini.
390 //After running XExtensionManager::synchronize, the configmgrini is
391 //cleaned up
392 m_xcs_files.push_back( token );
393 }
394 }
395 while (index >= 0);
396 }
397 if (readLine( &line, OUSTR("DATA="), ucb_content,
398 RTL_TEXTENCODING_UTF8 )) {
399 sal_Int32 index = sizeof ("DATA=") - 1;
400 do {
401 OUString token( line.getToken( 0, ' ', index ).trim() );
402 if (token.getLength() > 0)
403 {
404 if (token[ 0 ] == '?')
405 token = token.copy( 1 );
406 //The file may not exist anymore if a shared or bundled
407 //extension was removed, but it can still be in the configmgrini.
408 //After running XExtensionManager::synchronize, the configmgrini is
409 //cleaned up
410 m_xcu_files.push_back( token );
411 }
412 }
413 while (index >= 0);
414 }
415 }
416 m_configmgrini_modified = false;
417 m_configmgrini_inited = true;
418 }
419 }
420
421 //______________________________________________________________________________
configmgrini_flush(Reference<XCommandEnvironment> const & xCmdEnv)422 void BackendImpl::configmgrini_flush(
423 Reference<XCommandEnvironment> const & xCmdEnv )
424 {
425 if (transientMode())
426 return;
427 if (!m_configmgrini_inited || !m_configmgrini_modified)
428 return;
429
430 ::rtl::OStringBuffer buf;
431 if (! m_xcs_files.empty())
432 {
433 t_stringlist::const_iterator iPos( m_xcs_files.begin() );
434 t_stringlist::const_iterator const iEnd( m_xcs_files.end() );
435 buf.append( RTL_CONSTASCII_STRINGPARAM("SCHEMA=") );
436 while (iPos != iEnd) {
437 // encoded ASCII file-urls:
438 const ::rtl::OString item(
439 ::rtl::OUStringToOString( *iPos, RTL_TEXTENCODING_ASCII_US ) );
440 buf.append( item );
441 ++iPos;
442 if (iPos != iEnd)
443 buf.append( ' ' );
444 }
445 buf.append(LF);
446 }
447 if (! m_xcu_files.empty())
448 {
449 t_stringlist::const_iterator iPos( m_xcu_files.begin() );
450 t_stringlist::const_iterator const iEnd( m_xcu_files.end() );
451 buf.append( RTL_CONSTASCII_STRINGPARAM("DATA=") );
452 while (iPos != iEnd) {
453 // encoded ASCII file-urls:
454 const ::rtl::OString item(
455 ::rtl::OUStringToOString( *iPos, RTL_TEXTENCODING_ASCII_US ) );
456 buf.append( item );
457 ++iPos;
458 if (iPos != iEnd)
459 buf.append( ' ' );
460 }
461 buf.append(LF);
462 }
463
464 // write configmgr.ini:
465 const Reference<io::XInputStream> xData(
466 ::xmlscript::createInputStream(
467 ::rtl::ByteSequence(
468 reinterpret_cast<sal_Int8 const *>(buf.getStr()),
469 buf.getLength() ) ) );
470 ::ucbhelper::Content ucb_content(
471 makeURL( getCachePath(), OUSTR("configmgr.ini") ), xCmdEnv );
472 ucb_content.writeStream( xData, true /* replace existing */ );
473
474 m_configmgrini_modified = false;
475 }
476
477 //______________________________________________________________________________
addToConfigmgrIni(bool isSchema,bool isURL,OUString const & url_,Reference<XCommandEnvironment> const & xCmdEnv)478 bool BackendImpl::addToConfigmgrIni( bool isSchema, bool isURL, OUString const & url_,
479 Reference<XCommandEnvironment> const & xCmdEnv )
480 {
481 const OUString rcterm( isURL ? dp_misc::makeRcTerm(url_) : url_ );
482 const ::osl::MutexGuard guard( getMutex() );
483 configmgrini_verify_init( xCmdEnv );
484 t_stringlist & rSet = getFiles(isSchema);
485 if (::std::find( rSet.begin(), rSet.end(), rcterm ) == rSet.end()) {
486 rSet.push_front( rcterm ); // prepend to list, thus overriding
487 // write immediately:
488 m_configmgrini_modified = true;
489 configmgrini_flush( xCmdEnv );
490 return true;
491 }
492 else
493 return false;
494 }
495
496 //______________________________________________________________________________
removeFromConfigmgrIni(bool isSchema,OUString const & url_,Reference<XCommandEnvironment> const & xCmdEnv)497 bool BackendImpl::removeFromConfigmgrIni(
498 bool isSchema, OUString const & url_,
499 Reference<XCommandEnvironment> const & xCmdEnv )
500 {
501 const OUString rcterm( dp_misc::makeRcTerm(url_) );
502 const ::osl::MutexGuard guard( getMutex() );
503 configmgrini_verify_init( xCmdEnv );
504 t_stringlist & rSet = getFiles(isSchema);
505 t_stringlist::iterator i(std::find(rSet.begin(), rSet.end(), rcterm));
506 if (i == rSet.end() && !isSchema)
507 {
508 //in case the xcu contained %origin% then the configmr.ini contains the
509 //url to the file in the user installation (e.g. $BUNDLED_EXTENSIONS_USER)
510 //However, m_url (getURL()) contains the URL for the file in the actual
511 //extension installatation.
512 ::boost::optional<ConfigurationBackendDb::Data> data = readDataFromDb(url_);
513 if (data)
514 i = std::find(rSet.begin(), rSet.end(), data->iniEntry);
515 }
516 if (i == rSet.end()) {
517 return false;
518 }
519 rSet.erase(i);
520 // write immediately:
521 m_configmgrini_modified = true;
522 configmgrini_flush( xCmdEnv );
523 return true;
524 }
525
526 //##############################################################################
527
528 // Package
529 //______________________________________________________________________________
530
getMyBackend() const531 BackendImpl * BackendImpl::PackageImpl::getMyBackend() const
532 {
533 BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get());
534 if (NULL == pBackend)
535 {
536 //May throw a DisposedException
537 check();
538 //We should never get here...
539 throw RuntimeException(
540 OUSTR("Failed to get the BackendImpl"),
541 static_cast<OWeakObject*>(const_cast<PackageImpl *>(this)));
542 }
543 return pBackend;
544 }
545
546 beans::Optional< beans::Ambiguous<sal_Bool> >
isRegistered_(::osl::ResettableMutexGuard &,::rtl::Reference<AbortChannel> const &,Reference<XCommandEnvironment> const &)547 BackendImpl::PackageImpl::isRegistered_(
548 ::osl::ResettableMutexGuard &,
549 ::rtl::Reference<AbortChannel> const &,
550 Reference<XCommandEnvironment> const & )
551 {
552 BackendImpl * that = getMyBackend();
553 const rtl::OUString url(getURL());
554
555 bool bReg = false;
556 if (that->hasActiveEntry(getURL()))
557 bReg = true;
558 if (!bReg)
559 //fallback for user extension registered in berkeley DB
560 bReg = that->m_registeredPackages->has(
561 rtl::OUStringToOString( url, RTL_TEXTENCODING_UTF8 ));
562
563 return beans::Optional< beans::Ambiguous<sal_Bool> >(
564 true, beans::Ambiguous<sal_Bool>( bReg, false ) );
565 }
566
567 //------------------------------------------------------------------------------
encodeForXml(OUString const & text)568 OUString encodeForXml( OUString const & text )
569 {
570 // encode conforming xml:
571 sal_Int32 len = text.getLength();
572 ::rtl::OUStringBuffer buf;
573 for ( sal_Int32 pos = 0; pos < len; ++pos )
574 {
575 sal_Unicode c = text[ pos ];
576 switch (c) {
577 case '<':
578 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("<") );
579 break;
580 case '>':
581 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(">") );
582 break;
583 case '&':
584 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("&") );
585 break;
586 case '\'':
587 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("'") );
588 break;
589 case '\"':
590 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(""") );
591 break;
592 default:
593 buf.append( c );
594 break;
595 }
596 }
597 return buf.makeStringAndClear();
598 }
599
600 //______________________________________________________________________________
replaceOrigin(OUString const & url,OUString const & destFolder,Reference<XCommandEnvironment> const & xCmdEnv,bool & out_replaced)601 OUString replaceOrigin(
602 OUString const & url, OUString const & destFolder, Reference< XCommandEnvironment > const & xCmdEnv, bool & out_replaced)
603 {
604 // looking for %origin%:
605 ::ucbhelper::Content ucb_content( url, xCmdEnv );
606 ::rtl::ByteSequence bytes( readFile( ucb_content ) );
607 ::rtl::ByteSequence filtered( bytes.getLength() * 2,
608 ::rtl::BYTESEQ_NODEFAULT );
609 bool use_filtered = false;
610 ::rtl::OString origin;
611 sal_Char const * pBytes = reinterpret_cast<sal_Char const *>(
612 bytes.getConstArray());
613 sal_Size nBytes = bytes.getLength();
614 sal_Int32 write_pos = 0;
615 while (nBytes > 0)
616 {
617 sal_Int32 index = rtl_str_indexOfChar_WithLength( pBytes, nBytes, '%' );
618 if (index < 0) {
619 if (! use_filtered) // opt
620 break;
621 index = nBytes;
622 }
623
624 if ((write_pos + index) > filtered.getLength())
625 filtered.realloc( (filtered.getLength() + index) * 2 );
626 rtl_copyMemory( filtered.getArray() + write_pos, pBytes, index );
627 write_pos += index;
628 pBytes += index;
629 nBytes -= index;
630 if (nBytes == 0)
631 break;
632
633 // consume %:
634 ++pBytes;
635 --nBytes;
636 sal_Char const * pAdd = "%";
637 sal_Int32 nAdd = 1;
638 if (nBytes > 1 && pBytes[ 0 ] == '%')
639 {
640 // %% => %
641 ++pBytes;
642 --nBytes;
643 use_filtered = true;
644 }
645 else if (rtl_str_shortenedCompare_WithLength(
646 pBytes, nBytes,
647 RTL_CONSTASCII_STRINGPARAM("origin%"),
648 sizeof ("origin%") - 1 ) == 0)
649 {
650 if (origin.getLength() == 0) {
651 // encode only once
652 origin = ::rtl::OUStringToOString(
653 encodeForXml( url.copy( 0, url.lastIndexOf( '/' ) ) ),
654 // xxx todo: encode always for UTF-8? => lookup doc-header?
655 RTL_TEXTENCODING_UTF8 );
656 }
657 pAdd = origin.getStr();
658 nAdd = origin.getLength();
659 pBytes += (sizeof ("origin%") - 1);
660 nBytes -= (sizeof ("origin%") - 1);
661 use_filtered = true;
662 }
663 if ((write_pos + nAdd) > filtered.getLength())
664 filtered.realloc( (filtered.getLength() + nAdd) * 2 );
665 rtl_copyMemory( filtered.getArray() + write_pos, pAdd, nAdd );
666 write_pos += nAdd;
667 }
668 if (!use_filtered)
669 return url;
670 if (write_pos < filtered.getLength())
671 filtered.realloc( write_pos );
672 rtl::OUString newUrl(url);
673 if (destFolder.getLength())
674 {
675 //get the file name of the xcu and add it to the url of the temporary folder
676 sal_Int32 i = url.lastIndexOf('/');
677 newUrl = destFolder + url.copy(i);
678 }
679
680 ucbhelper::Content(newUrl, xCmdEnv).writeStream(
681 xmlscript::createInputStream(filtered), true);
682 out_replaced = true;
683 return newUrl;
684 }
685
686 //______________________________________________________________________________
processPackage_(::osl::ResettableMutexGuard &,bool doRegisterPackage,bool startup,::rtl::Reference<AbortChannel> const &,Reference<XCommandEnvironment> const & xCmdEnv)687 void BackendImpl::PackageImpl::processPackage_(
688 ::osl::ResettableMutexGuard &,
689 bool doRegisterPackage,
690 bool startup,
691 ::rtl::Reference<AbortChannel> const &,
692 Reference<XCommandEnvironment> const & xCmdEnv )
693 {
694 BackendImpl * that = getMyBackend();
695 OUString url( getURL() );
696
697 if (doRegisterPackage)
698 {
699 if (getMyBackend()->activateEntry(getURL()))
700 {
701 ::boost::optional<ConfigurationBackendDb::Data> data = that->readDataFromDb(url);
702 OSL_ASSERT(data);
703 that->addToConfigmgrIni( m_isSchema, false, data->iniEntry, xCmdEnv );
704 }
705 else
706 {
707 ConfigurationBackendDb::Data data;
708 if (!m_isSchema)
709 {
710 const OUString sModFolder = that->createFolder(OUString(), xCmdEnv);
711 bool out_replaced = false;
712 url = replaceOrigin(url, sModFolder, xCmdEnv, out_replaced);
713 if (out_replaced)
714 data.dataUrl = sModFolder;
715 else
716 deleteTempFolder(sModFolder);
717 }
718 //No need for live-deployment for bundled extension, because OOo
719 //restarts after installation
720 if (that->m_eContext != CONTEXT_BUNDLED
721 && that->m_eContext != CONTEXT_BUNDLED_PREREG
722 && !startup)
723 {
724 if (m_isSchema)
725 {
726 com::sun::star::configuration::Update::get(
727 that->m_xComponentContext)->insertExtensionXcsFile(
728 that->m_eContext == CONTEXT_SHARED, expandUnoRcUrl(url));
729 }
730 else
731 {
732 com::sun::star::configuration::Update::get(
733 that->m_xComponentContext)->insertExtensionXcuFile(
734 that->m_eContext == CONTEXT_SHARED, expandUnoRcUrl(url));
735 }
736 }
737 that->addToConfigmgrIni( m_isSchema, true, url, xCmdEnv );
738 data.iniEntry = dp_misc::makeRcTerm(url);
739 that->addDataToDb(getURL(), data);
740 }
741 }
742 else // revoke
743 {
744 if (!that->removeFromConfigmgrIni(m_isSchema, url, xCmdEnv)) {
745 t_string2string_map entries(
746 that->m_registeredPackages->getEntries());
747 for (t_string2string_map::iterator i(entries.begin());
748 i != entries.end(); ++i)
749 {
750 //If the xcu file was installed before the configmgr was chaned
751 //to use the configmgr.ini, one needed to rebuild to whole directory
752 //structur containing the xcu, xcs files from all extensions. Now,
753 //we just add all other xcu/xcs files to the configmgr.ini instead of
754 //rebuilding the directory structure.
755 rtl::OUString url2(
756 rtl::OStringToOUString(i->first, RTL_TEXTENCODING_UTF8));
757 if (url2 != url) {
758 bool schema = i->second.equalsIgnoreAsciiCase(
759 "vnd.sun.star.configuration-schema");
760 OUString url_replaced(url2);
761 ConfigurationBackendDb::Data data;
762 if (!schema)
763 {
764 const OUString sModFolder = that->createFolder(OUString(), xCmdEnv);
765 bool out_replaced = false;
766 url_replaced = replaceOrigin(
767 url2, sModFolder, xCmdEnv, out_replaced);
768 if (out_replaced)
769 data.dataUrl = sModFolder;
770 else
771 deleteTempFolder(sModFolder);
772 }
773 that->addToConfigmgrIni(schema, true, url_replaced, xCmdEnv);
774 data.iniEntry = dp_misc::makeRcTerm(url_replaced);
775 that->addDataToDb(url2, data);
776 }
777 that->m_registeredPackages->erase(i->first);
778 }
779 try
780 {
781 ::ucbhelper::Content(
782 makeURL( that->getCachePath(), OUSTR("registry") ),
783 xCmdEnv ).executeCommand(
784 OUSTR("delete"), Any( true /* delete physically */ ) );
785 }
786 catch(Exception&)
787 {
788 OSL_ASSERT(0);
789 }
790 }
791
792 ::boost::optional<ConfigurationBackendDb::Data> data = that->readDataFromDb(url);
793 //If an xcu file was life deployed then always a data entry is written.
794 //If the xcu file was already in the configmr.ini then there is also
795 //a data entry
796 if (!m_isSchema && data)
797 {
798 com::sun::star::configuration::Update::get(
799 that->m_xComponentContext)->removeExtensionXcuFile(expandUnoRcTerm(data->iniEntry));
800 }
801 that->revokeEntryFromDb(url);
802 }
803 }
804
805 } // anon namespace
806
807 namespace sdecl = comphelper::service_decl;
808 sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI;
809 extern sdecl::ServiceDecl const serviceDecl(
810 serviceBI,
811 "com.sun.star.comp.deployment.configuration.PackageRegistryBackend",
812 BACKEND_SERVICE_NAME );
813
814 } // namespace configuration
815 } // namespace backend
816 } // namespace dp_registry
817
818