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