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