xref: /trunk/main/scripting/source/stringresource/stringresource.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_scripting.hxx"
30 #include "stringresource.hxx"
31 #include <com/sun/star/io/XTextInputStream.hpp>
32 #include <com/sun/star/io/XTextOutputStream.hpp>
33 #include <com/sun/star/io/XActiveDataSink.hpp>
34 #include <com/sun/star/io/XActiveDataSource.hpp>
35 #include <com/sun/star/io/XStream.hpp>
36 #include <com/sun/star/io/XSeekable.hpp>
37 #include <com/sun/star/embed/ElementModes.hpp>
38 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
39 #ifndef _CPPUHELPER_IMPLEMENTATIONENTRY_HXX_
40 #include <cppuhelper/implementationentry.hxx>
41 #endif
42 #include <com/sun/star/beans/XPropertySet.hpp>
43 #include <com/sun/star/container/XNameAccess.hpp>
44 
45 
46 #include <rtl/ustrbuf.hxx>
47 #include <rtl/strbuf.hxx>
48 #include <tools/urlobj.hxx>
49 
50 using namespace ::com::sun::star;
51 using namespace ::com::sun::star::lang;
52 using namespace ::com::sun::star::uno;
53 using namespace ::com::sun::star::ucb;
54 using namespace ::com::sun::star::util;
55 using namespace ::com::sun::star::embed;
56 using namespace ::com::sun::star::container;
57 
58 
59 //.........................................................................
60 namespace stringresource
61 {
62 //.........................................................................
63 
64 // =============================================================================
65 // mutex
66 // =============================================================================
67 
68 ::osl::Mutex& getMutex()
69 {
70     static ::osl::Mutex* s_pMutex = 0;
71     if ( !s_pMutex )
72     {
73         ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
74         if ( !s_pMutex )
75         {
76             static ::osl::Mutex s_aMutex;
77             s_pMutex = &s_aMutex;
78         }
79     }
80     return *s_pMutex;
81 }
82 
83 
84 // =============================================================================
85 // StringResourceImpl
86 // =============================================================================
87 
88 // component operations
89 static Sequence< ::rtl::OUString > getSupportedServiceNames_StringResourceImpl()
90 {
91     Sequence< ::rtl::OUString > names(1);
92     names[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.resource.StringResource") );
93     return names;
94 }
95 
96 static ::rtl::OUString getImplementationName_StringResourceImpl()
97 {
98     return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.scripting.StringResource") );
99 }
100 
101 static Reference< XInterface > SAL_CALL create_StringResourceImpl(
102     Reference< XComponentContext > const & xContext )
103     SAL_THROW( () )
104 {
105     return static_cast< ::cppu::OWeakObject * >( new StringResourcePersistenceImpl( xContext ) );
106 }
107 
108 
109 // =============================================================================
110 
111 StringResourceImpl::StringResourceImpl( const Reference< XComponentContext >& rxContext )
112     : m_xContext( rxContext )
113     , m_pCurrentLocaleItem( NULL )
114     , m_pDefaultLocaleItem( NULL )
115     , m_bDefaultModified( false )
116     , m_aListenerContainer( getMutex() )
117     , m_bModified( false )
118     , m_bReadOnly( false )
119     , m_nNextUniqueNumericId( UNIQUE_NUMBER_NEEDS_INITIALISATION )
120 {
121 }
122 
123 // =============================================================================
124 
125 StringResourceImpl::~StringResourceImpl()
126 {
127     for( LocaleItemVectorIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
128     {
129         LocaleItem* pLocaleItem = *it;
130         delete pLocaleItem;
131     }
132 
133     for( LocaleItemVectorIt it = m_aDeletedLocaleItemVector.begin(); it != m_aDeletedLocaleItemVector.end(); it++ )
134     {
135         LocaleItem* pLocaleItem = *it;
136         delete pLocaleItem;
137     }
138 }
139 
140 
141 // =============================================================================
142 // XServiceInfo
143 
144 ::rtl::OUString StringResourceImpl::getImplementationName(  ) throw (RuntimeException)
145 {
146     return getImplementationName_StringResourceImpl();
147 }
148 
149 sal_Bool StringResourceImpl::supportsService( const ::rtl::OUString& rServiceName ) throw (RuntimeException)
150 {
151     Sequence< ::rtl::OUString > aNames( getSupportedServiceNames() );
152     const ::rtl::OUString* pNames = aNames.getConstArray();
153     const ::rtl::OUString* pEnd = pNames + aNames.getLength();
154     for ( ; pNames != pEnd && !pNames->equals( rServiceName ); ++pNames )
155         ;
156 
157     return pNames != pEnd;
158 }
159 
160 Sequence< ::rtl::OUString > StringResourceImpl::getSupportedServiceNames(  ) throw (RuntimeException)
161 {
162     return getSupportedServiceNames_StringResourceImpl();
163 }
164 
165 
166 // =============================================================================
167 // XModifyBroadcaster
168 
169 void StringResourceImpl::addModifyListener( const Reference< XModifyListener >& aListener )
170     throw (RuntimeException)
171 {
172     if( !aListener.is() )
173         throw RuntimeException();
174 
175     ::osl::MutexGuard aGuard( getMutex() );
176     Reference< XInterface > xIface( aListener, UNO_QUERY );
177     m_aListenerContainer.addInterface( xIface );
178 }
179 
180 void StringResourceImpl::removeModifyListener( const Reference< XModifyListener >& aListener )
181     throw (RuntimeException)
182 {
183     if( !aListener.is() )
184         throw RuntimeException();
185 
186     ::osl::MutexGuard aGuard( getMutex() );
187     Reference< XInterface > xIface( aListener, UNO_QUERY );
188     m_aListenerContainer.removeInterface( xIface );
189 }
190 
191 
192 // =============================================================================
193 // XStringResourceResolver
194 
195 ::rtl::OUString StringResourceImpl::implResolveString
196     ( const ::rtl::OUString& ResourceID, LocaleItem* pLocaleItem )
197         throw (::com::sun::star::resource::MissingResourceException)
198 {
199     ::rtl::OUString aRetStr;
200     bool bSuccess = false;
201     if( pLocaleItem != NULL && loadLocale( pLocaleItem ) )
202     {
203         IdToStringMap::iterator it = pLocaleItem->m_aIdToStringMap.find( ResourceID );
204         if( !( it == pLocaleItem->m_aIdToStringMap.end() ) )
205         {
206             aRetStr = (*it).second;
207             bSuccess = true;
208         }
209     }
210     if( !bSuccess )
211     {
212         ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceImpl: No entry for ResourceID: " );
213         errorMsg.concat( ResourceID );
214         throw ::com::sun::star::resource::MissingResourceException( errorMsg, Reference< XInterface >() );
215     }
216     return aRetStr;
217 }
218 
219 ::rtl::OUString StringResourceImpl::resolveString( const ::rtl::OUString& ResourceID )
220     throw (::com::sun::star::resource::MissingResourceException, RuntimeException)
221 {
222     ::osl::MutexGuard aGuard( getMutex() );
223     return implResolveString( ResourceID, m_pCurrentLocaleItem );
224 }
225 
226 ::rtl::OUString StringResourceImpl::resolveStringForLocale( const ::rtl::OUString& ResourceID, const Locale& locale )
227     throw ( ::com::sun::star::resource::MissingResourceException, RuntimeException)
228 {
229     ::osl::MutexGuard aGuard( getMutex() );
230     LocaleItem* pLocaleItem = getItemForLocale( locale, false );
231     return implResolveString( ResourceID, pLocaleItem );
232 }
233 
234 sal_Bool StringResourceImpl::implHasEntryForId( const ::rtl::OUString& ResourceID, LocaleItem* pLocaleItem )
235 {
236     bool bSuccess = false;
237     if( pLocaleItem != NULL && loadLocale( pLocaleItem ) )
238     {
239         IdToStringMap::iterator it = pLocaleItem->m_aIdToStringMap.find( ResourceID );
240         if( !( it == pLocaleItem->m_aIdToStringMap.end() ) )
241             bSuccess = true;
242     }
243     return bSuccess;
244 }
245 
246 sal_Bool StringResourceImpl::hasEntryForId( const ::rtl::OUString& ResourceID )
247     throw (RuntimeException)
248 {
249     ::osl::MutexGuard aGuard( getMutex() );
250     return implHasEntryForId( ResourceID, m_pCurrentLocaleItem );
251 }
252 
253 sal_Bool StringResourceImpl::hasEntryForIdAndLocale( const ::rtl::OUString& ResourceID,
254     const Locale& locale )
255         throw (RuntimeException)
256 {
257     ::osl::MutexGuard aGuard( getMutex() );
258     LocaleItem* pLocaleItem = getItemForLocale( locale, false );
259     return implHasEntryForId( ResourceID, pLocaleItem );
260 }
261 
262 Sequence< ::rtl::OUString > StringResourceImpl::implGetResourceIDs( LocaleItem* pLocaleItem )
263 {
264     Sequence< ::rtl::OUString > aIDSeq( 0 );
265     if( pLocaleItem && loadLocale( pLocaleItem ) )
266     {
267         const IdToStringMap& rHashMap = pLocaleItem->m_aIdToStringMap;
268         sal_Int32 nResourceIDCount = rHashMap.size();
269         aIDSeq.realloc( nResourceIDCount );
270         ::rtl::OUString* pStrings = aIDSeq.getArray();
271 
272         IdToStringMap::const_iterator it;
273         int iTarget = 0;
274         for( it = rHashMap.begin(); it != rHashMap.end(); it++ )
275         {
276             ::rtl::OUString aStr = (*it).first;
277             pStrings[iTarget] = aStr;
278             iTarget++;
279         }
280     }
281     return aIDSeq;
282 }
283 
284 Sequence< ::rtl::OUString > StringResourceImpl::getResourceIDsForLocale
285     ( const Locale& locale ) throw (::com::sun::star::uno::RuntimeException)
286 {
287     ::osl::MutexGuard aGuard( getMutex() );
288     LocaleItem* pLocaleItem = getItemForLocale( locale, false );
289     return implGetResourceIDs( pLocaleItem );
290 }
291 
292 Sequence< ::rtl::OUString > StringResourceImpl::getResourceIDs(  )
293     throw (RuntimeException)
294 {
295     ::osl::MutexGuard aGuard( getMutex() );
296     return implGetResourceIDs( m_pCurrentLocaleItem );
297 }
298 
299 Locale StringResourceImpl::getCurrentLocale()
300     throw (RuntimeException)
301 {
302     ::osl::MutexGuard aGuard( getMutex() );
303 
304     Locale aRetLocale;
305     if( m_pCurrentLocaleItem != NULL )
306         aRetLocale = m_pCurrentLocaleItem->m_locale;
307     return aRetLocale;
308 }
309 
310 Locale StringResourceImpl::getDefaultLocale(  )
311     throw (RuntimeException)
312 {
313     ::osl::MutexGuard aGuard( getMutex() );
314 
315     Locale aRetLocale;
316     if( m_pDefaultLocaleItem != NULL )
317         aRetLocale = m_pDefaultLocaleItem->m_locale;
318     return aRetLocale;
319 }
320 
321 Sequence< Locale > StringResourceImpl::getLocales(  )
322     throw (RuntimeException)
323 {
324     ::osl::MutexGuard aGuard( getMutex() );
325 
326     sal_Int32 nSize = m_aLocaleItemVector.size();
327     Sequence< Locale > aLocalSeq( nSize );
328     Locale* pLocales = aLocalSeq.getArray();
329     int iTarget = 0;
330     for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
331     {
332         LocaleItem* pLocaleItem = *it;
333         pLocales[iTarget] = pLocaleItem->m_locale;
334         iTarget++;
335     }
336     return aLocalSeq;
337 }
338 
339 
340 // =============================================================================
341 // XStringResourceManager
342 
343 void StringResourceImpl::implCheckReadOnly( const sal_Char* pExceptionMsg )
344     throw (NoSupportException)
345 {
346     if( m_bReadOnly )
347     {
348         ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( pExceptionMsg );
349         throw NoSupportException( errorMsg, Reference< XInterface >() );
350     }
351 }
352 
353 sal_Bool StringResourceImpl::isReadOnly()
354     throw (RuntimeException)
355 {
356     return m_bReadOnly;
357 }
358 
359 void StringResourceImpl::implSetCurrentLocale( const Locale& locale,
360     sal_Bool FindClosestMatch, sal_Bool bUseDefaultIfNoMatch )
361         throw (IllegalArgumentException, RuntimeException)
362 {
363     ::osl::MutexGuard aGuard( getMutex() );
364 
365     LocaleItem* pLocaleItem = NULL;
366     if( FindClosestMatch )
367         pLocaleItem = getClosestMatchItemForLocale( locale );
368     else
369         pLocaleItem = getItemForLocale( locale, true );
370 
371     if( pLocaleItem == NULL && bUseDefaultIfNoMatch )
372         pLocaleItem = m_pDefaultLocaleItem;
373 
374     if( pLocaleItem != NULL )
375     {
376         loadLocale( pLocaleItem );
377         m_pCurrentLocaleItem = pLocaleItem;
378 
379         // Only notify without modifying
380         implNotifyListeners();
381     }
382 }
383 
384 void StringResourceImpl::setCurrentLocale( const Locale& locale, sal_Bool FindClosestMatch )
385     throw (IllegalArgumentException, RuntimeException)
386 {
387     sal_Bool bUseDefaultIfNoMatch = false;
388     implSetCurrentLocale( locale, FindClosestMatch, bUseDefaultIfNoMatch );
389 }
390 
391 void StringResourceImpl::setDefaultLocale( const Locale& locale )
392     throw (IllegalArgumentException, RuntimeException,NoSupportException)
393 {
394     ::osl::MutexGuard aGuard( getMutex() );
395     implCheckReadOnly( "StringResourceImpl::setDefaultLocale(): Read only" );
396 
397     LocaleItem* pLocaleItem = getItemForLocale( locale, true );
398     if( pLocaleItem && pLocaleItem != m_pDefaultLocaleItem )
399     {
400         if( m_pDefaultLocaleItem )
401         {
402             LocaleItem* pChangedDefaultLocaleItem = new LocaleItem( m_pDefaultLocaleItem->m_locale );
403             m_aChangedDefaultLocaleVector.push_back( pChangedDefaultLocaleItem );
404         }
405 
406         m_pDefaultLocaleItem = pLocaleItem;
407         m_bDefaultModified = true;
408         implModified();
409     }
410 }
411 
412 void StringResourceImpl::implSetString( const ::rtl::OUString& ResourceID,
413     const ::rtl::OUString& Str, LocaleItem* pLocaleItem )
414 {
415     if( pLocaleItem != NULL && loadLocale( pLocaleItem ) )
416     {
417         IdToStringMap& rHashMap = pLocaleItem->m_aIdToStringMap;
418 
419         IdToStringMap::iterator it = rHashMap.find( ResourceID );
420         bool bNew = ( it == rHashMap.end() );
421         if( bNew )
422         {
423             IdToIndexMap& rIndexMap = pLocaleItem->m_aIdToIndexMap;
424             rIndexMap[ ResourceID ] = pLocaleItem->m_nNextIndex++;
425             implScanIdForNumber( ResourceID );
426         }
427         rHashMap[ ResourceID ] = Str;
428         pLocaleItem->m_bModified = true;
429         implModified();
430     }
431 }
432 
433 void StringResourceImpl::setString( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str )
434     throw (NoSupportException, RuntimeException)
435 {
436     ::osl::MutexGuard aGuard( getMutex() );
437     implCheckReadOnly( "StringResourceImpl::setString(): Read only" );
438     implSetString( ResourceID, Str, m_pCurrentLocaleItem );
439 }
440 
441 void StringResourceImpl::setStringForLocale
442     ( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str, const Locale& locale )
443         throw (NoSupportException, RuntimeException)
444 {
445     ::osl::MutexGuard aGuard( getMutex() );
446     implCheckReadOnly( "StringResourceImpl::setStringForLocale(): Read only" );
447     LocaleItem* pLocaleItem = getItemForLocale( locale, false );
448     implSetString( ResourceID, Str, pLocaleItem );
449 }
450 
451 void StringResourceImpl::implRemoveId( const ::rtl::OUString& ResourceID, LocaleItem* pLocaleItem )
452     throw (::com::sun::star::resource::MissingResourceException)
453 {
454     if( pLocaleItem != NULL && loadLocale( pLocaleItem ) )
455     {
456         IdToStringMap& rHashMap = pLocaleItem->m_aIdToStringMap;
457         IdToStringMap::iterator it = rHashMap.find( ResourceID );
458         if( it == rHashMap.end() )
459         {
460             ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceImpl: No entries for ResourceID: " );
461             errorMsg.concat( ResourceID );
462             throw ::com::sun::star::resource::MissingResourceException( errorMsg, Reference< XInterface >() );
463         }
464         rHashMap.erase( it );
465         pLocaleItem->m_bModified = true;
466         implModified();
467     }
468 }
469 
470 void StringResourceImpl::removeId( const ::rtl::OUString& ResourceID )
471     throw (::com::sun::star::resource::MissingResourceException, RuntimeException, NoSupportException)
472 {
473     ::osl::MutexGuard aGuard( getMutex() );
474     implCheckReadOnly( "StringResourceImpl::removeId(): Read only" );
475     implRemoveId( ResourceID, m_pCurrentLocaleItem );
476 }
477 
478 void StringResourceImpl::removeIdForLocale( const ::rtl::OUString& ResourceID, const Locale& locale )
479     throw (::com::sun::star::resource::MissingResourceException, RuntimeException, NoSupportException)
480 {
481     ::osl::MutexGuard aGuard( getMutex() );
482     implCheckReadOnly( "StringResourceImpl::removeIdForLocale(): Read only" );
483     LocaleItem* pLocaleItem = getItemForLocale( locale, false );
484     implRemoveId( ResourceID, pLocaleItem );
485 }
486 
487 void StringResourceImpl::newLocale( const Locale& locale )
488     throw (ElementExistException, IllegalArgumentException, RuntimeException, NoSupportException)
489 {
490     ::osl::MutexGuard aGuard( getMutex() );
491     implCheckReadOnly( "StringResourceImpl::newLocale(): Read only" );
492 
493     if( getItemForLocale( locale, false ) != NULL )
494     {
495         ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceImpl: locale already exists" );
496         throw ElementExistException( errorMsg, Reference< XInterface >() );
497     }
498 
499     // TODO?: Check if locale is valid? How?
500     bool bValid = true;
501     if( bValid )
502     {
503         LocaleItem* pLocaleItem = new LocaleItem( locale );
504         m_aLocaleItemVector.push_back( pLocaleItem );
505         pLocaleItem->m_bModified = true;
506 
507         // Copy strings from default locale
508         LocaleItem* pCopyFromItem = m_pDefaultLocaleItem;
509         if( pCopyFromItem == NULL )
510             pCopyFromItem = m_pCurrentLocaleItem;
511         if( pCopyFromItem != NULL && loadLocale( pCopyFromItem ) )
512         {
513             const IdToStringMap& rSourceMap = pCopyFromItem->m_aIdToStringMap;
514             IdToStringMap& rTargetMap = pLocaleItem->m_aIdToStringMap;
515             IdToStringMap::const_iterator it;
516             for( it = rSourceMap.begin(); it != rSourceMap.end(); it++ )
517             {
518                 ::rtl::OUString aId  = (*it).first;
519                 ::rtl::OUString aStr = (*it).second;
520                 rTargetMap[ aId ] = aStr;
521             }
522 
523             const IdToIndexMap& rSourceIndexMap = pCopyFromItem->m_aIdToIndexMap;
524             IdToIndexMap& rTargetIndexMap = pLocaleItem->m_aIdToIndexMap;
525             IdToIndexMap::const_iterator it_index;
526             for( it_index = rSourceIndexMap.begin(); it_index != rSourceIndexMap.end(); it_index++ )
527             {
528                 ::rtl::OUString aId  = (*it_index).first;
529                 sal_Int32 nIndex = (*it_index).second;
530                 rTargetIndexMap[ aId ] = nIndex;
531             }
532             pLocaleItem->m_nNextIndex = pCopyFromItem->m_nNextIndex;
533         }
534 
535         if( m_pCurrentLocaleItem == NULL )
536             m_pCurrentLocaleItem = pLocaleItem;
537 
538         if( m_pDefaultLocaleItem == NULL )
539         {
540             m_pDefaultLocaleItem = pLocaleItem;
541             m_bDefaultModified = true;
542         }
543 
544         implModified();
545     }
546     else
547     {
548         ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceImpl: Invalid locale" );
549         throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 );
550     }
551 }
552 
553 void StringResourceImpl::removeLocale( const Locale& locale )
554     throw (IllegalArgumentException, RuntimeException, NoSupportException)
555 {
556     ::osl::MutexGuard aGuard( getMutex() );
557     implCheckReadOnly( "StringResourceImpl::removeLocale(): Read only" );
558 
559     LocaleItem* pRemoveItem = getItemForLocale( locale, true );
560     if( pRemoveItem )
561     {
562         // Last locale?
563         sal_Int32 nLocaleCount = m_aLocaleItemVector.size();
564         if( nLocaleCount > 1 )
565         {
566             LocaleItem* pFallbackItem = NULL;
567             if( m_pCurrentLocaleItem == pRemoveItem ||
568                 m_pDefaultLocaleItem  == pRemoveItem )
569             {
570                 for( LocaleItemVectorIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
571                 {
572                     LocaleItem* pLocaleItem = *it;
573                     if( pLocaleItem != pRemoveItem )
574                     {
575                         pFallbackItem = pLocaleItem;
576                         break;
577                     }
578                 }
579                 if( m_pCurrentLocaleItem == pRemoveItem )
580                 {
581                     sal_Bool FindClosestMatch = false;
582                     setCurrentLocale( pFallbackItem->m_locale, FindClosestMatch );
583                 }
584                 if( m_pDefaultLocaleItem == pRemoveItem )
585                 {
586                     setDefaultLocale( pFallbackItem->m_locale );
587                 }
588             }
589         }
590         for( LocaleItemVectorIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
591         {
592             LocaleItem* pLocaleItem = *it;
593             if( pLocaleItem == pRemoveItem )
594             {
595                 // Remember locale item to delete file while storing
596                 m_aDeletedLocaleItemVector.push_back( pLocaleItem );
597 
598                 // Last locale?
599                 if( nLocaleCount == 1 )
600                 {
601                     m_nNextUniqueNumericId = 0;
602                     if( m_pDefaultLocaleItem )
603                     {
604                         LocaleItem* pChangedDefaultLocaleItem = new LocaleItem( m_pDefaultLocaleItem->m_locale );
605                         m_aChangedDefaultLocaleVector.push_back( pChangedDefaultLocaleItem );
606                     }
607                     m_pCurrentLocaleItem = NULL;
608                     m_pDefaultLocaleItem = NULL;
609                 }
610 
611                 m_aLocaleItemVector.erase( it );
612 
613                 implModified();
614                 break;
615             }
616         }
617     }
618 }
619 
620 void StringResourceImpl::implScanIdForNumber( const ::rtl::OUString& ResourceID )
621 {
622     const sal_Unicode* pSrc = ResourceID.getStr();
623     sal_Int32 nLen = ResourceID.getLength();
624 
625     sal_Int32 nNumber = 0;
626     for( sal_Int32 i = 0 ; i < nLen ; i++ )
627     {
628         sal_Unicode c = pSrc[i];
629         if( c >= '0' && c <= '9' )
630         {
631             sal_uInt16 nDigitVal = c - '0';
632             nNumber = 10*nNumber + nDigitVal;
633         }
634         else
635             break;
636     }
637 
638     if( m_nNextUniqueNumericId < nNumber + 1 )
639         m_nNextUniqueNumericId = nNumber + 1;
640 }
641 
642 sal_Int32 StringResourceImpl::getUniqueNumericId(  )
643     throw (RuntimeException, NoSupportException)
644 {
645     if( m_nNextUniqueNumericId == UNIQUE_NUMBER_NEEDS_INITIALISATION )
646     {
647         implLoadAllLocales();
648         m_nNextUniqueNumericId = 0;
649     }
650 
651     if( m_nNextUniqueNumericId < UNIQUE_NUMBER_NEEDS_INITIALISATION )
652     {
653         ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "getUniqueNumericId: Extended sal_Int32 range" );
654         throw NoSupportException( errorMsg, Reference< XInterface >() );
655     }
656     return m_nNextUniqueNumericId;
657 }
658 
659 
660 // =============================================================================
661 // Private helper methods
662 
663 LocaleItem* StringResourceImpl::getItemForLocale
664     ( const Locale& locale, sal_Bool bException )
665         throw (::com::sun::star::lang::IllegalArgumentException)
666 {
667     LocaleItem* pRetItem = NULL;
668 
669     // Search for locale
670     for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
671     {
672         LocaleItem* pLocaleItem = *it;
673         if( pLocaleItem )
674         {
675             Locale& cmp_locale = pLocaleItem->m_locale;
676             if( cmp_locale.Language == locale.Language &&
677                 cmp_locale.Country  == locale.Country &&
678                 cmp_locale.Variant  == locale.Variant )
679             {
680                 pRetItem = pLocaleItem;
681                 break;
682             }
683         }
684     }
685 
686     if( pRetItem == NULL && bException )
687     {
688         ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceImpl: Invalid locale" );
689         throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 );
690     }
691     return pRetItem;
692 }
693 
694 // Returns the LocalItem for a given locale, if it exists, otherwise NULL
695 // This method performes a closest match search, at least the language must match
696 LocaleItem* StringResourceImpl::getClosestMatchItemForLocale( const Locale& locale )
697 {
698     LocaleItem* pRetItem = NULL;
699 
700     // Search for locale
701     for( sal_Int32 iPass = 0 ; iPass <= 2 ; ++iPass )
702     {
703         for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
704         {
705             LocaleItem* pLocaleItem = *it;
706             if( pLocaleItem )
707             {
708                 Locale& cmp_locale = pLocaleItem->m_locale;
709                 if( cmp_locale.Language == locale.Language &&
710                     (iPass > 1 || cmp_locale.Country  == locale.Country) &&
711                     (iPass > 0 || cmp_locale.Variant  == locale.Variant) )
712                 {
713                     pRetItem = pLocaleItem;
714                     break;
715                 }
716             }
717         }
718         if( pRetItem )
719             break;
720     }
721 
722     return pRetItem;
723 }
724 
725 void StringResourceImpl::implModified( void )
726 {
727     m_bModified = true;
728     implNotifyListeners();
729 }
730 
731 void StringResourceImpl::implNotifyListeners( void )
732 {
733     EventObject aEvent;
734     aEvent.Source = static_cast< XInterface* >( (OWeakObject*)this );
735 
736     ::cppu::OInterfaceIteratorHelper it( m_aListenerContainer );
737     while( it.hasMoreElements() )
738     {
739         Reference< XInterface > xIface = it.next();
740         Reference< XModifyListener > xListener( xIface, UNO_QUERY );
741         try
742         {
743             xListener->modified( aEvent );
744         }
745         catch(RuntimeException&)
746         {
747             it.remove();
748         }
749     }
750 }
751 
752 
753 // =============================================================================
754 // Loading
755 
756 bool StringResourceImpl::loadLocale( LocaleItem* pLocaleItem )
757 {
758     // Base implementation has nothing to load
759     (void)pLocaleItem;
760     return true;
761 }
762 
763 void StringResourceImpl::implLoadAllLocales( void )
764 {
765     // Base implementation has nothing to load
766 }
767 
768 
769 Reference< XMultiComponentFactory > StringResourceImpl::getMultiComponentFactory( void )
770 {
771     ::osl::MutexGuard aGuard( getMutex() );
772 
773     if( !m_xMCF.is() )
774     {
775         Reference< XMultiComponentFactory > xSMgr( m_xContext->getServiceManager(), UNO_QUERY );
776         if( !xSMgr.is() )
777         {
778             throw RuntimeException(
779                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StringResourceImpl::getMultiComponentFactory: Couldn't instantiate MultiComponentFactory" ) ),
780                     Reference< XInterface >() );
781         }
782         m_xMCF = xSMgr;
783     }
784     return m_xMCF;
785 }
786 
787 
788 // =============================================================================
789 // StringResourcePersistenceImpl
790 // =============================================================================
791 
792 StringResourcePersistenceImpl::StringResourcePersistenceImpl( const Reference< XComponentContext >& rxContext )
793     : StringResourcePersistenceImpl_BASE( rxContext )
794 {
795 }
796 
797 // -----------------------------------------------------------------------------
798 
799 StringResourcePersistenceImpl::~StringResourcePersistenceImpl()
800 {
801 }
802 
803 // -----------------------------------------------------------------------------
804 // XServiceInfo
805 // -----------------------------------------------------------------------------
806 
807 ::rtl::OUString StringResourcePersistenceImpl::getImplementationName(  )
808     throw (RuntimeException)
809 {
810     return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM
811         ( "com.sun.star.comp.scripting.StringResourceWithLocation") );
812 }
813 
814 // -----------------------------------------------------------------------------
815 
816 sal_Bool StringResourcePersistenceImpl::supportsService( const ::rtl::OUString& rServiceName )
817     throw (RuntimeException)
818 {
819     return StringResourceImpl::supportsService( rServiceName );
820 }
821 
822 // -----------------------------------------------------------------------------
823 
824 Sequence< ::rtl::OUString > StringResourcePersistenceImpl::getSupportedServiceNames(  )
825     throw (RuntimeException)
826 {
827     return StringResourceImpl::getSupportedServiceNames();
828 }
829 
830 // -----------------------------------------------------------------------------
831 // XInitialization base functionality for derived classes
832 // -----------------------------------------------------------------------------
833 
834 static ::rtl::OUString aNameBaseDefaultStr = ::rtl::OUString::createFromAscii( "strings" );
835 
836 void StringResourcePersistenceImpl::implInitializeCommonParameters
837     ( const Sequence< Any >& aArguments )
838         throw (Exception, RuntimeException)
839 {
840     bool bReadOnlyOk = (aArguments[1] >>= m_bReadOnly);
841     if( !bReadOnlyOk )
842     {
843         ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "XInitialization::initialize: Expected ReadOnly flag" );
844         throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 1 );
845     }
846 
847     com::sun::star::lang::Locale aCurrentLocale;
848     bool bLocaleOk = (aArguments[2] >>= aCurrentLocale);
849     if( !bLocaleOk )
850     {
851         ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "XInitialization::initialize: Expected Locale" );
852         throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 2 );
853     }
854 
855     bool bNameBaseOk = (aArguments[3] >>= m_aNameBase);
856     if( !bNameBaseOk )
857     {
858         ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "XInitialization::initialize: Expected NameBase string" );
859         throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 3 );
860     }
861     if( m_aNameBase.getLength() == 0 )
862         m_aNameBase = aNameBaseDefaultStr;
863 
864     bool bCommentOk = (aArguments[4] >>= m_aComment);
865     if( !bCommentOk )
866     {
867         ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "XInitialization::initialize: Expected Comment string" );
868         throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 4 );
869     }
870 
871     implScanLocales();
872 
873     sal_Bool FindClosestMatch = true;
874     sal_Bool bUseDefaultIfNoMatch = true;
875     implSetCurrentLocale( aCurrentLocale, FindClosestMatch, bUseDefaultIfNoMatch );
876 }
877 
878 // -----------------------------------------------------------------------------
879 // Forwarding calls to base class
880 
881 // XModifyBroadcaster
882 void StringResourcePersistenceImpl::addModifyListener( const Reference< XModifyListener >& aListener )
883     throw (RuntimeException)
884 {
885     StringResourceImpl::addModifyListener( aListener );
886 }
887 void StringResourcePersistenceImpl::removeModifyListener( const Reference< XModifyListener >& aListener )
888     throw (RuntimeException)
889 {
890     StringResourceImpl::removeModifyListener( aListener );
891 }
892 
893 // XStringResourceResolver
894 ::rtl::OUString StringResourcePersistenceImpl::resolveString( const ::rtl::OUString& ResourceID )
895     throw (::com::sun::star::resource::MissingResourceException, RuntimeException)
896 {
897     return StringResourceImpl::resolveString( ResourceID ) ;
898 }
899 ::rtl::OUString StringResourcePersistenceImpl::resolveStringForLocale( const ::rtl::OUString& ResourceID, const Locale& locale )
900     throw ( ::com::sun::star::resource::MissingResourceException, RuntimeException)
901 {
902     return StringResourceImpl::resolveStringForLocale( ResourceID, locale );
903 }
904 sal_Bool StringResourcePersistenceImpl::hasEntryForId( const ::rtl::OUString& ResourceID )
905     throw (RuntimeException)
906 {
907     return StringResourceImpl::hasEntryForId( ResourceID ) ;
908 }
909 sal_Bool StringResourcePersistenceImpl::hasEntryForIdAndLocale( const ::rtl::OUString& ResourceID,
910     const Locale& locale )
911         throw (RuntimeException)
912 {
913     return StringResourceImpl::hasEntryForIdAndLocale( ResourceID, locale );
914 }
915 Locale StringResourcePersistenceImpl::getCurrentLocale()
916     throw (RuntimeException)
917 {
918     return StringResourceImpl::getCurrentLocale();
919 }
920 Locale StringResourcePersistenceImpl::getDefaultLocale(  )
921     throw (RuntimeException)
922 {
923     return StringResourceImpl::getDefaultLocale();
924 }
925 Sequence< Locale > StringResourcePersistenceImpl::getLocales(  )
926     throw (RuntimeException)
927 {
928     return StringResourceImpl::getLocales();
929 }
930 
931 // XStringResourceManager
932 sal_Bool StringResourcePersistenceImpl::isReadOnly()
933     throw (RuntimeException)
934 {
935     return StringResourceImpl::isReadOnly();
936 }
937 void StringResourcePersistenceImpl::setCurrentLocale( const Locale& locale, sal_Bool FindClosestMatch )
938     throw (IllegalArgumentException, RuntimeException)
939 {
940     StringResourceImpl::setCurrentLocale( locale, FindClosestMatch );
941 }
942 void StringResourcePersistenceImpl::setDefaultLocale( const Locale& locale )
943     throw (IllegalArgumentException, RuntimeException,NoSupportException)
944 {
945     StringResourceImpl::setDefaultLocale( locale );
946 }
947 Sequence< ::rtl::OUString > StringResourcePersistenceImpl::getResourceIDs(  )
948     throw (RuntimeException)
949 {
950     return StringResourceImpl::getResourceIDs();
951 }
952 void StringResourcePersistenceImpl::setString( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str )
953     throw (NoSupportException, RuntimeException)
954 {
955     StringResourceImpl::setString( ResourceID, Str );
956 }
957 void StringResourcePersistenceImpl::setStringForLocale
958     ( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str, const Locale& locale )
959         throw (NoSupportException, RuntimeException)
960 {
961     StringResourceImpl::setStringForLocale( ResourceID, Str, locale );
962 }
963 Sequence< ::rtl::OUString > StringResourcePersistenceImpl::getResourceIDsForLocale
964     ( const Locale& locale ) throw (::com::sun::star::uno::RuntimeException)
965 {
966     return StringResourceImpl::getResourceIDsForLocale( locale );
967 }
968 void StringResourcePersistenceImpl::removeId( const ::rtl::OUString& ResourceID )
969     throw (::com::sun::star::resource::MissingResourceException, RuntimeException, NoSupportException)
970 {
971     StringResourceImpl::removeId( ResourceID );
972 }
973 void StringResourcePersistenceImpl::removeIdForLocale( const ::rtl::OUString& ResourceID, const Locale& locale )
974     throw (::com::sun::star::resource::MissingResourceException, RuntimeException, NoSupportException)
975 {
976     StringResourceImpl::removeIdForLocale( ResourceID, locale );
977 }
978 void StringResourcePersistenceImpl::newLocale( const Locale& locale )
979     throw (ElementExistException, IllegalArgumentException, RuntimeException, NoSupportException)
980 {
981     StringResourceImpl::newLocale( locale );
982 }
983 void StringResourcePersistenceImpl::removeLocale( const Locale& locale )
984     throw (IllegalArgumentException, RuntimeException, NoSupportException)
985 {
986     StringResourceImpl::removeLocale( locale );
987 }
988 sal_Int32 StringResourcePersistenceImpl::getUniqueNumericId(  )
989     throw (RuntimeException, NoSupportException)
990 {
991     return StringResourceImpl::getUniqueNumericId();
992 }
993 
994 // -----------------------------------------------------------------------------
995 // XStringResourcePersistence
996 
997 void StringResourcePersistenceImpl::store()
998     throw (NoSupportException, Exception, RuntimeException)
999 {
1000 }
1001 
1002 sal_Bool StringResourcePersistenceImpl::isModified(  )
1003     throw (RuntimeException)
1004 {
1005     ::osl::MutexGuard aGuard( getMutex() );
1006 
1007     return m_bModified;
1008 }
1009 
1010 void StringResourcePersistenceImpl::setComment( const ::rtl::OUString& Comment )
1011     throw (::com::sun::star::uno::RuntimeException)
1012 {
1013     m_aComment = Comment;
1014 }
1015 
1016 void StringResourcePersistenceImpl::storeToStorage( const Reference< XStorage >& Storage,
1017     const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment )
1018         throw (Exception, RuntimeException)
1019 {
1020     ::osl::MutexGuard aGuard( getMutex() );
1021 
1022     bool bUsedForStore = false;
1023     bool bStoreAll = true;
1024     implStoreAtStorage( NameBase, Comment, Storage, bUsedForStore, bStoreAll );
1025 }
1026 
1027 void StringResourcePersistenceImpl::implStoreAtStorage
1028 (
1029     const ::rtl::OUString& aNameBase,
1030     const ::rtl::OUString& aComment,
1031     const Reference< ::com::sun::star::embed::XStorage >& Storage,
1032     bool bUsedForStore,
1033     bool bStoreAll
1034 )
1035     throw (Exception, RuntimeException)
1036 {
1037     // Delete files for deleted locales
1038     if( bUsedForStore )
1039     {
1040         while( m_aDeletedLocaleItemVector.size() > 0 )
1041         {
1042             LocaleItemVectorIt it = m_aDeletedLocaleItemVector.begin();
1043             LocaleItem* pLocaleItem = *it;
1044             if( pLocaleItem != NULL )
1045             {
1046                 ::rtl::OUString aStreamName = implGetFileNameForLocaleItem( pLocaleItem, m_aNameBase );
1047                 aStreamName += ::rtl::OUString::createFromAscii( ".properties" );
1048 
1049                 try
1050                 {
1051                     Storage->removeElement( aStreamName );
1052                 }
1053                 catch( Exception& )
1054                 {}
1055 
1056                 m_aDeletedLocaleItemVector.erase( it );
1057                 delete pLocaleItem;
1058             }
1059         }
1060     }
1061 
1062     for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
1063     {
1064         LocaleItem* pLocaleItem = *it;
1065         if( pLocaleItem != NULL && (bStoreAll || pLocaleItem->m_bModified) &&
1066             loadLocale( pLocaleItem ) )
1067         {
1068             ::rtl::OUString aStreamName = implGetFileNameForLocaleItem( pLocaleItem, aNameBase );
1069             aStreamName += ::rtl::OUString::createFromAscii( ".properties" );
1070 
1071             Reference< io::XStream > xElementStream =
1072                     Storage->openStreamElement( aStreamName, ElementModes::READWRITE );
1073 
1074             ::rtl::OUString aPropName = ::rtl::OUString::createFromAscii( "MediaType" );
1075             ::rtl::OUString aMime = ::rtl::OUString::createFromAscii( "text/plain" );
1076 
1077             uno::Reference< beans::XPropertySet > xProps( xElementStream, uno::UNO_QUERY );
1078             OSL_ENSURE( xProps.is(), "The StorageStream must implement XPropertySet interface!\n" );
1079             if ( xProps.is() )
1080             {
1081                 xProps->setPropertyValue( aPropName, uno::makeAny( aMime ) );
1082 
1083                 aPropName = ::rtl::OUString::createFromAscii( "UseCommonStoragePasswordEncryption" );
1084                 xProps->setPropertyValue( aPropName, uno::makeAny( sal_True ) );
1085             }
1086 
1087             Reference< io::XOutputStream > xOutputStream = xElementStream->getOutputStream();
1088             if( xOutputStream.is() )
1089                 implWritePropertiesFile( pLocaleItem, xOutputStream, aComment );
1090             xOutputStream->closeOutput();
1091 
1092             if( bUsedForStore )
1093                 pLocaleItem->m_bModified = false;
1094         }
1095     }
1096 
1097     // Delete files for changed defaults
1098     if( bUsedForStore )
1099     {
1100         for( LocaleItemVectorIt it = m_aChangedDefaultLocaleVector.begin();
1101              it != m_aChangedDefaultLocaleVector.end(); it++ )
1102         {
1103             LocaleItem* pLocaleItem = *it;
1104             if( pLocaleItem != NULL )
1105             {
1106                 ::rtl::OUString aStreamName = implGetFileNameForLocaleItem( pLocaleItem, m_aNameBase );
1107                 aStreamName += ::rtl::OUString::createFromAscii( ".default" );
1108 
1109                 try
1110                 {
1111                     Storage->removeElement( aStreamName );
1112                 }
1113                 catch( Exception& )
1114                 {}
1115 
1116                 delete pLocaleItem;
1117             }
1118         }
1119         m_aChangedDefaultLocaleVector.clear();
1120     }
1121 
1122     // Default locale
1123     if( m_pDefaultLocaleItem != NULL && (bStoreAll || m_bDefaultModified) )
1124     {
1125         ::rtl::OUString aStreamName = implGetFileNameForLocaleItem( m_pDefaultLocaleItem, aNameBase );
1126         aStreamName += ::rtl::OUString::createFromAscii( ".default" );
1127 
1128         Reference< io::XStream > xElementStream =
1129                 Storage->openStreamElement( aStreamName, ElementModes::READWRITE );
1130 
1131         ::rtl::OUString aPropName = ::rtl::OUString::createFromAscii( "MediaType" );
1132         ::rtl::OUString aMime = ::rtl::OUString::createFromAscii( "text/plain" );
1133 
1134         // Only create stream without content
1135         Reference< io::XOutputStream > xOutputStream = xElementStream->getOutputStream();
1136         xOutputStream->closeOutput();
1137 
1138         if( bUsedForStore )
1139             m_bDefaultModified = false;
1140     }
1141 }
1142 
1143 void StringResourcePersistenceImpl::storeToURL( const ::rtl::OUString& URL,
1144     const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment,
1145     const Reference< ::com::sun::star::task::XInteractionHandler >& Handler )
1146         throw (Exception, RuntimeException)
1147 {
1148     ::osl::MutexGuard aGuard( getMutex() );
1149 
1150     bool bUsedForStore = false;
1151     bool bStoreAll = true;
1152 
1153     Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory();
1154     Reference< ucb::XSimpleFileAccess > xFileAccess;
1155     xFileAccess = Reference< ucb::XSimpleFileAccess >( xMCF->createInstanceWithContext
1156         ( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ),
1157             m_xContext ), UNO_QUERY );
1158     if( xFileAccess.is() && Handler.is() )
1159         xFileAccess->setInteractionHandler( Handler );
1160 
1161     implStoreAtLocation( URL, NameBase, Comment, xFileAccess, bUsedForStore, bStoreAll );
1162 }
1163 
1164 void StringResourcePersistenceImpl::implKillRemovedLocaleFiles
1165 (
1166     const ::rtl::OUString& Location,
1167     const ::rtl::OUString& aNameBase,
1168     const ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XSimpleFileAccess >& xFileAccess
1169 )
1170     throw (Exception, RuntimeException)
1171 {
1172     // Delete files for deleted locales
1173     while( m_aDeletedLocaleItemVector.size() > 0 )
1174     {
1175         LocaleItemVectorIt it = m_aDeletedLocaleItemVector.begin();
1176         LocaleItem* pLocaleItem = *it;
1177         if( pLocaleItem != NULL )
1178         {
1179             ::rtl::OUString aCompleteFileName =
1180                 implGetPathForLocaleItem( pLocaleItem, aNameBase, Location );
1181             if( xFileAccess->exists( aCompleteFileName ) )
1182                 xFileAccess->kill( aCompleteFileName );
1183 
1184             m_aDeletedLocaleItemVector.erase( it );
1185             delete pLocaleItem;
1186         }
1187     }
1188 }
1189 
1190 void StringResourcePersistenceImpl::implKillChangedDefaultFiles
1191 (
1192     const ::rtl::OUString& Location,
1193     const ::rtl::OUString& aNameBase,
1194     const ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XSimpleFileAccess >& xFileAccess
1195 )
1196     throw (Exception, RuntimeException)
1197 {
1198     // Delete files for changed defaults
1199     for( LocaleItemVectorIt it = m_aChangedDefaultLocaleVector.begin();
1200          it != m_aChangedDefaultLocaleVector.end(); it++ )
1201     {
1202         LocaleItem* pLocaleItem = *it;
1203         if( pLocaleItem != NULL )
1204         {
1205             ::rtl::OUString aCompleteFileName =
1206                 implGetPathForLocaleItem( pLocaleItem, aNameBase, Location, true );
1207             if( xFileAccess->exists( aCompleteFileName ) )
1208                 xFileAccess->kill( aCompleteFileName );
1209 
1210             delete pLocaleItem;
1211         }
1212     }
1213     m_aChangedDefaultLocaleVector.clear();
1214 }
1215 
1216 void StringResourcePersistenceImpl::implStoreAtLocation
1217 (
1218     const ::rtl::OUString& Location,
1219     const ::rtl::OUString& aNameBase,
1220     const ::rtl::OUString& aComment,
1221     const Reference< ucb::XSimpleFileAccess >& xFileAccess,
1222     bool bUsedForStore,
1223     bool bStoreAll,
1224     bool bKillAll
1225 )
1226     throw (Exception, RuntimeException)
1227 {
1228     // Delete files for deleted locales
1229     if( bUsedForStore || bKillAll )
1230         implKillRemovedLocaleFiles( Location, aNameBase, xFileAccess );
1231 
1232     for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
1233     {
1234         LocaleItem* pLocaleItem = *it;
1235         if( pLocaleItem != NULL && (bStoreAll || bKillAll || pLocaleItem->m_bModified) &&
1236             loadLocale( pLocaleItem ) )
1237         {
1238             ::rtl::OUString aCompleteFileName =
1239                 implGetPathForLocaleItem( pLocaleItem, aNameBase, Location );
1240             if( xFileAccess->exists( aCompleteFileName ) )
1241                 xFileAccess->kill( aCompleteFileName );
1242 
1243             if( !bKillAll )
1244             {
1245                 // Create Output stream
1246                 Reference< io::XOutputStream > xOutputStream = xFileAccess->openFileWrite( aCompleteFileName );
1247                 if( xOutputStream.is() )
1248                 {
1249                     implWritePropertiesFile( pLocaleItem, xOutputStream, aComment );
1250                     xOutputStream->closeOutput();
1251                 }
1252                 if( bUsedForStore )
1253                     pLocaleItem->m_bModified = false;
1254             }
1255         }
1256     }
1257 
1258     // Delete files for changed defaults
1259     if( bUsedForStore || bKillAll )
1260         implKillChangedDefaultFiles( Location, aNameBase, xFileAccess );
1261 
1262     // Default locale
1263     if( m_pDefaultLocaleItem != NULL && (bStoreAll || bKillAll || m_bDefaultModified) )
1264     {
1265         ::rtl::OUString aCompleteFileName =
1266             implGetPathForLocaleItem( m_pDefaultLocaleItem, aNameBase, Location, true );
1267         if( xFileAccess->exists( aCompleteFileName ) )
1268             xFileAccess->kill( aCompleteFileName );
1269 
1270         if( !bKillAll )
1271         {
1272             // Create Output stream
1273             Reference< io::XOutputStream > xOutputStream = xFileAccess->openFileWrite( aCompleteFileName );
1274             if( xOutputStream.is() )
1275                 xOutputStream->closeOutput();
1276 
1277             if( bUsedForStore )
1278                 m_bDefaultModified = false;
1279         }
1280     }
1281 }
1282 
1283 
1284 // -----------------------------------------------------------------------------
1285 // BinaryOutput, helper class for exportBinary
1286 
1287 class BinaryOutput
1288 {
1289     Reference< XMultiComponentFactory >     m_xMCF;
1290     Reference< XComponentContext >          m_xContext;
1291     Reference< XInterface >                 m_xTempFile;
1292     Reference< io::XOutputStream >          m_xOutputStream;
1293 
1294 public:
1295     BinaryOutput( Reference< XMultiComponentFactory > xMCF,
1296         Reference< XComponentContext > xContext );
1297 
1298     Reference< io::XOutputStream > getOutputStream( void )
1299         { return m_xOutputStream; }
1300 
1301     Sequence< ::sal_Int8 > closeAndGetData( void );
1302 
1303     // Template to be used with sal_Int16 and sal_Unicode
1304     template< class T >
1305     void write16BitInt( T n );
1306     void writeInt16( sal_Int16 n )
1307         { write16BitInt( n ); }
1308     void writeUnicodeChar( sal_Unicode n )
1309         { write16BitInt( n ); }
1310     void writeInt32( sal_Int32 n );
1311     void writeString( const ::rtl::OUString& aStr );
1312 };
1313 
1314 BinaryOutput::BinaryOutput( Reference< XMultiComponentFactory > xMCF,
1315     Reference< XComponentContext > xContext )
1316         : m_xMCF( xMCF )
1317         , m_xContext( xContext )
1318 {
1319     m_xTempFile = m_xMCF->createInstanceWithContext
1320         ( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ), m_xContext );
1321     if( m_xTempFile.is() )
1322         m_xOutputStream = Reference< io::XOutputStream >( m_xTempFile, UNO_QUERY );
1323 }
1324 
1325 template< class T >
1326 void BinaryOutput::write16BitInt( T n )
1327 {
1328     if( !m_xOutputStream.is() )
1329         return;
1330 
1331     Sequence< sal_Int8 > aSeq( 2 );
1332     sal_Int8* p = aSeq.getArray();
1333 
1334     sal_Int8 nLow  = sal_Int8( n & 0xff );
1335     sal_Int8 nHigh = sal_Int8( n >> 8 );
1336 
1337     p[0] = nLow;
1338     p[1] = nHigh;
1339     m_xOutputStream->writeBytes( aSeq );
1340 }
1341 
1342 void BinaryOutput::writeInt32( sal_Int32 n )
1343 {
1344     if( !m_xOutputStream.is() )
1345         return;
1346 
1347     Sequence< sal_Int8 > aSeq( 4 );
1348     sal_Int8* p = aSeq.getArray();
1349 
1350     for( sal_Int16 i = 0 ; i < 4 ; i++ )
1351     {
1352         p[i] = sal_Int8( n & 0xff );
1353         n >>= 8;
1354     }
1355     m_xOutputStream->writeBytes( aSeq );
1356 }
1357 
1358 void BinaryOutput::writeString( const ::rtl::OUString& aStr )
1359 {
1360     sal_Int32 nLen = aStr.getLength();
1361     const sal_Unicode* pStr = aStr.getStr();
1362 
1363     for( sal_Int32 i = 0 ; i < nLen ; i++ )
1364         writeUnicodeChar( pStr[i] );
1365 
1366     writeUnicodeChar( 0 );
1367 }
1368 
1369 Sequence< ::sal_Int8 > BinaryOutput::closeAndGetData( void )
1370 {
1371     Sequence< ::sal_Int8 > aRetSeq;
1372     if( !m_xOutputStream.is() )
1373         return aRetSeq;
1374 
1375     m_xOutputStream->closeOutput();
1376 
1377     Reference< io::XSeekable> xSeekable( m_xTempFile, UNO_QUERY );
1378     if( !xSeekable.is() )
1379         return aRetSeq;
1380 
1381     sal_Int32 nSize = (sal_Int32)xSeekable->getPosition();
1382 
1383     Reference< io::XInputStream> xInputStream( m_xTempFile, UNO_QUERY );
1384     if( !xInputStream.is() )
1385         return aRetSeq;
1386 
1387     xSeekable->seek( 0 );
1388     sal_Int32 nRead = xInputStream->readBytes( aRetSeq, nSize );
1389     (void)nRead;
1390     OSL_ENSURE( nRead == nSize, "BinaryOutput::closeAndGetData: nRead != nSize" );
1391 
1392     return aRetSeq;
1393 }
1394 
1395 
1396 // Binary format:
1397 
1398 // Header
1399 // Byte         Content
1400 // 0 + 1        sal_Int16:  Version, currently 0, low byte first
1401 // 2 + 3        sal_Int16:  Locale count = n, low byte first
1402 // 4 + 5        sal_Int16:  Default Locale position in Locale list, == n if none
1403 // 6 - 7        sal_Int32:  Start index locale block 0, lowest byte first
1404 // (n-1) *      sal_Int32:  Start index locale block 1 to n, lowest byte first
1405 // 6 + 4*n      sal_Int32:  "Start index" non existing locale block n+1,
1406 //                          marks the first invalid index, kind of EOF
1407 
1408 // Locale block
1409 // All strings are stored as 2-Byte-0 terminated sequence
1410 // of 16 bit Unicode characters, each with low byte first
1411 // Empty strings only contain the 2-Byte-0
1412 
1413 // Members of com.sun.star.lang.Locale
1414 // with l1 = Locale.Language.getLength()
1415 // with l2 = Locale.Country.getLength()
1416 // with l3 = Locale.Variant.getLength()
1417 // pos0 = 0                     Locale.Language
1418 // pos1 = 2 * (l1 + 1)          Locale.Country
1419 // pos2 = pos1 + 2 * (l2 + 1)   Locale.Variant
1420 // pos3 = pos2 + 2 * (l3 + 1)
1421 // pos3                         Properties file written by implWritePropertiesFile
1422 
1423 Sequence< sal_Int8 > StringResourcePersistenceImpl::exportBinary(  )
1424     throw (RuntimeException)
1425 {
1426     Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory();
1427     BinaryOutput aOut( xMCF, m_xContext );
1428 
1429     sal_Int32 nLocaleCount = m_aLocaleItemVector.size();
1430     Sequence< sal_Int8 >* pLocaleDataSeq = new Sequence< sal_Int8 >[ nLocaleCount ];
1431 
1432     sal_Int32 iLocale = 0;
1433     sal_Int32 iDefault = 0;
1434     for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin();
1435          it != m_aLocaleItemVector.end(); it++,iLocale++ )
1436     {
1437         LocaleItem* pLocaleItem = *it;
1438         if( pLocaleItem != NULL && loadLocale( pLocaleItem ) )
1439         {
1440             if( m_pDefaultLocaleItem == pLocaleItem )
1441                 iDefault = iLocale;
1442 
1443             BinaryOutput aLocaleOut( m_xMCF, m_xContext );
1444             implWriteLocaleBinary( pLocaleItem, aLocaleOut );
1445 
1446             pLocaleDataSeq[iLocale] = aLocaleOut.closeAndGetData();
1447         }
1448     }
1449 
1450     // Write header
1451     sal_Int16 nVersion = 0;
1452     sal_Int16 nLocaleCount16 = (sal_Int16)nLocaleCount;
1453     sal_Int16 iDefault16 = (sal_Int16)iDefault;
1454     aOut.writeInt16( nVersion );
1455     aOut.writeInt16( nLocaleCount16 );
1456     aOut.writeInt16( iDefault16 );
1457 
1458     // Write data positions
1459     sal_Int32 nDataPos = 6 + 4 * (nLocaleCount + 1);
1460     for( iLocale = 0; iLocale < nLocaleCount; iLocale++ )
1461     {
1462         aOut.writeInt32( nDataPos );
1463 
1464         Sequence< sal_Int8 >& rSeq = pLocaleDataSeq[iLocale];
1465         sal_Int32 nSeqLen = rSeq.getLength();
1466         nDataPos += nSeqLen;
1467     }
1468     // Write final position
1469     aOut.writeInt32( nDataPos );
1470 
1471     // Write data
1472     Reference< io::XOutputStream > xOutputStream = aOut.getOutputStream();
1473     if( xOutputStream.is() )
1474     {
1475         for( iLocale = 0; iLocale < nLocaleCount; iLocale++ )
1476         {
1477             Sequence< sal_Int8 >& rSeq = pLocaleDataSeq[iLocale];
1478             xOutputStream->writeBytes( rSeq );
1479         }
1480     }
1481 
1482     delete[] pLocaleDataSeq;
1483 
1484     Sequence< sal_Int8 > aRetSeq = aOut.closeAndGetData();
1485     return aRetSeq;
1486 }
1487 
1488 void StringResourcePersistenceImpl::implWriteLocaleBinary
1489     ( LocaleItem* pLocaleItem, BinaryOutput& rOut )
1490 {
1491     Reference< io::XOutputStream > xOutputStream = rOut.getOutputStream();
1492     if( !xOutputStream.is() )
1493         return;
1494 
1495     Locale& rLocale = pLocaleItem->m_locale;
1496     rOut.writeString( rLocale.Language );
1497     rOut.writeString( rLocale.Country );
1498     rOut.writeString( rLocale.Variant );
1499     implWritePropertiesFile( pLocaleItem, xOutputStream, m_aComment );
1500 }
1501 
1502 // -----------------------------------------------------------------------------
1503 // BinaryOutput, helper class for exportBinary
1504 
1505 class BinaryInput
1506 {
1507     Sequence< sal_Int8 >                    m_aData;
1508     Reference< XMultiComponentFactory >     m_xMCF;
1509     Reference< XComponentContext >          m_xContext;
1510 
1511     const sal_Int8*                         m_pData;
1512     sal_Int32                               m_nCurPos;
1513     sal_Int32                               m_nSize;
1514 
1515 public:
1516     BinaryInput( Sequence< ::sal_Int8 > aData, Reference< XMultiComponentFactory > xMCF,
1517         Reference< XComponentContext > xContext );
1518 
1519     Reference< io::XInputStream > getInputStreamForSection( sal_Int32 nSize );
1520 
1521     void seek( sal_Int32 nPos );
1522     sal_Int32 getPosition( void )
1523         { return m_nCurPos; }
1524 
1525     sal_Int16 readInt16( void );
1526     sal_Int32 readInt32( void );
1527     sal_Unicode readUnicodeChar( void );
1528     ::rtl::OUString readString( void );
1529 };
1530 
1531 BinaryInput::BinaryInput( Sequence< ::sal_Int8 > aData, Reference< XMultiComponentFactory > xMCF,
1532     Reference< XComponentContext > xContext )
1533         : m_aData( aData )
1534         , m_xMCF( xMCF )
1535         , m_xContext( xContext )
1536 {
1537     m_pData = m_aData.getConstArray();
1538     m_nCurPos = 0;
1539     m_nSize = m_aData.getLength();
1540 }
1541 
1542 Reference< io::XInputStream > BinaryInput::getInputStreamForSection( sal_Int32 nSize )
1543 {
1544     Reference< io::XInputStream > xIn;
1545     if( m_nCurPos + nSize <= m_nSize )
1546     {
1547         Reference< io::XOutputStream > xTempOut( m_xMCF->createInstanceWithContext
1548             ( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ), m_xContext ), UNO_QUERY );
1549         if( xTempOut.is() )
1550         {
1551             Sequence< sal_Int8 > aSection( m_pData + m_nCurPos, nSize );
1552             xTempOut->writeBytes( aSection );
1553 
1554             Reference< io::XSeekable> xSeekable( xTempOut, UNO_QUERY );
1555             if( xSeekable.is() )
1556                 xSeekable->seek( 0 );
1557 
1558             xIn = Reference< io::XInputStream>( xTempOut, UNO_QUERY );
1559         }
1560     }
1561     else
1562         OSL_ENSURE( false, "BinaryInput::getInputStreamForSection(): Read past end" );
1563 
1564     return xIn;
1565 }
1566 
1567 void BinaryInput::seek( sal_Int32 nPos )
1568 {
1569     if( nPos <= m_nSize )
1570         m_nCurPos = nPos;
1571     else
1572         OSL_ENSURE( false, "BinaryInput::seek(): Position past end" );
1573 }
1574 
1575 
1576 sal_Int16 BinaryInput::readInt16( void )
1577 {
1578     sal_Int16 nRet = 0;
1579     if( m_nCurPos + 2 <= m_nSize )
1580     {
1581         nRet = nRet + sal_Int16( sal_uInt8( m_pData[m_nCurPos++] ) );
1582         nRet += 256 * sal_Int16( sal_uInt8( m_pData[m_nCurPos++] ) );
1583     }
1584     else
1585         OSL_ENSURE( false, "BinaryInput::readInt16(): Read past end" );
1586 
1587     return nRet;
1588 }
1589 
1590 sal_Int32 BinaryInput::readInt32( void )
1591 {
1592     sal_Int32 nRet = 0;
1593     if( m_nCurPos + 4 <= m_nSize )
1594     {
1595         sal_Int32 nFactor = 1;
1596         for( sal_Int16 i = 0; i < 4; i++ )
1597         {
1598             nRet += sal_uInt8( m_pData[m_nCurPos++] ) * nFactor;
1599             nFactor *= 256;
1600         }
1601     }
1602     else
1603         OSL_ENSURE( false, "BinaryInput::readInt32(): Read past end" );
1604 
1605     return nRet;
1606 }
1607 
1608 sal_Unicode BinaryInput::readUnicodeChar( void )
1609 {
1610     sal_uInt16 nRet = 0;
1611     if( m_nCurPos + 2 <= m_nSize )
1612     {
1613         nRet = nRet + sal_uInt8( m_pData[m_nCurPos++] );
1614         nRet += 256 * sal_uInt8( m_pData[m_nCurPos++] );
1615     }
1616     else
1617         OSL_ENSURE( false, "BinaryInput::readUnicodeChar(): Read past end" );
1618 
1619     sal_Unicode cRet = nRet;
1620     return cRet;
1621 }
1622 
1623 ::rtl::OUString BinaryInput::readString( void )
1624 {
1625     ::rtl::OUStringBuffer aBuf;
1626     sal_Unicode c;
1627     do
1628     {
1629         c = readUnicodeChar();
1630         if( c != 0 )
1631             aBuf.append( c );
1632     }
1633     while( c != 0 );
1634 
1635     ::rtl::OUString aRetStr = aBuf.makeStringAndClear();
1636     return aRetStr;
1637 }
1638 
1639 void StringResourcePersistenceImpl::importBinary( const Sequence< ::sal_Int8 >& Data )
1640     throw (IllegalArgumentException, RuntimeException)
1641 {
1642     // Init: Remove all locales
1643     sal_Int32 nOldLocaleCount = 0;
1644     do
1645     {
1646         Sequence< Locale > aLocaleSeq = getLocales();
1647         nOldLocaleCount = aLocaleSeq.getLength();
1648         if( nOldLocaleCount > 0 )
1649         {
1650             Locale aLocale = aLocaleSeq[0];
1651             removeLocale( aLocale );
1652         }
1653     }
1654     while( nOldLocaleCount > 0 );
1655 
1656     // Import data
1657     Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory();
1658     BinaryInput aIn( Data, xMCF, m_xContext );
1659 
1660     sal_Int32 nVersion = aIn.readInt16();
1661     (void)nVersion;
1662     sal_Int32 nLocaleCount = aIn.readInt16();
1663     sal_Int32 iDefault = aIn.readInt16();
1664     (void)iDefault;
1665 
1666     sal_Int32* pPositions = new sal_Int32[nLocaleCount + 1];
1667     for( sal_Int32 i = 0; i < nLocaleCount + 1; i++ )
1668         pPositions[i] = aIn.readInt32();
1669 
1670     // Import locales
1671     LocaleItem* pUseAsDefaultItem = NULL;
1672     for( sal_Int32 i = 0; i < nLocaleCount; i++ )
1673     {
1674         sal_Int32 nPos = pPositions[i];
1675         aIn.seek( nPos );
1676 
1677         Locale aLocale;
1678         aLocale.Language = aIn.readString();
1679         aLocale.Country = aIn.readString();
1680         aLocale.Variant = aIn.readString();
1681 
1682         sal_Int32 nAfterStringPos = aIn.getPosition();
1683         sal_Int32 nSize = pPositions[i+1] - nAfterStringPos;
1684         Reference< io::XInputStream > xInput = aIn.getInputStreamForSection( nSize );
1685         if( xInput.is() )
1686         {
1687             LocaleItem* pLocaleItem = new LocaleItem( aLocale );
1688             if( iDefault == i )
1689                 pUseAsDefaultItem = pLocaleItem;
1690             m_aLocaleItemVector.push_back( pLocaleItem );
1691             implReadPropertiesFile( pLocaleItem, xInput );
1692         }
1693     }
1694 
1695     if( pUseAsDefaultItem != NULL )
1696         setDefaultLocale( pUseAsDefaultItem->m_locale );
1697 
1698     delete[] pPositions;
1699 }
1700 
1701 
1702 // =============================================================================
1703 // Private helper methods
1704 
1705 bool checkNamingSceme( const ::rtl::OUString& aName, const ::rtl::OUString& aNameBase,
1706                        Locale& aLocale )
1707 {
1708     bool bSuccess = false;
1709 
1710     sal_Int32 nNameLen = aName.getLength();
1711     sal_Int32 nNameBaseLen = aNameBase.getLength();
1712 
1713     // Name has to start with NameBase followed
1714     // by a '_' and at least one more character
1715     if( aName.indexOf( aNameBase ) == 0 && nNameBaseLen < nNameLen-1 &&
1716         aName.getStr()[nNameBaseLen] == '_' )
1717     {
1718         bSuccess = true;
1719 
1720         sal_Int32 iStart = nNameBaseLen + 1;
1721         sal_Int32 iNext_ = aName.indexOf( '_', iStart );
1722         if( iNext_ != -1 && iNext_ < nNameLen-1 )
1723         {
1724             aLocale.Language = aName.copy( iStart, iNext_ - iStart );
1725 
1726             iStart = iNext_ + 1;
1727             iNext_ = aName.indexOf( '_', iStart );
1728             if( iNext_ != -1 && iNext_ < nNameLen-1 )
1729             {
1730                 aLocale.Country = aName.copy( iStart, iNext_ - iStart );
1731                 aLocale.Variant = aName.copy( iNext_ + 1 );
1732             }
1733             else
1734                 aLocale.Country = aName.copy( iStart );
1735         }
1736         else
1737             aLocale.Language = aName.copy( iStart );
1738     }
1739     return bSuccess;
1740 }
1741 
1742 void StringResourcePersistenceImpl::implLoadAllLocales( void )
1743 {
1744     for( LocaleItemVectorIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
1745     {
1746         LocaleItem* pLocaleItem = *it;
1747         if( pLocaleItem != NULL )
1748             loadLocale( pLocaleItem );
1749     }
1750 }
1751 
1752 // Scan locale properties files helper
1753 void StringResourcePersistenceImpl::implScanLocaleNames( const Sequence< ::rtl::OUString >& aContentSeq )
1754 {
1755     Locale aDefaultLocale;
1756     bool bDefaultFound = false;
1757 
1758     sal_Int32 nCount = aContentSeq.getLength();
1759     const ::rtl::OUString* pFiles = aContentSeq.getConstArray();
1760     for( int i = 0 ; i < nCount ; i++ )
1761     {
1762         ::rtl::OUString aCompleteName = pFiles[i];
1763         rtl::OUString aPureName;
1764         rtl::OUString aExtension;
1765         sal_Int32 iDot = aCompleteName.lastIndexOf( '.' );
1766         sal_Int32 iSlash = aCompleteName.lastIndexOf( '/' );
1767         if( iDot != -1 )
1768         {
1769             sal_Int32 iCopyFrom = (iSlash != -1) ? iSlash + 1 : 0;
1770             aPureName = aCompleteName.copy( iCopyFrom, iDot-iCopyFrom );
1771             aExtension = aCompleteName.copy( iDot + 1 );
1772         }
1773 
1774         if( aExtension.equalsAscii( "properties" ) )
1775         {
1776             //rtl::OUString aName = aInetObj.getBase();
1777             Locale aLocale;
1778 
1779             if( checkNamingSceme( aPureName, m_aNameBase, aLocale ) )
1780             {
1781                 LocaleItem* pLocaleItem = new LocaleItem( aLocale, false );
1782                 m_aLocaleItemVector.push_back( pLocaleItem );
1783 
1784                 if( m_pCurrentLocaleItem == NULL )
1785                     m_pCurrentLocaleItem = pLocaleItem;
1786 
1787                 if( m_pDefaultLocaleItem == NULL )
1788                 {
1789                     m_pDefaultLocaleItem = pLocaleItem;
1790                     m_bDefaultModified = true;
1791                 }
1792             }
1793         }
1794         else if( !bDefaultFound && aExtension.equalsAscii( "default" ) )
1795         {
1796             //rtl::OUString aName = aInetObj.getBase();
1797             Locale aLocale;
1798 
1799             if( checkNamingSceme( aPureName, m_aNameBase, aDefaultLocale ) )
1800                 bDefaultFound = true;
1801         }
1802     }
1803     if( bDefaultFound )
1804     {
1805         LocaleItem* pLocaleItem = getItemForLocale( aDefaultLocale, false );
1806         if( pLocaleItem )
1807         {
1808             m_pDefaultLocaleItem = pLocaleItem;
1809             m_bDefaultModified = false;
1810         }
1811     }
1812 }
1813 
1814 // Scan locale properties files
1815 void StringResourcePersistenceImpl::implScanLocales( void )
1816 {
1817     // Dummy implementation, method not called for this
1818     // base class, but pure virtual not possible-
1819 }
1820 
1821 bool StringResourcePersistenceImpl::loadLocale( LocaleItem* pLocaleItem )
1822 {
1823     bool bSuccess = false;
1824 
1825     OSL_ENSURE( pLocaleItem, "StringResourcePersistenceImpl::loadLocale(): pLocaleItem == NULL" );
1826     if( pLocaleItem )
1827     {
1828         if( pLocaleItem->m_bLoaded )
1829         {
1830             bSuccess = true;
1831         }
1832         else
1833         {
1834             bSuccess = implLoadLocale( pLocaleItem );
1835             pLocaleItem->m_bLoaded = true;      // = bSuccess??? -> leads to more tries
1836         }
1837     }
1838     return bSuccess;
1839 }
1840 
1841 bool StringResourcePersistenceImpl::implLoadLocale( LocaleItem* )
1842 {
1843     // Dummy implementation, method not called for this
1844     // base class, but pure virtual not possible-
1845     return false;
1846 }
1847 
1848 ::rtl::OUString implGetNameScemeForLocaleItem( const LocaleItem* pLocaleItem )
1849 {
1850     static ::rtl::OUString aUnder = ::rtl::OUString::createFromAscii( "_" );
1851 
1852     OSL_ENSURE( pLocaleItem,
1853         "StringResourcePersistenceImpl::implGetNameScemeForLocaleItem(): pLocaleItem == NULL" );
1854     Locale aLocale = pLocaleItem->m_locale;
1855 
1856     ::rtl::OUString aRetStr = aUnder;
1857     aRetStr += aLocale.Language;
1858 
1859     ::rtl::OUString aCountry  = aLocale.Country;
1860     if( aCountry.getLength() )
1861     {
1862         aRetStr += aUnder;
1863         aRetStr += aCountry;
1864     }
1865 
1866     ::rtl::OUString aVariant  = aLocale.Variant;
1867     if( aVariant.getLength() )
1868     {
1869         aRetStr += aUnder;
1870         aRetStr += aVariant;
1871     }
1872     return aRetStr;
1873 }
1874 
1875 ::rtl::OUString StringResourcePersistenceImpl::implGetFileNameForLocaleItem
1876     ( LocaleItem* pLocaleItem, const ::rtl::OUString& aNameBase )
1877 {
1878     ::rtl::OUString aFileName = aNameBase;
1879     if( aFileName.getLength() == 0 )
1880         aFileName = aNameBaseDefaultStr;
1881 
1882     aFileName += implGetNameScemeForLocaleItem( pLocaleItem );
1883     return aFileName;
1884 }
1885 
1886 ::rtl::OUString StringResourcePersistenceImpl::implGetPathForLocaleItem
1887     ( LocaleItem* pLocaleItem, const ::rtl::OUString& aNameBase,
1888       const ::rtl::OUString& aLocation, bool bDefaultFile )
1889 {
1890     ::rtl::OUString aFileName = implGetFileNameForLocaleItem( pLocaleItem, aNameBase );
1891     INetURLObject aInetObj( aLocation );
1892     aInetObj.insertName( aFileName, sal_True, INetURLObject::LAST_SEGMENT, sal_True, INetURLObject::ENCODE_ALL );
1893     if( bDefaultFile )
1894         aInetObj.setExtension( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("default") ) );
1895     else
1896         aInetObj.setExtension( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("properties") ) );
1897     ::rtl::OUString aCompleteFileName = aInetObj.GetMainURL( INetURLObject::NO_DECODE );
1898     return aCompleteFileName;
1899 }
1900 
1901 // White space according to Java property files specification in
1902 // http://java.sun.com/j2se/1.4.2/docs/api/java/util/Properties.html#load(java.io.InputStream)
1903 inline bool isWhiteSpace( sal_Unicode c )
1904 {
1905     bool bWhite = ( c == 0x0020 ||      // space
1906                     c == 0x0009 ||      // tab
1907                     c == 0x000a ||      // line feed, not always handled by TextInputStream
1908                     c == 0x000d ||      // carriage return, not always handled by TextInputStream
1909                     c == 0x000C );      // form feed
1910     return bWhite;
1911 }
1912 
1913 inline void skipWhites( const sal_Unicode* pBuf, sal_Int32 nLen, sal_Int32& ri )
1914 {
1915     while( ri < nLen )
1916     {
1917         if( !isWhiteSpace( pBuf[ri] ) )
1918             break;
1919         ri++;
1920     }
1921 }
1922 
1923 inline bool isHexDigit( sal_Unicode c, sal_uInt16& nDigitVal )
1924 {
1925     bool bRet = true;
1926     if( c >= '0' && c <= '9' )
1927         nDigitVal = c - '0';
1928     else if( c >= 'a' && c <= 'f' )
1929         nDigitVal = c - 'a' + 10;
1930     else if( c >= 'A' && c <= 'F' )
1931         nDigitVal = c - 'A' + 10;
1932     else
1933         bRet = false;
1934     return bRet;
1935 }
1936 
1937 sal_Unicode getEscapeChar( const sal_Unicode* pBuf, sal_Int32 nLen, sal_Int32& ri )
1938 {
1939     sal_Int32 i = ri;
1940 
1941     sal_Unicode cRet = 0;
1942     sal_Unicode c = pBuf[i];
1943     switch( c )
1944     {
1945         case 't':
1946             cRet = 0x0009;
1947             break;
1948         case 'n':
1949             cRet = 0x000a;
1950             break;
1951         case 'f':
1952             cRet = 0x000c;
1953             break;
1954         case 'r':
1955             cRet = 0x000d;
1956             break;
1957         case '\\':
1958             cRet = '\\';
1959             break;
1960         case 'u':
1961         {
1962             // Skip multiple u
1963             i++;
1964             while( i < nLen && pBuf[i] == 'u' )
1965                 i++;
1966 
1967             // Process hex digits
1968             sal_Int32 nDigitCount = 0;
1969             sal_uInt16 nDigitVal;
1970             while( i < nLen && isHexDigit( pBuf[i], nDigitVal ) )
1971             {
1972                 cRet = 16 * cRet + nDigitVal;
1973 
1974                 nDigitCount++;
1975                 if( nDigitCount == 4 )
1976                 {
1977                     // Write back position
1978                     ri = i;
1979                     break;
1980                 }
1981                 i++;
1982             }
1983             break;
1984         }
1985         default:
1986             cRet = c;
1987     }
1988 
1989     return cRet;
1990 }
1991 
1992 void CheckContinueInNextLine( Reference< io::XTextInputStream > xTextInputStream,
1993     ::rtl::OUString& aLine, bool& bEscapePending, const sal_Unicode*& pBuf,
1994     sal_Int32& nLen, sal_Int32& i )
1995 {
1996     if( i == nLen && bEscapePending )
1997     {
1998         bEscapePending = false;
1999 
2000         if( !xTextInputStream->isEOF() )
2001         {
2002             aLine = xTextInputStream->readLine();
2003             nLen = aLine.getLength();
2004             pBuf = aLine.getStr();
2005             i = 0;
2006 
2007             skipWhites( pBuf, nLen, i );
2008         }
2009     }
2010 }
2011 
2012 bool StringResourcePersistenceImpl::implReadPropertiesFile
2013     ( LocaleItem* pLocaleItem, const Reference< io::XInputStream >& xInputStream )
2014 {
2015     if( !xInputStream.is() || pLocaleItem == NULL )
2016         return false;
2017 
2018     bool bSuccess = false;
2019     Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory();
2020     Reference< io::XTextInputStream > xTextInputStream( xMCF->createInstanceWithContext
2021         ( ::rtl::OUString::createFromAscii( "com.sun.star.io.TextInputStream" ), m_xContext ), UNO_QUERY );
2022 
2023     if( xTextInputStream.is() )
2024     {
2025         Reference< io::XActiveDataSink> xActiveDataSink( xTextInputStream, UNO_QUERY );
2026         if( xActiveDataSink.is() )
2027         {
2028             bSuccess = true;
2029 
2030             xActiveDataSink->setInputStream( xInputStream );
2031 
2032             ::rtl::OUString aEncodingStr = ::rtl::OUString::createFromAscii
2033                 ( rtl_getMimeCharsetFromTextEncoding( RTL_TEXTENCODING_ISO_8859_1 ) );
2034             xTextInputStream->setEncoding( aEncodingStr );
2035 
2036             ::rtl::OUString aLine;
2037             while( !xTextInputStream->isEOF() )
2038             {
2039                 aLine = xTextInputStream->readLine();
2040 
2041                 sal_Int32 nLen = aLine.getLength();
2042                 if( 0 == nLen )
2043                     continue;
2044                 const sal_Unicode* pBuf = aLine.getStr();
2045                 ::rtl::OUStringBuffer aBuf;
2046                 sal_Unicode c = 0;
2047                 sal_Int32 i = 0;
2048 
2049                 skipWhites( pBuf, nLen, i );
2050                 if( i == nLen )
2051                     continue;   // line contains only white spaces
2052 
2053                 // Comment?
2054                 c = pBuf[i];
2055                 if( c == '#' || c == '!' )
2056                     continue;
2057 
2058                 // Scan key
2059                 ::rtl::OUString aResourceID;
2060                 bool bEscapePending = false;
2061                 bool bStrComplete = false;
2062                 while( i < nLen && !bStrComplete )
2063                 {
2064                     c = pBuf[i];
2065                     if( bEscapePending )
2066                     {
2067                         aBuf.append( getEscapeChar( pBuf, nLen, i ) );
2068                         bEscapePending = false;
2069                     }
2070                     else
2071                     {
2072                         if( c == '\\' )
2073                         {
2074                             bEscapePending = true;
2075                         }
2076                         else
2077                         {
2078                             if( c == ':' || c == '=' || isWhiteSpace( c ) )
2079                                 bStrComplete = true;
2080                             else
2081                                 aBuf.append( c );
2082                         }
2083                     }
2084                     i++;
2085 
2086                     CheckContinueInNextLine( xTextInputStream, aLine, bEscapePending, pBuf, nLen, i );
2087                     if( i == nLen )
2088                         bStrComplete = true;
2089 
2090                     if( bStrComplete )
2091                         aResourceID = aBuf.makeStringAndClear();
2092                 }
2093 
2094                 // Ignore lines with empty keys
2095                 if( 0 == aResourceID.getLength() )
2096                     continue;
2097 
2098                 // Scan value
2099                 skipWhites( pBuf, nLen, i );
2100 
2101                 ::rtl::OUString aValueStr;
2102                 bEscapePending = false;
2103                 bStrComplete = false;
2104                 while( i < nLen && !bStrComplete )
2105                 {
2106                     c = pBuf[i];
2107                     if( c == 0x000a || c == 0x000d )    // line feed/carriage return, not always handled by TextInputStream
2108                     {
2109                         i++;
2110                     }
2111                     else
2112                     {
2113                         if( bEscapePending )
2114                         {
2115                             aBuf.append( getEscapeChar( pBuf, nLen, i ) );
2116                             bEscapePending = false;
2117                         }
2118                         else if( c == '\\' )
2119                             bEscapePending = true;
2120                         else
2121                             aBuf.append( c );
2122                         i++;
2123 
2124                         CheckContinueInNextLine( xTextInputStream, aLine, bEscapePending, pBuf, nLen, i );
2125                     }
2126                     if( i == nLen )
2127                         bStrComplete = true;
2128 
2129                     if( bStrComplete )
2130                         aValueStr = aBuf.makeStringAndClear();
2131                 }
2132 
2133                 // Push into table
2134                 pLocaleItem->m_aIdToStringMap[ aResourceID ] = aValueStr;
2135                 implScanIdForNumber( aResourceID );
2136                 IdToIndexMap& rIndexMap = pLocaleItem->m_aIdToIndexMap;
2137                 rIndexMap[ aResourceID ] = pLocaleItem->m_nNextIndex++;
2138             }
2139         }
2140     }
2141 
2142     return bSuccess;
2143 }
2144 
2145 
2146 inline sal_Unicode getHexCharForDigit( sal_uInt16 nDigitVal )
2147 {
2148     sal_Unicode cRet = ( nDigitVal < 10 ) ? ('0' + nDigitVal) : ('a' + (nDigitVal-10));
2149     return cRet;
2150 }
2151 
2152 void implWriteCharToBuffer( ::rtl::OUStringBuffer& aBuf, sal_Unicode cu, bool bKey )
2153 {
2154     if( cu == '\\' )
2155     {
2156         aBuf.append( (sal_Unicode)'\\' );
2157         aBuf.append( (sal_Unicode)'\\' );
2158     }
2159     else if( cu == 0x000a )
2160     {
2161         aBuf.append( (sal_Unicode)'\\' );
2162         aBuf.append( (sal_Unicode)'n' );
2163     }
2164     else if( cu == 0x000d )
2165     {
2166         aBuf.append( (sal_Unicode)'\\' );
2167         aBuf.append( (sal_Unicode)'r' );
2168     }
2169     else if( bKey && cu == '=' )
2170     {
2171         aBuf.append( (sal_Unicode)'\\' );
2172         aBuf.append( (sal_Unicode)'=' );
2173     }
2174     else if( bKey && cu == ':' )
2175     {
2176         aBuf.append( (sal_Unicode)'\\' );
2177         aBuf.append( (sal_Unicode)':' );
2178     }
2179     // ISO/IEC 8859-1 range according to:
2180     // http://en.wikipedia.org/wiki/ISO/IEC_8859-1
2181     else if( (cu >= 0x20 && cu <= 0x7e) )
2182     //TODO: Check why (cu >= 0xa0 && cu <= 0xFF)
2183     //is encoded in sample properties files
2184     //else if( (cu >= 0x20 && cu <= 0x7e) ||
2185     //       (cu >= 0xa0 && cu <= 0xFF) )
2186     {
2187         aBuf.append( cu );
2188     }
2189     else
2190     {
2191         // Unicode encoding
2192         aBuf.append( (sal_Unicode)'\\' );
2193         aBuf.append( (sal_Unicode)'u' );
2194 
2195         sal_uInt16 nVal = cu;
2196         for( sal_uInt16 i = 0 ; i < 4 ; i++ )
2197         {
2198             sal_uInt16 nDigit = nVal / 0x1000;
2199             nVal -= nDigit * 0x1000;
2200             nVal *= 0x10;
2201             aBuf.append( getHexCharForDigit( nDigit ) );
2202         }
2203     }
2204 }
2205 
2206 void implWriteStringWithEncoding( const ::rtl::OUString& aStr,
2207     Reference< io::XTextOutputStream > xTextOutputStream, bool bKey )
2208 {
2209     static sal_Unicode cLineFeed = 0xa;
2210 
2211     (void)aStr;
2212     (void)xTextOutputStream;
2213 
2214     ::rtl::OUStringBuffer aBuf;
2215     sal_Int32 nLen = aStr.getLength();
2216     const sal_Unicode* pSrc = aStr.getStr();
2217     for( sal_Int32 i = 0 ; i < nLen ; i++ )
2218     {
2219         sal_Unicode cu = pSrc[i];
2220         implWriteCharToBuffer( aBuf, cu, bKey );
2221         // TODO?: split long lines
2222     }
2223     if( !bKey )
2224         aBuf.append( cLineFeed );
2225 
2226     ::rtl::OUString aWriteStr = aBuf.makeStringAndClear();
2227     xTextOutputStream->writeString( aWriteStr );
2228 }
2229 
2230 bool StringResourcePersistenceImpl::implWritePropertiesFile( LocaleItem* pLocaleItem,
2231     const Reference< io::XOutputStream >& xOutputStream, const ::rtl::OUString& aComment )
2232 {
2233     static ::rtl::OUString aAssignmentStr = ::rtl::OUString::createFromAscii( "=" );
2234     static ::rtl::OUString aLineFeedStr = ::rtl::OUString::createFromAscii( "\n" );
2235 
2236     if( !xOutputStream.is() || pLocaleItem == NULL )
2237         return false;
2238 
2239     bool bSuccess = false;
2240     Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory();
2241     Reference< io::XTextOutputStream > xTextOutputStream( xMCF->createInstanceWithContext
2242         ( ::rtl::OUString::createFromAscii( "com.sun.star.io.TextOutputStream" ), m_xContext ), UNO_QUERY );
2243 
2244     if( xTextOutputStream.is() )
2245     {
2246         Reference< io::XActiveDataSource> xActiveDataSource( xTextOutputStream, UNO_QUERY );
2247         if( xActiveDataSource.is() )
2248         {
2249             xActiveDataSource->setOutputStream( xOutputStream );
2250 
2251             ::rtl::OUString aEncodingStr = ::rtl::OUString::createFromAscii
2252                 ( rtl_getMimeCharsetFromTextEncoding( RTL_TEXTENCODING_ISO_8859_1 ) );
2253             xTextOutputStream->setEncoding( aEncodingStr );
2254 
2255             xTextOutputStream->writeString( aComment );
2256             xTextOutputStream->writeString( aLineFeedStr );
2257 
2258             const IdToStringMap& rHashMap = pLocaleItem->m_aIdToStringMap;
2259             if( rHashMap.size() > 0 )
2260             {
2261                 // Sort ids according to read order
2262                 const IdToIndexMap& rIndexMap = pLocaleItem->m_aIdToIndexMap;
2263                 IdToIndexMap::const_iterator it_index;
2264 
2265                 // Find max/min index
2266                 sal_Int32 nMinIndex = -1;
2267                 sal_Int32 nMaxIndex = -1;
2268                 for( it_index = rIndexMap.begin(); it_index != rIndexMap.end(); it_index++ )
2269                 {
2270                     sal_Int32 nIndex = (*it_index).second;
2271                     if( nMinIndex > nIndex || nMinIndex == -1 )
2272                         nMinIndex = nIndex;
2273                     if( nMaxIndex < nIndex )
2274                         nMaxIndex = nIndex;
2275                 }
2276                 sal_Int32 nTabSize = nMaxIndex - nMinIndex + 1;
2277 
2278                 // Create sorted array of pointers to the id strings
2279                 const ::rtl::OUString** pIdPtrs = new const ::rtl::OUString*[nTabSize];
2280                 sal_Int32 i;
2281                 for( i = 0 ; i < nTabSize ; i++ )
2282                     pIdPtrs[i] = NULL;
2283                 for( it_index = rIndexMap.begin(); it_index != rIndexMap.end(); it_index++ )
2284                 {
2285                     sal_Int32 nIndex = (*it_index).second;
2286                     pIdPtrs[nIndex - nMinIndex] = &((*it_index).first);
2287                 }
2288 
2289                 // Write lines in correct order
2290                 for( i = 0 ; i < nTabSize ; i++ )
2291                 {
2292                     const ::rtl::OUString* pStr = pIdPtrs[i];
2293                     if( pStr != NULL )
2294                     {
2295                         ::rtl::OUString aResourceID = *pStr;
2296                         IdToStringMap::const_iterator it = rHashMap.find( aResourceID );
2297                         if( !( it == rHashMap.end() ) )
2298                         {
2299                             implWriteStringWithEncoding( aResourceID, xTextOutputStream, true );
2300                             xTextOutputStream->writeString( aAssignmentStr );
2301                             ::rtl::OUString aValStr = (*it).second;
2302                             implWriteStringWithEncoding( aValStr, xTextOutputStream, false );
2303                         }
2304                     }
2305                 }
2306 
2307                 delete pIdPtrs;
2308             }
2309 
2310             bSuccess = true;
2311         }
2312     }
2313     return bSuccess;
2314 }
2315 
2316 
2317 // =============================================================================
2318 // StringResourceWithStorageImpl
2319 // =============================================================================
2320 
2321 // component operations
2322 static Sequence< ::rtl::OUString > getSupportedServiceNames_StringResourceWithStorageImpl()
2323 {
2324     Sequence< ::rtl::OUString > names(1);
2325     names[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.resource.StringResourceWithStorage") );
2326     return names;
2327 }
2328 
2329 static ::rtl::OUString getImplementationName_StringResourceWithStorageImpl()
2330 {
2331     return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.scripting.StringResourceWithStorage") );
2332 }
2333 
2334 static Reference< XInterface > SAL_CALL create_StringResourceWithStorageImpl(
2335     Reference< XComponentContext > const & xContext )
2336     SAL_THROW( () )
2337 {
2338     return static_cast< ::cppu::OWeakObject * >( new StringResourceWithStorageImpl( xContext ) );
2339 }
2340 
2341 // -----------------------------------------------------------------------------
2342 
2343 StringResourceWithStorageImpl::StringResourceWithStorageImpl( const Reference< XComponentContext >& rxContext )
2344     : StringResourceWithStorageImpl_BASE( rxContext )
2345     , m_bStorageChanged( false )
2346 {
2347 }
2348 
2349 // -----------------------------------------------------------------------------
2350 
2351 StringResourceWithStorageImpl::~StringResourceWithStorageImpl()
2352 {
2353 }
2354 
2355 // -----------------------------------------------------------------------------
2356 // XServiceInfo
2357 // -----------------------------------------------------------------------------
2358 
2359 ::rtl::OUString StringResourceWithStorageImpl::getImplementationName(  ) throw (RuntimeException)
2360 {
2361     return getImplementationName_StringResourceWithStorageImpl();
2362 }
2363 
2364 // -----------------------------------------------------------------------------
2365 
2366 sal_Bool StringResourceWithStorageImpl::supportsService( const ::rtl::OUString& rServiceName ) throw (RuntimeException)
2367 {
2368     Sequence< ::rtl::OUString > aNames( getSupportedServiceNames() );
2369     const ::rtl::OUString* pNames = aNames.getConstArray();
2370     const ::rtl::OUString* pEnd = pNames + aNames.getLength();
2371     for ( ; pNames != pEnd && !pNames->equals( rServiceName ); ++pNames )
2372         ;
2373 
2374     return pNames != pEnd;
2375 }
2376 
2377 // -----------------------------------------------------------------------------
2378 
2379 Sequence< ::rtl::OUString > StringResourceWithStorageImpl::getSupportedServiceNames(  ) throw (RuntimeException)
2380 {
2381     return getSupportedServiceNames_StringResourceWithStorageImpl();
2382 }
2383 
2384 // -----------------------------------------------------------------------------
2385 // XInitialization
2386 // -----------------------------------------------------------------------------
2387 
2388 void StringResourceWithStorageImpl::initialize( const Sequence< Any >& aArguments )
2389     throw (Exception, RuntimeException)
2390 {
2391     ::osl::MutexGuard aGuard( getMutex() );
2392 
2393     if ( aArguments.getLength() != 5 )
2394     {
2395         throw RuntimeException(
2396             ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StringResourceWithStorageImpl::initialize: invalid number of arguments!" ) ),
2397             Reference< XInterface >() );
2398     }
2399 
2400     bool bOk = (aArguments[0] >>= m_xStorage);
2401     if( bOk && !m_xStorage.is() )
2402         bOk = false;
2403 
2404     if( !bOk )
2405     {
2406         ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceWithStorageImpl::initialize: invalid storage" );
2407         throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 );
2408     }
2409 
2410     implInitializeCommonParameters( aArguments );
2411 }
2412 
2413 // -----------------------------------------------------------------------------
2414 // Forwarding calls to base class
2415 
2416 // XModifyBroadcaster
2417 void StringResourceWithStorageImpl::addModifyListener( const Reference< XModifyListener >& aListener )
2418     throw (RuntimeException)
2419 {
2420     StringResourceImpl::addModifyListener( aListener );
2421 }
2422 void StringResourceWithStorageImpl::removeModifyListener( const Reference< XModifyListener >& aListener )
2423     throw (RuntimeException)
2424 {
2425     StringResourceImpl::removeModifyListener( aListener );
2426 }
2427 
2428 // XStringResourceResolver
2429 ::rtl::OUString StringResourceWithStorageImpl::resolveString( const ::rtl::OUString& ResourceID )
2430     throw (::com::sun::star::resource::MissingResourceException, RuntimeException)
2431 {
2432     return StringResourceImpl::resolveString( ResourceID ) ;
2433 }
2434 ::rtl::OUString StringResourceWithStorageImpl::resolveStringForLocale( const ::rtl::OUString& ResourceID, const Locale& locale )
2435     throw ( ::com::sun::star::resource::MissingResourceException, RuntimeException)
2436 {
2437     return StringResourceImpl::resolveStringForLocale( ResourceID, locale );
2438 }
2439 sal_Bool StringResourceWithStorageImpl::hasEntryForId( const ::rtl::OUString& ResourceID )
2440     throw (RuntimeException)
2441 {
2442     return StringResourceImpl::hasEntryForId( ResourceID ) ;
2443 }
2444 sal_Bool StringResourceWithStorageImpl::hasEntryForIdAndLocale( const ::rtl::OUString& ResourceID,
2445     const Locale& locale )
2446         throw (RuntimeException)
2447 {
2448     return StringResourceImpl::hasEntryForIdAndLocale( ResourceID, locale );
2449 }
2450 Sequence< ::rtl::OUString > StringResourceWithStorageImpl::getResourceIDs(  )
2451     throw (RuntimeException)
2452 {
2453     return StringResourceImpl::getResourceIDs();
2454 }
2455 Sequence< ::rtl::OUString > StringResourceWithStorageImpl::getResourceIDsForLocale
2456     ( const Locale& locale ) throw (::com::sun::star::uno::RuntimeException)
2457 {
2458     return StringResourceImpl::getResourceIDsForLocale( locale );
2459 }
2460 Locale StringResourceWithStorageImpl::getCurrentLocale()
2461     throw (RuntimeException)
2462 {
2463     return StringResourceImpl::getCurrentLocale();
2464 }
2465 Locale StringResourceWithStorageImpl::getDefaultLocale(  )
2466     throw (RuntimeException)
2467 {
2468     return StringResourceImpl::getDefaultLocale();
2469 }
2470 Sequence< Locale > StringResourceWithStorageImpl::getLocales(  )
2471     throw (RuntimeException)
2472 {
2473     return StringResourceImpl::getLocales();
2474 }
2475 
2476 // XStringResourceManager
2477 sal_Bool StringResourceWithStorageImpl::isReadOnly()
2478     throw (RuntimeException)
2479 {
2480     return StringResourceImpl::isReadOnly();
2481 }
2482 void StringResourceWithStorageImpl::setCurrentLocale( const Locale& locale, sal_Bool FindClosestMatch )
2483     throw (IllegalArgumentException, RuntimeException)
2484 {
2485     StringResourceImpl::setCurrentLocale( locale, FindClosestMatch );
2486 }
2487 void StringResourceWithStorageImpl::setDefaultLocale( const Locale& locale )
2488     throw (IllegalArgumentException, RuntimeException,NoSupportException)
2489 {
2490     StringResourceImpl::setDefaultLocale( locale );
2491 }
2492 void StringResourceWithStorageImpl::setString( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str )
2493     throw (NoSupportException, RuntimeException)
2494 {
2495     StringResourceImpl::setString( ResourceID, Str );
2496 }
2497 void StringResourceWithStorageImpl::setStringForLocale
2498     ( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str, const Locale& locale )
2499         throw (NoSupportException, RuntimeException)
2500 {
2501     StringResourceImpl::setStringForLocale( ResourceID, Str, locale );
2502 }
2503 void StringResourceWithStorageImpl::removeId( const ::rtl::OUString& ResourceID )
2504     throw (::com::sun::star::resource::MissingResourceException, RuntimeException, NoSupportException)
2505 {
2506     StringResourceImpl::removeId( ResourceID );
2507 }
2508 void StringResourceWithStorageImpl::removeIdForLocale( const ::rtl::OUString& ResourceID, const Locale& locale )
2509     throw (::com::sun::star::resource::MissingResourceException, RuntimeException, NoSupportException)
2510 {
2511     StringResourceImpl::removeIdForLocale( ResourceID, locale );
2512 }
2513 void StringResourceWithStorageImpl::newLocale( const Locale& locale )
2514     throw (ElementExistException, IllegalArgumentException, RuntimeException, NoSupportException)
2515 {
2516     StringResourceImpl::newLocale( locale );
2517 }
2518 void StringResourceWithStorageImpl::removeLocale( const Locale& locale )
2519     throw (IllegalArgumentException, RuntimeException, NoSupportException)
2520 {
2521     StringResourceImpl::removeLocale( locale );
2522 }
2523 sal_Int32 StringResourceWithStorageImpl::getUniqueNumericId(  )
2524     throw (RuntimeException, NoSupportException)
2525 {
2526     return StringResourceImpl::getUniqueNumericId();
2527 }
2528 
2529 // XStringResourcePersistence
2530 void StringResourceWithStorageImpl::store()
2531     throw (NoSupportException, Exception, RuntimeException)
2532 {
2533     ::osl::MutexGuard aGuard( getMutex() );
2534     implCheckReadOnly( "StringResourceWithStorageImpl::store(): Read only" );
2535 
2536     bool bUsedForStore = true;
2537     bool bStoreAll = m_bStorageChanged;
2538     m_bStorageChanged = false;
2539     if( !m_bModified && !bStoreAll )
2540         return;
2541 
2542     implStoreAtStorage( m_aNameBase, m_aComment, m_xStorage, bUsedForStore, bStoreAll );
2543     m_bModified = false;
2544 }
2545 
2546 sal_Bool StringResourceWithStorageImpl::isModified(  )
2547     throw (RuntimeException)
2548 {
2549     return StringResourcePersistenceImpl::isModified();
2550 }
2551 void StringResourceWithStorageImpl::setComment( const ::rtl::OUString& Comment )
2552     throw (::com::sun::star::uno::RuntimeException)
2553 {
2554     StringResourcePersistenceImpl::setComment( Comment );
2555 }
2556 void StringResourceWithStorageImpl::storeToStorage( const Reference< XStorage >& Storage,
2557     const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment )
2558         throw (Exception, RuntimeException)
2559 {
2560     StringResourcePersistenceImpl::storeToStorage( Storage, NameBase, Comment );
2561 }
2562 void StringResourceWithStorageImpl::storeToURL( const ::rtl::OUString& URL,
2563     const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment,
2564     const Reference< ::com::sun::star::task::XInteractionHandler >& Handler )
2565         throw (Exception, RuntimeException)
2566 {
2567     StringResourcePersistenceImpl::storeToURL( URL, NameBase, Comment, Handler );
2568 }
2569 Sequence< ::sal_Int8 > StringResourceWithStorageImpl::exportBinary(  )
2570     throw (RuntimeException)
2571 {
2572     return StringResourcePersistenceImpl::exportBinary();
2573 }
2574 void StringResourceWithStorageImpl::importBinary( const Sequence< ::sal_Int8 >& Data )
2575     throw (IllegalArgumentException, RuntimeException)
2576 {
2577     StringResourcePersistenceImpl::importBinary( Data );
2578 }
2579 
2580 // -----------------------------------------------------------------------------
2581 // XStringResourceWithStorage
2582 
2583 void StringResourceWithStorageImpl::storeAsStorage( const Reference< XStorage >& Storage )
2584     throw (Exception, RuntimeException)
2585 {
2586     setStorage( Storage );
2587     store();
2588 }
2589 
2590 void StringResourceWithStorageImpl::setStorage( const Reference< XStorage >& Storage )
2591     throw (IllegalArgumentException, RuntimeException)
2592 {
2593     ::osl::MutexGuard aGuard( getMutex() );
2594 
2595     if( !Storage.is() )
2596     {
2597         ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii
2598             ( "StringResourceWithStorageImpl::setStorage: invalid storage" );
2599         throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 );
2600     }
2601 
2602     implLoadAllLocales();
2603 
2604     m_xStorage = Storage;
2605     m_bStorageChanged = true;
2606 }
2607 
2608 
2609 // =============================================================================
2610 // Private helper methods
2611 // =============================================================================
2612 
2613 // Scan locale properties files
2614 void StringResourceWithStorageImpl::implScanLocales( void )
2615 {
2616     Reference< container::XNameAccess > xNameAccess( m_xStorage, UNO_QUERY );
2617     if( xNameAccess.is() )
2618     {
2619         Sequence< ::rtl::OUString > aContentSeq = xNameAccess->getElementNames();
2620         implScanLocaleNames( aContentSeq );
2621     }
2622 
2623     implLoadAllLocales();
2624 }
2625 
2626 // Loading
2627 bool StringResourceWithStorageImpl::implLoadLocale( LocaleItem* pLocaleItem )
2628 {
2629     bool bSuccess = false;
2630     try
2631     {
2632         ::rtl::OUString aStreamName = implGetFileNameForLocaleItem( pLocaleItem, m_aNameBase );
2633         aStreamName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(".properties") );
2634 
2635         Reference< io::XStream > xElementStream =
2636             m_xStorage->openStreamElement( aStreamName, ElementModes::READ );
2637 
2638         if( xElementStream.is() )
2639         {
2640             Reference< io::XInputStream > xInputStream = xElementStream->getInputStream();
2641             if( xInputStream.is() )
2642             {
2643                 bSuccess = StringResourcePersistenceImpl::implReadPropertiesFile( pLocaleItem, xInputStream );
2644                 xInputStream->closeInput();
2645             }
2646         }
2647     }
2648     catch( uno::Exception& )
2649     {}
2650 
2651     return bSuccess;
2652 }
2653 
2654 
2655 // =============================================================================
2656 // StringResourceWithLocationImpl
2657 // =============================================================================
2658 
2659 // component operations
2660 static Sequence< ::rtl::OUString > getSupportedServiceNames_StringResourceWithLocationImpl()
2661 {
2662     Sequence< ::rtl::OUString > names(1);
2663     names[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.resource.StringResourceWithLocation") );
2664     return names;
2665 }
2666 
2667 static ::rtl::OUString getImplementationName_StringResourceWithLocationImpl()
2668 {
2669     return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.scripting.StringResourceWithLocation") );
2670 }
2671 
2672 static Reference< XInterface > SAL_CALL create_StringResourceWithLocationImpl(
2673     Reference< XComponentContext > const & xContext )
2674     SAL_THROW( () )
2675 {
2676     return static_cast< ::cppu::OWeakObject * >( new StringResourceWithLocationImpl( xContext ) );
2677 }
2678 
2679 // -----------------------------------------------------------------------------
2680 
2681 StringResourceWithLocationImpl::StringResourceWithLocationImpl( const Reference< XComponentContext >& rxContext )
2682     : StringResourceWithLocationImpl_BASE( rxContext )
2683     , m_bLocationChanged( false )
2684 {
2685 }
2686 
2687 // -----------------------------------------------------------------------------
2688 
2689 StringResourceWithLocationImpl::~StringResourceWithLocationImpl()
2690 {
2691 }
2692 
2693 // -----------------------------------------------------------------------------
2694 // XServiceInfo
2695 // -----------------------------------------------------------------------------
2696 
2697 ::rtl::OUString StringResourceWithLocationImpl::getImplementationName(  ) throw (RuntimeException)
2698 {
2699     return getImplementationName_StringResourceWithLocationImpl();
2700 }
2701 
2702 // -----------------------------------------------------------------------------
2703 
2704 sal_Bool StringResourceWithLocationImpl::supportsService( const ::rtl::OUString& rServiceName ) throw (RuntimeException)
2705 {
2706     Sequence< ::rtl::OUString > aNames( getSupportedServiceNames() );
2707     const ::rtl::OUString* pNames = aNames.getConstArray();
2708     const ::rtl::OUString* pEnd = pNames + aNames.getLength();
2709     for ( ; pNames != pEnd && !pNames->equals( rServiceName ); ++pNames )
2710         ;
2711 
2712     return pNames != pEnd;
2713 }
2714 
2715 // -----------------------------------------------------------------------------
2716 
2717 Sequence< ::rtl::OUString > StringResourceWithLocationImpl::getSupportedServiceNames(  ) throw (RuntimeException)
2718 {
2719     return getSupportedServiceNames_StringResourceWithLocationImpl();
2720 }
2721 
2722 // -----------------------------------------------------------------------------
2723 // XInitialization
2724 // -----------------------------------------------------------------------------
2725 
2726 void StringResourceWithLocationImpl::initialize( const Sequence< Any >& aArguments )
2727     throw (Exception, RuntimeException)
2728 {
2729     ::osl::MutexGuard aGuard( getMutex() );
2730 
2731     if ( aArguments.getLength() != 6 )
2732     {
2733         throw RuntimeException(
2734             ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM
2735                 ( "XInitialization::initialize: invalid number of arguments!" ) ),
2736             Reference< XInterface >() );
2737     }
2738 
2739     bool bOk = (aArguments[0] >>= m_aLocation);
2740     sal_Int32 nLen = m_aLocation.getLength();
2741     if( bOk && nLen == 0 )
2742     {
2743         bOk = false;
2744     }
2745     else
2746     {
2747         if( m_aLocation.getStr()[nLen - 1] != '/' )
2748             m_aLocation += ::rtl::OUString::createFromAscii( "/" );
2749     }
2750 
2751     if( !bOk )
2752     {
2753         ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "XInitialization::initialize: invalid URL" );
2754         throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 );
2755     }
2756 
2757 
2758     bOk = (aArguments[5] >>= m_xInteractionHandler);
2759     if( !bOk )
2760     {
2761         ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceWithStorageImpl::initialize: invalid type" );
2762         throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 5 );
2763     }
2764 
2765     implInitializeCommonParameters( aArguments );
2766 }
2767 
2768 // -----------------------------------------------------------------------------
2769 // Forwarding calls to base class
2770 
2771 // XModifyBroadcaster
2772 void StringResourceWithLocationImpl::addModifyListener( const Reference< XModifyListener >& aListener )
2773     throw (RuntimeException)
2774 {
2775     StringResourceImpl::addModifyListener( aListener );
2776 }
2777 void StringResourceWithLocationImpl::removeModifyListener( const Reference< XModifyListener >& aListener )
2778     throw (RuntimeException)
2779 {
2780     StringResourceImpl::removeModifyListener( aListener );
2781 }
2782 
2783 // XStringResourceResolver
2784 ::rtl::OUString StringResourceWithLocationImpl::resolveString( const ::rtl::OUString& ResourceID )
2785     throw (::com::sun::star::resource::MissingResourceException, RuntimeException)
2786 {
2787     return StringResourceImpl::resolveString( ResourceID ) ;
2788 }
2789 ::rtl::OUString StringResourceWithLocationImpl::resolveStringForLocale( const ::rtl::OUString& ResourceID, const Locale& locale )
2790     throw ( ::com::sun::star::resource::MissingResourceException, RuntimeException)
2791 {
2792     return StringResourceImpl::resolveStringForLocale( ResourceID, locale );
2793 }
2794 sal_Bool StringResourceWithLocationImpl::hasEntryForId( const ::rtl::OUString& ResourceID )
2795     throw (RuntimeException)
2796 {
2797     return StringResourceImpl::hasEntryForId( ResourceID ) ;
2798 }
2799 sal_Bool StringResourceWithLocationImpl::hasEntryForIdAndLocale( const ::rtl::OUString& ResourceID,
2800     const Locale& locale )
2801         throw (RuntimeException)
2802 {
2803     return StringResourceImpl::hasEntryForIdAndLocale( ResourceID, locale );
2804 }
2805 Sequence< ::rtl::OUString > StringResourceWithLocationImpl::getResourceIDs(  )
2806     throw (RuntimeException)
2807 {
2808     return StringResourceImpl::getResourceIDs();
2809 }
2810 Sequence< ::rtl::OUString > StringResourceWithLocationImpl::getResourceIDsForLocale
2811     ( const Locale& locale ) throw (::com::sun::star::uno::RuntimeException)
2812 {
2813     return StringResourceImpl::getResourceIDsForLocale( locale );
2814 }
2815 Locale StringResourceWithLocationImpl::getCurrentLocale()
2816     throw (RuntimeException)
2817 {
2818     return StringResourceImpl::getCurrentLocale();
2819 }
2820 Locale StringResourceWithLocationImpl::getDefaultLocale(  )
2821     throw (RuntimeException)
2822 {
2823     return StringResourceImpl::getDefaultLocale();
2824 }
2825 Sequence< Locale > StringResourceWithLocationImpl::getLocales(  )
2826     throw (RuntimeException)
2827 {
2828     return StringResourceImpl::getLocales();
2829 }
2830 
2831 // XStringResourceManager
2832 sal_Bool StringResourceWithLocationImpl::isReadOnly()
2833     throw (RuntimeException)
2834 {
2835     return StringResourceImpl::isReadOnly();
2836 }
2837 void StringResourceWithLocationImpl::setCurrentLocale( const Locale& locale, sal_Bool FindClosestMatch )
2838     throw (IllegalArgumentException, RuntimeException)
2839 {
2840     StringResourceImpl::setCurrentLocale( locale, FindClosestMatch );
2841 }
2842 void StringResourceWithLocationImpl::setDefaultLocale( const Locale& locale )
2843     throw (IllegalArgumentException, RuntimeException,NoSupportException)
2844 {
2845     StringResourceImpl::setDefaultLocale( locale );
2846 }
2847 void StringResourceWithLocationImpl::setString( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str )
2848     throw (NoSupportException, RuntimeException)
2849 {
2850     StringResourceImpl::setString( ResourceID, Str );
2851 }
2852 void StringResourceWithLocationImpl::setStringForLocale
2853     ( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str, const Locale& locale )
2854         throw (NoSupportException, RuntimeException)
2855 {
2856     StringResourceImpl::setStringForLocale( ResourceID, Str, locale );
2857 }
2858 void StringResourceWithLocationImpl::removeId( const ::rtl::OUString& ResourceID )
2859     throw (::com::sun::star::resource::MissingResourceException, RuntimeException, NoSupportException)
2860 {
2861     StringResourceImpl::removeId( ResourceID );
2862 }
2863 void StringResourceWithLocationImpl::removeIdForLocale( const ::rtl::OUString& ResourceID, const Locale& locale )
2864     throw (::com::sun::star::resource::MissingResourceException, RuntimeException, NoSupportException)
2865 {
2866     StringResourceImpl::removeIdForLocale( ResourceID, locale );
2867 }
2868 void StringResourceWithLocationImpl::newLocale( const Locale& locale )
2869     throw (ElementExistException, IllegalArgumentException, RuntimeException, NoSupportException)
2870 {
2871     StringResourceImpl::newLocale( locale );
2872 }
2873 void StringResourceWithLocationImpl::removeLocale( const Locale& locale )
2874     throw (IllegalArgumentException, RuntimeException, NoSupportException)
2875 {
2876     StringResourceImpl::removeLocale( locale );
2877 }
2878 sal_Int32 StringResourceWithLocationImpl::getUniqueNumericId(  )
2879     throw (RuntimeException, NoSupportException)
2880 {
2881     return StringResourceImpl::getUniqueNumericId();
2882 }
2883 
2884 // XStringResourcePersistence
2885 void StringResourceWithLocationImpl::store()
2886     throw (NoSupportException, Exception, RuntimeException)
2887 {
2888     ::osl::MutexGuard aGuard( getMutex() );
2889     implCheckReadOnly( "StringResourceWithLocationImpl::store(): Read only" );
2890 
2891     bool bUsedForStore = true;
2892     bool bStoreAll = m_bLocationChanged;
2893     m_bLocationChanged = false;
2894     if( !m_bModified && !bStoreAll )
2895         return;
2896 
2897     Reference< ucb::XSimpleFileAccess > xFileAccess = getFileAccess();
2898     implStoreAtLocation( m_aLocation, m_aNameBase, m_aComment,
2899         xFileAccess, bUsedForStore, bStoreAll );
2900     m_bModified = false;
2901 }
2902 
2903 sal_Bool StringResourceWithLocationImpl::isModified(  )
2904     throw (RuntimeException)
2905 {
2906     return StringResourcePersistenceImpl::isModified();
2907 }
2908 void StringResourceWithLocationImpl::setComment( const ::rtl::OUString& Comment )
2909     throw (::com::sun::star::uno::RuntimeException)
2910 {
2911     StringResourcePersistenceImpl::setComment( Comment );
2912 }
2913 void StringResourceWithLocationImpl::storeToStorage( const Reference< XStorage >& Storage,
2914     const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment )
2915         throw (Exception, RuntimeException)
2916 {
2917     StringResourcePersistenceImpl::storeToStorage( Storage, NameBase, Comment );
2918 }
2919 void StringResourceWithLocationImpl::storeToURL( const ::rtl::OUString& URL,
2920     const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment,
2921     const Reference< ::com::sun::star::task::XInteractionHandler >& Handler )
2922         throw (Exception, RuntimeException)
2923 {
2924     StringResourcePersistenceImpl::storeToURL( URL, NameBase, Comment, Handler );
2925 }
2926 Sequence< ::sal_Int8 > StringResourceWithLocationImpl::exportBinary(  )
2927     throw (RuntimeException)
2928 {
2929     return StringResourcePersistenceImpl::exportBinary();
2930 }
2931 void StringResourceWithLocationImpl::importBinary( const Sequence< ::sal_Int8 >& Data )
2932     throw (IllegalArgumentException, RuntimeException)
2933 {
2934     StringResourcePersistenceImpl::importBinary( Data );
2935 }
2936 
2937 // -----------------------------------------------------------------------------
2938 // XStringResourceWithLocation
2939 
2940 // XStringResourceWithLocation
2941 void StringResourceWithLocationImpl::storeAsURL( const ::rtl::OUString& URL )
2942     throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
2943 {
2944     setURL( URL );
2945     store();
2946 }
2947 
2948 void StringResourceWithLocationImpl::setURL( const ::rtl::OUString& URL )
2949     throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
2950 {
2951     ::osl::MutexGuard aGuard( getMutex() );
2952     implCheckReadOnly( "StringResourceWithLocationImpl::setURL(): Read only" );
2953 
2954     sal_Int32 nLen = URL.getLength();
2955     if( nLen == 0 )
2956     {
2957         ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii
2958             ( "StringResourceWithLocationImpl::setURL: invalid URL" );
2959         throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 );
2960     }
2961 
2962     implLoadAllLocales();
2963 
2964     // Delete files at old location
2965     bool bUsedForStore = false;
2966     bool bStoreAll = false;
2967     bool bKillAll = true;
2968     implStoreAtLocation( m_aLocation, m_aNameBase, m_aComment,
2969         getFileAccess(), bUsedForStore, bStoreAll, bKillAll );
2970 
2971     m_aLocation = URL;
2972     m_bLocationChanged = true;
2973 }
2974 
2975 
2976 // =============================================================================
2977 // Private helper methods
2978 // =============================================================================
2979 
2980 // Scan locale properties files
2981 void StringResourceWithLocationImpl::implScanLocales( void )
2982 {
2983     const Reference< ucb::XSimpleFileAccess > xFileAccess = getFileAccess();
2984     if( xFileAccess.is() && xFileAccess->isFolder( m_aLocation ) )
2985     {
2986         Sequence< ::rtl::OUString > aContentSeq = xFileAccess->getFolderContents( m_aLocation, false );
2987         implScanLocaleNames( aContentSeq );
2988     }
2989 }
2990 
2991 // Loading
2992 bool StringResourceWithLocationImpl::implLoadLocale( LocaleItem* pLocaleItem )
2993 {
2994     bool bSuccess = false;
2995 
2996     const Reference< ucb::XSimpleFileAccess > xFileAccess = getFileAccess();
2997     if( xFileAccess.is() )
2998     {
2999         ::rtl::OUString aCompleteFileName =
3000             implGetPathForLocaleItem( pLocaleItem, m_aNameBase, m_aLocation );
3001 
3002         Reference< io::XInputStream > xInputStream;
3003         try
3004         {
3005             xInputStream = xFileAccess->openFileRead( aCompleteFileName );
3006         }
3007         catch( Exception& )
3008         {}
3009         if( xInputStream.is() )
3010         {
3011             bSuccess = StringResourcePersistenceImpl::implReadPropertiesFile( pLocaleItem, xInputStream );
3012             xInputStream->closeInput();
3013         }
3014     }
3015 
3016     return bSuccess;
3017 }
3018 
3019 const Reference< ucb::XSimpleFileAccess > StringResourceWithLocationImpl::getFileAccess( void )
3020 {
3021     ::osl::MutexGuard aGuard( getMutex() );
3022 
3023     if( !m_xSFI.is() )
3024     {
3025         Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory();
3026         m_xSFI = Reference< ucb::XSimpleFileAccess >( xMCF->createInstanceWithContext
3027             ( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ), m_xContext ), UNO_QUERY );
3028 
3029         if( m_xSFI.is() && m_xInteractionHandler.is() )
3030             m_xSFI->setInteractionHandler( m_xInteractionHandler );
3031     }
3032     return m_xSFI;
3033 }
3034 
3035 
3036 // =============================================================================
3037 // component export operations
3038 // =============================================================================
3039 
3040 static struct ::cppu::ImplementationEntry s_component_entries [] =
3041 {
3042     {
3043         create_StringResourceImpl, getImplementationName_StringResourceImpl,
3044         getSupportedServiceNames_StringResourceImpl,
3045         ::cppu::createSingleComponentFactory,
3046         0, 0
3047     },
3048     {
3049         create_StringResourceWithLocationImpl, getImplementationName_StringResourceWithLocationImpl,
3050         getSupportedServiceNames_StringResourceWithLocationImpl,
3051         ::cppu::createSingleComponentFactory,
3052         0, 0
3053     },
3054     {
3055         create_StringResourceWithStorageImpl, getImplementationName_StringResourceWithStorageImpl,
3056         getSupportedServiceNames_StringResourceWithStorageImpl,
3057         ::cppu::createSingleComponentFactory,
3058         0, 0
3059     },
3060     { 0, 0, 0, 0, 0, 0 }
3061 };
3062 
3063 
3064 //.........................................................................
3065 }   // namespace dlgprov
3066 //.........................................................................
3067 
3068 
3069 // =============================================================================
3070 // component exports
3071 // =============================================================================
3072 
3073 extern "C"
3074 {
3075     void SAL_CALL component_getImplementationEnvironment(
3076         const sal_Char ** ppEnvTypeName, uno_Environment ** ppEnv )
3077     {
3078         (void)ppEnv;
3079 
3080         *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
3081     }
3082 
3083     void * SAL_CALL component_getFactory(
3084         const sal_Char * pImplName, lang::XMultiServiceFactory * pServiceManager,
3085         registry::XRegistryKey * pRegistryKey )
3086     {
3087         return ::cppu::component_getFactoryHelper(
3088             pImplName, pServiceManager, pRegistryKey, ::stringresource::s_component_entries );
3089     }
3090 }
3091