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