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, &params ))
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("&lt;") );
579             break;
580         case '>':
581             buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("&gt;") );
582             break;
583         case '&':
584             buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("&amp;") );
585             break;
586         case '\'':
587             buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("&apos;") );
588             break;
589         case '\"':
590             buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("&quot;") );
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