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_unotools.hxx"
26 
27 #include <stdio.h>
28 
29 #include "unotools/bootstrap.hxx"
30 
31 // ---------------------------------------------------------------------------------------
32 #include <rtl/ustring.hxx>
33 #include <rtl/ustrbuf.hxx>
34 #include <osl/file.hxx>
35 #include <osl/mutex.hxx>
36 #include <osl/diagnose.h>
37 // ---------------------------------------------------------------------------------------
38 #include <rtl/bootstrap.hxx>
39 #include <osl/process.h> // for osl_getExecutableFile
40 #include "tools/getprocessworkingdir.hxx"
41 
42 // ---------------------------------------------------------------------------------------
43 // #define this to a non-zero value, if remembering defaults is not supported properly
44 #define RTL_BOOTSTRAP_DEFAULTS_BROKEN 1
45 
46 // ---------------------------------------------------------------------------------------
47 #define BOOTSTRAP_DATA_NAME                 SAL_CONFIGFILE("bootstrap")
48 
49 #define BOOTSTRAP_ITEM_PRODUCT_KEY			"ProductKey"
50 #define BOOTSTRAP_ITEM_PRODUCT_SOURCE       "ProductSource"
51 #define BOOTSTRAP_ITEM_VERSIONFILE			"Location"
52 #define BOOTSTRAP_ITEM_BUILDID				"buildid"
53 
54 #define BOOTSTRAP_ITEM_BASEINSTALLATION		"BaseInstallation"
55 #define BOOTSTRAP_ITEM_USERINSTALLATION		"UserInstallation"
56 
57 #define BOOTSTRAP_ITEM_SHAREDIR		        "SharedDataDir"
58 #define BOOTSTRAP_ITEM_USERDIR		        "UserDataDir"
59 
60 #define BOOTSTRAP_DEFAULT_BASEINSTALL	    "$SYSBINDIR/.."
61 
62 #define BOOTSTRAP_DIRNAME_SHAREDIR		    "share"
63 #define BOOTSTRAP_DIRNAME_USERDIR		    "user"
64 
65 #define VERSIONFILE_SECTION         		"Versions"
66 #define VERSIONFILE_ITEM_SCSREVISION        "Revision"
67 
68 #define SETUP_DATA_NAME                 	SAL_CONFIGFILE("setup")
69 #define SETUP_ITEM_ALLUSERS         		"ALLUSERS"
70 // ---------------------------------------------------------------------------------------
71 typedef char const * AsciiString;
72 // ---------------------------------------------------------------------------------------
73 
74 namespace utl
75 {
76 // ---------------------------------------------------------------------------------------
77     using ::rtl::OUString;
78     using ::rtl::OUStringBuffer;
79     using ::rtl::OString;
80 
81 // ---------------------------------------------------------------------------------------
82 // Implementation class: Bootstrap::Impl
83 // ---------------------------------------------------------------------------------------
84 
85     class Bootstrap::Impl
86     {
87         OUString const m_aImplName;
88     public: // struct to cache the result of a path lookup
89         struct PathData
90         {
91             OUString     path;
92             PathStatus   status;
93 
PathDatautl::Bootstrap::Impl::PathData94             PathData()
95             : path()
96             , status(DATA_UNKNOWN)
97             {}
98         };
99     public: // data members
100         // base install data
101         PathData aBaseInstall_;
102 
103         // user install data
104         PathData aUserInstall_;
105 
106         // INI files
107         PathData aBootstrapINI_;
108         PathData aVersionINI_;
109 
110         // overall status
111         Status status_;
112 
113     public: // construction and initialization
114         explicit
Impl(OUString const & _aImplName)115         Impl(OUString const& _aImplName)
116         : m_aImplName(_aImplName)
117         {
118             status_ = initialize();
119         }
120 
121         Status initialize();
122 
123         // access helper
124         OUString getBootstrapValue(OUString const& _sName, OUString const& _sDefault) const;
125         sal_Bool getVersionValue(OUString const& _sName, OUString& _rValue, OUString const& _sDefault) const;
126 
getImplName() const127         OUString getImplName() const { return m_aImplName; }
128 
129     private: // implementation
130         bool initBaseInstallationData(rtl::Bootstrap& _rData);
131         bool initUserInstallationData(rtl::Bootstrap& _rData);
132     };
133 // ---------------------------------------------------------------------------------------
134     static OUString getExecutableDirectory();
135 // ---------------------------------------------------------------------------------------
136 
137     static Bootstrap::Impl* s_pData = NULL;
138 
data()139     Bootstrap::Impl const& Bootstrap::data()
140     {
141 
142         if (!s_pData)
143         {
144             using namespace osl;
145             MutexGuard aGuard( Mutex::getGlobalMutex() );
146 
147             // static Impl s_theData(getExecutableDirectory() + OUString(RTL_CONSTASCII_USTRINGPARAM("/"BOOTSTRAP_DATA_NAME)));
148             // s_pData = &s_theData;
149             rtl::OUString uri;
150             rtl::Bootstrap::get(
151                 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("OOO_BASE_DIR")), uri);
152             s_pData = new Impl(uri + OUString(RTL_CONSTASCII_USTRINGPARAM( "/program/" BOOTSTRAP_DATA_NAME)));
153         }
154         return *s_pData;
155     }
156 
reloadData()157     void Bootstrap::reloadData()
158     {
159         if (s_pData != NULL) {
160             delete s_pData;
161             s_pData = NULL;
162         }
163     }
164 
165 // ---------------------------------------------------------------------------------------
166 // helper
167 // ---------------------------------------------------------------------------------------
168 
169 typedef Bootstrap::PathStatus PathStatus;
170 
171 sal_Unicode const cURLSeparator = '/';
172 
173 // ---------------------------------------------------------------------------------------
174 static
175 inline
getURLSeparator()176 OUString getURLSeparator()
177 {
178     static OUString theSep(&cURLSeparator,1);
179     return theSep;
180 }
181 
182 // ---------------------------------------------------------------------------------------
183 // path status utility function
184 static
implCheckStatusOfURL(OUString const & _sURL,osl::DirectoryItem & aDirItem)185 PathStatus implCheckStatusOfURL(OUString const& _sURL, osl::DirectoryItem& aDirItem)
186 {
187     using namespace osl;
188 
189     PathStatus eStatus = Bootstrap::DATA_UNKNOWN;
190 
191     if (_sURL.getLength() != 0)
192     {
193         switch( DirectoryItem::get(_sURL, aDirItem) )
194         {
195         case DirectoryItem::E_None:		    // Success
196             eStatus = Bootstrap::PATH_EXISTS;
197             break;
198 
199         case DirectoryItem::E_NOENT:		// No such file or directory<br>
200             eStatus = Bootstrap::PATH_VALID;
201             break;
202 
203         case DirectoryItem::E_INVAL:		// the format of the parameters was not valid<br>
204         case DirectoryItem::E_NAMETOOLONG:	// File name too long<br>
205         case DirectoryItem::E_NOTDIR:		// A component of the path prefix of path is not a directory<p>
206             eStatus = Bootstrap::DATA_INVALID;
207             break;
208 
209         // how to handle these ?
210         case DirectoryItem::E_LOOP:			// Too many symbolic links encountered<br>
211         case DirectoryItem::E_ACCES:		// permission denied<br>
212         // any other error - what to do ?
213         default:
214             eStatus = Bootstrap::DATA_UNKNOWN;
215             break;
216         }
217     }
218     else
219         eStatus = Bootstrap::DATA_MISSING;
220 
221     return eStatus;
222 }
223 // ---------------------------------------------------------------------------------------
224 
225 static
implNormalizeURL(OUString & _sURL,osl::DirectoryItem & aDirItem)226 bool implNormalizeURL(OUString & _sURL, osl::DirectoryItem& aDirItem)
227 {
228     using namespace osl;
229 
230     OSL_PRECOND(aDirItem.is(), "Opened DirItem required");
231 
232     static const sal_uInt32 cFileStatusMask = FileStatusMask_FileURL;
233 
234     FileStatus aFileStatus(cFileStatusMask);
235 
236     if (aDirItem.getFileStatus(aFileStatus) != DirectoryItem::E_None)
237         return false;
238 
239     OUString aNormalizedURL = aFileStatus.getFileURL();
240 
241     if (aNormalizedURL.getLength() == 0)
242         return false;
243 
244     // #109863# sal/osl returns final slash for file URLs contradicting
245     // the URL/URI RFCs.
246     if ( aNormalizedURL.getStr()[aNormalizedURL.getLength()-1] != cURLSeparator )
247         _sURL = aNormalizedURL;
248     else
249         _sURL = aNormalizedURL.copy( 0, aNormalizedURL.getLength()-1 );
250 
251     return true;
252 }
253 // ---------------------------------------------------------------------------------------
254 static
implEnsureAbsolute(OUString & _rsURL)255 bool implEnsureAbsolute(OUString & _rsURL) // also strips embedded dots !!
256 {
257     using osl::File;
258 
259     OUString sBasePath;
260     OSL_VERIFY(tools::getProcessWorkingDir(&sBasePath));
261 
262     OUString sAbsolute;
263     if ( File::E_None == File::getAbsoluteFileURL(sBasePath, _rsURL, sAbsolute))
264     {
265         _rsURL = sAbsolute;
266         return true;
267     }
268     else
269     {
270         OSL_ENSURE(false, "Could not get absolute file URL for URL");
271         return false;
272     }
273 }
274 /*  old code to strip embedded dots
275     static OUString const sDots(RTL_CONSTASCII_USTRINGPARAM("/.."));
276 
277     sal_Int32 nDotsIndex = _rsURL.indexOf(sDots);
278     while (nDotsIndex >= 0)
279     {
280         OSL_ASSERT(_rsURL.indexOf(sDots) == nDotsIndex);
281 
282         sal_Int32 nStripIndex = _rsURL.lastIndexOf(cURLSeparator,nDotsIndex);
283         if (nStripIndex < 0 || nStripIndex+1 == nDotsIndex)
284         {
285             OSL_TRACE("Invalid use of dots in bootstrap URL");
286             return false;
287         }
288         _rsURL = _rsURL.copy(0,nStripIndex) + _rsURL.copy(nDotsIndex + sDots.getLength());
289 
290         nDotsIndex = _rsURL.indexOf(sDots,nStripIndex);
291     }
292     return true;
293 }
294 
295 */
296 // ---------------------------------------------------------------------------------------
297 
298 static
implMakeAbsoluteURL(OUString & _rsPathOrURL)299 bool implMakeAbsoluteURL(OUString & _rsPathOrURL)
300 {
301     using namespace osl;
302 
303     bool bURL;
304 
305     OUString sOther;
306 	// check if it already was normalized
307     if ( File::E_None == File::getSystemPathFromFileURL(_rsPathOrURL, sOther) )
308     {
309         bURL = true;
310     }
311 
312     else if ( File::E_None == File::getFileURLFromSystemPath(_rsPathOrURL, sOther) )
313     {
314         _rsPathOrURL = sOther;
315         bURL = true;
316     }
317     else
318         bURL = false;
319 
320     return bURL && implEnsureAbsolute(_rsPathOrURL);
321 }
322 // ---------------------------------------------------------------------------------------
323 #if OSL_DEBUG_LEVEL > 0
324 static
dbgCheckStatusOfURL(OUString const & _sURL)325 PathStatus dbgCheckStatusOfURL(OUString const& _sURL)
326 {
327     using namespace osl;
328 
329 	DirectoryItem aDirItem;
330 
331     return implCheckStatusOfURL(_sURL,aDirItem);
332 }
333 // ---------------------------------------------------------------------------------------
334 #endif
335 
336 static
checkStatusAndNormalizeURL(OUString & _sURL)337 PathStatus checkStatusAndNormalizeURL(OUString & _sURL)
338 {
339     using namespace osl;
340 
341     PathStatus eStatus = Bootstrap::DATA_UNKNOWN;
342 
343     if (_sURL.getLength() == 0)
344         eStatus = Bootstrap::DATA_MISSING;
345 
346     else if ( !implMakeAbsoluteURL(_sURL) )
347         eStatus = Bootstrap::DATA_INVALID;
348 
349     else
350     {
351 	    DirectoryItem aDirItem;
352 
353         eStatus = implCheckStatusOfURL(_sURL,aDirItem);
354 
355         if (eStatus == Bootstrap::PATH_EXISTS)
356         {
357             if (!implNormalizeURL(_sURL,aDirItem))
358                 OSL_ENSURE(false,"Unexpected failure getting actual URL for existing object");
359         }
360     }
361     return eStatus;
362 }
363 
364 
365 // ----------------------------------------------------------------------------------
366 // helpers to build and check a nested URL
367 static
getDerivedPath(OUString & _rURL,OUString const & _aBaseURL,PathStatus _aBaseStatus,OUString const & _sRelativeURL,rtl::Bootstrap & _rData,OUString const & _sBootstrapParameter)368 PathStatus getDerivedPath(
369               OUString& _rURL,
370               OUString const& _aBaseURL, PathStatus _aBaseStatus,
371               OUString const& _sRelativeURL,
372               rtl::Bootstrap& _rData, OUString const& _sBootstrapParameter
373           )
374 {
375     OUString sDerivedURL;
376 
377     OSL_PRECOND(!_rData.getFrom(_sBootstrapParameter,sDerivedURL),"Setting for derived path is already defined");
378     OSL_PRECOND(_sRelativeURL.getLength() != 0 && _sRelativeURL[0] != cURLSeparator,"Invalid Relative URL");
379 
380     PathStatus aStatus = _aBaseStatus;
381 
382     // do we have a base path ?
383     if (_aBaseURL.getLength())
384     {
385         OSL_PRECOND(_aBaseURL[_aBaseURL.getLength()-1] != cURLSeparator,"Unexpected: base URL ends in slash");
386 
387         sDerivedURL = _aBaseURL + getURLSeparator() + _sRelativeURL;
388 
389         // a derived (nested) URL can only exist or have a lesser status, if the parent exists
390         if (aStatus == Bootstrap::PATH_EXISTS)
391             aStatus = checkStatusAndNormalizeURL(sDerivedURL);
392 
393         else // the relative appendix must be valid
394             OSL_ASSERT(aStatus != Bootstrap::PATH_VALID || dbgCheckStatusOfURL(sDerivedURL) == Bootstrap::PATH_VALID);
395 
396         _rData.getFrom(_sBootstrapParameter, _rURL, sDerivedURL);
397 
398         OSL_ENSURE(sDerivedURL == _rURL,"Could not set derived URL via Bootstrap default parameter");
399         OSL_POSTCOND(RTL_BOOTSTRAP_DEFAULTS_BROKEN ||
400                     _rData.getFrom(_sBootstrapParameter,sDerivedURL) && sDerivedURL==_rURL,"Use of default did not affect bootstrap value");
401     }
402     else
403     {
404         // clear the result
405         _rURL = _aBaseURL;
406 
407         // if we have no data it can't be a valid path
408         OSL_ASSERT( aStatus > Bootstrap::PATH_VALID );
409     }
410 
411 
412     return aStatus;
413 }
414 
415 // ----------------------------------------------------------------------------------
416 static
417 inline
getDerivedPath(OUString & _rURL,Bootstrap::Impl::PathData const & _aBaseData,OUString const & _sRelativeURL,rtl::Bootstrap & _rData,OUString const & _sBootstrapParameter)418 PathStatus getDerivedPath(
419               OUString& _rURL,
420               Bootstrap::Impl::PathData const& _aBaseData,
421               OUString const& _sRelativeURL,
422               rtl::Bootstrap& _rData, OUString const& _sBootstrapParameter
423           )
424 {
425     return getDerivedPath(_rURL,_aBaseData.path,_aBaseData.status,_sRelativeURL,_rData,_sBootstrapParameter);
426 }
427 
428 // ---------------------------------------------------------------------------------------
429 
430 static
getExecutableBaseName()431 OUString getExecutableBaseName()
432 {
433 	OUString sExecutable;
434 
435     if (osl_Process_E_None == osl_getExecutableFile(&sExecutable.pData))
436     {
437         // split the executable name
438 	    sal_Int32 nSepIndex = sExecutable.lastIndexOf(cURLSeparator);
439 
440         sExecutable = sExecutable.copy(nSepIndex + 1);
441 
442         // ... and get the basename (strip the extension)
443         sal_Unicode const cExtensionSep = '.';
444 
445         sal_Int32 const nExtIndex =     sExecutable.lastIndexOf(cExtensionSep);
446         sal_Int32 const nExtLength =    sExecutable.getLength() - nExtIndex - 1;
447         if (0 < nExtIndex && nExtLength < 4)
448            sExecutable  = sExecutable.copy(0,nExtIndex);
449     }
450     else
451         OSL_TRACE("Cannot get executable name: osl_getExecutableFile failed\n");
452 
453     return sExecutable;
454 }
455 
456 // ---------------------------------------------------------------------------------------
457 static
getExecutableDirectory()458 OUString getExecutableDirectory()
459 {
460     OUString sFileName;
461     OSL_VERIFY(osl_Process_E_None == osl_getExecutableFile(&sFileName.pData));
462 
463     sal_Int32 nDirEnd = sFileName.lastIndexOf(cURLSeparator);
464 
465     OSL_ENSURE(nDirEnd >= 0, "Cannot locate executable directory");
466 
467     return sFileName.copy(0,nDirEnd);
468 }
469 
470 // ----------------------------------------------------------------------------------
471 
472 static
473 inline
updateStatus(Bootstrap::Impl::PathData & _rResult)474 Bootstrap::PathStatus updateStatus(Bootstrap::Impl::PathData & _rResult)
475 {
476     return _rResult.status = checkStatusAndNormalizeURL(_rResult.path);
477 }
478 // ---------------------------------------------------------------------------------------
479 
480 static
implGetBootstrapFile(rtl::Bootstrap & _rData,Bootstrap::Impl::PathData & _rBootstrapFile)481 Bootstrap::PathStatus implGetBootstrapFile(rtl::Bootstrap& _rData, Bootstrap::Impl::PathData & _rBootstrapFile)
482 {
483     _rData.getIniName(_rBootstrapFile.path);
484 
485     return updateStatus(_rBootstrapFile);
486 }
487 // ---------------------------------------------------------------------------------------
488 
489 static
implGetVersionFile(rtl::Bootstrap & _rData,Bootstrap::Impl::PathData & _rVersionFile)490 Bootstrap::PathStatus implGetVersionFile(rtl::Bootstrap& _rData, Bootstrap::Impl::PathData & _rVersionFile)
491 {
492     OUString const csVersionFileItem(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_VERSIONFILE));
493 
494     _rData.getFrom(csVersionFileItem,_rVersionFile.path);
495 
496     return updateStatus(_rVersionFile);
497 }
498 // ---------------------------------------------------------------------------------------
499 // Error reporting
500 
501 static char const IS_MISSING[] = "is missing";
502 static char const IS_INVALID[] = "is corrupt";
503 static char const PERIOD[] = ". ";
504 
505 // ---------------------------------------------------------------------------------------
addFileError(OUStringBuffer & _rBuf,OUString const & _aPath,AsciiString _sWhat)506 static void addFileError(OUStringBuffer& _rBuf, OUString const& _aPath, AsciiString _sWhat)
507 {
508     OUString sSimpleFileName = _aPath.copy(1 +_aPath.lastIndexOf(cURLSeparator));
509 
510     _rBuf.appendAscii("The configuration file");
511     _rBuf.appendAscii(" '").append(sSimpleFileName).appendAscii("' ");
512     _rBuf.appendAscii(_sWhat).appendAscii(PERIOD);
513 }
514 // ---------------------------------------------------------------------------------------
515 
addMissingDirectoryError(OUStringBuffer & _rBuf,OUString const & _aPath)516 static void addMissingDirectoryError(OUStringBuffer& _rBuf, OUString const& _aPath)
517 {
518     _rBuf.appendAscii("The configuration directory");
519     _rBuf.appendAscii(" '").append(_aPath).appendAscii("' ");
520     _rBuf.appendAscii(IS_MISSING).appendAscii(PERIOD);
521 }
522 // ---------------------------------------------------------------------------------------
523 
addUnexpectedError(OUStringBuffer & _rBuf,AsciiString _sExtraInfo=NULL)524 static void addUnexpectedError(OUStringBuffer& _rBuf, AsciiString _sExtraInfo = NULL)
525 {
526     if (NULL == _sExtraInfo)
527         _sExtraInfo = "An internal failure occurred";
528 
529     _rBuf.appendAscii(_sExtraInfo).appendAscii(PERIOD);
530 }
531 // ---------------------------------------------------------------------------------------
532 
describeError(OUStringBuffer & _rBuf,Bootstrap::Impl const & _rData)533 static Bootstrap::FailureCode describeError(OUStringBuffer& _rBuf, Bootstrap::Impl const& _rData)
534 {
535     Bootstrap::FailureCode eErrCode = Bootstrap::INVALID_BOOTSTRAP_DATA;
536 
537     _rBuf.appendAscii("The program cannot be started. ");
538 
539     switch (_rData.aUserInstall_.status)
540     {
541     case Bootstrap::PATH_EXISTS:
542         switch (_rData.aBaseInstall_.status)
543         {
544         case Bootstrap::PATH_VALID:
545             addMissingDirectoryError(_rBuf, _rData.aBaseInstall_.path);
546             eErrCode = Bootstrap::MISSING_INSTALL_DIRECTORY;
547             break;
548 
549         case Bootstrap::DATA_INVALID:
550             addUnexpectedError(_rBuf,"The installation path is invalid");
551             break;
552 
553         case Bootstrap::DATA_MISSING:
554             addUnexpectedError(_rBuf,"The installation path is not available");
555             break;
556 
557         case Bootstrap::PATH_EXISTS: // seems to be all fine (?)
558             addUnexpectedError(_rBuf,"");
559             break;
560 
561         default: OSL_ASSERT(false);
562             addUnexpectedError(_rBuf);
563             break;
564         }
565         break;
566 
567     case Bootstrap::PATH_VALID:
568         addMissingDirectoryError(_rBuf, _rData.aUserInstall_.path);
569         eErrCode = Bootstrap::MISSING_USER_DIRECTORY;
570         break;
571 
572         // else fall through
573     case Bootstrap::DATA_INVALID:
574         if (_rData.aVersionINI_.status == Bootstrap::PATH_EXISTS)
575         {
576             addFileError(_rBuf, _rData.aVersionINI_.path, IS_INVALID);
577             eErrCode = Bootstrap::INVALID_VERSION_FILE_ENTRY;
578             break;
579         }
580         // else fall through
581 
582     case Bootstrap::DATA_MISSING:
583         switch (_rData.aVersionINI_.status)
584         {
585         case Bootstrap::PATH_EXISTS:
586             addFileError(_rBuf, _rData.aVersionINI_.path, "does not support the current version");
587             eErrCode = Bootstrap::MISSING_VERSION_FILE_ENTRY;
588             break;
589 
590         case Bootstrap::PATH_VALID:
591             addFileError(_rBuf, _rData.aVersionINI_.path, IS_MISSING);
592             eErrCode = Bootstrap::MISSING_VERSION_FILE;
593             break;
594 
595         default:
596             switch (_rData.aBootstrapINI_.status)
597             {
598             case Bootstrap::PATH_EXISTS:
599                 addFileError(_rBuf, _rData.aBootstrapINI_.path, IS_INVALID);
600 
601                 if (_rData.aVersionINI_.status == Bootstrap::DATA_MISSING)
602                     eErrCode = Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY;
603                 else
604                     eErrCode = Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY;
605                 break;
606 
607             case Bootstrap::DATA_INVALID: OSL_ASSERT(false);
608             case Bootstrap::PATH_VALID:
609                 addFileError(_rBuf, _rData.aBootstrapINI_.path, IS_MISSING);
610                 eErrCode = Bootstrap::MISSING_BOOTSTRAP_FILE;
611                 break;
612 
613             default:
614                 addUnexpectedError(_rBuf);
615                 break;
616             }
617             break;
618         }
619         break;
620 
621     default: OSL_ASSERT(false);
622         addUnexpectedError(_rBuf);
623         break;
624     }
625 
626     return eErrCode;
627 }
628 // ---------------------------------------------------------------------------------------
629 // ---------------------------------------------------------------------------------------
630 // class Bootstrap
631 // ---------------------------------------------------------------------------------------
632 
getProductKey()633 OUString Bootstrap::getProductKey()
634 {
635     OUString const csProductKeyItem(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_PRODUCT_KEY));
636 
637     OUString const sDefaultProductKey = getExecutableBaseName();
638 
639     return data().getBootstrapValue( csProductKeyItem, sDefaultProductKey );
640 }
641 // ---------------------------------------------------------------------------------------
642 
getProductKey(OUString const & _sDefault)643 OUString Bootstrap::getProductKey(OUString const& _sDefault)
644 {
645     OUString const csProductKeyItem(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_PRODUCT_KEY));
646 
647     return data().getBootstrapValue( csProductKeyItem, _sDefault );
648 }
649 // ---------------------------------------------------------------------------------------
650 
getProductSource(OUString const & _sDefault)651 OUString Bootstrap::getProductSource(OUString const& _sDefault)
652 {
653     OUString const csProductSourceItem(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_PRODUCT_SOURCE));
654 
655     OUString sProductSource;
656     // read ProductSource from version.ini (versionrc)
657     data().getVersionValue( csProductSourceItem, sProductSource, _sDefault );
658     return sProductSource;
659 }
660 // ---------------------------------------------------------------------------------------
661 
getBuildIdData(OUString const & _sDefault)662 OUString Bootstrap::getBuildIdData(OUString const& _sDefault)
663 {
664     OUString const csBuildIdItem(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_BUILDID));
665 
666     OUString sBuildId;
667     // read buildid from version.ini (versionrc), if it doesn't exist or buildid is empty
668     if ( data().getVersionValue( csBuildIdItem, sBuildId, _sDefault ) != sal_True ||
669          sBuildId.getLength() == 0 )
670          // read buildid from bootstrap.ini (bootstraprc)
671         sBuildId = data().getBootstrapValue( csBuildIdItem, _sDefault );
672     return sBuildId;
673 }
674 // ---------------------------------------------------------------------------------------
675 
getRevisionInfo()676 OUString Bootstrap::getRevisionInfo()
677 {
678     OUString const _sDefault;
679     OUString const csRevisionItem(RTL_CONSTASCII_USTRINGPARAM(VERSIONFILE_ITEM_SCSREVISION));
680 
681     OUString sRevisionNumber;
682     // read buildid from version.ini (versionrc), if it doesn't exist or buildid is empty
683     if ( data().getVersionValue( csRevisionItem, sRevisionNumber, _sDefault ) != sal_True ||
684          sRevisionNumber.getLength() == 0 )
685          // read buildid from bootstrap.ini (bootstraprc)
686         sRevisionNumber = data().getBootstrapValue( csRevisionItem, _sDefault );
687     return sRevisionNumber;
688 }
689 
690 // ---------------------------------------------------------------------------------------
691 
getAllUsersValue(OUString const & _sDefault)692 OUString Bootstrap::getAllUsersValue(OUString const& _sDefault)
693 {
694     OUString const csAllUsersItem(RTL_CONSTASCII_USTRINGPARAM(SETUP_ITEM_ALLUSERS));
695 
696     rtl::Bootstrap aData( getExecutableDirectory() + OUString( RTL_CONSTASCII_USTRINGPARAM( "/" SETUP_DATA_NAME ) ) );
697     OUString sResult;
698     aData.getFrom( csAllUsersItem, sResult, _sDefault );
699     return sResult;
700 }
701 // ---------------------------------------------------------------------------------------
702 
locateBaseInstallation(OUString & _rURL)703 Bootstrap::PathStatus Bootstrap::locateBaseInstallation(OUString& _rURL)
704 {
705     Impl::PathData const& aPathData = data().aBaseInstall_;
706 
707     _rURL = aPathData.path;
708     return aPathData.status;
709 }
710 // ---------------------------------------------------------------------------------------
711 
locateUserInstallation(OUString & _rURL)712 PathStatus Bootstrap::locateUserInstallation(OUString& _rURL)
713 {
714     Impl::PathData const& aPathData = data().aUserInstall_;
715 
716     _rURL = aPathData.path;
717     return aPathData.status;
718 }
719 // ---------------------------------------------------------------------------------------
720 
locateSharedData(OUString & _rURL)721 PathStatus Bootstrap::locateSharedData(OUString& _rURL)
722 {
723     OUString const csShareDirItem(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_SHAREDIR));
724 
725     rtl::Bootstrap aData( data().getImplName() );
726 
727     if ( aData.getFrom(csShareDirItem, _rURL) )
728     {
729         return checkStatusAndNormalizeURL(_rURL);
730     }
731     else
732     {
733         OUString const csShareDir(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_DIRNAME_SHAREDIR));
734         return getDerivedPath(_rURL, data().aBaseInstall_, csShareDir, aData, csShareDirItem);
735     }
736 }
737 // ---------------------------------------------------------------------------------------
738 
locateUserData(OUString & _rURL)739 PathStatus Bootstrap::locateUserData(OUString& _rURL)
740 {
741     OUString const csUserDirItem(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_USERDIR));
742 
743     rtl::Bootstrap aData( data().getImplName() );
744 
745     if ( aData.getFrom(csUserDirItem, _rURL) )
746     {
747         return checkStatusAndNormalizeURL(_rURL);
748     }
749     else
750     {
751         OUString const csUserDir(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_DIRNAME_USERDIR));
752         return getDerivedPath(_rURL, data().aUserInstall_ ,csUserDir, aData, csUserDirItem);
753     }
754 }
755 // ---------------------------------------------------------------------------------------
756 
locateBootstrapFile(OUString & _rURL)757 PathStatus Bootstrap::locateBootstrapFile(OUString& _rURL)
758 {
759     Impl::PathData const& aPathData = data().aBootstrapINI_;
760 
761     _rURL = aPathData.path;
762     return aPathData.status;
763 }
764 // ---------------------------------------------------------------------------------------
765 
locateVersionFile(OUString & _rURL)766 PathStatus Bootstrap::locateVersionFile(OUString& _rURL)
767 {
768     Impl::PathData const& aPathData = data().aVersionINI_;
769 
770     _rURL = aPathData.path;
771     return aPathData.status;
772 }
773 // ---------------------------------------------------------------------------------------
774 
checkBootstrapStatus(OUString & _rDiagnosticMessage)775 Bootstrap::Status Bootstrap::checkBootstrapStatus(OUString& _rDiagnosticMessage)
776 {
777     FailureCode eDummyCode(NO_FAILURE);
778 
779     return checkBootstrapStatus(_rDiagnosticMessage,eDummyCode);
780 }
781 // ---------------------------------------------------------------------------------------
782 
checkBootstrapStatus(rtl::OUString & _rDiagnosticMessage,FailureCode & _rErrCode)783 Bootstrap::Status Bootstrap::checkBootstrapStatus(rtl::OUString& _rDiagnosticMessage, FailureCode& _rErrCode)
784 {
785     Impl const& aData = data();
786 
787     Status result = aData.status_;
788 
789     // maybe do further checks here
790 
791     OUStringBuffer sErrorBuffer;
792     if (result != DATA_OK)
793         _rErrCode = describeError(sErrorBuffer,aData);
794 
795     else
796         _rErrCode = NO_FAILURE;
797 
798     _rDiagnosticMessage = sErrorBuffer.makeStringAndClear();
799 
800     return result;
801 }
802 
803 // ---------------------------------------------------------------------------------------
804 // class Bootstrap::Impl
805 // ---------------------------------------------------------------------------------------
806 
initBaseInstallationData(rtl::Bootstrap & _rData)807 bool Bootstrap::Impl::initBaseInstallationData(rtl::Bootstrap& _rData)
808 {
809     OUString const csBaseInstallItem( RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_BASEINSTALLATION) );
810     OUString const csBaseInstallDefault( RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_DEFAULT_BASEINSTALL) );
811 
812     _rData.getFrom(csBaseInstallItem, aBaseInstall_.path, csBaseInstallDefault);
813 
814     bool bResult = (PATH_EXISTS == updateStatus(aBaseInstall_));
815 
816     implGetBootstrapFile(_rData, aBootstrapINI_);
817 
818     return bResult;
819 }
820 // ---------------------------------------------------------------------------------------
821 
initUserInstallationData(rtl::Bootstrap & _rData)822 bool Bootstrap::Impl::initUserInstallationData(rtl::Bootstrap& _rData)
823 {
824     OUString const csUserInstallItem( RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_USERINSTALLATION) );
825 
826     if (_rData.getFrom(csUserInstallItem, aUserInstall_.path))
827     {
828         updateStatus(aUserInstall_);
829     }
830     else
831     {
832         // should we do just this
833         aUserInstall_.status = DATA_MISSING;
834 
835         // .. or this - look for a single-user user directory ?
836         OUString const csUserDirItem(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_USERDIR));
837         OUString sDummy;
838         // look for $BASEINSTALLATION/user only if default UserDir setting is used
839         if (! _rData.getFrom(csUserDirItem, sDummy))
840         {
841             OUString const csUserDir(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_DIRNAME_USERDIR));
842 
843             if ( PATH_EXISTS == getDerivedPath(sDummy, aBaseInstall_, csUserDir, _rData, csUserDirItem) )
844                 aUserInstall_ = aBaseInstall_;
845         }
846     }
847 
848     bool bResult = (PATH_EXISTS == aUserInstall_.status);
849 
850     implGetVersionFile(_rData, aVersionINI_);
851 
852     return bResult;
853 }
854 // ---------------------------------------------------------------------------------------
855 
initialize()856 Bootstrap::Status Bootstrap::Impl::initialize()
857 {
858     Bootstrap::Status result;
859 
860     rtl::Bootstrap aData( m_aImplName );
861 
862     if (!initBaseInstallationData(aData))
863     {
864         result = INVALID_BASE_INSTALL;
865     }
866     else if (!initUserInstallationData(aData))
867     {
868         result = INVALID_USER_INSTALL;
869 
870         if (aUserInstall_.status >= DATA_MISSING)
871         {
872             switch (aVersionINI_.status)
873             {
874             case PATH_EXISTS:
875             case PATH_VALID:
876                 result = MISSING_USER_INSTALL;
877                 break;
878 
879             case DATA_INVALID:
880             case DATA_MISSING:
881                 result = INVALID_BASE_INSTALL;
882                 break;
883             default:
884                 break;
885             }
886         }
887     }
888     else
889     {
890         result = DATA_OK;
891     }
892     return result;
893 }
894 // ---------------------------------------------------------------------------------------
895 
getBootstrapValue(OUString const & _sName,OUString const & _sDefault) const896 OUString Bootstrap::Impl::getBootstrapValue(OUString const& _sName, OUString const& _sDefault) const
897 {
898     rtl::Bootstrap aData( m_aImplName );
899 
900     OUString sResult;
901     aData.getFrom(_sName,sResult,_sDefault);
902     return sResult;
903 }
904 // ---------------------------------------------------------------------------------------
905 
getVersionValue(OUString const & _sName,OUString & _rValue,OUString const & _sDefault) const906 sal_Bool Bootstrap::Impl::getVersionValue(OUString const& _sName, OUString& _rValue, OUString const& _sDefault) const
907 {
908     // try to open version.ini (versionrc)
909     rtl::OUString uri;
910     rtl::Bootstrap::get(
911         rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("OOO_BASE_DIR")), uri);
912     rtl::Bootstrap aData( uri +
913                           OUString(RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE("version"))) );
914     if ( aData.getHandle() == NULL )
915         // version.ini (versionrc) doesn't exist
916         return sal_False;
917 
918     // read value
919     aData.getFrom(_sName,_rValue,_sDefault);
920     return sal_True;
921 }
922 // ---------------------------------------------------------------------------------------
923 
924 } // namespace utl
925 
926