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