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/supportsservice.hxx>
31 #include <com/sun/star/beans/XPropertySet.hpp>
32 #include <com/sun/star/container/ElementExistException.hpp>
33 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
35 #include <osl/diagnose.h>
36 #include <o3tl/string_view.hxx>
37 #include <rtl/ref.hxx>
38 #include <rtl/tencinfo.h>
39 #include <rtl/ustrbuf.hxx>
40 #include <tools/urlobj.hxx>
41 #include <unotools/tempfile.hxx>
42 #include <i18nlangtag/languagetag.hxx>
43 #include <sal/log.hxx>
45 using namespace ::com::sun::star
;
46 using namespace ::com::sun::star::lang
;
47 using namespace ::com::sun::star::uno
;
48 using namespace ::com::sun::star::ucb
;
49 using namespace ::com::sun::star::util
;
50 using namespace ::com::sun::star::embed
;
51 using namespace ::com::sun::star::container
;
54 namespace stringresource
59 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
60 scripting_StringResourcePersistenceImpl_implementation(
61 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
63 return cppu::acquire(new StringResourcePersistenceImpl(context
));
67 StringResourceImpl::StringResourceImpl( const Reference
< XComponentContext
>& rxContext
)
68 : m_xContext( rxContext
)
69 , m_pCurrentLocaleItem( nullptr )
70 , m_pDefaultLocaleItem( nullptr )
71 , m_bDefaultModified( false )
72 , m_bModified( false )
73 , m_bReadOnly( false )
74 , m_nNextUniqueNumericId( UNIQUE_NUMBER_NEEDS_INITIALISATION
)
79 StringResourceImpl::~StringResourceImpl()
86 OUString
StringResourceImpl::getImplementationName( )
88 return u
"com.sun.star.comp.scripting.StringResource"_ustr
;
91 sal_Bool
StringResourceImpl::supportsService( const OUString
& rServiceName
)
93 return cppu::supportsService(this, rServiceName
);
96 Sequence
< OUString
> StringResourceImpl::getSupportedServiceNames( )
98 return { u
"com.sun.star.resource.StringResource"_ustr
};
102 // XModifyBroadcaster
104 void StringResourceImpl::addModifyListener( const Reference
< XModifyListener
>& aListener
)
106 if( !aListener
.is() )
107 throw RuntimeException();
109 std::unique_lock
aGuard( m_aMutex
);
110 m_aListenerContainer
.addInterface( aGuard
, aListener
);
113 void StringResourceImpl::removeModifyListener( const Reference
< XModifyListener
>& aListener
)
115 if( !aListener
.is() )
116 throw RuntimeException();
118 std::unique_lock
aGuard( m_aMutex
);
119 m_aListenerContainer
.removeInterface( aGuard
, aListener
);
123 // XStringResourceResolver
125 OUString
StringResourceImpl::implResolveString
126 (std::unique_lock
<std::mutex
>& rGuard
, const OUString
& ResourceID
, LocaleItem
* pLocaleItem
)
129 bool bSuccess
= false;
130 if( pLocaleItem
!= nullptr && loadLocale(rGuard
, pLocaleItem
) )
132 IdToStringMap::iterator it
= pLocaleItem
->m_aIdToStringMap
.find( ResourceID
);
133 if( it
!= pLocaleItem
->m_aIdToStringMap
.end() )
135 aRetStr
= (*it
).second
;
141 throw css::resource::MissingResourceException( "StringResourceImpl: No entry for ResourceID: " + ResourceID
);
146 OUString
StringResourceImpl::resolveString( const OUString
& ResourceID
)
148 std::unique_lock
aGuard( m_aMutex
);
149 return implResolveString(aGuard
, ResourceID
, m_pCurrentLocaleItem
);
152 OUString
StringResourceImpl::resolveStringForLocale( const OUString
& ResourceID
, const Locale
& locale
)
154 std::unique_lock
aGuard( m_aMutex
);
155 LocaleItem
* pLocaleItem
= getItemForLocale( locale
, false );
156 return implResolveString(aGuard
, ResourceID
, pLocaleItem
);
159 bool StringResourceImpl::implHasEntryForId(std::unique_lock
<std::mutex
>& rGuard
, const OUString
& ResourceID
, LocaleItem
* pLocaleItem
)
161 bool bSuccess
= false;
162 if( pLocaleItem
!= nullptr && loadLocale(rGuard
, pLocaleItem
) )
164 IdToStringMap::iterator it
= pLocaleItem
->m_aIdToStringMap
.find( ResourceID
);
165 if( it
!= pLocaleItem
->m_aIdToStringMap
.end() )
171 sal_Bool
StringResourceImpl::hasEntryForId( const OUString
& ResourceID
)
173 std::unique_lock
aGuard( m_aMutex
);
174 return implHasEntryForId(aGuard
, ResourceID
, m_pCurrentLocaleItem
);
177 sal_Bool
StringResourceImpl::hasEntryForIdAndLocale( const OUString
& ResourceID
,
178 const Locale
& locale
)
180 std::unique_lock
aGuard( m_aMutex
);
181 LocaleItem
* pLocaleItem
= getItemForLocale( locale
, false );
182 return implHasEntryForId(aGuard
, ResourceID
, pLocaleItem
);
185 Sequence
< OUString
> StringResourceImpl::implGetResourceIDs(std::unique_lock
<std::mutex
>& rGuard
, LocaleItem
* pLocaleItem
)
187 Sequence
< OUString
> aIDSeq( 0 );
188 if( pLocaleItem
&& loadLocale(rGuard
, pLocaleItem
) )
190 const IdToStringMap
& rHashMap
= pLocaleItem
->m_aIdToStringMap
;
191 sal_Int32 nResourceIDCount
= rHashMap
.size();
192 aIDSeq
.realloc( nResourceIDCount
);
193 OUString
* pStrings
= aIDSeq
.getArray();
196 for( const auto& rEntry
: rHashMap
)
198 pStrings
[iTarget
] = rEntry
.first
;
205 Sequence
< OUString
> StringResourceImpl::getResourceIDsForLocale
206 ( const Locale
& locale
)
208 std::unique_lock
aGuard( m_aMutex
);
209 LocaleItem
* pLocaleItem
= getItemForLocale( locale
, false );
210 return implGetResourceIDs(aGuard
, pLocaleItem
);
213 Sequence
< OUString
> StringResourceImpl::getResourceIDs( )
215 std::unique_lock
aGuard( m_aMutex
);
216 return implGetResourceIDs(aGuard
, m_pCurrentLocaleItem
);
219 Locale
StringResourceImpl::getCurrentLocale()
221 std::unique_lock
aGuard( m_aMutex
);
224 if( m_pCurrentLocaleItem
!= nullptr )
225 aRetLocale
= m_pCurrentLocaleItem
->m_locale
;
229 Locale
StringResourceImpl::getDefaultLocale( )
231 std::unique_lock
aGuard( m_aMutex
);
234 if( m_pDefaultLocaleItem
!= nullptr )
235 aRetLocale
= m_pDefaultLocaleItem
->m_locale
;
239 Sequence
< Locale
> StringResourceImpl::getLocales( )
241 std::unique_lock
aGuard( m_aMutex
);
243 sal_Int32 nSize
= m_aLocaleItemVector
.size();
244 Sequence
< Locale
> aLocalSeq( nSize
);
245 Locale
* pLocales
= aLocalSeq
.getArray();
247 for( const auto& pLocaleItem
: m_aLocaleItemVector
)
249 pLocales
[iTarget
] = pLocaleItem
->m_locale
;
256 // XStringResourceManager
258 void StringResourceImpl::implCheckReadOnly( const char* pExceptionMsg
)
262 OUString errorMsg
= OUString::createFromAscii( pExceptionMsg
);
263 throw NoSupportException( errorMsg
);
267 sal_Bool
StringResourceImpl::isReadOnly()
272 void StringResourceImpl::implSetCurrentLocale( std::unique_lock
<std::mutex
>& rGuard
, const Locale
& locale
,
273 bool FindClosestMatch
, bool bUseDefaultIfNoMatch
)
275 LocaleItem
* pLocaleItem
= nullptr;
276 if( FindClosestMatch
)
277 pLocaleItem
= getClosestMatchItemForLocale( locale
);
279 pLocaleItem
= getItemForLocale( locale
, true );
281 if( pLocaleItem
== nullptr && bUseDefaultIfNoMatch
)
282 pLocaleItem
= m_pDefaultLocaleItem
;
284 if( pLocaleItem
!= nullptr )
286 (void)loadLocale(rGuard
, pLocaleItem
);
287 m_pCurrentLocaleItem
= pLocaleItem
;
289 // Only notify without modifying
290 implNotifyListeners(rGuard
);
294 void StringResourceImpl::setCurrentLocale( const Locale
& locale
, sal_Bool FindClosestMatch
)
296 std::unique_lock
aGuard( m_aMutex
);
297 implSetCurrentLocale( aGuard
, locale
, FindClosestMatch
, false/*bUseDefaultIfNoMatch*/ );
300 void StringResourceImpl::setDefaultLocale( const Locale
& locale
)
302 std::unique_lock
aGuard( m_aMutex
);
303 implCheckReadOnly( "StringResourceImpl::setDefaultLocale(): Read only" );
305 LocaleItem
* pLocaleItem
= getItemForLocale( locale
, true );
306 if( pLocaleItem
&& pLocaleItem
!= m_pDefaultLocaleItem
)
308 if( m_pDefaultLocaleItem
)
310 m_aChangedDefaultLocaleVector
.push_back(
311 std::make_unique
<LocaleItem
>( m_pDefaultLocaleItem
->m_locale
) );
314 m_pDefaultLocaleItem
= pLocaleItem
;
315 m_bDefaultModified
= true;
316 implModified(aGuard
);
320 void StringResourceImpl::implSetString( std::unique_lock
<std::mutex
>& rGuard
, const OUString
& ResourceID
,
321 const OUString
& Str
, LocaleItem
* pLocaleItem
)
323 if( !(pLocaleItem
!= nullptr && loadLocale(rGuard
, pLocaleItem
)) )
326 IdToStringMap
& rHashMap
= pLocaleItem
->m_aIdToStringMap
;
328 IdToStringMap::iterator it
= rHashMap
.find( ResourceID
);
329 bool bNew
= ( it
== rHashMap
.end() );
332 IdToIndexMap
& rIndexMap
= pLocaleItem
->m_aIdToIndexMap
;
333 rIndexMap
[ ResourceID
] = pLocaleItem
->m_nNextIndex
++;
334 implScanIdForNumber(rGuard
, ResourceID
);
336 rHashMap
[ ResourceID
] = Str
;
337 pLocaleItem
->m_bModified
= true;
338 implModified(rGuard
);
341 void StringResourceImpl::setString( const OUString
& ResourceID
, const OUString
& Str
)
343 std::unique_lock
aGuard( m_aMutex
);
344 implCheckReadOnly( "StringResourceImpl::setString(): Read only" );
345 implSetString( aGuard
, ResourceID
, Str
, m_pCurrentLocaleItem
);
348 void StringResourceImpl::setStringForLocale
349 ( const OUString
& ResourceID
, const OUString
& Str
, const Locale
& locale
)
351 std::unique_lock
aGuard( m_aMutex
);
352 implCheckReadOnly( "StringResourceImpl::setStringForLocale(): Read only" );
353 LocaleItem
* pLocaleItem
= getItemForLocale( locale
, false );
354 implSetString( aGuard
, ResourceID
, Str
, pLocaleItem
);
357 void StringResourceImpl::implRemoveId( std::unique_lock
<std::mutex
>& rGuard
, const OUString
& ResourceID
, LocaleItem
* pLocaleItem
)
359 if( pLocaleItem
!= nullptr && loadLocale(rGuard
, pLocaleItem
) )
361 IdToStringMap
& rHashMap
= pLocaleItem
->m_aIdToStringMap
;
362 IdToStringMap::iterator it
= rHashMap
.find( ResourceID
);
363 if( it
== rHashMap
.end() )
365 throw css::resource::MissingResourceException( "StringResourceImpl: No entries for ResourceID: " + ResourceID
);
367 rHashMap
.erase( it
);
368 pLocaleItem
->m_bModified
= true;
369 implModified(rGuard
);
373 void StringResourceImpl::removeId( const OUString
& ResourceID
)
375 std::unique_lock
aGuard( m_aMutex
);
376 implCheckReadOnly( "StringResourceImpl::removeId(): Read only" );
377 implRemoveId( aGuard
, ResourceID
, m_pCurrentLocaleItem
);
380 void StringResourceImpl::removeIdForLocale( const OUString
& ResourceID
, const Locale
& locale
)
382 std::unique_lock
aGuard( m_aMutex
);
383 implCheckReadOnly( "StringResourceImpl::removeIdForLocale(): Read only" );
384 LocaleItem
* pLocaleItem
= getItemForLocale( locale
, false );
385 implRemoveId( aGuard
, ResourceID
, pLocaleItem
);
388 void StringResourceImpl::newLocale( const Locale
& locale
)
390 std::unique_lock
aGuard( m_aMutex
);
391 implCheckReadOnly( "StringResourceImpl::newLocale(): Read only" );
393 if( getItemForLocale( locale
, false ) != nullptr )
395 throw ElementExistException( u
"StringResourceImpl: locale already exists"_ustr
);
398 // TODO?: Check if locale is valid? How?
401 // OUString errorMsg("StringResourceImpl: Invalid locale");
402 // throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 );
405 LocaleItem
* pLocaleItem
= new LocaleItem( locale
);
406 m_aLocaleItemVector
.emplace_back( pLocaleItem
);
407 pLocaleItem
->m_bModified
= true;
409 // Copy strings from default locale
410 LocaleItem
* pCopyFromItem
= m_pDefaultLocaleItem
;
411 if( pCopyFromItem
== nullptr )
412 pCopyFromItem
= m_pCurrentLocaleItem
;
413 if( pCopyFromItem
!= nullptr && loadLocale(aGuard
, pCopyFromItem
) )
415 const IdToStringMap
& rSourceMap
= pCopyFromItem
->m_aIdToStringMap
;
416 IdToStringMap
& rTargetMap
= pLocaleItem
->m_aIdToStringMap
;
417 for( const auto& rEntry
: rSourceMap
)
419 OUString aId
= rEntry
.first
;
420 rTargetMap
[ aId
] = rEntry
.second
;
423 const IdToIndexMap
& rSourceIndexMap
= pCopyFromItem
->m_aIdToIndexMap
;
424 IdToIndexMap
& rTargetIndexMap
= pLocaleItem
->m_aIdToIndexMap
;
425 for( const auto& rIndex
: rSourceIndexMap
)
427 OUString aId
= rIndex
.first
;
428 sal_Int32 nIndex
= rIndex
.second
;
429 rTargetIndexMap
[ aId
] = nIndex
;
431 pLocaleItem
->m_nNextIndex
= pCopyFromItem
->m_nNextIndex
;
434 if( m_pCurrentLocaleItem
== nullptr )
435 m_pCurrentLocaleItem
= pLocaleItem
;
437 if( m_pDefaultLocaleItem
== nullptr )
439 m_pDefaultLocaleItem
= pLocaleItem
;
440 m_bDefaultModified
= true;
443 implModified(aGuard
);
446 void StringResourceImpl::removeLocale( const Locale
& locale
)
448 std::unique_lock
aGuard( m_aMutex
);
449 implCheckReadOnly( "StringResourceImpl::removeLocale(): Read only" );
451 LocaleItem
* pRemoveItem
= getItemForLocale( locale
, true );
456 sal_Int32 nLocaleCount
= m_aLocaleItemVector
.size();
457 if( nLocaleCount
> 1 )
459 if( m_pCurrentLocaleItem
== pRemoveItem
||
460 m_pDefaultLocaleItem
== pRemoveItem
)
462 LocaleItem
* pFallbackItem
= nullptr;
463 for( const auto& pLocaleItem
: m_aLocaleItemVector
)
465 if( pLocaleItem
.get() != pRemoveItem
)
467 pFallbackItem
= pLocaleItem
.get();
471 if( m_pCurrentLocaleItem
== pRemoveItem
)
473 assert(pFallbackItem
);
474 setCurrentLocale( pFallbackItem
->m_locale
, false/*FindClosestMatch*/ );
476 if( m_pDefaultLocaleItem
== pRemoveItem
)
478 assert(pFallbackItem
);
479 setDefaultLocale( pFallbackItem
->m_locale
);
483 auto it
= std::find_if(m_aLocaleItemVector
.begin(), m_aLocaleItemVector
.end(),
484 [&pRemoveItem
](const std::unique_ptr
<LocaleItem
>& rxItem
) { return rxItem
.get() == pRemoveItem
; });
485 if (it
== m_aLocaleItemVector
.end())
488 // Remember locale item to delete file while storing
489 m_aDeletedLocaleItemVector
.push_back( std::move(*it
) );
492 if( nLocaleCount
== 1 )
494 m_nNextUniqueNumericId
= 0;
495 if( m_pDefaultLocaleItem
)
497 m_aChangedDefaultLocaleVector
.push_back(
498 std::make_unique
<LocaleItem
>( m_pDefaultLocaleItem
->m_locale
) );
500 m_pCurrentLocaleItem
= nullptr;
501 m_pDefaultLocaleItem
= nullptr;
504 m_aLocaleItemVector
.erase( it
);
506 implModified(aGuard
);
509 void StringResourceImpl::implScanIdForNumber(std::unique_lock
<std::mutex
>& /*rGuard*/, const OUString
& ResourceID
)
511 const sal_Unicode
* pSrc
= ResourceID
.getStr();
512 sal_Int32 nLen
= ResourceID
.getLength();
514 sal_Int32 nNumber
= 0;
515 for( sal_Int32 i
= 0 ; i
< nLen
; i
++ )
517 sal_Unicode c
= pSrc
[i
];
518 if( c
>= '0' && c
<= '9' )
520 sal_uInt16 nDigitVal
= c
- '0';
521 nNumber
= 10*nNumber
+ nDigitVal
;
527 if( m_nNextUniqueNumericId
< nNumber
+ 1 )
528 m_nNextUniqueNumericId
= nNumber
+ 1;
531 sal_Int32
StringResourceImpl::getUniqueNumericId( )
533 std::unique_lock
aGuard( m_aMutex
);
535 if( m_nNextUniqueNumericId
== UNIQUE_NUMBER_NEEDS_INITIALISATION
)
537 implLoadAllLocales(aGuard
);
538 m_nNextUniqueNumericId
= 0;
541 if( m_nNextUniqueNumericId
< UNIQUE_NUMBER_NEEDS_INITIALISATION
)
543 throw NoSupportException( u
"getUniqueNumericId: Extended sal_Int32 range"_ustr
);
545 return m_nNextUniqueNumericId
;
549 // Private helper methods
551 LocaleItem
* StringResourceImpl::getItemForLocale
552 ( const Locale
& locale
, bool bException
)
554 LocaleItem
* pRetItem
= nullptr;
557 for( auto& pLocaleItem
: m_aLocaleItemVector
)
561 Locale
& cmp_locale
= pLocaleItem
->m_locale
;
562 if( cmp_locale
.Language
== locale
.Language
&&
563 cmp_locale
.Country
== locale
.Country
&&
564 cmp_locale
.Variant
== locale
.Variant
)
566 pRetItem
= pLocaleItem
.get();
572 if( pRetItem
== nullptr && bException
)
574 throw IllegalArgumentException( u
"StringResourceImpl: Invalid locale"_ustr
, Reference
< XInterface
>(), 0 );
579 // Returns the LocaleItem for a given locale, if it exists, otherwise NULL.
580 // This method performs a closest match search, at least the language must match.
581 LocaleItem
* StringResourceImpl::getClosestMatchItemForLocale( const Locale
& locale
)
583 LocaleItem
* pRetItem
= nullptr;
585 ::std::vector
< Locale
> aLocales( m_aLocaleItemVector
.size());
587 for( const auto& pLocaleItem
: m_aLocaleItemVector
)
589 aLocales
[i
] = (pLocaleItem
? pLocaleItem
->m_locale
: Locale());
592 ::std::vector
< Locale
>::const_iterator
iFound( LanguageTag::getMatchingFallback( aLocales
, locale
));
593 if (iFound
!= aLocales
.end())
594 pRetItem
= (m_aLocaleItemVector
.begin() + (iFound
- aLocales
.begin()))->get();
599 void StringResourceImpl::implModified(std::unique_lock
<std::mutex
>& rGuard
)
602 implNotifyListeners(rGuard
);
605 void StringResourceImpl::implNotifyListeners(std::unique_lock
<std::mutex
>& rGuard
)
608 aEvent
.Source
= getXWeak();
609 m_aListenerContainer
.forEach(rGuard
,
610 [&aEvent
](const css::uno::Reference
<XModifyListener
>& xListener
)
612 xListener
->modified(aEvent
);
619 bool StringResourceImpl::loadLocale(std::unique_lock
<std::mutex
>& /*rGuard*/, LocaleItem
*)
621 // Base implementation has nothing to load
625 void StringResourceImpl::implLoadAllLocales(std::unique_lock
<std::mutex
>& /*rGuard*/)
627 // Base implementation has nothing to load
630 // StringResourcePersistenceImpl
632 StringResourcePersistenceImpl::StringResourcePersistenceImpl( const Reference
< XComponentContext
>& rxContext
)
633 : StringResourcePersistenceImpl_BASE( rxContext
)
637 StringResourcePersistenceImpl::~StringResourcePersistenceImpl()
643 OUString
StringResourcePersistenceImpl::getImplementationName( )
645 return u
"com.sun.star.comp.scripting.StringResource"_ustr
;
649 sal_Bool
StringResourcePersistenceImpl::supportsService( const OUString
& rServiceName
)
651 return cppu::supportsService( this, rServiceName
);
655 Sequence
< OUString
> StringResourcePersistenceImpl::getSupportedServiceNames( )
657 return StringResourceImpl::getSupportedServiceNames();
661 // XInitialization base functionality for derived classes
664 constexpr OUString aNameBaseDefaultStr
= u
"strings"_ustr
;
666 void StringResourcePersistenceImpl::implInitializeCommonParameters
667 ( std::unique_lock
<std::mutex
>& rGuard
, const Sequence
< Any
>& aArguments
)
669 bool bReadOnlyOk
= (aArguments
[1] >>= m_bReadOnly
);
672 throw IllegalArgumentException( u
"XInitialization::initialize: Expected ReadOnly flag"_ustr
, Reference
< XInterface
>(), 1 );
675 css::lang::Locale aCurrentLocale
;
676 bool bLocaleOk
= (aArguments
[2] >>= aCurrentLocale
);
679 throw IllegalArgumentException( u
"XInitialization::initialize: Expected Locale"_ustr
, Reference
< XInterface
>(), 2 );
682 bool bNameBaseOk
= (aArguments
[3] >>= m_aNameBase
);
685 throw IllegalArgumentException( u
"XInitialization::initialize: Expected NameBase string"_ustr
, Reference
< XInterface
>(), 3 );
687 if( m_aNameBase
.isEmpty() )
688 m_aNameBase
= aNameBaseDefaultStr
;
690 bool bCommentOk
= (aArguments
[4] >>= m_aComment
);
693 throw IllegalArgumentException( u
"XInitialization::initialize: Expected Comment string"_ustr
, Reference
< XInterface
>(), 4 );
696 implScanLocales(rGuard
);
698 implSetCurrentLocale( rGuard
, aCurrentLocale
, true/*FindClosestMatch*/, true/*bUseDefaultIfNoMatch*/ );
702 // Forwarding calls to base class
704 // XModifyBroadcaster
705 void StringResourcePersistenceImpl::addModifyListener( const Reference
< XModifyListener
>& aListener
)
707 StringResourceImpl::addModifyListener( aListener
);
709 void StringResourcePersistenceImpl::removeModifyListener( const Reference
< XModifyListener
>& aListener
)
711 StringResourceImpl::removeModifyListener( aListener
);
714 // XStringResourceResolver
715 OUString
StringResourcePersistenceImpl::resolveString( const OUString
& ResourceID
)
717 return StringResourceImpl::resolveString( ResourceID
) ;
719 OUString
StringResourcePersistenceImpl::resolveStringForLocale( const OUString
& ResourceID
, const Locale
& locale
)
721 return StringResourceImpl::resolveStringForLocale( ResourceID
, locale
);
723 sal_Bool
StringResourcePersistenceImpl::hasEntryForId( const OUString
& ResourceID
)
725 return StringResourceImpl::hasEntryForId( ResourceID
) ;
727 sal_Bool
StringResourcePersistenceImpl::hasEntryForIdAndLocale( const OUString
& ResourceID
,
728 const Locale
& locale
)
730 return StringResourceImpl::hasEntryForIdAndLocale( ResourceID
, locale
);
732 Locale
StringResourcePersistenceImpl::getCurrentLocale()
734 return StringResourceImpl::getCurrentLocale();
736 Locale
StringResourcePersistenceImpl::getDefaultLocale( )
738 return StringResourceImpl::getDefaultLocale();
740 Sequence
< Locale
> StringResourcePersistenceImpl::getLocales( )
742 return StringResourceImpl::getLocales();
745 // XStringResourceManager
746 sal_Bool
StringResourcePersistenceImpl::isReadOnly()
748 return StringResourceImpl::isReadOnly();
750 void StringResourcePersistenceImpl::setCurrentLocale( const Locale
& locale
, sal_Bool FindClosestMatch
)
752 StringResourceImpl::setCurrentLocale( locale
, FindClosestMatch
);
754 void StringResourcePersistenceImpl::setDefaultLocale( const Locale
& locale
)
756 StringResourceImpl::setDefaultLocale( locale
);
758 Sequence
< OUString
> StringResourcePersistenceImpl::getResourceIDs( )
760 return StringResourceImpl::getResourceIDs();
762 void StringResourcePersistenceImpl::setString( const OUString
& ResourceID
, const OUString
& Str
)
764 StringResourceImpl::setString( ResourceID
, Str
);
766 void StringResourcePersistenceImpl::setStringForLocale
767 ( const OUString
& ResourceID
, const OUString
& Str
, const Locale
& locale
)
769 StringResourceImpl::setStringForLocale( ResourceID
, Str
, locale
);
771 Sequence
< OUString
> StringResourcePersistenceImpl::getResourceIDsForLocale
772 ( const Locale
& locale
)
774 return StringResourceImpl::getResourceIDsForLocale( locale
);
776 void StringResourcePersistenceImpl::removeId( const OUString
& ResourceID
)
778 StringResourceImpl::removeId( ResourceID
);
780 void StringResourcePersistenceImpl::removeIdForLocale( const OUString
& ResourceID
, const Locale
& locale
)
782 StringResourceImpl::removeIdForLocale( ResourceID
, locale
);
784 void StringResourcePersistenceImpl::newLocale( const Locale
& locale
)
786 StringResourceImpl::newLocale( locale
);
788 void StringResourcePersistenceImpl::removeLocale( const Locale
& locale
)
790 StringResourceImpl::removeLocale( locale
);
792 sal_Int32
StringResourcePersistenceImpl::getUniqueNumericId( )
794 return StringResourceImpl::getUniqueNumericId();
798 // XStringResourcePersistence
800 void StringResourcePersistenceImpl::store()
804 sal_Bool
StringResourcePersistenceImpl::isModified( )
806 std::unique_lock
aGuard( m_aMutex
);
811 void StringResourcePersistenceImpl::setComment( const OUString
& Comment
)
813 m_aComment
= Comment
;
816 void StringResourcePersistenceImpl::storeToStorage( const Reference
< XStorage
>& Storage
,
817 const OUString
& NameBase
, const OUString
& Comment
)
819 std::unique_lock
aGuard( m_aMutex
);
821 implStoreAtStorage(aGuard
, NameBase
, Comment
, Storage
, false/*bUsedForStore*/, true/*bStoreAll*/ );
824 void StringResourcePersistenceImpl::implStoreAtStorage
826 std::unique_lock
<std::mutex
>& rGuard
,
827 const OUString
& aNameBase
,
828 const OUString
& aComment
,
829 const Reference
< css::embed::XStorage
>& Storage
,
834 // Delete files for deleted locales
837 for( auto& pLocaleItem
: m_aDeletedLocaleItemVector
)
841 OUString aStreamName
= implGetFileNameForLocaleItem( pLocaleItem
.get(), m_aNameBase
) + ".properties";
845 Storage
->removeElement( aStreamName
);
853 m_aDeletedLocaleItemVector
.clear();
856 for( auto& pLocaleItem
: m_aLocaleItemVector
)
858 if( pLocaleItem
!= nullptr && (bStoreAll
|| pLocaleItem
->m_bModified
) &&
859 loadLocale(rGuard
, pLocaleItem
.get()) )
861 OUString aStreamName
= implGetFileNameForLocaleItem( pLocaleItem
.get(), aNameBase
) + ".properties";
863 Reference
< io::XStream
> xElementStream
=
864 Storage
->openStreamElement( aStreamName
, ElementModes::READWRITE
);
866 uno::Reference
< beans::XPropertySet
> xProps( xElementStream
, uno::UNO_QUERY
);
867 OSL_ENSURE( xProps
.is(), "The StorageStream must implement XPropertySet interface!" );
870 OUString
aPropName(u
"MediaType"_ustr
);
871 xProps
->setPropertyValue( aPropName
, uno::Any( u
"text/plain"_ustr
) );
873 aPropName
= "UseCommonStoragePasswordEncryption";
874 xProps
->setPropertyValue( aPropName
, uno::Any( true ) );
877 Reference
< io::XOutputStream
> xOutputStream
= xElementStream
->getOutputStream();
878 if( xOutputStream
.is() )
879 implWritePropertiesFile( pLocaleItem
.get(), xOutputStream
, aComment
);
880 xOutputStream
->closeOutput();
883 pLocaleItem
->m_bModified
= false;
887 // Delete files for changed defaults
890 for( auto& pLocaleItem
: m_aChangedDefaultLocaleVector
)
892 OUString aStreamName
= implGetFileNameForLocaleItem( pLocaleItem
.get(), m_aNameBase
) + ".default";
896 Storage
->removeElement( aStreamName
);
903 m_aChangedDefaultLocaleVector
.clear();
907 if( !(m_pDefaultLocaleItem
!= nullptr && (bStoreAll
|| m_bDefaultModified
)) )
910 OUString aStreamName
= implGetFileNameForLocaleItem( m_pDefaultLocaleItem
, aNameBase
) + ".default";
912 Reference
< io::XStream
> xElementStream
=
913 Storage
->openStreamElement( aStreamName
, ElementModes::READWRITE
);
915 // Only create stream without content
916 Reference
< io::XOutputStream
> xOutputStream
= xElementStream
->getOutputStream();
917 xOutputStream
->closeOutput();
920 m_bDefaultModified
= false;
923 void StringResourcePersistenceImpl::storeToURL( const OUString
& URL
,
924 const OUString
& NameBase
, const OUString
& Comment
,
925 const Reference
< css::task::XInteractionHandler
>& Handler
)
927 std::unique_lock
aGuard( m_aMutex
);
929 Reference
< ucb::XSimpleFileAccess3
> xFileAccess
= ucb::SimpleFileAccess::create(m_xContext
);
931 xFileAccess
->setInteractionHandler( Handler
);
933 implStoreAtLocation(aGuard
, URL
, NameBase
, Comment
, xFileAccess
, false/*bUsedForStore*/, true/*bStoreAll*/);
936 void StringResourcePersistenceImpl::implKillRemovedLocaleFiles
938 std::u16string_view Location
,
939 const OUString
& aNameBase
,
940 const css::uno::Reference
< css::ucb::XSimpleFileAccess3
>& xFileAccess
943 // Delete files for deleted locales
944 for( auto& pLocaleItem
: m_aDeletedLocaleItemVector
)
948 OUString aCompleteFileName
=
949 implGetPathForLocaleItem( pLocaleItem
.get(), aNameBase
, Location
);
950 if( xFileAccess
->exists( aCompleteFileName
) )
951 xFileAccess
->kill( aCompleteFileName
);
956 m_aDeletedLocaleItemVector
.clear();
959 void StringResourcePersistenceImpl::implKillChangedDefaultFiles
961 std::u16string_view Location
,
962 const OUString
& aNameBase
,
963 const css::uno::Reference
< css::ucb::XSimpleFileAccess3
>& xFileAccess
966 // Delete files for changed defaults
967 for( auto& pLocaleItem
: m_aChangedDefaultLocaleVector
)
969 OUString aCompleteFileName
=
970 implGetPathForLocaleItem( pLocaleItem
.get(), aNameBase
, Location
, true );
971 if( xFileAccess
->exists( aCompleteFileName
) )
972 xFileAccess
->kill( aCompleteFileName
);
975 m_aChangedDefaultLocaleVector
.clear();
978 void StringResourcePersistenceImpl::implStoreAtLocation
980 std::unique_lock
<std::mutex
>& rGuard
,
981 std::u16string_view Location
,
982 const OUString
& aNameBase
,
983 const OUString
& aComment
,
984 const Reference
< ucb::XSimpleFileAccess3
>& xFileAccess
,
990 // Delete files for deleted locales
991 if( bUsedForStore
|| bKillAll
)
992 implKillRemovedLocaleFiles( Location
, aNameBase
, xFileAccess
);
994 for( auto& pLocaleItem
: m_aLocaleItemVector
)
996 if( pLocaleItem
!= nullptr && (bStoreAll
|| bKillAll
|| pLocaleItem
->m_bModified
) &&
997 loadLocale(rGuard
, pLocaleItem
.get()) )
999 OUString aCompleteFileName
=
1000 implGetPathForLocaleItem( pLocaleItem
.get(), aNameBase
, Location
);
1001 if( xFileAccess
->exists( aCompleteFileName
) )
1002 xFileAccess
->kill( aCompleteFileName
);
1006 // Create Output stream
1007 Reference
< io::XOutputStream
> xOutputStream
= xFileAccess
->openFileWrite( aCompleteFileName
);
1008 if( xOutputStream
.is() )
1010 implWritePropertiesFile( pLocaleItem
.get(), xOutputStream
, aComment
);
1011 xOutputStream
->closeOutput();
1014 pLocaleItem
->m_bModified
= false;
1019 // Delete files for changed defaults
1020 if( bUsedForStore
|| bKillAll
)
1021 implKillChangedDefaultFiles( Location
, aNameBase
, xFileAccess
);
1024 if( !(m_pDefaultLocaleItem
!= nullptr && (bStoreAll
|| bKillAll
|| m_bDefaultModified
)) )
1027 OUString aCompleteFileName
=
1028 implGetPathForLocaleItem( m_pDefaultLocaleItem
, aNameBase
, Location
, true );
1029 if( xFileAccess
->exists( aCompleteFileName
) )
1030 xFileAccess
->kill( aCompleteFileName
);
1034 // Create Output stream
1035 Reference
< io::XOutputStream
> xOutputStream
= xFileAccess
->openFileWrite( aCompleteFileName
);
1036 if( xOutputStream
.is() )
1037 xOutputStream
->closeOutput();
1040 m_bDefaultModified
= false;
1045 // BinaryOutput, helper class for exportBinary
1049 rtl::Reference
< utl::TempFileFastService
> m_xTempFile
;
1052 explicit BinaryOutput();
1054 Reference
< io::XOutputStream
> getOutputStream() const
1055 { return m_xTempFile
; }
1057 Sequence
< ::sal_Int8
> closeAndGetData();
1059 // Template to be used with sal_Int16 and sal_Unicode
1061 void write16BitInt( T n
);
1062 void writeInt16( sal_Int16 n
)
1063 { write16BitInt( n
); }
1064 void writeUnicodeChar( sal_Unicode n
)
1065 { write16BitInt( n
); }
1066 void writeInt32( sal_Int32 n
);
1067 void writeString( const OUString
& aStr
);
1070 BinaryOutput::BinaryOutput()
1072 m_xTempFile
= new utl::TempFileFastService
;
1076 void BinaryOutput::write16BitInt( T n
)
1078 if( !m_xTempFile
.is() )
1081 Sequence
< sal_Int8
> aSeq( 2 );
1082 sal_Int8
* p
= aSeq
.getArray();
1084 sal_Int8 nLow
= sal_Int8( n
& 0xff );
1085 sal_Int8 nHigh
= sal_Int8( n
>> 8 );
1089 m_xTempFile
->writeBytes( aSeq
);
1092 void BinaryOutput::writeInt32( sal_Int32 n
)
1094 if( !m_xTempFile
.is() )
1097 Sequence
< sal_Int8
> aSeq( 4 );
1098 sal_Int8
* p
= aSeq
.getArray();
1100 for( sal_Int16 i
= 0 ; i
< 4 ; i
++ )
1102 p
[i
] = sal_Int8( n
& 0xff );
1105 m_xTempFile
->writeBytes( aSeq
);
1108 void BinaryOutput::writeString( const OUString
& aStr
)
1110 sal_Int32 nLen
= aStr
.getLength();
1111 const sal_Unicode
* pStr
= aStr
.getStr();
1113 for( sal_Int32 i
= 0 ; i
< nLen
; i
++ )
1114 writeUnicodeChar( pStr
[i
] );
1116 writeUnicodeChar( 0 );
1119 Sequence
< ::sal_Int8
> BinaryOutput::closeAndGetData()
1121 Sequence
< ::sal_Int8
> aRetSeq
;
1122 if( !m_xTempFile
.is() )
1125 m_xTempFile
->closeOutput();
1127 sal_Int32 nSize
= static_cast<sal_Int32
>(m_xTempFile
->getPosition());
1129 m_xTempFile
->seek( 0 );
1130 sal_Int32 nRead
= m_xTempFile
->readBytes( aRetSeq
, nSize
);
1131 OSL_ENSURE( nRead
== nSize
, "BinaryOutput::closeAndGetData: nRead != nSize" );
1141 // 0 + 1 sal_Int16: Version, currently 0, low byte first
1142 // 2 + 3 sal_Int16: Locale count = n, low byte first
1143 // 4 + 5 sal_Int16: Default Locale position in Locale list, == n if none
1144 // 6 - 7 sal_Int32: Start index locale block 0, lowest byte first
1145 // (n-1) * sal_Int32: Start index locale block 1 to n, lowest byte first
1146 // 6 + 4*n sal_Int32: "Start index" non existing locale block n+1,
1147 // marks the first invalid index, kind of EOF
1150 // All strings are stored as 2-Byte-0 terminated sequence
1151 // of 16 bit Unicode characters, each with low byte first
1152 // Empty strings only contain the 2-Byte-0
1154 // Members of com.sun.star.lang.Locale
1155 // with l1 = Locale.Language.getLength()
1156 // with l2 = Locale.Country.getLength()
1157 // with l3 = Locale.Variant.getLength()
1158 // pos0 = 0 Locale.Language
1159 // pos1 = 2 * (l1 + 1) Locale.Country
1160 // pos2 = pos1 + 2 * (l2 + 1) Locale.Variant
1161 // pos3 = pos2 + 2 * (l3 + 1)
1162 // pos3 Properties file written by implWritePropertiesFile
1164 Sequence
< sal_Int8
> StringResourcePersistenceImpl::exportBinary( )
1166 std::unique_lock
aGuard( m_aMutex
);
1170 sal_Int32 nLocaleCount
= m_aLocaleItemVector
.size();
1171 std::vector
<Sequence
< sal_Int8
>> aLocaleDataSeq(nLocaleCount
);
1173 sal_Int32 iLocale
= 0;
1174 sal_Int32 iDefault
= 0;
1175 for( auto& pLocaleItem
: m_aLocaleItemVector
)
1177 if( pLocaleItem
!= nullptr && loadLocale(aGuard
, pLocaleItem
.get()) )
1179 if( m_pDefaultLocaleItem
== pLocaleItem
.get() )
1182 BinaryOutput aLocaleOut
;
1183 implWriteLocaleBinary( pLocaleItem
.get(), aLocaleOut
);
1185 aLocaleDataSeq
[iLocale
] = aLocaleOut
.closeAndGetData();
1191 sal_Int16 nLocaleCount16
= static_cast<sal_Int16
>(nLocaleCount
);
1192 sal_Int16 iDefault16
= static_cast<sal_Int16
>(iDefault
);
1193 aOut
.writeInt16( 0 ); // nVersion
1194 aOut
.writeInt16( nLocaleCount16
);
1195 aOut
.writeInt16( iDefault16
);
1197 // Write data positions
1198 sal_Int32 nDataPos
= 6 + 4 * (nLocaleCount
+ 1);
1199 for( iLocale
= 0; iLocale
< nLocaleCount
; iLocale
++ )
1201 aOut
.writeInt32( nDataPos
);
1203 Sequence
< sal_Int8
>& rSeq
= aLocaleDataSeq
[iLocale
];
1204 sal_Int32 nSeqLen
= rSeq
.getLength();
1205 nDataPos
+= nSeqLen
;
1207 // Write final position
1208 aOut
.writeInt32( nDataPos
);
1211 Reference
< io::XOutputStream
> xOutputStream
= aOut
.getOutputStream();
1212 if( xOutputStream
.is() )
1214 for( iLocale
= 0; iLocale
< nLocaleCount
; iLocale
++ )
1216 Sequence
< sal_Int8
>& rSeq
= aLocaleDataSeq
[iLocale
];
1217 xOutputStream
->writeBytes( rSeq
);
1221 Sequence
< sal_Int8
> aRetSeq
= aOut
.closeAndGetData();
1225 void StringResourcePersistenceImpl::implWriteLocaleBinary
1226 ( LocaleItem
* pLocaleItem
, BinaryOutput
& rOut
)
1228 Reference
< io::XOutputStream
> xOutputStream
= rOut
.getOutputStream();
1229 if( !xOutputStream
.is() )
1232 Locale
& rLocale
= pLocaleItem
->m_locale
;
1233 rOut
.writeString( rLocale
.Language
);
1234 rOut
.writeString( rLocale
.Country
);
1235 rOut
.writeString( rLocale
.Variant
);
1236 implWritePropertiesFile( pLocaleItem
, xOutputStream
, m_aComment
);
1240 // BinaryOutput, helper class for exportBinary
1246 Sequence
< sal_Int8
> m_aData
;
1248 const sal_Int8
* m_pData
;
1249 sal_Int32 m_nCurPos
;
1253 BinaryInput( const Sequence
< ::sal_Int8
>& aData
);
1255 Reference
< io::XInputStream
> getInputStreamForSection( sal_Int32 nSize
);
1257 void seek( sal_Int32 nPos
);
1258 sal_Int32
getPosition() const
1259 { return m_nCurPos
; }
1261 sal_Int16
readInt16();
1262 sal_Int32
readInt32();
1263 sal_Unicode
readUnicodeChar();
1264 OUString
readString();
1269 BinaryInput::BinaryInput( const Sequence
< ::sal_Int8
>& aData
)
1272 m_pData
= m_aData
.getConstArray();
1274 m_nSize
= m_aData
.getLength();
1277 Reference
< io::XInputStream
> BinaryInput::getInputStreamForSection( sal_Int32 nSize
)
1279 Reference
< io::XInputStream
> xIn
;
1280 if( m_nCurPos
+ nSize
<= m_nSize
)
1282 rtl::Reference
< utl::TempFileFastService
> xTempOut
= new utl::TempFileFastService
;
1283 Sequence
< sal_Int8
> aSection( m_pData
+ m_nCurPos
, nSize
);
1284 xTempOut
->writeBytes( aSection
);
1285 xTempOut
->seek( 0 );
1289 OSL_FAIL( "BinaryInput::getInputStreamForSection(): Read past end" );
1294 void BinaryInput::seek( sal_Int32 nPos
)
1296 if( nPos
<= m_nSize
)
1299 OSL_FAIL( "BinaryInput::seek(): Position past end" );
1303 sal_Int16
BinaryInput::readInt16()
1306 if( m_nCurPos
+ 2 <= m_nSize
)
1308 nRet
= nRet
+ sal_Int16( sal_uInt8( m_pData
[m_nCurPos
++] ) );
1309 nRet
+= 256 * sal_Int16( sal_uInt8( m_pData
[m_nCurPos
++] ) );
1312 OSL_FAIL( "BinaryInput::readInt16(): Read past end" );
1317 sal_Int32
BinaryInput::readInt32()
1320 if( m_nCurPos
+ 4 <= m_nSize
)
1322 sal_Int32 nFactor
= 1;
1323 for( sal_Int16 i
= 0; i
< 4; i
++ )
1325 nRet
+= sal_uInt8( m_pData
[m_nCurPos
++] ) * nFactor
;
1330 OSL_FAIL( "BinaryInput::readInt32(): Read past end" );
1335 sal_Unicode
BinaryInput::readUnicodeChar()
1337 sal_uInt16 nRet
= 0;
1338 if( m_nCurPos
+ 2 <= m_nSize
)
1340 nRet
= nRet
+ sal_uInt8( m_pData
[m_nCurPos
++] );
1341 nRet
+= 256 * sal_uInt8( m_pData
[m_nCurPos
++] );
1344 OSL_FAIL( "BinaryInput::readUnicodeChar(): Read past end" );
1346 sal_Unicode cRet
= nRet
;
1350 OUString
BinaryInput::readString()
1352 OUStringBuffer aBuf
;
1356 c
= readUnicodeChar();
1362 OUString aRetStr
= aBuf
.makeStringAndClear();
1366 void StringResourcePersistenceImpl::importBinary( const Sequence
< ::sal_Int8
>& Data
)
1368 // Init: Remove all locales
1369 sal_Int32 nOldLocaleCount
= 0;
1372 Sequence
< Locale
> aLocaleSeq
= getLocales();
1373 nOldLocaleCount
= aLocaleSeq
.getLength();
1374 if( nOldLocaleCount
> 0 )
1376 removeLocale( aLocaleSeq
[0] );
1379 while( nOldLocaleCount
> 0 );
1382 BinaryInput
aIn( Data
);
1384 aIn
.readInt16(); // version
1385 sal_Int32 nLocaleCount
= aIn
.readInt16();
1386 sal_Int32 iDefault
= aIn
.readInt16();
1388 std::unique_ptr
<sal_Int32
[]> pPositions( new sal_Int32
[nLocaleCount
+ 1] );
1389 for( sal_Int32 i
= 0; i
< nLocaleCount
+ 1; i
++ )
1390 pPositions
[i
] = aIn
.readInt32();
1393 LocaleItem
* pUseAsDefaultItem
= nullptr;
1394 for( sal_Int32 i
= 0; i
< nLocaleCount
; i
++ )
1396 sal_Int32 nPos
= pPositions
[i
];
1400 aLocale
.Language
= aIn
.readString();
1401 aLocale
.Country
= aIn
.readString();
1402 aLocale
.Variant
= aIn
.readString();
1404 sal_Int32 nAfterStringPos
= aIn
.getPosition();
1405 sal_Int32 nSize
= pPositions
[i
+1] - nAfterStringPos
;
1406 Reference
< io::XInputStream
> xInput
= aIn
.getInputStreamForSection( nSize
);
1409 LocaleItem
* pLocaleItem
= new LocaleItem( std::move(aLocale
) );
1411 pUseAsDefaultItem
= pLocaleItem
;
1412 std::unique_lock
aGuard( m_aMutex
);
1413 m_aLocaleItemVector
.emplace_back( pLocaleItem
);
1414 implReadPropertiesFile(aGuard
, pLocaleItem
, xInput
);
1418 if( pUseAsDefaultItem
!= nullptr )
1419 setDefaultLocale( pUseAsDefaultItem
->m_locale
);
1423 // Private helper methods
1425 static bool checkNamingSceme( std::u16string_view aName
, std::u16string_view aNameBase
,
1428 bool bSuccess
= false;
1430 size_t nNameLen
= aName
.size();
1431 size_t nNameBaseLen
= aNameBase
.size();
1433 // Name has to start with NameBase followed
1434 // by a '_' and at least one more character
1435 if( o3tl::starts_with(aName
, aNameBase
) && nNameBaseLen
< nNameLen
-1 &&
1436 aName
[nNameBaseLen
] == '_' )
1440 /* FIXME-BCP47: this uses '_' underscore character as separator and
1441 * also appends Variant, which can't be blindly changed as it would
1442 * violate the naming scheme in use. */
1444 sal_Int32 iStart
= nNameBaseLen
+ 1;
1445 size_t iNext_
= aName
.find( '_', iStart
);
1446 if( iNext_
!= std::u16string_view::npos
&& iNext_
< nNameLen
-1 )
1448 aLocale
.Language
= aName
.substr( iStart
, iNext_
- iStart
);
1450 iStart
= iNext_
+ 1;
1451 iNext_
= aName
.find( '_', iStart
);
1452 if( iNext_
!= std::u16string_view::npos
&& iNext_
< nNameLen
-1 )
1454 aLocale
.Country
= aName
.substr( iStart
, iNext_
- iStart
);
1455 aLocale
.Variant
= aName
.substr( iNext_
+ 1 );
1458 aLocale
.Country
= aName
.substr( iStart
);
1461 aLocale
.Language
= aName
.substr( iStart
);
1466 void StringResourcePersistenceImpl::implLoadAllLocales(std::unique_lock
<std::mutex
>& rGuard
)
1468 for( auto& pLocaleItem
: m_aLocaleItemVector
)
1470 loadLocale(rGuard
, pLocaleItem
.get());
1473 // Scan locale properties files helper
1474 void StringResourcePersistenceImpl::implScanLocaleNames( const Sequence
< OUString
>& aContentSeq
)
1476 Locale aDefaultLocale
;
1477 bool bDefaultFound
= false;
1479 for( const OUString
& aCompleteName
: aContentSeq
)
1482 OUString aExtension
;
1483 sal_Int32 iDot
= aCompleteName
.lastIndexOf( '.' );
1484 sal_Int32 iSlash
= aCompleteName
.lastIndexOf( '/' );
1485 if( iDot
!= -1 && iDot
> iSlash
)
1487 sal_Int32 iCopyFrom
= (iSlash
!= -1) ? iSlash
+ 1 : 0;
1488 aPureName
= aCompleteName
.copy( iCopyFrom
, iDot
-iCopyFrom
);
1489 aExtension
= aCompleteName
.copy( iDot
+ 1 );
1492 if ( aExtension
== "properties" )
1494 //OUString aName = aInetObj.getBase();
1497 if( checkNamingSceme( aPureName
, m_aNameBase
, aLocale
) )
1499 LocaleItem
* pLocaleItem
= new LocaleItem( std::move(aLocale
), false );
1500 m_aLocaleItemVector
.emplace_back( pLocaleItem
);
1502 if( m_pCurrentLocaleItem
== nullptr )
1503 m_pCurrentLocaleItem
= pLocaleItem
;
1505 if( m_pDefaultLocaleItem
== nullptr )
1507 m_pDefaultLocaleItem
= pLocaleItem
;
1508 m_bDefaultModified
= true;
1512 else if( !bDefaultFound
&& aExtension
== "default" )
1514 if( checkNamingSceme( aPureName
, m_aNameBase
, aDefaultLocale
) )
1515 bDefaultFound
= true;
1520 LocaleItem
* pLocaleItem
= getItemForLocale( aDefaultLocale
, false );
1523 m_pDefaultLocaleItem
= pLocaleItem
;
1524 m_bDefaultModified
= false;
1529 // Scan locale properties files
1530 void StringResourcePersistenceImpl::implScanLocales(std::unique_lock
<std::mutex
>& /*rGuard*/)
1532 // Dummy implementation, method not called for this
1533 // base class, but pure virtual not possible-
1536 bool StringResourcePersistenceImpl::loadLocale(std::unique_lock
<std::mutex
>& rGuard
, LocaleItem
* pLocaleItem
)
1538 bool bSuccess
= false;
1540 OSL_ENSURE( pLocaleItem
, "StringResourcePersistenceImpl::loadLocale(): pLocaleItem == NULL" );
1543 if( pLocaleItem
->m_bLoaded
)
1549 bSuccess
= implLoadLocale(rGuard
, pLocaleItem
);
1550 pLocaleItem
->m_bLoaded
= true; // = bSuccess??? -> leads to more tries
1556 bool StringResourcePersistenceImpl::implLoadLocale(std::unique_lock
<std::mutex
>& /*rGuard*/, LocaleItem
*)
1558 // Dummy implementation, method not called for this
1559 // base class, but pure virtual not possible-
1563 static OUString
implGetNameScemeForLocaleItem( const LocaleItem
* pLocaleItem
)
1565 /* FIXME-BCP47: this uses '_' underscore character as separator and
1566 * also appends Variant, which can't be blindly changed as it would
1567 * violate the naming scheme in use. */
1569 static const char aUnder
[] = "_";
1571 assert(pLocaleItem
&&
1572 "StringResourcePersistenceImpl::implGetNameScemeForLocaleItem(): pLocaleItem == NULL");
1573 Locale aLocale
= pLocaleItem
->m_locale
;
1575 OUString aRetStr
= aUnder
+ aLocale
.Language
;
1577 OUString aCountry
= aLocale
.Country
;
1578 if( !aCountry
.isEmpty() )
1580 aRetStr
+= aUnder
+ aCountry
;
1583 OUString aVariant
= aLocale
.Variant
;
1584 if( !aVariant
.isEmpty() )
1586 aRetStr
+= aUnder
+ aVariant
;
1591 OUString
StringResourcePersistenceImpl::implGetFileNameForLocaleItem
1592 ( LocaleItem
const * pLocaleItem
, const OUString
& aNameBase
)
1594 OUString aFileName
= aNameBase
;
1595 if( aFileName
.isEmpty() )
1596 aFileName
= aNameBaseDefaultStr
;
1598 aFileName
+= implGetNameScemeForLocaleItem( pLocaleItem
);
1602 OUString
StringResourcePersistenceImpl::implGetPathForLocaleItem
1603 ( LocaleItem
const * pLocaleItem
, const OUString
& aNameBase
,
1604 std::u16string_view aLocation
, bool bDefaultFile
)
1606 OUString aFileName
= implGetFileNameForLocaleItem( pLocaleItem
, aNameBase
);
1607 INetURLObject
aInetObj( aLocation
);
1608 aInetObj
.insertName( aFileName
, true, INetURLObject::LAST_SEGMENT
, INetURLObject::EncodeMechanism::All
);
1610 aInetObj
.setExtension( u
"default" );
1612 aInetObj
.setExtension( u
"properties" );
1613 OUString aCompleteFileName
= aInetObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
1614 return aCompleteFileName
;
1617 // White space according to Java property files specification in
1618 // http://java.sun.com/j2se/1.4.2/docs/api/java/util/Properties.html#load(java.io.InputStream)
1619 static bool isWhiteSpace( sal_Unicode c
)
1621 bool bWhite
= ( c
== 0x0020 || // space
1622 c
== 0x0009 || // tab
1623 c
== 0x000a || // line feed, not always handled by TextInputStream
1624 c
== 0x000d || // carriage return, not always handled by TextInputStream
1625 c
== 0x000C ); // form feed
1629 static void skipWhites( const sal_Unicode
* pBuf
, sal_Int32 nLen
, sal_Int32
& ri
)
1633 if( !isWhiteSpace( pBuf
[ri
] ) )
1639 static bool isHexDigit( sal_Unicode c
, sal_uInt16
& nDigitVal
)
1642 if( c
>= '0' && c
<= '9' )
1643 nDigitVal
= c
- '0';
1644 else if( c
>= 'a' && c
<= 'f' )
1645 nDigitVal
= c
- 'a' + 10;
1646 else if( c
>= 'A' && c
<= 'F' )
1647 nDigitVal
= c
- 'A' + 10;
1653 static sal_Unicode
getEscapeChar( const sal_Unicode
* pBuf
, sal_Int32 nLen
, sal_Int32
& ri
)
1657 sal_Unicode cRet
= 0;
1658 sal_Unicode c
= pBuf
[i
];
1680 while( i
< nLen
&& pBuf
[i
] == 'u' )
1683 // Process hex digits
1684 sal_Int32 nDigitCount
= 0;
1685 sal_uInt16 nDigitVal
;
1686 while( i
< nLen
&& isHexDigit( pBuf
[i
], nDigitVal
) )
1688 cRet
= 16 * cRet
+ nDigitVal
;
1691 if( nDigitCount
== 4 )
1693 // Write back position
1708 static void CheckContinueInNextLine( const Reference
< io::XTextInputStream2
>& xTextInputStream
,
1709 OUString
& aLine
, bool& bEscapePending
, const sal_Unicode
*& pBuf
,
1710 sal_Int32
& nLen
, sal_Int32
& i
)
1712 if( !(i
== nLen
&& bEscapePending
) )
1715 bEscapePending
= false;
1717 if( !xTextInputStream
->isEOF() )
1719 aLine
= xTextInputStream
->readLine();
1720 nLen
= aLine
.getLength();
1721 pBuf
= aLine
.getStr();
1724 skipWhites( pBuf
, nLen
, i
);
1728 bool StringResourcePersistenceImpl::implReadPropertiesFile(
1729 std::unique_lock
<std::mutex
>& rGuard
, LocaleItem
* pLocaleItem
,
1730 const Reference
<io::XInputStream
>& xInputStream
)
1732 if( !xInputStream
.is() || pLocaleItem
== nullptr )
1735 Reference
< io::XTextInputStream2
> xTextInputStream
= io::TextInputStream::create( m_xContext
);
1737 xTextInputStream
->setInputStream( xInputStream
);
1739 OUString aEncodingStr
= OUString::createFromAscii
1740 ( rtl_getMimeCharsetFromTextEncoding( RTL_TEXTENCODING_ISO_8859_1
) );
1741 xTextInputStream
->setEncoding( aEncodingStr
);
1744 while( !xTextInputStream
->isEOF() )
1746 aLine
= xTextInputStream
->readLine();
1748 sal_Int32 nLen
= aLine
.getLength();
1751 const sal_Unicode
* pBuf
= aLine
.getStr();
1752 OUStringBuffer aBuf
;
1756 skipWhites( pBuf
, nLen
, i
);
1758 continue; // line contains only white spaces
1762 if( c
== '#' || c
== '!' )
1766 OUString aResourceID
;
1767 bool bEscapePending
= false;
1768 bool bStrComplete
= false;
1769 while( i
< nLen
&& !bStrComplete
)
1772 if( bEscapePending
)
1774 aBuf
.append( getEscapeChar( pBuf
, nLen
, i
) );
1775 bEscapePending
= false;
1781 bEscapePending
= true;
1785 if( c
== ':' || c
== '=' || isWhiteSpace( c
) )
1786 bStrComplete
= true;
1793 CheckContinueInNextLine( xTextInputStream
, aLine
, bEscapePending
, pBuf
, nLen
, i
);
1795 bStrComplete
= true;
1798 aResourceID
= aBuf
.makeStringAndClear();
1801 // Ignore lines with empty keys
1802 if( aResourceID
.isEmpty() )
1806 skipWhites( pBuf
, nLen
, i
);
1809 bEscapePending
= false;
1810 bStrComplete
= false;
1811 while( i
< nLen
&& !bStrComplete
)
1814 if( c
== 0x000a || c
== 0x000d ) // line feed/carriage return, not always handled by TextInputStream
1820 if( bEscapePending
)
1822 aBuf
.append( getEscapeChar( pBuf
, nLen
, i
) );
1823 bEscapePending
= false;
1825 else if( c
== '\\' )
1826 bEscapePending
= true;
1831 CheckContinueInNextLine( xTextInputStream
, aLine
, bEscapePending
, pBuf
, nLen
, i
);
1834 bStrComplete
= true;
1837 aValueStr
= aBuf
.makeStringAndClear();
1841 pLocaleItem
->m_aIdToStringMap
[ aResourceID
] = aValueStr
;
1842 implScanIdForNumber(rGuard
, aResourceID
);
1843 IdToIndexMap
& rIndexMap
= pLocaleItem
->m_aIdToIndexMap
;
1844 rIndexMap
[ aResourceID
] = pLocaleItem
->m_nNextIndex
++;
1850 static sal_Unicode
getHexCharForDigit( sal_uInt16 nDigitVal
)
1853 return static_cast<sal_Unicode
>('0' + nDigitVal
);
1855 return static_cast<sal_Unicode
>('a' + (nDigitVal
-10));
1858 static void implWriteCharToBuffer( OUStringBuffer
& aBuf
, sal_Unicode cu
, bool bKey
)
1862 aBuf
.append( '\\' );
1863 aBuf
.append( '\\' );
1865 else if( cu
== 0x000a )
1867 aBuf
.append( '\\' );
1870 else if( cu
== 0x000d )
1872 aBuf
.append( '\\' );
1875 else if( bKey
&& cu
== '=' )
1877 aBuf
.append( '\\' );
1880 else if( bKey
&& cu
== ':' )
1882 aBuf
.append( '\\' );
1885 // ISO/IEC 8859-1 range according to:
1886 // http://en.wikipedia.org/wiki/ISO/IEC_8859-1
1887 else if( cu
>= 0x20 && cu
<= 0x7e )
1888 //TODO: Check why (cu >= 0xa0 && cu <= 0xFF)
1889 //is encoded in sample properties files
1890 //else if( (cu >= 0x20 && cu <= 0x7e) ||
1891 // (cu >= 0xa0 && cu <= 0xFF) )
1898 aBuf
.append( '\\' );
1901 sal_uInt16 nVal
= cu
;
1902 for( sal_uInt16 i
= 0 ; i
< 4 ; i
++ )
1904 sal_uInt16 nDigit
= nVal
/ 0x1000;
1905 nVal
-= nDigit
* 0x1000;
1907 aBuf
.append( getHexCharForDigit( nDigit
) );
1912 static void implWriteStringWithEncoding( const OUString
& aStr
,
1913 Reference
< io::XTextOutputStream2
> const & xTextOutputStream
, bool bKey
)
1915 static const sal_Unicode cLineFeed
= 0xa;
1917 OUStringBuffer aBuf
;
1918 sal_Int32 nLen
= aStr
.getLength();
1919 const sal_Unicode
* pSrc
= aStr
.getStr();
1920 for( sal_Int32 i
= 0 ; i
< nLen
; i
++ )
1922 sal_Unicode cu
= pSrc
[i
];
1923 implWriteCharToBuffer( aBuf
, cu
, bKey
);
1924 // TODO?: split long lines
1927 aBuf
.append( cLineFeed
);
1929 OUString aWriteStr
= aBuf
.makeStringAndClear();
1930 xTextOutputStream
->writeString( aWriteStr
);
1933 bool StringResourcePersistenceImpl::implWritePropertiesFile( LocaleItem
const * pLocaleItem
,
1934 const Reference
< io::XOutputStream
>& xOutputStream
, const OUString
& aComment
)
1936 if( !xOutputStream
.is() || pLocaleItem
== nullptr )
1939 bool bSuccess
= false;
1940 Reference
< io::XTextOutputStream2
> xTextOutputStream
= io::TextOutputStream::create(m_xContext
);
1942 xTextOutputStream
->setOutputStream( xOutputStream
);
1944 OUString aEncodingStr
= OUString::createFromAscii
1945 ( rtl_getMimeCharsetFromTextEncoding( RTL_TEXTENCODING_ISO_8859_1
) );
1946 xTextOutputStream
->setEncoding( aEncodingStr
);
1948 xTextOutputStream
->writeString( aComment
);
1949 xTextOutputStream
->writeString( u
"\n"_ustr
);
1951 const IdToStringMap
& rHashMap
= pLocaleItem
->m_aIdToStringMap
;
1952 if( !rHashMap
.empty() )
1954 // Sort ids according to read order
1955 const IdToIndexMap
& rIndexMap
= pLocaleItem
->m_aIdToIndexMap
;
1957 // Find max/min index
1958 auto itMinMax
= std::minmax_element(rIndexMap
.begin(), rIndexMap
.end(),
1959 [](const IdToIndexMap::value_type
& a
, const IdToIndexMap::value_type
& b
) { return a
.second
< b
.second
; });
1960 sal_Int32 nMinIndex
= itMinMax
.first
->second
;
1961 sal_Int32 nMaxIndex
= itMinMax
.second
->second
;
1962 sal_Int32 nTabSize
= nMaxIndex
- nMinIndex
+ 1;
1964 // Create sorted array of pointers to the id strings
1965 std::unique_ptr
<const OUString
*[]> pIdPtrs( new const OUString
*[nTabSize
] );
1966 for(sal_Int32 i
= 0 ; i
< nTabSize
; i
++ )
1967 pIdPtrs
[i
] = nullptr;
1968 for( const auto& rIndex
: rIndexMap
)
1970 sal_Int32 nIndex
= rIndex
.second
;
1971 pIdPtrs
[nIndex
- nMinIndex
] = &(rIndex
.first
);
1974 // Write lines in correct order
1975 for(sal_Int32 i
= 0 ; i
< nTabSize
; i
++ )
1977 const OUString
* pStr
= pIdPtrs
[i
];
1978 if( pStr
!= nullptr )
1980 OUString aResourceID
= *pStr
;
1981 IdToStringMap::const_iterator it
= rHashMap
.find( aResourceID
);
1982 if( it
!= rHashMap
.end() )
1984 implWriteStringWithEncoding( aResourceID
, xTextOutputStream
, true );
1985 xTextOutputStream
->writeString( u
"="_ustr
);
1986 OUString aValStr
= (*it
).second
;
1987 implWriteStringWithEncoding( aValStr
, xTextOutputStream
, false );
1999 // StringResourceWithStorageImpl
2001 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
2002 scripting_StringResourceWithStorageImpl_get_implementation(
2003 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
2005 return cppu::acquire(new StringResourceWithStorageImpl(context
));
2009 StringResourceWithStorageImpl::StringResourceWithStorageImpl( const Reference
< XComponentContext
>& rxContext
)
2010 : StringResourceWithStorageImpl_BASE( rxContext
)
2011 , m_bStorageChanged( false )
2016 StringResourceWithStorageImpl::~StringResourceWithStorageImpl()
2024 OUString
StringResourceWithStorageImpl::getImplementationName( )
2026 return u
"com.sun.star.comp.scripting.StringResourceWithStorage"_ustr
;
2029 sal_Bool
StringResourceWithStorageImpl::supportsService( const OUString
& rServiceName
)
2031 return cppu::supportsService(this, rServiceName
);
2034 Sequence
< OUString
> StringResourceWithStorageImpl::getSupportedServiceNames( )
2036 return { u
"com.sun.star.resource.StringResourceWithStorage"_ustr
};
2043 void StringResourceWithStorageImpl::initialize( const Sequence
< Any
>& aArguments
)
2045 std::unique_lock
aGuard( m_aMutex
);
2047 if ( aArguments
.getLength() != 5 )
2049 throw RuntimeException(
2050 u
"StringResourceWithStorageImpl::initialize: invalid number of arguments!"_ustr
);
2053 bool bOk
= (aArguments
[0] >>= m_xStorage
);
2054 if( bOk
&& !m_xStorage
.is() )
2059 throw IllegalArgumentException( u
"StringResourceWithStorageImpl::initialize: invalid storage"_ustr
, Reference
< XInterface
>(), 0 );
2062 implInitializeCommonParameters( aGuard
, aArguments
);
2066 // Forwarding calls to base class
2068 // XModifyBroadcaster
2069 void StringResourceWithStorageImpl::addModifyListener( const Reference
< XModifyListener
>& aListener
)
2071 StringResourceImpl::addModifyListener( aListener
);
2073 void StringResourceWithStorageImpl::removeModifyListener( const Reference
< XModifyListener
>& aListener
)
2075 StringResourceImpl::removeModifyListener( aListener
);
2078 // XStringResourceResolver
2079 OUString
StringResourceWithStorageImpl::resolveString( const OUString
& ResourceID
)
2081 return StringResourceImpl::resolveString( ResourceID
) ;
2083 OUString
StringResourceWithStorageImpl::resolveStringForLocale( const OUString
& ResourceID
, const Locale
& locale
)
2085 return StringResourceImpl::resolveStringForLocale( ResourceID
, locale
);
2087 sal_Bool
StringResourceWithStorageImpl::hasEntryForId( const OUString
& ResourceID
)
2089 return StringResourceImpl::hasEntryForId( ResourceID
) ;
2091 sal_Bool
StringResourceWithStorageImpl::hasEntryForIdAndLocale( const OUString
& ResourceID
,
2092 const Locale
& locale
)
2094 return StringResourceImpl::hasEntryForIdAndLocale( ResourceID
, locale
);
2096 Sequence
< OUString
> StringResourceWithStorageImpl::getResourceIDs( )
2098 return StringResourceImpl::getResourceIDs();
2100 Sequence
< OUString
> StringResourceWithStorageImpl::getResourceIDsForLocale
2101 ( const Locale
& locale
)
2103 return StringResourceImpl::getResourceIDsForLocale( locale
);
2105 Locale
StringResourceWithStorageImpl::getCurrentLocale()
2107 return StringResourceImpl::getCurrentLocale();
2109 Locale
StringResourceWithStorageImpl::getDefaultLocale( )
2111 return StringResourceImpl::getDefaultLocale();
2113 Sequence
< Locale
> StringResourceWithStorageImpl::getLocales( )
2115 return StringResourceImpl::getLocales();
2118 // XStringResourceManager
2119 sal_Bool
StringResourceWithStorageImpl::isReadOnly()
2121 return StringResourceImpl::isReadOnly();
2123 void StringResourceWithStorageImpl::setCurrentLocale( const Locale
& locale
, sal_Bool FindClosestMatch
)
2125 StringResourceImpl::setCurrentLocale( locale
, FindClosestMatch
);
2127 void StringResourceWithStorageImpl::setDefaultLocale( const Locale
& locale
)
2129 StringResourceImpl::setDefaultLocale( locale
);
2131 void StringResourceWithStorageImpl::setString( const OUString
& ResourceID
, const OUString
& Str
)
2133 StringResourceImpl::setString( ResourceID
, Str
);
2135 void StringResourceWithStorageImpl::setStringForLocale
2136 ( const OUString
& ResourceID
, const OUString
& Str
, const Locale
& locale
)
2138 StringResourceImpl::setStringForLocale( ResourceID
, Str
, locale
);
2140 void StringResourceWithStorageImpl::removeId( const OUString
& ResourceID
)
2142 StringResourceImpl::removeId( ResourceID
);
2144 void StringResourceWithStorageImpl::removeIdForLocale( const OUString
& ResourceID
, const Locale
& locale
)
2146 StringResourceImpl::removeIdForLocale( ResourceID
, locale
);
2148 void StringResourceWithStorageImpl::newLocale( const Locale
& locale
)
2150 StringResourceImpl::newLocale( locale
);
2152 void StringResourceWithStorageImpl::removeLocale( const Locale
& locale
)
2154 StringResourceImpl::removeLocale( locale
);
2156 sal_Int32
StringResourceWithStorageImpl::getUniqueNumericId( )
2158 return StringResourceImpl::getUniqueNumericId();
2161 // XStringResourcePersistence
2162 void StringResourceWithStorageImpl::store()
2164 std::unique_lock
aGuard( m_aMutex
);
2165 implCheckReadOnly( "StringResourceWithStorageImpl::store(): Read only" );
2167 bool bStoreAll
= m_bStorageChanged
;
2168 m_bStorageChanged
= false;
2169 if( !m_bModified
&& !bStoreAll
)
2172 implStoreAtStorage(aGuard
, m_aNameBase
, m_aComment
, m_xStorage
, true/*bUsedForStore*/, bStoreAll
);
2173 m_bModified
= false;
2176 sal_Bool
StringResourceWithStorageImpl::isModified( )
2178 return StringResourcePersistenceImpl::isModified();
2180 void StringResourceWithStorageImpl::setComment( const OUString
& Comment
)
2182 StringResourcePersistenceImpl::setComment( Comment
);
2184 void StringResourceWithStorageImpl::storeToStorage( const Reference
< XStorage
>& Storage
,
2185 const OUString
& NameBase
, const OUString
& Comment
)
2187 StringResourcePersistenceImpl::storeToStorage( Storage
, NameBase
, Comment
);
2189 void StringResourceWithStorageImpl::storeToURL( const OUString
& URL
,
2190 const OUString
& NameBase
, const OUString
& Comment
,
2191 const Reference
< css::task::XInteractionHandler
>& Handler
)
2193 StringResourcePersistenceImpl::storeToURL( URL
, NameBase
, Comment
, Handler
);
2195 Sequence
< ::sal_Int8
> StringResourceWithStorageImpl::exportBinary( )
2197 return StringResourcePersistenceImpl::exportBinary();
2199 void StringResourceWithStorageImpl::importBinary( const Sequence
< ::sal_Int8
>& Data
)
2201 StringResourcePersistenceImpl::importBinary( Data
);
2205 // XStringResourceWithStorage
2207 void StringResourceWithStorageImpl::storeAsStorage( const Reference
< XStorage
>& Storage
)
2209 setStorage( Storage
);
2213 void StringResourceWithStorageImpl::setStorage( const Reference
< XStorage
>& Storage
)
2215 std::unique_lock
aGuard( m_aMutex
);
2219 throw IllegalArgumentException( u
"StringResourceWithStorageImpl::setStorage: invalid storage"_ustr
, Reference
< XInterface
>(), 0 );
2222 implLoadAllLocales(aGuard
);
2224 m_xStorage
= Storage
;
2225 m_bStorageChanged
= true;
2229 // Private helper methods
2232 // Scan locale properties files
2233 void StringResourceWithStorageImpl::implScanLocales(std::unique_lock
<std::mutex
>& rGuard
)
2235 if( m_xStorage
.is() )
2237 Sequence
< OUString
> aContentSeq
= m_xStorage
->getElementNames();
2238 implScanLocaleNames( aContentSeq
);
2241 implLoadAllLocales(rGuard
);
2245 bool StringResourceWithStorageImpl::implLoadLocale(std::unique_lock
<std::mutex
>& rGuard
, LocaleItem
* pLocaleItem
)
2247 bool bSuccess
= false;
2250 OUString aStreamName
= implGetFileNameForLocaleItem( pLocaleItem
, m_aNameBase
) + ".properties";
2252 Reference
< io::XStream
> xElementStream
=
2253 m_xStorage
->openStreamElement( aStreamName
, ElementModes::READ
);
2255 if( xElementStream
.is() )
2257 Reference
< io::XInputStream
> xInputStream
= xElementStream
->getInputStream();
2258 if( xInputStream
.is() )
2260 bSuccess
= StringResourcePersistenceImpl::implReadPropertiesFile(rGuard
, pLocaleItem
, xInputStream
);
2261 xInputStream
->closeInput();
2265 catch( uno::Exception
& )
2272 // StringResourceWithLocationImpl
2275 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
2276 scripting_StringResourceWithLocationImpl_get_implementation(
2277 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
2279 return cppu::acquire(new StringResourceWithLocationImpl(context
));
2284 StringResourceWithLocationImpl::StringResourceWithLocationImpl( const Reference
< XComponentContext
>& rxContext
)
2285 : StringResourceWithLocationImpl_BASE( rxContext
)
2286 , m_bLocationChanged( false )
2291 StringResourceWithLocationImpl::~StringResourceWithLocationImpl()
2299 OUString
StringResourceWithLocationImpl::getImplementationName( )
2301 return u
"com.sun.star.comp.scripting.StringResourceWithLocation"_ustr
;
2304 sal_Bool
StringResourceWithLocationImpl::supportsService( const OUString
& rServiceName
)
2306 return cppu::supportsService(this, rServiceName
);
2309 Sequence
< OUString
> StringResourceWithLocationImpl::getSupportedServiceNames( )
2311 return { u
"com.sun.star.resource.StringResourceWithLocation"_ustr
};
2318 void StringResourceWithLocationImpl::initialize( const Sequence
< Any
>& aArguments
)
2320 std::unique_lock
aGuard( m_aMutex
);
2322 if ( aArguments
.getLength() != 6 )
2324 throw RuntimeException(
2325 u
"XInitialization::initialize: invalid number of arguments!"_ustr
);
2328 bool bOk
= (aArguments
[0] >>= m_aLocation
);
2329 sal_Int32 nLen
= m_aLocation
.getLength();
2330 if( bOk
&& nLen
== 0 )
2336 if( m_aLocation
[nLen
- 1] != '/' )
2342 throw IllegalArgumentException( u
"XInitialization::initialize: invalid URL"_ustr
, Reference
< XInterface
>(), 0 );
2346 bOk
= (aArguments
[5] >>= m_xInteractionHandler
);
2349 throw IllegalArgumentException( u
"StringResourceWithStorageImpl::initialize: invalid type"_ustr
, Reference
< XInterface
>(), 5 );
2352 implInitializeCommonParameters( aGuard
, aArguments
);
2356 // Forwarding calls to base class
2358 // XModifyBroadcaster
2359 void StringResourceWithLocationImpl::addModifyListener( const Reference
< XModifyListener
>& aListener
)
2361 StringResourceImpl::addModifyListener( aListener
);
2363 void StringResourceWithLocationImpl::removeModifyListener( const Reference
< XModifyListener
>& aListener
)
2365 StringResourceImpl::removeModifyListener( aListener
);
2368 // XStringResourceResolver
2369 OUString
StringResourceWithLocationImpl::resolveString( const OUString
& ResourceID
)
2371 return StringResourceImpl::resolveString( ResourceID
) ;
2373 OUString
StringResourceWithLocationImpl::resolveStringForLocale( const OUString
& ResourceID
, const Locale
& locale
)
2375 return StringResourceImpl::resolveStringForLocale( ResourceID
, locale
);
2377 sal_Bool
StringResourceWithLocationImpl::hasEntryForId( const OUString
& ResourceID
)
2379 return StringResourceImpl::hasEntryForId( ResourceID
) ;
2381 sal_Bool
StringResourceWithLocationImpl::hasEntryForIdAndLocale( const OUString
& ResourceID
,
2382 const Locale
& locale
)
2384 return StringResourceImpl::hasEntryForIdAndLocale( ResourceID
, locale
);
2386 Sequence
< OUString
> StringResourceWithLocationImpl::getResourceIDs( )
2388 return StringResourceImpl::getResourceIDs();
2390 Sequence
< OUString
> StringResourceWithLocationImpl::getResourceIDsForLocale
2391 ( const Locale
& locale
)
2393 return StringResourceImpl::getResourceIDsForLocale( locale
);
2395 Locale
StringResourceWithLocationImpl::getCurrentLocale()
2397 return StringResourceImpl::getCurrentLocale();
2399 Locale
StringResourceWithLocationImpl::getDefaultLocale( )
2401 return StringResourceImpl::getDefaultLocale();
2403 Sequence
< Locale
> StringResourceWithLocationImpl::getLocales( )
2405 return StringResourceImpl::getLocales();
2408 // XStringResourceManager
2409 sal_Bool
StringResourceWithLocationImpl::isReadOnly()
2411 return StringResourceImpl::isReadOnly();
2413 void StringResourceWithLocationImpl::setCurrentLocale( const Locale
& locale
, sal_Bool FindClosestMatch
)
2415 StringResourceImpl::setCurrentLocale( locale
, FindClosestMatch
);
2417 void StringResourceWithLocationImpl::setDefaultLocale( const Locale
& locale
)
2419 StringResourceImpl::setDefaultLocale( locale
);
2421 void StringResourceWithLocationImpl::setString( const OUString
& ResourceID
, const OUString
& Str
)
2423 StringResourceImpl::setString( ResourceID
, Str
);
2425 void StringResourceWithLocationImpl::setStringForLocale
2426 ( const OUString
& ResourceID
, const OUString
& Str
, const Locale
& locale
)
2428 StringResourceImpl::setStringForLocale( ResourceID
, Str
, locale
);
2430 void StringResourceWithLocationImpl::removeId( const OUString
& ResourceID
)
2432 StringResourceImpl::removeId( ResourceID
);
2434 void StringResourceWithLocationImpl::removeIdForLocale( const OUString
& ResourceID
, const Locale
& locale
)
2436 StringResourceImpl::removeIdForLocale( ResourceID
, locale
);
2438 void StringResourceWithLocationImpl::newLocale( const Locale
& locale
)
2440 StringResourceImpl::newLocale( locale
);
2442 void StringResourceWithLocationImpl::removeLocale( const Locale
& locale
)
2444 StringResourceImpl::removeLocale( locale
);
2446 sal_Int32
StringResourceWithLocationImpl::getUniqueNumericId( )
2448 return StringResourceImpl::getUniqueNumericId();
2451 // XStringResourcePersistence
2452 void StringResourceWithLocationImpl::store()
2454 std::unique_lock
aGuard( m_aMutex
);
2455 implCheckReadOnly( "StringResourceWithLocationImpl::store(): Read only" );
2457 bool bStoreAll
= m_bLocationChanged
;
2458 m_bLocationChanged
= false;
2459 if( !m_bModified
&& !bStoreAll
)
2462 Reference
< ucb::XSimpleFileAccess3
> xFileAccess
= getFileAccessImpl();
2463 implStoreAtLocation(aGuard
, m_aLocation
, m_aNameBase
, m_aComment
,
2464 xFileAccess
, true/*bUsedForStore*/, bStoreAll
);
2465 m_bModified
= false;
2468 sal_Bool
StringResourceWithLocationImpl::isModified( )
2470 return StringResourcePersistenceImpl::isModified();
2472 void StringResourceWithLocationImpl::setComment( const OUString
& Comment
)
2474 StringResourcePersistenceImpl::setComment( Comment
);
2476 void StringResourceWithLocationImpl::storeToStorage( const Reference
< XStorage
>& Storage
,
2477 const OUString
& NameBase
, const OUString
& Comment
)
2479 StringResourcePersistenceImpl::storeToStorage( Storage
, NameBase
, Comment
);
2481 void StringResourceWithLocationImpl::storeToURL( const OUString
& URL
,
2482 const OUString
& NameBase
, const OUString
& Comment
,
2483 const Reference
< css::task::XInteractionHandler
>& Handler
)
2485 StringResourcePersistenceImpl::storeToURL( URL
, NameBase
, Comment
, Handler
);
2487 Sequence
< ::sal_Int8
> StringResourceWithLocationImpl::exportBinary( )
2489 return StringResourcePersistenceImpl::exportBinary();
2491 void StringResourceWithLocationImpl::importBinary( const Sequence
< ::sal_Int8
>& Data
)
2493 StringResourcePersistenceImpl::importBinary( Data
);
2497 // XStringResourceWithLocation
2499 // XStringResourceWithLocation
2500 void StringResourceWithLocationImpl::storeAsURL( const OUString
& URL
)
2506 void StringResourceWithLocationImpl::setURL( const OUString
& URL
)
2508 std::unique_lock
aGuard( m_aMutex
);
2509 implCheckReadOnly( "StringResourceWithLocationImpl::setURL(): Read only" );
2511 sal_Int32 nLen
= URL
.getLength();
2514 throw IllegalArgumentException( u
"StringResourceWithLocationImpl::setURL: invalid URL"_ustr
, Reference
< XInterface
>(), 0 );
2517 implLoadAllLocales(aGuard
);
2519 // Delete files at old location
2520 implStoreAtLocation(aGuard
, m_aLocation
, m_aNameBase
, m_aComment
,
2521 getFileAccessImpl(), false/*bUsedForStore*/, false/*bStoreAll*/, true/*bKillAll*/ );
2524 m_bLocationChanged
= true;
2528 // Private helper methods
2531 // Scan locale properties files
2532 void StringResourceWithLocationImpl::implScanLocales(std::unique_lock
<std::mutex
>& /*rGuard*/)
2534 const Reference
< ucb::XSimpleFileAccess3
> xFileAccess
= getFileAccessImpl();
2535 if( xFileAccess
->isFolder( m_aLocation
) )
2537 Sequence
< OUString
> aContentSeq
= xFileAccess
->getFolderContents( m_aLocation
, false );
2538 implScanLocaleNames( aContentSeq
);
2543 bool StringResourceWithLocationImpl::implLoadLocale(std::unique_lock
<std::mutex
>& rGuard
, LocaleItem
* pLocaleItem
)
2545 bool bSuccess
= false;
2547 const Reference
< ucb::XSimpleFileAccess3
> xFileAccess
= getFileAccessImpl();
2548 OUString aCompleteFileName
=
2549 implGetPathForLocaleItem( pLocaleItem
, m_aNameBase
, m_aLocation
);
2551 Reference
< io::XInputStream
> xInputStream
;
2554 xInputStream
= xFileAccess
->openFileRead( aCompleteFileName
);
2558 if( xInputStream
.is() )
2560 bSuccess
= StringResourcePersistenceImpl::implReadPropertiesFile(rGuard
, pLocaleItem
, xInputStream
);
2561 xInputStream
->closeInput();
2567 const Reference
< ucb::XSimpleFileAccess3
> & StringResourceWithLocationImpl::getFileAccessImpl()
2571 m_xSFI
= ucb::SimpleFileAccess::create(m_xContext
);
2573 if( m_xInteractionHandler
.is() )
2574 m_xSFI
->setInteractionHandler( m_xInteractionHandler
);
2579 } // namespace stringresource
2582 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */