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