xref: /AOO42X/main/sal/rtl/source/bootstrap.cxx (revision 87d2adbc9cadf14644c3679b041b9226f7630199)
1*87d2adbcSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*87d2adbcSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*87d2adbcSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*87d2adbcSAndrew Rist  * distributed with this work for additional information
6*87d2adbcSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*87d2adbcSAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*87d2adbcSAndrew Rist  * "License"); you may not use this file except in compliance
9*87d2adbcSAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
11*87d2adbcSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
13*87d2adbcSAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*87d2adbcSAndrew Rist  * software distributed under the License is distributed on an
15*87d2adbcSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*87d2adbcSAndrew Rist  * KIND, either express or implied.  See the License for the
17*87d2adbcSAndrew Rist  * specific language governing permissions and limitations
18*87d2adbcSAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
20*87d2adbcSAndrew Rist  *************************************************************/
21*87d2adbcSAndrew Rist 
22*87d2adbcSAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_sal.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include "rtl/bootstrap.h"
28cdf0e10cSrcweir #include "rtl/bootstrap.hxx"
29cdf0e10cSrcweir #include <osl/diagnose.h>
30cdf0e10cSrcweir #include <osl/module.h>
31cdf0e10cSrcweir #include <osl/process.h>
32cdf0e10cSrcweir #include <osl/file.hxx>
33cdf0e10cSrcweir #include <osl/mutex.hxx>
34cdf0e10cSrcweir #include <osl/profile.hxx>
35cdf0e10cSrcweir #include <osl/security.hxx>
36cdf0e10cSrcweir #include <rtl/alloc.h>
37cdf0e10cSrcweir #include <rtl/string.hxx>
38cdf0e10cSrcweir #include <rtl/ustrbuf.hxx>
39cdf0e10cSrcweir #include <rtl/ustring.hxx>
40cdf0e10cSrcweir #include <rtl/byteseq.hxx>
41cdf0e10cSrcweir #include <rtl/instance.hxx>
42cdf0e10cSrcweir #include <rtl/malformeduriexception.hxx>
43cdf0e10cSrcweir #include <rtl/uri.hxx>
44cdf0e10cSrcweir #include "rtl/allocator.hxx"
45cdf0e10cSrcweir 
46cdf0e10cSrcweir #include "macro.hxx"
47cdf0e10cSrcweir 
48cdf0e10cSrcweir #include <hash_map>
49cdf0e10cSrcweir #include <list>
50cdf0e10cSrcweir 
51cdf0e10cSrcweir #define MY_STRING_(x) # x
52cdf0e10cSrcweir #define MY_STRING(x) MY_STRING_(x)
53cdf0e10cSrcweir 
54cdf0e10cSrcweir //----------------------------------------------------------------------------
55cdf0e10cSrcweir 
56cdf0e10cSrcweir using osl::DirectoryItem;
57cdf0e10cSrcweir using osl::FileStatus;
58cdf0e10cSrcweir 
59cdf0e10cSrcweir using rtl::OString;
60cdf0e10cSrcweir using rtl::OUString;
61cdf0e10cSrcweir using rtl::OUStringToOString;
62cdf0e10cSrcweir 
63cdf0e10cSrcweir struct Bootstrap_Impl;
64cdf0e10cSrcweir 
65cdf0e10cSrcweir namespace {
66cdf0e10cSrcweir 
67cdf0e10cSrcweir static char const VND_SUN_STAR_PATHNAME[] = "vnd.sun.star.pathname:";
68cdf0e10cSrcweir 
69cdf0e10cSrcweir bool isPathnameUrl(rtl::OUString const & url) {
70cdf0e10cSrcweir     return url.matchIgnoreAsciiCaseAsciiL(
71cdf0e10cSrcweir         RTL_CONSTASCII_STRINGPARAM(VND_SUN_STAR_PATHNAME));
72cdf0e10cSrcweir }
73cdf0e10cSrcweir 
74cdf0e10cSrcweir bool resolvePathnameUrl(rtl::OUString * url) {
75cdf0e10cSrcweir     OSL_ASSERT(url !=  NULL);
76cdf0e10cSrcweir     if (!isPathnameUrl(*url) ||
77cdf0e10cSrcweir         (osl::FileBase::getFileURLFromSystemPath(
78cdf0e10cSrcweir             url->copy(RTL_CONSTASCII_LENGTH(VND_SUN_STAR_PATHNAME)), *url) ==
79cdf0e10cSrcweir          osl::FileBase::E_None))
80cdf0e10cSrcweir     {
81cdf0e10cSrcweir         return true;
82cdf0e10cSrcweir     } else {
83cdf0e10cSrcweir         *url = rtl::OUString();
84cdf0e10cSrcweir         return false;
85cdf0e10cSrcweir     }
86cdf0e10cSrcweir }
87cdf0e10cSrcweir 
88cdf0e10cSrcweir enum LookupMode {
89cdf0e10cSrcweir     LOOKUP_MODE_NORMAL, LOOKUP_MODE_URE_BOOTSTRAP,
90cdf0e10cSrcweir     LOOKUP_MODE_URE_BOOTSTRAP_EXPANSION };
91cdf0e10cSrcweir 
92cdf0e10cSrcweir struct ExpandRequestLink {
93cdf0e10cSrcweir     ExpandRequestLink const * next;
94cdf0e10cSrcweir     Bootstrap_Impl const * file;
95cdf0e10cSrcweir     rtl::OUString key;
96cdf0e10cSrcweir };
97cdf0e10cSrcweir 
98cdf0e10cSrcweir rtl::OUString expandMacros(
99cdf0e10cSrcweir     Bootstrap_Impl const * file, rtl::OUString const & text, LookupMode mode,
100cdf0e10cSrcweir     ExpandRequestLink const * requestStack);
101cdf0e10cSrcweir 
102cdf0e10cSrcweir rtl::OUString recursivelyExpandMacros(
103cdf0e10cSrcweir     Bootstrap_Impl const * file, rtl::OUString const & text, LookupMode mode,
104cdf0e10cSrcweir     Bootstrap_Impl const * requestFile, rtl::OUString const & requestKey,
105cdf0e10cSrcweir     ExpandRequestLink const * requestStack)
106cdf0e10cSrcweir {
107cdf0e10cSrcweir     for (; requestStack != NULL; requestStack = requestStack->next) {
108cdf0e10cSrcweir         if (requestStack->file == requestFile &&
109cdf0e10cSrcweir             requestStack->key == requestKey)
110cdf0e10cSrcweir         {
111cdf0e10cSrcweir             return rtl::OUString(
112cdf0e10cSrcweir                 RTL_CONSTASCII_USTRINGPARAM("***RECURSION DETECTED***"));
113cdf0e10cSrcweir         }
114cdf0e10cSrcweir     }
115cdf0e10cSrcweir     ExpandRequestLink link = { requestStack, requestFile, requestKey };
116cdf0e10cSrcweir     return expandMacros(file, text, mode, &link);
117cdf0e10cSrcweir }
118cdf0e10cSrcweir 
119cdf0e10cSrcweir }
120cdf0e10cSrcweir 
121cdf0e10cSrcweir //----------------------------------------------------------------------------
122cdf0e10cSrcweir 
123cdf0e10cSrcweir struct rtl_bootstrap_NameValue
124cdf0e10cSrcweir {
125cdf0e10cSrcweir     OUString sName;
126cdf0e10cSrcweir     OUString sValue;
127cdf0e10cSrcweir 
128cdf0e10cSrcweir     inline rtl_bootstrap_NameValue() SAL_THROW( () )
129cdf0e10cSrcweir         {}
130cdf0e10cSrcweir     inline rtl_bootstrap_NameValue(
131cdf0e10cSrcweir         OUString const & name, OUString const & value ) SAL_THROW( () )
132cdf0e10cSrcweir         : sName( name ),
133cdf0e10cSrcweir           sValue( value )
134cdf0e10cSrcweir         {}
135cdf0e10cSrcweir };
136cdf0e10cSrcweir 
137cdf0e10cSrcweir typedef std::list<
138cdf0e10cSrcweir     rtl_bootstrap_NameValue,
139cdf0e10cSrcweir     rtl::Allocator< rtl_bootstrap_NameValue >
140cdf0e10cSrcweir > NameValueList;
141cdf0e10cSrcweir 
142cdf0e10cSrcweir bool find(
143cdf0e10cSrcweir     NameValueList const & list, rtl::OUString const & key,
144cdf0e10cSrcweir     rtl::OUString * value)
145cdf0e10cSrcweir {
146cdf0e10cSrcweir     OSL_ASSERT(value != NULL);
147cdf0e10cSrcweir     for (NameValueList::const_iterator i(list.begin()); i != list.end(); ++i) {
148cdf0e10cSrcweir         if (i->sName == key) {
149cdf0e10cSrcweir             *value = i->sValue;
150cdf0e10cSrcweir             return true;
151cdf0e10cSrcweir         }
152cdf0e10cSrcweir     }
153cdf0e10cSrcweir     return false;
154cdf0e10cSrcweir }
155cdf0e10cSrcweir 
156cdf0e10cSrcweir namespace {
157cdf0e10cSrcweir     struct rtl_bootstrap_set_list :
158cdf0e10cSrcweir         public rtl::Static< NameValueList, rtl_bootstrap_set_list > {};
159cdf0e10cSrcweir }
160cdf0e10cSrcweir 
161cdf0e10cSrcweir //----------------------------------------------------------------------------
162cdf0e10cSrcweir 
163cdf0e10cSrcweir static sal_Bool getFromCommandLineArgs(
164cdf0e10cSrcweir     rtl::OUString const & key, rtl::OUString * value )
165cdf0e10cSrcweir {
166cdf0e10cSrcweir     OSL_ASSERT(value != NULL);
167cdf0e10cSrcweir     static NameValueList *pNameValueList = 0;
168cdf0e10cSrcweir     if( ! pNameValueList )
169cdf0e10cSrcweir     {
170cdf0e10cSrcweir         static NameValueList nameValueList;
171cdf0e10cSrcweir 
172cdf0e10cSrcweir         sal_Int32 nArgCount = osl_getCommandArgCount();
173cdf0e10cSrcweir         for(sal_Int32 i = 0; i < nArgCount; ++ i)
174cdf0e10cSrcweir         {
175cdf0e10cSrcweir             rtl_uString *pArg = 0;
176cdf0e10cSrcweir             osl_getCommandArg( i, &pArg );
177cdf0e10cSrcweir             if( ('-' == pArg->buffer[0] || '/' == pArg->buffer[0] ) &&
178cdf0e10cSrcweir                 'e' == pArg->buffer[1] &&
179cdf0e10cSrcweir                 'n' == pArg->buffer[2] &&
180cdf0e10cSrcweir                 'v' == pArg->buffer[3] &&
181cdf0e10cSrcweir                 ':' == pArg->buffer[4] )
182cdf0e10cSrcweir             {
183cdf0e10cSrcweir                 sal_Int32 nIndex = rtl_ustr_indexOfChar( pArg->buffer, '=' );
184cdf0e10cSrcweir                 if( nIndex >= 0 )
185cdf0e10cSrcweir                 {
186cdf0e10cSrcweir 
187cdf0e10cSrcweir                     rtl_bootstrap_NameValue nameValue;
188cdf0e10cSrcweir                     nameValue.sName = OUString( &(pArg->buffer[5]), nIndex - 5  );
189cdf0e10cSrcweir                     nameValue.sValue = OUString( &(pArg->buffer[nIndex+1]) );
190cdf0e10cSrcweir                     if( i == nArgCount-1 &&
191cdf0e10cSrcweir                         nameValue.sValue.getLength() &&
192cdf0e10cSrcweir                         nameValue.sValue[nameValue.sValue.getLength()-1] == 13 )
193cdf0e10cSrcweir                     {
194cdf0e10cSrcweir                         // avoid the 13 linefeed for the last argument,
195cdf0e10cSrcweir                         // when the executable is started from a script,
196cdf0e10cSrcweir                         // that was edited on windows
197cdf0e10cSrcweir                         nameValue.sValue = nameValue.sValue.copy(0,nameValue.sValue.getLength()-1);
198cdf0e10cSrcweir                     }
199cdf0e10cSrcweir                     nameValueList.push_back( nameValue );
200cdf0e10cSrcweir                 }
201cdf0e10cSrcweir             }
202cdf0e10cSrcweir             rtl_uString_release( pArg );
203cdf0e10cSrcweir         }
204cdf0e10cSrcweir         pNameValueList = &nameValueList;
205cdf0e10cSrcweir     }
206cdf0e10cSrcweir 
207cdf0e10cSrcweir     sal_Bool found = sal_False;
208cdf0e10cSrcweir 
209cdf0e10cSrcweir     for( NameValueList::iterator ii = pNameValueList->begin() ;
210cdf0e10cSrcweir          ii != pNameValueList->end() ;
211cdf0e10cSrcweir          ++ii )
212cdf0e10cSrcweir     {
213cdf0e10cSrcweir         if( (*ii).sName.equals(key) )
214cdf0e10cSrcweir         {
215cdf0e10cSrcweir             *value = (*ii).sValue;
216cdf0e10cSrcweir             found = sal_True;
217cdf0e10cSrcweir             break;
218cdf0e10cSrcweir         }
219cdf0e10cSrcweir     }
220cdf0e10cSrcweir 
221cdf0e10cSrcweir     return found;
222cdf0e10cSrcweir }
223cdf0e10cSrcweir 
224cdf0e10cSrcweir //----------------------------------------------------------------------------
225cdf0e10cSrcweir 
226cdf0e10cSrcweir extern "C" oslProcessError SAL_CALL osl_bootstrap_getExecutableFile_Impl (
227cdf0e10cSrcweir     rtl_uString ** ppFileURL) SAL_THROW_EXTERN_C();
228cdf0e10cSrcweir 
229cdf0e10cSrcweir inline void getExecutableFile_Impl (rtl_uString ** ppFileURL)
230cdf0e10cSrcweir {
231cdf0e10cSrcweir     osl_bootstrap_getExecutableFile_Impl (ppFileURL);
232cdf0e10cSrcweir }
233cdf0e10cSrcweir 
234cdf0e10cSrcweir //----------------------------------------------------------------------------
235cdf0e10cSrcweir 
236cdf0e10cSrcweir static void getExecutableDirectory_Impl (rtl_uString ** ppDirURL)
237cdf0e10cSrcweir {
238cdf0e10cSrcweir     OUString fileName;
239cdf0e10cSrcweir     getExecutableFile_Impl (&(fileName.pData));
240cdf0e10cSrcweir 
241cdf0e10cSrcweir     sal_Int32 nDirEnd = fileName.lastIndexOf('/');
242cdf0e10cSrcweir     OSL_ENSURE(nDirEnd >= 0, "Cannot locate executable directory");
243cdf0e10cSrcweir 
244cdf0e10cSrcweir     rtl_uString_newFromStr_WithLength(ppDirURL,fileName.getStr(),nDirEnd);
245cdf0e10cSrcweir }
246cdf0e10cSrcweir 
247cdf0e10cSrcweir //----------------------------------------------------------------------------
248cdf0e10cSrcweir 
249cdf0e10cSrcweir static OUString & getIniFileName_Impl()
250cdf0e10cSrcweir {
251cdf0e10cSrcweir     static OUString *pStaticName = 0;
252cdf0e10cSrcweir     if( ! pStaticName )
253cdf0e10cSrcweir     {
254cdf0e10cSrcweir         OUString fileName;
255cdf0e10cSrcweir 
256cdf0e10cSrcweir         if(getFromCommandLineArgs(
257cdf0e10cSrcweir                OUString(RTL_CONSTASCII_USTRINGPARAM("INIFILENAME")), &fileName))
258cdf0e10cSrcweir         {
259cdf0e10cSrcweir             resolvePathnameUrl(&fileName);
260cdf0e10cSrcweir         }
261cdf0e10cSrcweir         else
262cdf0e10cSrcweir         {
263cdf0e10cSrcweir             getExecutableFile_Impl (&(fileName.pData));
264cdf0e10cSrcweir 
265cdf0e10cSrcweir             // get rid of a potential executable extension
266cdf0e10cSrcweir             OUString progExt (RTL_CONSTASCII_USTRINGPARAM(".bin"));
267cdf0e10cSrcweir             if(fileName.getLength() > progExt.getLength()
268cdf0e10cSrcweir             && fileName.copy(fileName.getLength() - progExt.getLength()).equalsIgnoreAsciiCase(progExt))
269cdf0e10cSrcweir                 fileName = fileName.copy(0, fileName.getLength() - progExt.getLength());
270cdf0e10cSrcweir 
271cdf0e10cSrcweir             progExt = OUString::createFromAscii(".exe");
272cdf0e10cSrcweir             if(fileName.getLength() > progExt.getLength()
273cdf0e10cSrcweir             && fileName.copy(fileName.getLength() - progExt.getLength()).equalsIgnoreAsciiCase(progExt))
274cdf0e10cSrcweir                 fileName = fileName.copy(0, fileName.getLength() - progExt.getLength());
275cdf0e10cSrcweir 
276cdf0e10cSrcweir             // append config file suffix
277cdf0e10cSrcweir             fileName += OUString(RTL_CONSTASCII_USTRINGPARAM(SAL_CONFIGFILE("")));
278cdf0e10cSrcweir         }
279cdf0e10cSrcweir 
280cdf0e10cSrcweir         static OUString theFileName;
281cdf0e10cSrcweir         if(fileName.getLength())
282cdf0e10cSrcweir             theFileName = fileName;
283cdf0e10cSrcweir 
284cdf0e10cSrcweir         pStaticName = &theFileName;
285cdf0e10cSrcweir     }
286cdf0e10cSrcweir 
287cdf0e10cSrcweir     return *pStaticName;
288cdf0e10cSrcweir }
289cdf0e10cSrcweir 
290cdf0e10cSrcweir //----------------------------------------------------------------------------
291cdf0e10cSrcweir 
292cdf0e10cSrcweir static inline bool path_exists( OUString const & path )
293cdf0e10cSrcweir {
294cdf0e10cSrcweir     DirectoryItem dirItem;
295cdf0e10cSrcweir     return (DirectoryItem::E_None == DirectoryItem::get( path, dirItem ));
296cdf0e10cSrcweir }
297cdf0e10cSrcweir 
298cdf0e10cSrcweir //----------------------------------------------------------------------------
299cdf0e10cSrcweir // #111772#
300cdf0e10cSrcweir // ensure the given file url has no final slash
301cdf0e10cSrcweir 
302cdf0e10cSrcweir inline void EnsureNoFinalSlash (rtl::OUString & url)
303cdf0e10cSrcweir {
304cdf0e10cSrcweir     sal_Int32 i = url.getLength();
305cdf0e10cSrcweir     if (i > 0 && url[i - 1] == '/') {
306cdf0e10cSrcweir         url = url.copy(0, i - 1);
307cdf0e10cSrcweir     }
308cdf0e10cSrcweir }
309cdf0e10cSrcweir 
310cdf0e10cSrcweir //----------------------------------------------------------------------------
311cdf0e10cSrcweir //----------------------------------------------------------------------------
312cdf0e10cSrcweir 
313cdf0e10cSrcweir struct Bootstrap_Impl
314cdf0e10cSrcweir {
315cdf0e10cSrcweir     sal_Int32 _nRefCount;
316cdf0e10cSrcweir     Bootstrap_Impl * _base_ini;
317cdf0e10cSrcweir 
318cdf0e10cSrcweir     NameValueList _nameValueList;
319cdf0e10cSrcweir     OUString      _iniName;
320cdf0e10cSrcweir 
321cdf0e10cSrcweir     explicit Bootstrap_Impl (OUString const & rIniName);
322cdf0e10cSrcweir     ~Bootstrap_Impl();
323cdf0e10cSrcweir 
324cdf0e10cSrcweir     static void * operator new (std::size_t n) SAL_THROW(())
325cdf0e10cSrcweir         { return rtl_allocateMemory (sal_uInt32(n)); }
326cdf0e10cSrcweir     static void operator delete (void * p , std::size_t) SAL_THROW(())
327cdf0e10cSrcweir         { rtl_freeMemory (p); }
328cdf0e10cSrcweir 
329cdf0e10cSrcweir     bool getValue(
330cdf0e10cSrcweir         rtl::OUString const & key, rtl_uString ** value,
331cdf0e10cSrcweir         rtl_uString * defaultValue, LookupMode mode, bool override,
332cdf0e10cSrcweir         ExpandRequestLink const * requestStack) const;
333cdf0e10cSrcweir     bool getDirectValue(
334cdf0e10cSrcweir         rtl::OUString const & key, rtl_uString ** value, LookupMode mode,
335cdf0e10cSrcweir         ExpandRequestLink const * requestStack) const;
336cdf0e10cSrcweir     bool getAmbienceValue(
337cdf0e10cSrcweir         rtl::OUString const & key, rtl_uString ** value, LookupMode mode,
338cdf0e10cSrcweir         ExpandRequestLink const * requestStack) const;
339cdf0e10cSrcweir     void expandValue(
340cdf0e10cSrcweir         rtl_uString ** value, rtl::OUString const & text, LookupMode mode,
341cdf0e10cSrcweir         Bootstrap_Impl const * requestFile, rtl::OUString const & requestKey,
342cdf0e10cSrcweir         ExpandRequestLink const * requestStack) const;
343cdf0e10cSrcweir };
344cdf0e10cSrcweir 
345cdf0e10cSrcweir //----------------------------------------------------------------------------
346cdf0e10cSrcweir 
347cdf0e10cSrcweir Bootstrap_Impl::Bootstrap_Impl( OUString const & rIniName )
348cdf0e10cSrcweir     : _nRefCount( 0 ),
349cdf0e10cSrcweir       _base_ini( 0 ),
350cdf0e10cSrcweir       _iniName (rIniName)
351cdf0e10cSrcweir {
352cdf0e10cSrcweir     OUString base_ini( getIniFileName_Impl() );
353cdf0e10cSrcweir     // normalize path
354cdf0e10cSrcweir     FileStatus status( FileStatusMask_FileURL );
355cdf0e10cSrcweir     DirectoryItem dirItem;
356cdf0e10cSrcweir     if (DirectoryItem::E_None == DirectoryItem::get( base_ini, dirItem ) &&
357cdf0e10cSrcweir         DirectoryItem::E_None == dirItem.getFileStatus( status ))
358cdf0e10cSrcweir     {
359cdf0e10cSrcweir         base_ini = status.getFileURL();
360cdf0e10cSrcweir         if (! rIniName.equals( base_ini ))
361cdf0e10cSrcweir         {
362cdf0e10cSrcweir             _base_ini = static_cast< Bootstrap_Impl * >(
363cdf0e10cSrcweir                 rtl_bootstrap_args_open( base_ini.pData ) );
364cdf0e10cSrcweir         }
365cdf0e10cSrcweir     }
366cdf0e10cSrcweir 
367cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
368cdf0e10cSrcweir     OString sFile = OUStringToOString(_iniName, RTL_TEXTENCODING_ASCII_US);
369cdf0e10cSrcweir     OSL_TRACE(__FILE__" -- Bootstrap_Impl() - %s\n", sFile.getStr());
370cdf0e10cSrcweir #endif /* OSL_DEBUG_LEVEL > 1 */
371cdf0e10cSrcweir 
372cdf0e10cSrcweir     oslFileHandle handle;
373cdf0e10cSrcweir     if (_iniName.getLength() &&
374cdf0e10cSrcweir         osl_File_E_None == osl_openFile(_iniName.pData, &handle, osl_File_OpenFlag_Read))
375cdf0e10cSrcweir     {
376cdf0e10cSrcweir         rtl::ByteSequence seq;
377cdf0e10cSrcweir 
378cdf0e10cSrcweir         while (osl_File_E_None == osl_readLine(handle , (sal_Sequence **)&seq))
379cdf0e10cSrcweir         {
380cdf0e10cSrcweir             OString line( (const sal_Char *) seq.getConstArray(), seq.getLength() );
381cdf0e10cSrcweir             sal_Int32 nIndex = line.indexOf('=');
382cdf0e10cSrcweir             if (nIndex >= 1)
383cdf0e10cSrcweir             {
384cdf0e10cSrcweir                 struct rtl_bootstrap_NameValue nameValue;
385cdf0e10cSrcweir                 nameValue.sName = OStringToOUString(
386cdf0e10cSrcweir                     line.copy(0,nIndex).trim(), RTL_TEXTENCODING_ASCII_US );
387cdf0e10cSrcweir                 nameValue.sValue = OStringToOUString(
388cdf0e10cSrcweir                     line.copy(nIndex+1).trim(), RTL_TEXTENCODING_UTF8 );
389cdf0e10cSrcweir 
390cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
391cdf0e10cSrcweir                 OString name_tmp = OUStringToOString(nameValue.sName, RTL_TEXTENCODING_ASCII_US);
392cdf0e10cSrcweir                 OString value_tmp = OUStringToOString(nameValue.sValue, RTL_TEXTENCODING_UTF8);
393cdf0e10cSrcweir                 OSL_TRACE(
394cdf0e10cSrcweir                     __FILE__" -- pushing: name=%s value=%s\n",
395cdf0e10cSrcweir                     name_tmp.getStr(), value_tmp.getStr() );
396cdf0e10cSrcweir #endif /* OSL_DEBUG_LEVEL > 1 */
397cdf0e10cSrcweir 
398cdf0e10cSrcweir                 _nameValueList.push_back(nameValue);
399cdf0e10cSrcweir             }
400cdf0e10cSrcweir         }
401cdf0e10cSrcweir         osl_closeFile(handle);
402cdf0e10cSrcweir     }
403cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
404cdf0e10cSrcweir     else
405cdf0e10cSrcweir     {
406cdf0e10cSrcweir         OString file_tmp = OUStringToOString(_iniName, RTL_TEXTENCODING_ASCII_US);
407cdf0e10cSrcweir         OSL_TRACE( __FILE__" -- couldn't open file: %s", file_tmp.getStr() );
408cdf0e10cSrcweir     }
409cdf0e10cSrcweir #endif /* OSL_DEBUG_LEVEL > 1 */
410cdf0e10cSrcweir }
411cdf0e10cSrcweir 
412cdf0e10cSrcweir //----------------------------------------------------------------------------
413cdf0e10cSrcweir 
414cdf0e10cSrcweir Bootstrap_Impl::~Bootstrap_Impl()
415cdf0e10cSrcweir {
416cdf0e10cSrcweir     if (_base_ini != 0)
417cdf0e10cSrcweir         rtl_bootstrap_args_close( _base_ini );
418cdf0e10cSrcweir }
419cdf0e10cSrcweir 
420cdf0e10cSrcweir //----------------------------------------------------------------------------
421cdf0e10cSrcweir 
422cdf0e10cSrcweir namespace {
423cdf0e10cSrcweir 
424cdf0e10cSrcweir Bootstrap_Impl * get_static_bootstrap_handle() SAL_THROW(())
425cdf0e10cSrcweir {
426cdf0e10cSrcweir     osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
427cdf0e10cSrcweir     static Bootstrap_Impl * s_handle = 0;
428cdf0e10cSrcweir     if (s_handle == 0)
429cdf0e10cSrcweir     {
430cdf0e10cSrcweir         OUString iniName (getIniFileName_Impl());
431cdf0e10cSrcweir         s_handle = static_cast< Bootstrap_Impl * >(
432cdf0e10cSrcweir             rtl_bootstrap_args_open( iniName.pData ) );
433cdf0e10cSrcweir         if (s_handle == 0)
434cdf0e10cSrcweir         {
435cdf0e10cSrcweir             Bootstrap_Impl * that = new Bootstrap_Impl( iniName );
436cdf0e10cSrcweir             ++that->_nRefCount;
437cdf0e10cSrcweir             s_handle = that;
438cdf0e10cSrcweir         }
439cdf0e10cSrcweir     }
440cdf0e10cSrcweir     return s_handle;
441cdf0e10cSrcweir }
442cdf0e10cSrcweir 
443cdf0e10cSrcweir struct FundamentalIniData {
444cdf0e10cSrcweir     rtlBootstrapHandle ini;
445cdf0e10cSrcweir 
446cdf0e10cSrcweir     FundamentalIniData() {
447cdf0e10cSrcweir         OUString uri;
448cdf0e10cSrcweir         ini =
449cdf0e10cSrcweir             ((static_cast< Bootstrap_Impl * >(get_static_bootstrap_handle())->
450cdf0e10cSrcweir               getValue(
451cdf0e10cSrcweir                   rtl::OUString(
452cdf0e10cSrcweir                       RTL_CONSTASCII_USTRINGPARAM("URE_BOOTSTRAP")),
453cdf0e10cSrcweir                   &uri.pData, 0, LOOKUP_MODE_NORMAL, false, 0)) &&
454cdf0e10cSrcweir              resolvePathnameUrl(&uri))
455cdf0e10cSrcweir             ? rtl_bootstrap_args_open(uri.pData) : NULL;
456cdf0e10cSrcweir     }
457cdf0e10cSrcweir 
458cdf0e10cSrcweir     ~FundamentalIniData() { rtl_bootstrap_args_close(ini); }
459cdf0e10cSrcweir 
460cdf0e10cSrcweir private:
461cdf0e10cSrcweir     FundamentalIniData(FundamentalIniData &); // not defined
462cdf0e10cSrcweir     void operator =(FundamentalIniData &); // not defined
463cdf0e10cSrcweir };
464cdf0e10cSrcweir 
465cdf0e10cSrcweir struct FundamentalIni: public rtl::Static< FundamentalIniData, FundamentalIni >
466cdf0e10cSrcweir {};
467cdf0e10cSrcweir 
468cdf0e10cSrcweir }
469cdf0e10cSrcweir 
470cdf0e10cSrcweir bool Bootstrap_Impl::getValue(
471cdf0e10cSrcweir     rtl::OUString const & key, rtl_uString ** value, rtl_uString * defaultValue,
472cdf0e10cSrcweir     LookupMode mode, bool override, ExpandRequestLink const * requestStack)
473cdf0e10cSrcweir     const
474cdf0e10cSrcweir {
475cdf0e10cSrcweir     if (mode == LOOKUP_MODE_NORMAL &&
476cdf0e10cSrcweir         key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("URE_BOOTSTRAP")))
477cdf0e10cSrcweir     {
478cdf0e10cSrcweir         mode = LOOKUP_MODE_URE_BOOTSTRAP;
479cdf0e10cSrcweir     }
480cdf0e10cSrcweir     if (override && getDirectValue(key, value, mode, requestStack)) {
481cdf0e10cSrcweir         return true;
482cdf0e10cSrcweir     }
483cdf0e10cSrcweir     if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("_OS"))) {
484cdf0e10cSrcweir         rtl_uString_assign(
485cdf0e10cSrcweir             value, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(THIS_OS)).pData);
486cdf0e10cSrcweir         return true;
487cdf0e10cSrcweir     }
488cdf0e10cSrcweir     if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("_ARCH"))) {
489cdf0e10cSrcweir         rtl_uString_assign(
490cdf0e10cSrcweir             value, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(THIS_ARCH)).pData);
491cdf0e10cSrcweir         return true;
492cdf0e10cSrcweir     }
493cdf0e10cSrcweir     if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("_CPPU_ENV"))) {
494cdf0e10cSrcweir         rtl_uString_assign(
495cdf0e10cSrcweir             value,
496cdf0e10cSrcweir             (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(MY_STRING(CPPU_ENV))).
497cdf0e10cSrcweir              pData));
498cdf0e10cSrcweir         return true;
499cdf0e10cSrcweir     }
500cdf0e10cSrcweir     if (key.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("ORIGIN"))) {
501cdf0e10cSrcweir         rtl_uString_assign(
502cdf0e10cSrcweir             value,
503cdf0e10cSrcweir             _iniName.copy(
504cdf0e10cSrcweir                 0, std::max<sal_Int32>(0, _iniName.lastIndexOf('/'))).pData);
505cdf0e10cSrcweir         return true;
506cdf0e10cSrcweir     }
507cdf0e10cSrcweir     if (getAmbienceValue(key, value, mode, requestStack)) {
508cdf0e10cSrcweir         return true;
509cdf0e10cSrcweir     }
510cdf0e10cSrcweir     if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("SYSUSERCONFIG"))) {
511cdf0e10cSrcweir         rtl::OUString v;
512cdf0e10cSrcweir         bool b = osl::Security().getConfigDir(v);
513cdf0e10cSrcweir         EnsureNoFinalSlash(v);
514cdf0e10cSrcweir         rtl_uString_assign(value, v.pData);
515cdf0e10cSrcweir         return b;
516cdf0e10cSrcweir     }
517cdf0e10cSrcweir     if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("SYSUSERHOME"))) {
518cdf0e10cSrcweir         rtl::OUString v;
519cdf0e10cSrcweir         bool b = osl::Security().getHomeDir(v);
520cdf0e10cSrcweir         EnsureNoFinalSlash(v);
521cdf0e10cSrcweir         rtl_uString_assign(value, v.pData);
522cdf0e10cSrcweir         return b;
523cdf0e10cSrcweir     }
524cdf0e10cSrcweir     if (key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("SYSBINDIR"))) {
525cdf0e10cSrcweir         getExecutableDirectory_Impl(value);
526cdf0e10cSrcweir         return true;
527cdf0e10cSrcweir     }
528cdf0e10cSrcweir     if (_base_ini != NULL &&
529cdf0e10cSrcweir         _base_ini->getDirectValue(key, value, mode, requestStack))
530cdf0e10cSrcweir     {
531cdf0e10cSrcweir         return true;
532cdf0e10cSrcweir     }
533cdf0e10cSrcweir     if (!override && getDirectValue(key, value, mode, requestStack)) {
534cdf0e10cSrcweir         return true;
535cdf0e10cSrcweir     }
536cdf0e10cSrcweir     if (mode == LOOKUP_MODE_NORMAL) {
537cdf0e10cSrcweir         FundamentalIniData const & d = FundamentalIni::get();
538cdf0e10cSrcweir         Bootstrap_Impl const * b = static_cast<Bootstrap_Impl const *>(d.ini);
539cdf0e10cSrcweir         if (b != NULL && b != this &&
540cdf0e10cSrcweir             b->getDirectValue(key, value, mode, requestStack))
541cdf0e10cSrcweir         {
542cdf0e10cSrcweir             return true;
543cdf0e10cSrcweir         }
544cdf0e10cSrcweir     }
545cdf0e10cSrcweir     if (defaultValue != NULL) {
546cdf0e10cSrcweir         rtl_uString_assign(value, defaultValue);
547cdf0e10cSrcweir         return true;
548cdf0e10cSrcweir     }
549cdf0e10cSrcweir     rtl_uString_new(value);
550cdf0e10cSrcweir     return false;
551cdf0e10cSrcweir }
552cdf0e10cSrcweir 
553cdf0e10cSrcweir bool Bootstrap_Impl::getDirectValue(
554cdf0e10cSrcweir     rtl::OUString const & key, rtl_uString ** value, LookupMode mode,
555cdf0e10cSrcweir     ExpandRequestLink const * requestStack) const
556cdf0e10cSrcweir {
557cdf0e10cSrcweir     rtl::OUString v;
558cdf0e10cSrcweir     if (find(_nameValueList, key, &v)) {
559cdf0e10cSrcweir         expandValue(value, v, mode, this, key, requestStack);
560cdf0e10cSrcweir         return true;
561cdf0e10cSrcweir     } else {
562cdf0e10cSrcweir         return false;
563cdf0e10cSrcweir     }
564cdf0e10cSrcweir }
565cdf0e10cSrcweir 
566cdf0e10cSrcweir bool Bootstrap_Impl::getAmbienceValue(
567cdf0e10cSrcweir     rtl::OUString const & key, rtl_uString ** value, LookupMode mode,
568cdf0e10cSrcweir     ExpandRequestLink const * requestStack) const
569cdf0e10cSrcweir {
570cdf0e10cSrcweir     rtl::OUString v;
571cdf0e10cSrcweir     bool f;
572cdf0e10cSrcweir     {
573cdf0e10cSrcweir         osl::MutexGuard g(osl::Mutex::getGlobalMutex());
574cdf0e10cSrcweir         f = find(rtl_bootstrap_set_list::get(), key, &v);
575cdf0e10cSrcweir     }
576cdf0e10cSrcweir     if (f || getFromCommandLineArgs(key, &v) ||
577cdf0e10cSrcweir         osl_getEnvironment(key.pData, &v.pData) == osl_Process_E_None)
578cdf0e10cSrcweir     {
579cdf0e10cSrcweir         expandValue(value, v, mode, NULL, key, requestStack);
580cdf0e10cSrcweir         return true;
581cdf0e10cSrcweir     } else {
582cdf0e10cSrcweir         return false;
583cdf0e10cSrcweir     }
584cdf0e10cSrcweir }
585cdf0e10cSrcweir 
586cdf0e10cSrcweir void Bootstrap_Impl::expandValue(
587cdf0e10cSrcweir     rtl_uString ** value, rtl::OUString const & text, LookupMode mode,
588cdf0e10cSrcweir     Bootstrap_Impl const * requestFile, rtl::OUString const & requestKey,
589cdf0e10cSrcweir     ExpandRequestLink const * requestStack) const
590cdf0e10cSrcweir {
591cdf0e10cSrcweir     rtl_uString_assign(
592cdf0e10cSrcweir         value,
593cdf0e10cSrcweir         (mode == LOOKUP_MODE_URE_BOOTSTRAP && isPathnameUrl(text) ?
594cdf0e10cSrcweir          text :
595cdf0e10cSrcweir          recursivelyExpandMacros(
596cdf0e10cSrcweir              this, text,
597cdf0e10cSrcweir              (mode == LOOKUP_MODE_URE_BOOTSTRAP ?
598cdf0e10cSrcweir               LOOKUP_MODE_URE_BOOTSTRAP_EXPANSION : mode),
599cdf0e10cSrcweir              requestFile, requestKey, requestStack)).pData);
600cdf0e10cSrcweir }
601cdf0e10cSrcweir 
602cdf0e10cSrcweir //----------------------------------------------------------------------------
603cdf0e10cSrcweir //----------------------------------------------------------------------------
604cdf0e10cSrcweir 
605cdf0e10cSrcweir namespace {
606cdf0e10cSrcweir 
607cdf0e10cSrcweir struct bootstrap_map {
608cdf0e10cSrcweir     // map<> may be preferred here, but hash_map<> is implemented fully inline,
609cdf0e10cSrcweir     // thus there is no need to link against the stlport:
610cdf0e10cSrcweir     typedef std::hash_map<
611cdf0e10cSrcweir         rtl::OUString, Bootstrap_Impl *,
612cdf0e10cSrcweir         rtl::OUStringHash, std::equal_to< rtl::OUString >,
613cdf0e10cSrcweir         rtl::Allocator< OUString > > t;
614cdf0e10cSrcweir 
615cdf0e10cSrcweir     // get and release must only be called properly synchronized via some mutex
616cdf0e10cSrcweir     // (e.g., osl::Mutex::getGlobalMutex()):
617cdf0e10cSrcweir 
618cdf0e10cSrcweir     static t * get() {
619cdf0e10cSrcweir         if (m_map == NULL) {
620cdf0e10cSrcweir             m_map = new t;
621cdf0e10cSrcweir         }
622cdf0e10cSrcweir         return m_map;
623cdf0e10cSrcweir     }
624cdf0e10cSrcweir 
625cdf0e10cSrcweir     static void release() {
626cdf0e10cSrcweir         if (m_map != NULL && m_map->empty()) {
627cdf0e10cSrcweir             delete m_map;
628cdf0e10cSrcweir             m_map = NULL;
629cdf0e10cSrcweir         }
630cdf0e10cSrcweir     }
631cdf0e10cSrcweir 
632cdf0e10cSrcweir private:
633cdf0e10cSrcweir     bootstrap_map(); // not defined
634cdf0e10cSrcweir 
635cdf0e10cSrcweir     static t * m_map;
636cdf0e10cSrcweir };
637cdf0e10cSrcweir 
638cdf0e10cSrcweir bootstrap_map::t * bootstrap_map::m_map = NULL;
639cdf0e10cSrcweir 
640cdf0e10cSrcweir }
641cdf0e10cSrcweir 
642cdf0e10cSrcweir //----------------------------------------------------------------------------
643cdf0e10cSrcweir 
644cdf0e10cSrcweir rtlBootstrapHandle SAL_CALL rtl_bootstrap_args_open (
645cdf0e10cSrcweir     rtl_uString * pIniName
646cdf0e10cSrcweir ) SAL_THROW_EXTERN_C()
647cdf0e10cSrcweir {
648cdf0e10cSrcweir     OUString iniName( pIniName );
649cdf0e10cSrcweir 
650cdf0e10cSrcweir     // normalize path
651cdf0e10cSrcweir     FileStatus status( FileStatusMask_FileURL );
652cdf0e10cSrcweir     DirectoryItem dirItem;
653cdf0e10cSrcweir     if (DirectoryItem::E_None != DirectoryItem::get( iniName, dirItem ) ||
654cdf0e10cSrcweir         DirectoryItem::E_None != dirItem.getFileStatus( status ))
655cdf0e10cSrcweir     {
656cdf0e10cSrcweir         return 0;
657cdf0e10cSrcweir     }
658cdf0e10cSrcweir     iniName = status.getFileURL();
659cdf0e10cSrcweir 
660cdf0e10cSrcweir     Bootstrap_Impl * that;
661cdf0e10cSrcweir     osl::ResettableMutexGuard guard( osl::Mutex::getGlobalMutex() );
662cdf0e10cSrcweir     bootstrap_map::t* p_bootstrap_map = bootstrap_map::get();
663cdf0e10cSrcweir     bootstrap_map::t::const_iterator iFind( p_bootstrap_map->find( iniName ) );
664cdf0e10cSrcweir     if (iFind == p_bootstrap_map->end())
665cdf0e10cSrcweir     {
666cdf0e10cSrcweir         bootstrap_map::release();
667cdf0e10cSrcweir         guard.clear();
668cdf0e10cSrcweir         that = new Bootstrap_Impl( iniName );
669cdf0e10cSrcweir         guard.reset();
670cdf0e10cSrcweir         p_bootstrap_map = bootstrap_map::get();
671cdf0e10cSrcweir         iFind = p_bootstrap_map->find( iniName );
672cdf0e10cSrcweir         if (iFind == p_bootstrap_map->end())
673cdf0e10cSrcweir         {
674cdf0e10cSrcweir             ++that->_nRefCount;
675cdf0e10cSrcweir             ::std::pair< bootstrap_map::t::iterator, bool > insertion(
676cdf0e10cSrcweir                 p_bootstrap_map->insert(
677cdf0e10cSrcweir                     bootstrap_map::t::value_type( iniName, that ) ) );
678cdf0e10cSrcweir             OSL_ASSERT( insertion.second );
679cdf0e10cSrcweir         }
680cdf0e10cSrcweir         else
681cdf0e10cSrcweir         {
682cdf0e10cSrcweir             Bootstrap_Impl * obsolete = that;
683cdf0e10cSrcweir             that = iFind->second;
684cdf0e10cSrcweir             ++that->_nRefCount;
685cdf0e10cSrcweir             guard.clear();
686cdf0e10cSrcweir             delete obsolete;
687cdf0e10cSrcweir         }
688cdf0e10cSrcweir     }
689cdf0e10cSrcweir     else
690cdf0e10cSrcweir     {
691cdf0e10cSrcweir         that = iFind->second;
692cdf0e10cSrcweir         ++that->_nRefCount;
693cdf0e10cSrcweir     }
694cdf0e10cSrcweir     return static_cast< rtlBootstrapHandle >( that );
695cdf0e10cSrcweir }
696cdf0e10cSrcweir 
697cdf0e10cSrcweir //----------------------------------------------------------------------------
698cdf0e10cSrcweir 
699cdf0e10cSrcweir void SAL_CALL rtl_bootstrap_args_close (
700cdf0e10cSrcweir     rtlBootstrapHandle handle
701cdf0e10cSrcweir ) SAL_THROW_EXTERN_C()
702cdf0e10cSrcweir {
703cdf0e10cSrcweir     if (handle == 0)
704cdf0e10cSrcweir         return;
705cdf0e10cSrcweir     Bootstrap_Impl * that = static_cast< Bootstrap_Impl * >( handle );
706cdf0e10cSrcweir 
707cdf0e10cSrcweir     osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
708cdf0e10cSrcweir     bootstrap_map::t* p_bootstrap_map = bootstrap_map::get();
709cdf0e10cSrcweir     OSL_ASSERT(
710cdf0e10cSrcweir         p_bootstrap_map->find( that->_iniName )->second == that );
711cdf0e10cSrcweir     --that->_nRefCount;
712cdf0e10cSrcweir     if (that->_nRefCount == 0)
713cdf0e10cSrcweir     {
714cdf0e10cSrcweir         ::std::size_t nLeaking = 8; // only hold up to 8 files statically
715cdf0e10cSrcweir 
716cdf0e10cSrcweir #if OSL_DEBUG_LEVEL == 1 // nonpro
717cdf0e10cSrcweir         nLeaking = 0;
718cdf0e10cSrcweir #elif OSL_DEBUG_LEVEL > 1 // debug
719cdf0e10cSrcweir         nLeaking = 1;
720cdf0e10cSrcweir #endif /* OSL_DEBUG_LEVEL */
721cdf0e10cSrcweir 
722cdf0e10cSrcweir         if (p_bootstrap_map->size() > nLeaking)
723cdf0e10cSrcweir         {
724cdf0e10cSrcweir             ::std::size_t erased = p_bootstrap_map->erase( that->_iniName );
725cdf0e10cSrcweir             if (erased != 1) {
726cdf0e10cSrcweir                 OSL_ASSERT( false );
727cdf0e10cSrcweir             }
728cdf0e10cSrcweir             delete that;
729cdf0e10cSrcweir         }
730cdf0e10cSrcweir         bootstrap_map::release();
731cdf0e10cSrcweir     }
732cdf0e10cSrcweir }
733cdf0e10cSrcweir 
734cdf0e10cSrcweir //----------------------------------------------------------------------------
735cdf0e10cSrcweir 
736cdf0e10cSrcweir sal_Bool SAL_CALL rtl_bootstrap_get_from_handle(
737cdf0e10cSrcweir     rtlBootstrapHandle handle,
738cdf0e10cSrcweir     rtl_uString      * pName,
739cdf0e10cSrcweir     rtl_uString     ** ppValue,
740cdf0e10cSrcweir     rtl_uString      * pDefault
741cdf0e10cSrcweir ) SAL_THROW_EXTERN_C()
742cdf0e10cSrcweir {
743cdf0e10cSrcweir     osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
744cdf0e10cSrcweir 
745cdf0e10cSrcweir     sal_Bool found = sal_False;
746cdf0e10cSrcweir     if(ppValue && pName)
747cdf0e10cSrcweir     {
748cdf0e10cSrcweir         if (handle == 0)
749cdf0e10cSrcweir             handle = get_static_bootstrap_handle();
750cdf0e10cSrcweir         found = static_cast< Bootstrap_Impl * >( handle )->getValue(
751cdf0e10cSrcweir             pName, ppValue, pDefault, LOOKUP_MODE_NORMAL, false, NULL );
752cdf0e10cSrcweir     }
753cdf0e10cSrcweir 
754cdf0e10cSrcweir     return found;
755cdf0e10cSrcweir }
756cdf0e10cSrcweir 
757cdf0e10cSrcweir //----------------------------------------------------------------------------
758cdf0e10cSrcweir 
759cdf0e10cSrcweir void SAL_CALL rtl_bootstrap_get_iniName_from_handle (
760cdf0e10cSrcweir     rtlBootstrapHandle handle,
761cdf0e10cSrcweir     rtl_uString     ** ppIniName
762cdf0e10cSrcweir ) SAL_THROW_EXTERN_C()
763cdf0e10cSrcweir {
764cdf0e10cSrcweir     if(ppIniName)
765cdf0e10cSrcweir     {
766cdf0e10cSrcweir         if(handle)
767cdf0e10cSrcweir         {
768cdf0e10cSrcweir             Bootstrap_Impl * pImpl = static_cast<Bootstrap_Impl*>(handle);
769cdf0e10cSrcweir             rtl_uString_assign(ppIniName, pImpl->_iniName.pData);
770cdf0e10cSrcweir         }
771cdf0e10cSrcweir         else
772cdf0e10cSrcweir         {
773cdf0e10cSrcweir             const OUString & iniName = getIniFileName_Impl();
774cdf0e10cSrcweir             rtl_uString_assign(ppIniName, iniName.pData);
775cdf0e10cSrcweir         }
776cdf0e10cSrcweir     }
777cdf0e10cSrcweir }
778cdf0e10cSrcweir 
779cdf0e10cSrcweir //----------------------------------------------------------------------------
780cdf0e10cSrcweir 
781cdf0e10cSrcweir void SAL_CALL rtl_bootstrap_setIniFileName (
782cdf0e10cSrcweir     rtl_uString * pName
783cdf0e10cSrcweir ) SAL_THROW_EXTERN_C()
784cdf0e10cSrcweir {
785cdf0e10cSrcweir     osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
786cdf0e10cSrcweir     OUString & file = getIniFileName_Impl();
787cdf0e10cSrcweir     file = pName;
788cdf0e10cSrcweir }
789cdf0e10cSrcweir 
790cdf0e10cSrcweir //----------------------------------------------------------------------------
791cdf0e10cSrcweir 
792cdf0e10cSrcweir sal_Bool SAL_CALL rtl_bootstrap_get (
793cdf0e10cSrcweir     rtl_uString  * pName,
794cdf0e10cSrcweir     rtl_uString ** ppValue,
795cdf0e10cSrcweir     rtl_uString  * pDefault
796cdf0e10cSrcweir ) SAL_THROW_EXTERN_C()
797cdf0e10cSrcweir {
798cdf0e10cSrcweir     return rtl_bootstrap_get_from_handle(0, pName, ppValue, pDefault);
799cdf0e10cSrcweir }
800cdf0e10cSrcweir 
801cdf0e10cSrcweir //----------------------------------------------------------------------------
802cdf0e10cSrcweir 
803cdf0e10cSrcweir void SAL_CALL rtl_bootstrap_set (
804cdf0e10cSrcweir     rtl_uString * pName,
805cdf0e10cSrcweir     rtl_uString * pValue
806cdf0e10cSrcweir ) SAL_THROW_EXTERN_C()
807cdf0e10cSrcweir {
808cdf0e10cSrcweir     const OUString name( pName );
809cdf0e10cSrcweir     const OUString value( pValue );
810cdf0e10cSrcweir 
811cdf0e10cSrcweir     osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
812cdf0e10cSrcweir 
813cdf0e10cSrcweir     NameValueList& r_rtl_bootstrap_set_list = rtl_bootstrap_set_list::get();
814cdf0e10cSrcweir     NameValueList::iterator iPos( r_rtl_bootstrap_set_list.begin() );
815cdf0e10cSrcweir     NameValueList::iterator iEnd( r_rtl_bootstrap_set_list.end() );
816cdf0e10cSrcweir     for ( ; iPos != iEnd; ++iPos )
817cdf0e10cSrcweir     {
818cdf0e10cSrcweir         if (iPos->sName.equals( name ))
819cdf0e10cSrcweir         {
820cdf0e10cSrcweir             iPos->sValue = value;
821cdf0e10cSrcweir             return;
822cdf0e10cSrcweir         }
823cdf0e10cSrcweir     }
824cdf0e10cSrcweir 
825cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
826cdf0e10cSrcweir     OString cstr_name( OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ) );
827cdf0e10cSrcweir     OString cstr_value( OUStringToOString( value, RTL_TEXTENCODING_ASCII_US ) );
828cdf0e10cSrcweir     OSL_TRACE(
829cdf0e10cSrcweir         "bootstrap.cxx: explicitly setting: name=%s value=%s\n",
830cdf0e10cSrcweir         cstr_name.getStr(), cstr_value.getStr() );
831cdf0e10cSrcweir #endif /* OSL_DEBUG_LEVEL > 1 */
832cdf0e10cSrcweir 
833cdf0e10cSrcweir     r_rtl_bootstrap_set_list.push_back( rtl_bootstrap_NameValue( name, value ) );
834cdf0e10cSrcweir }
835cdf0e10cSrcweir 
836cdf0e10cSrcweir //----------------------------------------------------------------------------
837cdf0e10cSrcweir 
838cdf0e10cSrcweir void SAL_CALL rtl_bootstrap_expandMacros_from_handle (
839cdf0e10cSrcweir     rtlBootstrapHandle handle,
840cdf0e10cSrcweir     rtl_uString     ** macro
841cdf0e10cSrcweir ) SAL_THROW_EXTERN_C()
842cdf0e10cSrcweir {
843cdf0e10cSrcweir     if (handle == NULL) {
844cdf0e10cSrcweir         handle = get_static_bootstrap_handle();
845cdf0e10cSrcweir     }
846cdf0e10cSrcweir     OUString expanded( expandMacros( static_cast< Bootstrap_Impl * >( handle ),
847cdf0e10cSrcweir                                      * reinterpret_cast< OUString const * >( macro ),
848cdf0e10cSrcweir                                      LOOKUP_MODE_NORMAL, NULL ) );
849cdf0e10cSrcweir     rtl_uString_assign( macro, expanded.pData );
850cdf0e10cSrcweir }
851cdf0e10cSrcweir 
852cdf0e10cSrcweir //----------------------------------------------------------------------------
853cdf0e10cSrcweir 
854cdf0e10cSrcweir void SAL_CALL rtl_bootstrap_expandMacros(
855cdf0e10cSrcweir     rtl_uString ** macro )
856cdf0e10cSrcweir     SAL_THROW_EXTERN_C()
857cdf0e10cSrcweir {
858cdf0e10cSrcweir     rtl_bootstrap_expandMacros_from_handle(NULL, macro);
859cdf0e10cSrcweir }
860cdf0e10cSrcweir 
861cdf0e10cSrcweir void rtl_bootstrap_encode( rtl_uString const * value, rtl_uString ** encoded )
862cdf0e10cSrcweir     SAL_THROW_EXTERN_C()
863cdf0e10cSrcweir {
864cdf0e10cSrcweir     OSL_ASSERT(value != NULL);
865cdf0e10cSrcweir     rtl::OUStringBuffer b;
866cdf0e10cSrcweir     for (sal_Int32 i = 0; i < value->length; ++i) {
867cdf0e10cSrcweir         sal_Unicode c = value->buffer[i];
868cdf0e10cSrcweir         if (c == '$' || c == '\\') {
869cdf0e10cSrcweir             b.append(sal_Unicode('\\'));
870cdf0e10cSrcweir         }
871cdf0e10cSrcweir         b.append(c);
872cdf0e10cSrcweir     }
873cdf0e10cSrcweir     rtl_uString_assign(encoded, b.makeStringAndClear().pData);
874cdf0e10cSrcweir }
875cdf0e10cSrcweir 
876cdf0e10cSrcweir namespace {
877cdf0e10cSrcweir 
878cdf0e10cSrcweir int hex(sal_Unicode c) {
879cdf0e10cSrcweir     return
880cdf0e10cSrcweir         c >= '0' && c <= '9' ? c - '0' :
881cdf0e10cSrcweir         c >= 'A' && c <= 'F' ? c - 'A' + 10 :
882cdf0e10cSrcweir         c >= 'a' && c <= 'f' ? c - 'a' + 10 : -1;
883cdf0e10cSrcweir }
884cdf0e10cSrcweir 
885cdf0e10cSrcweir sal_Unicode read(rtl::OUString const & text, sal_Int32 * pos, bool * escaped) {
886cdf0e10cSrcweir     OSL_ASSERT(
887cdf0e10cSrcweir         pos != NULL && *pos >= 0 && *pos < text.getLength() && escaped != NULL);
888cdf0e10cSrcweir     sal_Unicode c = text[(*pos)++];
889cdf0e10cSrcweir     if (c == '\\') {
890cdf0e10cSrcweir         int n1, n2, n3, n4;
891cdf0e10cSrcweir         if (*pos < text.getLength() - 4 && text[*pos] == 'u' &&
892cdf0e10cSrcweir             ((n1 = hex(text[*pos + 1])) >= 0) &&
893cdf0e10cSrcweir             ((n2 = hex(text[*pos + 2])) >= 0) &&
894cdf0e10cSrcweir             ((n3 = hex(text[*pos + 3])) >= 0) &&
895cdf0e10cSrcweir             ((n4 = hex(text[*pos + 4])) >= 0))
896cdf0e10cSrcweir         {
897cdf0e10cSrcweir             *pos += 5;
898cdf0e10cSrcweir             *escaped = true;
899cdf0e10cSrcweir             return static_cast< sal_Unicode >(
900cdf0e10cSrcweir                 (n1 << 12) | (n2 << 8) | (n3 << 4) | n4);
901cdf0e10cSrcweir         } else if (*pos < text.getLength()) {
902cdf0e10cSrcweir             *escaped = true;
903cdf0e10cSrcweir             return text[(*pos)++];
904cdf0e10cSrcweir         }
905cdf0e10cSrcweir     }
906cdf0e10cSrcweir     *escaped = false;
907cdf0e10cSrcweir     return c;
908cdf0e10cSrcweir }
909cdf0e10cSrcweir 
910cdf0e10cSrcweir rtl::OUString lookup(
911cdf0e10cSrcweir     Bootstrap_Impl const * file, LookupMode mode, bool override,
912cdf0e10cSrcweir     rtl::OUString const & key, ExpandRequestLink const * requestStack)
913cdf0e10cSrcweir {
914cdf0e10cSrcweir     rtl::OUString v;
915cdf0e10cSrcweir     (file == NULL ? get_static_bootstrap_handle() : file)->getValue(
916cdf0e10cSrcweir         key, &v.pData, NULL, mode, override, requestStack);
917cdf0e10cSrcweir     return v;
918cdf0e10cSrcweir }
919cdf0e10cSrcweir 
920cdf0e10cSrcweir rtl::OUString expandMacros(
921cdf0e10cSrcweir     Bootstrap_Impl const * file, rtl::OUString const & text, LookupMode mode,
922cdf0e10cSrcweir     ExpandRequestLink const * requestStack)
923cdf0e10cSrcweir {
924cdf0e10cSrcweir     rtl::OUStringBuffer buf;
925cdf0e10cSrcweir     for (sal_Int32 i = 0; i < text.getLength();) {
926cdf0e10cSrcweir         bool escaped;
927cdf0e10cSrcweir         sal_Unicode c = read(text, &i, &escaped);
928cdf0e10cSrcweir         if (escaped || c != '$') {
929cdf0e10cSrcweir             buf.append(c);
930cdf0e10cSrcweir         } else {
931cdf0e10cSrcweir             if (i < text.getLength() && text[i] == '{') {
932cdf0e10cSrcweir                 ++i;
933cdf0e10cSrcweir                 sal_Int32 p = i;
934cdf0e10cSrcweir                 sal_Int32 nesting = 0;
935cdf0e10cSrcweir                 rtl::OUString seg[3];
936cdf0e10cSrcweir                 int n = 0;
937cdf0e10cSrcweir                 while (i < text.getLength()) {
938cdf0e10cSrcweir                     sal_Int32 j = i;
939cdf0e10cSrcweir                     c = read(text, &i, &escaped);
940cdf0e10cSrcweir                     if (!escaped) {
941cdf0e10cSrcweir                         switch (c) {
942cdf0e10cSrcweir                         case '{':
943cdf0e10cSrcweir                             ++nesting;
944cdf0e10cSrcweir                             break;
945cdf0e10cSrcweir                         case '}':
946cdf0e10cSrcweir                             if (nesting == 0) {
947cdf0e10cSrcweir                                 seg[n++] = text.copy(p, j - p);
948cdf0e10cSrcweir                                 goto done;
949cdf0e10cSrcweir                             } else {
950cdf0e10cSrcweir                                 --nesting;
951cdf0e10cSrcweir                             }
952cdf0e10cSrcweir                             break;
953cdf0e10cSrcweir                         case ':':
954cdf0e10cSrcweir                             if (nesting == 0 && n < 2) {
955cdf0e10cSrcweir                                 seg[n++] = text.copy(p, j - p);
956cdf0e10cSrcweir                                 p = i;
957cdf0e10cSrcweir                             }
958cdf0e10cSrcweir                             break;
959cdf0e10cSrcweir                         }
960cdf0e10cSrcweir                     }
961cdf0e10cSrcweir                 }
962cdf0e10cSrcweir             done:
963cdf0e10cSrcweir                 for (int j = 0; j < n; ++j) {
964cdf0e10cSrcweir                     seg[j] = expandMacros(file, seg[j], mode, requestStack);
965cdf0e10cSrcweir                 }
966cdf0e10cSrcweir                 if (n == 3 && seg[1].getLength() == 0) {
967cdf0e10cSrcweir                     // For backward compatibility, treat ${file::key} the same
968cdf0e10cSrcweir                     // as just ${file:key}:
969cdf0e10cSrcweir                     seg[1] = seg[2];
970cdf0e10cSrcweir                     n = 2;
971cdf0e10cSrcweir                 }
972cdf0e10cSrcweir                 if (n == 1) {
973cdf0e10cSrcweir                     buf.append(lookup(file, mode, false, seg[0], requestStack));
974cdf0e10cSrcweir                 } else if (n == 2) {
975cdf0e10cSrcweir                     if (seg[0].equalsAsciiL(
976cdf0e10cSrcweir                             RTL_CONSTASCII_STRINGPARAM(".link")))
977cdf0e10cSrcweir                     {
978cdf0e10cSrcweir                         osl::File f(seg[1]);
979cdf0e10cSrcweir                         rtl::ByteSequence seq;
980cdf0e10cSrcweir                         rtl::OUString line;
981cdf0e10cSrcweir                         rtl::OUString url;
982cdf0e10cSrcweir                         // Silently ignore any errors (is that good?):
983cdf0e10cSrcweir                         if (f.open(OpenFlag_Read) == osl::FileBase::E_None &&
984cdf0e10cSrcweir                             f.readLine(seq) == osl::FileBase::E_None &&
985cdf0e10cSrcweir                             rtl_convertStringToUString(
986cdf0e10cSrcweir                                 &line.pData,
987cdf0e10cSrcweir                                 reinterpret_cast< char const * >(
988cdf0e10cSrcweir                                     seq.getConstArray()),
989cdf0e10cSrcweir                                 seq.getLength(), RTL_TEXTENCODING_UTF8,
990cdf0e10cSrcweir                                 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
991cdf0e10cSrcweir                                  RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
992cdf0e10cSrcweir                                  RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)) &&
993cdf0e10cSrcweir                             (osl::File::getFileURLFromSystemPath(line, url) ==
994cdf0e10cSrcweir                              osl::FileBase::E_None))
995cdf0e10cSrcweir                         {
996cdf0e10cSrcweir                             try {
997cdf0e10cSrcweir                                 buf.append(
998cdf0e10cSrcweir                                     rtl::Uri::convertRelToAbs(seg[1], url));
999cdf0e10cSrcweir                             } catch (rtl::MalformedUriException &) {}
1000cdf0e10cSrcweir                         }
1001cdf0e10cSrcweir                     } else {
1002cdf0e10cSrcweir                         buf.append(
1003cdf0e10cSrcweir                             lookup(
1004cdf0e10cSrcweir                                 static_cast< Bootstrap_Impl * >(
1005cdf0e10cSrcweir                                     rtl::Bootstrap(seg[0]).getHandle()),
1006cdf0e10cSrcweir                                 mode, false, seg[1], requestStack));
1007cdf0e10cSrcweir                     }
1008cdf0e10cSrcweir                 } else if (seg[0].equalsAsciiL(
1009cdf0e10cSrcweir                                RTL_CONSTASCII_STRINGPARAM(".override")))
1010cdf0e10cSrcweir                 {
1011cdf0e10cSrcweir                     rtl::Bootstrap b(seg[1]);
1012cdf0e10cSrcweir                     Bootstrap_Impl * f = static_cast< Bootstrap_Impl * >(
1013cdf0e10cSrcweir                         b.getHandle());
1014cdf0e10cSrcweir                     buf.append(
1015cdf0e10cSrcweir                         lookup(f, mode, f != NULL, seg[2], requestStack));
1016cdf0e10cSrcweir                 } else {
1017cdf0e10cSrcweir                     // Going through osl::Profile, this code erroneously does
1018cdf0e10cSrcweir                     // not recursively expand macros in the resulting
1019cdf0e10cSrcweir                     // replacement text (and if it did, it would fail to detect
1020cdf0e10cSrcweir                     // cycles that pass through here):
1021cdf0e10cSrcweir                     buf.append(
1022cdf0e10cSrcweir                         rtl::OStringToOUString(
1023cdf0e10cSrcweir                             osl::Profile(seg[0]).readString(
1024cdf0e10cSrcweir                                 rtl::OUStringToOString(
1025cdf0e10cSrcweir                                     seg[1], RTL_TEXTENCODING_UTF8),
1026cdf0e10cSrcweir                                 rtl::OUStringToOString(
1027cdf0e10cSrcweir                                     seg[2], RTL_TEXTENCODING_UTF8),
1028cdf0e10cSrcweir                                 rtl::OString()),
1029cdf0e10cSrcweir                             RTL_TEXTENCODING_UTF8));
1030cdf0e10cSrcweir                 }
1031cdf0e10cSrcweir             } else {
1032cdf0e10cSrcweir                 rtl::OUStringBuffer kbuf;
1033cdf0e10cSrcweir                 for (; i < text.getLength();) {
1034cdf0e10cSrcweir                     sal_Int32 j = i;
1035cdf0e10cSrcweir                     c = read(text, &j, &escaped);
1036cdf0e10cSrcweir                     if (!escaped &&
1037cdf0e10cSrcweir                         (c == ' ' || c == '$' || c == '-' || c == '/' ||
1038cdf0e10cSrcweir                          c == ';' || c == '\\'))
1039cdf0e10cSrcweir                     {
1040cdf0e10cSrcweir                         break;
1041cdf0e10cSrcweir                     }
1042cdf0e10cSrcweir                     kbuf.append(c);
1043cdf0e10cSrcweir                     i = j;
1044cdf0e10cSrcweir                 }
1045cdf0e10cSrcweir                 buf.append(
1046cdf0e10cSrcweir                     lookup(
1047cdf0e10cSrcweir                         file, mode, false, kbuf.makeStringAndClear(),
1048cdf0e10cSrcweir                         requestStack));
1049cdf0e10cSrcweir             }
1050cdf0e10cSrcweir         }
1051cdf0e10cSrcweir     }
1052cdf0e10cSrcweir     return buf.makeStringAndClear();
1053cdf0e10cSrcweir }
1054cdf0e10cSrcweir 
1055cdf0e10cSrcweir }
1056