/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_scripting.hxx"
#include "stringresource.hxx"
#include <com/sun/star/io/XTextInputStream.hpp>
#include <com/sun/star/io/XTextOutputStream.hpp>
#include <com/sun/star/io/XActiveDataSink.hpp>
#include <com/sun/star/io/XActiveDataSource.hpp>
#include <com/sun/star/io/XStream.hpp>
#include <com/sun/star/io/XSeekable.hpp>
#include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/lang/XMultiComponentFactory.hpp>
#ifndef _CPPUHELPER_IMPLEMENTATIONENTRY_HXX_
#include <cppuhelper/implementationentry.hxx>
#endif
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/container/XNameAccess.hpp>


#include <rtl/ustrbuf.hxx>
#include <rtl/strbuf.hxx>
#include <tools/urlobj.hxx>

using namespace ::com::sun::star;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::ucb;
using namespace ::com::sun::star::util;
using namespace ::com::sun::star::embed;
using namespace ::com::sun::star::container;


//.........................................................................
namespace stringresource
{
//.........................................................................

// =============================================================================
// mutex
// =============================================================================

::osl::Mutex& getMutex()
{
    static ::osl::Mutex* s_pMutex = 0;
    if ( !s_pMutex )
    {
        ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
	    if ( !s_pMutex )
	    {
            static ::osl::Mutex s_aMutex;
		    s_pMutex = &s_aMutex;
	    }
    }
    return *s_pMutex;
}


// =============================================================================
// StringResourceImpl
// =============================================================================

// component operations
static Sequence< ::rtl::OUString > getSupportedServiceNames_StringResourceImpl()
{
    Sequence< ::rtl::OUString > names(1);
    names[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.resource.StringResource") );
    return names;
}

static ::rtl::OUString getImplementationName_StringResourceImpl()
{
    return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.scripting.StringResource") );
}

static Reference< XInterface > SAL_CALL create_StringResourceImpl(
    Reference< XComponentContext > const & xContext )
    SAL_THROW( () )
{
    return static_cast< ::cppu::OWeakObject * >( new StringResourcePersistenceImpl( xContext ) );
}


// =============================================================================

StringResourceImpl::StringResourceImpl( const Reference< XComponentContext >& rxContext )
    : m_xContext( rxContext )
	, m_pCurrentLocaleItem( NULL )
	, m_pDefaultLocaleItem( NULL )
	, m_bDefaultModified( false )
	, m_aListenerContainer( getMutex() )
	, m_bModified( false )
	, m_bReadOnly( false )
	, m_nNextUniqueNumericId( UNIQUE_NUMBER_NEEDS_INITIALISATION )
{
}

// =============================================================================

StringResourceImpl::~StringResourceImpl()
{
	for( LocaleItemVectorIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
	{
		LocaleItem* pLocaleItem = *it;
		delete pLocaleItem;
	}

	for( LocaleItemVectorIt it = m_aDeletedLocaleItemVector.begin(); it != m_aDeletedLocaleItemVector.end(); it++ )
	{
		LocaleItem* pLocaleItem = *it;
		delete pLocaleItem;
	}
}


// =============================================================================
// XServiceInfo

::rtl::OUString StringResourceImpl::getImplementationName(  ) throw (RuntimeException)
{
    return getImplementationName_StringResourceImpl();
}

sal_Bool StringResourceImpl::supportsService( const ::rtl::OUString& rServiceName ) throw (RuntimeException)
{
	Sequence< ::rtl::OUString > aNames( getSupportedServiceNames() );
	const ::rtl::OUString* pNames = aNames.getConstArray();
	const ::rtl::OUString* pEnd = pNames + aNames.getLength();
	for ( ; pNames != pEnd && !pNames->equals( rServiceName ); ++pNames )
		;

	return pNames != pEnd;
}

Sequence< ::rtl::OUString > StringResourceImpl::getSupportedServiceNames(  ) throw (RuntimeException)
{
    return getSupportedServiceNames_StringResourceImpl();
}


// =============================================================================
// XModifyBroadcaster

void StringResourceImpl::addModifyListener( const Reference< XModifyListener >& aListener )
	throw (RuntimeException)
{
	if( !aListener.is() )
		throw RuntimeException();

    ::osl::MutexGuard aGuard( getMutex() );
	Reference< XInterface > xIface( aListener, UNO_QUERY );
	m_aListenerContainer.addInterface( xIface );
}

void StringResourceImpl::removeModifyListener( const Reference< XModifyListener >& aListener )
	throw (RuntimeException)
{
	if( !aListener.is() )
		throw RuntimeException();

    ::osl::MutexGuard aGuard( getMutex() );
	Reference< XInterface > xIface( aListener, UNO_QUERY );
	m_aListenerContainer.removeInterface( xIface );
}


// =============================================================================
// XStringResourceResolver

::rtl::OUString StringResourceImpl::implResolveString
	( const ::rtl::OUString& ResourceID, LocaleItem* pLocaleItem )
		throw (::com::sun::star::resource::MissingResourceException)
{
	::rtl::OUString aRetStr;
	bool bSuccess = false;
	if( pLocaleItem != NULL && loadLocale( pLocaleItem ) )
	{
		IdToStringMap::iterator it = pLocaleItem->m_aIdToStringMap.find( ResourceID );
		if( !( it == pLocaleItem->m_aIdToStringMap.end() ) )
		{
			aRetStr = (*it).second;
			bSuccess = true;
		}
	}
	if( !bSuccess )
	{
		::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceImpl: No entry for ResourceID: " );
        errorMsg.concat( ResourceID );
        throw ::com::sun::star::resource::MissingResourceException( errorMsg, Reference< XInterface >() );
	}
	return aRetStr;
}

::rtl::OUString StringResourceImpl::resolveString( const ::rtl::OUString& ResourceID ) 
	throw (::com::sun::star::resource::MissingResourceException, RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );
	return implResolveString( ResourceID, m_pCurrentLocaleItem );
}

::rtl::OUString StringResourceImpl::resolveStringForLocale( const ::rtl::OUString& ResourceID, const Locale& locale )
	throw ( ::com::sun::star::resource::MissingResourceException, RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );
	LocaleItem* pLocaleItem = getItemForLocale( locale, false );
	return implResolveString( ResourceID, pLocaleItem );
}

sal_Bool StringResourceImpl::implHasEntryForId( const ::rtl::OUString& ResourceID, LocaleItem* pLocaleItem )
{
	bool bSuccess = false;
	if( pLocaleItem != NULL && loadLocale( pLocaleItem ) )
	{
		IdToStringMap::iterator it = pLocaleItem->m_aIdToStringMap.find( ResourceID );
		if( !( it == pLocaleItem->m_aIdToStringMap.end() ) )
			bSuccess = true;
	}
	return bSuccess;
}

sal_Bool StringResourceImpl::hasEntryForId( const ::rtl::OUString& ResourceID )
	throw (RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );
	return implHasEntryForId( ResourceID, m_pCurrentLocaleItem );
}

sal_Bool StringResourceImpl::hasEntryForIdAndLocale( const ::rtl::OUString& ResourceID, 
	const Locale& locale )
		throw (RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );
	LocaleItem* pLocaleItem = getItemForLocale( locale, false );
	return implHasEntryForId( ResourceID, pLocaleItem );
}

Sequence< ::rtl::OUString > StringResourceImpl::implGetResourceIDs( LocaleItem* pLocaleItem )
{
	Sequence< ::rtl::OUString > aIDSeq( 0 );
	if( pLocaleItem && loadLocale( pLocaleItem ) )
	{
		const IdToStringMap& rHashMap = pLocaleItem->m_aIdToStringMap;
		sal_Int32 nResourceIDCount = rHashMap.size();
		aIDSeq.realloc( nResourceIDCount );
		::rtl::OUString* pStrings = aIDSeq.getArray();

		IdToStringMap::const_iterator it;
		int iTarget = 0;
		for( it = rHashMap.begin(); it != rHashMap.end(); it++ )
		{
			::rtl::OUString aStr = (*it).first;
			pStrings[iTarget] = aStr;
			iTarget++;
		}
	}
	return aIDSeq;
}

Sequence< ::rtl::OUString > StringResourceImpl::getResourceIDsForLocale
	( const Locale& locale ) throw (::com::sun::star::uno::RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );
	LocaleItem* pLocaleItem = getItemForLocale( locale, false );
	return implGetResourceIDs( pLocaleItem );
}

Sequence< ::rtl::OUString > StringResourceImpl::getResourceIDs(  )
	throw (RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );
	return implGetResourceIDs( m_pCurrentLocaleItem );
}

Locale StringResourceImpl::getCurrentLocale()
	throw (RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );

	Locale aRetLocale;
	if( m_pCurrentLocaleItem != NULL )
		aRetLocale = m_pCurrentLocaleItem->m_locale;
	return aRetLocale;
}

Locale StringResourceImpl::getDefaultLocale(  )
	throw (RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );

	Locale aRetLocale;
	if( m_pDefaultLocaleItem != NULL )
		aRetLocale = m_pDefaultLocaleItem->m_locale;
	return aRetLocale;
}

Sequence< Locale > StringResourceImpl::getLocales(  )
	throw (RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );

	sal_Int32 nSize = m_aLocaleItemVector.size();
	Sequence< Locale > aLocalSeq( nSize );
	Locale* pLocales = aLocalSeq.getArray();
	int iTarget = 0;
    for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
    {
		LocaleItem* pLocaleItem = *it;
		pLocales[iTarget] = pLocaleItem->m_locale;
		iTarget++;
	}
	return aLocalSeq;
}


// =============================================================================
// XStringResourceManager

void StringResourceImpl::implCheckReadOnly( const sal_Char* pExceptionMsg )
	throw (NoSupportException)
{
	if( m_bReadOnly )
	{
		::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( pExceptionMsg );
        throw NoSupportException( errorMsg, Reference< XInterface >() );
	}
}

sal_Bool StringResourceImpl::isReadOnly()
	throw (RuntimeException)
{
	return m_bReadOnly;
}

void StringResourceImpl::implSetCurrentLocale( const Locale& locale,
	sal_Bool FindClosestMatch, sal_Bool bUseDefaultIfNoMatch )
		throw (IllegalArgumentException, RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );

	LocaleItem* pLocaleItem = NULL;
	if( FindClosestMatch )
		pLocaleItem = getClosestMatchItemForLocale( locale );
	else
		pLocaleItem = getItemForLocale( locale, true );

	if( pLocaleItem == NULL && bUseDefaultIfNoMatch )
		pLocaleItem = m_pDefaultLocaleItem;

	if( pLocaleItem != NULL )
	{
		loadLocale( pLocaleItem );
		m_pCurrentLocaleItem = pLocaleItem;

		// Only notify without modifying
		implNotifyListeners();
	}
}

void StringResourceImpl::setCurrentLocale( const Locale& locale, sal_Bool FindClosestMatch )
	throw (IllegalArgumentException, RuntimeException)
{
	sal_Bool bUseDefaultIfNoMatch = false;
	implSetCurrentLocale( locale, FindClosestMatch, bUseDefaultIfNoMatch );
}

void StringResourceImpl::setDefaultLocale( const Locale& locale )
	throw (IllegalArgumentException, RuntimeException,NoSupportException)
{
    ::osl::MutexGuard aGuard( getMutex() );
	implCheckReadOnly( "StringResourceImpl::setDefaultLocale(): Read only" );

	LocaleItem* pLocaleItem = getItemForLocale( locale, true );
	if( pLocaleItem && pLocaleItem != m_pDefaultLocaleItem )
	{
		if( m_pDefaultLocaleItem )
		{
			LocaleItem* pChangedDefaultLocaleItem = new LocaleItem( m_pDefaultLocaleItem->m_locale );
			m_aChangedDefaultLocaleVector.push_back( pChangedDefaultLocaleItem );
		}

		m_pDefaultLocaleItem = pLocaleItem;
		m_bDefaultModified = true;
		implModified();
	}
}

void StringResourceImpl::implSetString( const ::rtl::OUString& ResourceID, 
	const ::rtl::OUString& Str, LocaleItem* pLocaleItem )
{
	if( pLocaleItem != NULL && loadLocale( pLocaleItem ) )
	{
		IdToStringMap& rHashMap = pLocaleItem->m_aIdToStringMap;

		IdToStringMap::iterator it = rHashMap.find( ResourceID );
		bool bNew = ( it == rHashMap.end() );
		if( bNew )
		{
			IdToIndexMap& rIndexMap = pLocaleItem->m_aIdToIndexMap;
			rIndexMap[ ResourceID ] = pLocaleItem->m_nNextIndex++;
			implScanIdForNumber( ResourceID );
		}
		rHashMap[ ResourceID ] = Str;
		pLocaleItem->m_bModified = true;
		implModified();
	}
}

void StringResourceImpl::setString( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str )
	throw (NoSupportException, RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );
	implCheckReadOnly( "StringResourceImpl::setString(): Read only" );
	implSetString( ResourceID, Str, m_pCurrentLocaleItem );
}

void StringResourceImpl::setStringForLocale
	( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str, const Locale& locale )
		throw (NoSupportException, RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );
	implCheckReadOnly( "StringResourceImpl::setStringForLocale(): Read only" );
	LocaleItem* pLocaleItem = getItemForLocale( locale, false );
	implSetString( ResourceID, Str, pLocaleItem );
}

void StringResourceImpl::implRemoveId( const ::rtl::OUString& ResourceID, LocaleItem* pLocaleItem )
	throw (::com::sun::star::resource::MissingResourceException)
{
	if( pLocaleItem != NULL && loadLocale( pLocaleItem ) )
	{
		IdToStringMap& rHashMap = pLocaleItem->m_aIdToStringMap;
		IdToStringMap::iterator it = rHashMap.find( ResourceID );
		if( it == rHashMap.end() )
		{
			::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceImpl: No entries for ResourceID: " );
			errorMsg.concat( ResourceID );
			throw ::com::sun::star::resource::MissingResourceException( errorMsg, Reference< XInterface >() );
		}
		rHashMap.erase( it );
		pLocaleItem->m_bModified = true;
		implModified();
	}
}

void StringResourceImpl::removeId( const ::rtl::OUString& ResourceID )
	throw (::com::sun::star::resource::MissingResourceException, RuntimeException, NoSupportException)
{
    ::osl::MutexGuard aGuard( getMutex() );
	implCheckReadOnly( "StringResourceImpl::removeId(): Read only" );
	implRemoveId( ResourceID, m_pCurrentLocaleItem );
}

void StringResourceImpl::removeIdForLocale( const ::rtl::OUString& ResourceID, const Locale& locale )
	throw (::com::sun::star::resource::MissingResourceException, RuntimeException, NoSupportException)
{
    ::osl::MutexGuard aGuard( getMutex() );
	implCheckReadOnly( "StringResourceImpl::removeIdForLocale(): Read only" );
	LocaleItem* pLocaleItem = getItemForLocale( locale, false );
	implRemoveId( ResourceID, pLocaleItem );
}

void StringResourceImpl::newLocale( const Locale& locale )
	throw (ElementExistException, IllegalArgumentException, RuntimeException, NoSupportException)
{
    ::osl::MutexGuard aGuard( getMutex() );
	implCheckReadOnly( "StringResourceImpl::newLocale(): Read only" );

	if( getItemForLocale( locale, false ) != NULL )
	{
        ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceImpl: locale already exists" );
        throw ElementExistException( errorMsg, Reference< XInterface >() );
	}

	// TODO?: Check if locale is valid? How?
	bool bValid = true;
	if( bValid )
	{
		LocaleItem* pLocaleItem = new LocaleItem( locale );
		m_aLocaleItemVector.push_back( pLocaleItem );
		pLocaleItem->m_bModified = true;

		// Copy strings from default locale
		LocaleItem* pCopyFromItem = m_pDefaultLocaleItem;
		if( pCopyFromItem == NULL )
			pCopyFromItem = m_pCurrentLocaleItem;
		if( pCopyFromItem != NULL && loadLocale( pCopyFromItem ) )
		{
			const IdToStringMap& rSourceMap = pCopyFromItem->m_aIdToStringMap;
			IdToStringMap& rTargetMap = pLocaleItem->m_aIdToStringMap;
			IdToStringMap::const_iterator it;
			for( it = rSourceMap.begin(); it != rSourceMap.end(); it++ )
			{
				::rtl::OUString aId  = (*it).first;
				::rtl::OUString aStr = (*it).second;
				rTargetMap[ aId ] = aStr;
			}

			const IdToIndexMap& rSourceIndexMap = pCopyFromItem->m_aIdToIndexMap;
			IdToIndexMap& rTargetIndexMap = pLocaleItem->m_aIdToIndexMap;
			IdToIndexMap::const_iterator it_index;
			for( it_index = rSourceIndexMap.begin(); it_index != rSourceIndexMap.end(); it_index++ )
			{
				::rtl::OUString aId  = (*it_index).first;
				sal_Int32 nIndex = (*it_index).second;
				rTargetIndexMap[ aId ] = nIndex;
			}
			pLocaleItem->m_nNextIndex = pCopyFromItem->m_nNextIndex;
		}

		if( m_pCurrentLocaleItem == NULL )
			m_pCurrentLocaleItem = pLocaleItem;

		if( m_pDefaultLocaleItem == NULL )
		{
			m_pDefaultLocaleItem = pLocaleItem;
			m_bDefaultModified = true;
		}

		implModified();
	}
	else
	{
        ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceImpl: Invalid locale" );
        throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 );
	}
}

void StringResourceImpl::removeLocale( const Locale& locale )
	throw (IllegalArgumentException, RuntimeException, NoSupportException)
{
    ::osl::MutexGuard aGuard( getMutex() );
	implCheckReadOnly( "StringResourceImpl::removeLocale(): Read only" );

	LocaleItem* pRemoveItem = getItemForLocale( locale, true );
	if( pRemoveItem )
	{
		// Last locale?
		sal_Int32 nLocaleCount = m_aLocaleItemVector.size();
		if( nLocaleCount > 1 )
		{
			LocaleItem* pFallbackItem = NULL;
			if( m_pCurrentLocaleItem == pRemoveItem ||
				m_pDefaultLocaleItem  == pRemoveItem )
			{
				for( LocaleItemVectorIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
				{
					LocaleItem* pLocaleItem = *it;
					if( pLocaleItem != pRemoveItem )
					{
						pFallbackItem = pLocaleItem;
						break;
					}
				}
				if( m_pCurrentLocaleItem == pRemoveItem )
				{
					sal_Bool FindClosestMatch = false;
					setCurrentLocale( pFallbackItem->m_locale, FindClosestMatch );
				}
				if( m_pDefaultLocaleItem == pRemoveItem )
				{
					setDefaultLocale( pFallbackItem->m_locale );
				}
			}
		}
		for( LocaleItemVectorIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
		{
			LocaleItem* pLocaleItem = *it;
			if( pLocaleItem == pRemoveItem )
			{
				// Remember locale item to delete file while storing
				m_aDeletedLocaleItemVector.push_back( pLocaleItem );

				// Last locale?
				if( nLocaleCount == 1 )
				{
					m_nNextUniqueNumericId = 0;
					if( m_pDefaultLocaleItem )
					{
						LocaleItem* pChangedDefaultLocaleItem = new LocaleItem( m_pDefaultLocaleItem->m_locale );
						m_aChangedDefaultLocaleVector.push_back( pChangedDefaultLocaleItem );
					}
					m_pCurrentLocaleItem = NULL;
					m_pDefaultLocaleItem = NULL;
				}

				m_aLocaleItemVector.erase( it );

				implModified();
				break;
			}
		}
	}
}

void StringResourceImpl::implScanIdForNumber( const ::rtl::OUString& ResourceID )
{
	const sal_Unicode* pSrc = ResourceID.getStr();
	sal_Int32 nLen = ResourceID.getLength();

	sal_Int32 nNumber = 0;
	for( sal_Int32 i = 0 ; i < nLen ; i++ )
	{
		sal_Unicode c = pSrc[i];
		if( c >= '0' && c <= '9' )
		{
			sal_uInt16 nDigitVal = c - '0';
			nNumber = 10*nNumber + nDigitVal;
		}
		else
			break;
	}

	if( m_nNextUniqueNumericId < nNumber + 1 )
		m_nNextUniqueNumericId = nNumber + 1;
}

sal_Int32 StringResourceImpl::getUniqueNumericId(  )
	throw (RuntimeException, NoSupportException)
{
	if( m_nNextUniqueNumericId == UNIQUE_NUMBER_NEEDS_INITIALISATION )
	{
		implLoadAllLocales();
		m_nNextUniqueNumericId = 0;
	}

	if( m_nNextUniqueNumericId < UNIQUE_NUMBER_NEEDS_INITIALISATION )
	{
        ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "getUniqueNumericId: Extended sal_Int32 range" );
        throw NoSupportException( errorMsg, Reference< XInterface >() );
	}
	return m_nNextUniqueNumericId;
}


// =============================================================================
// Private helper methods

LocaleItem* StringResourceImpl::getItemForLocale
	( const Locale& locale, sal_Bool bException )
		throw (::com::sun::star::lang::IllegalArgumentException)
{
	LocaleItem* pRetItem = NULL;

	// Search for locale
    for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
    {
		LocaleItem* pLocaleItem = *it;
		if( pLocaleItem )
		{
			Locale& cmp_locale = pLocaleItem->m_locale;
			if( cmp_locale.Language == locale.Language &&
				cmp_locale.Country  == locale.Country &&
				cmp_locale.Variant  == locale.Variant )
			{
				pRetItem = pLocaleItem;
				break;
			}
		}
    }

	if( pRetItem == NULL && bException )
	{
        ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceImpl: Invalid locale" );
        throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 );
	}
	return pRetItem;
}

// Returns the LocalItem for a given locale, if it exists, otherwise NULL
// This method performes a closest match search, at least the language must match
LocaleItem* StringResourceImpl::getClosestMatchItemForLocale( const Locale& locale )
{
	LocaleItem* pRetItem = NULL;

	// Search for locale
	for( sal_Int32 iPass = 0 ; iPass <= 2 ; ++iPass )
	{
		for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
		{
			LocaleItem* pLocaleItem = *it;
			if( pLocaleItem )
			{
				Locale& cmp_locale = pLocaleItem->m_locale;
				if( cmp_locale.Language == locale.Language &&
					(iPass > 1 || cmp_locale.Country  == locale.Country) &&
					(iPass > 0 || cmp_locale.Variant  == locale.Variant) )
				{
					pRetItem = pLocaleItem;
					break;
				}
			}
		}
		if( pRetItem )
			break;
	}

	return pRetItem;
}

void StringResourceImpl::implModified( void )
{
	m_bModified = true;
	implNotifyListeners();
}

void StringResourceImpl::implNotifyListeners( void )
{
	EventObject aEvent;
	aEvent.Source = static_cast< XInterface* >( (OWeakObject*)this );

	::cppu::OInterfaceIteratorHelper it( m_aListenerContainer );
	while( it.hasMoreElements() )
	{
		Reference< XInterface > xIface = it.next();
		Reference< XModifyListener > xListener( xIface, UNO_QUERY );
        try
        {
            xListener->modified( aEvent );
        }
        catch(RuntimeException&)
        {
            it.remove();
        }
	}
}


// =============================================================================
// Loading

bool StringResourceImpl::loadLocale( LocaleItem* pLocaleItem )
{
	// Base implementation has nothing to load
	(void)pLocaleItem;
	return true;
}

void StringResourceImpl::implLoadAllLocales( void )
{
	// Base implementation has nothing to load
}


Reference< XMultiComponentFactory > StringResourceImpl::getMultiComponentFactory( void )
{
    ::osl::MutexGuard aGuard( getMutex() );

	if( !m_xMCF.is() )
	{
		Reference< XMultiComponentFactory > xSMgr( m_xContext->getServiceManager(), UNO_QUERY );
		if( !xSMgr.is() )
		{
			throw RuntimeException(
				::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StringResourceImpl::getMultiComponentFactory: Couldn't instantiate MultiComponentFactory" ) ),
					Reference< XInterface >() );
		}
		m_xMCF = xSMgr;
	}
	return m_xMCF;
}


// =============================================================================
// StringResourcePersistenceImpl
// =============================================================================

StringResourcePersistenceImpl::StringResourcePersistenceImpl( const Reference< XComponentContext >& rxContext )
    : StringResourcePersistenceImpl_BASE( rxContext )
{
}

// -----------------------------------------------------------------------------

StringResourcePersistenceImpl::~StringResourcePersistenceImpl()
{
}

// -----------------------------------------------------------------------------
// XServiceInfo
// -----------------------------------------------------------------------------

::rtl::OUString StringResourcePersistenceImpl::getImplementationName(  )
	throw (RuntimeException)
{
    return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM
		( "com.sun.star.comp.scripting.StringResourceWithLocation") );
}

// -----------------------------------------------------------------------------

sal_Bool StringResourcePersistenceImpl::supportsService( const ::rtl::OUString& rServiceName )
	throw (RuntimeException)
{
	return StringResourceImpl::supportsService( rServiceName );
}

// -----------------------------------------------------------------------------

Sequence< ::rtl::OUString > StringResourcePersistenceImpl::getSupportedServiceNames(  )
	throw (RuntimeException)
{
    return StringResourceImpl::getSupportedServiceNames();
}

// -----------------------------------------------------------------------------
// XInitialization base functionality for derived classes
// -----------------------------------------------------------------------------

static ::rtl::OUString aNameBaseDefaultStr = ::rtl::OUString::createFromAscii( "strings" );

void StringResourcePersistenceImpl::implInitializeCommonParameters
	( const Sequence< Any >& aArguments ) 
		throw (Exception, RuntimeException)
{
	bool bReadOnlyOk = (aArguments[1] >>= m_bReadOnly);
	if( !bReadOnlyOk )
    {
        ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "XInitialization::initialize: Expected ReadOnly flag" );
        throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 1 );
	}

	com::sun::star::lang::Locale aCurrentLocale;
	bool bLocaleOk = (aArguments[2] >>= aCurrentLocale);
	if( !bLocaleOk )
    {
        ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "XInitialization::initialize: Expected Locale" );
        throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 2 );
	}

	bool bNameBaseOk = (aArguments[3] >>= m_aNameBase);
	if( !bNameBaseOk )
    {
        ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "XInitialization::initialize: Expected NameBase string" );
        throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 3 );
	}
	if( m_aNameBase.getLength() == 0 )
		m_aNameBase = aNameBaseDefaultStr;

	bool bCommentOk = (aArguments[4] >>= m_aComment);
	if( !bCommentOk )
    {
        ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "XInitialization::initialize: Expected Comment string" );
        throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 4 );
	}

	implScanLocales();

	sal_Bool FindClosestMatch = true;
	sal_Bool bUseDefaultIfNoMatch = true;
	implSetCurrentLocale( aCurrentLocale, FindClosestMatch, bUseDefaultIfNoMatch );
}

// -----------------------------------------------------------------------------
// Forwarding calls to base class

// XModifyBroadcaster
void StringResourcePersistenceImpl::addModifyListener( const Reference< XModifyListener >& aListener )
	throw (RuntimeException)
{
	StringResourceImpl::addModifyListener( aListener );
}
void StringResourcePersistenceImpl::removeModifyListener( const Reference< XModifyListener >& aListener )
	throw (RuntimeException)
{
	StringResourceImpl::removeModifyListener( aListener );
}

// XStringResourceResolver
::rtl::OUString StringResourcePersistenceImpl::resolveString( const ::rtl::OUString& ResourceID ) 
	throw (::com::sun::star::resource::MissingResourceException, RuntimeException)
{
	return StringResourceImpl::resolveString( ResourceID ) ;
}
::rtl::OUString StringResourcePersistenceImpl::resolveStringForLocale( const ::rtl::OUString& ResourceID, const Locale& locale )
	throw ( ::com::sun::star::resource::MissingResourceException, RuntimeException)
{
	return StringResourceImpl::resolveStringForLocale( ResourceID, locale );
}
sal_Bool StringResourcePersistenceImpl::hasEntryForId( const ::rtl::OUString& ResourceID )
	throw (RuntimeException)
{
	return StringResourceImpl::hasEntryForId( ResourceID ) ;
}
sal_Bool StringResourcePersistenceImpl::hasEntryForIdAndLocale( const ::rtl::OUString& ResourceID, 
	const Locale& locale )
		throw (RuntimeException)
{
	return StringResourceImpl::hasEntryForIdAndLocale( ResourceID, locale );
}
Locale StringResourcePersistenceImpl::getCurrentLocale()
	throw (RuntimeException)
{
	return StringResourceImpl::getCurrentLocale();
}
Locale StringResourcePersistenceImpl::getDefaultLocale(  )
	throw (RuntimeException)
{
	return StringResourceImpl::getDefaultLocale();
}
Sequence< Locale > StringResourcePersistenceImpl::getLocales(  )
	throw (RuntimeException)
{
	return StringResourceImpl::getLocales();
}

// XStringResourceManager
sal_Bool StringResourcePersistenceImpl::isReadOnly()
	throw (RuntimeException)
{
	return StringResourceImpl::isReadOnly();
}
void StringResourcePersistenceImpl::setCurrentLocale( const Locale& locale, sal_Bool FindClosestMatch )
	throw (IllegalArgumentException, RuntimeException)
{
	StringResourceImpl::setCurrentLocale( locale, FindClosestMatch );
}
void StringResourcePersistenceImpl::setDefaultLocale( const Locale& locale )
	throw (IllegalArgumentException, RuntimeException,NoSupportException)
{
	StringResourceImpl::setDefaultLocale( locale );
}
Sequence< ::rtl::OUString > StringResourcePersistenceImpl::getResourceIDs(  )
	throw (RuntimeException)
{
	return StringResourceImpl::getResourceIDs();
}
void StringResourcePersistenceImpl::setString( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str )
	throw (NoSupportException, RuntimeException)
{
	StringResourceImpl::setString( ResourceID, Str );
}
void StringResourcePersistenceImpl::setStringForLocale
	( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str, const Locale& locale )
		throw (NoSupportException, RuntimeException)
{
	StringResourceImpl::setStringForLocale( ResourceID, Str, locale );
}
Sequence< ::rtl::OUString > StringResourcePersistenceImpl::getResourceIDsForLocale
	( const Locale& locale ) throw (::com::sun::star::uno::RuntimeException)
{
	return StringResourceImpl::getResourceIDsForLocale( locale );
}
void StringResourcePersistenceImpl::removeId( const ::rtl::OUString& ResourceID )
	throw (::com::sun::star::resource::MissingResourceException, RuntimeException, NoSupportException)
{
	StringResourceImpl::removeId( ResourceID );
}
void StringResourcePersistenceImpl::removeIdForLocale( const ::rtl::OUString& ResourceID, const Locale& locale )
	throw (::com::sun::star::resource::MissingResourceException, RuntimeException, NoSupportException)
{
	StringResourceImpl::removeIdForLocale( ResourceID, locale );
}
void StringResourcePersistenceImpl::newLocale( const Locale& locale )
	throw (ElementExistException, IllegalArgumentException, RuntimeException, NoSupportException)
{
	StringResourceImpl::newLocale( locale );
}
void StringResourcePersistenceImpl::removeLocale( const Locale& locale )
	throw (IllegalArgumentException, RuntimeException, NoSupportException)
{
	StringResourceImpl::removeLocale( locale );
}
sal_Int32 StringResourcePersistenceImpl::getUniqueNumericId(  )
	throw (RuntimeException, NoSupportException)
{
	return StringResourceImpl::getUniqueNumericId();
}

// -----------------------------------------------------------------------------
// XStringResourcePersistence

void StringResourcePersistenceImpl::store()
	throw (NoSupportException, Exception, RuntimeException)
{
}

sal_Bool StringResourcePersistenceImpl::isModified(  )
	throw (RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );

	return m_bModified;
}

void StringResourcePersistenceImpl::setComment( const ::rtl::OUString& Comment )
	throw (::com::sun::star::uno::RuntimeException)
{
	m_aComment = Comment;
}

void StringResourcePersistenceImpl::storeToStorage( const Reference< XStorage >& Storage,
	const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment )
		throw (Exception, RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );

	bool bUsedForStore = false;
	bool bStoreAll = true;
	implStoreAtStorage( NameBase, Comment, Storage, bUsedForStore, bStoreAll );
}

void StringResourcePersistenceImpl::implStoreAtStorage
(
	const ::rtl::OUString& aNameBase,
	const ::rtl::OUString& aComment,
	const Reference< ::com::sun::star::embed::XStorage >& Storage,
	bool bUsedForStore,
	bool bStoreAll
)
	throw (Exception, RuntimeException)
{
	// Delete files for deleted locales
	if( bUsedForStore )
	{
		while( m_aDeletedLocaleItemVector.size() > 0 )
		{
			LocaleItemVectorIt it = m_aDeletedLocaleItemVector.begin();
			LocaleItem* pLocaleItem = *it;
			if( pLocaleItem != NULL )
			{
				::rtl::OUString aStreamName = implGetFileNameForLocaleItem( pLocaleItem, m_aNameBase );
				aStreamName += ::rtl::OUString::createFromAscii( ".properties" );

				try
				{
					Storage->removeElement( aStreamName );
				}
				catch( Exception& )
				{}

				m_aDeletedLocaleItemVector.erase( it );
				delete pLocaleItem;
			}
		}
	}

    for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
    {
		LocaleItem* pLocaleItem = *it;
		if( pLocaleItem != NULL && (bStoreAll || pLocaleItem->m_bModified) && 
			loadLocale( pLocaleItem ) )
		{
			::rtl::OUString aStreamName = implGetFileNameForLocaleItem( pLocaleItem, aNameBase );
			aStreamName += ::rtl::OUString::createFromAscii( ".properties" );

			Reference< io::XStream > xElementStream = 
					Storage->openStreamElement( aStreamName, ElementModes::READWRITE );

			::rtl::OUString aPropName = ::rtl::OUString::createFromAscii( "MediaType" );
			::rtl::OUString aMime = ::rtl::OUString::createFromAscii( "text/plain" );

			uno::Reference< beans::XPropertySet > xProps( xElementStream, uno::UNO_QUERY );
			OSL_ENSURE( xProps.is(), "The StorageStream must implement XPropertySet interface!\n" );
            if ( xProps.is() )
            {
                xProps->setPropertyValue( aPropName, uno::makeAny( aMime ) );

                aPropName = ::rtl::OUString::createFromAscii( "UseCommonStoragePasswordEncryption" );
                xProps->setPropertyValue( aPropName, uno::makeAny( sal_True ) );
            }

            Reference< io::XOutputStream > xOutputStream = xElementStream->getOutputStream();
			if( xOutputStream.is() )
				implWritePropertiesFile( pLocaleItem, xOutputStream, aComment );
            xOutputStream->closeOutput();

			if( bUsedForStore )
				pLocaleItem->m_bModified = false;
		}
	}

	// Delete files for changed defaults
	if( bUsedForStore )
	{
		for( LocaleItemVectorIt it = m_aChangedDefaultLocaleVector.begin(); 
			 it != m_aChangedDefaultLocaleVector.end(); it++ )
		{
			LocaleItem* pLocaleItem = *it;
			if( pLocaleItem != NULL )
			{
				::rtl::OUString aStreamName = implGetFileNameForLocaleItem( pLocaleItem, m_aNameBase );
				aStreamName += ::rtl::OUString::createFromAscii( ".default" );

				try
				{
					Storage->removeElement( aStreamName );
				}
				catch( Exception& )
				{}

				delete pLocaleItem;
			}
		}
		m_aChangedDefaultLocaleVector.clear();
	}

	// Default locale
	if( m_pDefaultLocaleItem != NULL && (bStoreAll || m_bDefaultModified) )
	{
		::rtl::OUString aStreamName = implGetFileNameForLocaleItem( m_pDefaultLocaleItem, aNameBase );
		aStreamName += ::rtl::OUString::createFromAscii( ".default" );

		Reference< io::XStream > xElementStream = 
				Storage->openStreamElement( aStreamName, ElementModes::READWRITE );

		::rtl::OUString aPropName = ::rtl::OUString::createFromAscii( "MediaType" );
		::rtl::OUString aMime = ::rtl::OUString::createFromAscii( "text/plain" );

		// Only create stream without content
		Reference< io::XOutputStream > xOutputStream = xElementStream->getOutputStream();
		xOutputStream->closeOutput();

		if( bUsedForStore )
			m_bDefaultModified = false;
	}
}

void StringResourcePersistenceImpl::storeToURL( const ::rtl::OUString& URL,
	const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment,
	const Reference< ::com::sun::star::task::XInteractionHandler >& Handler )
		throw (Exception, RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );

	bool bUsedForStore = false;
	bool bStoreAll = true;

	Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory();
	Reference< ucb::XSimpleFileAccess > xFileAccess;
	xFileAccess = Reference< ucb::XSimpleFileAccess >( xMCF->createInstanceWithContext
		( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ), 
			m_xContext ), UNO_QUERY );
	if( xFileAccess.is() && Handler.is() )
		xFileAccess->setInteractionHandler( Handler );

	implStoreAtLocation( URL, NameBase, Comment, xFileAccess, bUsedForStore, bStoreAll );
}

void StringResourcePersistenceImpl::implKillRemovedLocaleFiles
(
	const ::rtl::OUString& Location,
	const ::rtl::OUString& aNameBase,
	const ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XSimpleFileAccess >& xFileAccess
)
	throw (Exception, RuntimeException)
{
	// Delete files for deleted locales
	while( m_aDeletedLocaleItemVector.size() > 0 )
	{
		LocaleItemVectorIt it = m_aDeletedLocaleItemVector.begin();
		LocaleItem* pLocaleItem = *it;
		if( pLocaleItem != NULL )
		{
			::rtl::OUString aCompleteFileName = 
				implGetPathForLocaleItem( pLocaleItem, aNameBase, Location );
			if( xFileAccess->exists( aCompleteFileName ) )
				xFileAccess->kill( aCompleteFileName );

			m_aDeletedLocaleItemVector.erase( it );
			delete pLocaleItem;
		}
	}
}

void StringResourcePersistenceImpl::implKillChangedDefaultFiles
(
	const ::rtl::OUString& Location,
	const ::rtl::OUString& aNameBase,
	const ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XSimpleFileAccess >& xFileAccess
)
	throw (Exception, RuntimeException)
{
	// Delete files for changed defaults
	for( LocaleItemVectorIt it = m_aChangedDefaultLocaleVector.begin(); 
		 it != m_aChangedDefaultLocaleVector.end(); it++ )
	{
		LocaleItem* pLocaleItem = *it;
		if( pLocaleItem != NULL )
		{
			::rtl::OUString aCompleteFileName = 
				implGetPathForLocaleItem( pLocaleItem, aNameBase, Location, true );
			if( xFileAccess->exists( aCompleteFileName ) )
				xFileAccess->kill( aCompleteFileName );

			delete pLocaleItem;
		}
	}
	m_aChangedDefaultLocaleVector.clear();
}

void StringResourcePersistenceImpl::implStoreAtLocation
(
	const ::rtl::OUString& Location,
	const ::rtl::OUString& aNameBase,
	const ::rtl::OUString& aComment,
	const Reference< ucb::XSimpleFileAccess >& xFileAccess,
	bool bUsedForStore,
	bool bStoreAll,
	bool bKillAll
)
	throw (Exception, RuntimeException)
{
	// Delete files for deleted locales
	if( bUsedForStore || bKillAll )
		implKillRemovedLocaleFiles( Location, aNameBase, xFileAccess );

    for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
    {
		LocaleItem* pLocaleItem = *it;
		if( pLocaleItem != NULL && (bStoreAll || bKillAll || pLocaleItem->m_bModified) && 
			loadLocale( pLocaleItem ) )
		{
			::rtl::OUString aCompleteFileName = 
				implGetPathForLocaleItem( pLocaleItem, aNameBase, Location );
			if( xFileAccess->exists( aCompleteFileName ) )
				xFileAccess->kill( aCompleteFileName );

			if( !bKillAll )
			{
				// Create Output stream
				Reference< io::XOutputStream > xOutputStream = xFileAccess->openFileWrite( aCompleteFileName );
				if( xOutputStream.is() )
				{
					implWritePropertiesFile( pLocaleItem, xOutputStream, aComment );
					xOutputStream->closeOutput();
				}
				if( bUsedForStore )
					pLocaleItem->m_bModified = false;
			}
		}
	}

	// Delete files for changed defaults
	if( bUsedForStore || bKillAll )
		implKillChangedDefaultFiles( Location, aNameBase, xFileAccess );

	// Default locale
	if( m_pDefaultLocaleItem != NULL && (bStoreAll || bKillAll || m_bDefaultModified) )
	{
		::rtl::OUString aCompleteFileName = 
			implGetPathForLocaleItem( m_pDefaultLocaleItem, aNameBase, Location, true );
		if( xFileAccess->exists( aCompleteFileName ) )
			xFileAccess->kill( aCompleteFileName );

		if( !bKillAll )
		{
			// Create Output stream
			Reference< io::XOutputStream > xOutputStream = xFileAccess->openFileWrite( aCompleteFileName );
			if( xOutputStream.is() )
				xOutputStream->closeOutput();

			if( bUsedForStore )
				m_bDefaultModified = false;
		}
	}
}


// -----------------------------------------------------------------------------
// BinaryOutput, helper class for exportBinary

class BinaryOutput
{
	Reference< XMultiComponentFactory >		m_xMCF;
    Reference< XComponentContext >	        m_xContext;
	Reference< XInterface >					m_xTempFile;
	Reference< io::XOutputStream >			m_xOutputStream;

public:
	BinaryOutput( Reference< XMultiComponentFactory > xMCF,
		Reference< XComponentContext > xContext );

	Reference< io::XOutputStream > getOutputStream( void )
		{ return m_xOutputStream; }

	Sequence< ::sal_Int8 > closeAndGetData( void );

	// Template to be used with sal_Int16 and sal_Unicode
	template< class T >
	void write16BitInt( T n );
	void writeInt16( sal_Int16 n )
		{ write16BitInt( n ); }
	void writeUnicodeChar( sal_Unicode n )
		{ write16BitInt( n ); }
	void writeInt32( sal_Int32 n );
	void writeString( const ::rtl::OUString& aStr );
};

BinaryOutput::BinaryOutput( Reference< XMultiComponentFactory > xMCF,
	Reference< XComponentContext > xContext )
		: m_xMCF( xMCF )
		, m_xContext( xContext )
{
	m_xTempFile = m_xMCF->createInstanceWithContext
		( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ), m_xContext );
	if( m_xTempFile.is() )
		m_xOutputStream = Reference< io::XOutputStream >( m_xTempFile, UNO_QUERY );
}

template< class T >
void BinaryOutput::write16BitInt( T n )
{
	if( !m_xOutputStream.is() )
		return;

	Sequence< sal_Int8 > aSeq( 2 );
	sal_Int8* p = aSeq.getArray();

	sal_Int8 nLow  = sal_Int8( n & 0xff );
	sal_Int8 nHigh = sal_Int8( n >> 8 );

	p[0] = nLow;
	p[1] = nHigh;
	m_xOutputStream->writeBytes( aSeq );
}

void BinaryOutput::writeInt32( sal_Int32 n )
{
	if( !m_xOutputStream.is() )
		return;

	Sequence< sal_Int8 > aSeq( 4 );
	sal_Int8* p = aSeq.getArray();

	for( sal_Int16 i = 0 ; i < 4 ; i++ )
	{
		p[i] = sal_Int8( n & 0xff );
		n >>= 8;
	}
	m_xOutputStream->writeBytes( aSeq );
}

void BinaryOutput::writeString( const ::rtl::OUString& aStr )
{
	sal_Int32 nLen = aStr.getLength();
	const sal_Unicode* pStr = aStr.getStr();

	for( sal_Int32 i = 0 ; i < nLen ; i++ )
		writeUnicodeChar( pStr[i] );

	writeUnicodeChar( 0 );
}

Sequence< ::sal_Int8 > BinaryOutput::closeAndGetData( void )
{
	Sequence< ::sal_Int8 > aRetSeq;
	if( !m_xOutputStream.is() )
		return aRetSeq;

	m_xOutputStream->closeOutput();

	Reference< io::XSeekable> xSeekable( m_xTempFile, UNO_QUERY );
	if( !xSeekable.is() )
		return aRetSeq;

	sal_Int32 nSize = (sal_Int32)xSeekable->getPosition();

	Reference< io::XInputStream> xInputStream( m_xTempFile, UNO_QUERY );
	if( !xInputStream.is() )
		return aRetSeq;

	xSeekable->seek( 0 );
	sal_Int32 nRead = xInputStream->readBytes( aRetSeq, nSize );
	(void)nRead;
	OSL_ENSURE( nRead == nSize, "BinaryOutput::closeAndGetData: nRead != nSize" );

	return aRetSeq;
}


// Binary format:

// Header
// Byte			Content
// 0 + 1		sal_Int16:	Version, currently 0, low byte first
// 2 + 3		sal_Int16:	Locale count = n, low byte first
// 4 + 5		sal_Int16:	Default Locale position in Locale list, == n if none
// 6 - 7		sal_Int32:	Start index locale block 0, lowest byte first
// (n-1) *		sal_Int32:	Start index locale block 1 to n, lowest byte first
// 6 + 4*n		sal_Int32:	"Start index" non existing locale block n+1,
//							marks the first invalid index, kind of EOF

// Locale block
// All strings are stored as 2-Byte-0 terminated sequence
// of 16 bit Unicode characters, each with low byte first
// Empty strings only contain the 2-Byte-0

// Members of com.sun.star.lang.Locale
// with l1 = Locale.Language.getLength()
// with l2 = Locale.Country.getLength()
// with l3 = Locale.Variant.getLength()
// pos0 = 0						Locale.Language
// pos1 = 2 * (l1 + 1)			Locale.Country
// pos2 = pos1 + 2 * (l2 + 1)	Locale.Variant
// pos3 = pos2 + 2 * (l3 + 1)
// pos3							Properties file written by implWritePropertiesFile

Sequence< sal_Int8 > StringResourcePersistenceImpl::exportBinary(  )
	throw (RuntimeException)
{
	Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory();
	BinaryOutput aOut( xMCF, m_xContext );

	sal_Int32 nLocaleCount = m_aLocaleItemVector.size();
	Sequence< sal_Int8 >* pLocaleDataSeq = new Sequence< sal_Int8 >[ nLocaleCount ];

	sal_Int32 iLocale = 0;
	sal_Int32 iDefault = 0;
    for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin(); 
		 it != m_aLocaleItemVector.end(); it++,iLocale++ )
    {
		LocaleItem* pLocaleItem = *it;
		if( pLocaleItem != NULL && loadLocale( pLocaleItem ) )
		{
			if( m_pDefaultLocaleItem == pLocaleItem )
				iDefault = iLocale;

			BinaryOutput aLocaleOut( m_xMCF, m_xContext );
			implWriteLocaleBinary( pLocaleItem, aLocaleOut );

			pLocaleDataSeq[iLocale] = aLocaleOut.closeAndGetData();
		}
	}

	// Write header
	sal_Int16 nVersion = 0;
	sal_Int16 nLocaleCount16 = (sal_Int16)nLocaleCount;
	sal_Int16 iDefault16 = (sal_Int16)iDefault;
	aOut.writeInt16( nVersion );
	aOut.writeInt16( nLocaleCount16 );
	aOut.writeInt16( iDefault16 );

	// Write data positions
	sal_Int32 nDataPos = 6 + 4 * (nLocaleCount + 1);
	for( iLocale = 0; iLocale < nLocaleCount; iLocale++ )
	{
		aOut.writeInt32( nDataPos );

		Sequence< sal_Int8 >& rSeq = pLocaleDataSeq[iLocale];
	    sal_Int32 nSeqLen = rSeq.getLength();
		nDataPos += nSeqLen;
	}
	// Write final position
	aOut.writeInt32( nDataPos );

	// Write data
	Reference< io::XOutputStream > xOutputStream = aOut.getOutputStream();
	if( xOutputStream.is() )
	{
		for( iLocale = 0; iLocale < nLocaleCount; iLocale++ )
		{
			Sequence< sal_Int8 >& rSeq = pLocaleDataSeq[iLocale];
			xOutputStream->writeBytes( rSeq );
		}
	}

	delete[] pLocaleDataSeq;

	Sequence< sal_Int8 > aRetSeq = aOut.closeAndGetData();
	return aRetSeq;
}

void StringResourcePersistenceImpl::implWriteLocaleBinary
	( LocaleItem* pLocaleItem, BinaryOutput& rOut )
{
	Reference< io::XOutputStream > xOutputStream = rOut.getOutputStream();
	if( !xOutputStream.is() )
		return;

	Locale& rLocale = pLocaleItem->m_locale;
	rOut.writeString( rLocale.Language );
	rOut.writeString( rLocale.Country );
	rOut.writeString( rLocale.Variant );
	implWritePropertiesFile( pLocaleItem, xOutputStream, m_aComment );
}

// -----------------------------------------------------------------------------
// BinaryOutput, helper class for exportBinary

class BinaryInput
{
	Sequence< sal_Int8 >					m_aData;
	Reference< XMultiComponentFactory >		m_xMCF;
	Reference< XComponentContext >	        m_xContext;

	const sal_Int8*							m_pData;
	sal_Int32								m_nCurPos;
	sal_Int32								m_nSize;

public:
	BinaryInput( Sequence< ::sal_Int8 > aData, Reference< XMultiComponentFactory > xMCF,
		Reference< XComponentContext > xContext );

	Reference< io::XInputStream > getInputStreamForSection( sal_Int32 nSize );

	void seek( sal_Int32 nPos );
	sal_Int32 getPosition( void )
		{ return m_nCurPos; }

	sal_Int16 readInt16( void );
	sal_Int32 readInt32( void );
	sal_Unicode readUnicodeChar( void );
	::rtl::OUString readString( void );
};

BinaryInput::BinaryInput( Sequence< ::sal_Int8 > aData, Reference< XMultiComponentFactory > xMCF,
	Reference< XComponentContext > xContext )
		: m_aData( aData )
		, m_xMCF( xMCF )
		, m_xContext( xContext )
{
	m_pData = m_aData.getConstArray();
	m_nCurPos = 0;
	m_nSize = m_aData.getLength();
}

Reference< io::XInputStream > BinaryInput::getInputStreamForSection( sal_Int32 nSize )
{
	Reference< io::XInputStream > xIn;
	if( m_nCurPos + nSize <= m_nSize )
	{
		Reference< io::XOutputStream > xTempOut( m_xMCF->createInstanceWithContext
			( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ), m_xContext ), UNO_QUERY );
		if( xTempOut.is() )
		{
			Sequence< sal_Int8 > aSection( m_pData + m_nCurPos, nSize );
			xTempOut->writeBytes( aSection );

			Reference< io::XSeekable> xSeekable( xTempOut, UNO_QUERY );
			if( xSeekable.is() )
				xSeekable->seek( 0 );

			xIn = Reference< io::XInputStream>( xTempOut, UNO_QUERY );
		}
	}
	else
		OSL_ENSURE( false, "BinaryInput::getInputStreamForSection(): Read past end" );

	return xIn;
}

void BinaryInput::seek( sal_Int32 nPos )
{
	if( nPos <= m_nSize )
		m_nCurPos = nPos;
	else
		OSL_ENSURE( false, "BinaryInput::seek(): Position past end" );
}


sal_Int16 BinaryInput::readInt16( void )
{
	sal_Int16 nRet = 0;
	if( m_nCurPos + 2 <= m_nSize )
	{
		nRet = nRet + sal_Int16( sal_uInt8( m_pData[m_nCurPos++] ) );
		nRet += 256 * sal_Int16( sal_uInt8( m_pData[m_nCurPos++] ) );
	}
	else
		OSL_ENSURE( false, "BinaryInput::readInt16(): Read past end" );

	return nRet;
}

sal_Int32 BinaryInput::readInt32( void )
{
	sal_Int32 nRet = 0;
	if( m_nCurPos + 4 <= m_nSize )
	{
		sal_Int32 nFactor = 1;
		for( sal_Int16 i = 0; i < 4; i++ )
		{
			nRet += sal_uInt8( m_pData[m_nCurPos++] ) * nFactor;
			nFactor *= 256;
		}
	}
	else
		OSL_ENSURE( false, "BinaryInput::readInt32(): Read past end" );

	return nRet;
}

sal_Unicode BinaryInput::readUnicodeChar( void )
{
	sal_uInt16 nRet = 0;
	if( m_nCurPos + 2 <= m_nSize )
	{
		nRet = nRet + sal_uInt8( m_pData[m_nCurPos++] );
		nRet += 256 * sal_uInt8( m_pData[m_nCurPos++] );
	}
	else
		OSL_ENSURE( false, "BinaryInput::readUnicodeChar(): Read past end" );

	sal_Unicode cRet = nRet;
	return cRet;
}

::rtl::OUString BinaryInput::readString( void )
{
	::rtl::OUStringBuffer aBuf;
	sal_Unicode c;
	do
	{
		c = readUnicodeChar();
		if( c != 0 )
			aBuf.append( c );
	}
	while( c != 0 );

	::rtl::OUString aRetStr = aBuf.makeStringAndClear();
	return aRetStr;
}

void StringResourcePersistenceImpl::importBinary( const Sequence< ::sal_Int8 >& Data )
	throw (IllegalArgumentException, RuntimeException)
{
	// Init: Remove all locales
	sal_Int32 nOldLocaleCount = 0;
	do
	{
		Sequence< Locale > aLocaleSeq = getLocales();
		nOldLocaleCount = aLocaleSeq.getLength();
		if( nOldLocaleCount > 0 )
		{
			Locale aLocale = aLocaleSeq[0];
			removeLocale( aLocale );
		}
	}
	while( nOldLocaleCount > 0 );

	// Import data
	Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory();
	BinaryInput aIn( Data, xMCF, m_xContext );

	sal_Int32 nVersion = aIn.readInt16();
	(void)nVersion;
	sal_Int32 nLocaleCount = aIn.readInt16();
	sal_Int32 iDefault = aIn.readInt16();
	(void)iDefault;

	sal_Int32* pPositions = new sal_Int32[nLocaleCount + 1];
	for( sal_Int32 i = 0; i < nLocaleCount + 1; i++ )
		pPositions[i] = aIn.readInt32();

	// Import locales
	LocaleItem* pUseAsDefaultItem = NULL;
	for( sal_Int32 i = 0; i < nLocaleCount; i++ )
	{
		sal_Int32 nPos = pPositions[i];
		aIn.seek( nPos );

		Locale aLocale;
		aLocale.Language = aIn.readString();
		aLocale.Country = aIn.readString();
		aLocale.Variant = aIn.readString();

		sal_Int32 nAfterStringPos = aIn.getPosition();
		sal_Int32 nSize = pPositions[i+1] - nAfterStringPos;
		Reference< io::XInputStream > xInput = aIn.getInputStreamForSection( nSize );
		if( xInput.is() )
		{
			LocaleItem* pLocaleItem = new LocaleItem( aLocale );
			if( iDefault == i )
				pUseAsDefaultItem = pLocaleItem;
			m_aLocaleItemVector.push_back( pLocaleItem );
			implReadPropertiesFile( pLocaleItem, xInput );
		}
	}

	if( pUseAsDefaultItem != NULL )
		setDefaultLocale( pUseAsDefaultItem->m_locale );

	delete[] pPositions;
}


// =============================================================================
// Private helper methods

bool checkNamingSceme( const ::rtl::OUString& aName, const ::rtl::OUString& aNameBase,
					   Locale& aLocale )
{
	bool bSuccess = false;

	sal_Int32 nNameLen = aName.getLength();
	sal_Int32 nNameBaseLen = aNameBase.getLength();

	// Name has to start with NameBase followed
	// by a '_' and at least one more character
    if( aName.indexOf( aNameBase ) == 0 && nNameBaseLen < nNameLen-1 &&
		aName.getStr()[nNameBaseLen] == '_' )
	{
		bSuccess = true;

		sal_Int32 iStart = nNameBaseLen + 1;
		sal_Int32 iNext_ = aName.indexOf( '_', iStart );
		if( iNext_ != -1 && iNext_ < nNameLen-1 )
		{
			aLocale.Language = aName.copy( iStart, iNext_ - iStart );

			iStart = iNext_ + 1;
			iNext_ = aName.indexOf( '_', iStart );
			if( iNext_ != -1 && iNext_ < nNameLen-1 )
			{
				aLocale.Country = aName.copy( iStart, iNext_ - iStart );
				aLocale.Variant = aName.copy( iNext_ + 1 );
			}
			else
				aLocale.Country = aName.copy( iStart );
		}
		else
			aLocale.Language = aName.copy( iStart );
	}
	return bSuccess;
}

void StringResourcePersistenceImpl::implLoadAllLocales( void )
{
	for( LocaleItemVectorIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ )
	{
		LocaleItem* pLocaleItem = *it;
		if( pLocaleItem != NULL )
			loadLocale( pLocaleItem );
	}
}

// Scan locale properties files helper
void StringResourcePersistenceImpl::implScanLocaleNames( const Sequence< ::rtl::OUString >& aContentSeq )
{
	Locale aDefaultLocale;
	bool bDefaultFound = false;

    sal_Int32 nCount = aContentSeq.getLength();
	const ::rtl::OUString* pFiles = aContentSeq.getConstArray();
	for( int i = 0 ; i < nCount ; i++ )
	{
		::rtl::OUString aCompleteName = pFiles[i];
		rtl::OUString aPureName;
		rtl::OUString aExtension;
		sal_Int32 iDot = aCompleteName.lastIndexOf( '.' );
		sal_Int32 iSlash = aCompleteName.lastIndexOf( '/' );
		if( iDot != -1 )
		{
			sal_Int32 iCopyFrom = (iSlash != -1) ? iSlash + 1 : 0;
			aPureName = aCompleteName.copy( iCopyFrom, iDot-iCopyFrom );
			aExtension = aCompleteName.copy( iDot + 1 );
		}

		if( aExtension.equalsAscii( "properties" ) )
		{
			//rtl::OUString aName = aInetObj.getBase();
			Locale aLocale;

			if( checkNamingSceme( aPureName, m_aNameBase, aLocale ) )
			{
				LocaleItem* pLocaleItem = new LocaleItem( aLocale, false );
				m_aLocaleItemVector.push_back( pLocaleItem );

				if( m_pCurrentLocaleItem == NULL )
					m_pCurrentLocaleItem = pLocaleItem;

				if( m_pDefaultLocaleItem == NULL )
				{
					m_pDefaultLocaleItem = pLocaleItem;
					m_bDefaultModified = true;
				}
			}
		}
		else if( !bDefaultFound && aExtension.equalsAscii( "default" ) )
		{
			//rtl::OUString aName = aInetObj.getBase();
			Locale aLocale;

			if( checkNamingSceme( aPureName, m_aNameBase, aDefaultLocale ) )
				bDefaultFound = true;
		}
	}
	if( bDefaultFound )
	{
		LocaleItem* pLocaleItem = getItemForLocale( aDefaultLocale, false );
		if( pLocaleItem )
		{
			m_pDefaultLocaleItem = pLocaleItem;
			m_bDefaultModified = false;
		}
	}
}

// Scan locale properties files
void StringResourcePersistenceImpl::implScanLocales( void )
{
	// Dummy implementation, method not called for this
	// base class, but pure virtual not possible-
}

bool StringResourcePersistenceImpl::loadLocale( LocaleItem* pLocaleItem )
{
	bool bSuccess = false;

	OSL_ENSURE( pLocaleItem, "StringResourcePersistenceImpl::loadLocale(): pLocaleItem == NULL" );
    if( pLocaleItem )
    {
		if( pLocaleItem->m_bLoaded )
		{
			bSuccess = true;
		}
		else
		{
			bSuccess = implLoadLocale( pLocaleItem );
			pLocaleItem->m_bLoaded = true;		// = bSuccess??? -> leads to more tries
		}
	}
	return bSuccess;
}

bool StringResourcePersistenceImpl::implLoadLocale( LocaleItem* )
{
	// Dummy implementation, method not called for this
	// base class, but pure virtual not possible-
	return false;
}

::rtl::OUString implGetNameScemeForLocaleItem( const LocaleItem* pLocaleItem )
{
	static ::rtl::OUString aUnder = ::rtl::OUString::createFromAscii( "_" );

	OSL_ENSURE( pLocaleItem, 
		"StringResourcePersistenceImpl::implGetNameScemeForLocaleItem(): pLocaleItem == NULL" );
	Locale aLocale = pLocaleItem->m_locale;

	::rtl::OUString aRetStr = aUnder;
	aRetStr += aLocale.Language;

	::rtl::OUString aCountry  = aLocale.Country;
	if( aCountry.getLength() )
	{
		aRetStr += aUnder;
		aRetStr += aCountry;
	}

	::rtl::OUString aVariant  = aLocale.Variant;
	if( aVariant.getLength() )
	{
		aRetStr += aUnder;
		aRetStr += aVariant;
	}
	return aRetStr;
}

::rtl::OUString StringResourcePersistenceImpl::implGetFileNameForLocaleItem
	( LocaleItem* pLocaleItem, const ::rtl::OUString& aNameBase )
{
	::rtl::OUString aFileName = aNameBase;
	if( aFileName.getLength() == 0 )
		aFileName = aNameBaseDefaultStr;

	aFileName += implGetNameScemeForLocaleItem( pLocaleItem );
	return aFileName;
}

::rtl::OUString StringResourcePersistenceImpl::implGetPathForLocaleItem
	( LocaleItem* pLocaleItem, const ::rtl::OUString& aNameBase, 
	  const ::rtl::OUString& aLocation, bool bDefaultFile )
{
	::rtl::OUString aFileName = implGetFileNameForLocaleItem( pLocaleItem, aNameBase );
	INetURLObject aInetObj( aLocation );
	aInetObj.insertName( aFileName, sal_True, INetURLObject::LAST_SEGMENT, sal_True, INetURLObject::ENCODE_ALL );
	if( bDefaultFile )
		aInetObj.setExtension( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("default") ) );
	else
		aInetObj.setExtension( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("properties") ) );
	::rtl::OUString aCompleteFileName = aInetObj.GetMainURL( INetURLObject::NO_DECODE );
	return aCompleteFileName;
}

// White space according to Java property files specification in
// http://java.sun.com/j2se/1.4.2/docs/api/java/util/Properties.html#load(java.io.InputStream)
inline bool isWhiteSpace( sal_Unicode c )
{
	bool bWhite = (	c == 0x0020 ||		// space
					c == 0x0009 ||		// tab
					c == 0x000a ||		// line feed, not always handled by TextInputStream
					c == 0x000d ||		// carriage return, not always handled by TextInputStream
					c == 0x000C );		// form feed
	return bWhite;
}

inline void skipWhites( const sal_Unicode* pBuf, sal_Int32 nLen, sal_Int32& ri )
{
	while( ri < nLen )
	{
		if( !isWhiteSpace( pBuf[ri] ) )
			break;
		ri++;
	}
}

inline bool isHexDigit( sal_Unicode c, sal_uInt16& nDigitVal )
{
	bool bRet = true;
	if( c >= '0' && c <= '9' )
		nDigitVal = c - '0';
	else if( c >= 'a' && c <= 'f' )
		nDigitVal = c - 'a' + 10;
	else if( c >= 'A' && c <= 'F' )
		nDigitVal = c - 'A' + 10;
	else
		bRet = false;
	return bRet;
}

sal_Unicode getEscapeChar( const sal_Unicode* pBuf, sal_Int32 nLen, sal_Int32& ri )
{
	sal_Int32 i = ri;

	sal_Unicode cRet = 0;
	sal_Unicode c = pBuf[i];
	switch( c )
	{
		case 't':
			cRet = 0x0009;
			break;
		case 'n':
			cRet = 0x000a;
			break;
		case 'f':
			cRet = 0x000c;
			break;
		case 'r':
			cRet = 0x000d;
			break;
		case '\\':
			cRet = '\\';
			break;
		case 'u':
		{
			// Skip multiple u
			i++;
			while( i < nLen && pBuf[i] == 'u' )
				i++;

			// Process hex digits
			sal_Int32 nDigitCount = 0;
			sal_uInt16 nDigitVal;
			while( i < nLen && isHexDigit( pBuf[i], nDigitVal ) )
			{
				cRet = 16 * cRet + nDigitVal;
			
				nDigitCount++;
				if( nDigitCount == 4 )
				{
					// Write back position
					ri = i;
					break;
				}
				i++;
			}
			break;
		}
		default:
			cRet = c;
	}

	return cRet;
}

void CheckContinueInNextLine( Reference< io::XTextInputStream > xTextInputStream, 
	::rtl::OUString& aLine, bool& bEscapePending, const sal_Unicode*& pBuf, 
	sal_Int32& nLen, sal_Int32& i )
{
	if( i == nLen && bEscapePending )
	{
		bEscapePending = false;

		if( !xTextInputStream->isEOF() )
		{
			aLine = xTextInputStream->readLine();
			nLen = aLine.getLength();
			pBuf = aLine.getStr();
			i = 0;

			skipWhites( pBuf, nLen, i );
		}
	}
}

bool StringResourcePersistenceImpl::implReadPropertiesFile
	( LocaleItem* pLocaleItem, const Reference< io::XInputStream >& xInputStream )
{
	if( !xInputStream.is() || pLocaleItem == NULL )
		return false;

	bool bSuccess = false;
	Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory();
	Reference< io::XTextInputStream > xTextInputStream( xMCF->createInstanceWithContext
		( ::rtl::OUString::createFromAscii( "com.sun.star.io.TextInputStream" ), m_xContext ), UNO_QUERY );

	if( xTextInputStream.is() )
	{
		Reference< io::XActiveDataSink> xActiveDataSink( xTextInputStream, UNO_QUERY );
		if( xActiveDataSink.is() )
		{
			bSuccess = true;

			xActiveDataSink->setInputStream( xInputStream );

			::rtl::OUString aEncodingStr = ::rtl::OUString::createFromAscii
				( rtl_getMimeCharsetFromTextEncoding( RTL_TEXTENCODING_ISO_8859_1 ) );
			xTextInputStream->setEncoding( aEncodingStr );

			::rtl::OUString aLine;
			while( !xTextInputStream->isEOF() )
			{
				aLine = xTextInputStream->readLine();

				sal_Int32 nLen = aLine.getLength();
				if( 0 == nLen )
					continue;
				const sal_Unicode* pBuf = aLine.getStr();
				::rtl::OUStringBuffer aBuf;
				sal_Unicode c = 0;
				sal_Int32 i = 0;

				skipWhites( pBuf, nLen, i );
				if( i == nLen )
					continue;	// line contains only white spaces
				
				// Comment?
				c = pBuf[i];
				if( c == '#' || c == '!' )
					continue;

				// Scan key
				::rtl::OUString aResourceID;
				bool bEscapePending = false;
				bool bStrComplete = false;
				while( i < nLen && !bStrComplete )
				{
					c = pBuf[i];
					if( bEscapePending )
					{
						aBuf.append( getEscapeChar( pBuf, nLen, i ) );
						bEscapePending = false;
					}
					else
					{
						if( c == '\\' )
						{
							bEscapePending = true;
						}
						else
						{
							if( c == ':' || c == '=' || isWhiteSpace( c ) )
								bStrComplete = true;
							else
								aBuf.append( c );
						}
					}
					i++;

					CheckContinueInNextLine( xTextInputStream, aLine, bEscapePending, pBuf, nLen, i );
					if( i == nLen )
						bStrComplete = true;

					if( bStrComplete )
						aResourceID = aBuf.makeStringAndClear();
				}

				// Ignore lines with empty keys
				if( 0 == aResourceID.getLength() )
					continue;

				// Scan value
				skipWhites( pBuf, nLen, i );

				::rtl::OUString aValueStr;
				bEscapePending = false;
				bStrComplete = false;
				while( i < nLen && !bStrComplete )
				{
					c = pBuf[i];
					if( c == 0x000a || c == 0x000d )	// line feed/carriage return, not always handled by TextInputStream
					{
						i++;
					}
					else
					{
						if( bEscapePending )
						{
							aBuf.append( getEscapeChar( pBuf, nLen, i ) );
							bEscapePending = false;
						}
						else if( c == '\\' )
							bEscapePending = true;
						else
							aBuf.append( c );
						i++;

						CheckContinueInNextLine( xTextInputStream, aLine, bEscapePending, pBuf, nLen, i );
					}
					if( i == nLen )
						bStrComplete = true;

					if( bStrComplete )
						aValueStr = aBuf.makeStringAndClear();
				}

				// Push into table
				pLocaleItem->m_aIdToStringMap[ aResourceID ] = aValueStr;
				implScanIdForNumber( aResourceID );
				IdToIndexMap& rIndexMap = pLocaleItem->m_aIdToIndexMap;
				rIndexMap[ aResourceID ] = pLocaleItem->m_nNextIndex++;
			}
		}
	}

	return bSuccess;
}


inline sal_Unicode getHexCharForDigit( sal_uInt16 nDigitVal )
{
	sal_Unicode cRet = ( nDigitVal < 10 ) ? ('0' + nDigitVal) : ('a' + (nDigitVal-10));
	return cRet;
}

void implWriteCharToBuffer( ::rtl::OUStringBuffer& aBuf, sal_Unicode cu, bool bKey )
{
	if( cu == '\\' )
	{
		aBuf.append( (sal_Unicode)'\\' );
		aBuf.append( (sal_Unicode)'\\' );
	}
	else if( cu == 0x000a )
	{
		aBuf.append( (sal_Unicode)'\\' );
		aBuf.append( (sal_Unicode)'n' );
	}
	else if( cu == 0x000d )
	{
		aBuf.append( (sal_Unicode)'\\' );
		aBuf.append( (sal_Unicode)'r' );
	}
	else if( bKey && cu == '=' )
	{
		aBuf.append( (sal_Unicode)'\\' );
		aBuf.append( (sal_Unicode)'=' );
	}
	else if( bKey && cu == ':' )
	{
		aBuf.append( (sal_Unicode)'\\' );
		aBuf.append( (sal_Unicode)':' );
	}
	// ISO/IEC 8859-1 range according to:
	// http://en.wikipedia.org/wiki/ISO/IEC_8859-1
	else if( (cu >= 0x20 && cu <= 0x7e) )
	//TODO: Check why (cu >= 0xa0 && cu <= 0xFF) 
	//is encoded in sample properties files
	//else if( (cu >= 0x20 && cu <= 0x7e) ||
	//		 (cu >= 0xa0 && cu <= 0xFF) )
	{
		aBuf.append( cu );
	}
	else
	{
		// Unicode encoding
		aBuf.append( (sal_Unicode)'\\' );
		aBuf.append( (sal_Unicode)'u' );

		sal_uInt16 nVal = cu;
		for( sal_uInt16 i = 0 ; i < 4 ; i++ )
		{
			sal_uInt16 nDigit = nVal / 0x1000;
			nVal -= nDigit * 0x1000;
			nVal *= 0x10;
			aBuf.append( getHexCharForDigit( nDigit ) );
		}
	}
}

void implWriteStringWithEncoding( const ::rtl::OUString& aStr,
	Reference< io::XTextOutputStream > xTextOutputStream, bool bKey )
{
	static sal_Unicode cLineFeed = 0xa;

	(void)aStr;
	(void)xTextOutputStream;

	::rtl::OUStringBuffer aBuf;
	sal_Int32 nLen = aStr.getLength();
	const sal_Unicode* pSrc = aStr.getStr();
	for( sal_Int32 i = 0 ; i < nLen ; i++ )
	{
		sal_Unicode cu = pSrc[i];
		implWriteCharToBuffer( aBuf, cu, bKey );
		// TODO?: split long lines
	}
	if( !bKey )
		aBuf.append( cLineFeed );

	::rtl::OUString aWriteStr = aBuf.makeStringAndClear();
	xTextOutputStream->writeString( aWriteStr );
}

bool StringResourcePersistenceImpl::implWritePropertiesFile( LocaleItem* pLocaleItem, 
	const Reference< io::XOutputStream >& xOutputStream, const ::rtl::OUString& aComment )
{
	static ::rtl::OUString aAssignmentStr = ::rtl::OUString::createFromAscii( "=" );
	static ::rtl::OUString aLineFeedStr = ::rtl::OUString::createFromAscii( "\n" );

	if( !xOutputStream.is() || pLocaleItem == NULL )
		return false;

	bool bSuccess = false;
	Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory();
	Reference< io::XTextOutputStream > xTextOutputStream( xMCF->createInstanceWithContext
		( ::rtl::OUString::createFromAscii( "com.sun.star.io.TextOutputStream" ), m_xContext ), UNO_QUERY );

	if( xTextOutputStream.is() )
	{
		Reference< io::XActiveDataSource> xActiveDataSource( xTextOutputStream, UNO_QUERY );
		if( xActiveDataSource.is() )
		{
			xActiveDataSource->setOutputStream( xOutputStream );

			::rtl::OUString aEncodingStr = ::rtl::OUString::createFromAscii
				( rtl_getMimeCharsetFromTextEncoding( RTL_TEXTENCODING_ISO_8859_1 ) );
			xTextOutputStream->setEncoding( aEncodingStr );

			xTextOutputStream->writeString( aComment );
			xTextOutputStream->writeString( aLineFeedStr );

			const IdToStringMap& rHashMap = pLocaleItem->m_aIdToStringMap;
			if( rHashMap.size() > 0 )
			{
				// Sort ids according to read order
				const IdToIndexMap& rIndexMap = pLocaleItem->m_aIdToIndexMap;
				IdToIndexMap::const_iterator it_index;

				// Find max/min index
				sal_Int32 nMinIndex = -1;
				sal_Int32 nMaxIndex = -1;
				for( it_index = rIndexMap.begin(); it_index != rIndexMap.end(); it_index++ )
				{
					sal_Int32 nIndex = (*it_index).second;
					if( nMinIndex > nIndex || nMinIndex == -1 )
						nMinIndex = nIndex;
					if( nMaxIndex < nIndex )
						nMaxIndex = nIndex;
				}
				sal_Int32 nTabSize = nMaxIndex - nMinIndex + 1;

				// Create sorted array of pointers to the id strings
				const ::rtl::OUString** pIdPtrs = new const ::rtl::OUString*[nTabSize];
				sal_Int32 i;
				for( i = 0 ; i < nTabSize ; i++ )
					pIdPtrs[i] = NULL;
				for( it_index = rIndexMap.begin(); it_index != rIndexMap.end(); it_index++ )
				{
					sal_Int32 nIndex = (*it_index).second;
					pIdPtrs[nIndex - nMinIndex] = &((*it_index).first);
				}

				// Write lines in correct order
				for( i = 0 ; i < nTabSize ; i++ )
				{
					const ::rtl::OUString* pStr = pIdPtrs[i];
					if( pStr != NULL )
					{
						::rtl::OUString aResourceID = *pStr;
						IdToStringMap::const_iterator it = rHashMap.find( aResourceID );
						if( !( it == rHashMap.end() ) )
						{
							implWriteStringWithEncoding( aResourceID, xTextOutputStream, true );
							xTextOutputStream->writeString( aAssignmentStr );
							::rtl::OUString aValStr = (*it).second;
							implWriteStringWithEncoding( aValStr, xTextOutputStream, false );
						}
					}
				}

				delete pIdPtrs;
			}

			bSuccess = true;
		}
	}
	return bSuccess;
}


// =============================================================================
// StringResourceWithStorageImpl
// =============================================================================

// component operations
static Sequence< ::rtl::OUString > getSupportedServiceNames_StringResourceWithStorageImpl()
{
    Sequence< ::rtl::OUString > names(1);
    names[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.resource.StringResourceWithStorage") );
    return names;
}

static ::rtl::OUString getImplementationName_StringResourceWithStorageImpl()
{
    return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.scripting.StringResourceWithStorage") );
}

static Reference< XInterface > SAL_CALL create_StringResourceWithStorageImpl(
    Reference< XComponentContext > const & xContext )
    SAL_THROW( () )
{
    return static_cast< ::cppu::OWeakObject * >( new StringResourceWithStorageImpl( xContext ) );
}

// -----------------------------------------------------------------------------

StringResourceWithStorageImpl::StringResourceWithStorageImpl( const Reference< XComponentContext >& rxContext )
    : StringResourceWithStorageImpl_BASE( rxContext )
	, m_bStorageChanged( false )
{
}

// -----------------------------------------------------------------------------

StringResourceWithStorageImpl::~StringResourceWithStorageImpl()
{
}

// -----------------------------------------------------------------------------
// XServiceInfo
// -----------------------------------------------------------------------------

::rtl::OUString StringResourceWithStorageImpl::getImplementationName(  ) throw (RuntimeException)
{
    return getImplementationName_StringResourceWithStorageImpl();
}

// -----------------------------------------------------------------------------

sal_Bool StringResourceWithStorageImpl::supportsService( const ::rtl::OUString& rServiceName ) throw (RuntimeException)
{
	Sequence< ::rtl::OUString > aNames( getSupportedServiceNames() );
	const ::rtl::OUString* pNames = aNames.getConstArray();
	const ::rtl::OUString* pEnd = pNames + aNames.getLength();
	for ( ; pNames != pEnd && !pNames->equals( rServiceName ); ++pNames )
		;

	return pNames != pEnd;
}

// -----------------------------------------------------------------------------

Sequence< ::rtl::OUString > StringResourceWithStorageImpl::getSupportedServiceNames(  ) throw (RuntimeException)
{
    return getSupportedServiceNames_StringResourceWithStorageImpl();
}

// -----------------------------------------------------------------------------
// XInitialization
// -----------------------------------------------------------------------------

void StringResourceWithStorageImpl::initialize( const Sequence< Any >& aArguments )
	throw (Exception, RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );

    if ( aArguments.getLength() != 5 )
    {
        throw RuntimeException(
            ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StringResourceWithStorageImpl::initialize: invalid number of arguments!" ) ),
            Reference< XInterface >() );
    }

	bool bOk = (aArguments[0] >>= m_xStorage);
	if( bOk && !m_xStorage.is() )
		bOk = false;

	if( !bOk )
    {
        ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceWithStorageImpl::initialize: invalid storage" );
        throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 );
	}

	implInitializeCommonParameters( aArguments );
}

// -----------------------------------------------------------------------------
// Forwarding calls to base class

// XModifyBroadcaster
void StringResourceWithStorageImpl::addModifyListener( const Reference< XModifyListener >& aListener )
	throw (RuntimeException)
{
	StringResourceImpl::addModifyListener( aListener );
}
void StringResourceWithStorageImpl::removeModifyListener( const Reference< XModifyListener >& aListener )
	throw (RuntimeException)
{
	StringResourceImpl::removeModifyListener( aListener );
}

// XStringResourceResolver
::rtl::OUString StringResourceWithStorageImpl::resolveString( const ::rtl::OUString& ResourceID ) 
	throw (::com::sun::star::resource::MissingResourceException, RuntimeException)
{
	return StringResourceImpl::resolveString( ResourceID ) ;
}
::rtl::OUString StringResourceWithStorageImpl::resolveStringForLocale( const ::rtl::OUString& ResourceID, const Locale& locale )
	throw ( ::com::sun::star::resource::MissingResourceException, RuntimeException)
{
	return StringResourceImpl::resolveStringForLocale( ResourceID, locale );
}
sal_Bool StringResourceWithStorageImpl::hasEntryForId( const ::rtl::OUString& ResourceID )
	throw (RuntimeException)
{
	return StringResourceImpl::hasEntryForId( ResourceID ) ;
}
sal_Bool StringResourceWithStorageImpl::hasEntryForIdAndLocale( const ::rtl::OUString& ResourceID, 
	const Locale& locale )
		throw (RuntimeException)
{
	return StringResourceImpl::hasEntryForIdAndLocale( ResourceID, locale );
}
Sequence< ::rtl::OUString > StringResourceWithStorageImpl::getResourceIDs(  )
	throw (RuntimeException)
{
	return StringResourceImpl::getResourceIDs();
}
Sequence< ::rtl::OUString > StringResourceWithStorageImpl::getResourceIDsForLocale
	( const Locale& locale ) throw (::com::sun::star::uno::RuntimeException)
{
	return StringResourceImpl::getResourceIDsForLocale( locale );
}
Locale StringResourceWithStorageImpl::getCurrentLocale()
	throw (RuntimeException)
{
	return StringResourceImpl::getCurrentLocale();
}
Locale StringResourceWithStorageImpl::getDefaultLocale(  )
	throw (RuntimeException)
{
	return StringResourceImpl::getDefaultLocale();
}
Sequence< Locale > StringResourceWithStorageImpl::getLocales(  )
	throw (RuntimeException)
{
	return StringResourceImpl::getLocales();
}

// XStringResourceManager
sal_Bool StringResourceWithStorageImpl::isReadOnly()
	throw (RuntimeException)
{
	return StringResourceImpl::isReadOnly();
}
void StringResourceWithStorageImpl::setCurrentLocale( const Locale& locale, sal_Bool FindClosestMatch )
	throw (IllegalArgumentException, RuntimeException)
{
	StringResourceImpl::setCurrentLocale( locale, FindClosestMatch );
}
void StringResourceWithStorageImpl::setDefaultLocale( const Locale& locale )
	throw (IllegalArgumentException, RuntimeException,NoSupportException)
{
	StringResourceImpl::setDefaultLocale( locale );
}
void StringResourceWithStorageImpl::setString( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str )
	throw (NoSupportException, RuntimeException)
{
	StringResourceImpl::setString( ResourceID, Str );
}
void StringResourceWithStorageImpl::setStringForLocale
	( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str, const Locale& locale )
		throw (NoSupportException, RuntimeException)
{
	StringResourceImpl::setStringForLocale( ResourceID, Str, locale );
}
void StringResourceWithStorageImpl::removeId( const ::rtl::OUString& ResourceID )
	throw (::com::sun::star::resource::MissingResourceException, RuntimeException, NoSupportException)
{
	StringResourceImpl::removeId( ResourceID );
}
void StringResourceWithStorageImpl::removeIdForLocale( const ::rtl::OUString& ResourceID, const Locale& locale )
	throw (::com::sun::star::resource::MissingResourceException, RuntimeException, NoSupportException)
{
	StringResourceImpl::removeIdForLocale( ResourceID, locale );
}
void StringResourceWithStorageImpl::newLocale( const Locale& locale )
	throw (ElementExistException, IllegalArgumentException, RuntimeException, NoSupportException)
{
	StringResourceImpl::newLocale( locale );
}
void StringResourceWithStorageImpl::removeLocale( const Locale& locale )
	throw (IllegalArgumentException, RuntimeException, NoSupportException)
{
	StringResourceImpl::removeLocale( locale );
}
sal_Int32 StringResourceWithStorageImpl::getUniqueNumericId(  )
	throw (RuntimeException, NoSupportException)
{
	return StringResourceImpl::getUniqueNumericId();
}

// XStringResourcePersistence
void StringResourceWithStorageImpl::store()
	throw (NoSupportException, Exception, RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );
	implCheckReadOnly( "StringResourceWithStorageImpl::store(): Read only" );

	bool bUsedForStore = true;
	bool bStoreAll = m_bStorageChanged;
	m_bStorageChanged = false;
	if( !m_bModified && !bStoreAll )
		return;

	implStoreAtStorage( m_aNameBase, m_aComment, m_xStorage, bUsedForStore, bStoreAll );
	m_bModified = false;
}

sal_Bool StringResourceWithStorageImpl::isModified(  )
	throw (RuntimeException)
{
	return StringResourcePersistenceImpl::isModified();
}
void StringResourceWithStorageImpl::setComment( const ::rtl::OUString& Comment )
	throw (::com::sun::star::uno::RuntimeException)
{
	StringResourcePersistenceImpl::setComment( Comment );
}
void StringResourceWithStorageImpl::storeToStorage( const Reference< XStorage >& Storage,
	const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment )
		throw (Exception, RuntimeException)
{
	StringResourcePersistenceImpl::storeToStorage( Storage, NameBase, Comment );
}
void StringResourceWithStorageImpl::storeToURL( const ::rtl::OUString& URL,
	const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment,
	const Reference< ::com::sun::star::task::XInteractionHandler >& Handler )
		throw (Exception, RuntimeException)
{
	StringResourcePersistenceImpl::storeToURL( URL, NameBase, Comment, Handler );
}
Sequence< ::sal_Int8 > StringResourceWithStorageImpl::exportBinary(  )
	throw (RuntimeException)
{
	return StringResourcePersistenceImpl::exportBinary();
}
void StringResourceWithStorageImpl::importBinary( const Sequence< ::sal_Int8 >& Data )
	throw (IllegalArgumentException, RuntimeException)
{
	StringResourcePersistenceImpl::importBinary( Data );
}

// -----------------------------------------------------------------------------
// XStringResourceWithStorage

void StringResourceWithStorageImpl::storeAsStorage( const Reference< XStorage >& Storage )
	throw (Exception, RuntimeException)
{
	setStorage( Storage );
	store();
}

void StringResourceWithStorageImpl::setStorage( const Reference< XStorage >& Storage )
	throw (IllegalArgumentException, RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );

	if( !Storage.is() )
    {
        ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii
			( "StringResourceWithStorageImpl::setStorage: invalid storage" );
        throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 );
	}

	implLoadAllLocales();

	m_xStorage = Storage;
	m_bStorageChanged = true;
}


// =============================================================================
// Private helper methods
// =============================================================================

// Scan locale properties files
void StringResourceWithStorageImpl::implScanLocales( void )
{
	Reference< container::XNameAccess > xNameAccess( m_xStorage, UNO_QUERY );
    if( xNameAccess.is() )
    {
		Sequence< ::rtl::OUString > aContentSeq = xNameAccess->getElementNames();
		implScanLocaleNames( aContentSeq );
	}

	implLoadAllLocales();
}

// Loading
bool StringResourceWithStorageImpl::implLoadLocale( LocaleItem* pLocaleItem )
{
	bool bSuccess = false;
	try
	{
		::rtl::OUString aStreamName = implGetFileNameForLocaleItem( pLocaleItem, m_aNameBase );
		aStreamName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(".properties") );

		Reference< io::XStream > xElementStream = 
			m_xStorage->openStreamElement( aStreamName, ElementModes::READ );

		if( xElementStream.is() )
		{
			Reference< io::XInputStream > xInputStream = xElementStream->getInputStream();
			if( xInputStream.is() )
			{
				bSuccess = StringResourcePersistenceImpl::implReadPropertiesFile( pLocaleItem, xInputStream );
				xInputStream->closeInput();
			}
		}
	}
	catch( uno::Exception& )
	{}

	return bSuccess;
}


// =============================================================================
// StringResourceWithLocationImpl
// =============================================================================

// component operations
static Sequence< ::rtl::OUString > getSupportedServiceNames_StringResourceWithLocationImpl()
{
    Sequence< ::rtl::OUString > names(1);
    names[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.resource.StringResourceWithLocation") );
    return names;
}

static ::rtl::OUString getImplementationName_StringResourceWithLocationImpl()
{
    return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.scripting.StringResourceWithLocation") );
}

static Reference< XInterface > SAL_CALL create_StringResourceWithLocationImpl(
    Reference< XComponentContext > const & xContext )
    SAL_THROW( () )
{
    return static_cast< ::cppu::OWeakObject * >( new StringResourceWithLocationImpl( xContext ) );
}

// -----------------------------------------------------------------------------

StringResourceWithLocationImpl::StringResourceWithLocationImpl( const Reference< XComponentContext >& rxContext )
    : StringResourceWithLocationImpl_BASE( rxContext )
	, m_bLocationChanged( false )
{
}

// -----------------------------------------------------------------------------

StringResourceWithLocationImpl::~StringResourceWithLocationImpl()
{
}

// -----------------------------------------------------------------------------
// XServiceInfo
// -----------------------------------------------------------------------------

::rtl::OUString StringResourceWithLocationImpl::getImplementationName(  ) throw (RuntimeException)
{
    return getImplementationName_StringResourceWithLocationImpl();
}

// -----------------------------------------------------------------------------

sal_Bool StringResourceWithLocationImpl::supportsService( const ::rtl::OUString& rServiceName ) throw (RuntimeException)
{
	Sequence< ::rtl::OUString > aNames( getSupportedServiceNames() );
	const ::rtl::OUString* pNames = aNames.getConstArray();
	const ::rtl::OUString* pEnd = pNames + aNames.getLength();
	for ( ; pNames != pEnd && !pNames->equals( rServiceName ); ++pNames )
		;

	return pNames != pEnd;
}

// -----------------------------------------------------------------------------

Sequence< ::rtl::OUString > StringResourceWithLocationImpl::getSupportedServiceNames(  ) throw (RuntimeException)
{
    return getSupportedServiceNames_StringResourceWithLocationImpl();
}

// -----------------------------------------------------------------------------
// XInitialization
// -----------------------------------------------------------------------------

void StringResourceWithLocationImpl::initialize( const Sequence< Any >& aArguments )
	throw (Exception, RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );

    if ( aArguments.getLength() != 6 )
    {
        throw RuntimeException(
            ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM
				( "XInitialization::initialize: invalid number of arguments!" ) ),
            Reference< XInterface >() );
    }

	bool bOk = (aArguments[0] >>= m_aLocation);
	sal_Int32 nLen = m_aLocation.getLength();
	if( bOk && nLen == 0 )
	{
		bOk = false;
	}
	else
	{
		if( m_aLocation.getStr()[nLen - 1] != '/' )
			m_aLocation += ::rtl::OUString::createFromAscii( "/" );
	}

	if( !bOk )
    {
		::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "XInitialization::initialize: invalid URL" );
		throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 );
	}


	bOk = (aArguments[5] >>= m_xInteractionHandler);
	if( !bOk )
    {
        ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceWithStorageImpl::initialize: invalid type" );
        throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 5 );
	}

	implInitializeCommonParameters( aArguments );
}

// -----------------------------------------------------------------------------
// Forwarding calls to base class

// XModifyBroadcaster
void StringResourceWithLocationImpl::addModifyListener( const Reference< XModifyListener >& aListener )
	throw (RuntimeException)
{
	StringResourceImpl::addModifyListener( aListener );
}
void StringResourceWithLocationImpl::removeModifyListener( const Reference< XModifyListener >& aListener )
	throw (RuntimeException)
{
	StringResourceImpl::removeModifyListener( aListener );
}

// XStringResourceResolver
::rtl::OUString StringResourceWithLocationImpl::resolveString( const ::rtl::OUString& ResourceID ) 
	throw (::com::sun::star::resource::MissingResourceException, RuntimeException)
{
	return StringResourceImpl::resolveString( ResourceID ) ;
}
::rtl::OUString StringResourceWithLocationImpl::resolveStringForLocale( const ::rtl::OUString& ResourceID, const Locale& locale )
	throw ( ::com::sun::star::resource::MissingResourceException, RuntimeException)
{
	return StringResourceImpl::resolveStringForLocale( ResourceID, locale );
}
sal_Bool StringResourceWithLocationImpl::hasEntryForId( const ::rtl::OUString& ResourceID )
	throw (RuntimeException)
{
	return StringResourceImpl::hasEntryForId( ResourceID ) ;
}
sal_Bool StringResourceWithLocationImpl::hasEntryForIdAndLocale( const ::rtl::OUString& ResourceID, 
	const Locale& locale )
		throw (RuntimeException)
{
	return StringResourceImpl::hasEntryForIdAndLocale( ResourceID, locale );
}
Sequence< ::rtl::OUString > StringResourceWithLocationImpl::getResourceIDs(  )
	throw (RuntimeException)
{
	return StringResourceImpl::getResourceIDs();
}
Sequence< ::rtl::OUString > StringResourceWithLocationImpl::getResourceIDsForLocale
	( const Locale& locale ) throw (::com::sun::star::uno::RuntimeException)
{
	return StringResourceImpl::getResourceIDsForLocale( locale );
}
Locale StringResourceWithLocationImpl::getCurrentLocale()
	throw (RuntimeException)
{
	return StringResourceImpl::getCurrentLocale();
}
Locale StringResourceWithLocationImpl::getDefaultLocale(  )
	throw (RuntimeException)
{
	return StringResourceImpl::getDefaultLocale();
}
Sequence< Locale > StringResourceWithLocationImpl::getLocales(  )
	throw (RuntimeException)
{
	return StringResourceImpl::getLocales();
}

// XStringResourceManager
sal_Bool StringResourceWithLocationImpl::isReadOnly()
	throw (RuntimeException)
{
	return StringResourceImpl::isReadOnly();
}
void StringResourceWithLocationImpl::setCurrentLocale( const Locale& locale, sal_Bool FindClosestMatch )
	throw (IllegalArgumentException, RuntimeException)
{
	StringResourceImpl::setCurrentLocale( locale, FindClosestMatch );
}
void StringResourceWithLocationImpl::setDefaultLocale( const Locale& locale )
	throw (IllegalArgumentException, RuntimeException,NoSupportException)
{
	StringResourceImpl::setDefaultLocale( locale );
}
void StringResourceWithLocationImpl::setString( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str )
	throw (NoSupportException, RuntimeException)
{
	StringResourceImpl::setString( ResourceID, Str );
}
void StringResourceWithLocationImpl::setStringForLocale
	( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str, const Locale& locale )
		throw (NoSupportException, RuntimeException)
{
	StringResourceImpl::setStringForLocale( ResourceID, Str, locale );
}
void StringResourceWithLocationImpl::removeId( const ::rtl::OUString& ResourceID )
	throw (::com::sun::star::resource::MissingResourceException, RuntimeException, NoSupportException)
{
	StringResourceImpl::removeId( ResourceID );
}
void StringResourceWithLocationImpl::removeIdForLocale( const ::rtl::OUString& ResourceID, const Locale& locale )
	throw (::com::sun::star::resource::MissingResourceException, RuntimeException, NoSupportException)
{
	StringResourceImpl::removeIdForLocale( ResourceID, locale );
}
void StringResourceWithLocationImpl::newLocale( const Locale& locale )
	throw (ElementExistException, IllegalArgumentException, RuntimeException, NoSupportException)
{
	StringResourceImpl::newLocale( locale );
}
void StringResourceWithLocationImpl::removeLocale( const Locale& locale )
	throw (IllegalArgumentException, RuntimeException, NoSupportException)
{
	StringResourceImpl::removeLocale( locale );
}
sal_Int32 StringResourceWithLocationImpl::getUniqueNumericId(  )
	throw (RuntimeException, NoSupportException)
{
	return StringResourceImpl::getUniqueNumericId();
}

// XStringResourcePersistence
void StringResourceWithLocationImpl::store()
	throw (NoSupportException, Exception, RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );
	implCheckReadOnly( "StringResourceWithLocationImpl::store(): Read only" );

	bool bUsedForStore = true;
	bool bStoreAll = m_bLocationChanged;
	m_bLocationChanged = false;
	if( !m_bModified && !bStoreAll )
		return;

	Reference< ucb::XSimpleFileAccess > xFileAccess = getFileAccess();
	implStoreAtLocation( m_aLocation, m_aNameBase, m_aComment, 
		xFileAccess, bUsedForStore, bStoreAll );
	m_bModified = false;
}

sal_Bool StringResourceWithLocationImpl::isModified(  )
	throw (RuntimeException)
{
	return StringResourcePersistenceImpl::isModified();
}
void StringResourceWithLocationImpl::setComment( const ::rtl::OUString& Comment )
	throw (::com::sun::star::uno::RuntimeException)
{
	StringResourcePersistenceImpl::setComment( Comment );
}
void StringResourceWithLocationImpl::storeToStorage( const Reference< XStorage >& Storage,
	const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment )
		throw (Exception, RuntimeException)
{
	StringResourcePersistenceImpl::storeToStorage( Storage, NameBase, Comment );
}
void StringResourceWithLocationImpl::storeToURL( const ::rtl::OUString& URL,
	const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment,
	const Reference< ::com::sun::star::task::XInteractionHandler >& Handler )
		throw (Exception, RuntimeException)
{
	StringResourcePersistenceImpl::storeToURL( URL, NameBase, Comment, Handler );
}
Sequence< ::sal_Int8 > StringResourceWithLocationImpl::exportBinary(  )
	throw (RuntimeException)
{
	return StringResourcePersistenceImpl::exportBinary();
}
void StringResourceWithLocationImpl::importBinary( const Sequence< ::sal_Int8 >& Data )
	throw (IllegalArgumentException, RuntimeException)
{
	StringResourcePersistenceImpl::importBinary( Data );
}

// -----------------------------------------------------------------------------
// XStringResourceWithLocation

// XStringResourceWithLocation
void StringResourceWithLocationImpl::storeAsURL( const ::rtl::OUString& URL ) 
	throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
{
	setURL( URL );
	store();
}

void StringResourceWithLocationImpl::setURL( const ::rtl::OUString& URL )
	throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
{
    ::osl::MutexGuard aGuard( getMutex() );
	implCheckReadOnly( "StringResourceWithLocationImpl::setURL(): Read only" );

	sal_Int32 nLen = URL.getLength();
	if( nLen == 0 )
    {
		::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii
			( "StringResourceWithLocationImpl::setURL: invalid URL" );
		throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 );
	}

	implLoadAllLocales();

	// Delete files at old location
	bool bUsedForStore = false;
	bool bStoreAll = false;
	bool bKillAll = true;
	implStoreAtLocation( m_aLocation, m_aNameBase, m_aComment,
		getFileAccess(), bUsedForStore, bStoreAll, bKillAll );

	m_aLocation = URL;
	m_bLocationChanged = true;
}


// =============================================================================
// Private helper methods
// =============================================================================

// Scan locale properties files
void StringResourceWithLocationImpl::implScanLocales( void )
{
	const Reference< ucb::XSimpleFileAccess > xFileAccess = getFileAccess();
    if( xFileAccess.is() && xFileAccess->isFolder( m_aLocation ) )
    {
		Sequence< ::rtl::OUString > aContentSeq = xFileAccess->getFolderContents( m_aLocation, false );
		implScanLocaleNames( aContentSeq );
	}
}

// Loading
bool StringResourceWithLocationImpl::implLoadLocale( LocaleItem* pLocaleItem )
{
	bool bSuccess = false;

	const Reference< ucb::XSimpleFileAccess > xFileAccess = getFileAccess();
	if( xFileAccess.is() )
	{
		::rtl::OUString aCompleteFileName = 
			implGetPathForLocaleItem( pLocaleItem, m_aNameBase, m_aLocation );

		Reference< io::XInputStream > xInputStream;
		try
		{
			xInputStream = xFileAccess->openFileRead( aCompleteFileName );
		}
		catch( Exception& )
		{}
		if( xInputStream.is() )
		{
			bSuccess = StringResourcePersistenceImpl::implReadPropertiesFile( pLocaleItem, xInputStream );
			xInputStream->closeInput();
		}
	}

	return bSuccess;
}

const Reference< ucb::XSimpleFileAccess > StringResourceWithLocationImpl::getFileAccess( void )
{
    ::osl::MutexGuard aGuard( getMutex() );

	if( !m_xSFI.is() )
	{
		Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory();
		m_xSFI = Reference< ucb::XSimpleFileAccess >( xMCF->createInstanceWithContext
			( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ), m_xContext ), UNO_QUERY );

		if( m_xSFI.is() && m_xInteractionHandler.is() )
			m_xSFI->setInteractionHandler( m_xInteractionHandler );
	}
	return m_xSFI;
}


// =============================================================================
// component export operations
// =============================================================================

static struct ::cppu::ImplementationEntry s_component_entries [] =
{
    {
        create_StringResourceImpl, getImplementationName_StringResourceImpl,
        getSupportedServiceNames_StringResourceImpl,
		::cppu::createSingleComponentFactory,
        0, 0
    },
    {
        create_StringResourceWithLocationImpl, getImplementationName_StringResourceWithLocationImpl,
        getSupportedServiceNames_StringResourceWithLocationImpl,
        ::cppu::createSingleComponentFactory,
        0, 0
    },
    {
        create_StringResourceWithStorageImpl, getImplementationName_StringResourceWithStorageImpl,
        getSupportedServiceNames_StringResourceWithStorageImpl,
        ::cppu::createSingleComponentFactory,
        0, 0
    },
    { 0, 0, 0, 0, 0, 0 }
};


//.........................................................................
}	// namespace dlgprov
//.........................................................................


// =============================================================================
// component exports
// =============================================================================

extern "C"
{
    void SAL_CALL component_getImplementationEnvironment( 
        const sal_Char ** ppEnvTypeName, uno_Environment ** ppEnv )
    {
		(void)ppEnv;

        *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
    }

    void * SAL_CALL component_getFactory( 
        const sal_Char * pImplName, lang::XMultiServiceFactory * pServiceManager,
        registry::XRegistryKey * pRegistryKey )
    {
        return ::cppu::component_getFactoryHelper( 
            pImplName, pServiceManager, pRegistryKey, ::stringresource::s_component_entries );
    }
}