1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "stringresource.hxx"
22 #include <com/sun/star/io/TempFile.hpp>
23 #include <com/sun/star/io/TextInputStream.hpp>
24 #include <com/sun/star/io/TextOutputStream.hpp>
25 #include <com/sun/star/io/XStream.hpp>
26 #include <com/sun/star/io/XSeekable.hpp>
27 #include <com/sun/star/embed/ElementModes.hpp>
28 #include <com/sun/star/lang/NoSupportException.hpp>
29 #include <com/sun/star/resource/MissingResourceException.hpp>
30 #include <cppuhelper/implementationentry.hxx>
31 #include <cppuhelper/supportsservice.hxx>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/container/ElementExistException.hpp>
34 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
36 #include <osl/diagnose.h>
37 #include <rtl/tencinfo.h>
38 #include <rtl/ustrbuf.hxx>
39 #include <tools/urlobj.hxx>
40 #include <i18nlangtag/languagetag.hxx>
42 using namespace ::com::sun::star
;
43 using namespace ::com::sun::star::lang
;
44 using namespace ::com::sun::star::uno
;
45 using namespace ::com::sun::star::ucb
;
46 using namespace ::com::sun::star::util
;
47 using namespace ::com::sun::star::embed
;
48 using namespace ::com::sun::star::container
;
51 namespace stringresource
58 ::osl::Mutex
& getMutex()
60 static ::osl::Mutex s_aMutex
;
68 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
69 scripting_StringResourcePersistenceImpl_implementation(
70 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
72 return cppu::acquire(new StringResourcePersistenceImpl(context
));
76 StringResourceImpl::StringResourceImpl( const Reference
< XComponentContext
>& rxContext
)
77 : m_xContext( rxContext
)
78 , m_pCurrentLocaleItem( nullptr )
79 , m_pDefaultLocaleItem( nullptr )
80 , m_bDefaultModified( false )
81 , m_aListenerContainer( getMutex() )
82 , m_bModified( false )
83 , m_bReadOnly( false )
84 , m_nNextUniqueNumericId( UNIQUE_NUMBER_NEEDS_INITIALISATION
)
89 StringResourceImpl::~StringResourceImpl()
96 OUString
StringResourceImpl::getImplementationName( )
98 return "com.sun.star.comp.scripting.StringResource";
101 sal_Bool
StringResourceImpl::supportsService( const OUString
& rServiceName
)
103 return cppu::supportsService(this, rServiceName
);
106 Sequence
< OUString
> StringResourceImpl::getSupportedServiceNames( )
108 return { "com.sun.star.resource.StringResource" };
112 // XModifyBroadcaster
114 void StringResourceImpl::addModifyListener( const Reference
< XModifyListener
>& aListener
)
116 if( !aListener
.is() )
117 throw RuntimeException();
119 ::osl::MutexGuard
aGuard( getMutex() );
120 m_aListenerContainer
.addInterface( Reference
<XInterface
>( aListener
, UNO_QUERY
) );
123 void StringResourceImpl::removeModifyListener( const Reference
< XModifyListener
>& aListener
)
125 if( !aListener
.is() )
126 throw RuntimeException();
128 ::osl::MutexGuard
aGuard( getMutex() );
129 m_aListenerContainer
.removeInterface( Reference
<XInterface
>( aListener
, UNO_QUERY
) );
133 // XStringResourceResolver
135 OUString
StringResourceImpl::implResolveString
136 ( const OUString
& ResourceID
, LocaleItem
* pLocaleItem
)
139 bool bSuccess
= false;
140 if( pLocaleItem
!= nullptr && loadLocale( pLocaleItem
) )
142 IdToStringMap::iterator it
= pLocaleItem
->m_aIdToStringMap
.find( ResourceID
);
143 if( it
!= pLocaleItem
->m_aIdToStringMap
.end() )
145 aRetStr
= (*it
).second
;
151 throw css::resource::MissingResourceException( "StringResourceImpl: No entry for ResourceID: " + ResourceID
);
156 OUString
StringResourceImpl::resolveString( const OUString
& ResourceID
)
158 ::osl::MutexGuard
aGuard( getMutex() );
159 return implResolveString( ResourceID
, m_pCurrentLocaleItem
);
162 OUString
StringResourceImpl::resolveStringForLocale( const OUString
& ResourceID
, const Locale
& locale
)
164 ::osl::MutexGuard
aGuard( getMutex() );
165 LocaleItem
* pLocaleItem
= getItemForLocale( locale
, false );
166 return implResolveString( ResourceID
, pLocaleItem
);
169 bool StringResourceImpl::implHasEntryForId( const OUString
& ResourceID
, LocaleItem
* pLocaleItem
)
171 bool bSuccess
= false;
172 if( pLocaleItem
!= nullptr && loadLocale( pLocaleItem
) )
174 IdToStringMap::iterator it
= pLocaleItem
->m_aIdToStringMap
.find( ResourceID
);
175 if( it
!= pLocaleItem
->m_aIdToStringMap
.end() )
181 sal_Bool
StringResourceImpl::hasEntryForId( const OUString
& ResourceID
)
183 ::osl::MutexGuard
aGuard( getMutex() );
184 return implHasEntryForId( ResourceID
, m_pCurrentLocaleItem
);
187 sal_Bool
StringResourceImpl::hasEntryForIdAndLocale( const OUString
& ResourceID
,
188 const Locale
& locale
)
190 ::osl::MutexGuard
aGuard( getMutex() );
191 LocaleItem
* pLocaleItem
= getItemForLocale( locale
, false );
192 return implHasEntryForId( ResourceID
, pLocaleItem
);
195 Sequence
< OUString
> StringResourceImpl::implGetResourceIDs( LocaleItem
* pLocaleItem
)
197 Sequence
< OUString
> aIDSeq( 0 );
198 if( pLocaleItem
&& loadLocale( pLocaleItem
) )
200 const IdToStringMap
& rHashMap
= pLocaleItem
->m_aIdToStringMap
;
201 sal_Int32 nResourceIDCount
= rHashMap
.size();
202 aIDSeq
.realloc( nResourceIDCount
);
203 OUString
* pStrings
= aIDSeq
.getArray();
206 for( const auto& rEntry
: rHashMap
)
208 OUString aStr
= rEntry
.first
;
209 pStrings
[iTarget
] = aStr
;
216 Sequence
< OUString
> StringResourceImpl::getResourceIDsForLocale
217 ( const Locale
& locale
)
219 ::osl::MutexGuard
aGuard( getMutex() );
220 LocaleItem
* pLocaleItem
= getItemForLocale( locale
, false );
221 return implGetResourceIDs( pLocaleItem
);
224 Sequence
< OUString
> StringResourceImpl::getResourceIDs( )
226 ::osl::MutexGuard
aGuard( getMutex() );
227 return implGetResourceIDs( m_pCurrentLocaleItem
);
230 Locale
StringResourceImpl::getCurrentLocale()
232 ::osl::MutexGuard
aGuard( getMutex() );
235 if( m_pCurrentLocaleItem
!= nullptr )
236 aRetLocale
= m_pCurrentLocaleItem
->m_locale
;
240 Locale
StringResourceImpl::getDefaultLocale( )
242 ::osl::MutexGuard
aGuard( getMutex() );
245 if( m_pDefaultLocaleItem
!= nullptr )
246 aRetLocale
= m_pDefaultLocaleItem
->m_locale
;
250 Sequence
< Locale
> StringResourceImpl::getLocales( )
252 ::osl::MutexGuard
aGuard( getMutex() );
254 sal_Int32 nSize
= m_aLocaleItemVector
.size();
255 Sequence
< Locale
> aLocalSeq( nSize
);
256 Locale
* pLocales
= aLocalSeq
.getArray();
258 for( const auto& pLocaleItem
: m_aLocaleItemVector
)
260 pLocales
[iTarget
] = pLocaleItem
->m_locale
;
267 // XStringResourceManager
269 void StringResourceImpl::implCheckReadOnly( const char* pExceptionMsg
)
273 OUString errorMsg
= OUString::createFromAscii( pExceptionMsg
);
274 throw NoSupportException( errorMsg
);
278 sal_Bool
StringResourceImpl::isReadOnly()
283 void StringResourceImpl::implSetCurrentLocale( const Locale
& locale
,
284 bool FindClosestMatch
, bool bUseDefaultIfNoMatch
)
286 ::osl::MutexGuard
aGuard( getMutex() );
288 LocaleItem
* pLocaleItem
= nullptr;
289 if( FindClosestMatch
)
290 pLocaleItem
= getClosestMatchItemForLocale( locale
);
292 pLocaleItem
= getItemForLocale( locale
, true );
294 if( pLocaleItem
== nullptr && bUseDefaultIfNoMatch
)
295 pLocaleItem
= m_pDefaultLocaleItem
;
297 if( pLocaleItem
!= nullptr )
299 (void)loadLocale( pLocaleItem
);
300 m_pCurrentLocaleItem
= pLocaleItem
;
302 // Only notify without modifying
303 implNotifyListeners();
307 void StringResourceImpl::setCurrentLocale( const Locale
& locale
, sal_Bool FindClosestMatch
)
309 implSetCurrentLocale( locale
, FindClosestMatch
, false/*bUseDefaultIfNoMatch*/ );
312 void StringResourceImpl::setDefaultLocale( const Locale
& locale
)
314 ::osl::MutexGuard
aGuard( getMutex() );
315 implCheckReadOnly( "StringResourceImpl::setDefaultLocale(): Read only" );
317 LocaleItem
* pLocaleItem
= getItemForLocale( locale
, true );
318 if( pLocaleItem
&& pLocaleItem
!= m_pDefaultLocaleItem
)
320 if( m_pDefaultLocaleItem
)
322 m_aChangedDefaultLocaleVector
.push_back(
323 std::make_unique
<LocaleItem
>( m_pDefaultLocaleItem
->m_locale
) );
326 m_pDefaultLocaleItem
= pLocaleItem
;
327 m_bDefaultModified
= true;
332 void StringResourceImpl::implSetString( const OUString
& ResourceID
,
333 const OUString
& Str
, LocaleItem
* pLocaleItem
)
335 if( !(pLocaleItem
!= nullptr && loadLocale( pLocaleItem
)) )
338 IdToStringMap
& rHashMap
= pLocaleItem
->m_aIdToStringMap
;
340 IdToStringMap::iterator it
= rHashMap
.find( ResourceID
);
341 bool bNew
= ( it
== rHashMap
.end() );
344 IdToIndexMap
& rIndexMap
= pLocaleItem
->m_aIdToIndexMap
;
345 rIndexMap
[ ResourceID
] = pLocaleItem
->m_nNextIndex
++;
346 implScanIdForNumber( ResourceID
);
348 rHashMap
[ ResourceID
] = Str
;
349 pLocaleItem
->m_bModified
= true;
353 void StringResourceImpl::setString( const OUString
& ResourceID
, const OUString
& Str
)
355 ::osl::MutexGuard
aGuard( getMutex() );
356 implCheckReadOnly( "StringResourceImpl::setString(): Read only" );
357 implSetString( ResourceID
, Str
, m_pCurrentLocaleItem
);
360 void StringResourceImpl::setStringForLocale
361 ( const OUString
& ResourceID
, const OUString
& Str
, const Locale
& locale
)
363 ::osl::MutexGuard
aGuard( getMutex() );
364 implCheckReadOnly( "StringResourceImpl::setStringForLocale(): Read only" );
365 LocaleItem
* pLocaleItem
= getItemForLocale( locale
, false );
366 implSetString( ResourceID
, Str
, pLocaleItem
);
369 void StringResourceImpl::implRemoveId( const OUString
& ResourceID
, LocaleItem
* pLocaleItem
)
371 if( pLocaleItem
!= nullptr && loadLocale( pLocaleItem
) )
373 IdToStringMap
& rHashMap
= pLocaleItem
->m_aIdToStringMap
;
374 IdToStringMap::iterator it
= rHashMap
.find( ResourceID
);
375 if( it
== rHashMap
.end() )
377 throw css::resource::MissingResourceException( "StringResourceImpl: No entries for ResourceID: " + ResourceID
);
379 rHashMap
.erase( it
);
380 pLocaleItem
->m_bModified
= true;
385 void StringResourceImpl::removeId( const OUString
& ResourceID
)
387 ::osl::MutexGuard
aGuard( getMutex() );
388 implCheckReadOnly( "StringResourceImpl::removeId(): Read only" );
389 implRemoveId( ResourceID
, m_pCurrentLocaleItem
);
392 void StringResourceImpl::removeIdForLocale( const OUString
& ResourceID
, const Locale
& locale
)
394 ::osl::MutexGuard
aGuard( getMutex() );
395 implCheckReadOnly( "StringResourceImpl::removeIdForLocale(): Read only" );
396 LocaleItem
* pLocaleItem
= getItemForLocale( locale
, false );
397 implRemoveId( ResourceID
, pLocaleItem
);
400 void StringResourceImpl::newLocale( const Locale
& locale
)
402 ::osl::MutexGuard
aGuard( getMutex() );
403 implCheckReadOnly( "StringResourceImpl::newLocale(): Read only" );
405 if( getItemForLocale( locale
, false ) != nullptr )
407 throw ElementExistException( "StringResourceImpl: locale already exists" );
410 // TODO?: Check if locale is valid? How?
413 // OUString errorMsg("StringResourceImpl: Invalid locale");
414 // throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 );
417 LocaleItem
* pLocaleItem
= new LocaleItem( locale
);
418 m_aLocaleItemVector
.emplace_back( pLocaleItem
);
419 pLocaleItem
->m_bModified
= true;
421 // Copy strings from default locale
422 LocaleItem
* pCopyFromItem
= m_pDefaultLocaleItem
;
423 if( pCopyFromItem
== nullptr )
424 pCopyFromItem
= m_pCurrentLocaleItem
;
425 if( pCopyFromItem
!= nullptr && loadLocale( pCopyFromItem
) )
427 const IdToStringMap
& rSourceMap
= pCopyFromItem
->m_aIdToStringMap
;
428 IdToStringMap
& rTargetMap
= pLocaleItem
->m_aIdToStringMap
;
429 for( const auto& rEntry
: rSourceMap
)
431 OUString aId
= rEntry
.first
;
432 OUString aStr
= rEntry
.second
;
433 rTargetMap
[ aId
] = aStr
;
436 const IdToIndexMap
& rSourceIndexMap
= pCopyFromItem
->m_aIdToIndexMap
;
437 IdToIndexMap
& rTargetIndexMap
= pLocaleItem
->m_aIdToIndexMap
;
438 for( const auto& rIndex
: rSourceIndexMap
)
440 OUString aId
= rIndex
.first
;
441 sal_Int32 nIndex
= rIndex
.second
;
442 rTargetIndexMap
[ aId
] = nIndex
;
444 pLocaleItem
->m_nNextIndex
= pCopyFromItem
->m_nNextIndex
;
447 if( m_pCurrentLocaleItem
== nullptr )
448 m_pCurrentLocaleItem
= pLocaleItem
;
450 if( m_pDefaultLocaleItem
== nullptr )
452 m_pDefaultLocaleItem
= pLocaleItem
;
453 m_bDefaultModified
= true;
459 void StringResourceImpl::removeLocale( const Locale
& locale
)
461 ::osl::MutexGuard
aGuard( getMutex() );
462 implCheckReadOnly( "StringResourceImpl::removeLocale(): Read only" );
464 LocaleItem
* pRemoveItem
= getItemForLocale( locale
, true );
469 sal_Int32 nLocaleCount
= m_aLocaleItemVector
.size();
470 if( nLocaleCount
> 1 )
472 if( m_pCurrentLocaleItem
== pRemoveItem
||
473 m_pDefaultLocaleItem
== pRemoveItem
)
475 LocaleItem
* pFallbackItem
= nullptr;
476 for( const auto& pLocaleItem
: m_aLocaleItemVector
)
478 if( pLocaleItem
.get() != pRemoveItem
)
480 pFallbackItem
= pLocaleItem
.get();
484 if( m_pCurrentLocaleItem
== pRemoveItem
)
486 setCurrentLocale( pFallbackItem
->m_locale
, false/*FindClosestMatch*/ );
488 if( m_pDefaultLocaleItem
== pRemoveItem
)
490 setDefaultLocale( pFallbackItem
->m_locale
);
494 auto it
= std::find_if(m_aLocaleItemVector
.begin(), m_aLocaleItemVector
.end(),
495 [&pRemoveItem
](const std::unique_ptr
<LocaleItem
>& rxItem
) { return rxItem
.get() == pRemoveItem
; });
496 if (it
== m_aLocaleItemVector
.end())
499 // Remember locale item to delete file while storing
500 m_aDeletedLocaleItemVector
.push_back( std::move(*it
) );
503 if( nLocaleCount
== 1 )
505 m_nNextUniqueNumericId
= 0;
506 if( m_pDefaultLocaleItem
)
508 m_aChangedDefaultLocaleVector
.push_back(
509 std::make_unique
<LocaleItem
>( m_pDefaultLocaleItem
->m_locale
) );
511 m_pCurrentLocaleItem
= nullptr;
512 m_pDefaultLocaleItem
= nullptr;
515 m_aLocaleItemVector
.erase( it
);
520 void StringResourceImpl::implScanIdForNumber( const OUString
& ResourceID
)
522 const sal_Unicode
* pSrc
= ResourceID
.getStr();
523 sal_Int32 nLen
= ResourceID
.getLength();
525 sal_Int32 nNumber
= 0;
526 for( sal_Int32 i
= 0 ; i
< nLen
; i
++ )
528 sal_Unicode c
= pSrc
[i
];
529 if( c
>= '0' && c
<= '9' )
531 sal_uInt16 nDigitVal
= c
- '0';
532 nNumber
= 10*nNumber
+ nDigitVal
;
538 if( m_nNextUniqueNumericId
< nNumber
+ 1 )
539 m_nNextUniqueNumericId
= nNumber
+ 1;
542 sal_Int32
StringResourceImpl::getUniqueNumericId( )
544 if( m_nNextUniqueNumericId
== UNIQUE_NUMBER_NEEDS_INITIALISATION
)
546 implLoadAllLocales();
547 m_nNextUniqueNumericId
= 0;
550 if( m_nNextUniqueNumericId
< UNIQUE_NUMBER_NEEDS_INITIALISATION
)
552 throw NoSupportException( "getUniqueNumericId: Extended sal_Int32 range" );
554 return m_nNextUniqueNumericId
;
558 // Private helper methods
560 LocaleItem
* StringResourceImpl::getItemForLocale
561 ( const Locale
& locale
, bool bException
)
563 LocaleItem
* pRetItem
= nullptr;
566 for( auto& pLocaleItem
: m_aLocaleItemVector
)
570 Locale
& cmp_locale
= pLocaleItem
->m_locale
;
571 if( cmp_locale
.Language
== locale
.Language
&&
572 cmp_locale
.Country
== locale
.Country
&&
573 cmp_locale
.Variant
== locale
.Variant
)
575 pRetItem
= pLocaleItem
.get();
581 if( pRetItem
== nullptr && bException
)
583 throw IllegalArgumentException( "StringResourceImpl: Invalid locale", Reference
< XInterface
>(), 0 );
588 // Returns the LocaleItem for a given locale, if it exists, otherwise NULL.
589 // This method performs a closest match search, at least the language must match.
590 LocaleItem
* StringResourceImpl::getClosestMatchItemForLocale( const Locale
& locale
)
592 LocaleItem
* pRetItem
= nullptr;
594 ::std::vector
< Locale
> aLocales( m_aLocaleItemVector
.size());
596 for( const auto& pLocaleItem
: m_aLocaleItemVector
)
598 aLocales
[i
] = (pLocaleItem
? pLocaleItem
->m_locale
: Locale());
601 ::std::vector
< Locale
>::const_iterator
iFound( LanguageTag::getMatchingFallback( aLocales
, locale
));
602 if (iFound
!= aLocales
.end())
603 pRetItem
= (m_aLocaleItemVector
.begin() + (iFound
- aLocales
.begin()))->get();
608 void StringResourceImpl::implModified()
611 implNotifyListeners();
614 void StringResourceImpl::implNotifyListeners()
617 aEvent
.Source
= static_cast< XInterface
* >( static_cast<OWeakObject
*>(this) );
619 ::comphelper::OInterfaceIteratorHelper2
it( m_aListenerContainer
);
620 while( it
.hasMoreElements() )
622 Reference
< XInterface
> xIface
= it
.next();
623 Reference
< XModifyListener
> xListener( xIface
, UNO_QUERY
);
626 xListener
->modified( aEvent
);
628 catch(RuntimeException
&)
638 bool StringResourceImpl::loadLocale( LocaleItem
* )
640 // Base implementation has nothing to load
644 void StringResourceImpl::implLoadAllLocales()
646 // Base implementation has nothing to load
650 // StringResourcePersistenceImpl
653 StringResourcePersistenceImpl::StringResourcePersistenceImpl( const Reference
< XComponentContext
>& rxContext
)
654 : StringResourcePersistenceImpl_BASE( rxContext
)
659 StringResourcePersistenceImpl::~StringResourcePersistenceImpl()
667 OUString
StringResourcePersistenceImpl::getImplementationName( )
669 return "com.sun.star.comp.scripting.StringResource";
673 sal_Bool
StringResourcePersistenceImpl::supportsService( const OUString
& rServiceName
)
675 return cppu::supportsService( this, rServiceName
);
679 Sequence
< OUString
> StringResourcePersistenceImpl::getSupportedServiceNames( )
681 return StringResourceImpl::getSupportedServiceNames();
685 // XInitialization base functionality for derived classes
688 const char aNameBaseDefaultStr
[] = "strings";
690 void StringResourcePersistenceImpl::implInitializeCommonParameters
691 ( const Sequence
< Any
>& aArguments
)
693 bool bReadOnlyOk
= (aArguments
[1] >>= m_bReadOnly
);
696 throw IllegalArgumentException( "XInitialization::initialize: Expected ReadOnly flag", Reference
< XInterface
>(), 1 );
699 css::lang::Locale aCurrentLocale
;
700 bool bLocaleOk
= (aArguments
[2] >>= aCurrentLocale
);
703 throw IllegalArgumentException( "XInitialization::initialize: Expected Locale", Reference
< XInterface
>(), 2 );
706 bool bNameBaseOk
= (aArguments
[3] >>= m_aNameBase
);
709 throw IllegalArgumentException( "XInitialization::initialize: Expected NameBase string", Reference
< XInterface
>(), 3 );
711 if( m_aNameBase
.isEmpty() )
712 m_aNameBase
= aNameBaseDefaultStr
;
714 bool bCommentOk
= (aArguments
[4] >>= m_aComment
);
717 throw IllegalArgumentException( "XInitialization::initialize: Expected Comment string", Reference
< XInterface
>(), 4 );
722 implSetCurrentLocale( aCurrentLocale
, true/*FindClosestMatch*/, true/*bUseDefaultIfNoMatch*/ );
726 // Forwarding calls to base class
728 // XModifyBroadcaster
729 void StringResourcePersistenceImpl::addModifyListener( const Reference
< XModifyListener
>& aListener
)
731 StringResourceImpl::addModifyListener( aListener
);
733 void StringResourcePersistenceImpl::removeModifyListener( const Reference
< XModifyListener
>& aListener
)
735 StringResourceImpl::removeModifyListener( aListener
);
738 // XStringResourceResolver
739 OUString
StringResourcePersistenceImpl::resolveString( const OUString
& ResourceID
)
741 return StringResourceImpl::resolveString( ResourceID
) ;
743 OUString
StringResourcePersistenceImpl::resolveStringForLocale( const OUString
& ResourceID
, const Locale
& locale
)
745 return StringResourceImpl::resolveStringForLocale( ResourceID
, locale
);
747 sal_Bool
StringResourcePersistenceImpl::hasEntryForId( const OUString
& ResourceID
)
749 return StringResourceImpl::hasEntryForId( ResourceID
) ;
751 sal_Bool
StringResourcePersistenceImpl::hasEntryForIdAndLocale( const OUString
& ResourceID
,
752 const Locale
& locale
)
754 return StringResourceImpl::hasEntryForIdAndLocale( ResourceID
, locale
);
756 Locale
StringResourcePersistenceImpl::getCurrentLocale()
758 return StringResourceImpl::getCurrentLocale();
760 Locale
StringResourcePersistenceImpl::getDefaultLocale( )
762 return StringResourceImpl::getDefaultLocale();
764 Sequence
< Locale
> StringResourcePersistenceImpl::getLocales( )
766 return StringResourceImpl::getLocales();
769 // XStringResourceManager
770 sal_Bool
StringResourcePersistenceImpl::isReadOnly()
772 return StringResourceImpl::isReadOnly();
774 void StringResourcePersistenceImpl::setCurrentLocale( const Locale
& locale
, sal_Bool FindClosestMatch
)
776 StringResourceImpl::setCurrentLocale( locale
, FindClosestMatch
);
778 void StringResourcePersistenceImpl::setDefaultLocale( const Locale
& locale
)
780 StringResourceImpl::setDefaultLocale( locale
);
782 Sequence
< OUString
> StringResourcePersistenceImpl::getResourceIDs( )
784 return StringResourceImpl::getResourceIDs();
786 void StringResourcePersistenceImpl::setString( const OUString
& ResourceID
, const OUString
& Str
)
788 StringResourceImpl::setString( ResourceID
, Str
);
790 void StringResourcePersistenceImpl::setStringForLocale
791 ( const OUString
& ResourceID
, const OUString
& Str
, const Locale
& locale
)
793 StringResourceImpl::setStringForLocale( ResourceID
, Str
, locale
);
795 Sequence
< OUString
> StringResourcePersistenceImpl::getResourceIDsForLocale
796 ( const Locale
& locale
)
798 return StringResourceImpl::getResourceIDsForLocale( locale
);
800 void StringResourcePersistenceImpl::removeId( const OUString
& ResourceID
)
802 StringResourceImpl::removeId( ResourceID
);
804 void StringResourcePersistenceImpl::removeIdForLocale( const OUString
& ResourceID
, const Locale
& locale
)
806 StringResourceImpl::removeIdForLocale( ResourceID
, locale
);
808 void StringResourcePersistenceImpl::newLocale( const Locale
& locale
)
810 StringResourceImpl::newLocale( locale
);
812 void StringResourcePersistenceImpl::removeLocale( const Locale
& locale
)
814 StringResourceImpl::removeLocale( locale
);
816 sal_Int32
StringResourcePersistenceImpl::getUniqueNumericId( )
818 return StringResourceImpl::getUniqueNumericId();
822 // XStringResourcePersistence
824 void StringResourcePersistenceImpl::store()
828 sal_Bool
StringResourcePersistenceImpl::isModified( )
830 ::osl::MutexGuard
aGuard( getMutex() );
835 void StringResourcePersistenceImpl::setComment( const OUString
& Comment
)
837 m_aComment
= Comment
;
840 void StringResourcePersistenceImpl::storeToStorage( const Reference
< XStorage
>& Storage
,
841 const OUString
& NameBase
, const OUString
& Comment
)
843 ::osl::MutexGuard
aGuard( getMutex() );
845 implStoreAtStorage( NameBase
, Comment
, Storage
, false/*bUsedForStore*/, true/*bStoreAll*/ );
848 void StringResourcePersistenceImpl::implStoreAtStorage
850 const OUString
& aNameBase
,
851 const OUString
& aComment
,
852 const Reference
< css::embed::XStorage
>& Storage
,
857 // Delete files for deleted locales
860 for( auto& pLocaleItem
: m_aDeletedLocaleItemVector
)
864 OUString aStreamName
= implGetFileNameForLocaleItem( pLocaleItem
.get(), m_aNameBase
) + ".properties";
868 Storage
->removeElement( aStreamName
);
876 m_aDeletedLocaleItemVector
.clear();
879 for( auto& pLocaleItem
: m_aLocaleItemVector
)
881 if( pLocaleItem
!= nullptr && (bStoreAll
|| pLocaleItem
->m_bModified
) &&
882 loadLocale( pLocaleItem
.get() ) )
884 OUString aStreamName
= implGetFileNameForLocaleItem( pLocaleItem
.get(), aNameBase
) + ".properties";
886 Reference
< io::XStream
> xElementStream
=
887 Storage
->openStreamElement( aStreamName
, ElementModes::READWRITE
);
889 uno::Reference
< beans::XPropertySet
> xProps( xElementStream
, uno::UNO_QUERY
);
890 OSL_ENSURE( xProps
.is(), "The StorageStream must implement XPropertySet interface!" );
893 OUString
aPropName("MediaType");
894 xProps
->setPropertyValue( aPropName
, uno::makeAny( OUString("text/plain") ) );
896 aPropName
= "UseCommonStoragePasswordEncryption";
897 xProps
->setPropertyValue( aPropName
, uno::makeAny( true ) );
900 Reference
< io::XOutputStream
> xOutputStream
= xElementStream
->getOutputStream();
901 if( xOutputStream
.is() )
902 implWritePropertiesFile( pLocaleItem
.get(), xOutputStream
, aComment
);
903 xOutputStream
->closeOutput();
906 pLocaleItem
->m_bModified
= false;
910 // Delete files for changed defaults
913 for( auto& pLocaleItem
: m_aChangedDefaultLocaleVector
)
915 OUString aStreamName
= implGetFileNameForLocaleItem( pLocaleItem
.get(), m_aNameBase
) + ".default";
919 Storage
->removeElement( aStreamName
);
926 m_aChangedDefaultLocaleVector
.clear();
930 if( !(m_pDefaultLocaleItem
!= nullptr && (bStoreAll
|| m_bDefaultModified
)) )
933 OUString aStreamName
= implGetFileNameForLocaleItem( m_pDefaultLocaleItem
, aNameBase
) + ".default";
935 Reference
< io::XStream
> xElementStream
=
936 Storage
->openStreamElement( aStreamName
, ElementModes::READWRITE
);
938 // Only create stream without content
939 Reference
< io::XOutputStream
> xOutputStream
= xElementStream
->getOutputStream();
940 xOutputStream
->closeOutput();
943 m_bDefaultModified
= false;
946 void StringResourcePersistenceImpl::storeToURL( const OUString
& URL
,
947 const OUString
& NameBase
, const OUString
& Comment
,
948 const Reference
< css::task::XInteractionHandler
>& Handler
)
950 ::osl::MutexGuard
aGuard( getMutex() );
952 Reference
< ucb::XSimpleFileAccess3
> xFileAccess
= ucb::SimpleFileAccess::create(m_xContext
);
953 if( xFileAccess
.is() && Handler
.is() )
954 xFileAccess
->setInteractionHandler( Handler
);
956 implStoreAtLocation( URL
, NameBase
, Comment
, xFileAccess
, false/*bUsedForStore*/, true/*bStoreAll*/ );
959 void StringResourcePersistenceImpl::implKillRemovedLocaleFiles
961 const OUString
& Location
,
962 const OUString
& aNameBase
,
963 const css::uno::Reference
< css::ucb::XSimpleFileAccess3
>& xFileAccess
966 // Delete files for deleted locales
967 for( auto& pLocaleItem
: m_aDeletedLocaleItemVector
)
971 OUString aCompleteFileName
=
972 implGetPathForLocaleItem( pLocaleItem
.get(), aNameBase
, Location
);
973 if( xFileAccess
->exists( aCompleteFileName
) )
974 xFileAccess
->kill( aCompleteFileName
);
979 m_aDeletedLocaleItemVector
.clear();
982 void StringResourcePersistenceImpl::implKillChangedDefaultFiles
984 const OUString
& Location
,
985 const OUString
& aNameBase
,
986 const css::uno::Reference
< css::ucb::XSimpleFileAccess3
>& xFileAccess
989 // Delete files for changed defaults
990 for( auto& pLocaleItem
: m_aChangedDefaultLocaleVector
)
992 OUString aCompleteFileName
=
993 implGetPathForLocaleItem( pLocaleItem
.get(), aNameBase
, Location
, true );
994 if( xFileAccess
->exists( aCompleteFileName
) )
995 xFileAccess
->kill( aCompleteFileName
);
998 m_aChangedDefaultLocaleVector
.clear();
1001 void StringResourcePersistenceImpl::implStoreAtLocation
1003 const OUString
& Location
,
1004 const OUString
& aNameBase
,
1005 const OUString
& aComment
,
1006 const Reference
< ucb::XSimpleFileAccess3
>& xFileAccess
,
1012 // Delete files for deleted locales
1013 if( bUsedForStore
|| bKillAll
)
1014 implKillRemovedLocaleFiles( Location
, aNameBase
, xFileAccess
);
1016 for( auto& pLocaleItem
: m_aLocaleItemVector
)
1018 if( pLocaleItem
!= nullptr && (bStoreAll
|| bKillAll
|| pLocaleItem
->m_bModified
) &&
1019 loadLocale( pLocaleItem
.get() ) )
1021 OUString aCompleteFileName
=
1022 implGetPathForLocaleItem( pLocaleItem
.get(), aNameBase
, Location
);
1023 if( xFileAccess
->exists( aCompleteFileName
) )
1024 xFileAccess
->kill( aCompleteFileName
);
1028 // Create Output stream
1029 Reference
< io::XOutputStream
> xOutputStream
= xFileAccess
->openFileWrite( aCompleteFileName
);
1030 if( xOutputStream
.is() )
1032 implWritePropertiesFile( pLocaleItem
.get(), xOutputStream
, aComment
);
1033 xOutputStream
->closeOutput();
1036 pLocaleItem
->m_bModified
= false;
1041 // Delete files for changed defaults
1042 if( bUsedForStore
|| bKillAll
)
1043 implKillChangedDefaultFiles( Location
, aNameBase
, xFileAccess
);
1046 if( !(m_pDefaultLocaleItem
!= nullptr && (bStoreAll
|| bKillAll
|| m_bDefaultModified
)) )
1049 OUString aCompleteFileName
=
1050 implGetPathForLocaleItem( m_pDefaultLocaleItem
, aNameBase
, Location
, true );
1051 if( xFileAccess
->exists( aCompleteFileName
) )
1052 xFileAccess
->kill( aCompleteFileName
);
1056 // Create Output stream
1057 Reference
< io::XOutputStream
> xOutputStream
= xFileAccess
->openFileWrite( aCompleteFileName
);
1058 if( xOutputStream
.is() )
1059 xOutputStream
->closeOutput();
1062 m_bDefaultModified
= false;
1067 // BinaryOutput, helper class for exportBinary
1071 Reference
< XComponentContext
> m_xContext
;
1072 Reference
< XInterface
> m_xTempFile
;
1073 Reference
< io::XOutputStream
> m_xOutputStream
;
1076 explicit BinaryOutput( Reference
< XComponentContext
> const & xContext
);
1078 const Reference
< io::XOutputStream
>& getOutputStream() const
1079 { return m_xOutputStream
; }
1081 Sequence
< ::sal_Int8
> closeAndGetData();
1083 // Template to be used with sal_Int16 and sal_Unicode
1085 void write16BitInt( T n
);
1086 void writeInt16( sal_Int16 n
)
1087 { write16BitInt( n
); }
1088 void writeUnicodeChar( sal_Unicode n
)
1089 { write16BitInt( n
); }
1090 void writeInt32( sal_Int32 n
);
1091 void writeString( const OUString
& aStr
);
1094 BinaryOutput::BinaryOutput( Reference
< XComponentContext
> const & xContext
)
1095 : m_xContext( xContext
)
1097 m_xTempFile
= io::TempFile::create( m_xContext
);
1098 m_xOutputStream
.set( m_xTempFile
, UNO_QUERY_THROW
);
1102 void BinaryOutput::write16BitInt( T n
)
1104 if( !m_xOutputStream
.is() )
1107 Sequence
< sal_Int8
> aSeq( 2 );
1108 sal_Int8
* p
= aSeq
.getArray();
1110 sal_Int8 nLow
= sal_Int8( n
& 0xff );
1111 sal_Int8 nHigh
= sal_Int8( n
>> 8 );
1115 m_xOutputStream
->writeBytes( aSeq
);
1118 void BinaryOutput::writeInt32( sal_Int32 n
)
1120 if( !m_xOutputStream
.is() )
1123 Sequence
< sal_Int8
> aSeq( 4 );
1124 sal_Int8
* p
= aSeq
.getArray();
1126 for( sal_Int16 i
= 0 ; i
< 4 ; i
++ )
1128 p
[i
] = sal_Int8( n
& 0xff );
1131 m_xOutputStream
->writeBytes( aSeq
);
1134 void BinaryOutput::writeString( const OUString
& aStr
)
1136 sal_Int32 nLen
= aStr
.getLength();
1137 const sal_Unicode
* pStr
= aStr
.getStr();
1139 for( sal_Int32 i
= 0 ; i
< nLen
; i
++ )
1140 writeUnicodeChar( pStr
[i
] );
1142 writeUnicodeChar( 0 );
1145 Sequence
< ::sal_Int8
> BinaryOutput::closeAndGetData()
1147 Sequence
< ::sal_Int8
> aRetSeq
;
1148 if( !m_xOutputStream
.is() )
1151 m_xOutputStream
->closeOutput();
1153 Reference
< io::XSeekable
> xSeekable( m_xTempFile
, UNO_QUERY
);
1154 if( !xSeekable
.is() )
1157 sal_Int32 nSize
= static_cast<sal_Int32
>(xSeekable
->getPosition());
1159 Reference
< io::XInputStream
> xInputStream( m_xTempFile
, UNO_QUERY
);
1160 if( !xInputStream
.is() )
1163 xSeekable
->seek( 0 );
1164 sal_Int32 nRead
= xInputStream
->readBytes( aRetSeq
, nSize
);
1165 OSL_ENSURE( nRead
== nSize
, "BinaryOutput::closeAndGetData: nRead != nSize" );
1175 // 0 + 1 sal_Int16: Version, currently 0, low byte first
1176 // 2 + 3 sal_Int16: Locale count = n, low byte first
1177 // 4 + 5 sal_Int16: Default Locale position in Locale list, == n if none
1178 // 6 - 7 sal_Int32: Start index locale block 0, lowest byte first
1179 // (n-1) * sal_Int32: Start index locale block 1 to n, lowest byte first
1180 // 6 + 4*n sal_Int32: "Start index" non existing locale block n+1,
1181 // marks the first invalid index, kind of EOF
1184 // All strings are stored as 2-Byte-0 terminated sequence
1185 // of 16 bit Unicode characters, each with low byte first
1186 // Empty strings only contain the 2-Byte-0
1188 // Members of com.sun.star.lang.Locale
1189 // with l1 = Locale.Language.getLength()
1190 // with l2 = Locale.Country.getLength()
1191 // with l3 = Locale.Variant.getLength()
1192 // pos0 = 0 Locale.Language
1193 // pos1 = 2 * (l1 + 1) Locale.Country
1194 // pos2 = pos1 + 2 * (l2 + 1) Locale.Variant
1195 // pos3 = pos2 + 2 * (l3 + 1)
1196 // pos3 Properties file written by implWritePropertiesFile
1198 Sequence
< sal_Int8
> StringResourcePersistenceImpl::exportBinary( )
1200 BinaryOutput
aOut( m_xContext
);
1202 sal_Int32 nLocaleCount
= m_aLocaleItemVector
.size();
1203 std::vector
<Sequence
< sal_Int8
>> aLocaleDataSeq(nLocaleCount
);
1205 sal_Int32 iLocale
= 0;
1206 sal_Int32 iDefault
= 0;
1207 for( auto& pLocaleItem
: m_aLocaleItemVector
)
1209 if( pLocaleItem
!= nullptr && loadLocale( pLocaleItem
.get() ) )
1211 if( m_pDefaultLocaleItem
== pLocaleItem
.get() )
1214 BinaryOutput
aLocaleOut( m_xContext
);
1215 implWriteLocaleBinary( pLocaleItem
.get(), aLocaleOut
);
1217 aLocaleDataSeq
[iLocale
] = aLocaleOut
.closeAndGetData();
1223 sal_Int16 nLocaleCount16
= static_cast<sal_Int16
>(nLocaleCount
);
1224 sal_Int16 iDefault16
= static_cast<sal_Int16
>(iDefault
);
1225 aOut
.writeInt16( 0 ); // nVersion
1226 aOut
.writeInt16( nLocaleCount16
);
1227 aOut
.writeInt16( iDefault16
);
1229 // Write data positions
1230 sal_Int32 nDataPos
= 6 + 4 * (nLocaleCount
+ 1);
1231 for( iLocale
= 0; iLocale
< nLocaleCount
; iLocale
++ )
1233 aOut
.writeInt32( nDataPos
);
1235 Sequence
< sal_Int8
>& rSeq
= aLocaleDataSeq
[iLocale
];
1236 sal_Int32 nSeqLen
= rSeq
.getLength();
1237 nDataPos
+= nSeqLen
;
1239 // Write final position
1240 aOut
.writeInt32( nDataPos
);
1243 Reference
< io::XOutputStream
> xOutputStream
= aOut
.getOutputStream();
1244 if( xOutputStream
.is() )
1246 for( iLocale
= 0; iLocale
< nLocaleCount
; iLocale
++ )
1248 Sequence
< sal_Int8
>& rSeq
= aLocaleDataSeq
[iLocale
];
1249 xOutputStream
->writeBytes( rSeq
);
1253 Sequence
< sal_Int8
> aRetSeq
= aOut
.closeAndGetData();
1257 void StringResourcePersistenceImpl::implWriteLocaleBinary
1258 ( LocaleItem
* pLocaleItem
, BinaryOutput
& rOut
)
1260 Reference
< io::XOutputStream
> xOutputStream
= rOut
.getOutputStream();
1261 if( !xOutputStream
.is() )
1264 Locale
& rLocale
= pLocaleItem
->m_locale
;
1265 rOut
.writeString( rLocale
.Language
);
1266 rOut
.writeString( rLocale
.Country
);
1267 rOut
.writeString( rLocale
.Variant
);
1268 implWritePropertiesFile( pLocaleItem
, xOutputStream
, m_aComment
);
1272 // BinaryOutput, helper class for exportBinary
1278 Sequence
< sal_Int8
> m_aData
;
1279 Reference
< XComponentContext
> m_xContext
;
1281 const sal_Int8
* m_pData
;
1282 sal_Int32 m_nCurPos
;
1286 BinaryInput( const Sequence
< ::sal_Int8
>& aData
, Reference
< XComponentContext
> const & xContext
);
1288 Reference
< io::XInputStream
> getInputStreamForSection( sal_Int32 nSize
);
1290 void seek( sal_Int32 nPos
);
1291 sal_Int32
getPosition() const
1292 { return m_nCurPos
; }
1294 sal_Int16
readInt16();
1295 sal_Int32
readInt32();
1296 sal_Unicode
readUnicodeChar();
1297 OUString
readString();
1302 BinaryInput::BinaryInput( const Sequence
< ::sal_Int8
>& aData
, Reference
< XComponentContext
> const & xContext
)
1304 , m_xContext( xContext
)
1306 m_pData
= m_aData
.getConstArray();
1308 m_nSize
= m_aData
.getLength();
1311 Reference
< io::XInputStream
> BinaryInput::getInputStreamForSection( sal_Int32 nSize
)
1313 Reference
< io::XInputStream
> xIn
;
1314 if( m_nCurPos
+ nSize
<= m_nSize
)
1316 Reference
< io::XOutputStream
> xTempOut( io::TempFile::create(m_xContext
), UNO_QUERY_THROW
);
1317 Sequence
< sal_Int8
> aSection( m_pData
+ m_nCurPos
, nSize
);
1318 xTempOut
->writeBytes( aSection
);
1320 Reference
< io::XSeekable
> xSeekable( xTempOut
, UNO_QUERY
);
1321 if( xSeekable
.is() )
1322 xSeekable
->seek( 0 );
1324 xIn
.set( xTempOut
, UNO_QUERY
);
1327 OSL_FAIL( "BinaryInput::getInputStreamForSection(): Read past end" );
1332 void BinaryInput::seek( sal_Int32 nPos
)
1334 if( nPos
<= m_nSize
)
1337 OSL_FAIL( "BinaryInput::seek(): Position past end" );
1341 sal_Int16
BinaryInput::readInt16()
1344 if( m_nCurPos
+ 2 <= m_nSize
)
1346 nRet
= nRet
+ sal_Int16( sal_uInt8( m_pData
[m_nCurPos
++] ) );
1347 nRet
+= 256 * sal_Int16( sal_uInt8( m_pData
[m_nCurPos
++] ) );
1350 OSL_FAIL( "BinaryInput::readInt16(): Read past end" );
1355 sal_Int32
BinaryInput::readInt32()
1358 if( m_nCurPos
+ 4 <= m_nSize
)
1360 sal_Int32 nFactor
= 1;
1361 for( sal_Int16 i
= 0; i
< 4; i
++ )
1363 nRet
+= sal_uInt8( m_pData
[m_nCurPos
++] ) * nFactor
;
1368 OSL_FAIL( "BinaryInput::readInt32(): Read past end" );
1373 sal_Unicode
BinaryInput::readUnicodeChar()
1375 sal_uInt16 nRet
= 0;
1376 if( m_nCurPos
+ 2 <= m_nSize
)
1378 nRet
= nRet
+ sal_uInt8( m_pData
[m_nCurPos
++] );
1379 nRet
+= 256 * sal_uInt8( m_pData
[m_nCurPos
++] );
1382 OSL_FAIL( "BinaryInput::readUnicodeChar(): Read past end" );
1384 sal_Unicode cRet
= nRet
;
1388 OUString
BinaryInput::readString()
1390 OUStringBuffer aBuf
;
1394 c
= readUnicodeChar();
1400 OUString aRetStr
= aBuf
.makeStringAndClear();
1404 void StringResourcePersistenceImpl::importBinary( const Sequence
< ::sal_Int8
>& Data
)
1406 // Init: Remove all locales
1407 sal_Int32 nOldLocaleCount
= 0;
1410 Sequence
< Locale
> aLocaleSeq
= getLocales();
1411 nOldLocaleCount
= aLocaleSeq
.getLength();
1412 if( nOldLocaleCount
> 0 )
1414 Locale aLocale
= aLocaleSeq
[0];
1415 removeLocale( aLocale
);
1418 while( nOldLocaleCount
> 0 );
1421 BinaryInput
aIn( Data
, m_xContext
);
1423 aIn
.readInt16(); // version
1424 sal_Int32 nLocaleCount
= aIn
.readInt16();
1425 sal_Int32 iDefault
= aIn
.readInt16();
1427 std::unique_ptr
<sal_Int32
[]> pPositions( new sal_Int32
[nLocaleCount
+ 1] );
1428 for( sal_Int32 i
= 0; i
< nLocaleCount
+ 1; i
++ )
1429 pPositions
[i
] = aIn
.readInt32();
1432 LocaleItem
* pUseAsDefaultItem
= nullptr;
1433 for( sal_Int32 i
= 0; i
< nLocaleCount
; i
++ )
1435 sal_Int32 nPos
= pPositions
[i
];
1439 aLocale
.Language
= aIn
.readString();
1440 aLocale
.Country
= aIn
.readString();
1441 aLocale
.Variant
= aIn
.readString();
1443 sal_Int32 nAfterStringPos
= aIn
.getPosition();
1444 sal_Int32 nSize
= pPositions
[i
+1] - nAfterStringPos
;
1445 Reference
< io::XInputStream
> xInput
= aIn
.getInputStreamForSection( nSize
);
1448 LocaleItem
* pLocaleItem
= new LocaleItem( aLocale
);
1450 pUseAsDefaultItem
= pLocaleItem
;
1451 m_aLocaleItemVector
.emplace_back( pLocaleItem
);
1452 implReadPropertiesFile( pLocaleItem
, xInput
);
1456 if( pUseAsDefaultItem
!= nullptr )
1457 setDefaultLocale( pUseAsDefaultItem
->m_locale
);
1461 // Private helper methods
1463 static bool checkNamingSceme( const OUString
& aName
, const OUString
& aNameBase
,
1466 bool bSuccess
= false;
1468 sal_Int32 nNameLen
= aName
.getLength();
1469 sal_Int32 nNameBaseLen
= aNameBase
.getLength();
1471 // Name has to start with NameBase followed
1472 // by a '_' and at least one more character
1473 if( aName
.startsWith( aNameBase
) && nNameBaseLen
< nNameLen
-1 &&
1474 aName
[nNameBaseLen
] == '_' )
1478 /* FIXME-BCP47: this uses '_' underscore character as separator and
1479 * also appends Variant, which can't be blindly changed as it would
1480 * violate the naming scheme in use. */
1482 sal_Int32 iStart
= nNameBaseLen
+ 1;
1483 sal_Int32 iNext_
= aName
.indexOf( '_', iStart
);
1484 if( iNext_
!= -1 && iNext_
< nNameLen
-1 )
1486 aLocale
.Language
= aName
.copy( iStart
, iNext_
- iStart
);
1488 iStart
= iNext_
+ 1;
1489 iNext_
= aName
.indexOf( '_', iStart
);
1490 if( iNext_
!= -1 && iNext_
< nNameLen
-1 )
1492 aLocale
.Country
= aName
.copy( iStart
, iNext_
- iStart
);
1493 aLocale
.Variant
= aName
.copy( iNext_
+ 1 );
1496 aLocale
.Country
= aName
.copy( iStart
);
1499 aLocale
.Language
= aName
.copy( iStart
);
1504 void StringResourcePersistenceImpl::implLoadAllLocales()
1506 for( auto& pLocaleItem
: m_aLocaleItemVector
)
1508 loadLocale( pLocaleItem
.get() );
1511 // Scan locale properties files helper
1512 void StringResourcePersistenceImpl::implScanLocaleNames( const Sequence
< OUString
>& aContentSeq
)
1514 Locale aDefaultLocale
;
1515 bool bDefaultFound
= false;
1517 for( const OUString
& aCompleteName
: aContentSeq
)
1520 OUString aExtension
;
1521 sal_Int32 iDot
= aCompleteName
.lastIndexOf( '.' );
1522 sal_Int32 iSlash
= aCompleteName
.lastIndexOf( '/' );
1523 if( iDot
!= -1 && iDot
> iSlash
)
1525 sal_Int32 iCopyFrom
= (iSlash
!= -1) ? iSlash
+ 1 : 0;
1526 aPureName
= aCompleteName
.copy( iCopyFrom
, iDot
-iCopyFrom
);
1527 aExtension
= aCompleteName
.copy( iDot
+ 1 );
1530 if ( aExtension
== "properties" )
1532 //OUString aName = aInetObj.getBase();
1535 if( checkNamingSceme( aPureName
, m_aNameBase
, aLocale
) )
1537 LocaleItem
* pLocaleItem
= new LocaleItem( aLocale
, false );
1538 m_aLocaleItemVector
.emplace_back( pLocaleItem
);
1540 if( m_pCurrentLocaleItem
== nullptr )
1541 m_pCurrentLocaleItem
= pLocaleItem
;
1543 if( m_pDefaultLocaleItem
== nullptr )
1545 m_pDefaultLocaleItem
= pLocaleItem
;
1546 m_bDefaultModified
= true;
1550 else if( !bDefaultFound
&& aExtension
== "default" )
1552 if( checkNamingSceme( aPureName
, m_aNameBase
, aDefaultLocale
) )
1553 bDefaultFound
= true;
1558 LocaleItem
* pLocaleItem
= getItemForLocale( aDefaultLocale
, false );
1561 m_pDefaultLocaleItem
= pLocaleItem
;
1562 m_bDefaultModified
= false;
1567 // Scan locale properties files
1568 void StringResourcePersistenceImpl::implScanLocales()
1570 // Dummy implementation, method not called for this
1571 // base class, but pure virtual not possible-
1574 bool StringResourcePersistenceImpl::loadLocale( LocaleItem
* pLocaleItem
)
1576 bool bSuccess
= false;
1578 OSL_ENSURE( pLocaleItem
, "StringResourcePersistenceImpl::loadLocale(): pLocaleItem == NULL" );
1581 if( pLocaleItem
->m_bLoaded
)
1587 bSuccess
= implLoadLocale( pLocaleItem
);
1588 pLocaleItem
->m_bLoaded
= true; // = bSuccess??? -> leads to more tries
1594 bool StringResourcePersistenceImpl::implLoadLocale( LocaleItem
* )
1596 // Dummy implementation, method not called for this
1597 // base class, but pure virtual not possible-
1601 static OUString
implGetNameScemeForLocaleItem( const LocaleItem
* pLocaleItem
)
1603 /* FIXME-BCP47: this uses '_' underscore character as separator and
1604 * also appends Variant, which can't be blindly changed as it would
1605 * violate the naming scheme in use. */
1607 static const char aUnder
[] = "_";
1609 OSL_ENSURE( pLocaleItem
,
1610 "StringResourcePersistenceImpl::implGetNameScemeForLocaleItem(): pLocaleItem == NULL" );
1611 Locale aLocale
= pLocaleItem
->m_locale
;
1613 OUString aRetStr
= aUnder
+ aLocale
.Language
;
1615 OUString aCountry
= aLocale
.Country
;
1616 if( !aCountry
.isEmpty() )
1618 aRetStr
+= aUnder
+ aCountry
;
1621 OUString aVariant
= aLocale
.Variant
;
1622 if( !aVariant
.isEmpty() )
1624 aRetStr
+= aUnder
+ aVariant
;
1629 OUString
StringResourcePersistenceImpl::implGetFileNameForLocaleItem
1630 ( LocaleItem
const * pLocaleItem
, const OUString
& aNameBase
)
1632 OUString aFileName
= aNameBase
;
1633 if( aFileName
.isEmpty() )
1634 aFileName
= aNameBaseDefaultStr
;
1636 aFileName
+= implGetNameScemeForLocaleItem( pLocaleItem
);
1640 OUString
StringResourcePersistenceImpl::implGetPathForLocaleItem
1641 ( LocaleItem
const * pLocaleItem
, const OUString
& aNameBase
,
1642 const OUString
& aLocation
, bool bDefaultFile
)
1644 OUString aFileName
= implGetFileNameForLocaleItem( pLocaleItem
, aNameBase
);
1645 INetURLObject
aInetObj( aLocation
);
1646 aInetObj
.insertName( aFileName
, true, INetURLObject::LAST_SEGMENT
, INetURLObject::EncodeMechanism::All
);
1648 aInetObj
.setExtension( "default" );
1650 aInetObj
.setExtension( "properties" );
1651 OUString aCompleteFileName
= aInetObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
1652 return aCompleteFileName
;
1655 // White space according to Java property files specification in
1656 // http://java.sun.com/j2se/1.4.2/docs/api/java/util/Properties.html#load(java.io.InputStream)
1657 static bool isWhiteSpace( sal_Unicode c
)
1659 bool bWhite
= ( c
== 0x0020 || // space
1660 c
== 0x0009 || // tab
1661 c
== 0x000a || // line feed, not always handled by TextInputStream
1662 c
== 0x000d || // carriage return, not always handled by TextInputStream
1663 c
== 0x000C ); // form feed
1667 static void skipWhites( const sal_Unicode
* pBuf
, sal_Int32 nLen
, sal_Int32
& ri
)
1671 if( !isWhiteSpace( pBuf
[ri
] ) )
1677 static bool isHexDigit( sal_Unicode c
, sal_uInt16
& nDigitVal
)
1680 if( c
>= '0' && c
<= '9' )
1681 nDigitVal
= c
- '0';
1682 else if( c
>= 'a' && c
<= 'f' )
1683 nDigitVal
= c
- 'a' + 10;
1684 else if( c
>= 'A' && c
<= 'F' )
1685 nDigitVal
= c
- 'A' + 10;
1691 static sal_Unicode
getEscapeChar( const sal_Unicode
* pBuf
, sal_Int32 nLen
, sal_Int32
& ri
)
1695 sal_Unicode cRet
= 0;
1696 sal_Unicode c
= pBuf
[i
];
1718 while( i
< nLen
&& pBuf
[i
] == 'u' )
1721 // Process hex digits
1722 sal_Int32 nDigitCount
= 0;
1723 sal_uInt16 nDigitVal
;
1724 while( i
< nLen
&& isHexDigit( pBuf
[i
], nDigitVal
) )
1726 cRet
= 16 * cRet
+ nDigitVal
;
1729 if( nDigitCount
== 4 )
1731 // Write back position
1746 static void CheckContinueInNextLine( const Reference
< io::XTextInputStream2
>& xTextInputStream
,
1747 OUString
& aLine
, bool& bEscapePending
, const sal_Unicode
*& pBuf
,
1748 sal_Int32
& nLen
, sal_Int32
& i
)
1750 if( !(i
== nLen
&& bEscapePending
) )
1753 bEscapePending
= false;
1755 if( !xTextInputStream
->isEOF() )
1757 aLine
= xTextInputStream
->readLine();
1758 nLen
= aLine
.getLength();
1759 pBuf
= aLine
.getStr();
1762 skipWhites( pBuf
, nLen
, i
);
1766 bool StringResourcePersistenceImpl::implReadPropertiesFile
1767 ( LocaleItem
* pLocaleItem
, const Reference
< io::XInputStream
>& xInputStream
)
1769 if( !xInputStream
.is() || pLocaleItem
== nullptr )
1772 Reference
< io::XTextInputStream2
> xTextInputStream
= io::TextInputStream::create( m_xContext
);
1774 xTextInputStream
->setInputStream( xInputStream
);
1776 OUString aEncodingStr
= OUString::createFromAscii
1777 ( rtl_getMimeCharsetFromTextEncoding( RTL_TEXTENCODING_ISO_8859_1
) );
1778 xTextInputStream
->setEncoding( aEncodingStr
);
1781 while( !xTextInputStream
->isEOF() )
1783 aLine
= xTextInputStream
->readLine();
1785 sal_Int32 nLen
= aLine
.getLength();
1788 const sal_Unicode
* pBuf
= aLine
.getStr();
1789 OUStringBuffer aBuf
;
1793 skipWhites( pBuf
, nLen
, i
);
1795 continue; // line contains only white spaces
1799 if( c
== '#' || c
== '!' )
1803 OUString aResourceID
;
1804 bool bEscapePending
= false;
1805 bool bStrComplete
= false;
1806 while( i
< nLen
&& !bStrComplete
)
1809 if( bEscapePending
)
1811 aBuf
.append( getEscapeChar( pBuf
, nLen
, i
) );
1812 bEscapePending
= false;
1818 bEscapePending
= true;
1822 if( c
== ':' || c
== '=' || isWhiteSpace( c
) )
1823 bStrComplete
= true;
1830 CheckContinueInNextLine( xTextInputStream
, aLine
, bEscapePending
, pBuf
, nLen
, i
);
1832 bStrComplete
= true;
1835 aResourceID
= aBuf
.makeStringAndClear();
1838 // Ignore lines with empty keys
1839 if( aResourceID
.isEmpty() )
1843 skipWhites( pBuf
, nLen
, i
);
1846 bEscapePending
= false;
1847 bStrComplete
= false;
1848 while( i
< nLen
&& !bStrComplete
)
1851 if( c
== 0x000a || c
== 0x000d ) // line feed/carriage return, not always handled by TextInputStream
1857 if( bEscapePending
)
1859 aBuf
.append( getEscapeChar( pBuf
, nLen
, i
) );
1860 bEscapePending
= false;
1862 else if( c
== '\\' )
1863 bEscapePending
= true;
1868 CheckContinueInNextLine( xTextInputStream
, aLine
, bEscapePending
, pBuf
, nLen
, i
);
1871 bStrComplete
= true;
1874 aValueStr
= aBuf
.makeStringAndClear();
1878 pLocaleItem
->m_aIdToStringMap
[ aResourceID
] = aValueStr
;
1879 implScanIdForNumber( aResourceID
);
1880 IdToIndexMap
& rIndexMap
= pLocaleItem
->m_aIdToIndexMap
;
1881 rIndexMap
[ aResourceID
] = pLocaleItem
->m_nNextIndex
++;
1888 static sal_Unicode
getHexCharForDigit( sal_uInt16 nDigitVal
)
1890 sal_Unicode cRet
= ( nDigitVal
< 10 ) ? ('0' + nDigitVal
) : ('a' + (nDigitVal
-10));
1894 static void implWriteCharToBuffer( OUStringBuffer
& aBuf
, sal_Unicode cu
, bool bKey
)
1898 aBuf
.append( '\\' );
1899 aBuf
.append( '\\' );
1901 else if( cu
== 0x000a )
1903 aBuf
.append( '\\' );
1906 else if( cu
== 0x000d )
1908 aBuf
.append( '\\' );
1911 else if( bKey
&& cu
== '=' )
1913 aBuf
.append( '\\' );
1916 else if( bKey
&& cu
== ':' )
1918 aBuf
.append( '\\' );
1921 // ISO/IEC 8859-1 range according to:
1922 // http://en.wikipedia.org/wiki/ISO/IEC_8859-1
1923 else if( cu
>= 0x20 && cu
<= 0x7e )
1924 //TODO: Check why (cu >= 0xa0 && cu <= 0xFF)
1925 //is encoded in sample properties files
1926 //else if( (cu >= 0x20 && cu <= 0x7e) ||
1927 // (cu >= 0xa0 && cu <= 0xFF) )
1934 aBuf
.append( '\\' );
1937 sal_uInt16 nVal
= cu
;
1938 for( sal_uInt16 i
= 0 ; i
< 4 ; i
++ )
1940 sal_uInt16 nDigit
= nVal
/ 0x1000;
1941 nVal
-= nDigit
* 0x1000;
1943 aBuf
.append( getHexCharForDigit( nDigit
) );
1948 static void implWriteStringWithEncoding( const OUString
& aStr
,
1949 Reference
< io::XTextOutputStream2
> const & xTextOutputStream
, bool bKey
)
1951 static const sal_Unicode cLineFeed
= 0xa;
1953 OUStringBuffer aBuf
;
1954 sal_Int32 nLen
= aStr
.getLength();
1955 const sal_Unicode
* pSrc
= aStr
.getStr();
1956 for( sal_Int32 i
= 0 ; i
< nLen
; i
++ )
1958 sal_Unicode cu
= pSrc
[i
];
1959 implWriteCharToBuffer( aBuf
, cu
, bKey
);
1960 // TODO?: split long lines
1963 aBuf
.append( cLineFeed
);
1965 OUString aWriteStr
= aBuf
.makeStringAndClear();
1966 xTextOutputStream
->writeString( aWriteStr
);
1969 bool StringResourcePersistenceImpl::implWritePropertiesFile( LocaleItem
const * pLocaleItem
,
1970 const Reference
< io::XOutputStream
>& xOutputStream
, const OUString
& aComment
)
1972 if( !xOutputStream
.is() || pLocaleItem
== nullptr )
1975 bool bSuccess
= false;
1976 Reference
< io::XTextOutputStream2
> xTextOutputStream
= io::TextOutputStream::create(m_xContext
);
1978 xTextOutputStream
->setOutputStream( xOutputStream
);
1980 OUString aEncodingStr
= OUString::createFromAscii
1981 ( rtl_getMimeCharsetFromTextEncoding( RTL_TEXTENCODING_ISO_8859_1
) );
1982 xTextOutputStream
->setEncoding( aEncodingStr
);
1984 xTextOutputStream
->writeString( aComment
);
1985 xTextOutputStream
->writeString( "\n" );
1987 const IdToStringMap
& rHashMap
= pLocaleItem
->m_aIdToStringMap
;
1988 if( !rHashMap
.empty() )
1990 // Sort ids according to read order
1991 const IdToIndexMap
& rIndexMap
= pLocaleItem
->m_aIdToIndexMap
;
1993 // Find max/min index
1994 auto itMinMax
= std::minmax_element(rIndexMap
.begin(), rIndexMap
.end(),
1995 [](const IdToIndexMap::value_type
& a
, const IdToIndexMap::value_type
& b
) { return a
.second
< b
.second
; });
1996 sal_Int32 nMinIndex
= itMinMax
.first
->second
;
1997 sal_Int32 nMaxIndex
= itMinMax
.second
->second
;
1998 sal_Int32 nTabSize
= nMaxIndex
- nMinIndex
+ 1;
2000 // Create sorted array of pointers to the id strings
2001 std::unique_ptr
<const OUString
*[]> pIdPtrs( new const OUString
*[nTabSize
] );
2002 for(sal_Int32 i
= 0 ; i
< nTabSize
; i
++ )
2003 pIdPtrs
[i
] = nullptr;
2004 for( const auto& rIndex
: rIndexMap
)
2006 sal_Int32 nIndex
= rIndex
.second
;
2007 pIdPtrs
[nIndex
- nMinIndex
] = &(rIndex
.first
);
2010 // Write lines in correct order
2011 for(sal_Int32 i
= 0 ; i
< nTabSize
; i
++ )
2013 const OUString
* pStr
= pIdPtrs
[i
];
2014 if( pStr
!= nullptr )
2016 OUString aResourceID
= *pStr
;
2017 IdToStringMap::const_iterator it
= rHashMap
.find( aResourceID
);
2018 if( it
!= rHashMap
.end() )
2020 implWriteStringWithEncoding( aResourceID
, xTextOutputStream
, true );
2021 xTextOutputStream
->writeString( "=" );
2022 OUString aValStr
= (*it
).second
;
2023 implWriteStringWithEncoding( aValStr
, xTextOutputStream
, false );
2035 // StringResourceWithStorageImpl
2037 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
2038 scripting_StringResourceWithStorageImpl_get_implementation(
2039 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
2041 return cppu::acquire(new StringResourceWithStorageImpl(context
));
2045 StringResourceWithStorageImpl::StringResourceWithStorageImpl( const Reference
< XComponentContext
>& rxContext
)
2046 : StringResourceWithStorageImpl_BASE( rxContext
)
2047 , m_bStorageChanged( false )
2052 StringResourceWithStorageImpl::~StringResourceWithStorageImpl()
2060 OUString
StringResourceWithStorageImpl::getImplementationName( )
2062 return "com.sun.star.comp.scripting.StringResourceWithStorage";
2065 sal_Bool
StringResourceWithStorageImpl::supportsService( const OUString
& rServiceName
)
2067 return cppu::supportsService(this, rServiceName
);
2070 Sequence
< OUString
> StringResourceWithStorageImpl::getSupportedServiceNames( )
2072 return { "com.sun.star.resource.StringResourceWithStorage" };
2079 void StringResourceWithStorageImpl::initialize( const Sequence
< Any
>& aArguments
)
2081 ::osl::MutexGuard
aGuard( getMutex() );
2083 if ( aArguments
.getLength() != 5 )
2085 throw RuntimeException(
2086 "StringResourceWithStorageImpl::initialize: invalid number of arguments!" );
2089 bool bOk
= (aArguments
[0] >>= m_xStorage
);
2090 if( bOk
&& !m_xStorage
.is() )
2095 throw IllegalArgumentException( "StringResourceWithStorageImpl::initialize: invalid storage", Reference
< XInterface
>(), 0 );
2098 implInitializeCommonParameters( aArguments
);
2102 // Forwarding calls to base class
2104 // XModifyBroadcaster
2105 void StringResourceWithStorageImpl::addModifyListener( const Reference
< XModifyListener
>& aListener
)
2107 StringResourceImpl::addModifyListener( aListener
);
2109 void StringResourceWithStorageImpl::removeModifyListener( const Reference
< XModifyListener
>& aListener
)
2111 StringResourceImpl::removeModifyListener( aListener
);
2114 // XStringResourceResolver
2115 OUString
StringResourceWithStorageImpl::resolveString( const OUString
& ResourceID
)
2117 return StringResourceImpl::resolveString( ResourceID
) ;
2119 OUString
StringResourceWithStorageImpl::resolveStringForLocale( const OUString
& ResourceID
, const Locale
& locale
)
2121 return StringResourceImpl::resolveStringForLocale( ResourceID
, locale
);
2123 sal_Bool
StringResourceWithStorageImpl::hasEntryForId( const OUString
& ResourceID
)
2125 return StringResourceImpl::hasEntryForId( ResourceID
) ;
2127 sal_Bool
StringResourceWithStorageImpl::hasEntryForIdAndLocale( const OUString
& ResourceID
,
2128 const Locale
& locale
)
2130 return StringResourceImpl::hasEntryForIdAndLocale( ResourceID
, locale
);
2132 Sequence
< OUString
> StringResourceWithStorageImpl::getResourceIDs( )
2134 return StringResourceImpl::getResourceIDs();
2136 Sequence
< OUString
> StringResourceWithStorageImpl::getResourceIDsForLocale
2137 ( const Locale
& locale
)
2139 return StringResourceImpl::getResourceIDsForLocale( locale
);
2141 Locale
StringResourceWithStorageImpl::getCurrentLocale()
2143 return StringResourceImpl::getCurrentLocale();
2145 Locale
StringResourceWithStorageImpl::getDefaultLocale( )
2147 return StringResourceImpl::getDefaultLocale();
2149 Sequence
< Locale
> StringResourceWithStorageImpl::getLocales( )
2151 return StringResourceImpl::getLocales();
2154 // XStringResourceManager
2155 sal_Bool
StringResourceWithStorageImpl::isReadOnly()
2157 return StringResourceImpl::isReadOnly();
2159 void StringResourceWithStorageImpl::setCurrentLocale( const Locale
& locale
, sal_Bool FindClosestMatch
)
2161 StringResourceImpl::setCurrentLocale( locale
, FindClosestMatch
);
2163 void StringResourceWithStorageImpl::setDefaultLocale( const Locale
& locale
)
2165 StringResourceImpl::setDefaultLocale( locale
);
2167 void StringResourceWithStorageImpl::setString( const OUString
& ResourceID
, const OUString
& Str
)
2169 StringResourceImpl::setString( ResourceID
, Str
);
2171 void StringResourceWithStorageImpl::setStringForLocale
2172 ( const OUString
& ResourceID
, const OUString
& Str
, const Locale
& locale
)
2174 StringResourceImpl::setStringForLocale( ResourceID
, Str
, locale
);
2176 void StringResourceWithStorageImpl::removeId( const OUString
& ResourceID
)
2178 StringResourceImpl::removeId( ResourceID
);
2180 void StringResourceWithStorageImpl::removeIdForLocale( const OUString
& ResourceID
, const Locale
& locale
)
2182 StringResourceImpl::removeIdForLocale( ResourceID
, locale
);
2184 void StringResourceWithStorageImpl::newLocale( const Locale
& locale
)
2186 StringResourceImpl::newLocale( locale
);
2188 void StringResourceWithStorageImpl::removeLocale( const Locale
& locale
)
2190 StringResourceImpl::removeLocale( locale
);
2192 sal_Int32
StringResourceWithStorageImpl::getUniqueNumericId( )
2194 return StringResourceImpl::getUniqueNumericId();
2197 // XStringResourcePersistence
2198 void StringResourceWithStorageImpl::store()
2200 ::osl::MutexGuard
aGuard( getMutex() );
2201 implCheckReadOnly( "StringResourceWithStorageImpl::store(): Read only" );
2203 bool bStoreAll
= m_bStorageChanged
;
2204 m_bStorageChanged
= false;
2205 if( !m_bModified
&& !bStoreAll
)
2208 implStoreAtStorage( m_aNameBase
, m_aComment
, m_xStorage
, true/*bUsedForStore*/, bStoreAll
);
2209 m_bModified
= false;
2212 sal_Bool
StringResourceWithStorageImpl::isModified( )
2214 return StringResourcePersistenceImpl::isModified();
2216 void StringResourceWithStorageImpl::setComment( const OUString
& Comment
)
2218 StringResourcePersistenceImpl::setComment( Comment
);
2220 void StringResourceWithStorageImpl::storeToStorage( const Reference
< XStorage
>& Storage
,
2221 const OUString
& NameBase
, const OUString
& Comment
)
2223 StringResourcePersistenceImpl::storeToStorage( Storage
, NameBase
, Comment
);
2225 void StringResourceWithStorageImpl::storeToURL( const OUString
& URL
,
2226 const OUString
& NameBase
, const OUString
& Comment
,
2227 const Reference
< css::task::XInteractionHandler
>& Handler
)
2229 StringResourcePersistenceImpl::storeToURL( URL
, NameBase
, Comment
, Handler
);
2231 Sequence
< ::sal_Int8
> StringResourceWithStorageImpl::exportBinary( )
2233 return StringResourcePersistenceImpl::exportBinary();
2235 void StringResourceWithStorageImpl::importBinary( const Sequence
< ::sal_Int8
>& Data
)
2237 StringResourcePersistenceImpl::importBinary( Data
);
2241 // XStringResourceWithStorage
2243 void StringResourceWithStorageImpl::storeAsStorage( const Reference
< XStorage
>& Storage
)
2245 setStorage( Storage
);
2249 void StringResourceWithStorageImpl::setStorage( const Reference
< XStorage
>& Storage
)
2251 ::osl::MutexGuard
aGuard( getMutex() );
2255 throw IllegalArgumentException( "StringResourceWithStorageImpl::setStorage: invalid storage", Reference
< XInterface
>(), 0 );
2258 implLoadAllLocales();
2260 m_xStorage
= Storage
;
2261 m_bStorageChanged
= true;
2265 // Private helper methods
2268 // Scan locale properties files
2269 void StringResourceWithStorageImpl::implScanLocales()
2271 if( m_xStorage
.is() )
2273 Sequence
< OUString
> aContentSeq
= m_xStorage
->getElementNames();
2274 implScanLocaleNames( aContentSeq
);
2277 implLoadAllLocales();
2281 bool StringResourceWithStorageImpl::implLoadLocale( LocaleItem
* pLocaleItem
)
2283 bool bSuccess
= false;
2286 OUString aStreamName
= implGetFileNameForLocaleItem( pLocaleItem
, m_aNameBase
) + ".properties";
2288 Reference
< io::XStream
> xElementStream
=
2289 m_xStorage
->openStreamElement( aStreamName
, ElementModes::READ
);
2291 if( xElementStream
.is() )
2293 Reference
< io::XInputStream
> xInputStream
= xElementStream
->getInputStream();
2294 if( xInputStream
.is() )
2296 bSuccess
= StringResourcePersistenceImpl::implReadPropertiesFile( pLocaleItem
, xInputStream
);
2297 xInputStream
->closeInput();
2301 catch( uno::Exception
& )
2308 // StringResourceWithLocationImpl
2311 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
2312 scripting_StringResourceWithLocationImpl_get_implementation(
2313 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
2315 return cppu::acquire(new StringResourceWithLocationImpl(context
));
2320 StringResourceWithLocationImpl::StringResourceWithLocationImpl( const Reference
< XComponentContext
>& rxContext
)
2321 : StringResourceWithLocationImpl_BASE( rxContext
)
2322 , m_bLocationChanged( false )
2327 StringResourceWithLocationImpl::~StringResourceWithLocationImpl()
2335 OUString
StringResourceWithLocationImpl::getImplementationName( )
2337 return "com.sun.star.comp.scripting.StringResourceWithLocation";
2340 sal_Bool
StringResourceWithLocationImpl::supportsService( const OUString
& rServiceName
)
2342 return cppu::supportsService(this, rServiceName
);
2345 Sequence
< OUString
> StringResourceWithLocationImpl::getSupportedServiceNames( )
2347 return { "com.sun.star.resource.StringResourceWithLocation" };
2354 void StringResourceWithLocationImpl::initialize( const Sequence
< Any
>& aArguments
)
2356 ::osl::MutexGuard
aGuard( getMutex() );
2358 if ( aArguments
.getLength() != 6 )
2360 throw RuntimeException(
2361 "XInitialization::initialize: invalid number of arguments!" );
2364 bool bOk
= (aArguments
[0] >>= m_aLocation
);
2365 sal_Int32 nLen
= m_aLocation
.getLength();
2366 if( bOk
&& nLen
== 0 )
2372 if( m_aLocation
[nLen
- 1] != '/' )
2378 throw IllegalArgumentException( "XInitialization::initialize: invalid URL", Reference
< XInterface
>(), 0 );
2382 bOk
= (aArguments
[5] >>= m_xInteractionHandler
);
2385 throw IllegalArgumentException( "StringResourceWithStorageImpl::initialize: invalid type", Reference
< XInterface
>(), 5 );
2388 implInitializeCommonParameters( aArguments
);
2392 // Forwarding calls to base class
2394 // XModifyBroadcaster
2395 void StringResourceWithLocationImpl::addModifyListener( const Reference
< XModifyListener
>& aListener
)
2397 StringResourceImpl::addModifyListener( aListener
);
2399 void StringResourceWithLocationImpl::removeModifyListener( const Reference
< XModifyListener
>& aListener
)
2401 StringResourceImpl::removeModifyListener( aListener
);
2404 // XStringResourceResolver
2405 OUString
StringResourceWithLocationImpl::resolveString( const OUString
& ResourceID
)
2407 return StringResourceImpl::resolveString( ResourceID
) ;
2409 OUString
StringResourceWithLocationImpl::resolveStringForLocale( const OUString
& ResourceID
, const Locale
& locale
)
2411 return StringResourceImpl::resolveStringForLocale( ResourceID
, locale
);
2413 sal_Bool
StringResourceWithLocationImpl::hasEntryForId( const OUString
& ResourceID
)
2415 return StringResourceImpl::hasEntryForId( ResourceID
) ;
2417 sal_Bool
StringResourceWithLocationImpl::hasEntryForIdAndLocale( const OUString
& ResourceID
,
2418 const Locale
& locale
)
2420 return StringResourceImpl::hasEntryForIdAndLocale( ResourceID
, locale
);
2422 Sequence
< OUString
> StringResourceWithLocationImpl::getResourceIDs( )
2424 return StringResourceImpl::getResourceIDs();
2426 Sequence
< OUString
> StringResourceWithLocationImpl::getResourceIDsForLocale
2427 ( const Locale
& locale
)
2429 return StringResourceImpl::getResourceIDsForLocale( locale
);
2431 Locale
StringResourceWithLocationImpl::getCurrentLocale()
2433 return StringResourceImpl::getCurrentLocale();
2435 Locale
StringResourceWithLocationImpl::getDefaultLocale( )
2437 return StringResourceImpl::getDefaultLocale();
2439 Sequence
< Locale
> StringResourceWithLocationImpl::getLocales( )
2441 return StringResourceImpl::getLocales();
2444 // XStringResourceManager
2445 sal_Bool
StringResourceWithLocationImpl::isReadOnly()
2447 return StringResourceImpl::isReadOnly();
2449 void StringResourceWithLocationImpl::setCurrentLocale( const Locale
& locale
, sal_Bool FindClosestMatch
)
2451 StringResourceImpl::setCurrentLocale( locale
, FindClosestMatch
);
2453 void StringResourceWithLocationImpl::setDefaultLocale( const Locale
& locale
)
2455 StringResourceImpl::setDefaultLocale( locale
);
2457 void StringResourceWithLocationImpl::setString( const OUString
& ResourceID
, const OUString
& Str
)
2459 StringResourceImpl::setString( ResourceID
, Str
);
2461 void StringResourceWithLocationImpl::setStringForLocale
2462 ( const OUString
& ResourceID
, const OUString
& Str
, const Locale
& locale
)
2464 StringResourceImpl::setStringForLocale( ResourceID
, Str
, locale
);
2466 void StringResourceWithLocationImpl::removeId( const OUString
& ResourceID
)
2468 StringResourceImpl::removeId( ResourceID
);
2470 void StringResourceWithLocationImpl::removeIdForLocale( const OUString
& ResourceID
, const Locale
& locale
)
2472 StringResourceImpl::removeIdForLocale( ResourceID
, locale
);
2474 void StringResourceWithLocationImpl::newLocale( const Locale
& locale
)
2476 StringResourceImpl::newLocale( locale
);
2478 void StringResourceWithLocationImpl::removeLocale( const Locale
& locale
)
2480 StringResourceImpl::removeLocale( locale
);
2482 sal_Int32
StringResourceWithLocationImpl::getUniqueNumericId( )
2484 return StringResourceImpl::getUniqueNumericId();
2487 // XStringResourcePersistence
2488 void StringResourceWithLocationImpl::store()
2490 ::osl::MutexGuard
aGuard( getMutex() );
2491 implCheckReadOnly( "StringResourceWithLocationImpl::store(): Read only" );
2493 bool bStoreAll
= m_bLocationChanged
;
2494 m_bLocationChanged
= false;
2495 if( !m_bModified
&& !bStoreAll
)
2498 Reference
< ucb::XSimpleFileAccess3
> xFileAccess
= getFileAccess();
2499 implStoreAtLocation( m_aLocation
, m_aNameBase
, m_aComment
,
2500 xFileAccess
, true/*bUsedForStore*/, bStoreAll
);
2501 m_bModified
= false;
2504 sal_Bool
StringResourceWithLocationImpl::isModified( )
2506 return StringResourcePersistenceImpl::isModified();
2508 void StringResourceWithLocationImpl::setComment( const OUString
& Comment
)
2510 StringResourcePersistenceImpl::setComment( Comment
);
2512 void StringResourceWithLocationImpl::storeToStorage( const Reference
< XStorage
>& Storage
,
2513 const OUString
& NameBase
, const OUString
& Comment
)
2515 StringResourcePersistenceImpl::storeToStorage( Storage
, NameBase
, Comment
);
2517 void StringResourceWithLocationImpl::storeToURL( const OUString
& URL
,
2518 const OUString
& NameBase
, const OUString
& Comment
,
2519 const Reference
< css::task::XInteractionHandler
>& Handler
)
2521 StringResourcePersistenceImpl::storeToURL( URL
, NameBase
, Comment
, Handler
);
2523 Sequence
< ::sal_Int8
> StringResourceWithLocationImpl::exportBinary( )
2525 return StringResourcePersistenceImpl::exportBinary();
2527 void StringResourceWithLocationImpl::importBinary( const Sequence
< ::sal_Int8
>& Data
)
2529 StringResourcePersistenceImpl::importBinary( Data
);
2533 // XStringResourceWithLocation
2535 // XStringResourceWithLocation
2536 void StringResourceWithLocationImpl::storeAsURL( const OUString
& URL
)
2542 void StringResourceWithLocationImpl::setURL( const OUString
& URL
)
2544 ::osl::MutexGuard
aGuard( getMutex() );
2545 implCheckReadOnly( "StringResourceWithLocationImpl::setURL(): Read only" );
2547 sal_Int32 nLen
= URL
.getLength();
2550 throw IllegalArgumentException( "StringResourceWithLocationImpl::setURL: invalid URL", Reference
< XInterface
>(), 0 );
2553 implLoadAllLocales();
2555 // Delete files at old location
2556 implStoreAtLocation( m_aLocation
, m_aNameBase
, m_aComment
,
2557 getFileAccess(), false/*bUsedForStore*/, false/*bStoreAll*/, true/*bKillAll*/ );
2560 m_bLocationChanged
= true;
2564 // Private helper methods
2567 // Scan locale properties files
2568 void StringResourceWithLocationImpl::implScanLocales()
2570 const Reference
< ucb::XSimpleFileAccess3
> xFileAccess
= getFileAccess();
2571 if( xFileAccess
.is() && xFileAccess
->isFolder( m_aLocation
) )
2573 Sequence
< OUString
> aContentSeq
= xFileAccess
->getFolderContents( m_aLocation
, false );
2574 implScanLocaleNames( aContentSeq
);
2579 bool StringResourceWithLocationImpl::implLoadLocale( LocaleItem
* pLocaleItem
)
2581 bool bSuccess
= false;
2583 const Reference
< ucb::XSimpleFileAccess3
> xFileAccess
= getFileAccess();
2584 if( xFileAccess
.is() )
2586 OUString aCompleteFileName
=
2587 implGetPathForLocaleItem( pLocaleItem
, m_aNameBase
, m_aLocation
);
2589 Reference
< io::XInputStream
> xInputStream
;
2592 xInputStream
= xFileAccess
->openFileRead( aCompleteFileName
);
2596 if( xInputStream
.is() )
2598 bSuccess
= StringResourcePersistenceImpl::implReadPropertiesFile( pLocaleItem
, xInputStream
);
2599 xInputStream
->closeInput();
2606 const Reference
< ucb::XSimpleFileAccess3
> & StringResourceWithLocationImpl::getFileAccess()
2608 ::osl::MutexGuard
aGuard( getMutex() );
2612 m_xSFI
= ucb::SimpleFileAccess::create(m_xContext
);
2614 if( m_xSFI
.is() && m_xInteractionHandler
.is() )
2615 m_xSFI
->setInteractionHandler( m_xInteractionHandler
);
2620 } // namespace stringresource
2623 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */